├── .dockerignore ├── .gitignore ├── Dockerfile ├── LICENSE.txt ├── README.md ├── config.py ├── flaskapp ├── __init__.py ├── forms.py ├── lib │ ├── __init__.py │ ├── template_helpers.py │ └── util.py ├── meta.py ├── models.py ├── static │ ├── cache │ │ ├── style-06956745a2.css │ │ ├── style-f797b9a07e.min.css │ │ └── vendor │ │ │ └── mui-0.9.17 │ │ │ ├── angular │ │ │ ├── mui-angular-bca0010feb.js │ │ │ └── mui-angular-de11fbdcc7.min.js │ │ │ ├── css │ │ │ ├── mui-f33078ec84.css │ │ │ ├── mui-f7be884ff8.min.css │ │ │ ├── mui-rtl-59fbfcbc8c.min.css │ │ │ └── mui-rtl-e660de5472.css │ │ │ ├── email │ │ │ ├── mui-email-inline-65e896e92c.css │ │ │ ├── mui-email-inline-rtl-6898316011.css │ │ │ ├── mui-email-styletag-d8aa291e6d.css │ │ │ └── mui-email-styletag-rtl-c59925b8b2.css │ │ │ ├── extra │ │ │ ├── mui-angular-combined-2ef86ce313.js │ │ │ ├── mui-angular-combined-d3b8cca7fb.min.js │ │ │ ├── mui-colors-45b1960c08.css │ │ │ ├── mui-colors-8630fec18a.min.css │ │ │ ├── mui-combined-0cdbab1d4a.js │ │ │ ├── mui-combined-32029b42f0.min.js │ │ │ ├── mui-noglobals-4b283fe32b.min.css │ │ │ ├── mui-noglobals-ae15abfbb2.css │ │ │ ├── mui-noglobals-rtl-05f9aeb9a3.css │ │ │ ├── mui-noglobals-rtl-21ee63aad1.min.css │ │ │ ├── mui-react-combined-f4b51b1165.js │ │ │ └── mui-react-combined-fe79856b81.min.js │ │ │ ├── js │ │ │ ├── mui-45131227e5.js │ │ │ └── mui-b7b8f924a9.min.js │ │ │ ├── react │ │ │ ├── mui-react-8b2bfeb3d6.js │ │ │ └── mui-react-96e0b6b0b0.min.js │ │ │ └── webcomponents │ │ │ ├── mui-webcomponents-347f2425c4.min.js │ │ │ └── mui-webcomponents-a2432bac9e.js │ ├── rev-manifest.json │ ├── style.css │ ├── style.min.css │ └── vendor │ │ └── mui-0.9.17 │ │ ├── angular │ │ ├── mui-angular.js │ │ └── mui-angular.min.js │ │ ├── css │ │ ├── mui-rtl.css │ │ ├── mui-rtl.min.css │ │ ├── mui.css │ │ └── mui.min.css │ │ ├── email │ │ ├── mui-email-inline-rtl.css │ │ ├── mui-email-inline.css │ │ ├── mui-email-styletag-rtl.css │ │ └── mui-email-styletag.css │ │ ├── extra │ │ ├── mui-angular-combined.js │ │ ├── mui-angular-combined.min.js │ │ ├── mui-colors.css │ │ ├── mui-colors.min.css │ │ ├── mui-combined.js │ │ ├── mui-combined.min.js │ │ ├── mui-noglobals-rtl.css │ │ ├── mui-noglobals-rtl.min.css │ │ ├── mui-noglobals.css │ │ ├── mui-noglobals.min.css │ │ ├── mui-react-combined.js │ │ └── mui-react-combined.min.js │ │ ├── js │ │ ├── mui.js │ │ └── mui.min.js │ │ ├── react │ │ ├── mui-react.js │ │ └── mui-react.min.js │ │ └── webcomponents │ │ ├── mui-webcomponents.js │ │ └── mui-webcomponents.min.js ├── templates │ ├── auth │ │ ├── create-account.html │ │ ├── email-verification-request-followup.html │ │ ├── email-verification-request.html │ │ ├── forgot-followup.html │ │ ├── forgot.html │ │ ├── login.html │ │ ├── reset-password-email.html │ │ ├── reset-password-email.txt │ │ ├── reset-password-error.html │ │ ├── reset-password-followup.html │ │ ├── reset-password.html │ │ ├── verify-email-email.html │ │ ├── verify-email-email.txt │ │ ├── verify-email-error.html │ │ └── verify-email-followup.html │ ├── content │ │ └── home.html │ ├── shared-email │ │ ├── base-layout.html │ │ └── skeleton.html │ ├── shared │ │ ├── base-layout.html │ │ └── modal-layout.html │ ├── skeleton.html │ └── skeleton.js └── views │ ├── __init__.py │ ├── auth.py │ └── content.py ├── requirements.txt ├── scripts └── create_db.py ├── static-src ├── gulpfile.js ├── package-lock.json ├── package.json └── src │ ├── sass │ └── global.scss │ └── vendor │ └── mui-0.9.17 │ ├── angular │ ├── mui-angular.js │ └── mui-angular.min.js │ ├── css │ ├── mui-rtl.css │ ├── mui-rtl.min.css │ ├── mui.css │ └── mui.min.css │ ├── email │ ├── mui-email-inline-rtl.css │ ├── mui-email-inline.css │ ├── mui-email-styletag-rtl.css │ └── mui-email-styletag.css │ ├── extra │ ├── mui-angular-combined.js │ ├── mui-angular-combined.min.js │ ├── mui-colors.css │ ├── mui-colors.min.css │ ├── mui-combined.js │ ├── mui-combined.min.js │ ├── mui-noglobals-rtl.css │ ├── mui-noglobals-rtl.min.css │ ├── mui-noglobals.css │ ├── mui-noglobals.min.css │ ├── mui-react-combined.js │ └── mui-react-combined.min.js │ ├── js │ ├── mui.js │ └── mui.min.js │ ├── react │ ├── mui-react.js │ └── mui-react.min.js │ └── webcomponents │ ├── mui-webcomponents.js │ └── mui-webcomponents.min.js ├── tests ├── __init__.py └── views │ ├── __init__.py │ ├── test_auth.py │ └── test_content.py └── wsgi.py /.dockerignore: -------------------------------------------------------------------------------- 1 | /static-src 2 | 3 | /.git 4 | 5 | **/__pycache__ 6 | *~ 7 | *.pyc 8 | *.swp 9 | *.swo 10 | *.un~ 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # git-ls-files --others --exclude-from=.git/info/exclude 2 | # Lines that start with '#' are comments. 3 | # For a project mostly in C, the following would be a good set of 4 | # exclude patterns (uncomment them if you want to use them): 5 | # *.[oa] 6 | # *~ 7 | *.pyc 8 | *~ 9 | \#* 10 | node_modules 11 | npm-debug.log 12 | app.db 13 | test.db 14 | __pycache__ 15 | .venv 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8.2-alpine as base 2 | MAINTAINER Andres Morey "andresmarcel@gmail.com" 3 | 4 | # ----------------------------------------------------------------------------- 5 | 6 | FROM base as builder 7 | 8 | # system dependencies 9 | RUN apk update \ 10 | && apk add --no-cache --virtual build-dependencies gcc libffi-dev libxml2-dev musl-dev make \ 11 | && apk add --no-cache libxslt-dev \ 12 | && apk add --no-cache bash 13 | 14 | # python dependencies 15 | COPY requirements.txt /requirements.txt 16 | RUN pip install -r /requirements.txt 17 | 18 | # cleanup /usr/lib 19 | RUN apk del build-dependencies 20 | 21 | # ----------------------------------------------------------------------------- 22 | 23 | FROM base 24 | 25 | # copy dependencies 26 | COPY --from=builder /usr/lib /usr/lib 27 | COPY --from=builder /usr/local /usr/local 28 | 29 | # copy source 30 | COPY . /app 31 | WORKDIR /app 32 | 33 | # entrypoint 34 | ENTRYPOINT ["gunicorn", "wsgi:app"] 35 | CMD ["--bind=0.0.0.0:5000", "--worker-class=gevent", "--workers=4", "--threads=1", "--preload"] 36 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Andres Morey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flask Seed App 2 | 3 | This app is meant to serve as template for new projects. It has the following features: 4 | 5 | * User accounts implemented with SQLite, cookies and Flask-Login 6 | * Passwords hashed with bcrypt 7 | * CSRF protection with Flask-CSRF 8 | * Email with Flask-Mail 9 | * Login/logout/forgot password workflow 10 | * Static asset build step with gulp 11 | * Basic HTML Web and Email templates with MUI (https://www.muicss.com) 12 | * Unittests 13 | 14 | To create a new app from `flaskapp` first clone the repository and remove the `.git` directory: 15 | 16 | ```bash 17 | $ git clone git@github.com:muicss/flaskapp.git 18 | $ rm -rf flaskapp/.git 19 | ``` 20 | 21 | Then, do a search-replace on the string `flaskapp` (remember to replace `` with your app's name): 22 | 23 | ```bash 24 | $ find flaskapp -type f | xargs sed -i'' -e 's/flaskapp//g' 25 | $ find flaskapp -type f | xargs sed -i'' -e 's/Flaskapp//g' 26 | $ mv flaskapp 27 | $ mv /flaskapp / 28 | ``` 29 | 30 | Now you have your own flask seed project. 31 | 32 | ## Config Variables 33 | 34 | flaskapp can be configured using the following environment variables: 35 | 36 | Name | Description | Default | Required 37 | ------------- | --------------------------- | ------- | ------- 38 | DEBUG | Flask debug variable | "False" | no 39 | SECRET_KEY | Flask cookie encryption key | null | yes 40 | MAIL_PORT | SMTP port | null | yes 41 | MAIL_SERVER | SMTP hostname | null | yes 42 | MAIL_USERNAME | SMTP username | null | yes 43 | MAIL_PASSWORD | SMTP password | null | yes 44 | 45 | ## Quickstart 46 | 47 | To work in a sandboxed Python environment we recommend installing the app in a Python [virtualenv](https://pypi.python.org/pypi/virtualenv). 48 | 49 | 1. Install dependencies 50 | 51 | ```bash 52 | $ cd /path/to/flaskapp 53 | $ pip install -r requirements.txt 54 | ``` 55 | 56 | 1. Setup a SQLite database for development (`app.db`) 57 | 58 | ```bash 59 | $ python scripts/create_db.py 60 | ``` 61 | 62 | 1. Environment variables 63 | 64 | In order to configure flaskapp it is recommended that you create an environment file with the required variables listed above: 65 | 66 | ```bash 67 | #!/bin/bash 68 | # Environment variables for Flask seed app 69 | 70 | export DEBUG="True" 71 | export SECRET_KEY="replaceme" 72 | export MAIL_PORT="587" 73 | export MAIL_SERVER="mail.google.com" 74 | export MAIL_USERNAME="user@example.com" 75 | export MAIL_PASSWORD="replaceme" 76 | ``` 77 | 78 | To add the variables to your environment you can source the file as part of your normal workflow: 79 | 80 | ```bash 81 | $ source /path/to/env-vars.sh 82 | ``` 83 | 84 | 1. Run development server 85 | 86 | ```bash 87 | $ python wsgi.py 88 | ``` 89 | 90 | View at http://127.0.0.1:5000 91 | 92 | 1. Frontend build scripts 93 | 94 | Install node dependencies: 95 | 96 | ```bash 97 | $ cd /path/to/flaskapp/static-src 98 | $ npm install 99 | ``` 100 | 101 | Run gulp: 102 | 103 | ```bash 104 | $ npm run build 105 | ``` 106 | 107 | ## Unittests ## 108 | 109 | To run all tests: 110 | 111 | ```bash 112 | $ nosetests 113 | ``` 114 | 115 | To run an individual test: 116 | 117 | ```bash 118 | $ nosetests tests/views/test_content.py 119 | ``` 120 | 121 | ## Contribute ## 122 | 123 | Contributions are welcome! If you'd like to report an issue or submit a pull request please use our github page: https://github.com/muicss/flaskapp. 124 | 125 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import os 2 | import ast 3 | import datetime 4 | 5 | basedir = os.path.abspath(os.path.dirname(__file__)) 6 | 7 | # Global 8 | DEBUG = ast.literal_eval(os.environ.get('DEBUG', 'False')) 9 | SECRET_KEY = os.environ.get('SECRET_KEY', 'replaceme') 10 | PERMANENT_SESSION_LIFETIME = datetime.timedelta(days=30) 11 | 12 | # SQLAlchemy 13 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db') 14 | SQLALCHEMY_TRACK_MODIFICATIONS = False # Will be false in Flask-SQLA v3 15 | 16 | # Flask-Mail 17 | MAIL_USE_TLS = True 18 | MAIL_DEFAULT_SENDER = 'Flaskapp ' 19 | MAIL_PORT = os.environ.get('MAIL_PORT') 20 | MAIL_SERVER = os.environ.get('MAIL_SERVER') 21 | MAIL_USERNAME = os.environ.get('MAIL_USERNAME') 22 | MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') 23 | MAIL_DEBUG = False 24 | -------------------------------------------------------------------------------- /flaskapp/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import logging 4 | import pkg_resources 5 | 6 | import cssutils 7 | from flask import Flask, g 8 | from flask_wtf import CSRFProtect 9 | from flask_login import current_user 10 | from flask_principal import Principal, UserNeed, identity_loaded 11 | 12 | from flaskapp.lib import template_helpers 13 | from flaskapp.meta import mail, db, lm 14 | from flaskapp.models import User 15 | from flaskapp.views import content, auth 16 | 17 | 18 | # suppress cssutils warning messages 19 | cssutils.log.setLevel(logging.CRITICAL) 20 | 21 | 22 | # ================================ 23 | # App creator method 24 | # ================================ 25 | def create_app(extra_config=None): 26 | """Create Flask app for Flaskapp 27 | """ 28 | app = Flask('flaskapp', 29 | template_folder='templates', 30 | static_folder='static') 31 | 32 | app.config.from_object('config') 33 | app.config.update(**(extra_config or {})) 34 | app.before_request(before_request) 35 | 36 | # import static file manifest 37 | js = pkg_resources.resource_string('flaskapp', '/static/rev-manifest.json') 38 | app.config['static_manifest'] = json.loads(js.decode('utf-8')) 39 | 40 | # configure jinja2 41 | app.jinja_env.globals.update({'h': template_helpers}) 42 | 43 | # add Flask-WTForms CSRF Protection 44 | CSRFProtect(app) 45 | 46 | # init Flask-SQLAlchemy 47 | db.init_app(app) 48 | 49 | # init Flask-Principal 50 | Principal(app) 51 | identity_loaded.connect(on_identity_loaded, app) 52 | 53 | # init Flask-Login 54 | lm.init_app(app) 55 | lm.login_view = 'auth.login' 56 | lm.user_loader(load_user) 57 | 58 | # init Flask-Mail 59 | mail.init_app(app) 60 | 61 | # register blueprints 62 | app.register_blueprint(content.bp) 63 | app.register_blueprint(auth.bp, url_prefix='/auth') 64 | 65 | return app 66 | 67 | 68 | # =============================== 69 | # Helper methods 70 | # =============================== 71 | def before_request(): 72 | """Add current user to g object 73 | """ 74 | g.user = current_user 75 | 76 | 77 | def load_user(id): 78 | """Method for LoginManager user_loader method 79 | """ 80 | return User.query.get(int(id)) 81 | 82 | 83 | def on_identity_loaded(sender, identity): 84 | """Method for Flask Principal identity load listener 85 | """ 86 | # set the identity user object 87 | identity.user = current_user 88 | 89 | if current_user.is_authenticated: 90 | # add UserNeed to identity 91 | identity.provides.add(UserNeed(current_user.id)) 92 | -------------------------------------------------------------------------------- /flaskapp/forms.py: -------------------------------------------------------------------------------- 1 | from flask import g 2 | from flask_wtf import FlaskForm 3 | from wtforms import (StringField, PasswordField, BooleanField, TextAreaField, 4 | FileField) 5 | from wtforms.validators import (InputRequired, Email, URL, EqualTo, 6 | ValidationError, StopValidation) 7 | from wtforms.widgets import PasswordInput, CheckboxInput 8 | 9 | from flaskapp.models import User 10 | from flaskapp.lib.util import verify_password_hash 11 | 12 | 13 | # ============================ 14 | # Auth forms 15 | # ============================ 16 | class LoginForm(FlaskForm): 17 | """Sign in form 18 | """ 19 | email = StringField( 20 | 'Email address', 21 | validators=[ 22 | InputRequired('Please enter your email address'), 23 | Email() 24 | ]) 25 | 26 | password = PasswordField( 27 | 'Password', 28 | widget=PasswordInput(hide_value=False), 29 | validators=[ 30 | InputRequired('Please enter your password') 31 | ]) 32 | 33 | remember_me = BooleanField( 34 | 'Remember me', 35 | widget=CheckboxInput(), 36 | default=True) 37 | 38 | def validate_password(form, field): 39 | """Verify password 40 | """ 41 | if not form.email.data: 42 | raise StopValidation() 43 | 44 | # get user and verify password 45 | u = User.query.filter(User.email == form.email.data).first() 46 | if not u or not verify_password_hash(field.data, u.password): 47 | raise ValidationError('Email and password must match') 48 | 49 | 50 | class CreateAccountForm(FlaskForm): 51 | """Create account form 52 | """ 53 | email = StringField( 54 | 'Email address', 55 | validators=[ 56 | InputRequired('Please enter an email address'), 57 | Email() 58 | ]) 59 | 60 | password = PasswordField( 61 | 'Password', 62 | widget=PasswordInput(hide_value=False), 63 | validators=[ 64 | InputRequired('Please choose a password'), 65 | EqualTo('password_confirm', message='Passwords must match') 66 | ]) 67 | 68 | password_confirm = PasswordField( 69 | 'Confirm Password', 70 | widget=PasswordInput(hide_value=False), 71 | validators=[ 72 | InputRequired('Please confirm your password') 73 | ]) 74 | 75 | newsletter = BooleanField( 76 | 'Please send me product updates', 77 | widget=CheckboxInput(), 78 | default=True 79 | ) 80 | 81 | def validate_email(form, field): 82 | """Check if email already exists 83 | """ 84 | u = User.query.filter(User.email == field.data).first() 85 | if u != None: 86 | raise ValidationError('Did your forget your password?') 87 | 88 | 89 | class ForgotPasswordForm(FlaskForm): 90 | email = StringField( 91 | 'Email address', 92 | validators=[ 93 | InputRequired('Please enter an email address'), 94 | Email() 95 | ]) 96 | 97 | def validate_email(form, field): 98 | """Check if email exists 99 | """ 100 | u = User.query.filter(User.email == field.data).first() 101 | if u == None: 102 | raise ValidationError('Sorry, %s is not registered' % field.data) 103 | 104 | 105 | class ResetPasswordForm(FlaskForm): 106 | password = PasswordField( 107 | 'New Password', 108 | widget=PasswordInput(hide_value=False), 109 | validators=[ 110 | InputRequired('Please choose a password'), 111 | EqualTo('password_confirm', message='Passwords must match') 112 | ]) 113 | 114 | password_confirm = PasswordField( 115 | 'Confirm Password', 116 | widget=PasswordInput(hide_value=False), 117 | validators=[ 118 | InputRequired('Please confirm your password') 119 | ]) 120 | 121 | 122 | # ==================================== 123 | # Miscellaneous forms 124 | # ==================================== 125 | class FeedbackForm(FlaskForm): 126 | """Feedback form 127 | """ 128 | email = StringField( 129 | 'From', 130 | validators=[ 131 | InputRequired('Please enter your email address'), 132 | Email() 133 | ]) 134 | 135 | message = TextAreaField() 136 | 137 | newsletter = BooleanField( 138 | 'Please send me product updates', 139 | widget=CheckboxInput(), 140 | default=True 141 | ) 142 | -------------------------------------------------------------------------------- /flaskapp/lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amorey/flaskapp/6f301397b3d45511d3360f50fc9ac375a4b60fb8/flaskapp/lib/__init__.py -------------------------------------------------------------------------------- /flaskapp/lib/template_helpers.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import pkg_resources 3 | 4 | from flask import current_app, url_for 5 | from markupsafe import Markup 6 | 7 | 8 | __all__ = ['datetime', 'javascript_tag', 'stylesheet_tag'] 9 | 10 | 11 | def javascript_tag(url): 12 | """Return html tag for external javascript file 13 | """ 14 | return Markup('' % url) 15 | 16 | 17 | def stylesheet_tag(url): 18 | """Return html tag for external stylesheet 19 | """ 20 | html = '' % url 22 | return Markup(html) 23 | 24 | 25 | def static(rel_pathname): 26 | """Returns url for cached file if available 27 | """ 28 | rel_pathname = rel_pathname.lstrip('/') 29 | 30 | # check if file is in manifest 31 | filename = current_app.config['static_manifest'].get(rel_pathname) 32 | 33 | if filename and current_app.config['DEBUG'] == False: 34 | filename = 'cache/' + filename 35 | else: 36 | filename = rel_pathname 37 | 38 | return url_for('static', filename=filename) 39 | -------------------------------------------------------------------------------- /flaskapp/lib/util.py: -------------------------------------------------------------------------------- 1 | import bcrypt 2 | 3 | 4 | def generate_password_hash(password): 5 | """Method to centralize the hashing of passwords 6 | """ 7 | password = password.encode('utf-8') 8 | return bcrypt.hashpw(password, bcrypt.gensalt(12)) 9 | 10 | 11 | def verify_password_hash(password, password_hash): 12 | """Method to centralize the verification of password hash 13 | """ 14 | password = password.encode('utf-8') 15 | return bcrypt.hashpw(password, password_hash) == password_hash 16 | -------------------------------------------------------------------------------- /flaskapp/meta.py: -------------------------------------------------------------------------------- 1 | from flask_mail import Mail 2 | from flask_sqlalchemy import SQLAlchemy 3 | from flask_login import LoginManager 4 | 5 | # Flask-Mail instance 6 | mail = Mail() 7 | 8 | # Flask-SQLAlchemy instance 9 | db = SQLAlchemy(session_options={'autocommit': True, 'autoflush': False}) 10 | 11 | # Flask-Login instance 12 | lm = LoginManager() 13 | -------------------------------------------------------------------------------- /flaskapp/models.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from flaskapp.meta import db 4 | 5 | 6 | # ================================ 7 | # Define models 8 | # ================================ 9 | class User(db.Model): 10 | """User object 11 | """ 12 | id = db.Column(db.Integer, primary_key=True) 13 | email = db.Column(db.String(120), index=True, unique=True, nullable=False) 14 | password = db.Column(db.String(60), index=True, nullable=False) 15 | is_verified = db.Column(db.Boolean(), default=False, nullable=False) 16 | password_reset_requests = db.relationship( 17 | 'PasswordResetRequest', 18 | backref=db.backref('user')) 19 | email_verification_requests = db.relationship( 20 | 'EmailVerificationRequest', 21 | backref=db.backref('user')) 22 | 23 | def __repr__(self): 24 | return '' % self.email 25 | 26 | # =========================== 27 | # Flask-Login methods 28 | # =========================== 29 | def is_authenticated(self): 30 | return True 31 | 32 | def is_active(self): 33 | return True 34 | 35 | def is_anonymous(self): 36 | return False 37 | 38 | def get_id(self): 39 | return self.id 40 | 41 | 42 | class PasswordResetRequest(db.Model): 43 | """PasswordResetRequest object 44 | """ 45 | key = db.Column(db.String(64), primary_key=True) 46 | fk_user = db.Column(db.Integer, db.ForeignKey('user.id')) 47 | create_ts = db.Column(db.DateTime, default=datetime.datetime.utcnow, \ 48 | nullable=False) 49 | 50 | 51 | class EmailVerificationRequest(db.Model): 52 | """EmailVerificationRequest object 53 | """ 54 | key = db.Column(db.String(64), primary_key=True) 55 | fk_user = db.Column(db.Integer, db.ForeignKey('user.id')) 56 | create_ts = db.Column(db.DateTime, default=datetime.datetime.utcnow, \ 57 | nullable=False) 58 | -------------------------------------------------------------------------------- /flaskapp/static/cache/style-06956745a2.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Flaskapp Global Stylesheet 3 | * @module global 4 | */ 5 | /** 6 | * Variables 7 | */ 8 | /** 9 | * Global CSS 10 | */ 11 | html, 12 | body { 13 | height: 100%; 14 | background-color: #eee; 15 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, Tahoma; 16 | } 17 | 18 | html, 19 | body, 20 | input, 21 | textarea, 22 | buttons { 23 | -webkit-font-smoothing: antialiased; 24 | -moz-osx-font-smoothing: grayscale; 25 | text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.004); 26 | } 27 | 28 | /** 29 | * Layout CSS 30 | */ 31 | #header { 32 | margin-bottom: 20px; 33 | } 34 | 35 | #wrapper { 36 | -webkit-box-sizing: border-box; 37 | box-sizing: border-box; 38 | min-height: 100%; 39 | margin-bottom: -80px; 40 | padding-bottom: 80px; 41 | } 42 | 43 | #footer { 44 | -webkit-box-sizing: border-box; 45 | box-sizing: border-box; 46 | height: 80px; 47 | line-height: 80px; 48 | background-color: #ccc; 49 | } 50 | 51 | #panel { 52 | -webkit-box-sizing: border-box; 53 | box-sizing: border-box; 54 | min-height: -o-calc(100vh - 200px); 55 | min-height: calc(100vh - 200px); 56 | } 57 | 58 | /** 59 | * Flash CSS 60 | */ 61 | #flash { 62 | position: fixed; 63 | top: 0; 64 | right: 0; 65 | } 66 | #flash li { 67 | font-size: 12px; 68 | color: #fff; 69 | background-color: red; 70 | padding: 1px 5px; 71 | margin: 2px; 72 | } 73 | 74 | /** 75 | * Header CSS 76 | */ 77 | #header td > a { 78 | color: #fff; 79 | } 80 | #header td > a:not(:last-child) { 81 | margin-right: 10px; 82 | } 83 | 84 | #header a[data-mui-toggle=dropdown] { 85 | color: #fff; 86 | cursor: pointer; 87 | } 88 | #header a[data-mui-toggle=dropdown] :hover { 89 | color: #fff; 90 | } 91 | 92 | /** 93 | * Modal CSS 94 | */ 95 | #modal-wrapper { 96 | min-height: 100%; 97 | margin-bottom: -50px; 98 | padding-bottom: 50px; 99 | } 100 | #modal-wrapper .mui-panel { 101 | margin: 0 auto 20px; 102 | } 103 | 104 | #modal-footer { 105 | height: 50px; 106 | text-align: center; 107 | } 108 | #modal-footer a { 109 | color: #333; 110 | } 111 | 112 | #modal-header-brand { 113 | color: #777; 114 | margin: 20px 0px; 115 | display: inline-block; 116 | font-size: 25px; 117 | } 118 | #modal-header-brand:hover { 119 | text-decoration: none; 120 | } 121 | #modal-header-brand img { 122 | height: 30px; 123 | width: 30px; 124 | position: relative; 125 | top: -3px; 126 | } -------------------------------------------------------------------------------- /flaskapp/static/cache/style-f797b9a07e.min.css: -------------------------------------------------------------------------------- 1 | body,html{height:100%;background-color:#eee;font-family:Helvetica Neue,Helvetica,Arial,Verdana,Tahoma}body,buttons,html,input,textarea{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-shadow:1px 1px 1px rgba(0,0,0,.004)}#header{margin-bottom:20px}#wrapper{min-height:100%;margin-bottom:-80px;padding-bottom:80px}#footer,#wrapper{box-sizing:border-box}#footer{height:80px;line-height:80px;background-color:#ccc}#panel{box-sizing:border-box;min-height:-o-calc(100vh - 200px);min-height:calc(100vh - 200px)}#flash{position:fixed;top:0;right:0}#flash li{font-size:12px;background-color:red;padding:1px 5px;margin:2px}#flash li,#header td>a{color:#fff}#header td>a:not(:last-child){margin-right:10px}#header a[data-mui-toggle=dropdown]{color:#fff;cursor:pointer}#header a[data-mui-toggle=dropdown] :hover{color:#fff}#modal-wrapper{min-height:100%;margin-bottom:-50px;padding-bottom:50px}#modal-wrapper .mui-panel{margin:0 auto 20px}#modal-footer{height:50px;text-align:center}#modal-footer a{color:#333}#modal-header-brand{color:#777;margin:20px 0;display:inline-block;font-size:25px}#modal-header-brand:hover{text-decoration:none}#modal-header-brand img{height:30px;width:30px;position:relative;top:-3px} -------------------------------------------------------------------------------- /flaskapp/static/cache/vendor/mui-0.9.17/email/mui-email-inline-65e896e92c.css: -------------------------------------------------------------------------------- 1 | body { 2 | width: 100% !important; 3 | min-width: 100%; 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | img { 9 | border: 0 none; 10 | height: auto; 11 | line-height: 100%; 12 | outline: none; 13 | text-decoration: none; 14 | } 15 | 16 | a img { 17 | border: 0 none; 18 | } 19 | 20 | table { 21 | border-spacing: 0; 22 | border-collapse: collapse; 23 | } 24 | 25 | td { 26 | padding: 0; 27 | text-align: left; 28 | word-break: break-word; 29 | -webkit-hyphens: auto; 30 | -moz-hyphens: auto; 31 | hyphens: auto; 32 | border-collapse: collapse !important; 33 | } 34 | 35 | table, td { 36 | mso-table-lspace: 0pt; 37 | mso-table-rspace: 0pt; 38 | } 39 | 40 | body, 41 | table, 42 | td, 43 | p, 44 | a, 45 | li, 46 | blockquote { 47 | -webkit-text-size-adjust: 100%; 48 | -ms-text-size-adjust: 100%; 49 | } 50 | 51 | img { 52 | -ms-interpolation-mode: bicubic; 53 | } 54 | 55 | /** 56 | * MUI Colors module 57 | */ 58 | /** 59 | * MUI Email Reboot 60 | */ 61 | body { 62 | color: #212121; 63 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, "Trebuchet MS"; 64 | font-weight: 400; 65 | font-size: 14px; 66 | line-height: 1.429; 67 | letter-spacing: 0.001em; 68 | background-color: #FFF; 69 | } 70 | 71 | a { 72 | color: #2196F3; 73 | text-decoration: none; 74 | } 75 | 76 | p { 77 | margin: 0 0 10px; 78 | } 79 | 80 | hr { 81 | color: #e0e0e0; 82 | background-color: #e0e0e0; 83 | height: 1px; 84 | border: none; 85 | } 86 | 87 | strong { 88 | font-weight: 700; 89 | } 90 | 91 | h1, h2, h3 { 92 | margin-top: 20px; 93 | margin-bottom: 10px; 94 | } 95 | 96 | h4, h5, h6 { 97 | margin-top: 10px; 98 | margin-bottom: 10px; 99 | } 100 | 101 | /** 102 | * MUI Email Body Component 103 | */ 104 | .mui-body { 105 | margin: 0; 106 | padding: 0; 107 | height: 100%; 108 | width: 100%; 109 | color: #212121; 110 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, "Trebuchet MS"; 111 | font-weight: 400; 112 | font-size: 14px; 113 | line-height: 1.429; 114 | letter-spacing: 0.001em; 115 | background-color: #FFF; 116 | } 117 | 118 | /** 119 | * MUI Email Buttons 120 | */ 121 | .mui-btn { 122 | cursor: pointer; 123 | white-space: nowrap; 124 | } 125 | 126 | a.mui-btn { 127 | font-weight: 500; 128 | font-size: 14px; 129 | color: #212121; 130 | line-height: 14px; 131 | letter-spacing: 0.03em; 132 | text-transform: uppercase; 133 | border-top: 1px solid transparent; 134 | border-left: 1px solid transparent; 135 | border-right: 1px solid transparent; 136 | border-bottom: 1px solid transparent; 137 | border-top: 1px solid #FFF; 138 | border-left: 1px solid #FFF; 139 | border-right: 1px solid #FFF; 140 | border-bottom: 1px solid #FFF; 141 | color: #212121; 142 | background-color: #FFF; 143 | display: inline-block; 144 | text-decoration: none; 145 | text-align: center; 146 | border-radius: 3px; 147 | padding: 10px 25px; 148 | background-color: transparent; 149 | } 150 | 151 | a.mui-btn.mui-btn--raised { 152 | border-top: 1px solid #f2f2f2; 153 | border-left: 1px solid #e6e6e6; 154 | border-right: 1px solid #e6e6e6; 155 | border-bottom: 2px solid #bababa; 156 | } 157 | 158 | a.mui-btn.mui-btn--flat { 159 | background-color: transparent; 160 | color: #212121; 161 | border-top: 1px solid transparent; 162 | border-left: 1px solid transparent; 163 | border-right: 1px solid transparent; 164 | border-bottom: 1px solid transparent; 165 | } 166 | 167 | a.mui-btn.mui-btn--primary { 168 | border-top: 1px solid #2196F3; 169 | border-left: 1px solid #2196F3; 170 | border-right: 1px solid #2196F3; 171 | border-bottom: 1px solid #2196F3; 172 | color: #FFF; 173 | background-color: #2196F3; 174 | } 175 | 176 | a.mui-btn.mui-btn--primary.mui-btn--raised { 177 | border-top: 1px solid #51adf6; 178 | border-left: 1px solid #2196F3; 179 | border-right: 1px solid #2196F3; 180 | border-bottom: 2px solid #0a6ebd; 181 | } 182 | 183 | a.mui-btn.mui-btn--primary.mui-btn--flat { 184 | background-color: transparent; 185 | color: #2196F3; 186 | border-top: 1px solid transparent; 187 | border-left: 1px solid transparent; 188 | border-right: 1px solid transparent; 189 | border-bottom: 1px solid transparent; 190 | } 191 | 192 | a.mui-btn.mui-btn--danger { 193 | border-top: 1px solid #F44336; 194 | border-left: 1px solid #F44336; 195 | border-right: 1px solid #F44336; 196 | border-bottom: 1px solid #F44336; 197 | color: #FFF; 198 | background-color: #F44336; 199 | } 200 | 201 | a.mui-btn.mui-btn--danger.mui-btn--raised { 202 | border-top: 1px solid #f77066; 203 | border-left: 1px solid #F44336; 204 | border-right: 1px solid #F44336; 205 | border-bottom: 2px solid #d2190b; 206 | } 207 | 208 | a.mui-btn.mui-btn--danger.mui-btn--flat { 209 | background-color: transparent; 210 | color: #F44336; 211 | border-top: 1px solid transparent; 212 | border-left: 1px solid transparent; 213 | border-right: 1px solid transparent; 214 | border-bottom: 1px solid transparent; 215 | } 216 | 217 | a.mui-btn.mui-btn--dark { 218 | border-top: 1px solid #424242; 219 | border-left: 1px solid #424242; 220 | border-right: 1px solid #424242; 221 | border-bottom: 1px solid #424242; 222 | color: #FFF; 223 | background-color: #424242; 224 | } 225 | 226 | a.mui-btn.mui-btn--dark.mui-btn--raised { 227 | border-top: 1px solid #5c5c5c; 228 | border-left: 1px solid #424242; 229 | border-right: 1px solid #424242; 230 | border-bottom: 2px solid #1c1c1c; 231 | } 232 | 233 | a.mui-btn.mui-btn--dark.mui-btn--flat { 234 | background-color: transparent; 235 | color: #424242; 236 | border-top: 1px solid transparent; 237 | border-left: 1px solid transparent; 238 | border-right: 1px solid transparent; 239 | border-bottom: 1px solid transparent; 240 | } 241 | 242 | a.mui-btn.mui-btn--accent { 243 | border-top: 1px solid #FF4081; 244 | border-left: 1px solid #FF4081; 245 | border-right: 1px solid #FF4081; 246 | border-bottom: 1px solid #FF4081; 247 | color: #FFF; 248 | background-color: #FF4081; 249 | } 250 | 251 | a.mui-btn.mui-btn--accent.mui-btn--raised { 252 | border-top: 1px solid #ff73a3; 253 | border-left: 1px solid #FF4081; 254 | border-right: 1px solid #FF4081; 255 | border-bottom: 2px solid #f30053; 256 | } 257 | 258 | a.mui-btn.mui-btn--accent.mui-btn--flat { 259 | background-color: transparent; 260 | color: #FF4081; 261 | border-top: 1px solid transparent; 262 | border-left: 1px solid transparent; 263 | border-right: 1px solid transparent; 264 | border-bottom: 1px solid transparent; 265 | } 266 | 267 | table.mui-btn > tr > td, 268 | table.mui-btn > tbody > tr > td { 269 | background-color: #FFF; 270 | } 271 | 272 | table.mui-btn > tr > td > a, 273 | table.mui-btn > tbody > tr > td > a { 274 | color: #212121; 275 | border-top: 1px solid #FFF; 276 | border-left: 1px solid #FFF; 277 | border-right: 1px solid #FFF; 278 | border-bottom: 1px solid #FFF; 279 | } 280 | 281 | table.mui-btn.mui-btn--raised > tr > td > a, 282 | table.mui-btn.mui-btn--raised > tbody > tr > td > a { 283 | border-top: 1px solid #f2f2f2; 284 | border-left: 1px solid #e6e6e6; 285 | border-right: 1px solid #e6e6e6; 286 | border-bottom: 2px solid #bababa; 287 | } 288 | 289 | table.mui-btn.mui-btn--flat > tr > td, 290 | table.mui-btn.mui-btn--flat > tbody > tr > td { 291 | background-color: transparent; 292 | } 293 | 294 | table.mui-btn.mui-btn--flat > tr > td > a, 295 | table.mui-btn.mui-btn--flat > tbody > tr > td > a { 296 | color: #212121; 297 | border-top: 1px solid transparent; 298 | border-left: 1px solid transparent; 299 | border-right: 1px solid transparent; 300 | border-bottom: 1px solid transparent; 301 | } 302 | 303 | table.mui-btn > tr > td, 304 | table.mui-btn > tbody > tr > td { 305 | border-radius: 3px; 306 | } 307 | 308 | table.mui-btn > tr > td > a, 309 | table.mui-btn > tbody > tr > td > a { 310 | font-weight: 500; 311 | font-size: 14px; 312 | color: #212121; 313 | line-height: 14px; 314 | letter-spacing: 0.03em; 315 | text-transform: uppercase; 316 | border-top: 1px solid transparent; 317 | border-left: 1px solid transparent; 318 | border-right: 1px solid transparent; 319 | border-bottom: 1px solid transparent; 320 | display: inline-block; 321 | text-decoration: none; 322 | text-align: center; 323 | border-radius: 3px; 324 | padding: 10px 25px; 325 | background-color: transparent; 326 | } 327 | 328 | table.mui-btn.mui-btn--primary > tr > td, 329 | table.mui-btn.mui-btn--primary > tbody > tr > td { 330 | background-color: #2196F3; 331 | } 332 | 333 | table.mui-btn.mui-btn--primary > tr > td > a, 334 | table.mui-btn.mui-btn--primary > tbody > tr > td > a { 335 | color: #FFF; 336 | border-top: 1px solid #2196F3; 337 | border-left: 1px solid #2196F3; 338 | border-right: 1px solid #2196F3; 339 | border-bottom: 1px solid #2196F3; 340 | } 341 | 342 | table.mui-btn.mui-btn--primary.mui-btn--raised > tr > td > a, 343 | table.mui-btn.mui-btn--primary.mui-btn--raised > tbody > tr > td > a { 344 | border-top: 1px solid #51adf6; 345 | border-left: 1px solid #2196F3; 346 | border-right: 1px solid #2196F3; 347 | border-bottom: 2px solid #0a6ebd; 348 | } 349 | 350 | table.mui-btn.mui-btn--primary.mui-btn--flat > tr > td, 351 | table.mui-btn.mui-btn--primary.mui-btn--flat > tbody > tr > td { 352 | background-color: transparent; 353 | } 354 | 355 | table.mui-btn.mui-btn--primary.mui-btn--flat > tr > td > a, 356 | table.mui-btn.mui-btn--primary.mui-btn--flat > tbody > tr > td > a { 357 | color: #2196F3; 358 | border-top: 1px solid transparent; 359 | border-left: 1px solid transparent; 360 | border-right: 1px solid transparent; 361 | border-bottom: 1px solid transparent; 362 | } 363 | 364 | table.mui-btn.mui-btn--danger > tr > td, 365 | table.mui-btn.mui-btn--danger > tbody > tr > td { 366 | background-color: #F44336; 367 | } 368 | 369 | table.mui-btn.mui-btn--danger > tr > td > a, 370 | table.mui-btn.mui-btn--danger > tbody > tr > td > a { 371 | color: #FFF; 372 | border-top: 1px solid #F44336; 373 | border-left: 1px solid #F44336; 374 | border-right: 1px solid #F44336; 375 | border-bottom: 1px solid #F44336; 376 | } 377 | 378 | table.mui-btn.mui-btn--danger.mui-btn--raised > tr > td > a, 379 | table.mui-btn.mui-btn--danger.mui-btn--raised > tbody > tr > td > a { 380 | border-top: 1px solid #f77066; 381 | border-left: 1px solid #F44336; 382 | border-right: 1px solid #F44336; 383 | border-bottom: 2px solid #d2190b; 384 | } 385 | 386 | table.mui-btn.mui-btn--danger.mui-btn--flat > tr > td, 387 | table.mui-btn.mui-btn--danger.mui-btn--flat > tbody > tr > td { 388 | background-color: transparent; 389 | } 390 | 391 | table.mui-btn.mui-btn--danger.mui-btn--flat > tr > td > a, 392 | table.mui-btn.mui-btn--danger.mui-btn--flat > tbody > tr > td > a { 393 | color: #F44336; 394 | border-top: 1px solid transparent; 395 | border-left: 1px solid transparent; 396 | border-right: 1px solid transparent; 397 | border-bottom: 1px solid transparent; 398 | } 399 | 400 | table.mui-btn.mui-btn--dark > tr > td, 401 | table.mui-btn.mui-btn--dark > tbody > tr > td { 402 | background-color: #424242; 403 | } 404 | 405 | table.mui-btn.mui-btn--dark > tr > td > a, 406 | table.mui-btn.mui-btn--dark > tbody > tr > td > a { 407 | color: #FFF; 408 | border-top: 1px solid #424242; 409 | border-left: 1px solid #424242; 410 | border-right: 1px solid #424242; 411 | border-bottom: 1px solid #424242; 412 | } 413 | 414 | table.mui-btn.mui-btn--dark.mui-btn--raised > tr > td > a, 415 | table.mui-btn.mui-btn--dark.mui-btn--raised > tbody > tr > td > a { 416 | border-top: 1px solid #5c5c5c; 417 | border-left: 1px solid #424242; 418 | border-right: 1px solid #424242; 419 | border-bottom: 2px solid #1c1c1c; 420 | } 421 | 422 | table.mui-btn.mui-btn--dark.mui-btn--flat > tr > td, 423 | table.mui-btn.mui-btn--dark.mui-btn--flat > tbody > tr > td { 424 | background-color: transparent; 425 | } 426 | 427 | table.mui-btn.mui-btn--dark.mui-btn--flat > tr > td > a, 428 | table.mui-btn.mui-btn--dark.mui-btn--flat > tbody > tr > td > a { 429 | color: #424242; 430 | border-top: 1px solid transparent; 431 | border-left: 1px solid transparent; 432 | border-right: 1px solid transparent; 433 | border-bottom: 1px solid transparent; 434 | } 435 | 436 | table.mui-btn.mui-btn--accent > tr > td, 437 | table.mui-btn.mui-btn--accent > tbody > tr > td { 438 | background-color: #FF4081; 439 | } 440 | 441 | table.mui-btn.mui-btn--accent > tr > td > a, 442 | table.mui-btn.mui-btn--accent > tbody > tr > td > a { 443 | color: #FFF; 444 | border-top: 1px solid #FF4081; 445 | border-left: 1px solid #FF4081; 446 | border-right: 1px solid #FF4081; 447 | border-bottom: 1px solid #FF4081; 448 | } 449 | 450 | table.mui-btn.mui-btn--accent.mui-btn--raised > tr > td > a, 451 | table.mui-btn.mui-btn--accent.mui-btn--raised > tbody > tr > td > a { 452 | border-top: 1px solid #ff73a3; 453 | border-left: 1px solid #FF4081; 454 | border-right: 1px solid #FF4081; 455 | border-bottom: 2px solid #f30053; 456 | } 457 | 458 | table.mui-btn.mui-btn--accent.mui-btn--flat > tr > td, 459 | table.mui-btn.mui-btn--accent.mui-btn--flat > tbody > tr > td { 460 | background-color: transparent; 461 | } 462 | 463 | table.mui-btn.mui-btn--accent.mui-btn--flat > tr > td > a, 464 | table.mui-btn.mui-btn--accent.mui-btn--flat > tbody > tr > td > a { 465 | color: #FF4081; 466 | border-top: 1px solid transparent; 467 | border-left: 1px solid transparent; 468 | border-right: 1px solid transparent; 469 | border-bottom: 1px solid transparent; 470 | } 471 | 472 | a.mui-btn--small, 473 | table.mui-btn--small > tr > td > a, 474 | table.mui-btn--small > tbody > tr > td > a { 475 | font-size: 13px; 476 | padding: 7.8px 15px; 477 | } 478 | 479 | a.mui-btn--large, 480 | table.mui-btn--large > tr > td > a, 481 | table.mui-btn--large > tbody > tr > td > a { 482 | font-size: 14px; 483 | padding: 19px 25px; 484 | } 485 | 486 | /** 487 | * MUI Email Containers 488 | */ 489 | .mui-container, .mui-container-fixed { 490 | max-width: 600px; 491 | display: block; 492 | margin: 0 auto; 493 | clear: both; 494 | text-align: left; 495 | padding-left: 15px; 496 | padding-right: 15px; 497 | } 498 | 499 | .mui-container-fixed { 500 | width: 600px; 501 | } 502 | 503 | /** 504 | * MUI Email Dividers 505 | */ 506 | .mui-divider { 507 | display: block; 508 | height: 1px; 509 | background-color: #e0e0e0; 510 | } 511 | 512 | .mui--divider-top { 513 | border-top: 1px solid #e0e0e0; 514 | } 515 | 516 | .mui--divider-bottom { 517 | border-bottom: 1px solid #e0e0e0; 518 | } 519 | 520 | .mui--divider-left { 521 | border-left: 1px solid #e0e0e0; 522 | } 523 | 524 | .mui--divider-right { 525 | border-right: 1px solid #e0e0e0; 526 | } 527 | 528 | /** 529 | * MUI Email Panel 530 | */ 531 | .mui-panel { 532 | padding: 15px; 533 | border-radius: 0; 534 | background-color: #FFF; 535 | border-top: 1px solid #ededed; 536 | border-left: 1px solid #e6e6e6; 537 | border-right: 1px solid #e6e6e6; 538 | border-bottom: 2px solid #d4d4d4; 539 | } 540 | 541 | /** 542 | * MUI Email Helpers 543 | */ 544 | .mui--text-left { 545 | text-align: left; 546 | } 547 | 548 | .mui--text-right { 549 | text-align: right; 550 | } 551 | 552 | .mui--text-center { 553 | text-align: center; 554 | } 555 | 556 | .mui--text-justify { 557 | text-align: justify; 558 | } 559 | 560 | .mui-image--fix { 561 | display: block; 562 | } 563 | 564 | .mui--text-dark { 565 | color: #212121; 566 | } 567 | 568 | .mui--text-dark-secondary { 569 | color: #757575; 570 | } 571 | 572 | .mui--text-dark-hint { 573 | color: #9e9e9e; 574 | } 575 | 576 | .mui--text-light { 577 | color: #FFF; 578 | } 579 | 580 | .mui--text-light-secondary { 581 | color: #b3b3b3; 582 | } 583 | 584 | .mui--text-light-hint { 585 | color: gray; 586 | } 587 | 588 | .mui--text-accent { 589 | color: #FF4081; 590 | } 591 | 592 | .mui--text-accent-secondary { 593 | color: #ff82ad; 594 | } 595 | 596 | .mui--text-accent-hint { 597 | color: #ffa6c4; 598 | } 599 | 600 | .mui--text-black { 601 | color: #000; 602 | } 603 | 604 | .mui--text-white { 605 | color: #FFF; 606 | } 607 | 608 | .mui--text-danger { 609 | color: #F44336; 610 | } 611 | 612 | /** 613 | * MUI Email Typography 614 | */ 615 | .mui--text-display4 { 616 | font-weight: 300; 617 | font-size: 112px; 618 | line-height: 112px; 619 | } 620 | 621 | .mui--text-display3 { 622 | font-weight: 400; 623 | font-size: 56px; 624 | line-height: 56px; 625 | } 626 | 627 | .mui--text-display2 { 628 | font-weight: 400; 629 | font-size: 45px; 630 | line-height: 48px; 631 | } 632 | 633 | .mui--text-display1, h1 { 634 | font-weight: 400; 635 | font-size: 34px; 636 | line-height: 40px; 637 | } 638 | 639 | .mui--text-headline, h2 { 640 | font-weight: 400; 641 | font-size: 24px; 642 | line-height: 32px; 643 | } 644 | 645 | .mui--text-title, h3 { 646 | font-weight: 400; 647 | font-size: 20px; 648 | line-height: 28px; 649 | } 650 | 651 | .mui--text-subhead, h4 { 652 | font-weight: 400; 653 | font-size: 16px; 654 | line-height: 24px; 655 | } 656 | 657 | .mui--text-body2, h5 { 658 | font-weight: 500; 659 | font-size: 14px; 660 | line-height: 24px; 661 | } 662 | 663 | .mui--text-body1 { 664 | font-weight: 400; 665 | font-size: 14px; 666 | line-height: 20px; 667 | } 668 | 669 | .mui--text-caption { 670 | font-weight: 400; 671 | font-size: 12px; 672 | line-height: 16px; 673 | } 674 | 675 | .mui--text-menu { 676 | font-weight: 500; 677 | font-size: 13px; 678 | line-height: 17px; 679 | } 680 | 681 | .mui--text-button { 682 | font-weight: 500; 683 | font-size: 14px; 684 | line-height: 18px; 685 | text-transform: uppercase; 686 | } 687 | -------------------------------------------------------------------------------- /flaskapp/static/cache/vendor/mui-0.9.17/email/mui-email-inline-rtl-6898316011.css: -------------------------------------------------------------------------------- 1 | body { 2 | width: 100% !important; 3 | min-width: 100%; 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | img { 9 | border: 0 none; 10 | height: auto; 11 | line-height: 100%; 12 | outline: none; 13 | text-decoration: none; 14 | } 15 | 16 | a img { 17 | border: 0 none; 18 | } 19 | 20 | table { 21 | border-spacing: 0; 22 | border-collapse: collapse; 23 | } 24 | 25 | td { 26 | padding: 0; 27 | text-align: right; 28 | word-break: break-word; 29 | -webkit-hyphens: auto; 30 | -moz-hyphens: auto; 31 | hyphens: auto; 32 | border-collapse: collapse !important; 33 | } 34 | 35 | table, td { 36 | mso-table-lspace: 0pt; 37 | mso-table-rspace: 0pt; 38 | } 39 | 40 | body, 41 | table, 42 | td, 43 | p, 44 | a, 45 | li, 46 | blockquote { 47 | -webkit-text-size-adjust: 100%; 48 | -ms-text-size-adjust: 100%; 49 | } 50 | 51 | img { 52 | -ms-interpolation-mode: bicubic; 53 | } 54 | 55 | /** 56 | * MUI Colors module 57 | */ 58 | /** 59 | * MUI Email Reboot 60 | */ 61 | body { 62 | color: #212121; 63 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, "Trebuchet MS"; 64 | font-weight: 400; 65 | font-size: 14px; 66 | line-height: 1.429; 67 | letter-spacing: 0.001em; 68 | background-color: #FFF; 69 | } 70 | 71 | a { 72 | color: #2196F3; 73 | text-decoration: none; 74 | } 75 | 76 | p { 77 | margin: 0 0 10px; 78 | } 79 | 80 | hr { 81 | color: #e0e0e0; 82 | background-color: #e0e0e0; 83 | height: 1px; 84 | border: none; 85 | } 86 | 87 | strong { 88 | font-weight: 700; 89 | } 90 | 91 | h1, h2, h3 { 92 | margin-top: 20px; 93 | margin-bottom: 10px; 94 | } 95 | 96 | h4, h5, h6 { 97 | margin-top: 10px; 98 | margin-bottom: 10px; 99 | } 100 | 101 | /** 102 | * MUI Email Body Component 103 | */ 104 | .mui-body { 105 | margin: 0; 106 | padding: 0; 107 | height: 100%; 108 | width: 100%; 109 | color: #212121; 110 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, "Trebuchet MS"; 111 | font-weight: 400; 112 | font-size: 14px; 113 | line-height: 1.429; 114 | letter-spacing: 0.001em; 115 | background-color: #FFF; 116 | } 117 | 118 | /** 119 | * MUI Email Buttons 120 | */ 121 | .mui-btn { 122 | cursor: pointer; 123 | white-space: nowrap; 124 | } 125 | 126 | a.mui-btn { 127 | font-weight: 500; 128 | font-size: 14px; 129 | color: #212121; 130 | line-height: 14px; 131 | letter-spacing: 0.03em; 132 | text-transform: uppercase; 133 | border-top: 1px solid transparent; 134 | border-right: 1px solid transparent; 135 | border-left: 1px solid transparent; 136 | border-bottom: 1px solid transparent; 137 | border-top: 1px solid #FFF; 138 | border-right: 1px solid #FFF; 139 | border-left: 1px solid #FFF; 140 | border-bottom: 1px solid #FFF; 141 | color: #212121; 142 | background-color: #FFF; 143 | display: inline-block; 144 | text-decoration: none; 145 | text-align: center; 146 | border-radius: 3px; 147 | padding: 10px 25px; 148 | background-color: transparent; 149 | } 150 | 151 | a.mui-btn.mui-btn--raised { 152 | border-top: 1px solid #f2f2f2; 153 | border-right: 1px solid #e6e6e6; 154 | border-left: 1px solid #e6e6e6; 155 | border-bottom: 2px solid #bababa; 156 | } 157 | 158 | a.mui-btn.mui-btn--flat { 159 | background-color: transparent; 160 | color: #212121; 161 | border-top: 1px solid transparent; 162 | border-right: 1px solid transparent; 163 | border-left: 1px solid transparent; 164 | border-bottom: 1px solid transparent; 165 | } 166 | 167 | a.mui-btn.mui-btn--primary { 168 | border-top: 1px solid #2196F3; 169 | border-right: 1px solid #2196F3; 170 | border-left: 1px solid #2196F3; 171 | border-bottom: 1px solid #2196F3; 172 | color: #FFF; 173 | background-color: #2196F3; 174 | } 175 | 176 | a.mui-btn.mui-btn--primary.mui-btn--raised { 177 | border-top: 1px solid #51adf6; 178 | border-right: 1px solid #2196F3; 179 | border-left: 1px solid #2196F3; 180 | border-bottom: 2px solid #0a6ebd; 181 | } 182 | 183 | a.mui-btn.mui-btn--primary.mui-btn--flat { 184 | background-color: transparent; 185 | color: #2196F3; 186 | border-top: 1px solid transparent; 187 | border-right: 1px solid transparent; 188 | border-left: 1px solid transparent; 189 | border-bottom: 1px solid transparent; 190 | } 191 | 192 | a.mui-btn.mui-btn--danger { 193 | border-top: 1px solid #F44336; 194 | border-right: 1px solid #F44336; 195 | border-left: 1px solid #F44336; 196 | border-bottom: 1px solid #F44336; 197 | color: #FFF; 198 | background-color: #F44336; 199 | } 200 | 201 | a.mui-btn.mui-btn--danger.mui-btn--raised { 202 | border-top: 1px solid #f77066; 203 | border-right: 1px solid #F44336; 204 | border-left: 1px solid #F44336; 205 | border-bottom: 2px solid #d2190b; 206 | } 207 | 208 | a.mui-btn.mui-btn--danger.mui-btn--flat { 209 | background-color: transparent; 210 | color: #F44336; 211 | border-top: 1px solid transparent; 212 | border-right: 1px solid transparent; 213 | border-left: 1px solid transparent; 214 | border-bottom: 1px solid transparent; 215 | } 216 | 217 | a.mui-btn.mui-btn--dark { 218 | border-top: 1px solid #424242; 219 | border-right: 1px solid #424242; 220 | border-left: 1px solid #424242; 221 | border-bottom: 1px solid #424242; 222 | color: #FFF; 223 | background-color: #424242; 224 | } 225 | 226 | a.mui-btn.mui-btn--dark.mui-btn--raised { 227 | border-top: 1px solid #5c5c5c; 228 | border-right: 1px solid #424242; 229 | border-left: 1px solid #424242; 230 | border-bottom: 2px solid #1c1c1c; 231 | } 232 | 233 | a.mui-btn.mui-btn--dark.mui-btn--flat { 234 | background-color: transparent; 235 | color: #424242; 236 | border-top: 1px solid transparent; 237 | border-right: 1px solid transparent; 238 | border-left: 1px solid transparent; 239 | border-bottom: 1px solid transparent; 240 | } 241 | 242 | a.mui-btn.mui-btn--accent { 243 | border-top: 1px solid #FF4081; 244 | border-right: 1px solid #FF4081; 245 | border-left: 1px solid #FF4081; 246 | border-bottom: 1px solid #FF4081; 247 | color: #FFF; 248 | background-color: #FF4081; 249 | } 250 | 251 | a.mui-btn.mui-btn--accent.mui-btn--raised { 252 | border-top: 1px solid #ff73a3; 253 | border-right: 1px solid #FF4081; 254 | border-left: 1px solid #FF4081; 255 | border-bottom: 2px solid #f30053; 256 | } 257 | 258 | a.mui-btn.mui-btn--accent.mui-btn--flat { 259 | background-color: transparent; 260 | color: #FF4081; 261 | border-top: 1px solid transparent; 262 | border-right: 1px solid transparent; 263 | border-left: 1px solid transparent; 264 | border-bottom: 1px solid transparent; 265 | } 266 | 267 | table.mui-btn > tr > td, 268 | table.mui-btn > tbody > tr > td { 269 | background-color: #FFF; 270 | } 271 | 272 | table.mui-btn > tr > td > a, 273 | table.mui-btn > tbody > tr > td > a { 274 | color: #212121; 275 | border-top: 1px solid #FFF; 276 | border-right: 1px solid #FFF; 277 | border-left: 1px solid #FFF; 278 | border-bottom: 1px solid #FFF; 279 | } 280 | 281 | table.mui-btn.mui-btn--raised > tr > td > a, 282 | table.mui-btn.mui-btn--raised > tbody > tr > td > a { 283 | border-top: 1px solid #f2f2f2; 284 | border-right: 1px solid #e6e6e6; 285 | border-left: 1px solid #e6e6e6; 286 | border-bottom: 2px solid #bababa; 287 | } 288 | 289 | table.mui-btn.mui-btn--flat > tr > td, 290 | table.mui-btn.mui-btn--flat > tbody > tr > td { 291 | background-color: transparent; 292 | } 293 | 294 | table.mui-btn.mui-btn--flat > tr > td > a, 295 | table.mui-btn.mui-btn--flat > tbody > tr > td > a { 296 | color: #212121; 297 | border-top: 1px solid transparent; 298 | border-right: 1px solid transparent; 299 | border-left: 1px solid transparent; 300 | border-bottom: 1px solid transparent; 301 | } 302 | 303 | table.mui-btn > tr > td, 304 | table.mui-btn > tbody > tr > td { 305 | border-radius: 3px; 306 | } 307 | 308 | table.mui-btn > tr > td > a, 309 | table.mui-btn > tbody > tr > td > a { 310 | font-weight: 500; 311 | font-size: 14px; 312 | color: #212121; 313 | line-height: 14px; 314 | letter-spacing: 0.03em; 315 | text-transform: uppercase; 316 | border-top: 1px solid transparent; 317 | border-right: 1px solid transparent; 318 | border-left: 1px solid transparent; 319 | border-bottom: 1px solid transparent; 320 | display: inline-block; 321 | text-decoration: none; 322 | text-align: center; 323 | border-radius: 3px; 324 | padding: 10px 25px; 325 | background-color: transparent; 326 | } 327 | 328 | table.mui-btn.mui-btn--primary > tr > td, 329 | table.mui-btn.mui-btn--primary > tbody > tr > td { 330 | background-color: #2196F3; 331 | } 332 | 333 | table.mui-btn.mui-btn--primary > tr > td > a, 334 | table.mui-btn.mui-btn--primary > tbody > tr > td > a { 335 | color: #FFF; 336 | border-top: 1px solid #2196F3; 337 | border-right: 1px solid #2196F3; 338 | border-left: 1px solid #2196F3; 339 | border-bottom: 1px solid #2196F3; 340 | } 341 | 342 | table.mui-btn.mui-btn--primary.mui-btn--raised > tr > td > a, 343 | table.mui-btn.mui-btn--primary.mui-btn--raised > tbody > tr > td > a { 344 | border-top: 1px solid #51adf6; 345 | border-right: 1px solid #2196F3; 346 | border-left: 1px solid #2196F3; 347 | border-bottom: 2px solid #0a6ebd; 348 | } 349 | 350 | table.mui-btn.mui-btn--primary.mui-btn--flat > tr > td, 351 | table.mui-btn.mui-btn--primary.mui-btn--flat > tbody > tr > td { 352 | background-color: transparent; 353 | } 354 | 355 | table.mui-btn.mui-btn--primary.mui-btn--flat > tr > td > a, 356 | table.mui-btn.mui-btn--primary.mui-btn--flat > tbody > tr > td > a { 357 | color: #2196F3; 358 | border-top: 1px solid transparent; 359 | border-right: 1px solid transparent; 360 | border-left: 1px solid transparent; 361 | border-bottom: 1px solid transparent; 362 | } 363 | 364 | table.mui-btn.mui-btn--danger > tr > td, 365 | table.mui-btn.mui-btn--danger > tbody > tr > td { 366 | background-color: #F44336; 367 | } 368 | 369 | table.mui-btn.mui-btn--danger > tr > td > a, 370 | table.mui-btn.mui-btn--danger > tbody > tr > td > a { 371 | color: #FFF; 372 | border-top: 1px solid #F44336; 373 | border-right: 1px solid #F44336; 374 | border-left: 1px solid #F44336; 375 | border-bottom: 1px solid #F44336; 376 | } 377 | 378 | table.mui-btn.mui-btn--danger.mui-btn--raised > tr > td > a, 379 | table.mui-btn.mui-btn--danger.mui-btn--raised > tbody > tr > td > a { 380 | border-top: 1px solid #f77066; 381 | border-right: 1px solid #F44336; 382 | border-left: 1px solid #F44336; 383 | border-bottom: 2px solid #d2190b; 384 | } 385 | 386 | table.mui-btn.mui-btn--danger.mui-btn--flat > tr > td, 387 | table.mui-btn.mui-btn--danger.mui-btn--flat > tbody > tr > td { 388 | background-color: transparent; 389 | } 390 | 391 | table.mui-btn.mui-btn--danger.mui-btn--flat > tr > td > a, 392 | table.mui-btn.mui-btn--danger.mui-btn--flat > tbody > tr > td > a { 393 | color: #F44336; 394 | border-top: 1px solid transparent; 395 | border-right: 1px solid transparent; 396 | border-left: 1px solid transparent; 397 | border-bottom: 1px solid transparent; 398 | } 399 | 400 | table.mui-btn.mui-btn--dark > tr > td, 401 | table.mui-btn.mui-btn--dark > tbody > tr > td { 402 | background-color: #424242; 403 | } 404 | 405 | table.mui-btn.mui-btn--dark > tr > td > a, 406 | table.mui-btn.mui-btn--dark > tbody > tr > td > a { 407 | color: #FFF; 408 | border-top: 1px solid #424242; 409 | border-right: 1px solid #424242; 410 | border-left: 1px solid #424242; 411 | border-bottom: 1px solid #424242; 412 | } 413 | 414 | table.mui-btn.mui-btn--dark.mui-btn--raised > tr > td > a, 415 | table.mui-btn.mui-btn--dark.mui-btn--raised > tbody > tr > td > a { 416 | border-top: 1px solid #5c5c5c; 417 | border-right: 1px solid #424242; 418 | border-left: 1px solid #424242; 419 | border-bottom: 2px solid #1c1c1c; 420 | } 421 | 422 | table.mui-btn.mui-btn--dark.mui-btn--flat > tr > td, 423 | table.mui-btn.mui-btn--dark.mui-btn--flat > tbody > tr > td { 424 | background-color: transparent; 425 | } 426 | 427 | table.mui-btn.mui-btn--dark.mui-btn--flat > tr > td > a, 428 | table.mui-btn.mui-btn--dark.mui-btn--flat > tbody > tr > td > a { 429 | color: #424242; 430 | border-top: 1px solid transparent; 431 | border-right: 1px solid transparent; 432 | border-left: 1px solid transparent; 433 | border-bottom: 1px solid transparent; 434 | } 435 | 436 | table.mui-btn.mui-btn--accent > tr > td, 437 | table.mui-btn.mui-btn--accent > tbody > tr > td { 438 | background-color: #FF4081; 439 | } 440 | 441 | table.mui-btn.mui-btn--accent > tr > td > a, 442 | table.mui-btn.mui-btn--accent > tbody > tr > td > a { 443 | color: #FFF; 444 | border-top: 1px solid #FF4081; 445 | border-right: 1px solid #FF4081; 446 | border-left: 1px solid #FF4081; 447 | border-bottom: 1px solid #FF4081; 448 | } 449 | 450 | table.mui-btn.mui-btn--accent.mui-btn--raised > tr > td > a, 451 | table.mui-btn.mui-btn--accent.mui-btn--raised > tbody > tr > td > a { 452 | border-top: 1px solid #ff73a3; 453 | border-right: 1px solid #FF4081; 454 | border-left: 1px solid #FF4081; 455 | border-bottom: 2px solid #f30053; 456 | } 457 | 458 | table.mui-btn.mui-btn--accent.mui-btn--flat > tr > td, 459 | table.mui-btn.mui-btn--accent.mui-btn--flat > tbody > tr > td { 460 | background-color: transparent; 461 | } 462 | 463 | table.mui-btn.mui-btn--accent.mui-btn--flat > tr > td > a, 464 | table.mui-btn.mui-btn--accent.mui-btn--flat > tbody > tr > td > a { 465 | color: #FF4081; 466 | border-top: 1px solid transparent; 467 | border-right: 1px solid transparent; 468 | border-left: 1px solid transparent; 469 | border-bottom: 1px solid transparent; 470 | } 471 | 472 | a.mui-btn--small, 473 | table.mui-btn--small > tr > td > a, 474 | table.mui-btn--small > tbody > tr > td > a { 475 | font-size: 13px; 476 | padding: 7.8px 15px; 477 | } 478 | 479 | a.mui-btn--large, 480 | table.mui-btn--large > tr > td > a, 481 | table.mui-btn--large > tbody > tr > td > a { 482 | font-size: 14px; 483 | padding: 19px 25px; 484 | } 485 | 486 | /** 487 | * MUI Email Containers 488 | */ 489 | .mui-container, .mui-container-fixed { 490 | max-width: 600px; 491 | display: block; 492 | margin: 0 auto; 493 | clear: both; 494 | text-align: right; 495 | padding-right: 15px; 496 | padding-left: 15px; 497 | } 498 | 499 | .mui-container-fixed { 500 | width: 600px; 501 | } 502 | 503 | /** 504 | * MUI Email Dividers 505 | */ 506 | .mui-divider { 507 | display: block; 508 | height: 1px; 509 | background-color: #e0e0e0; 510 | } 511 | 512 | .mui--divider-top { 513 | border-top: 1px solid #e0e0e0; 514 | } 515 | 516 | .mui--divider-bottom { 517 | border-bottom: 1px solid #e0e0e0; 518 | } 519 | 520 | .mui--divider-right { 521 | border-right: 1px solid #e0e0e0; 522 | } 523 | 524 | .mui--divider-left { 525 | border-left: 1px solid #e0e0e0; 526 | } 527 | 528 | /** 529 | * MUI Email Panel 530 | */ 531 | .mui-panel { 532 | padding: 15px; 533 | border-radius: 0; 534 | background-color: #FFF; 535 | border-top: 1px solid #ededed; 536 | border-right: 1px solid #e6e6e6; 537 | border-left: 1px solid #e6e6e6; 538 | border-bottom: 2px solid #d4d4d4; 539 | } 540 | 541 | /** 542 | * MUI Email Helpers 543 | */ 544 | .mui--text-left { 545 | text-align: right; 546 | } 547 | 548 | .mui--text-right { 549 | text-align: left; 550 | } 551 | 552 | .mui--text-center { 553 | text-align: center; 554 | } 555 | 556 | .mui--text-justify { 557 | text-align: justify; 558 | } 559 | 560 | .mui-image--fix { 561 | display: block; 562 | } 563 | 564 | .mui--text-dark { 565 | color: #212121; 566 | } 567 | 568 | .mui--text-dark-secondary { 569 | color: #757575; 570 | } 571 | 572 | .mui--text-dark-hint { 573 | color: #9e9e9e; 574 | } 575 | 576 | .mui--text-light { 577 | color: #FFF; 578 | } 579 | 580 | .mui--text-light-secondary { 581 | color: #b3b3b3; 582 | } 583 | 584 | .mui--text-light-hint { 585 | color: gray; 586 | } 587 | 588 | .mui--text-accent { 589 | color: #FF4081; 590 | } 591 | 592 | .mui--text-accent-secondary { 593 | color: #ff82ad; 594 | } 595 | 596 | .mui--text-accent-hint { 597 | color: #ffa6c4; 598 | } 599 | 600 | .mui--text-black { 601 | color: #000; 602 | } 603 | 604 | .mui--text-white { 605 | color: #FFF; 606 | } 607 | 608 | .mui--text-danger { 609 | color: #F44336; 610 | } 611 | 612 | /** 613 | * MUI Email Typography 614 | */ 615 | .mui--text-display4 { 616 | font-weight: 300; 617 | font-size: 112px; 618 | line-height: 112px; 619 | } 620 | 621 | .mui--text-display3 { 622 | font-weight: 400; 623 | font-size: 56px; 624 | line-height: 56px; 625 | } 626 | 627 | .mui--text-display2 { 628 | font-weight: 400; 629 | font-size: 45px; 630 | line-height: 48px; 631 | } 632 | 633 | .mui--text-display1, h1 { 634 | font-weight: 400; 635 | font-size: 34px; 636 | line-height: 40px; 637 | } 638 | 639 | .mui--text-headline, h2 { 640 | font-weight: 400; 641 | font-size: 24px; 642 | line-height: 32px; 643 | } 644 | 645 | .mui--text-title, h3 { 646 | font-weight: 400; 647 | font-size: 20px; 648 | line-height: 28px; 649 | } 650 | 651 | .mui--text-subhead, h4 { 652 | font-weight: 400; 653 | font-size: 16px; 654 | line-height: 24px; 655 | } 656 | 657 | .mui--text-body2, h5 { 658 | font-weight: 500; 659 | font-size: 14px; 660 | line-height: 24px; 661 | } 662 | 663 | .mui--text-body1 { 664 | font-weight: 400; 665 | font-size: 14px; 666 | line-height: 20px; 667 | } 668 | 669 | .mui--text-caption { 670 | font-weight: 400; 671 | font-size: 12px; 672 | line-height: 16px; 673 | } 674 | 675 | .mui--text-menu { 676 | font-weight: 500; 677 | font-size: 13px; 678 | line-height: 17px; 679 | } 680 | 681 | .mui--text-button { 682 | font-weight: 500; 683 | font-size: 14px; 684 | line-height: 18px; 685 | text-transform: uppercase; 686 | } 687 | html,body,.mui-body{direction:rtl;} -------------------------------------------------------------------------------- /flaskapp/static/cache/vendor/mui-0.9.17/email/mui-email-styletag-d8aa291e6d.css: -------------------------------------------------------------------------------- 1 | /** 2 | * MUI Colors module 3 | */ 4 | /** 5 | * MUI Email Styletag 6 | */ 7 | #outlook a { 8 | padding: 0; 9 | } 10 | 11 | .ReadMsgBody { 12 | width: 100%; 13 | } 14 | 15 | .ExternalClass { 16 | width: 100%; 17 | } 18 | 19 | .ExternalClass, 20 | .ExternalClass p, 21 | .ExternalClass span, 22 | .ExternalClass font, 23 | .ExternalClass td, 24 | .ExternalClass div { 25 | line-height: 100%; 26 | } 27 | 28 | .mui-container-fixed { 29 | width: 600px; 30 | display: block; 31 | margin: 0 auto; 32 | clear: both; 33 | text-align: left; 34 | padding-left: 15px; 35 | padding-right: 15px; 36 | } 37 | -------------------------------------------------------------------------------- /flaskapp/static/cache/vendor/mui-0.9.17/email/mui-email-styletag-rtl-c59925b8b2.css: -------------------------------------------------------------------------------- 1 | /** 2 | * MUI Colors module 3 | */ 4 | /** 5 | * MUI Email Styletag 6 | */ 7 | #outlook a { 8 | padding: 0; 9 | } 10 | 11 | .ReadMsgBody { 12 | width: 100%; 13 | } 14 | 15 | .ExternalClass { 16 | width: 100%; 17 | } 18 | 19 | .ExternalClass, 20 | .ExternalClass p, 21 | .ExternalClass span, 22 | .ExternalClass font, 23 | .ExternalClass td, 24 | .ExternalClass div { 25 | line-height: 100%; 26 | } 27 | 28 | .mui-container-fixed { 29 | width: 600px; 30 | display: block; 31 | margin: 0 auto; 32 | clear: both; 33 | text-align: right; 34 | padding-right: 15px; 35 | padding-left: 15px; 36 | } 37 | -------------------------------------------------------------------------------- /flaskapp/static/rev-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "style.css": "style-06956745a2.css", 3 | "style.min.css": "style-f797b9a07e.min.css", 4 | "vendor/mui-0.9.17/angular/mui-angular.js": "vendor/mui-0.9.17/angular/mui-angular-bca0010feb.js", 5 | "vendor/mui-0.9.17/angular/mui-angular.min.js": "vendor/mui-0.9.17/angular/mui-angular-de11fbdcc7.min.js", 6 | "vendor/mui-0.9.17/css/mui-rtl.css": "vendor/mui-0.9.17/css/mui-rtl-e660de5472.css", 7 | "vendor/mui-0.9.17/css/mui-rtl.min.css": "vendor/mui-0.9.17/css/mui-rtl-59fbfcbc8c.min.css", 8 | "vendor/mui-0.9.17/css/mui.css": "vendor/mui-0.9.17/css/mui-f33078ec84.css", 9 | "vendor/mui-0.9.17/css/mui.min.css": "vendor/mui-0.9.17/css/mui-f7be884ff8.min.css", 10 | "vendor/mui-0.9.17/email/mui-email-inline-rtl.css": "vendor/mui-0.9.17/email/mui-email-inline-rtl-6898316011.css", 11 | "vendor/mui-0.9.17/email/mui-email-inline.css": "vendor/mui-0.9.17/email/mui-email-inline-65e896e92c.css", 12 | "vendor/mui-0.9.17/email/mui-email-styletag-rtl.css": "vendor/mui-0.9.17/email/mui-email-styletag-rtl-c59925b8b2.css", 13 | "vendor/mui-0.9.17/email/mui-email-styletag.css": "vendor/mui-0.9.17/email/mui-email-styletag-d8aa291e6d.css", 14 | "vendor/mui-0.9.17/extra/mui-angular-combined.js": "vendor/mui-0.9.17/extra/mui-angular-combined-2ef86ce313.js", 15 | "vendor/mui-0.9.17/extra/mui-angular-combined.min.js": "vendor/mui-0.9.17/extra/mui-angular-combined-d3b8cca7fb.min.js", 16 | "vendor/mui-0.9.17/extra/mui-colors.css": "vendor/mui-0.9.17/extra/mui-colors-45b1960c08.css", 17 | "vendor/mui-0.9.17/extra/mui-colors.min.css": "vendor/mui-0.9.17/extra/mui-colors-8630fec18a.min.css", 18 | "vendor/mui-0.9.17/extra/mui-combined.js": "vendor/mui-0.9.17/extra/mui-combined-0cdbab1d4a.js", 19 | "vendor/mui-0.9.17/extra/mui-combined.min.js": "vendor/mui-0.9.17/extra/mui-combined-32029b42f0.min.js", 20 | "vendor/mui-0.9.17/extra/mui-noglobals-rtl.css": "vendor/mui-0.9.17/extra/mui-noglobals-rtl-05f9aeb9a3.css", 21 | "vendor/mui-0.9.17/extra/mui-noglobals-rtl.min.css": "vendor/mui-0.9.17/extra/mui-noglobals-rtl-21ee63aad1.min.css", 22 | "vendor/mui-0.9.17/extra/mui-noglobals.css": "vendor/mui-0.9.17/extra/mui-noglobals-ae15abfbb2.css", 23 | "vendor/mui-0.9.17/extra/mui-noglobals.min.css": "vendor/mui-0.9.17/extra/mui-noglobals-4b283fe32b.min.css", 24 | "vendor/mui-0.9.17/extra/mui-react-combined.js": "vendor/mui-0.9.17/extra/mui-react-combined-f4b51b1165.js", 25 | "vendor/mui-0.9.17/extra/mui-react-combined.min.js": "vendor/mui-0.9.17/extra/mui-react-combined-fe79856b81.min.js", 26 | "vendor/mui-0.9.17/js/mui.js": "vendor/mui-0.9.17/js/mui-45131227e5.js", 27 | "vendor/mui-0.9.17/js/mui.min.js": "vendor/mui-0.9.17/js/mui-b7b8f924a9.min.js", 28 | "vendor/mui-0.9.17/react/mui-react.js": "vendor/mui-0.9.17/react/mui-react-8b2bfeb3d6.js", 29 | "vendor/mui-0.9.17/react/mui-react.min.js": "vendor/mui-0.9.17/react/mui-react-96e0b6b0b0.min.js", 30 | "vendor/mui-0.9.17/webcomponents/mui-webcomponents.js": "vendor/mui-0.9.17/webcomponents/mui-webcomponents-a2432bac9e.js", 31 | "vendor/mui-0.9.17/webcomponents/mui-webcomponents.min.js": "vendor/mui-0.9.17/webcomponents/mui-webcomponents-347f2425c4.min.js" 32 | } -------------------------------------------------------------------------------- /flaskapp/static/style.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Flaskapp Global Stylesheet 3 | * @module global 4 | */ 5 | /** 6 | * Variables 7 | */ 8 | /** 9 | * Global CSS 10 | */ 11 | html, 12 | body { 13 | height: 100%; 14 | background-color: #eee; 15 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, Tahoma; 16 | } 17 | 18 | html, 19 | body, 20 | input, 21 | textarea, 22 | buttons { 23 | -webkit-font-smoothing: antialiased; 24 | -moz-osx-font-smoothing: grayscale; 25 | text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.004); 26 | } 27 | 28 | /** 29 | * Layout CSS 30 | */ 31 | #header { 32 | margin-bottom: 20px; 33 | } 34 | 35 | #wrapper { 36 | -webkit-box-sizing: border-box; 37 | box-sizing: border-box; 38 | min-height: 100%; 39 | margin-bottom: -80px; 40 | padding-bottom: 80px; 41 | } 42 | 43 | #footer { 44 | -webkit-box-sizing: border-box; 45 | box-sizing: border-box; 46 | height: 80px; 47 | line-height: 80px; 48 | background-color: #ccc; 49 | } 50 | 51 | #panel { 52 | -webkit-box-sizing: border-box; 53 | box-sizing: border-box; 54 | min-height: -o-calc(100vh - 200px); 55 | min-height: calc(100vh - 200px); 56 | } 57 | 58 | /** 59 | * Flash CSS 60 | */ 61 | #flash { 62 | position: fixed; 63 | top: 0; 64 | right: 0; 65 | } 66 | #flash li { 67 | font-size: 12px; 68 | color: #fff; 69 | background-color: red; 70 | padding: 1px 5px; 71 | margin: 2px; 72 | } 73 | 74 | /** 75 | * Header CSS 76 | */ 77 | #header td > a { 78 | color: #fff; 79 | } 80 | #header td > a:not(:last-child) { 81 | margin-right: 10px; 82 | } 83 | 84 | #header a[data-mui-toggle=dropdown] { 85 | color: #fff; 86 | cursor: pointer; 87 | } 88 | #header a[data-mui-toggle=dropdown] :hover { 89 | color: #fff; 90 | } 91 | 92 | /** 93 | * Modal CSS 94 | */ 95 | #modal-wrapper { 96 | min-height: 100%; 97 | margin-bottom: -50px; 98 | padding-bottom: 50px; 99 | } 100 | #modal-wrapper .mui-panel { 101 | margin: 0 auto 20px; 102 | } 103 | 104 | #modal-footer { 105 | height: 50px; 106 | text-align: center; 107 | } 108 | #modal-footer a { 109 | color: #333; 110 | } 111 | 112 | #modal-header-brand { 113 | color: #777; 114 | margin: 20px 0px; 115 | display: inline-block; 116 | font-size: 25px; 117 | } 118 | #modal-header-brand:hover { 119 | text-decoration: none; 120 | } 121 | #modal-header-brand img { 122 | height: 30px; 123 | width: 30px; 124 | position: relative; 125 | top: -3px; 126 | } -------------------------------------------------------------------------------- /flaskapp/static/style.min.css: -------------------------------------------------------------------------------- 1 | body,html{height:100%;background-color:#eee;font-family:Helvetica Neue,Helvetica,Arial,Verdana,Tahoma}body,buttons,html,input,textarea{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-shadow:1px 1px 1px rgba(0,0,0,.004)}#header{margin-bottom:20px}#wrapper{min-height:100%;margin-bottom:-80px;padding-bottom:80px}#footer,#wrapper{box-sizing:border-box}#footer{height:80px;line-height:80px;background-color:#ccc}#panel{box-sizing:border-box;min-height:-o-calc(100vh - 200px);min-height:calc(100vh - 200px)}#flash{position:fixed;top:0;right:0}#flash li{font-size:12px;background-color:red;padding:1px 5px;margin:2px}#flash li,#header td>a{color:#fff}#header td>a:not(:last-child){margin-right:10px}#header a[data-mui-toggle=dropdown]{color:#fff;cursor:pointer}#header a[data-mui-toggle=dropdown] :hover{color:#fff}#modal-wrapper{min-height:100%;margin-bottom:-50px;padding-bottom:50px}#modal-wrapper .mui-panel{margin:0 auto 20px}#modal-footer{height:50px;text-align:center}#modal-footer a{color:#333}#modal-header-brand{color:#777;margin:20px 0;display:inline-block;font-size:25px}#modal-header-brand:hover{text-decoration:none}#modal-header-brand img{height:30px;width:30px;position:relative;top:-3px} -------------------------------------------------------------------------------- /flaskapp/static/vendor/mui-0.9.17/email/mui-email-inline-rtl.css: -------------------------------------------------------------------------------- 1 | body { 2 | width: 100% !important; 3 | min-width: 100%; 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | img { 9 | border: 0 none; 10 | height: auto; 11 | line-height: 100%; 12 | outline: none; 13 | text-decoration: none; 14 | } 15 | 16 | a img { 17 | border: 0 none; 18 | } 19 | 20 | table { 21 | border-spacing: 0; 22 | border-collapse: collapse; 23 | } 24 | 25 | td { 26 | padding: 0; 27 | text-align: right; 28 | word-break: break-word; 29 | -webkit-hyphens: auto; 30 | -moz-hyphens: auto; 31 | hyphens: auto; 32 | border-collapse: collapse !important; 33 | } 34 | 35 | table, td { 36 | mso-table-lspace: 0pt; 37 | mso-table-rspace: 0pt; 38 | } 39 | 40 | body, 41 | table, 42 | td, 43 | p, 44 | a, 45 | li, 46 | blockquote { 47 | -webkit-text-size-adjust: 100%; 48 | -ms-text-size-adjust: 100%; 49 | } 50 | 51 | img { 52 | -ms-interpolation-mode: bicubic; 53 | } 54 | 55 | /** 56 | * MUI Colors module 57 | */ 58 | /** 59 | * MUI Email Reboot 60 | */ 61 | body { 62 | color: #212121; 63 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, "Trebuchet MS"; 64 | font-weight: 400; 65 | font-size: 14px; 66 | line-height: 1.429; 67 | letter-spacing: 0.001em; 68 | background-color: #FFF; 69 | } 70 | 71 | a { 72 | color: #2196F3; 73 | text-decoration: none; 74 | } 75 | 76 | p { 77 | margin: 0 0 10px; 78 | } 79 | 80 | hr { 81 | color: #e0e0e0; 82 | background-color: #e0e0e0; 83 | height: 1px; 84 | border: none; 85 | } 86 | 87 | strong { 88 | font-weight: 700; 89 | } 90 | 91 | h1, h2, h3 { 92 | margin-top: 20px; 93 | margin-bottom: 10px; 94 | } 95 | 96 | h4, h5, h6 { 97 | margin-top: 10px; 98 | margin-bottom: 10px; 99 | } 100 | 101 | /** 102 | * MUI Email Body Component 103 | */ 104 | .mui-body { 105 | margin: 0; 106 | padding: 0; 107 | height: 100%; 108 | width: 100%; 109 | color: #212121; 110 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, "Trebuchet MS"; 111 | font-weight: 400; 112 | font-size: 14px; 113 | line-height: 1.429; 114 | letter-spacing: 0.001em; 115 | background-color: #FFF; 116 | } 117 | 118 | /** 119 | * MUI Email Buttons 120 | */ 121 | .mui-btn { 122 | cursor: pointer; 123 | white-space: nowrap; 124 | } 125 | 126 | a.mui-btn { 127 | font-weight: 500; 128 | font-size: 14px; 129 | color: #212121; 130 | line-height: 14px; 131 | letter-spacing: 0.03em; 132 | text-transform: uppercase; 133 | border-top: 1px solid transparent; 134 | border-right: 1px solid transparent; 135 | border-left: 1px solid transparent; 136 | border-bottom: 1px solid transparent; 137 | border-top: 1px solid #FFF; 138 | border-right: 1px solid #FFF; 139 | border-left: 1px solid #FFF; 140 | border-bottom: 1px solid #FFF; 141 | color: #212121; 142 | background-color: #FFF; 143 | display: inline-block; 144 | text-decoration: none; 145 | text-align: center; 146 | border-radius: 3px; 147 | padding: 10px 25px; 148 | background-color: transparent; 149 | } 150 | 151 | a.mui-btn.mui-btn--raised { 152 | border-top: 1px solid #f2f2f2; 153 | border-right: 1px solid #e6e6e6; 154 | border-left: 1px solid #e6e6e6; 155 | border-bottom: 2px solid #bababa; 156 | } 157 | 158 | a.mui-btn.mui-btn--flat { 159 | background-color: transparent; 160 | color: #212121; 161 | border-top: 1px solid transparent; 162 | border-right: 1px solid transparent; 163 | border-left: 1px solid transparent; 164 | border-bottom: 1px solid transparent; 165 | } 166 | 167 | a.mui-btn.mui-btn--primary { 168 | border-top: 1px solid #2196F3; 169 | border-right: 1px solid #2196F3; 170 | border-left: 1px solid #2196F3; 171 | border-bottom: 1px solid #2196F3; 172 | color: #FFF; 173 | background-color: #2196F3; 174 | } 175 | 176 | a.mui-btn.mui-btn--primary.mui-btn--raised { 177 | border-top: 1px solid #51adf6; 178 | border-right: 1px solid #2196F3; 179 | border-left: 1px solid #2196F3; 180 | border-bottom: 2px solid #0a6ebd; 181 | } 182 | 183 | a.mui-btn.mui-btn--primary.mui-btn--flat { 184 | background-color: transparent; 185 | color: #2196F3; 186 | border-top: 1px solid transparent; 187 | border-right: 1px solid transparent; 188 | border-left: 1px solid transparent; 189 | border-bottom: 1px solid transparent; 190 | } 191 | 192 | a.mui-btn.mui-btn--danger { 193 | border-top: 1px solid #F44336; 194 | border-right: 1px solid #F44336; 195 | border-left: 1px solid #F44336; 196 | border-bottom: 1px solid #F44336; 197 | color: #FFF; 198 | background-color: #F44336; 199 | } 200 | 201 | a.mui-btn.mui-btn--danger.mui-btn--raised { 202 | border-top: 1px solid #f77066; 203 | border-right: 1px solid #F44336; 204 | border-left: 1px solid #F44336; 205 | border-bottom: 2px solid #d2190b; 206 | } 207 | 208 | a.mui-btn.mui-btn--danger.mui-btn--flat { 209 | background-color: transparent; 210 | color: #F44336; 211 | border-top: 1px solid transparent; 212 | border-right: 1px solid transparent; 213 | border-left: 1px solid transparent; 214 | border-bottom: 1px solid transparent; 215 | } 216 | 217 | a.mui-btn.mui-btn--dark { 218 | border-top: 1px solid #424242; 219 | border-right: 1px solid #424242; 220 | border-left: 1px solid #424242; 221 | border-bottom: 1px solid #424242; 222 | color: #FFF; 223 | background-color: #424242; 224 | } 225 | 226 | a.mui-btn.mui-btn--dark.mui-btn--raised { 227 | border-top: 1px solid #5c5c5c; 228 | border-right: 1px solid #424242; 229 | border-left: 1px solid #424242; 230 | border-bottom: 2px solid #1c1c1c; 231 | } 232 | 233 | a.mui-btn.mui-btn--dark.mui-btn--flat { 234 | background-color: transparent; 235 | color: #424242; 236 | border-top: 1px solid transparent; 237 | border-right: 1px solid transparent; 238 | border-left: 1px solid transparent; 239 | border-bottom: 1px solid transparent; 240 | } 241 | 242 | a.mui-btn.mui-btn--accent { 243 | border-top: 1px solid #FF4081; 244 | border-right: 1px solid #FF4081; 245 | border-left: 1px solid #FF4081; 246 | border-bottom: 1px solid #FF4081; 247 | color: #FFF; 248 | background-color: #FF4081; 249 | } 250 | 251 | a.mui-btn.mui-btn--accent.mui-btn--raised { 252 | border-top: 1px solid #ff73a3; 253 | border-right: 1px solid #FF4081; 254 | border-left: 1px solid #FF4081; 255 | border-bottom: 2px solid #f30053; 256 | } 257 | 258 | a.mui-btn.mui-btn--accent.mui-btn--flat { 259 | background-color: transparent; 260 | color: #FF4081; 261 | border-top: 1px solid transparent; 262 | border-right: 1px solid transparent; 263 | border-left: 1px solid transparent; 264 | border-bottom: 1px solid transparent; 265 | } 266 | 267 | table.mui-btn > tr > td, 268 | table.mui-btn > tbody > tr > td { 269 | background-color: #FFF; 270 | } 271 | 272 | table.mui-btn > tr > td > a, 273 | table.mui-btn > tbody > tr > td > a { 274 | color: #212121; 275 | border-top: 1px solid #FFF; 276 | border-right: 1px solid #FFF; 277 | border-left: 1px solid #FFF; 278 | border-bottom: 1px solid #FFF; 279 | } 280 | 281 | table.mui-btn.mui-btn--raised > tr > td > a, 282 | table.mui-btn.mui-btn--raised > tbody > tr > td > a { 283 | border-top: 1px solid #f2f2f2; 284 | border-right: 1px solid #e6e6e6; 285 | border-left: 1px solid #e6e6e6; 286 | border-bottom: 2px solid #bababa; 287 | } 288 | 289 | table.mui-btn.mui-btn--flat > tr > td, 290 | table.mui-btn.mui-btn--flat > tbody > tr > td { 291 | background-color: transparent; 292 | } 293 | 294 | table.mui-btn.mui-btn--flat > tr > td > a, 295 | table.mui-btn.mui-btn--flat > tbody > tr > td > a { 296 | color: #212121; 297 | border-top: 1px solid transparent; 298 | border-right: 1px solid transparent; 299 | border-left: 1px solid transparent; 300 | border-bottom: 1px solid transparent; 301 | } 302 | 303 | table.mui-btn > tr > td, 304 | table.mui-btn > tbody > tr > td { 305 | border-radius: 3px; 306 | } 307 | 308 | table.mui-btn > tr > td > a, 309 | table.mui-btn > tbody > tr > td > a { 310 | font-weight: 500; 311 | font-size: 14px; 312 | color: #212121; 313 | line-height: 14px; 314 | letter-spacing: 0.03em; 315 | text-transform: uppercase; 316 | border-top: 1px solid transparent; 317 | border-right: 1px solid transparent; 318 | border-left: 1px solid transparent; 319 | border-bottom: 1px solid transparent; 320 | display: inline-block; 321 | text-decoration: none; 322 | text-align: center; 323 | border-radius: 3px; 324 | padding: 10px 25px; 325 | background-color: transparent; 326 | } 327 | 328 | table.mui-btn.mui-btn--primary > tr > td, 329 | table.mui-btn.mui-btn--primary > tbody > tr > td { 330 | background-color: #2196F3; 331 | } 332 | 333 | table.mui-btn.mui-btn--primary > tr > td > a, 334 | table.mui-btn.mui-btn--primary > tbody > tr > td > a { 335 | color: #FFF; 336 | border-top: 1px solid #2196F3; 337 | border-right: 1px solid #2196F3; 338 | border-left: 1px solid #2196F3; 339 | border-bottom: 1px solid #2196F3; 340 | } 341 | 342 | table.mui-btn.mui-btn--primary.mui-btn--raised > tr > td > a, 343 | table.mui-btn.mui-btn--primary.mui-btn--raised > tbody > tr > td > a { 344 | border-top: 1px solid #51adf6; 345 | border-right: 1px solid #2196F3; 346 | border-left: 1px solid #2196F3; 347 | border-bottom: 2px solid #0a6ebd; 348 | } 349 | 350 | table.mui-btn.mui-btn--primary.mui-btn--flat > tr > td, 351 | table.mui-btn.mui-btn--primary.mui-btn--flat > tbody > tr > td { 352 | background-color: transparent; 353 | } 354 | 355 | table.mui-btn.mui-btn--primary.mui-btn--flat > tr > td > a, 356 | table.mui-btn.mui-btn--primary.mui-btn--flat > tbody > tr > td > a { 357 | color: #2196F3; 358 | border-top: 1px solid transparent; 359 | border-right: 1px solid transparent; 360 | border-left: 1px solid transparent; 361 | border-bottom: 1px solid transparent; 362 | } 363 | 364 | table.mui-btn.mui-btn--danger > tr > td, 365 | table.mui-btn.mui-btn--danger > tbody > tr > td { 366 | background-color: #F44336; 367 | } 368 | 369 | table.mui-btn.mui-btn--danger > tr > td > a, 370 | table.mui-btn.mui-btn--danger > tbody > tr > td > a { 371 | color: #FFF; 372 | border-top: 1px solid #F44336; 373 | border-right: 1px solid #F44336; 374 | border-left: 1px solid #F44336; 375 | border-bottom: 1px solid #F44336; 376 | } 377 | 378 | table.mui-btn.mui-btn--danger.mui-btn--raised > tr > td > a, 379 | table.mui-btn.mui-btn--danger.mui-btn--raised > tbody > tr > td > a { 380 | border-top: 1px solid #f77066; 381 | border-right: 1px solid #F44336; 382 | border-left: 1px solid #F44336; 383 | border-bottom: 2px solid #d2190b; 384 | } 385 | 386 | table.mui-btn.mui-btn--danger.mui-btn--flat > tr > td, 387 | table.mui-btn.mui-btn--danger.mui-btn--flat > tbody > tr > td { 388 | background-color: transparent; 389 | } 390 | 391 | table.mui-btn.mui-btn--danger.mui-btn--flat > tr > td > a, 392 | table.mui-btn.mui-btn--danger.mui-btn--flat > tbody > tr > td > a { 393 | color: #F44336; 394 | border-top: 1px solid transparent; 395 | border-right: 1px solid transparent; 396 | border-left: 1px solid transparent; 397 | border-bottom: 1px solid transparent; 398 | } 399 | 400 | table.mui-btn.mui-btn--dark > tr > td, 401 | table.mui-btn.mui-btn--dark > tbody > tr > td { 402 | background-color: #424242; 403 | } 404 | 405 | table.mui-btn.mui-btn--dark > tr > td > a, 406 | table.mui-btn.mui-btn--dark > tbody > tr > td > a { 407 | color: #FFF; 408 | border-top: 1px solid #424242; 409 | border-right: 1px solid #424242; 410 | border-left: 1px solid #424242; 411 | border-bottom: 1px solid #424242; 412 | } 413 | 414 | table.mui-btn.mui-btn--dark.mui-btn--raised > tr > td > a, 415 | table.mui-btn.mui-btn--dark.mui-btn--raised > tbody > tr > td > a { 416 | border-top: 1px solid #5c5c5c; 417 | border-right: 1px solid #424242; 418 | border-left: 1px solid #424242; 419 | border-bottom: 2px solid #1c1c1c; 420 | } 421 | 422 | table.mui-btn.mui-btn--dark.mui-btn--flat > tr > td, 423 | table.mui-btn.mui-btn--dark.mui-btn--flat > tbody > tr > td { 424 | background-color: transparent; 425 | } 426 | 427 | table.mui-btn.mui-btn--dark.mui-btn--flat > tr > td > a, 428 | table.mui-btn.mui-btn--dark.mui-btn--flat > tbody > tr > td > a { 429 | color: #424242; 430 | border-top: 1px solid transparent; 431 | border-right: 1px solid transparent; 432 | border-left: 1px solid transparent; 433 | border-bottom: 1px solid transparent; 434 | } 435 | 436 | table.mui-btn.mui-btn--accent > tr > td, 437 | table.mui-btn.mui-btn--accent > tbody > tr > td { 438 | background-color: #FF4081; 439 | } 440 | 441 | table.mui-btn.mui-btn--accent > tr > td > a, 442 | table.mui-btn.mui-btn--accent > tbody > tr > td > a { 443 | color: #FFF; 444 | border-top: 1px solid #FF4081; 445 | border-right: 1px solid #FF4081; 446 | border-left: 1px solid #FF4081; 447 | border-bottom: 1px solid #FF4081; 448 | } 449 | 450 | table.mui-btn.mui-btn--accent.mui-btn--raised > tr > td > a, 451 | table.mui-btn.mui-btn--accent.mui-btn--raised > tbody > tr > td > a { 452 | border-top: 1px solid #ff73a3; 453 | border-right: 1px solid #FF4081; 454 | border-left: 1px solid #FF4081; 455 | border-bottom: 2px solid #f30053; 456 | } 457 | 458 | table.mui-btn.mui-btn--accent.mui-btn--flat > tr > td, 459 | table.mui-btn.mui-btn--accent.mui-btn--flat > tbody > tr > td { 460 | background-color: transparent; 461 | } 462 | 463 | table.mui-btn.mui-btn--accent.mui-btn--flat > tr > td > a, 464 | table.mui-btn.mui-btn--accent.mui-btn--flat > tbody > tr > td > a { 465 | color: #FF4081; 466 | border-top: 1px solid transparent; 467 | border-right: 1px solid transparent; 468 | border-left: 1px solid transparent; 469 | border-bottom: 1px solid transparent; 470 | } 471 | 472 | a.mui-btn--small, 473 | table.mui-btn--small > tr > td > a, 474 | table.mui-btn--small > tbody > tr > td > a { 475 | font-size: 13px; 476 | padding: 7.8px 15px; 477 | } 478 | 479 | a.mui-btn--large, 480 | table.mui-btn--large > tr > td > a, 481 | table.mui-btn--large > tbody > tr > td > a { 482 | font-size: 14px; 483 | padding: 19px 25px; 484 | } 485 | 486 | /** 487 | * MUI Email Containers 488 | */ 489 | .mui-container, .mui-container-fixed { 490 | max-width: 600px; 491 | display: block; 492 | margin: 0 auto; 493 | clear: both; 494 | text-align: right; 495 | padding-right: 15px; 496 | padding-left: 15px; 497 | } 498 | 499 | .mui-container-fixed { 500 | width: 600px; 501 | } 502 | 503 | /** 504 | * MUI Email Dividers 505 | */ 506 | .mui-divider { 507 | display: block; 508 | height: 1px; 509 | background-color: #e0e0e0; 510 | } 511 | 512 | .mui--divider-top { 513 | border-top: 1px solid #e0e0e0; 514 | } 515 | 516 | .mui--divider-bottom { 517 | border-bottom: 1px solid #e0e0e0; 518 | } 519 | 520 | .mui--divider-right { 521 | border-right: 1px solid #e0e0e0; 522 | } 523 | 524 | .mui--divider-left { 525 | border-left: 1px solid #e0e0e0; 526 | } 527 | 528 | /** 529 | * MUI Email Panel 530 | */ 531 | .mui-panel { 532 | padding: 15px; 533 | border-radius: 0; 534 | background-color: #FFF; 535 | border-top: 1px solid #ededed; 536 | border-right: 1px solid #e6e6e6; 537 | border-left: 1px solid #e6e6e6; 538 | border-bottom: 2px solid #d4d4d4; 539 | } 540 | 541 | /** 542 | * MUI Email Helpers 543 | */ 544 | .mui--text-left { 545 | text-align: right; 546 | } 547 | 548 | .mui--text-right { 549 | text-align: left; 550 | } 551 | 552 | .mui--text-center { 553 | text-align: center; 554 | } 555 | 556 | .mui--text-justify { 557 | text-align: justify; 558 | } 559 | 560 | .mui-image--fix { 561 | display: block; 562 | } 563 | 564 | .mui--text-dark { 565 | color: #212121; 566 | } 567 | 568 | .mui--text-dark-secondary { 569 | color: #757575; 570 | } 571 | 572 | .mui--text-dark-hint { 573 | color: #9e9e9e; 574 | } 575 | 576 | .mui--text-light { 577 | color: #FFF; 578 | } 579 | 580 | .mui--text-light-secondary { 581 | color: #b3b3b3; 582 | } 583 | 584 | .mui--text-light-hint { 585 | color: gray; 586 | } 587 | 588 | .mui--text-accent { 589 | color: #FF4081; 590 | } 591 | 592 | .mui--text-accent-secondary { 593 | color: #ff82ad; 594 | } 595 | 596 | .mui--text-accent-hint { 597 | color: #ffa6c4; 598 | } 599 | 600 | .mui--text-black { 601 | color: #000; 602 | } 603 | 604 | .mui--text-white { 605 | color: #FFF; 606 | } 607 | 608 | .mui--text-danger { 609 | color: #F44336; 610 | } 611 | 612 | /** 613 | * MUI Email Typography 614 | */ 615 | .mui--text-display4 { 616 | font-weight: 300; 617 | font-size: 112px; 618 | line-height: 112px; 619 | } 620 | 621 | .mui--text-display3 { 622 | font-weight: 400; 623 | font-size: 56px; 624 | line-height: 56px; 625 | } 626 | 627 | .mui--text-display2 { 628 | font-weight: 400; 629 | font-size: 45px; 630 | line-height: 48px; 631 | } 632 | 633 | .mui--text-display1, h1 { 634 | font-weight: 400; 635 | font-size: 34px; 636 | line-height: 40px; 637 | } 638 | 639 | .mui--text-headline, h2 { 640 | font-weight: 400; 641 | font-size: 24px; 642 | line-height: 32px; 643 | } 644 | 645 | .mui--text-title, h3 { 646 | font-weight: 400; 647 | font-size: 20px; 648 | line-height: 28px; 649 | } 650 | 651 | .mui--text-subhead, h4 { 652 | font-weight: 400; 653 | font-size: 16px; 654 | line-height: 24px; 655 | } 656 | 657 | .mui--text-body2, h5 { 658 | font-weight: 500; 659 | font-size: 14px; 660 | line-height: 24px; 661 | } 662 | 663 | .mui--text-body1 { 664 | font-weight: 400; 665 | font-size: 14px; 666 | line-height: 20px; 667 | } 668 | 669 | .mui--text-caption { 670 | font-weight: 400; 671 | font-size: 12px; 672 | line-height: 16px; 673 | } 674 | 675 | .mui--text-menu { 676 | font-weight: 500; 677 | font-size: 13px; 678 | line-height: 17px; 679 | } 680 | 681 | .mui--text-button { 682 | font-weight: 500; 683 | font-size: 14px; 684 | line-height: 18px; 685 | text-transform: uppercase; 686 | } 687 | html,body,.mui-body{direction:rtl;} -------------------------------------------------------------------------------- /flaskapp/static/vendor/mui-0.9.17/email/mui-email-inline.css: -------------------------------------------------------------------------------- 1 | body { 2 | width: 100% !important; 3 | min-width: 100%; 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | img { 9 | border: 0 none; 10 | height: auto; 11 | line-height: 100%; 12 | outline: none; 13 | text-decoration: none; 14 | } 15 | 16 | a img { 17 | border: 0 none; 18 | } 19 | 20 | table { 21 | border-spacing: 0; 22 | border-collapse: collapse; 23 | } 24 | 25 | td { 26 | padding: 0; 27 | text-align: left; 28 | word-break: break-word; 29 | -webkit-hyphens: auto; 30 | -moz-hyphens: auto; 31 | hyphens: auto; 32 | border-collapse: collapse !important; 33 | } 34 | 35 | table, td { 36 | mso-table-lspace: 0pt; 37 | mso-table-rspace: 0pt; 38 | } 39 | 40 | body, 41 | table, 42 | td, 43 | p, 44 | a, 45 | li, 46 | blockquote { 47 | -webkit-text-size-adjust: 100%; 48 | -ms-text-size-adjust: 100%; 49 | } 50 | 51 | img { 52 | -ms-interpolation-mode: bicubic; 53 | } 54 | 55 | /** 56 | * MUI Colors module 57 | */ 58 | /** 59 | * MUI Email Reboot 60 | */ 61 | body { 62 | color: #212121; 63 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, "Trebuchet MS"; 64 | font-weight: 400; 65 | font-size: 14px; 66 | line-height: 1.429; 67 | letter-spacing: 0.001em; 68 | background-color: #FFF; 69 | } 70 | 71 | a { 72 | color: #2196F3; 73 | text-decoration: none; 74 | } 75 | 76 | p { 77 | margin: 0 0 10px; 78 | } 79 | 80 | hr { 81 | color: #e0e0e0; 82 | background-color: #e0e0e0; 83 | height: 1px; 84 | border: none; 85 | } 86 | 87 | strong { 88 | font-weight: 700; 89 | } 90 | 91 | h1, h2, h3 { 92 | margin-top: 20px; 93 | margin-bottom: 10px; 94 | } 95 | 96 | h4, h5, h6 { 97 | margin-top: 10px; 98 | margin-bottom: 10px; 99 | } 100 | 101 | /** 102 | * MUI Email Body Component 103 | */ 104 | .mui-body { 105 | margin: 0; 106 | padding: 0; 107 | height: 100%; 108 | width: 100%; 109 | color: #212121; 110 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, "Trebuchet MS"; 111 | font-weight: 400; 112 | font-size: 14px; 113 | line-height: 1.429; 114 | letter-spacing: 0.001em; 115 | background-color: #FFF; 116 | } 117 | 118 | /** 119 | * MUI Email Buttons 120 | */ 121 | .mui-btn { 122 | cursor: pointer; 123 | white-space: nowrap; 124 | } 125 | 126 | a.mui-btn { 127 | font-weight: 500; 128 | font-size: 14px; 129 | color: #212121; 130 | line-height: 14px; 131 | letter-spacing: 0.03em; 132 | text-transform: uppercase; 133 | border-top: 1px solid transparent; 134 | border-left: 1px solid transparent; 135 | border-right: 1px solid transparent; 136 | border-bottom: 1px solid transparent; 137 | border-top: 1px solid #FFF; 138 | border-left: 1px solid #FFF; 139 | border-right: 1px solid #FFF; 140 | border-bottom: 1px solid #FFF; 141 | color: #212121; 142 | background-color: #FFF; 143 | display: inline-block; 144 | text-decoration: none; 145 | text-align: center; 146 | border-radius: 3px; 147 | padding: 10px 25px; 148 | background-color: transparent; 149 | } 150 | 151 | a.mui-btn.mui-btn--raised { 152 | border-top: 1px solid #f2f2f2; 153 | border-left: 1px solid #e6e6e6; 154 | border-right: 1px solid #e6e6e6; 155 | border-bottom: 2px solid #bababa; 156 | } 157 | 158 | a.mui-btn.mui-btn--flat { 159 | background-color: transparent; 160 | color: #212121; 161 | border-top: 1px solid transparent; 162 | border-left: 1px solid transparent; 163 | border-right: 1px solid transparent; 164 | border-bottom: 1px solid transparent; 165 | } 166 | 167 | a.mui-btn.mui-btn--primary { 168 | border-top: 1px solid #2196F3; 169 | border-left: 1px solid #2196F3; 170 | border-right: 1px solid #2196F3; 171 | border-bottom: 1px solid #2196F3; 172 | color: #FFF; 173 | background-color: #2196F3; 174 | } 175 | 176 | a.mui-btn.mui-btn--primary.mui-btn--raised { 177 | border-top: 1px solid #51adf6; 178 | border-left: 1px solid #2196F3; 179 | border-right: 1px solid #2196F3; 180 | border-bottom: 2px solid #0a6ebd; 181 | } 182 | 183 | a.mui-btn.mui-btn--primary.mui-btn--flat { 184 | background-color: transparent; 185 | color: #2196F3; 186 | border-top: 1px solid transparent; 187 | border-left: 1px solid transparent; 188 | border-right: 1px solid transparent; 189 | border-bottom: 1px solid transparent; 190 | } 191 | 192 | a.mui-btn.mui-btn--danger { 193 | border-top: 1px solid #F44336; 194 | border-left: 1px solid #F44336; 195 | border-right: 1px solid #F44336; 196 | border-bottom: 1px solid #F44336; 197 | color: #FFF; 198 | background-color: #F44336; 199 | } 200 | 201 | a.mui-btn.mui-btn--danger.mui-btn--raised { 202 | border-top: 1px solid #f77066; 203 | border-left: 1px solid #F44336; 204 | border-right: 1px solid #F44336; 205 | border-bottom: 2px solid #d2190b; 206 | } 207 | 208 | a.mui-btn.mui-btn--danger.mui-btn--flat { 209 | background-color: transparent; 210 | color: #F44336; 211 | border-top: 1px solid transparent; 212 | border-left: 1px solid transparent; 213 | border-right: 1px solid transparent; 214 | border-bottom: 1px solid transparent; 215 | } 216 | 217 | a.mui-btn.mui-btn--dark { 218 | border-top: 1px solid #424242; 219 | border-left: 1px solid #424242; 220 | border-right: 1px solid #424242; 221 | border-bottom: 1px solid #424242; 222 | color: #FFF; 223 | background-color: #424242; 224 | } 225 | 226 | a.mui-btn.mui-btn--dark.mui-btn--raised { 227 | border-top: 1px solid #5c5c5c; 228 | border-left: 1px solid #424242; 229 | border-right: 1px solid #424242; 230 | border-bottom: 2px solid #1c1c1c; 231 | } 232 | 233 | a.mui-btn.mui-btn--dark.mui-btn--flat { 234 | background-color: transparent; 235 | color: #424242; 236 | border-top: 1px solid transparent; 237 | border-left: 1px solid transparent; 238 | border-right: 1px solid transparent; 239 | border-bottom: 1px solid transparent; 240 | } 241 | 242 | a.mui-btn.mui-btn--accent { 243 | border-top: 1px solid #FF4081; 244 | border-left: 1px solid #FF4081; 245 | border-right: 1px solid #FF4081; 246 | border-bottom: 1px solid #FF4081; 247 | color: #FFF; 248 | background-color: #FF4081; 249 | } 250 | 251 | a.mui-btn.mui-btn--accent.mui-btn--raised { 252 | border-top: 1px solid #ff73a3; 253 | border-left: 1px solid #FF4081; 254 | border-right: 1px solid #FF4081; 255 | border-bottom: 2px solid #f30053; 256 | } 257 | 258 | a.mui-btn.mui-btn--accent.mui-btn--flat { 259 | background-color: transparent; 260 | color: #FF4081; 261 | border-top: 1px solid transparent; 262 | border-left: 1px solid transparent; 263 | border-right: 1px solid transparent; 264 | border-bottom: 1px solid transparent; 265 | } 266 | 267 | table.mui-btn > tr > td, 268 | table.mui-btn > tbody > tr > td { 269 | background-color: #FFF; 270 | } 271 | 272 | table.mui-btn > tr > td > a, 273 | table.mui-btn > tbody > tr > td > a { 274 | color: #212121; 275 | border-top: 1px solid #FFF; 276 | border-left: 1px solid #FFF; 277 | border-right: 1px solid #FFF; 278 | border-bottom: 1px solid #FFF; 279 | } 280 | 281 | table.mui-btn.mui-btn--raised > tr > td > a, 282 | table.mui-btn.mui-btn--raised > tbody > tr > td > a { 283 | border-top: 1px solid #f2f2f2; 284 | border-left: 1px solid #e6e6e6; 285 | border-right: 1px solid #e6e6e6; 286 | border-bottom: 2px solid #bababa; 287 | } 288 | 289 | table.mui-btn.mui-btn--flat > tr > td, 290 | table.mui-btn.mui-btn--flat > tbody > tr > td { 291 | background-color: transparent; 292 | } 293 | 294 | table.mui-btn.mui-btn--flat > tr > td > a, 295 | table.mui-btn.mui-btn--flat > tbody > tr > td > a { 296 | color: #212121; 297 | border-top: 1px solid transparent; 298 | border-left: 1px solid transparent; 299 | border-right: 1px solid transparent; 300 | border-bottom: 1px solid transparent; 301 | } 302 | 303 | table.mui-btn > tr > td, 304 | table.mui-btn > tbody > tr > td { 305 | border-radius: 3px; 306 | } 307 | 308 | table.mui-btn > tr > td > a, 309 | table.mui-btn > tbody > tr > td > a { 310 | font-weight: 500; 311 | font-size: 14px; 312 | color: #212121; 313 | line-height: 14px; 314 | letter-spacing: 0.03em; 315 | text-transform: uppercase; 316 | border-top: 1px solid transparent; 317 | border-left: 1px solid transparent; 318 | border-right: 1px solid transparent; 319 | border-bottom: 1px solid transparent; 320 | display: inline-block; 321 | text-decoration: none; 322 | text-align: center; 323 | border-radius: 3px; 324 | padding: 10px 25px; 325 | background-color: transparent; 326 | } 327 | 328 | table.mui-btn.mui-btn--primary > tr > td, 329 | table.mui-btn.mui-btn--primary > tbody > tr > td { 330 | background-color: #2196F3; 331 | } 332 | 333 | table.mui-btn.mui-btn--primary > tr > td > a, 334 | table.mui-btn.mui-btn--primary > tbody > tr > td > a { 335 | color: #FFF; 336 | border-top: 1px solid #2196F3; 337 | border-left: 1px solid #2196F3; 338 | border-right: 1px solid #2196F3; 339 | border-bottom: 1px solid #2196F3; 340 | } 341 | 342 | table.mui-btn.mui-btn--primary.mui-btn--raised > tr > td > a, 343 | table.mui-btn.mui-btn--primary.mui-btn--raised > tbody > tr > td > a { 344 | border-top: 1px solid #51adf6; 345 | border-left: 1px solid #2196F3; 346 | border-right: 1px solid #2196F3; 347 | border-bottom: 2px solid #0a6ebd; 348 | } 349 | 350 | table.mui-btn.mui-btn--primary.mui-btn--flat > tr > td, 351 | table.mui-btn.mui-btn--primary.mui-btn--flat > tbody > tr > td { 352 | background-color: transparent; 353 | } 354 | 355 | table.mui-btn.mui-btn--primary.mui-btn--flat > tr > td > a, 356 | table.mui-btn.mui-btn--primary.mui-btn--flat > tbody > tr > td > a { 357 | color: #2196F3; 358 | border-top: 1px solid transparent; 359 | border-left: 1px solid transparent; 360 | border-right: 1px solid transparent; 361 | border-bottom: 1px solid transparent; 362 | } 363 | 364 | table.mui-btn.mui-btn--danger > tr > td, 365 | table.mui-btn.mui-btn--danger > tbody > tr > td { 366 | background-color: #F44336; 367 | } 368 | 369 | table.mui-btn.mui-btn--danger > tr > td > a, 370 | table.mui-btn.mui-btn--danger > tbody > tr > td > a { 371 | color: #FFF; 372 | border-top: 1px solid #F44336; 373 | border-left: 1px solid #F44336; 374 | border-right: 1px solid #F44336; 375 | border-bottom: 1px solid #F44336; 376 | } 377 | 378 | table.mui-btn.mui-btn--danger.mui-btn--raised > tr > td > a, 379 | table.mui-btn.mui-btn--danger.mui-btn--raised > tbody > tr > td > a { 380 | border-top: 1px solid #f77066; 381 | border-left: 1px solid #F44336; 382 | border-right: 1px solid #F44336; 383 | border-bottom: 2px solid #d2190b; 384 | } 385 | 386 | table.mui-btn.mui-btn--danger.mui-btn--flat > tr > td, 387 | table.mui-btn.mui-btn--danger.mui-btn--flat > tbody > tr > td { 388 | background-color: transparent; 389 | } 390 | 391 | table.mui-btn.mui-btn--danger.mui-btn--flat > tr > td > a, 392 | table.mui-btn.mui-btn--danger.mui-btn--flat > tbody > tr > td > a { 393 | color: #F44336; 394 | border-top: 1px solid transparent; 395 | border-left: 1px solid transparent; 396 | border-right: 1px solid transparent; 397 | border-bottom: 1px solid transparent; 398 | } 399 | 400 | table.mui-btn.mui-btn--dark > tr > td, 401 | table.mui-btn.mui-btn--dark > tbody > tr > td { 402 | background-color: #424242; 403 | } 404 | 405 | table.mui-btn.mui-btn--dark > tr > td > a, 406 | table.mui-btn.mui-btn--dark > tbody > tr > td > a { 407 | color: #FFF; 408 | border-top: 1px solid #424242; 409 | border-left: 1px solid #424242; 410 | border-right: 1px solid #424242; 411 | border-bottom: 1px solid #424242; 412 | } 413 | 414 | table.mui-btn.mui-btn--dark.mui-btn--raised > tr > td > a, 415 | table.mui-btn.mui-btn--dark.mui-btn--raised > tbody > tr > td > a { 416 | border-top: 1px solid #5c5c5c; 417 | border-left: 1px solid #424242; 418 | border-right: 1px solid #424242; 419 | border-bottom: 2px solid #1c1c1c; 420 | } 421 | 422 | table.mui-btn.mui-btn--dark.mui-btn--flat > tr > td, 423 | table.mui-btn.mui-btn--dark.mui-btn--flat > tbody > tr > td { 424 | background-color: transparent; 425 | } 426 | 427 | table.mui-btn.mui-btn--dark.mui-btn--flat > tr > td > a, 428 | table.mui-btn.mui-btn--dark.mui-btn--flat > tbody > tr > td > a { 429 | color: #424242; 430 | border-top: 1px solid transparent; 431 | border-left: 1px solid transparent; 432 | border-right: 1px solid transparent; 433 | border-bottom: 1px solid transparent; 434 | } 435 | 436 | table.mui-btn.mui-btn--accent > tr > td, 437 | table.mui-btn.mui-btn--accent > tbody > tr > td { 438 | background-color: #FF4081; 439 | } 440 | 441 | table.mui-btn.mui-btn--accent > tr > td > a, 442 | table.mui-btn.mui-btn--accent > tbody > tr > td > a { 443 | color: #FFF; 444 | border-top: 1px solid #FF4081; 445 | border-left: 1px solid #FF4081; 446 | border-right: 1px solid #FF4081; 447 | border-bottom: 1px solid #FF4081; 448 | } 449 | 450 | table.mui-btn.mui-btn--accent.mui-btn--raised > tr > td > a, 451 | table.mui-btn.mui-btn--accent.mui-btn--raised > tbody > tr > td > a { 452 | border-top: 1px solid #ff73a3; 453 | border-left: 1px solid #FF4081; 454 | border-right: 1px solid #FF4081; 455 | border-bottom: 2px solid #f30053; 456 | } 457 | 458 | table.mui-btn.mui-btn--accent.mui-btn--flat > tr > td, 459 | table.mui-btn.mui-btn--accent.mui-btn--flat > tbody > tr > td { 460 | background-color: transparent; 461 | } 462 | 463 | table.mui-btn.mui-btn--accent.mui-btn--flat > tr > td > a, 464 | table.mui-btn.mui-btn--accent.mui-btn--flat > tbody > tr > td > a { 465 | color: #FF4081; 466 | border-top: 1px solid transparent; 467 | border-left: 1px solid transparent; 468 | border-right: 1px solid transparent; 469 | border-bottom: 1px solid transparent; 470 | } 471 | 472 | a.mui-btn--small, 473 | table.mui-btn--small > tr > td > a, 474 | table.mui-btn--small > tbody > tr > td > a { 475 | font-size: 13px; 476 | padding: 7.8px 15px; 477 | } 478 | 479 | a.mui-btn--large, 480 | table.mui-btn--large > tr > td > a, 481 | table.mui-btn--large > tbody > tr > td > a { 482 | font-size: 14px; 483 | padding: 19px 25px; 484 | } 485 | 486 | /** 487 | * MUI Email Containers 488 | */ 489 | .mui-container, .mui-container-fixed { 490 | max-width: 600px; 491 | display: block; 492 | margin: 0 auto; 493 | clear: both; 494 | text-align: left; 495 | padding-left: 15px; 496 | padding-right: 15px; 497 | } 498 | 499 | .mui-container-fixed { 500 | width: 600px; 501 | } 502 | 503 | /** 504 | * MUI Email Dividers 505 | */ 506 | .mui-divider { 507 | display: block; 508 | height: 1px; 509 | background-color: #e0e0e0; 510 | } 511 | 512 | .mui--divider-top { 513 | border-top: 1px solid #e0e0e0; 514 | } 515 | 516 | .mui--divider-bottom { 517 | border-bottom: 1px solid #e0e0e0; 518 | } 519 | 520 | .mui--divider-left { 521 | border-left: 1px solid #e0e0e0; 522 | } 523 | 524 | .mui--divider-right { 525 | border-right: 1px solid #e0e0e0; 526 | } 527 | 528 | /** 529 | * MUI Email Panel 530 | */ 531 | .mui-panel { 532 | padding: 15px; 533 | border-radius: 0; 534 | background-color: #FFF; 535 | border-top: 1px solid #ededed; 536 | border-left: 1px solid #e6e6e6; 537 | border-right: 1px solid #e6e6e6; 538 | border-bottom: 2px solid #d4d4d4; 539 | } 540 | 541 | /** 542 | * MUI Email Helpers 543 | */ 544 | .mui--text-left { 545 | text-align: left; 546 | } 547 | 548 | .mui--text-right { 549 | text-align: right; 550 | } 551 | 552 | .mui--text-center { 553 | text-align: center; 554 | } 555 | 556 | .mui--text-justify { 557 | text-align: justify; 558 | } 559 | 560 | .mui-image--fix { 561 | display: block; 562 | } 563 | 564 | .mui--text-dark { 565 | color: #212121; 566 | } 567 | 568 | .mui--text-dark-secondary { 569 | color: #757575; 570 | } 571 | 572 | .mui--text-dark-hint { 573 | color: #9e9e9e; 574 | } 575 | 576 | .mui--text-light { 577 | color: #FFF; 578 | } 579 | 580 | .mui--text-light-secondary { 581 | color: #b3b3b3; 582 | } 583 | 584 | .mui--text-light-hint { 585 | color: gray; 586 | } 587 | 588 | .mui--text-accent { 589 | color: #FF4081; 590 | } 591 | 592 | .mui--text-accent-secondary { 593 | color: #ff82ad; 594 | } 595 | 596 | .mui--text-accent-hint { 597 | color: #ffa6c4; 598 | } 599 | 600 | .mui--text-black { 601 | color: #000; 602 | } 603 | 604 | .mui--text-white { 605 | color: #FFF; 606 | } 607 | 608 | .mui--text-danger { 609 | color: #F44336; 610 | } 611 | 612 | /** 613 | * MUI Email Typography 614 | */ 615 | .mui--text-display4 { 616 | font-weight: 300; 617 | font-size: 112px; 618 | line-height: 112px; 619 | } 620 | 621 | .mui--text-display3 { 622 | font-weight: 400; 623 | font-size: 56px; 624 | line-height: 56px; 625 | } 626 | 627 | .mui--text-display2 { 628 | font-weight: 400; 629 | font-size: 45px; 630 | line-height: 48px; 631 | } 632 | 633 | .mui--text-display1, h1 { 634 | font-weight: 400; 635 | font-size: 34px; 636 | line-height: 40px; 637 | } 638 | 639 | .mui--text-headline, h2 { 640 | font-weight: 400; 641 | font-size: 24px; 642 | line-height: 32px; 643 | } 644 | 645 | .mui--text-title, h3 { 646 | font-weight: 400; 647 | font-size: 20px; 648 | line-height: 28px; 649 | } 650 | 651 | .mui--text-subhead, h4 { 652 | font-weight: 400; 653 | font-size: 16px; 654 | line-height: 24px; 655 | } 656 | 657 | .mui--text-body2, h5 { 658 | font-weight: 500; 659 | font-size: 14px; 660 | line-height: 24px; 661 | } 662 | 663 | .mui--text-body1 { 664 | font-weight: 400; 665 | font-size: 14px; 666 | line-height: 20px; 667 | } 668 | 669 | .mui--text-caption { 670 | font-weight: 400; 671 | font-size: 12px; 672 | line-height: 16px; 673 | } 674 | 675 | .mui--text-menu { 676 | font-weight: 500; 677 | font-size: 13px; 678 | line-height: 17px; 679 | } 680 | 681 | .mui--text-button { 682 | font-weight: 500; 683 | font-size: 14px; 684 | line-height: 18px; 685 | text-transform: uppercase; 686 | } 687 | -------------------------------------------------------------------------------- /flaskapp/static/vendor/mui-0.9.17/email/mui-email-styletag-rtl.css: -------------------------------------------------------------------------------- 1 | /** 2 | * MUI Colors module 3 | */ 4 | /** 5 | * MUI Email Styletag 6 | */ 7 | #outlook a { 8 | padding: 0; 9 | } 10 | 11 | .ReadMsgBody { 12 | width: 100%; 13 | } 14 | 15 | .ExternalClass { 16 | width: 100%; 17 | } 18 | 19 | .ExternalClass, 20 | .ExternalClass p, 21 | .ExternalClass span, 22 | .ExternalClass font, 23 | .ExternalClass td, 24 | .ExternalClass div { 25 | line-height: 100%; 26 | } 27 | 28 | .mui-container-fixed { 29 | width: 600px; 30 | display: block; 31 | margin: 0 auto; 32 | clear: both; 33 | text-align: right; 34 | padding-right: 15px; 35 | padding-left: 15px; 36 | } 37 | -------------------------------------------------------------------------------- /flaskapp/static/vendor/mui-0.9.17/email/mui-email-styletag.css: -------------------------------------------------------------------------------- 1 | /** 2 | * MUI Colors module 3 | */ 4 | /** 5 | * MUI Email Styletag 6 | */ 7 | #outlook a { 8 | padding: 0; 9 | } 10 | 11 | .ReadMsgBody { 12 | width: 100%; 13 | } 14 | 15 | .ExternalClass { 16 | width: 100%; 17 | } 18 | 19 | .ExternalClass, 20 | .ExternalClass p, 21 | .ExternalClass span, 22 | .ExternalClass font, 23 | .ExternalClass td, 24 | .ExternalClass div { 25 | line-height: 100%; 26 | } 27 | 28 | .mui-container-fixed { 29 | width: 600px; 30 | display: block; 31 | margin: 0 auto; 32 | clear: both; 33 | text-align: left; 34 | padding-left: 15px; 35 | padding-right: 15px; 36 | } 37 | -------------------------------------------------------------------------------- /flaskapp/static/vendor/mui-0.9.17/js/mui.min.js: -------------------------------------------------------------------------------- 1 | !function t(e,i,n){function o(s,a){if(!i[s]){if(!e[s]){var l="function"==typeof require&&require;if(!a&&l)return l(s,!0);if(r)return r(s,!0);throw new Error("Cannot find module '"+s+"'")}var u=i[s]={exports:{}};e[s][0].call(u.exports,function(t){var i=e[s][1][t];return o(i||t)},u,u.exports,t,e,i,n)}return i[s].exports}for(var r="function"==typeof require&&require,s=0;s input","mui-textfield-inserted"],[".mui-textfield > textarea","mui-textfield-inserted"],[".mui-textfield > input:-webkit-autofill","mui-textfield-autofill"],[".mui-textfield > textarea:-webkit-autofill","mui-textfield-autofill"],[".mui-select > select","mui-select-inserted"],[".mui-select > select ~ .mui-event-trigger","mui-node-inserted"],[".mui-select > select:disabled ~ .mui-event-trigger","mui-node-disabled"]],i="",n=0,o=e.length;nd&&(p=s+(i+1)*r-(-1*a+n+o),h=e*r+2*s-f,v=Math.min(p,h)),{height:f+"px",top:a+"px",scrollTop:v}}}},{}],5:[function(t,e,i){"use strict";function n(t){if(void 0===t)return"undefined";var e=Object.prototype.toString.call(t);if(0===e.indexOf("[object "))return e.slice(8,-1).toLowerCase();throw new Error("MUI: Could not understand type: "+e)}function o(t,e,i,n){n=void 0!==n&&n;var o=t._muiEventCache=t._muiEventCache||{};e.split(" ").map(function(e){t.addEventListener(e,i,n),o[e]=o[e]||[],o[e].push([i,n])})}function r(t,e,i,n){n=void 0!==n&&n;var o,r,s,a=t._muiEventCache=t._muiEventCache||{};e.split(" ").map(function(e){for(s=(o=a[e]||[]).length;s--;)r=o[s],(void 0===i||r[0]===i&&r[1]===n)&&(o.splice(s,1),t.removeEventListener(e,r[0],r[1]))})}function s(t,e){var i=window;if(void 0===e){if(t===i){var n=document.documentElement;return(i.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}return t.scrollLeft}t===i?i.scrollTo(e,a(i)):t.scrollLeft=e}function a(t,e){var i=window;if(void 0===e){if(t===i){var n=document.documentElement;return(i.pageYOffset||n.scrollTop)-(n.clientTop||0)}return t.scrollTop}t===i?i.scrollTo(s(i),e):t.scrollTop=e}function l(t){return" "+(t.getAttribute("class")||"").replace(/[\n\t]/g,"")+" "}function u(t){return t.replace(d,function(t,e,i,n){return n?i.toUpperCase():i}).replace(m,"Moz$1")}function c(t,e,i){var n;return""!==(n=i.getPropertyValue(e))||t.ownerDocument||(n=t.style[u(e)]),n}var d=/([\:\-\_]+(.))/g,m=/^moz([A-Z])/;e.exports={addClass:function(t,e){if(e&&t.setAttribute){for(var i,n=l(t),o=e.split(" "),r=0;r-1},off:r,offset:function(t){var e=window,i=t.getBoundingClientRect(),n=a(e),o=s(e);return{top:i.top+n,left:i.left+o,height:i.height,width:i.width}},on:o,one:function(t,e,i,n){e.split(" ").map(function(e){o(t,e,function o(s){i&&i.apply(this,arguments),r(t,e,o,n)},n)})},ready:function(t){var e=!1,i=!0,n=document,o=n.defaultView,r=n.documentElement,s=n.addEventListener?"addEventListener":"attachEvent",a=n.addEventListener?"removeEventListener":"detachEvent",l=n.addEventListener?"":"on",u=function(i){"readystatechange"==i.type&&"complete"!=n.readyState||(("load"==i.type?o:n)[a](l+i.type,u,!1),!e&&(e=!0)&&t.call(o,i.type||i))},c=function(){try{r.doScroll("left")}catch(t){return void setTimeout(c,50)}u("poll")};if("complete"==n.readyState)t.call(o,"lazy");else{if(n.createEventObject&&r.doScroll){try{i=!o.frameElement}catch(t){}i&&c()}n[s](l+"DOMContentLoaded",u,!1),n[s](l+"readystatechange",u,!1),o[s](l+"load",u,!1)}},removeClass:function(t,e){if(e&&t.setAttribute){for(var i,n=l(t),o=e.split(" "),r=0;r=0;)n=n.replace(" "+i+" "," ");t.setAttribute("class",n.trim())}},type:n,scrollLeft:s,scrollTop:a}},{}],6:[function(t,e,i){"use strict";function n(t){var e,i=document;e=i.head||i.getElementsByTagName("head")[0]||i.documentElement;var n=i.createElement("style");return n.type="text/css",n.styleSheet?n.styleSheet.cssText=t:n.appendChild(i.createTextNode(t)),e.insertBefore(n,e.firstChild),n}var o,r,s,a,l,u=t("../config"),c=t("./jqLite"),d=0,m="mui-scroll-lock";s=function(t){t.target.tagName||t.stopImmediatePropagation()};var f=function(){if(void 0!==a)return a;var t=document,e=t.body,i=t.createElement("div");return i.innerHTML='
',i=i.firstChild,e.appendChild(i),a=i.offsetWidth-i.clientWidth,e.removeChild(i),a};e.exports={callback:function(t,e){return function(){t[e].apply(t,arguments)}},classNames:function(t){var e="";for(var i in t)e+=t[i]?i+" ":"";return e.trim()},disableScrollLock:function(t){0!==d&&0==(d-=1)&&(c.removeClass(document.body,m),r.parentNode.removeChild(r),t&&window.scrollTo(o.left,o.top),c.off(window,"scroll",s,!0))},dispatchEvent:function(t,e,i,n,o){var r,s=document.createEvent("HTMLEvents"),i=void 0===i||i,n=void 0===n||n;if(s.initEvent(e,i,n),o)for(r in o)s[r]=o[r];return t&&t.dispatchEvent(s),s},enableScrollLock:function(){if(1===(d+=1)){var t,e,i,a=document,l=window,u=a.documentElement,p=a.body,h=f();t=["overflow:hidden"],h&&(u.scrollHeight>u.clientHeight&&(i=parseInt(c.css(p,"padding-right"))+h,t.push("padding-right:"+i+"px")),u.scrollWidth>u.clientWidth&&(i=parseInt(c.css(p,"padding-bottom"))+h,t.push("padding-bottom:"+i+"px"))),e="."+m+"{",e+=t.join(" !important;")+" !important;}",r=n(e),c.on(l,"scroll",s,!0),o={left:c.scrollLeft(l),top:c.scrollTop(l)},c.addClass(p,m)}},log:function(){var t=window;if(u.debug&&void 0!==t.console)try{t.console.log.apply(t.console,arguments)}catch(i){var e=Array.prototype.slice.call(arguments);t.console.log(e.join("\n"))}},loadStyle:n,raiseError:function(t,e){if(!e)throw new Error("MUI: "+t);"undefined"!=typeof console&&console.error("MUI Warning: "+t)},requestAnimationFrame:function(t){var e=window.requestAnimationFrame;e?e(t):setTimeout(t,0)},supportsPointerEvents:function(){if(void 0!==l)return l;var t=document.createElement("x");return t.style.cssText="pointer-events:auto",l="auto"===t.style.pointerEvents}}},{"../config":2,"./jqLite":5}],7:[function(t,e,i){"use strict";function n(t){if(!0!==t._muiDropdown){t._muiDropdown=!0;var e=t.tagName;"INPUT"!==e&&"BUTTON"!==e||t.hasAttribute("type")||(t.type="button"),s.on(t,"click",o)}}function o(t){if(0===t.button){var e=this;null===e.getAttribute("disabled")&&r(e)}}function r(t){function e(){s.removeClass(n,u),s.off(o,"click",e)}var i=t.parentNode,n=t.nextElementSibling,o=i.ownerDocument;if(!n||!s.hasClass(n,c))return a.raiseError("Dropdown menu element not found");s.hasClass(n,u)?e():function(){var r=i.getBoundingClientRect(),a=t.getBoundingClientRect(),l=a.top-r.top+a.height;s.css(n,"top",l+"px"),s.addClass(n,u),setTimeout(function(){s.on(o,"click",e)},0)}()}var s=t("./lib/jqLite"),a=t("./lib/util"),l=t("./lib/animationHelpers"),u="mui--is-open",c="mui-dropdown__menu";e.exports={initListeners:function(){for(var t=document.querySelectorAll('[data-mui-toggle="dropdown"]'),e=t.length;e--;)n(t[e]);l.onAnimationStart("mui-dropdown-inserted",function(t){n(t.target)})}}},{"./lib/animationHelpers":3,"./lib/jqLite":5,"./lib/util":6}],8:[function(t,e,i){e.exports=t(5)},{}],9:[function(t,e,i){"use strict";function n(t,e){var i=document,n=i.body,o=i.getElementById(p);if(i.activeElement&&(d=i.activeElement),m.enableScrollLock(),o){for(;o.firstChild;)o.removeChild(o.firstChild);e&&o.appendChild(e)}else(o=i.createElement("div")).setAttribute("id",p),o.setAttribute("tabindex","-1"),e&&o.appendChild(e),n.appendChild(o);return h.test(navigator.userAgent)&&f.css(o,"cursor","pointer"),t.keyboard?r():s(),t.static?u(o):l(o),o.muiOptions=t,o.focus(),o}function o(){var t,e=document.getElementById(p);if(e){for(;e.firstChild;)e.removeChild(e.firstChild);e.parentNode.removeChild(e),t=e.muiOptions.onclose,u(e)}return m.disableScrollLock(),s(),d&&d.focus(),t&&t(),e}function r(){f.on(document,"keyup",a)}function s(){f.off(document,"keyup",a)}function a(t){27===t.keyCode&&o()}function l(t){f.on(t,"click",c)}function u(t){f.off(t,"click",c)}function c(t){t.target.id===p&&o()}var d,m=t("./lib/util"),f=t("./lib/jqLite"),p="mui-overlay",h=/(iPad|iPhone|iPod)/g;e.exports=function(t){var e;if("on"===t){for(var i,r,s,a=arguments.length-1;a>0;a--)i=arguments[a],"object"===f.type(i)&&(r=i),i instanceof Element&&1===i.nodeType&&(s=i);void 0===(r=r||{}).keyboard&&(r.keyboard=!0),void 0===r.static&&(r.static=!1),e=n(r,s)}else"off"===t?e=o():m.raiseError("Expecting 'on' or 'off'");return e}},{"./lib/jqLite":5,"./lib/util":6}],10:[function(t,e,i){"use strict";function n(t){!0!==t._muiRipple&&(t._muiRipple=!0,"INPUT"!==t.tagName&&s.on(t,c,o))}function o(t){if("mousedown"!==t.type||0===t.button){var e=this,i=e._rippleEl;if(!e.disabled){if(!i){var n=document.createElement("span");n.className="mui-btn__ripple-container",n.innerHTML='',e.appendChild(n),i=e._rippleEl=n.children[0],s.on(e,d,r)}var o,l,u=s.offset(e),c="touchstart"===t.type?t.touches[0]:t;l=2*(o=Math.sqrt(u.height*u.height+u.width*u.width))+"px",s.css(i,{width:l,height:l,top:Math.round(c.pageY-u.top-o)+"px",left:Math.round(c.pageX-u.left-o)+"px"}),s.removeClass(i,"mui--is-animating"),s.addClass(i,"mui--is-visible"),a.requestAnimationFrame(function(){s.addClass(i,"mui--is-animating")})}}}function r(t){var e=this._rippleEl;a.requestAnimationFrame(function(){s.removeClass(e,"mui--is-visible")})}var s=t("./lib/jqLite"),a=t("./lib/util"),l=t("./lib/animationHelpers"),u="ontouchstart"in document.documentElement,c=u?"touchstart":"mousedown",d=u?"touchend":"mouseup mouseleave";e.exports={initListeners:function(){for(var t=document.getElementsByClassName("mui-btn"),e=t.length;e--;)n(t[e]);l.onAnimationStart("mui-btn-inserted",function(t){n(t.target)})}}},{"./lib/animationHelpers":3,"./lib/jqLite":5,"./lib/util":6}],11:[function(t,e,i){"use strict";function n(t){if(!0!==t._muiSelect&&(t._muiSelect=!0,!("ontouchstart"in v.documentElement))){var e=t.parentNode;e._selectEl=t,e._menu=null,e._q="",e._qTimeout=null,t.disabled||(e.tabIndex=0),t.tabIndex=-1,d.on(t,"mousedown",o),d.on(e,"click",l),d.on(e,"blur focus",r),d.on(e,"keydown",s),d.on(e,"keypress",a);var i=document.createElement("div");i.className="mui-event-trigger",e.appendChild(i),d.on(i,f.animationEvents,function(t){t.stopPropagation(),"mui-node-disabled"===t.animationName?t.target.parentNode.removeAttribute("tabIndex"):t.target.parentNode.tabIndex=0})}}function o(t){0===t.button&&t.preventDefault()}function r(t){m.dispatchEvent(this._selectEl,t.type,!1,!1)}function s(t){if(!t.defaultPrevented){var e=t.keyCode,i=this._menu;if(i){if(9===e)return i.destroy();27!==e&&40!==e&&38!==e&&13!==e||t.preventDefault(),27===e?i.destroy():40===e?i.increment():38===e?i.decrement():13===e&&(i.selectCurrent(),i.destroy())}else 32!==e&&38!==e&&40!==e||(t.preventDefault(),u(this))}}function a(t){var e=this._menu;if(!t.defaultPrevented&&e){var i=this;clearTimeout(this._qTimeout),this._q+=t.key,this._qTimeout=setTimeout(function(){i._q=""},300);var n,o=new RegExp("^"+this._q,"i"),r=e.itemArray;for(n in r)if(o.test(r[n].innerText)){e.selectPos(n);break}}}function l(t){0!==t.button||this._selectEl.disabled||(this.focus(),u(this))}function u(t){t._menu||(t._menu=new c(t,t._selectEl,function(){t._menu=null,t.focus()}))}function c(t,e,i){m.enableScrollLock(),this.itemArray=[],this.origPos=null,this.currentPos=null,this.selectEl=e,this.wrapperEl=t,this.menuEl=this._createMenuEl(t,e);var n=m.callback;this.onClickCB=n(this,"onClick"),this.destroyCB=n(this,"destroy"),this.wrapperCallbackFn=i,t.appendChild(this.menuEl),d.scrollTop(this.menuEl,this.menuEl._scrollTop);var o=this.destroyCB;d.on(this.menuEl,"click",this.onClickCB),d.on(b,"resize",o),setTimeout(function(){d.on(v,"click",o)},0)}var d=t("./lib/jqLite"),m=t("./lib/util"),f=t("./lib/animationHelpers"),p=t("./lib/forms"),h="mui--is-selected",v=document,b=window;c.prototype._createMenuEl=function(t,e){var i,n,o,r,s,a,l,u,c=v.createElement("div"),m=e.children,f=this.itemArray,b=0,g=0,y=0,C=document.createDocumentFragment();for(c.className="mui-select__menu",s=0,a=m.length;s select"),e=t.length;e--;)n(t[e]);f.onAnimationStart("mui-select-inserted",function(t){n(t.target)})}}},{"./lib/animationHelpers":3,"./lib/forms":4,"./lib/jqLite":5,"./lib/util":6}],12:[function(t,e,i){"use strict";function n(t){!0!==t._muiTabs&&(t._muiTabs=!0,a.on(t,"click",o))}function o(t){if(0===t.button){var e=this;null===e.getAttribute("disabled")&&r(e)}}function r(t){var e,i,n,o,r,u,v,b,g,y=t.parentNode,C=t.getAttribute(c),E=document.getElementById(C);a.hasClass(y,d)||(E||l.raiseError('Tab pane "'+C+'" not found'),n=(i=s(E)).id,g="["+c+'="'+n+'"]',o=document.querySelectorAll(g)[0],e=o.parentNode,r={paneId:C,relatedPaneId:n},u={paneId:n,relatedPaneId:C},v=l.dispatchEvent(o,p,!0,!0,u),b=l.dispatchEvent(t,m,!0,!0,r),setTimeout(function(){v.defaultPrevented||b.defaultPrevented||(e&&a.removeClass(e,d),i&&a.removeClass(i,d),a.addClass(y,d),a.addClass(E,d),l.dispatchEvent(o,h,!0,!1,u),l.dispatchEvent(t,f,!0,!1,r))},0))}function s(t){for(var e,i=t.parentNode.children,n=i.length,o=null;n--&&!o;)(e=i[n])!==t&&a.hasClass(e,d)&&(o=e);return o}var a=t("./lib/jqLite"),l=t("./lib/util"),u=t("./lib/animationHelpers"),c="data-mui-controls",d="mui--is-active",m="mui.tabs.showstart",f="mui.tabs.showend",p="mui.tabs.hidestart",h="mui.tabs.hideend";e.exports={initListeners:function(){for(var t=document.querySelectorAll('[data-mui-toggle="tab"]'),e=t.length;e--;)n(t[e]);u.onAnimationStart("mui-tab-inserted",function(t){n(t.target)})},api:{activate:function(t){var e="["+c+"="+t+"]",i=document.querySelectorAll(e);i.length||l.raiseError('Tab control for pane "'+t+'" not found'),r(i[0])}}}},{"./lib/animationHelpers":3,"./lib/jqLite":5,"./lib/util":6}],13:[function(t,e,i){"use strict";function n(t){!0!==t._muiTextfield&&(t._muiTextfield=!0,t.value.length?s.addClass(t,p):s.addClass(t,f),s.addClass(t,c+" "+d),s.on(t,"blur",function e(){document.activeElement!==t&&(s.removeClass(t,c),s.addClass(t,u),s.off(t,"blur",e))}),s.one(t,"input change",function(){s.removeClass(t,d),s.addClass(t,m)}),s.on(t,"input change",o))}function o(){var t=this;t.value.length?(s.removeClass(t,f),s.addClass(t,p)):(s.removeClass(t,p),s.addClass(t,f))}function r(t){!0===t._muiTextfield&&o.call(t)}var s=t("./lib/jqLite"),a=t("./lib/util"),l=t("./lib/animationHelpers"),u="mui--is-touched",c="mui--is-untouched",d="mui--is-pristine",m="mui--is-dirty",f="mui--is-empty",p="mui--is-not-empty";e.exports={initialize:n,initListeners:function(){for(var t=document,e=t.querySelectorAll(".mui-textfield > input, .mui-textfield > textarea"),i=e.length;i--;)n(e[i]);l.onAnimationStart("mui-textfield-inserted",function(t){n(t.target)}),setTimeout(function(){var t=".mui-textfield.mui-textfield--float-label > label {"+["-webkit-transition","-moz-transition","-o-transition","transition",""].join(":all .15s ease-out;")+"}";a.loadStyle(t)},150),l.onAnimationStart("mui-textfield-autofill",function(t){r(t.target)}),!1===a.supportsPointerEvents()&&s.on(t,"click",function(t){var e=t.target;if("LABEL"===e.tagName&&s.hasClass(e.parentNode,"mui-textfield--float-label")){var i=e.previousElementSibling;i&&i.focus()}})}}},{"./lib/animationHelpers":3,"./lib/jqLite":5,"./lib/util":6}]},{},[1]); -------------------------------------------------------------------------------- /flaskapp/templates/auth/create-account.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared/modal-layout.html" %} 2 | 3 | 4 | {% block HEADERTAGS %} 5 | {{ super() }} 6 | 11 | {% endblock %} 12 | 13 | 14 | {% block BODY %} 15 |
16 |
22 | Create a new account 23 | {{ form.csrf_token }} 24 |
25 | {{ form.email(placeholder="Email address", 26 | autofocus="true", 27 | type="email", 28 | spellcheck="false") }} 29 | {% if form.email.errors -%} 30 |
{{ form.email.errors[0] }}
31 | {%- endif %} 32 |
33 |
34 | {{ form.password(placeholder="Password") }} 35 | {% if form.password.errors -%} 36 |
{{ form.password.errors[0] }}
37 | {%- endif %} 38 |
39 |
40 | {{ form.password_confirm(placeholder="Confirm password") }} 41 | {% if form.password_confirm.errors -%} 42 |
{{ form.password_confirm.errors[0] }}
43 | {%- endif %} 44 |
45 | 46 |
47 |
48 |
49 | Already have an account? Log in to your account » 50 |
51 | {% endblock %} 52 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/email-verification-request-followup.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared/modal-layout.html" %} 2 | 3 | 4 | {% block HEADERTAGS %} 5 | {{ super() }} 6 | 12 | {% endblock %} 13 | 14 | 15 | {% block BODY %} 16 |
17 |

Success - an email has been sent

18 |

An email was sent to {{ email }} with instructions on how to verify your account.

19 |

Would you like to:

20 | 24 |
25 | {% endblock %} 26 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/email-verification-request.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared/modal-layout.html" %} 2 | 3 | 4 | {% block HEADERTAGS %} 5 | {{ super() }} 6 | 12 | {% endblock %} 13 | 14 | 15 | {% block BODY %} 16 |
17 |
23 | Send verification request 24 | {{ form.csrf_token }} 25 |

A verification request will be sent to your email address. Please check your inbox for an email from us with insructions on how to verify your email address.

26 | 27 |
28 |
29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/forgot-followup.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared/modal-layout.html" %} 2 | 3 | 4 | {% block HEADERTAGS %} 5 | {{ super() }} 6 | 11 | {% endblock %} 12 | 13 | 14 | {% block BODY %} 15 |
16 |

Success - an email has been sent

17 |

An email was sent to {{ email }} with instructions on how to reset your password.

18 |

Would you like to:

19 | 23 |
24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/forgot.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared/modal-layout.html" %} 2 | 3 | 4 | {% block HEADERTAGS %} 5 | {{ super() }} 6 | 11 | {% endblock %} 12 | 13 | 14 | {% block BODY %} 15 |
16 |
22 | Reset your password 23 | {{ form.csrf_token }} 24 |
25 | {{ form.email(placeholder="Email address", 26 | autofocus="true", 27 | type="email") }} 28 | {% if form.email.errors -%} 29 |
{{ form.email.errors[0] }}
30 | {%- endif %} 31 |
32 | 33 |
34 |
35 |
36 | Remember your password? Log in to your account » 37 |
38 | {% endblock %} 39 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/login.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared/modal-layout.html" %} 2 | 3 | 4 | {% block HEADERTAGS %} 5 | {{ super() }} 6 | 15 | {% endblock %} 16 | 17 | 18 | {% block BODY %} 19 |
20 |
26 | Log in to your account 27 | {{ form.csrf_token }} 28 |
29 | {{ form.email(placeholder="Email address", 30 | autofocus="true", 31 | type="email") 32 | }} 33 | {% if form.email.errors -%} 34 |
{{ form.email.errors[0] }}
35 | {%- endif %} 36 |
37 |
38 | {{ form.password(placeholder="Password") }} 39 | {% if form.password.errors -%} 40 |
{{ form.password.errors[0] }}
41 | {%- endif %} 42 |
43 |
44 | 48 |
49 | 50 | Forgot password? 51 |
52 |
53 |
54 | Don't have an account? Create a new account » 55 |
56 | {% endblock %} 57 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/reset-password-email.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared-email/base-layout.html" %} 2 | 3 | 4 | {% block PANEL_CONTENT %} 5 |

Password Reset Request

6 |
7 |

A password reset request has been issued for your account. To choose a new password click on the button below:

8 |

Choose New Password »

9 |

If you're having trouble you can also use this link:

10 |

{{ reset_url }}

11 |

Note: If you did not issue this request please let us know (contact@flaskapp.com).

12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/reset-password-email.txt: -------------------------------------------------------------------------------- 1 | To reset the password for your account visit: 2 | 3 | {{ reset_url }} 4 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/reset-password-error.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared/modal-layout.html" %} 2 | 3 | 4 | {% block HEADERTAGS %} 5 | {{ super() }} 6 | 12 | {% endblock %} 13 | 14 | 15 | {% block BODY %} 16 |
17 |

Error! Reset link has expired

18 |

Sorry, the reset link you are using has expired. Please try to reset your password again.

19 |

Would you like to:

20 | 24 |
25 | {% endblock %} 26 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/reset-password-followup.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared/modal-layout.html" %} 2 | 3 | 4 | {% block HEADERTAGS %} 5 | {{ super() }} 6 | 12 | {% endblock %} 13 | 14 | 15 | {% block BODY %} 16 |
17 |

Success! Your password has been reset

18 |

Your password has been reset and you are now logged in.

19 |

Would you like to:

20 | 23 |
24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/reset-password.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared/modal-layout.html" %} 2 | 3 | 4 | {% block HEADERTAGS %} 5 | {{ super() }} 6 | 12 | {% endblock %} 13 | 14 | 15 | {% block BODY %} 16 |
17 |
23 | {{ form.csrf_token }} 24 | Choose a new password 25 |
26 | {{ form.password(placeholder="Password", autofocus="true") }} 27 | {% if form.password.errors -%} 28 |
{{ form.password.errors[0] }}
29 | {%- endif %} 30 |
31 |
32 | {{ form.password_confirm(placeholder="Confirm password") }} 33 | {% if form.password_confirm.errors -%} 34 |
{{ form.password_confirm.errors[0] }}
35 | {%- endif %} 36 |
37 | 38 |
39 |
40 | {% endblock %} 41 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/verify-email-email.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared-email/base-layout.html" %} 2 | 3 | 4 | {% block PANEL_CONTENT %} 5 |

Confirm your Account

6 |
7 |

To confirm your email address please click on the button below:

8 |

Confirm Account »

9 |

If you're having trouble you can also use this link:

10 |

{{ verify_url }}

11 |

Note: If you did not create an account please let us know (contact@example.com)

12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/verify-email-email.txt: -------------------------------------------------------------------------------- 1 | To verify your account please visit: 2 | 3 | {{ verify_url }} 4 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/verify-email-error.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared/modal-layout.html" %} 2 | 3 | 4 | {% block HEADERTAGS %} 5 | {{ super() }} 6 | 12 | {% endblock %} 13 | 14 | 15 | {% block BODY %} 16 |
17 |

Error! Verification link has expired

18 |

Sorry, the verification link you are using has expired. Please try to verify your account again.

19 |

Would you like to:

20 | 24 |
25 | {% endblock %} 26 | -------------------------------------------------------------------------------- /flaskapp/templates/auth/verify-email-followup.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared/modal-layout.html" %} 2 | 3 | 4 | {% block HEADERTAGS %} 5 | {{ super() }} 6 | 12 | {% endblock %} 13 | 14 | 15 | {% block BODY %} 16 |
17 |

Success! Your email has been verified

18 |

Your email address has been verified.

19 |

Would you like to:

20 | 23 |
24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /flaskapp/templates/content/home.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared/base-layout.html" %} 2 | 3 | 4 | {% block BODY %} 5 |

Flaskapp

6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /flaskapp/templates/shared-email/base-layout.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared-email/skeleton.html" %} 2 | 3 | 4 | {% block HEADERTAGS %} 5 | 8 | 11 | 43 | {% endblock %} 44 | 45 | 46 | {% block HTML %} 47 | 48 | 49 | 70 | 71 |
50 |
51 | 52 |
53 | 54 | 55 | 58 | 59 |
56 | Flaskapp 57 |
60 | 61 | 62 | 63 | 64 |
{% block PANEL_CONTENT %}{% endblock %}
65 | {{ footer_html() }} 66 |
67 | 68 |
69 |
72 | {% endblock %} 73 | 74 | 75 | {% macro footer_html() %} 76 | 77 | 78 | 82 | 83 | 84 | {% endmacro %} 85 | -------------------------------------------------------------------------------- /flaskapp/templates/shared-email/skeleton.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {% block HEADERTAGS %}{% endblock %} 7 | 8 | 9 | {% block HTML %}{% endblock %} 10 | 11 | 12 | -------------------------------------------------------------------------------- /flaskapp/templates/shared/base-layout.html: -------------------------------------------------------------------------------- 1 | {% extends "/skeleton.html" %} 2 | 3 | 4 | {% block HEADERTAGS %} 5 | {{ h.stylesheet_tag('//cdn.muicss.com/mui-0.9.17/css/mui.min.css') }} 6 | {{ h.stylesheet_tag(h.static('style.min.css')) }} 7 | 12 | 13 | {% with messages = get_flashed_messages() -%} 14 | {% if messages -%} 15 | 36 | {%- endif %} 37 | {%- endwith %} 38 | {% endblock %} 39 | 40 | 41 | {% block HTML %} 42 |
43 | 46 |
47 |
48 | {% block BODY %}{% endblock %} 49 |
50 |
51 |
52 |
53 | {{ base_footer_html() }} 54 |
55 | {% endblock %} 56 | 57 | 58 | {% macro base_header_html() -%} 59 | 83 | {%- endmacro %} 84 | 85 | 86 | {% macro base_footer_html() -%} 87 | 90 | {%- endmacro %} 91 | -------------------------------------------------------------------------------- /flaskapp/templates/shared/modal-layout.html: -------------------------------------------------------------------------------- 1 | {% extends "/shared/base-layout.html" %} 2 | 3 | 4 | {% block HTML %} 5 | 13 |
14 | {{ modal_footer_html() }} 15 |
16 | {% endblock %} 17 | 18 | 19 | {% macro modal_header_html() -%} 20 | Flaskapp 21 | {%- endmacro %} 22 | 23 | 24 | {% macro modal_footer_html() -%} 25 | 28 | {%- endmacro %} 29 | -------------------------------------------------------------------------------- /flaskapp/templates/skeleton.html: -------------------------------------------------------------------------------- 1 | {% from "skeleton.js" import global_js -%} 2 | 3 | 4 | 5 | 6 | 7 | {% block TITLE %}{% endblock %} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | {% block HEADERTAGS %}{% endblock %} 20 | 21 | 22 | {% block HTML %}{% endblock %} 23 | {% block FOOTERTAGS %}{% endblock %} 24 | 25 | 26 | -------------------------------------------------------------------------------- /flaskapp/templates/skeleton.js: -------------------------------------------------------------------------------- 1 | {% macro global_js() -%} 2 | {# LoadJS https://github.com/muicss/loadjs #} 3 | loadjs=function(){function e(e,n){e=e.push?e:[e];var t,r,o,i,c=[],s=e.length,h=s;for(t=function(e,t){t.length&&c.push(e),h--,h||n(c)};s--;)r=e[s],o=u[r],o?t(r,o):(i=f[r]=f[r]||[],i.push(t))}function n(e,n){if(e){var t=f[e];if(u[e]=n,t)for(;t.length;)t[0](e,n),t.splice(0,1)}}function t(e,n,r,o){var c,u,f=document,s=r.async,h=(r.numRetries||0)+1,a=r.before||i;o=o||0,/\.css$/.test(e)?(c=!0,u=f.createElement("link"),u.rel="stylesheet",u.href=e):(u=f.createElement("script"),u.src=e,u.async=void 0===s||s),u.onload=u.onerror=u.onbeforeload=function(i){var f=i.type[0];if(c&&"hideFocus"in u)try{u.sheet.cssText.length||(f="e")}catch(e){f="e"}return"e"==f&&(o+=1,o 0: 142 | db.session.delete(r) 143 | db.session.flush() 144 | return render_template('/auth/reset-password-error.html'), 400 145 | 146 | # handle form 147 | form = ResetPasswordForm() 148 | if form.validate_on_submit(): 149 | # save new password 150 | u = r.user 151 | u.password = generate_password_hash(form.password.data) 152 | db.session.add(u) 153 | 154 | # login user 155 | login_user(u, remember=True) 156 | identity_changed.send(current_app._get_current_object(), 157 | identity=Identity(u.id)) 158 | 159 | # delete password reset 160 | db.session.delete(r) 161 | db.session.flush() 162 | 163 | return render_template('/auth/reset-password-followup.html') 164 | 165 | return render_template('/auth/reset-password.html', form=form) 166 | 167 | 168 | @bp.route('/email-verification-request', methods=['GET', 'POST']) 169 | @login_required 170 | def email_verification_request(): 171 | """GET|POST /email-verification-request: handle email verification requests 172 | """ 173 | u = g.user 174 | 175 | form = FlaskForm() 176 | if form.validate_on_submit(): 177 | send_verification_email(u) 178 | fn = '/auth/email-verification-request-followup.html' 179 | return render_template(fn, email=u.email) 180 | 181 | return render_template('/auth/email-verification-request.html', form=form) 182 | 183 | 184 | @bp.route('/verify-email', methods=['GET']) 185 | def verify_email(): 186 | """GET|POST /verify-email: handle email verification request 187 | """ 188 | # get email-verification-request entry 189 | f = (EmailVerificationRequest.key == request.args.get('key'), 190 | User.email == request.args.get('email')) 191 | r = EmailVerificationRequest\ 192 | .query\ 193 | .filter(*f)\ 194 | .filter(EmailVerificationRequest.fk_user == User.id)\ 195 | .first() 196 | 197 | # return error response if link doesn't exist or wrong email 198 | if r == None or r.user.email != request.args['email']: 199 | return render_template('/auth/verify-email-error.html'), 400 200 | 201 | # expired if older than 3 days 202 | delta = datetime.datetime.utcnow() - r.create_ts 203 | if delta.days > 2: 204 | db.session.delete(r) 205 | db.session.flush() 206 | return render_template('/auth/verify-email-error.html'), 400 207 | 208 | # update status 209 | u = r.user 210 | u.is_verified = True 211 | db.session.add(u) 212 | 213 | # delete verification request 214 | db.session.delete(r) 215 | db.session.flush() 216 | 217 | return render_template('/auth/verify-email-followup.html') 218 | 219 | 220 | def send_verification_email(user): 221 | """Send verification email to user 222 | """ 223 | # create email verification request 224 | r = EmailVerificationRequest(key=os.urandom(32).hex(), user=user) 225 | db.session.add(r) 226 | db.session.flush() 227 | 228 | # send email 229 | subject = 'Flaskapp Account: Please Confirm Email' 230 | msg = Message(subject, recipients=[user.email]) 231 | verify_url = url_for('.verify_email', key=r.key, email=user.email, \ 232 | _external=True) 233 | 234 | f = '/auth/verify-email-email' 235 | msg.body = render_template(f + '.txt', verify_url=verify_url) 236 | 237 | html = render_template(f + '.html', verify_url=verify_url) 238 | base_url = url_for('content.home', _external=True) 239 | msg.html = transform(html, base_url=base_url) 240 | mail.send(msg) 241 | -------------------------------------------------------------------------------- /flaskapp/views/content.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, render_template 2 | 3 | 4 | bp = Blueprint('content', __name__) 5 | 6 | 7 | @bp.route('/', methods=['GET']) 8 | def home(): 9 | """GET /: render homepage 10 | """ 11 | return render_template('/content/home.html') 12 | 13 | 14 | @bp.route('/feedback', methods=['GET', 'POST']) 15 | def feedback(): 16 | """GET|POST /feedback: feedback form handler 17 | """ 18 | form = FeedbackForm() 19 | if form.validate_on_submit(): 20 | # TODO: send feedback to contact@example.com 21 | return 'ok' 22 | 23 | return render_template('/content/feedback.html', form=form) 24 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | bcrypt==4.1.2 2 | blinker==1.7.0 3 | cachetools==5.3.3 4 | certifi==2024.2.2 5 | charset-normalizer==3.3.2 6 | click==8.1.7 7 | cssselect==1.2.0 8 | cssutils==2.10.2 9 | Flask==3.0.3 10 | Flask-Login==0.6.3 11 | Flask-Mail==0.9.1 12 | Flask-Principal==0.4.0 13 | Flask-SQLAlchemy==3.1.1 14 | Flask-WTF==1.2.1 15 | gevent==24.2.1 16 | greenlet==3.0.3 17 | idna==3.7 18 | itsdangerous==2.1.2 19 | Jinja2==3.1.4 20 | lxml==5.2.1 21 | MarkupSafe==2.1.5 22 | premailer==3.10.0 23 | requests==2.31.0 24 | setuptools==69.2.0 25 | SQLAlchemy==2.0.29 26 | typing_extensions==4.11.0 27 | urllib3==2.2.1 28 | Werkzeug==3.0.3 29 | WTForms==3.1.2 30 | zope.event==5.0 31 | zope.interface==6.2 32 | -------------------------------------------------------------------------------- /scripts/create_db.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 3 | 4 | from flaskapp import create_app 5 | from flaskapp.meta import db 6 | 7 | # create database tables 8 | with create_app().app_context(): 9 | db.create_all() 10 | -------------------------------------------------------------------------------- /static-src/gulpfile.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | var del = require('del'), 4 | gulp = require('gulp'), 5 | plugins = require('gulp-load-plugins')(), 6 | sass = require('gulp-sass')(require('sass')); 7 | 8 | 9 | var destDir = '../flaskapp/static'; 10 | 11 | 12 | 13 | 14 | // ============================================================================ 15 | // PUBLIC TASKS 16 | // ============================================================================ 17 | 18 | gulp.task('build', gulp.series( 19 | clean, 20 | gulp.parallel( 21 | buildCss, 22 | copyVendor 23 | ), 24 | buildRev 25 | )); 26 | 27 | 28 | 29 | 30 | // ============================================================================ 31 | // PRIVATE TASKS 32 | // ============================================================================ 33 | 34 | function clean(done) { 35 | return del(destDir, {force: true}, done); 36 | } 37 | 38 | 39 | function buildCss() { 40 | return gulp.src('src/sass/global.scss') 41 | .pipe(sass().on('error', sass.logError)) 42 | .pipe(plugins.autoprefixer({ 43 | cascade: false 44 | })) 45 | .pipe(plugins.concat('style.css')) 46 | .pipe(gulp.dest(destDir)) 47 | .pipe(plugins.cssnano({discardComments: {removeAll: true}})) 48 | .pipe(plugins.rename('style.min.css')) 49 | .pipe(gulp.dest(destDir)); 50 | } 51 | 52 | 53 | function copyVendor() { 54 | return gulp.src('src/vendor/**/*') 55 | .pipe(gulp.dest(destDir + '/vendor')); 56 | } 57 | 58 | 59 | function buildRev() { 60 | var base = path.join(process.cwd(), destDir); 61 | 62 | var sources = [ 63 | destDir + '/**/*.css', 64 | destDir + '/**/*.js', 65 | destDir + '/**/*.ico', 66 | destDir + '/**/*.png', 67 | destDir + '/**/*.eot', 68 | destDir + '/**/*.svg', 69 | destDir + '/**/*.ttf', 70 | destDir + '/**/*.woff', 71 | '!' + destDir + '/email/**' 72 | ]; 73 | 74 | return gulp.src(sources, {base: base}) 75 | .pipe(plugins.rev()) 76 | .pipe(gulp.dest(destDir + '/cache')) 77 | .pipe(plugins.rev.manifest()) 78 | .pipe(gulp.dest(destDir)); 79 | } 80 | -------------------------------------------------------------------------------- /static-src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flaskapp", 3 | "version": "0.0.1", 4 | "browserslist": [ 5 | "last 3 versions" 6 | ], 7 | "scripts": { 8 | "build": "gulp build" 9 | }, 10 | "devDependencies": { 11 | "autoprefixer": "^10.4.7", 12 | "del": "^6.1.1", 13 | "gulp": "^4.0.2", 14 | "gulp-autoprefixer": "^8.0.0", 15 | "gulp-concat": "^2.6.1", 16 | "gulp-load-plugins": "^2.0.7", 17 | "gulp-rename": "^2.0.0", 18 | "gulp-rev": "^9.0.0", 19 | "gulp-sass": "^5.1.0" 20 | }, 21 | "dependencies": { 22 | "gulp-cssnano": "^2.1.3", 23 | "sass": "^1.53.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /static-src/src/sass/global.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Flaskapp Global Stylesheet 3 | * @module global 4 | */ 5 | 6 | 7 | /** 8 | * Variables 9 | */ 10 | $bodyBackgroundColor: #eee; 11 | $footerHeight: 80px; 12 | $footerBackgroundColor: #ccc; 13 | $flashesColor: #fff; 14 | $flashesBackgroundColor: red; 15 | $modalFooterHeight: 50px; 16 | 17 | 18 | /** 19 | * Global CSS 20 | */ 21 | html, 22 | body { 23 | height: 100%; 24 | background-color: $bodyBackgroundColor; 25 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, Tahoma; 26 | } 27 | 28 | // enable font-smoothing 29 | html, 30 | body, 31 | input, 32 | textarea, 33 | buttons { 34 | -webkit-font-smoothing: antialiased; 35 | -moz-osx-font-smoothing: grayscale; 36 | text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.004); 37 | } 38 | 39 | 40 | /** 41 | * Layout CSS 42 | */ 43 | #header { 44 | margin-bottom: 20px; 45 | } 46 | 47 | #wrapper { 48 | box-sizing: border-box; 49 | min-height: 100%; 50 | margin-bottom: -($footerHeight); 51 | padding-bottom: $footerHeight; 52 | } 53 | 54 | #footer { 55 | box-sizing: border-box; 56 | height: $footerHeight; 57 | line-height: $footerHeight; 58 | background-color: $footerBackgroundColor; 59 | } 60 | 61 | #panel { 62 | box-sizing: border-box; 63 | $heightExpr: "100vh - 200px"; 64 | min-height: -webkit-calc(#{$heightExpr}); 65 | min-height: -moz-calc(#{$heightExpr}); 66 | min-height: -o-calc(#{$heightExpr}); 67 | min-height: calc(#{$heightExpr}); 68 | } 69 | 70 | 71 | /** 72 | * Flash CSS 73 | */ 74 | #flash { 75 | position: fixed; 76 | top: 0; 77 | right: 0; 78 | 79 | li { 80 | font-size: 12px; 81 | color: $flashesColor; 82 | background-color: $flashesBackgroundColor; 83 | padding: 1px 5px; 84 | margin: 2px; 85 | } 86 | } 87 | 88 | 89 | /** 90 | * Header CSS 91 | */ 92 | #header td { 93 | > a { 94 | color: #fff; 95 | } 96 | 97 | > a:not(:last-child) { 98 | margin-right: 10px; 99 | } 100 | } 101 | 102 | #header a[data-mui-toggle="dropdown"] { 103 | color: #fff; 104 | cursor: pointer; 105 | 106 | :hover { 107 | color: #fff; 108 | } 109 | } 110 | 111 | /** 112 | * Modal CSS 113 | */ 114 | #modal-wrapper { 115 | min-height: 100%; 116 | margin-bottom: -($modalFooterHeight); 117 | padding-bottom: $modalFooterHeight; 118 | 119 | .mui-panel { 120 | margin: 0 auto 20px; 121 | } 122 | } 123 | 124 | #modal-footer { 125 | height: $modalFooterHeight; 126 | text-align: center; 127 | 128 | a { 129 | color: #333; 130 | } 131 | } 132 | 133 | #modal-header-brand { 134 | color: #777; 135 | margin: 20px 0px; 136 | display: inline-block; 137 | font-size: 25px; 138 | 139 | &:hover { 140 | text-decoration: none; 141 | } 142 | 143 | img { 144 | height: 30px; 145 | width: 30px; 146 | position: relative; 147 | top: -3px; 148 | } 149 | } 150 | 151 | -------------------------------------------------------------------------------- /static-src/src/vendor/mui-0.9.17/email/mui-email-inline-rtl.css: -------------------------------------------------------------------------------- 1 | body { 2 | width: 100% !important; 3 | min-width: 100%; 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | img { 9 | border: 0 none; 10 | height: auto; 11 | line-height: 100%; 12 | outline: none; 13 | text-decoration: none; 14 | } 15 | 16 | a img { 17 | border: 0 none; 18 | } 19 | 20 | table { 21 | border-spacing: 0; 22 | border-collapse: collapse; 23 | } 24 | 25 | td { 26 | padding: 0; 27 | text-align: right; 28 | word-break: break-word; 29 | -webkit-hyphens: auto; 30 | -moz-hyphens: auto; 31 | hyphens: auto; 32 | border-collapse: collapse !important; 33 | } 34 | 35 | table, td { 36 | mso-table-lspace: 0pt; 37 | mso-table-rspace: 0pt; 38 | } 39 | 40 | body, 41 | table, 42 | td, 43 | p, 44 | a, 45 | li, 46 | blockquote { 47 | -webkit-text-size-adjust: 100%; 48 | -ms-text-size-adjust: 100%; 49 | } 50 | 51 | img { 52 | -ms-interpolation-mode: bicubic; 53 | } 54 | 55 | /** 56 | * MUI Colors module 57 | */ 58 | /** 59 | * MUI Email Reboot 60 | */ 61 | body { 62 | color: #212121; 63 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, "Trebuchet MS"; 64 | font-weight: 400; 65 | font-size: 14px; 66 | line-height: 1.429; 67 | letter-spacing: 0.001em; 68 | background-color: #FFF; 69 | } 70 | 71 | a { 72 | color: #2196F3; 73 | text-decoration: none; 74 | } 75 | 76 | p { 77 | margin: 0 0 10px; 78 | } 79 | 80 | hr { 81 | color: #e0e0e0; 82 | background-color: #e0e0e0; 83 | height: 1px; 84 | border: none; 85 | } 86 | 87 | strong { 88 | font-weight: 700; 89 | } 90 | 91 | h1, h2, h3 { 92 | margin-top: 20px; 93 | margin-bottom: 10px; 94 | } 95 | 96 | h4, h5, h6 { 97 | margin-top: 10px; 98 | margin-bottom: 10px; 99 | } 100 | 101 | /** 102 | * MUI Email Body Component 103 | */ 104 | .mui-body { 105 | margin: 0; 106 | padding: 0; 107 | height: 100%; 108 | width: 100%; 109 | color: #212121; 110 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, "Trebuchet MS"; 111 | font-weight: 400; 112 | font-size: 14px; 113 | line-height: 1.429; 114 | letter-spacing: 0.001em; 115 | background-color: #FFF; 116 | } 117 | 118 | /** 119 | * MUI Email Buttons 120 | */ 121 | .mui-btn { 122 | cursor: pointer; 123 | white-space: nowrap; 124 | } 125 | 126 | a.mui-btn { 127 | font-weight: 500; 128 | font-size: 14px; 129 | color: #212121; 130 | line-height: 14px; 131 | letter-spacing: 0.03em; 132 | text-transform: uppercase; 133 | border-top: 1px solid transparent; 134 | border-right: 1px solid transparent; 135 | border-left: 1px solid transparent; 136 | border-bottom: 1px solid transparent; 137 | border-top: 1px solid #FFF; 138 | border-right: 1px solid #FFF; 139 | border-left: 1px solid #FFF; 140 | border-bottom: 1px solid #FFF; 141 | color: #212121; 142 | background-color: #FFF; 143 | display: inline-block; 144 | text-decoration: none; 145 | text-align: center; 146 | border-radius: 3px; 147 | padding: 10px 25px; 148 | background-color: transparent; 149 | } 150 | 151 | a.mui-btn.mui-btn--raised { 152 | border-top: 1px solid #f2f2f2; 153 | border-right: 1px solid #e6e6e6; 154 | border-left: 1px solid #e6e6e6; 155 | border-bottom: 2px solid #bababa; 156 | } 157 | 158 | a.mui-btn.mui-btn--flat { 159 | background-color: transparent; 160 | color: #212121; 161 | border-top: 1px solid transparent; 162 | border-right: 1px solid transparent; 163 | border-left: 1px solid transparent; 164 | border-bottom: 1px solid transparent; 165 | } 166 | 167 | a.mui-btn.mui-btn--primary { 168 | border-top: 1px solid #2196F3; 169 | border-right: 1px solid #2196F3; 170 | border-left: 1px solid #2196F3; 171 | border-bottom: 1px solid #2196F3; 172 | color: #FFF; 173 | background-color: #2196F3; 174 | } 175 | 176 | a.mui-btn.mui-btn--primary.mui-btn--raised { 177 | border-top: 1px solid #51adf6; 178 | border-right: 1px solid #2196F3; 179 | border-left: 1px solid #2196F3; 180 | border-bottom: 2px solid #0a6ebd; 181 | } 182 | 183 | a.mui-btn.mui-btn--primary.mui-btn--flat { 184 | background-color: transparent; 185 | color: #2196F3; 186 | border-top: 1px solid transparent; 187 | border-right: 1px solid transparent; 188 | border-left: 1px solid transparent; 189 | border-bottom: 1px solid transparent; 190 | } 191 | 192 | a.mui-btn.mui-btn--danger { 193 | border-top: 1px solid #F44336; 194 | border-right: 1px solid #F44336; 195 | border-left: 1px solid #F44336; 196 | border-bottom: 1px solid #F44336; 197 | color: #FFF; 198 | background-color: #F44336; 199 | } 200 | 201 | a.mui-btn.mui-btn--danger.mui-btn--raised { 202 | border-top: 1px solid #f77066; 203 | border-right: 1px solid #F44336; 204 | border-left: 1px solid #F44336; 205 | border-bottom: 2px solid #d2190b; 206 | } 207 | 208 | a.mui-btn.mui-btn--danger.mui-btn--flat { 209 | background-color: transparent; 210 | color: #F44336; 211 | border-top: 1px solid transparent; 212 | border-right: 1px solid transparent; 213 | border-left: 1px solid transparent; 214 | border-bottom: 1px solid transparent; 215 | } 216 | 217 | a.mui-btn.mui-btn--dark { 218 | border-top: 1px solid #424242; 219 | border-right: 1px solid #424242; 220 | border-left: 1px solid #424242; 221 | border-bottom: 1px solid #424242; 222 | color: #FFF; 223 | background-color: #424242; 224 | } 225 | 226 | a.mui-btn.mui-btn--dark.mui-btn--raised { 227 | border-top: 1px solid #5c5c5c; 228 | border-right: 1px solid #424242; 229 | border-left: 1px solid #424242; 230 | border-bottom: 2px solid #1c1c1c; 231 | } 232 | 233 | a.mui-btn.mui-btn--dark.mui-btn--flat { 234 | background-color: transparent; 235 | color: #424242; 236 | border-top: 1px solid transparent; 237 | border-right: 1px solid transparent; 238 | border-left: 1px solid transparent; 239 | border-bottom: 1px solid transparent; 240 | } 241 | 242 | a.mui-btn.mui-btn--accent { 243 | border-top: 1px solid #FF4081; 244 | border-right: 1px solid #FF4081; 245 | border-left: 1px solid #FF4081; 246 | border-bottom: 1px solid #FF4081; 247 | color: #FFF; 248 | background-color: #FF4081; 249 | } 250 | 251 | a.mui-btn.mui-btn--accent.mui-btn--raised { 252 | border-top: 1px solid #ff73a3; 253 | border-right: 1px solid #FF4081; 254 | border-left: 1px solid #FF4081; 255 | border-bottom: 2px solid #f30053; 256 | } 257 | 258 | a.mui-btn.mui-btn--accent.mui-btn--flat { 259 | background-color: transparent; 260 | color: #FF4081; 261 | border-top: 1px solid transparent; 262 | border-right: 1px solid transparent; 263 | border-left: 1px solid transparent; 264 | border-bottom: 1px solid transparent; 265 | } 266 | 267 | table.mui-btn > tr > td, 268 | table.mui-btn > tbody > tr > td { 269 | background-color: #FFF; 270 | } 271 | 272 | table.mui-btn > tr > td > a, 273 | table.mui-btn > tbody > tr > td > a { 274 | color: #212121; 275 | border-top: 1px solid #FFF; 276 | border-right: 1px solid #FFF; 277 | border-left: 1px solid #FFF; 278 | border-bottom: 1px solid #FFF; 279 | } 280 | 281 | table.mui-btn.mui-btn--raised > tr > td > a, 282 | table.mui-btn.mui-btn--raised > tbody > tr > td > a { 283 | border-top: 1px solid #f2f2f2; 284 | border-right: 1px solid #e6e6e6; 285 | border-left: 1px solid #e6e6e6; 286 | border-bottom: 2px solid #bababa; 287 | } 288 | 289 | table.mui-btn.mui-btn--flat > tr > td, 290 | table.mui-btn.mui-btn--flat > tbody > tr > td { 291 | background-color: transparent; 292 | } 293 | 294 | table.mui-btn.mui-btn--flat > tr > td > a, 295 | table.mui-btn.mui-btn--flat > tbody > tr > td > a { 296 | color: #212121; 297 | border-top: 1px solid transparent; 298 | border-right: 1px solid transparent; 299 | border-left: 1px solid transparent; 300 | border-bottom: 1px solid transparent; 301 | } 302 | 303 | table.mui-btn > tr > td, 304 | table.mui-btn > tbody > tr > td { 305 | border-radius: 3px; 306 | } 307 | 308 | table.mui-btn > tr > td > a, 309 | table.mui-btn > tbody > tr > td > a { 310 | font-weight: 500; 311 | font-size: 14px; 312 | color: #212121; 313 | line-height: 14px; 314 | letter-spacing: 0.03em; 315 | text-transform: uppercase; 316 | border-top: 1px solid transparent; 317 | border-right: 1px solid transparent; 318 | border-left: 1px solid transparent; 319 | border-bottom: 1px solid transparent; 320 | display: inline-block; 321 | text-decoration: none; 322 | text-align: center; 323 | border-radius: 3px; 324 | padding: 10px 25px; 325 | background-color: transparent; 326 | } 327 | 328 | table.mui-btn.mui-btn--primary > tr > td, 329 | table.mui-btn.mui-btn--primary > tbody > tr > td { 330 | background-color: #2196F3; 331 | } 332 | 333 | table.mui-btn.mui-btn--primary > tr > td > a, 334 | table.mui-btn.mui-btn--primary > tbody > tr > td > a { 335 | color: #FFF; 336 | border-top: 1px solid #2196F3; 337 | border-right: 1px solid #2196F3; 338 | border-left: 1px solid #2196F3; 339 | border-bottom: 1px solid #2196F3; 340 | } 341 | 342 | table.mui-btn.mui-btn--primary.mui-btn--raised > tr > td > a, 343 | table.mui-btn.mui-btn--primary.mui-btn--raised > tbody > tr > td > a { 344 | border-top: 1px solid #51adf6; 345 | border-right: 1px solid #2196F3; 346 | border-left: 1px solid #2196F3; 347 | border-bottom: 2px solid #0a6ebd; 348 | } 349 | 350 | table.mui-btn.mui-btn--primary.mui-btn--flat > tr > td, 351 | table.mui-btn.mui-btn--primary.mui-btn--flat > tbody > tr > td { 352 | background-color: transparent; 353 | } 354 | 355 | table.mui-btn.mui-btn--primary.mui-btn--flat > tr > td > a, 356 | table.mui-btn.mui-btn--primary.mui-btn--flat > tbody > tr > td > a { 357 | color: #2196F3; 358 | border-top: 1px solid transparent; 359 | border-right: 1px solid transparent; 360 | border-left: 1px solid transparent; 361 | border-bottom: 1px solid transparent; 362 | } 363 | 364 | table.mui-btn.mui-btn--danger > tr > td, 365 | table.mui-btn.mui-btn--danger > tbody > tr > td { 366 | background-color: #F44336; 367 | } 368 | 369 | table.mui-btn.mui-btn--danger > tr > td > a, 370 | table.mui-btn.mui-btn--danger > tbody > tr > td > a { 371 | color: #FFF; 372 | border-top: 1px solid #F44336; 373 | border-right: 1px solid #F44336; 374 | border-left: 1px solid #F44336; 375 | border-bottom: 1px solid #F44336; 376 | } 377 | 378 | table.mui-btn.mui-btn--danger.mui-btn--raised > tr > td > a, 379 | table.mui-btn.mui-btn--danger.mui-btn--raised > tbody > tr > td > a { 380 | border-top: 1px solid #f77066; 381 | border-right: 1px solid #F44336; 382 | border-left: 1px solid #F44336; 383 | border-bottom: 2px solid #d2190b; 384 | } 385 | 386 | table.mui-btn.mui-btn--danger.mui-btn--flat > tr > td, 387 | table.mui-btn.mui-btn--danger.mui-btn--flat > tbody > tr > td { 388 | background-color: transparent; 389 | } 390 | 391 | table.mui-btn.mui-btn--danger.mui-btn--flat > tr > td > a, 392 | table.mui-btn.mui-btn--danger.mui-btn--flat > tbody > tr > td > a { 393 | color: #F44336; 394 | border-top: 1px solid transparent; 395 | border-right: 1px solid transparent; 396 | border-left: 1px solid transparent; 397 | border-bottom: 1px solid transparent; 398 | } 399 | 400 | table.mui-btn.mui-btn--dark > tr > td, 401 | table.mui-btn.mui-btn--dark > tbody > tr > td { 402 | background-color: #424242; 403 | } 404 | 405 | table.mui-btn.mui-btn--dark > tr > td > a, 406 | table.mui-btn.mui-btn--dark > tbody > tr > td > a { 407 | color: #FFF; 408 | border-top: 1px solid #424242; 409 | border-right: 1px solid #424242; 410 | border-left: 1px solid #424242; 411 | border-bottom: 1px solid #424242; 412 | } 413 | 414 | table.mui-btn.mui-btn--dark.mui-btn--raised > tr > td > a, 415 | table.mui-btn.mui-btn--dark.mui-btn--raised > tbody > tr > td > a { 416 | border-top: 1px solid #5c5c5c; 417 | border-right: 1px solid #424242; 418 | border-left: 1px solid #424242; 419 | border-bottom: 2px solid #1c1c1c; 420 | } 421 | 422 | table.mui-btn.mui-btn--dark.mui-btn--flat > tr > td, 423 | table.mui-btn.mui-btn--dark.mui-btn--flat > tbody > tr > td { 424 | background-color: transparent; 425 | } 426 | 427 | table.mui-btn.mui-btn--dark.mui-btn--flat > tr > td > a, 428 | table.mui-btn.mui-btn--dark.mui-btn--flat > tbody > tr > td > a { 429 | color: #424242; 430 | border-top: 1px solid transparent; 431 | border-right: 1px solid transparent; 432 | border-left: 1px solid transparent; 433 | border-bottom: 1px solid transparent; 434 | } 435 | 436 | table.mui-btn.mui-btn--accent > tr > td, 437 | table.mui-btn.mui-btn--accent > tbody > tr > td { 438 | background-color: #FF4081; 439 | } 440 | 441 | table.mui-btn.mui-btn--accent > tr > td > a, 442 | table.mui-btn.mui-btn--accent > tbody > tr > td > a { 443 | color: #FFF; 444 | border-top: 1px solid #FF4081; 445 | border-right: 1px solid #FF4081; 446 | border-left: 1px solid #FF4081; 447 | border-bottom: 1px solid #FF4081; 448 | } 449 | 450 | table.mui-btn.mui-btn--accent.mui-btn--raised > tr > td > a, 451 | table.mui-btn.mui-btn--accent.mui-btn--raised > tbody > tr > td > a { 452 | border-top: 1px solid #ff73a3; 453 | border-right: 1px solid #FF4081; 454 | border-left: 1px solid #FF4081; 455 | border-bottom: 2px solid #f30053; 456 | } 457 | 458 | table.mui-btn.mui-btn--accent.mui-btn--flat > tr > td, 459 | table.mui-btn.mui-btn--accent.mui-btn--flat > tbody > tr > td { 460 | background-color: transparent; 461 | } 462 | 463 | table.mui-btn.mui-btn--accent.mui-btn--flat > tr > td > a, 464 | table.mui-btn.mui-btn--accent.mui-btn--flat > tbody > tr > td > a { 465 | color: #FF4081; 466 | border-top: 1px solid transparent; 467 | border-right: 1px solid transparent; 468 | border-left: 1px solid transparent; 469 | border-bottom: 1px solid transparent; 470 | } 471 | 472 | a.mui-btn--small, 473 | table.mui-btn--small > tr > td > a, 474 | table.mui-btn--small > tbody > tr > td > a { 475 | font-size: 13px; 476 | padding: 7.8px 15px; 477 | } 478 | 479 | a.mui-btn--large, 480 | table.mui-btn--large > tr > td > a, 481 | table.mui-btn--large > tbody > tr > td > a { 482 | font-size: 14px; 483 | padding: 19px 25px; 484 | } 485 | 486 | /** 487 | * MUI Email Containers 488 | */ 489 | .mui-container, .mui-container-fixed { 490 | max-width: 600px; 491 | display: block; 492 | margin: 0 auto; 493 | clear: both; 494 | text-align: right; 495 | padding-right: 15px; 496 | padding-left: 15px; 497 | } 498 | 499 | .mui-container-fixed { 500 | width: 600px; 501 | } 502 | 503 | /** 504 | * MUI Email Dividers 505 | */ 506 | .mui-divider { 507 | display: block; 508 | height: 1px; 509 | background-color: #e0e0e0; 510 | } 511 | 512 | .mui--divider-top { 513 | border-top: 1px solid #e0e0e0; 514 | } 515 | 516 | .mui--divider-bottom { 517 | border-bottom: 1px solid #e0e0e0; 518 | } 519 | 520 | .mui--divider-right { 521 | border-right: 1px solid #e0e0e0; 522 | } 523 | 524 | .mui--divider-left { 525 | border-left: 1px solid #e0e0e0; 526 | } 527 | 528 | /** 529 | * MUI Email Panel 530 | */ 531 | .mui-panel { 532 | padding: 15px; 533 | border-radius: 0; 534 | background-color: #FFF; 535 | border-top: 1px solid #ededed; 536 | border-right: 1px solid #e6e6e6; 537 | border-left: 1px solid #e6e6e6; 538 | border-bottom: 2px solid #d4d4d4; 539 | } 540 | 541 | /** 542 | * MUI Email Helpers 543 | */ 544 | .mui--text-left { 545 | text-align: right; 546 | } 547 | 548 | .mui--text-right { 549 | text-align: left; 550 | } 551 | 552 | .mui--text-center { 553 | text-align: center; 554 | } 555 | 556 | .mui--text-justify { 557 | text-align: justify; 558 | } 559 | 560 | .mui-image--fix { 561 | display: block; 562 | } 563 | 564 | .mui--text-dark { 565 | color: #212121; 566 | } 567 | 568 | .mui--text-dark-secondary { 569 | color: #757575; 570 | } 571 | 572 | .mui--text-dark-hint { 573 | color: #9e9e9e; 574 | } 575 | 576 | .mui--text-light { 577 | color: #FFF; 578 | } 579 | 580 | .mui--text-light-secondary { 581 | color: #b3b3b3; 582 | } 583 | 584 | .mui--text-light-hint { 585 | color: gray; 586 | } 587 | 588 | .mui--text-accent { 589 | color: #FF4081; 590 | } 591 | 592 | .mui--text-accent-secondary { 593 | color: #ff82ad; 594 | } 595 | 596 | .mui--text-accent-hint { 597 | color: #ffa6c4; 598 | } 599 | 600 | .mui--text-black { 601 | color: #000; 602 | } 603 | 604 | .mui--text-white { 605 | color: #FFF; 606 | } 607 | 608 | .mui--text-danger { 609 | color: #F44336; 610 | } 611 | 612 | /** 613 | * MUI Email Typography 614 | */ 615 | .mui--text-display4 { 616 | font-weight: 300; 617 | font-size: 112px; 618 | line-height: 112px; 619 | } 620 | 621 | .mui--text-display3 { 622 | font-weight: 400; 623 | font-size: 56px; 624 | line-height: 56px; 625 | } 626 | 627 | .mui--text-display2 { 628 | font-weight: 400; 629 | font-size: 45px; 630 | line-height: 48px; 631 | } 632 | 633 | .mui--text-display1, h1 { 634 | font-weight: 400; 635 | font-size: 34px; 636 | line-height: 40px; 637 | } 638 | 639 | .mui--text-headline, h2 { 640 | font-weight: 400; 641 | font-size: 24px; 642 | line-height: 32px; 643 | } 644 | 645 | .mui--text-title, h3 { 646 | font-weight: 400; 647 | font-size: 20px; 648 | line-height: 28px; 649 | } 650 | 651 | .mui--text-subhead, h4 { 652 | font-weight: 400; 653 | font-size: 16px; 654 | line-height: 24px; 655 | } 656 | 657 | .mui--text-body2, h5 { 658 | font-weight: 500; 659 | font-size: 14px; 660 | line-height: 24px; 661 | } 662 | 663 | .mui--text-body1 { 664 | font-weight: 400; 665 | font-size: 14px; 666 | line-height: 20px; 667 | } 668 | 669 | .mui--text-caption { 670 | font-weight: 400; 671 | font-size: 12px; 672 | line-height: 16px; 673 | } 674 | 675 | .mui--text-menu { 676 | font-weight: 500; 677 | font-size: 13px; 678 | line-height: 17px; 679 | } 680 | 681 | .mui--text-button { 682 | font-weight: 500; 683 | font-size: 14px; 684 | line-height: 18px; 685 | text-transform: uppercase; 686 | } 687 | html,body,.mui-body{direction:rtl;} -------------------------------------------------------------------------------- /static-src/src/vendor/mui-0.9.17/email/mui-email-inline.css: -------------------------------------------------------------------------------- 1 | body { 2 | width: 100% !important; 3 | min-width: 100%; 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | img { 9 | border: 0 none; 10 | height: auto; 11 | line-height: 100%; 12 | outline: none; 13 | text-decoration: none; 14 | } 15 | 16 | a img { 17 | border: 0 none; 18 | } 19 | 20 | table { 21 | border-spacing: 0; 22 | border-collapse: collapse; 23 | } 24 | 25 | td { 26 | padding: 0; 27 | text-align: left; 28 | word-break: break-word; 29 | -webkit-hyphens: auto; 30 | -moz-hyphens: auto; 31 | hyphens: auto; 32 | border-collapse: collapse !important; 33 | } 34 | 35 | table, td { 36 | mso-table-lspace: 0pt; 37 | mso-table-rspace: 0pt; 38 | } 39 | 40 | body, 41 | table, 42 | td, 43 | p, 44 | a, 45 | li, 46 | blockquote { 47 | -webkit-text-size-adjust: 100%; 48 | -ms-text-size-adjust: 100%; 49 | } 50 | 51 | img { 52 | -ms-interpolation-mode: bicubic; 53 | } 54 | 55 | /** 56 | * MUI Colors module 57 | */ 58 | /** 59 | * MUI Email Reboot 60 | */ 61 | body { 62 | color: #212121; 63 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, "Trebuchet MS"; 64 | font-weight: 400; 65 | font-size: 14px; 66 | line-height: 1.429; 67 | letter-spacing: 0.001em; 68 | background-color: #FFF; 69 | } 70 | 71 | a { 72 | color: #2196F3; 73 | text-decoration: none; 74 | } 75 | 76 | p { 77 | margin: 0 0 10px; 78 | } 79 | 80 | hr { 81 | color: #e0e0e0; 82 | background-color: #e0e0e0; 83 | height: 1px; 84 | border: none; 85 | } 86 | 87 | strong { 88 | font-weight: 700; 89 | } 90 | 91 | h1, h2, h3 { 92 | margin-top: 20px; 93 | margin-bottom: 10px; 94 | } 95 | 96 | h4, h5, h6 { 97 | margin-top: 10px; 98 | margin-bottom: 10px; 99 | } 100 | 101 | /** 102 | * MUI Email Body Component 103 | */ 104 | .mui-body { 105 | margin: 0; 106 | padding: 0; 107 | height: 100%; 108 | width: 100%; 109 | color: #212121; 110 | font-family: "Helvetica Neue", Helvetica, Arial, Verdana, "Trebuchet MS"; 111 | font-weight: 400; 112 | font-size: 14px; 113 | line-height: 1.429; 114 | letter-spacing: 0.001em; 115 | background-color: #FFF; 116 | } 117 | 118 | /** 119 | * MUI Email Buttons 120 | */ 121 | .mui-btn { 122 | cursor: pointer; 123 | white-space: nowrap; 124 | } 125 | 126 | a.mui-btn { 127 | font-weight: 500; 128 | font-size: 14px; 129 | color: #212121; 130 | line-height: 14px; 131 | letter-spacing: 0.03em; 132 | text-transform: uppercase; 133 | border-top: 1px solid transparent; 134 | border-left: 1px solid transparent; 135 | border-right: 1px solid transparent; 136 | border-bottom: 1px solid transparent; 137 | border-top: 1px solid #FFF; 138 | border-left: 1px solid #FFF; 139 | border-right: 1px solid #FFF; 140 | border-bottom: 1px solid #FFF; 141 | color: #212121; 142 | background-color: #FFF; 143 | display: inline-block; 144 | text-decoration: none; 145 | text-align: center; 146 | border-radius: 3px; 147 | padding: 10px 25px; 148 | background-color: transparent; 149 | } 150 | 151 | a.mui-btn.mui-btn--raised { 152 | border-top: 1px solid #f2f2f2; 153 | border-left: 1px solid #e6e6e6; 154 | border-right: 1px solid #e6e6e6; 155 | border-bottom: 2px solid #bababa; 156 | } 157 | 158 | a.mui-btn.mui-btn--flat { 159 | background-color: transparent; 160 | color: #212121; 161 | border-top: 1px solid transparent; 162 | border-left: 1px solid transparent; 163 | border-right: 1px solid transparent; 164 | border-bottom: 1px solid transparent; 165 | } 166 | 167 | a.mui-btn.mui-btn--primary { 168 | border-top: 1px solid #2196F3; 169 | border-left: 1px solid #2196F3; 170 | border-right: 1px solid #2196F3; 171 | border-bottom: 1px solid #2196F3; 172 | color: #FFF; 173 | background-color: #2196F3; 174 | } 175 | 176 | a.mui-btn.mui-btn--primary.mui-btn--raised { 177 | border-top: 1px solid #51adf6; 178 | border-left: 1px solid #2196F3; 179 | border-right: 1px solid #2196F3; 180 | border-bottom: 2px solid #0a6ebd; 181 | } 182 | 183 | a.mui-btn.mui-btn--primary.mui-btn--flat { 184 | background-color: transparent; 185 | color: #2196F3; 186 | border-top: 1px solid transparent; 187 | border-left: 1px solid transparent; 188 | border-right: 1px solid transparent; 189 | border-bottom: 1px solid transparent; 190 | } 191 | 192 | a.mui-btn.mui-btn--danger { 193 | border-top: 1px solid #F44336; 194 | border-left: 1px solid #F44336; 195 | border-right: 1px solid #F44336; 196 | border-bottom: 1px solid #F44336; 197 | color: #FFF; 198 | background-color: #F44336; 199 | } 200 | 201 | a.mui-btn.mui-btn--danger.mui-btn--raised { 202 | border-top: 1px solid #f77066; 203 | border-left: 1px solid #F44336; 204 | border-right: 1px solid #F44336; 205 | border-bottom: 2px solid #d2190b; 206 | } 207 | 208 | a.mui-btn.mui-btn--danger.mui-btn--flat { 209 | background-color: transparent; 210 | color: #F44336; 211 | border-top: 1px solid transparent; 212 | border-left: 1px solid transparent; 213 | border-right: 1px solid transparent; 214 | border-bottom: 1px solid transparent; 215 | } 216 | 217 | a.mui-btn.mui-btn--dark { 218 | border-top: 1px solid #424242; 219 | border-left: 1px solid #424242; 220 | border-right: 1px solid #424242; 221 | border-bottom: 1px solid #424242; 222 | color: #FFF; 223 | background-color: #424242; 224 | } 225 | 226 | a.mui-btn.mui-btn--dark.mui-btn--raised { 227 | border-top: 1px solid #5c5c5c; 228 | border-left: 1px solid #424242; 229 | border-right: 1px solid #424242; 230 | border-bottom: 2px solid #1c1c1c; 231 | } 232 | 233 | a.mui-btn.mui-btn--dark.mui-btn--flat { 234 | background-color: transparent; 235 | color: #424242; 236 | border-top: 1px solid transparent; 237 | border-left: 1px solid transparent; 238 | border-right: 1px solid transparent; 239 | border-bottom: 1px solid transparent; 240 | } 241 | 242 | a.mui-btn.mui-btn--accent { 243 | border-top: 1px solid #FF4081; 244 | border-left: 1px solid #FF4081; 245 | border-right: 1px solid #FF4081; 246 | border-bottom: 1px solid #FF4081; 247 | color: #FFF; 248 | background-color: #FF4081; 249 | } 250 | 251 | a.mui-btn.mui-btn--accent.mui-btn--raised { 252 | border-top: 1px solid #ff73a3; 253 | border-left: 1px solid #FF4081; 254 | border-right: 1px solid #FF4081; 255 | border-bottom: 2px solid #f30053; 256 | } 257 | 258 | a.mui-btn.mui-btn--accent.mui-btn--flat { 259 | background-color: transparent; 260 | color: #FF4081; 261 | border-top: 1px solid transparent; 262 | border-left: 1px solid transparent; 263 | border-right: 1px solid transparent; 264 | border-bottom: 1px solid transparent; 265 | } 266 | 267 | table.mui-btn > tr > td, 268 | table.mui-btn > tbody > tr > td { 269 | background-color: #FFF; 270 | } 271 | 272 | table.mui-btn > tr > td > a, 273 | table.mui-btn > tbody > tr > td > a { 274 | color: #212121; 275 | border-top: 1px solid #FFF; 276 | border-left: 1px solid #FFF; 277 | border-right: 1px solid #FFF; 278 | border-bottom: 1px solid #FFF; 279 | } 280 | 281 | table.mui-btn.mui-btn--raised > tr > td > a, 282 | table.mui-btn.mui-btn--raised > tbody > tr > td > a { 283 | border-top: 1px solid #f2f2f2; 284 | border-left: 1px solid #e6e6e6; 285 | border-right: 1px solid #e6e6e6; 286 | border-bottom: 2px solid #bababa; 287 | } 288 | 289 | table.mui-btn.mui-btn--flat > tr > td, 290 | table.mui-btn.mui-btn--flat > tbody > tr > td { 291 | background-color: transparent; 292 | } 293 | 294 | table.mui-btn.mui-btn--flat > tr > td > a, 295 | table.mui-btn.mui-btn--flat > tbody > tr > td > a { 296 | color: #212121; 297 | border-top: 1px solid transparent; 298 | border-left: 1px solid transparent; 299 | border-right: 1px solid transparent; 300 | border-bottom: 1px solid transparent; 301 | } 302 | 303 | table.mui-btn > tr > td, 304 | table.mui-btn > tbody > tr > td { 305 | border-radius: 3px; 306 | } 307 | 308 | table.mui-btn > tr > td > a, 309 | table.mui-btn > tbody > tr > td > a { 310 | font-weight: 500; 311 | font-size: 14px; 312 | color: #212121; 313 | line-height: 14px; 314 | letter-spacing: 0.03em; 315 | text-transform: uppercase; 316 | border-top: 1px solid transparent; 317 | border-left: 1px solid transparent; 318 | border-right: 1px solid transparent; 319 | border-bottom: 1px solid transparent; 320 | display: inline-block; 321 | text-decoration: none; 322 | text-align: center; 323 | border-radius: 3px; 324 | padding: 10px 25px; 325 | background-color: transparent; 326 | } 327 | 328 | table.mui-btn.mui-btn--primary > tr > td, 329 | table.mui-btn.mui-btn--primary > tbody > tr > td { 330 | background-color: #2196F3; 331 | } 332 | 333 | table.mui-btn.mui-btn--primary > tr > td > a, 334 | table.mui-btn.mui-btn--primary > tbody > tr > td > a { 335 | color: #FFF; 336 | border-top: 1px solid #2196F3; 337 | border-left: 1px solid #2196F3; 338 | border-right: 1px solid #2196F3; 339 | border-bottom: 1px solid #2196F3; 340 | } 341 | 342 | table.mui-btn.mui-btn--primary.mui-btn--raised > tr > td > a, 343 | table.mui-btn.mui-btn--primary.mui-btn--raised > tbody > tr > td > a { 344 | border-top: 1px solid #51adf6; 345 | border-left: 1px solid #2196F3; 346 | border-right: 1px solid #2196F3; 347 | border-bottom: 2px solid #0a6ebd; 348 | } 349 | 350 | table.mui-btn.mui-btn--primary.mui-btn--flat > tr > td, 351 | table.mui-btn.mui-btn--primary.mui-btn--flat > tbody > tr > td { 352 | background-color: transparent; 353 | } 354 | 355 | table.mui-btn.mui-btn--primary.mui-btn--flat > tr > td > a, 356 | table.mui-btn.mui-btn--primary.mui-btn--flat > tbody > tr > td > a { 357 | color: #2196F3; 358 | border-top: 1px solid transparent; 359 | border-left: 1px solid transparent; 360 | border-right: 1px solid transparent; 361 | border-bottom: 1px solid transparent; 362 | } 363 | 364 | table.mui-btn.mui-btn--danger > tr > td, 365 | table.mui-btn.mui-btn--danger > tbody > tr > td { 366 | background-color: #F44336; 367 | } 368 | 369 | table.mui-btn.mui-btn--danger > tr > td > a, 370 | table.mui-btn.mui-btn--danger > tbody > tr > td > a { 371 | color: #FFF; 372 | border-top: 1px solid #F44336; 373 | border-left: 1px solid #F44336; 374 | border-right: 1px solid #F44336; 375 | border-bottom: 1px solid #F44336; 376 | } 377 | 378 | table.mui-btn.mui-btn--danger.mui-btn--raised > tr > td > a, 379 | table.mui-btn.mui-btn--danger.mui-btn--raised > tbody > tr > td > a { 380 | border-top: 1px solid #f77066; 381 | border-left: 1px solid #F44336; 382 | border-right: 1px solid #F44336; 383 | border-bottom: 2px solid #d2190b; 384 | } 385 | 386 | table.mui-btn.mui-btn--danger.mui-btn--flat > tr > td, 387 | table.mui-btn.mui-btn--danger.mui-btn--flat > tbody > tr > td { 388 | background-color: transparent; 389 | } 390 | 391 | table.mui-btn.mui-btn--danger.mui-btn--flat > tr > td > a, 392 | table.mui-btn.mui-btn--danger.mui-btn--flat > tbody > tr > td > a { 393 | color: #F44336; 394 | border-top: 1px solid transparent; 395 | border-left: 1px solid transparent; 396 | border-right: 1px solid transparent; 397 | border-bottom: 1px solid transparent; 398 | } 399 | 400 | table.mui-btn.mui-btn--dark > tr > td, 401 | table.mui-btn.mui-btn--dark > tbody > tr > td { 402 | background-color: #424242; 403 | } 404 | 405 | table.mui-btn.mui-btn--dark > tr > td > a, 406 | table.mui-btn.mui-btn--dark > tbody > tr > td > a { 407 | color: #FFF; 408 | border-top: 1px solid #424242; 409 | border-left: 1px solid #424242; 410 | border-right: 1px solid #424242; 411 | border-bottom: 1px solid #424242; 412 | } 413 | 414 | table.mui-btn.mui-btn--dark.mui-btn--raised > tr > td > a, 415 | table.mui-btn.mui-btn--dark.mui-btn--raised > tbody > tr > td > a { 416 | border-top: 1px solid #5c5c5c; 417 | border-left: 1px solid #424242; 418 | border-right: 1px solid #424242; 419 | border-bottom: 2px solid #1c1c1c; 420 | } 421 | 422 | table.mui-btn.mui-btn--dark.mui-btn--flat > tr > td, 423 | table.mui-btn.mui-btn--dark.mui-btn--flat > tbody > tr > td { 424 | background-color: transparent; 425 | } 426 | 427 | table.mui-btn.mui-btn--dark.mui-btn--flat > tr > td > a, 428 | table.mui-btn.mui-btn--dark.mui-btn--flat > tbody > tr > td > a { 429 | color: #424242; 430 | border-top: 1px solid transparent; 431 | border-left: 1px solid transparent; 432 | border-right: 1px solid transparent; 433 | border-bottom: 1px solid transparent; 434 | } 435 | 436 | table.mui-btn.mui-btn--accent > tr > td, 437 | table.mui-btn.mui-btn--accent > tbody > tr > td { 438 | background-color: #FF4081; 439 | } 440 | 441 | table.mui-btn.mui-btn--accent > tr > td > a, 442 | table.mui-btn.mui-btn--accent > tbody > tr > td > a { 443 | color: #FFF; 444 | border-top: 1px solid #FF4081; 445 | border-left: 1px solid #FF4081; 446 | border-right: 1px solid #FF4081; 447 | border-bottom: 1px solid #FF4081; 448 | } 449 | 450 | table.mui-btn.mui-btn--accent.mui-btn--raised > tr > td > a, 451 | table.mui-btn.mui-btn--accent.mui-btn--raised > tbody > tr > td > a { 452 | border-top: 1px solid #ff73a3; 453 | border-left: 1px solid #FF4081; 454 | border-right: 1px solid #FF4081; 455 | border-bottom: 2px solid #f30053; 456 | } 457 | 458 | table.mui-btn.mui-btn--accent.mui-btn--flat > tr > td, 459 | table.mui-btn.mui-btn--accent.mui-btn--flat > tbody > tr > td { 460 | background-color: transparent; 461 | } 462 | 463 | table.mui-btn.mui-btn--accent.mui-btn--flat > tr > td > a, 464 | table.mui-btn.mui-btn--accent.mui-btn--flat > tbody > tr > td > a { 465 | color: #FF4081; 466 | border-top: 1px solid transparent; 467 | border-left: 1px solid transparent; 468 | border-right: 1px solid transparent; 469 | border-bottom: 1px solid transparent; 470 | } 471 | 472 | a.mui-btn--small, 473 | table.mui-btn--small > tr > td > a, 474 | table.mui-btn--small > tbody > tr > td > a { 475 | font-size: 13px; 476 | padding: 7.8px 15px; 477 | } 478 | 479 | a.mui-btn--large, 480 | table.mui-btn--large > tr > td > a, 481 | table.mui-btn--large > tbody > tr > td > a { 482 | font-size: 14px; 483 | padding: 19px 25px; 484 | } 485 | 486 | /** 487 | * MUI Email Containers 488 | */ 489 | .mui-container, .mui-container-fixed { 490 | max-width: 600px; 491 | display: block; 492 | margin: 0 auto; 493 | clear: both; 494 | text-align: left; 495 | padding-left: 15px; 496 | padding-right: 15px; 497 | } 498 | 499 | .mui-container-fixed { 500 | width: 600px; 501 | } 502 | 503 | /** 504 | * MUI Email Dividers 505 | */ 506 | .mui-divider { 507 | display: block; 508 | height: 1px; 509 | background-color: #e0e0e0; 510 | } 511 | 512 | .mui--divider-top { 513 | border-top: 1px solid #e0e0e0; 514 | } 515 | 516 | .mui--divider-bottom { 517 | border-bottom: 1px solid #e0e0e0; 518 | } 519 | 520 | .mui--divider-left { 521 | border-left: 1px solid #e0e0e0; 522 | } 523 | 524 | .mui--divider-right { 525 | border-right: 1px solid #e0e0e0; 526 | } 527 | 528 | /** 529 | * MUI Email Panel 530 | */ 531 | .mui-panel { 532 | padding: 15px; 533 | border-radius: 0; 534 | background-color: #FFF; 535 | border-top: 1px solid #ededed; 536 | border-left: 1px solid #e6e6e6; 537 | border-right: 1px solid #e6e6e6; 538 | border-bottom: 2px solid #d4d4d4; 539 | } 540 | 541 | /** 542 | * MUI Email Helpers 543 | */ 544 | .mui--text-left { 545 | text-align: left; 546 | } 547 | 548 | .mui--text-right { 549 | text-align: right; 550 | } 551 | 552 | .mui--text-center { 553 | text-align: center; 554 | } 555 | 556 | .mui--text-justify { 557 | text-align: justify; 558 | } 559 | 560 | .mui-image--fix { 561 | display: block; 562 | } 563 | 564 | .mui--text-dark { 565 | color: #212121; 566 | } 567 | 568 | .mui--text-dark-secondary { 569 | color: #757575; 570 | } 571 | 572 | .mui--text-dark-hint { 573 | color: #9e9e9e; 574 | } 575 | 576 | .mui--text-light { 577 | color: #FFF; 578 | } 579 | 580 | .mui--text-light-secondary { 581 | color: #b3b3b3; 582 | } 583 | 584 | .mui--text-light-hint { 585 | color: gray; 586 | } 587 | 588 | .mui--text-accent { 589 | color: #FF4081; 590 | } 591 | 592 | .mui--text-accent-secondary { 593 | color: #ff82ad; 594 | } 595 | 596 | .mui--text-accent-hint { 597 | color: #ffa6c4; 598 | } 599 | 600 | .mui--text-black { 601 | color: #000; 602 | } 603 | 604 | .mui--text-white { 605 | color: #FFF; 606 | } 607 | 608 | .mui--text-danger { 609 | color: #F44336; 610 | } 611 | 612 | /** 613 | * MUI Email Typography 614 | */ 615 | .mui--text-display4 { 616 | font-weight: 300; 617 | font-size: 112px; 618 | line-height: 112px; 619 | } 620 | 621 | .mui--text-display3 { 622 | font-weight: 400; 623 | font-size: 56px; 624 | line-height: 56px; 625 | } 626 | 627 | .mui--text-display2 { 628 | font-weight: 400; 629 | font-size: 45px; 630 | line-height: 48px; 631 | } 632 | 633 | .mui--text-display1, h1 { 634 | font-weight: 400; 635 | font-size: 34px; 636 | line-height: 40px; 637 | } 638 | 639 | .mui--text-headline, h2 { 640 | font-weight: 400; 641 | font-size: 24px; 642 | line-height: 32px; 643 | } 644 | 645 | .mui--text-title, h3 { 646 | font-weight: 400; 647 | font-size: 20px; 648 | line-height: 28px; 649 | } 650 | 651 | .mui--text-subhead, h4 { 652 | font-weight: 400; 653 | font-size: 16px; 654 | line-height: 24px; 655 | } 656 | 657 | .mui--text-body2, h5 { 658 | font-weight: 500; 659 | font-size: 14px; 660 | line-height: 24px; 661 | } 662 | 663 | .mui--text-body1 { 664 | font-weight: 400; 665 | font-size: 14px; 666 | line-height: 20px; 667 | } 668 | 669 | .mui--text-caption { 670 | font-weight: 400; 671 | font-size: 12px; 672 | line-height: 16px; 673 | } 674 | 675 | .mui--text-menu { 676 | font-weight: 500; 677 | font-size: 13px; 678 | line-height: 17px; 679 | } 680 | 681 | .mui--text-button { 682 | font-weight: 500; 683 | font-size: 14px; 684 | line-height: 18px; 685 | text-transform: uppercase; 686 | } 687 | -------------------------------------------------------------------------------- /static-src/src/vendor/mui-0.9.17/email/mui-email-styletag-rtl.css: -------------------------------------------------------------------------------- 1 | /** 2 | * MUI Colors module 3 | */ 4 | /** 5 | * MUI Email Styletag 6 | */ 7 | #outlook a { 8 | padding: 0; 9 | } 10 | 11 | .ReadMsgBody { 12 | width: 100%; 13 | } 14 | 15 | .ExternalClass { 16 | width: 100%; 17 | } 18 | 19 | .ExternalClass, 20 | .ExternalClass p, 21 | .ExternalClass span, 22 | .ExternalClass font, 23 | .ExternalClass td, 24 | .ExternalClass div { 25 | line-height: 100%; 26 | } 27 | 28 | .mui-container-fixed { 29 | width: 600px; 30 | display: block; 31 | margin: 0 auto; 32 | clear: both; 33 | text-align: right; 34 | padding-right: 15px; 35 | padding-left: 15px; 36 | } 37 | -------------------------------------------------------------------------------- /static-src/src/vendor/mui-0.9.17/email/mui-email-styletag.css: -------------------------------------------------------------------------------- 1 | /** 2 | * MUI Colors module 3 | */ 4 | /** 5 | * MUI Email Styletag 6 | */ 7 | #outlook a { 8 | padding: 0; 9 | } 10 | 11 | .ReadMsgBody { 12 | width: 100%; 13 | } 14 | 15 | .ExternalClass { 16 | width: 100%; 17 | } 18 | 19 | .ExternalClass, 20 | .ExternalClass p, 21 | .ExternalClass span, 22 | .ExternalClass font, 23 | .ExternalClass td, 24 | .ExternalClass div { 25 | line-height: 100%; 26 | } 27 | 28 | .mui-container-fixed { 29 | width: 600px; 30 | display: block; 31 | margin: 0 auto; 32 | clear: both; 33 | text-align: left; 34 | padding-left: 15px; 35 | padding-right: 15px; 36 | } 37 | -------------------------------------------------------------------------------- /static-src/src/vendor/mui-0.9.17/js/mui.min.js: -------------------------------------------------------------------------------- 1 | !function t(e,i,n){function o(s,a){if(!i[s]){if(!e[s]){var l="function"==typeof require&&require;if(!a&&l)return l(s,!0);if(r)return r(s,!0);throw new Error("Cannot find module '"+s+"'")}var u=i[s]={exports:{}};e[s][0].call(u.exports,function(t){var i=e[s][1][t];return o(i||t)},u,u.exports,t,e,i,n)}return i[s].exports}for(var r="function"==typeof require&&require,s=0;s input","mui-textfield-inserted"],[".mui-textfield > textarea","mui-textfield-inserted"],[".mui-textfield > input:-webkit-autofill","mui-textfield-autofill"],[".mui-textfield > textarea:-webkit-autofill","mui-textfield-autofill"],[".mui-select > select","mui-select-inserted"],[".mui-select > select ~ .mui-event-trigger","mui-node-inserted"],[".mui-select > select:disabled ~ .mui-event-trigger","mui-node-disabled"]],i="",n=0,o=e.length;nd&&(p=s+(i+1)*r-(-1*a+n+o),h=e*r+2*s-f,v=Math.min(p,h)),{height:f+"px",top:a+"px",scrollTop:v}}}},{}],5:[function(t,e,i){"use strict";function n(t){if(void 0===t)return"undefined";var e=Object.prototype.toString.call(t);if(0===e.indexOf("[object "))return e.slice(8,-1).toLowerCase();throw new Error("MUI: Could not understand type: "+e)}function o(t,e,i,n){n=void 0!==n&&n;var o=t._muiEventCache=t._muiEventCache||{};e.split(" ").map(function(e){t.addEventListener(e,i,n),o[e]=o[e]||[],o[e].push([i,n])})}function r(t,e,i,n){n=void 0!==n&&n;var o,r,s,a=t._muiEventCache=t._muiEventCache||{};e.split(" ").map(function(e){for(s=(o=a[e]||[]).length;s--;)r=o[s],(void 0===i||r[0]===i&&r[1]===n)&&(o.splice(s,1),t.removeEventListener(e,r[0],r[1]))})}function s(t,e){var i=window;if(void 0===e){if(t===i){var n=document.documentElement;return(i.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}return t.scrollLeft}t===i?i.scrollTo(e,a(i)):t.scrollLeft=e}function a(t,e){var i=window;if(void 0===e){if(t===i){var n=document.documentElement;return(i.pageYOffset||n.scrollTop)-(n.clientTop||0)}return t.scrollTop}t===i?i.scrollTo(s(i),e):t.scrollTop=e}function l(t){return" "+(t.getAttribute("class")||"").replace(/[\n\t]/g,"")+" "}function u(t){return t.replace(d,function(t,e,i,n){return n?i.toUpperCase():i}).replace(m,"Moz$1")}function c(t,e,i){var n;return""!==(n=i.getPropertyValue(e))||t.ownerDocument||(n=t.style[u(e)]),n}var d=/([\:\-\_]+(.))/g,m=/^moz([A-Z])/;e.exports={addClass:function(t,e){if(e&&t.setAttribute){for(var i,n=l(t),o=e.split(" "),r=0;r-1},off:r,offset:function(t){var e=window,i=t.getBoundingClientRect(),n=a(e),o=s(e);return{top:i.top+n,left:i.left+o,height:i.height,width:i.width}},on:o,one:function(t,e,i,n){e.split(" ").map(function(e){o(t,e,function o(s){i&&i.apply(this,arguments),r(t,e,o,n)},n)})},ready:function(t){var e=!1,i=!0,n=document,o=n.defaultView,r=n.documentElement,s=n.addEventListener?"addEventListener":"attachEvent",a=n.addEventListener?"removeEventListener":"detachEvent",l=n.addEventListener?"":"on",u=function(i){"readystatechange"==i.type&&"complete"!=n.readyState||(("load"==i.type?o:n)[a](l+i.type,u,!1),!e&&(e=!0)&&t.call(o,i.type||i))},c=function(){try{r.doScroll("left")}catch(t){return void setTimeout(c,50)}u("poll")};if("complete"==n.readyState)t.call(o,"lazy");else{if(n.createEventObject&&r.doScroll){try{i=!o.frameElement}catch(t){}i&&c()}n[s](l+"DOMContentLoaded",u,!1),n[s](l+"readystatechange",u,!1),o[s](l+"load",u,!1)}},removeClass:function(t,e){if(e&&t.setAttribute){for(var i,n=l(t),o=e.split(" "),r=0;r=0;)n=n.replace(" "+i+" "," ");t.setAttribute("class",n.trim())}},type:n,scrollLeft:s,scrollTop:a}},{}],6:[function(t,e,i){"use strict";function n(t){var e,i=document;e=i.head||i.getElementsByTagName("head")[0]||i.documentElement;var n=i.createElement("style");return n.type="text/css",n.styleSheet?n.styleSheet.cssText=t:n.appendChild(i.createTextNode(t)),e.insertBefore(n,e.firstChild),n}var o,r,s,a,l,u=t("../config"),c=t("./jqLite"),d=0,m="mui-scroll-lock";s=function(t){t.target.tagName||t.stopImmediatePropagation()};var f=function(){if(void 0!==a)return a;var t=document,e=t.body,i=t.createElement("div");return i.innerHTML='
',i=i.firstChild,e.appendChild(i),a=i.offsetWidth-i.clientWidth,e.removeChild(i),a};e.exports={callback:function(t,e){return function(){t[e].apply(t,arguments)}},classNames:function(t){var e="";for(var i in t)e+=t[i]?i+" ":"";return e.trim()},disableScrollLock:function(t){0!==d&&0==(d-=1)&&(c.removeClass(document.body,m),r.parentNode.removeChild(r),t&&window.scrollTo(o.left,o.top),c.off(window,"scroll",s,!0))},dispatchEvent:function(t,e,i,n,o){var r,s=document.createEvent("HTMLEvents"),i=void 0===i||i,n=void 0===n||n;if(s.initEvent(e,i,n),o)for(r in o)s[r]=o[r];return t&&t.dispatchEvent(s),s},enableScrollLock:function(){if(1===(d+=1)){var t,e,i,a=document,l=window,u=a.documentElement,p=a.body,h=f();t=["overflow:hidden"],h&&(u.scrollHeight>u.clientHeight&&(i=parseInt(c.css(p,"padding-right"))+h,t.push("padding-right:"+i+"px")),u.scrollWidth>u.clientWidth&&(i=parseInt(c.css(p,"padding-bottom"))+h,t.push("padding-bottom:"+i+"px"))),e="."+m+"{",e+=t.join(" !important;")+" !important;}",r=n(e),c.on(l,"scroll",s,!0),o={left:c.scrollLeft(l),top:c.scrollTop(l)},c.addClass(p,m)}},log:function(){var t=window;if(u.debug&&void 0!==t.console)try{t.console.log.apply(t.console,arguments)}catch(i){var e=Array.prototype.slice.call(arguments);t.console.log(e.join("\n"))}},loadStyle:n,raiseError:function(t,e){if(!e)throw new Error("MUI: "+t);"undefined"!=typeof console&&console.error("MUI Warning: "+t)},requestAnimationFrame:function(t){var e=window.requestAnimationFrame;e?e(t):setTimeout(t,0)},supportsPointerEvents:function(){if(void 0!==l)return l;var t=document.createElement("x");return t.style.cssText="pointer-events:auto",l="auto"===t.style.pointerEvents}}},{"../config":2,"./jqLite":5}],7:[function(t,e,i){"use strict";function n(t){if(!0!==t._muiDropdown){t._muiDropdown=!0;var e=t.tagName;"INPUT"!==e&&"BUTTON"!==e||t.hasAttribute("type")||(t.type="button"),s.on(t,"click",o)}}function o(t){if(0===t.button){var e=this;null===e.getAttribute("disabled")&&r(e)}}function r(t){function e(){s.removeClass(n,u),s.off(o,"click",e)}var i=t.parentNode,n=t.nextElementSibling,o=i.ownerDocument;if(!n||!s.hasClass(n,c))return a.raiseError("Dropdown menu element not found");s.hasClass(n,u)?e():function(){var r=i.getBoundingClientRect(),a=t.getBoundingClientRect(),l=a.top-r.top+a.height;s.css(n,"top",l+"px"),s.addClass(n,u),setTimeout(function(){s.on(o,"click",e)},0)}()}var s=t("./lib/jqLite"),a=t("./lib/util"),l=t("./lib/animationHelpers"),u="mui--is-open",c="mui-dropdown__menu";e.exports={initListeners:function(){for(var t=document.querySelectorAll('[data-mui-toggle="dropdown"]'),e=t.length;e--;)n(t[e]);l.onAnimationStart("mui-dropdown-inserted",function(t){n(t.target)})}}},{"./lib/animationHelpers":3,"./lib/jqLite":5,"./lib/util":6}],8:[function(t,e,i){e.exports=t(5)},{}],9:[function(t,e,i){"use strict";function n(t,e){var i=document,n=i.body,o=i.getElementById(p);if(i.activeElement&&(d=i.activeElement),m.enableScrollLock(),o){for(;o.firstChild;)o.removeChild(o.firstChild);e&&o.appendChild(e)}else(o=i.createElement("div")).setAttribute("id",p),o.setAttribute("tabindex","-1"),e&&o.appendChild(e),n.appendChild(o);return h.test(navigator.userAgent)&&f.css(o,"cursor","pointer"),t.keyboard?r():s(),t.static?u(o):l(o),o.muiOptions=t,o.focus(),o}function o(){var t,e=document.getElementById(p);if(e){for(;e.firstChild;)e.removeChild(e.firstChild);e.parentNode.removeChild(e),t=e.muiOptions.onclose,u(e)}return m.disableScrollLock(),s(),d&&d.focus(),t&&t(),e}function r(){f.on(document,"keyup",a)}function s(){f.off(document,"keyup",a)}function a(t){27===t.keyCode&&o()}function l(t){f.on(t,"click",c)}function u(t){f.off(t,"click",c)}function c(t){t.target.id===p&&o()}var d,m=t("./lib/util"),f=t("./lib/jqLite"),p="mui-overlay",h=/(iPad|iPhone|iPod)/g;e.exports=function(t){var e;if("on"===t){for(var i,r,s,a=arguments.length-1;a>0;a--)i=arguments[a],"object"===f.type(i)&&(r=i),i instanceof Element&&1===i.nodeType&&(s=i);void 0===(r=r||{}).keyboard&&(r.keyboard=!0),void 0===r.static&&(r.static=!1),e=n(r,s)}else"off"===t?e=o():m.raiseError("Expecting 'on' or 'off'");return e}},{"./lib/jqLite":5,"./lib/util":6}],10:[function(t,e,i){"use strict";function n(t){!0!==t._muiRipple&&(t._muiRipple=!0,"INPUT"!==t.tagName&&s.on(t,c,o))}function o(t){if("mousedown"!==t.type||0===t.button){var e=this,i=e._rippleEl;if(!e.disabled){if(!i){var n=document.createElement("span");n.className="mui-btn__ripple-container",n.innerHTML='',e.appendChild(n),i=e._rippleEl=n.children[0],s.on(e,d,r)}var o,l,u=s.offset(e),c="touchstart"===t.type?t.touches[0]:t;l=2*(o=Math.sqrt(u.height*u.height+u.width*u.width))+"px",s.css(i,{width:l,height:l,top:Math.round(c.pageY-u.top-o)+"px",left:Math.round(c.pageX-u.left-o)+"px"}),s.removeClass(i,"mui--is-animating"),s.addClass(i,"mui--is-visible"),a.requestAnimationFrame(function(){s.addClass(i,"mui--is-animating")})}}}function r(t){var e=this._rippleEl;a.requestAnimationFrame(function(){s.removeClass(e,"mui--is-visible")})}var s=t("./lib/jqLite"),a=t("./lib/util"),l=t("./lib/animationHelpers"),u="ontouchstart"in document.documentElement,c=u?"touchstart":"mousedown",d=u?"touchend":"mouseup mouseleave";e.exports={initListeners:function(){for(var t=document.getElementsByClassName("mui-btn"),e=t.length;e--;)n(t[e]);l.onAnimationStart("mui-btn-inserted",function(t){n(t.target)})}}},{"./lib/animationHelpers":3,"./lib/jqLite":5,"./lib/util":6}],11:[function(t,e,i){"use strict";function n(t){if(!0!==t._muiSelect&&(t._muiSelect=!0,!("ontouchstart"in v.documentElement))){var e=t.parentNode;e._selectEl=t,e._menu=null,e._q="",e._qTimeout=null,t.disabled||(e.tabIndex=0),t.tabIndex=-1,d.on(t,"mousedown",o),d.on(e,"click",l),d.on(e,"blur focus",r),d.on(e,"keydown",s),d.on(e,"keypress",a);var i=document.createElement("div");i.className="mui-event-trigger",e.appendChild(i),d.on(i,f.animationEvents,function(t){t.stopPropagation(),"mui-node-disabled"===t.animationName?t.target.parentNode.removeAttribute("tabIndex"):t.target.parentNode.tabIndex=0})}}function o(t){0===t.button&&t.preventDefault()}function r(t){m.dispatchEvent(this._selectEl,t.type,!1,!1)}function s(t){if(!t.defaultPrevented){var e=t.keyCode,i=this._menu;if(i){if(9===e)return i.destroy();27!==e&&40!==e&&38!==e&&13!==e||t.preventDefault(),27===e?i.destroy():40===e?i.increment():38===e?i.decrement():13===e&&(i.selectCurrent(),i.destroy())}else 32!==e&&38!==e&&40!==e||(t.preventDefault(),u(this))}}function a(t){var e=this._menu;if(!t.defaultPrevented&&e){var i=this;clearTimeout(this._qTimeout),this._q+=t.key,this._qTimeout=setTimeout(function(){i._q=""},300);var n,o=new RegExp("^"+this._q,"i"),r=e.itemArray;for(n in r)if(o.test(r[n].innerText)){e.selectPos(n);break}}}function l(t){0!==t.button||this._selectEl.disabled||(this.focus(),u(this))}function u(t){t._menu||(t._menu=new c(t,t._selectEl,function(){t._menu=null,t.focus()}))}function c(t,e,i){m.enableScrollLock(),this.itemArray=[],this.origPos=null,this.currentPos=null,this.selectEl=e,this.wrapperEl=t,this.menuEl=this._createMenuEl(t,e);var n=m.callback;this.onClickCB=n(this,"onClick"),this.destroyCB=n(this,"destroy"),this.wrapperCallbackFn=i,t.appendChild(this.menuEl),d.scrollTop(this.menuEl,this.menuEl._scrollTop);var o=this.destroyCB;d.on(this.menuEl,"click",this.onClickCB),d.on(b,"resize",o),setTimeout(function(){d.on(v,"click",o)},0)}var d=t("./lib/jqLite"),m=t("./lib/util"),f=t("./lib/animationHelpers"),p=t("./lib/forms"),h="mui--is-selected",v=document,b=window;c.prototype._createMenuEl=function(t,e){var i,n,o,r,s,a,l,u,c=v.createElement("div"),m=e.children,f=this.itemArray,b=0,g=0,y=0,C=document.createDocumentFragment();for(c.className="mui-select__menu",s=0,a=m.length;s select"),e=t.length;e--;)n(t[e]);f.onAnimationStart("mui-select-inserted",function(t){n(t.target)})}}},{"./lib/animationHelpers":3,"./lib/forms":4,"./lib/jqLite":5,"./lib/util":6}],12:[function(t,e,i){"use strict";function n(t){!0!==t._muiTabs&&(t._muiTabs=!0,a.on(t,"click",o))}function o(t){if(0===t.button){var e=this;null===e.getAttribute("disabled")&&r(e)}}function r(t){var e,i,n,o,r,u,v,b,g,y=t.parentNode,C=t.getAttribute(c),E=document.getElementById(C);a.hasClass(y,d)||(E||l.raiseError('Tab pane "'+C+'" not found'),n=(i=s(E)).id,g="["+c+'="'+n+'"]',o=document.querySelectorAll(g)[0],e=o.parentNode,r={paneId:C,relatedPaneId:n},u={paneId:n,relatedPaneId:C},v=l.dispatchEvent(o,p,!0,!0,u),b=l.dispatchEvent(t,m,!0,!0,r),setTimeout(function(){v.defaultPrevented||b.defaultPrevented||(e&&a.removeClass(e,d),i&&a.removeClass(i,d),a.addClass(y,d),a.addClass(E,d),l.dispatchEvent(o,h,!0,!1,u),l.dispatchEvent(t,f,!0,!1,r))},0))}function s(t){for(var e,i=t.parentNode.children,n=i.length,o=null;n--&&!o;)(e=i[n])!==t&&a.hasClass(e,d)&&(o=e);return o}var a=t("./lib/jqLite"),l=t("./lib/util"),u=t("./lib/animationHelpers"),c="data-mui-controls",d="mui--is-active",m="mui.tabs.showstart",f="mui.tabs.showend",p="mui.tabs.hidestart",h="mui.tabs.hideend";e.exports={initListeners:function(){for(var t=document.querySelectorAll('[data-mui-toggle="tab"]'),e=t.length;e--;)n(t[e]);u.onAnimationStart("mui-tab-inserted",function(t){n(t.target)})},api:{activate:function(t){var e="["+c+"="+t+"]",i=document.querySelectorAll(e);i.length||l.raiseError('Tab control for pane "'+t+'" not found'),r(i[0])}}}},{"./lib/animationHelpers":3,"./lib/jqLite":5,"./lib/util":6}],13:[function(t,e,i){"use strict";function n(t){!0!==t._muiTextfield&&(t._muiTextfield=!0,t.value.length?s.addClass(t,p):s.addClass(t,f),s.addClass(t,c+" "+d),s.on(t,"blur",function e(){document.activeElement!==t&&(s.removeClass(t,c),s.addClass(t,u),s.off(t,"blur",e))}),s.one(t,"input change",function(){s.removeClass(t,d),s.addClass(t,m)}),s.on(t,"input change",o))}function o(){var t=this;t.value.length?(s.removeClass(t,f),s.addClass(t,p)):(s.removeClass(t,p),s.addClass(t,f))}function r(t){!0===t._muiTextfield&&o.call(t)}var s=t("./lib/jqLite"),a=t("./lib/util"),l=t("./lib/animationHelpers"),u="mui--is-touched",c="mui--is-untouched",d="mui--is-pristine",m="mui--is-dirty",f="mui--is-empty",p="mui--is-not-empty";e.exports={initialize:n,initListeners:function(){for(var t=document,e=t.querySelectorAll(".mui-textfield > input, .mui-textfield > textarea"),i=e.length;i--;)n(e[i]);l.onAnimationStart("mui-textfield-inserted",function(t){n(t.target)}),setTimeout(function(){var t=".mui-textfield.mui-textfield--float-label > label {"+["-webkit-transition","-moz-transition","-o-transition","transition",""].join(":all .15s ease-out;")+"}";a.loadStyle(t)},150),l.onAnimationStart("mui-textfield-autofill",function(t){r(t.target)}),!1===a.supportsPointerEvents()&&s.on(t,"click",function(t){var e=t.target;if("LABEL"===e.tagName&&s.hasClass(e.parentNode,"mui-textfield--float-label")){var i=e.previousElementSibling;i&&i.focus()}})}}},{"./lib/animationHelpers":3,"./lib/jqLite":5,"./lib/util":6}]},{},[1]); -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amorey/flaskapp/6f301397b3d45511d3360f50fc9ac375a4b60fb8/tests/__init__.py -------------------------------------------------------------------------------- /tests/views/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | 4 | from flask import url_for 5 | 6 | from config import basedir 7 | from flaskapp import create_app 8 | from flaskapp.meta import db 9 | 10 | 11 | users = { 12 | 'userA': { 13 | 'email': 'barack@whitehouse.gov', 14 | 'password': 'imabelieber' 15 | }, 16 | 'userB': { 17 | 'email': 'bieber@bieber.com', 18 | 'password': 'imabelieber' 19 | } 20 | } 21 | 22 | 23 | class WebsiteTestCase(unittest.TestCase): 24 | # ============================== 25 | # Test-level setup/teardown 26 | # ============================== 27 | def setUp(self): 28 | db_url = 'sqlite:///' + os.path.join(basedir, 'test.db') 29 | self.app = create_app(extra_config={ 30 | 'TESTING': True, 31 | 'SERVER_NAME': 'example.com', 32 | 'WTF_CSRF_ENABLED': False, 33 | 'SQLALCHEMY_DATABASE_URI': db_url 34 | }) 35 | self.client = self.app.test_client() 36 | 37 | # setup database 38 | with self.app.app_context(): 39 | db.create_all() 40 | 41 | def tearDown(self): 42 | # teardown database 43 | with self.app.app_context(): 44 | db.session.remove() 45 | db.drop_all() 46 | 47 | # ============================== 48 | # Utility methods 49 | # ============================== 50 | def login(self, email, password): 51 | """Log in user and return response 52 | """ 53 | data = dict(email=email, password=password) 54 | return self.client.post(self.url_for('auth.login'), data=data) 55 | 56 | def logout(self): 57 | """Log out user and return response 58 | """ 59 | return self.client.get(self.url_for('auth.logout')) 60 | 61 | def create_account(self, email, password, password_confirm=None): 62 | """Create user account and return response 63 | """ 64 | if password_confirm == None: 65 | password_confirm = password 66 | 67 | data = dict(email=email, 68 | password=password, 69 | password_confirm=password_confirm) 70 | 71 | return self.client.post(self.url_for('auth.create_account'), data=data) 72 | 73 | def url_for(self, *args, **kwargs): 74 | """Return url generated within app context 75 | """ 76 | with self.app.app_context(): 77 | u = url_for(*args, **kwargs) 78 | return u 79 | -------------------------------------------------------------------------------- /tests/views/test_auth.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from flaskapp.meta import mail 4 | from flaskapp.models import User 5 | 6 | from . import WebsiteTestCase, users 7 | 8 | 9 | class AuthTests(WebsiteTestCase): 10 | def test_create_account(self): 11 | # test form page 12 | resp = self.client.get(self.url_for('auth.create_account')) 13 | self.assertEqual(resp.status_code, 200) 14 | self.assertTrue(b'Create a new account' \ 15 | in resp.data) 16 | 17 | email = users['userA']['email'] 18 | passwd = users['userA']['password'] 19 | 20 | # test bad email 21 | resp = self.create_account('barack', passwd) 22 | 23 | # test bad password confirmation 24 | resp = self.create_account(email, passwd, 'a') 25 | self.assertTrue(b'Passwords must match' in resp.data) 26 | 27 | # test good data 28 | resp = self.create_account(email, passwd, passwd) 29 | self.assertEqual(resp.status_code, 302) 30 | self.assertEqual(resp.headers['Location'], 31 | self.url_for('content.home')) 32 | 33 | resp = self.client.get(self.url_for('content.home')) 34 | self.assertTrue(email in resp.data.decode('utf-8')) 35 | 36 | def test_logout(self): 37 | email = users['userA']['email'] 38 | passwd = users['userA']['password'] 39 | self.create_account(email, passwd, passwd) 40 | 41 | resp = self.client.get(self.url_for('content.home')) 42 | self.assertTrue(email in resp.data.decode('utf-8')) 43 | 44 | resp = self.logout() 45 | self.assertEqual(resp.status_code, 302) 46 | 47 | resp = self.client.get(self.url_for('content.home')) 48 | self.assertFalse(email in resp.data.decode('utf-8')) 49 | 50 | def test_login(self): 51 | # test form page 52 | resp = self.client.get(self.url_for('auth.login')) 53 | self.assertEqual(resp.status_code, 200) 54 | self.assertTrue(b'Log in to your account' \ 55 | in resp.data) 56 | 57 | email = users['userA']['email'] 58 | passwd = users['userA']['password'] 59 | 60 | # test invalid login 61 | resp = self.login(email, passwd) 62 | self.assertTrue(b'Email and password must match' in resp.data) 63 | 64 | # create account 65 | self.create_account(email, passwd) 66 | resp = self.client.get(self.url_for('content.home')) 67 | self.assertTrue(email in resp.data.decode('utf-8')) 68 | 69 | self.logout() 70 | 71 | # test valid login 72 | resp = self.login(email, passwd) 73 | self.assertEqual(resp.status_code, 302) 74 | self.assertEqual(resp.headers['Location'], 75 | self.url_for('content.home')) 76 | 77 | resp = self.client.get(self.url_for('content.home')) 78 | self.assertTrue(email in resp.data.decode('utf-8')) 79 | 80 | def test_forgot(self): 81 | email = users['userA']['email'] 82 | passwd = users['userA']['password'] 83 | self.create_account(email, passwd) 84 | self.logout() 85 | 86 | # test forgot form 87 | resp = self.client.get(self.url_for('auth.forgot')) 88 | self.assertTrue(b'Reset your password' in resp.data) 89 | 90 | # test bad submission 91 | data = dict(email='doesntexist@example.com') 92 | resp = self.client.post(self.url_for('auth.forgot'), data=data) 93 | self.assertTrue(b'not registered' in resp.data) 94 | 95 | # test good submission 96 | with mail.record_messages() as outbox: 97 | data = dict(email=email) 98 | resp = self.client.post(self.url_for('auth.forgot'), data=data) 99 | self.assertTrue(b'Success' in resp.data) 100 | self.assertEqual(len(outbox), 1) 101 | self.assertEqual(outbox[0].subject, 'Password Reset Request') 102 | 103 | # get reset url 104 | m = re.search('/auth/reset-password.*$', outbox[0].body) 105 | reset_url = m.group(0) 106 | 107 | # test that key works 108 | resp = self.client.get(reset_url) 109 | self.assertTrue(b'Choose a new password' in resp.data) 110 | 111 | def test_reset_password(self): 112 | email = users['userA']['email'] 113 | passwd = users['userA']['password'] 114 | self.create_account(email, passwd) 115 | self.logout() 116 | 117 | # get reset url 118 | with mail.record_messages() as outbox: 119 | data = dict(email=email) 120 | resp = self.client.post(self.url_for('auth.forgot'), data=data) 121 | self.assertTrue(b'Success' in resp.data) 122 | self.assertEqual(len(outbox), 1) 123 | self.assertEqual(outbox[0].subject, 'Password Reset Request') 124 | 125 | m = re.search('/auth/reset-password.*$', outbox[0].body) 126 | reset_url = m.group(0) 127 | 128 | # test bad request 129 | resp = self.client.get(self.url_for('auth.reset_password')) 130 | self.assertTrue(b'Error' in resp.data) 131 | self.assertEqual(resp.status_code, 400) 132 | 133 | # test bad key 134 | u = self.url_for('auth.reset_password', key='badkey') 135 | resp = self.client.get(u) 136 | self.assertTrue(b'Error' in resp.data) 137 | 138 | # test good key, bad email 139 | u = re.sub('email=.*?&|$', '', reset_url) + 'email=bademail' 140 | resp = self.client.get(u) 141 | self.assertTrue(b'Error' in resp.data) 142 | 143 | # test good request 144 | resp = self.client.get(reset_url) 145 | self.assertEqual(resp.status_code, 200) 146 | 147 | # test submission 148 | data = dict(password='newpasswd', password_confirm='newpasswd') 149 | resp = self.client.post(reset_url, data=data) 150 | self.assertEqual(resp.status_code, 200) 151 | self.assertTrue(b'Success' in resp.data) 152 | 153 | # check that user is logged in 154 | resp = self.client.get('/') 155 | self.assertTrue(email in resp.data.decode('utf-8')) 156 | 157 | # check that new password works 158 | self.logout() 159 | self.login(email, data['password']) 160 | resp = self.client.get('/') 161 | self.assertTrue(email in resp.data.decode('utf-8')) 162 | 163 | def test_email_verification_request(self): 164 | email = users['userA']['email'] 165 | passwd = users['userA']['password'] 166 | self.create_account(email, passwd) 167 | 168 | # check user 169 | with self.app.app_context(): 170 | u = User.query.filter(User.email == email).first() 171 | self.assertEqual(u.is_verified, False) 172 | 173 | # test form 174 | resp = self.client.get(self.url_for('auth.email_verification_request')) 175 | self.assertTrue(b'Send verification request' \ 176 | in resp.data) 177 | 178 | # test submission 179 | with mail.record_messages() as outbox: 180 | url = self.url_for('auth.email_verification_request') 181 | resp = self.client.post(url) 182 | self.assertTrue(b'Success' in resp.data) 183 | self.assertEqual(len(outbox), 1) 184 | self.assertEqual(outbox[0].subject, 185 | 'Flaskapp Account: Please Confirm Email') 186 | 187 | # get reset url 188 | m = re.search('/auth/verify-email.*$', outbox[0].body) 189 | verify_url = m.group(0) 190 | 191 | # test bad request 192 | resp = self.client.get(self.url_for('auth.verify_email')) 193 | self.assertTrue(b'Error' in resp.data) 194 | self.assertEqual(resp.status_code, 400) 195 | 196 | # test bad key 197 | u = self.url_for('auth.verify_email', key='badkey') 198 | resp = self.client.get(u) 199 | self.assertTrue(b'Error' in resp.data) 200 | 201 | # test good key, bad email 202 | verify_url2 = re.sub('email=.*?&|$', '', verify_url) \ 203 | + 'email=bademail' 204 | resp = self.client.get(verify_url2) 205 | self.assertTrue(b'Error' in resp.data) 206 | 207 | # test good request 208 | resp = self.client.get(verify_url) 209 | self.assertTrue(b'Your email has been verified' in resp.data) 210 | 211 | # check user 212 | with self.app.app_context(): 213 | u = User.query.filter(User.email == email).first() 214 | self.assertEqual(u.is_verified, True) 215 | -------------------------------------------------------------------------------- /tests/views/test_content.py: -------------------------------------------------------------------------------- 1 | from . import WebsiteTestCase 2 | 3 | 4 | class ContentTests(WebsiteTestCase): 5 | def test_pages(self): 6 | urls = [ 7 | '/' 8 | ] 9 | 10 | # test that content pages return 200 status code 11 | for url in urls: 12 | resp = self.client.get(url) 13 | self.assertEqual(resp.status_code, 200, url) 14 | -------------------------------------------------------------------------------- /wsgi.py: -------------------------------------------------------------------------------- 1 | from flaskapp import create_app 2 | 3 | 4 | app = create_app() 5 | 6 | 7 | if __name__ == "__main__": 8 | from werkzeug.serving import run_simple 9 | 10 | app.jinja_env.auto_reload = True 11 | 12 | run_simple('0.0.0.0', 13 | 5000, 14 | app, 15 | threaded=True, 16 | use_reloader=True, 17 | use_debugger=True) 18 | --------------------------------------------------------------------------------