diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 72e294c..0000000 --- a/.dockerignore +++ /dev/null @@ -1,5 +0,0 @@ -.git -__pycache__ -*.pyc -*.pyo -*.pyd \ No newline at end of file diff --git a/.env b/.env deleted file mode 100644 index 43a1de8..0000000 --- a/.env +++ /dev/null @@ -1,8 +0,0 @@ -DEBUG=True -SECRET_KEY=S3cr3t_K#Key -DB_ENGINE=postgresql -DB_NAME=appseed-flask -DB_HOST=localhost -DB_PORT=5432 -DB_USERNAME=appseed -DB_PASS=pass diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 9fc790f..0000000 --- a/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -# byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] - -# tests and coverage -*.pytest_cache -.coverage - -# database & logs -*.db -*.sqlite3 -*.log - -# venv -env -venv - -# other -.DS_Store - -# sphinx docs -_build -_static -_templates - -# javascript -package-lock.json -.vscode/symbols.json - -apps/static/assets/node_modules -apps/static/assets/yarn.lock -apps/static/assets/.temp - diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 1f09130..0000000 --- a/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM python:3.9 - -COPY . . - -# set environment variables -ENV PYTHONDONTWRITEBYTECODE 1 -ENV PYTHONUNBUFFERED 1 - -# install python dependencies -RUN pip install --upgrade pip -RUN pip install --no-cache-dir -r requirements.txt - -# gunicorn -CMD ["gunicorn", "--config", "gunicorn-cfg.py", "run:app"] diff --git a/Procfile b/Procfile deleted file mode 100644 index a443d0f..0000000 --- a/Procfile +++ /dev/null @@ -1 +0,0 @@ -web: gunicorn run:app --log-file=- diff --git a/apps/__init__.py b/apps/__init__.py deleted file mode 100644 index f23857d..0000000 --- a/apps/__init__.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- encoding: utf-8 -*- -""" -Copyright (c) 2019 - present AppSeed.us -""" - -from flask import Flask -from flask_login import LoginManager -from flask_sqlalchemy import SQLAlchemy -from importlib import import_module - - -db = SQLAlchemy() -login_manager = LoginManager() - - -def register_extensions(app): - db.init_app(app) - login_manager.init_app(app) - - -def register_blueprints(app): - for module_name in ('authentication', 'home'): - module = import_module('apps.{}.routes'.format(module_name)) - app.register_blueprint(module.blueprint) - - -def configure_database(app): - - @app.before_first_request - def initialize_database(): - db.create_all() - - @app.teardown_request - def shutdown_session(exception=None): - db.session.remove() - - -def create_app(config): - app = Flask(__name__) - app.config.from_object(config) - register_extensions(app) - register_blueprints(app) - configure_database(app) - return app diff --git a/apps/authentication/__init__.py b/apps/authentication/__init__.py deleted file mode 100644 index 25243ec..0000000 --- a/apps/authentication/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- encoding: utf-8 -*- -""" -Copyright (c) 2019 - present AppSeed.us -""" - -from flask import Blueprint - -blueprint = Blueprint( - 'authentication_blueprint', - __name__, - url_prefix='' -) diff --git a/apps/authentication/forms.py b/apps/authentication/forms.py deleted file mode 100644 index 16cac6b..0000000 --- a/apps/authentication/forms.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- encoding: utf-8 -*- -""" -Copyright (c) 2019 - present AppSeed.us -""" - -from flask_wtf import FlaskForm -from wtforms import TextField, PasswordField -from wtforms.validators import Email, DataRequired - -# login and registration - - -class LoginForm(FlaskForm): - username = TextField('Username', - id='username_login', - validators=[DataRequired()]) - password = PasswordField('Password', - id='pwd_login', - validators=[DataRequired()]) - - -class CreateAccountForm(FlaskForm): - username = TextField('Username', - id='username_create', - validators=[DataRequired()]) - email = TextField('Email', - id='email_create', - validators=[DataRequired(), Email()]) - password = PasswordField('Password', - id='pwd_create', - validators=[DataRequired()]) diff --git a/apps/authentication/models.py b/apps/authentication/models.py deleted file mode 100644 index cf152ef..0000000 --- a/apps/authentication/models.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- encoding: utf-8 -*- -""" -Copyright (c) 2019 - present AppSeed.us -""" - -from flask_login import UserMixin - -from apps import db, login_manager - -from apps.authentication.util import hash_pass - -class Users(db.Model, UserMixin): - - __tablename__ = 'Users' - - id = db.Column(db.Integer, primary_key=True) - username = db.Column(db.String(64), unique=True) - email = db.Column(db.String(64), unique=True) - password = db.Column(db.LargeBinary) - - def __init__(self, **kwargs): - for property, value in kwargs.items(): - # depending on whether value is an iterable or not, we must - # unpack it's value (when **kwargs is request.form, some values - # will be a 1-element list) - if hasattr(value, '__iter__') and not isinstance(value, str): - # the ,= unpack of a singleton fails PEP8 (travis flake8 test) - value = value[0] - - if property == 'password': - value = hash_pass(value) # we need bytes here (not plain str) - - setattr(self, property, value) - - def __repr__(self): - return str(self.username) - - -@login_manager.user_loader -def user_loader(id): - return Users.query.filter_by(id=id).first() - - -@login_manager.request_loader -def request_loader(request): - username = request.form.get('username') - user = Users.query.filter_by(username=username).first() - return user if user else None diff --git a/apps/authentication/routes.py b/apps/authentication/routes.py deleted file mode 100644 index 23daf31..0000000 --- a/apps/authentication/routes.py +++ /dev/null @@ -1,127 +0,0 @@ -# -*- encoding: utf-8 -*- -""" -Copyright (c) 2019 - present AppSeed.us -""" - -from flask import render_template, redirect, request, url_for -from flask_login import ( - current_user, - login_user, - logout_user -) - -from apps import db, login_manager -from apps.authentication import blueprint -from apps.authentication.forms import LoginForm, CreateAccountForm -from apps.authentication.models import Users - -from apps.authentication.util import verify_pass - - -@blueprint.route('/') -def route_default(): - return redirect(url_for('authentication_blueprint.login')) - - -# Login & Registration - -@blueprint.route('/login', methods=['GET', 'POST']) -def login(): - login_form = LoginForm(request.form) - if 'login' in request.form: - - # read form data - username = request.form['username'] - password = request.form['password'] - - # Locate user - user = Users.query.filter_by(username=username).first() - - # Check the password - if user and verify_pass(password, user.password): - - login_user(user) - return redirect(url_for('authentication_blueprint.route_default')) - - # Something (user or pass) is not ok - return render_template('accounts/login.html', - segment = 'login', - msg='Wrong user or password', - form=login_form) - - if not current_user.is_authenticated: - return render_template('accounts/login.html', - segment = 'login', - form=login_form) - return redirect(url_for('home_blueprint.index')) - - -@blueprint.route('/register', methods=['GET', 'POST']) -def register(): - create_account_form = CreateAccountForm(request.form) - if 'register' in request.form: - - username = request.form['username'] - email = request.form['email'] - - # Check usename exists - user = Users.query.filter_by(username=username).first() - if user: - return render_template('accounts/register.html', - msg='Username already registered', - segment = 'register', - success=False, - form=create_account_form) - - # Check email exists - user = Users.query.filter_by(email=email).first() - if user: - return render_template('accounts/register.html', - msg='Email already registered', - segment = 'register', - success=False, - form=create_account_form) - - # else we can create the user - user = Users(**request.form) - db.session.add(user) - db.session.commit() - - return render_template('accounts/register.html', - msg='User created please login', - segment = 'register', - success=True, - form=create_account_form) - - else: - return render_template( 'accounts/register.html', - segment = 'register', - form=create_account_form) - - -@blueprint.route('/logout') -def logout(): - logout_user() - return redirect(url_for('authentication_blueprint.login')) - - -# Errors - -@login_manager.unauthorized_handler -def unauthorized_handler(): - return render_template('home/page-403.html'), 403 - - -@blueprint.errorhandler(403) -def access_forbidden(error): - return render_template('home/page-403.html'), 403 - - -@blueprint.errorhandler(404) -def not_found_error(error): - return render_template('home/page-404.html'), 404 - - -@blueprint.errorhandler(500) -def internal_error(error): - return render_template('home/page-500.html'), 500 diff --git a/apps/authentication/util.py b/apps/authentication/util.py deleted file mode 100644 index 9130da8..0000000 --- a/apps/authentication/util.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- encoding: utf-8 -*- -""" -Copyright (c) 2019 - present AppSeed.us -""" - -import os -import hashlib -import binascii - -# Inspiration -> https://www.vitoshacademy.com/hashing-passwords-in-python/ - - -def hash_pass(password): - """Hash a password for storing.""" - - salt = hashlib.sha256(os.urandom(60)).hexdigest().encode('ascii') - pwdhash = hashlib.pbkdf2_hmac('sha512', password.encode('utf-8'), - salt, 100000) - pwdhash = binascii.hexlify(pwdhash) - return (salt + pwdhash) # return bytes - - -def verify_pass(provided_password, stored_password): - """Verify a stored password against one provided by user""" - - stored_password = stored_password.decode('ascii') - salt = stored_password[:64] - stored_password = stored_password[64:] - pwdhash = hashlib.pbkdf2_hmac('sha512', - provided_password.encode('utf-8'), - salt.encode('ascii'), - 100000) - pwdhash = binascii.hexlify(pwdhash).decode('ascii') - return pwdhash == stored_password diff --git a/apps/config.py b/apps/config.py deleted file mode 100644 index 2fe5430..0000000 --- a/apps/config.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- encoding: utf-8 -*- -""" -Copyright (c) 2019 - present AppSeed.us -""" - -import os -from decouple import config - -class Config(object): - - basedir = os.path.abspath(os.path.dirname(__file__)) - - # Set up the App SECRET_KEY - SECRET_KEY = config('SECRET_KEY', default='S#perS3crEt_007') - - # This will create a file in FOLDER - SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'db.sqlite3') - SQLALCHEMY_TRACK_MODIFICATIONS = False - - -class ProductionConfig(Config): - DEBUG = False - - # Security - SESSION_COOKIE_HTTPONLY = True - REMEMBER_COOKIE_HTTPONLY = True - REMEMBER_COOKIE_DURATION = 3600 - - # PostgreSQL database - SQLALCHEMY_DATABASE_URI = '{}://{}:{}@{}:{}/{}'.format( - config('DB_ENGINE', default='postgresql'), - config('DB_USERNAME', default='appseed'), - config('DB_PASS', default='pass'), - config('DB_HOST', default='localhost'), - config('DB_PORT', default=5432), - config('DB_NAME', default='appseed-flask') - ) - - -class DebugConfig(Config): - DEBUG = True - - -# Load all possible configurations -config_dict = { - 'Production': ProductionConfig, - 'Debug': DebugConfig -} diff --git a/apps/home/__init__.py b/apps/home/__init__.py deleted file mode 100644 index dec76db..0000000 --- a/apps/home/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- encoding: utf-8 -*- -""" -Copyright (c) 2019 - present AppSeed.us -""" - -from flask import Blueprint - -blueprint = Blueprint( - 'home_blueprint', - __name__, - url_prefix='' -) diff --git a/apps/home/routes.py b/apps/home/routes.py deleted file mode 100644 index 455c524..0000000 --- a/apps/home/routes.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- encoding: utf-8 -*- -""" -Copyright (c) 2019 - present AppSeed.us -""" - -from apps.home import blueprint -from flask import render_template, request -from flask_login import login_required -from jinja2 import TemplateNotFound - - -@blueprint.route('/index') -@login_required -def index(): - - return render_template('home/index.html', segment='index') - -@blueprint.route('/