From b978e0da56e90779b832f42917162cf37ab6dfbc Mon Sep 17 00:00:00 2001 From: Lunaresk Date: Wed, 13 Jul 2022 09:00:26 +0200 Subject: [PATCH] refactoring, reorganizing Changed the folder structure for better maintenance and inserted Dockerfile for image building. --- Dockerfile | 22 ++ app/__init__.py | 32 ++- app/auth/__init__.py | 5 + app/auth/forms.py | 27 +++ app/auth/routes.py | 44 ++++ app/errors/__init__.py | 5 + app/errors/handlers.py | 12 + app/forms.py | 61 ----- app/main/__init__.py | 5 + app/main/forms.py | 37 ++++ app/{ => main}/routes.py | 157 ++++++------- app/models.py | 29 ++- app/templates/auth/login.html | 19 ++ app/templates/auth/register.html | 19 ++ app/templates/base.html | 208 +++++++++--------- app/templates/errors/404.html | 6 + app/templates/errors/500.html | 7 + app/templates/login.html | 24 -- app/templates/{admin => main}/new_item.html | 2 +- app/templates/{ => main}/overview.html | 2 +- app/templates/register.html | 37 ---- app/utils/constants.py | 1 + boot.sh | 5 + .../versions/05fce74b56cb_full_structure.py | 35 ++- run.py | 4 +- 25 files changed, 447 insertions(+), 358 deletions(-) create mode 100644 Dockerfile create mode 100644 app/auth/__init__.py create mode 100644 app/auth/forms.py create mode 100644 app/auth/routes.py create mode 100644 app/errors/__init__.py create mode 100644 app/errors/handlers.py delete mode 100644 app/forms.py create mode 100644 app/main/__init__.py create mode 100644 app/main/forms.py rename app/{ => main}/routes.py (63%) create mode 100644 app/templates/auth/login.html create mode 100644 app/templates/auth/register.html create mode 100644 app/templates/errors/404.html create mode 100644 app/templates/errors/500.html delete mode 100644 app/templates/login.html rename app/templates/{admin => main}/new_item.html (96%) rename app/templates/{ => main}/overview.html (97%) delete mode 100644 app/templates/register.html create mode 100644 app/utils/constants.py create mode 100644 boot.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9072cc7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM python:3.10-slim + +RUN useradd scan2kasse + +WORKDIR /home/scan2kasse + +COPY requirements.txt requirements.txt +RUN python -m venv venv +RUN venv/bin/pip install -r requirements.txt + +COPY app app +COPY migrations migrations +COPY run.py boot.sh ./ +RUN chmod +x boot.sh + +ENV FLASK_APP run.py + +RUN chown -R scan2kasse:scan2kasse ./ +USER scan2kasse + +EXPOSE 5000 +ENTRYPOINT ["./boot.sh"] \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py index 2542ee0..86a4bee 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,12 +1,13 @@ from flask import Flask +from flask_bootstrap import Bootstrap from flask_login import LoginManager from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate -from yaml import safe_load from logging import getLogger from logging.config import fileConfig from os import makedirs from os.path import dirname, exists +from yaml import safe_load try: dir_name = dirname(__file__) @@ -23,11 +24,28 @@ if not exists(DIR + "logs"): fileConfig(DIR + "configs/log.conf") LOGGER = getLogger("root") -app = Flask(__name__) -app.config.from_file("configs/config.yaml", safe_load) -db = SQLAlchemy(app) -migrate = Migrate(app, db, render_as_batch=True) -login = LoginManager(app) +bootstrap = Bootstrap() +db = SQLAlchemy() +login = LoginManager() login.login_view = 'web_login' +migrate = Migrate() -from app import routes, models \ No newline at end of file + +def create_app(config_file="configs/config.yaml"): + app = Flask(__name__) + app.config.from_file(config_file, safe_load) + bootstrap.init_app(app) + db.init_app(app) + login.init_app(app) + migrate.init_app(app, db, render_as_batch=True) + + from app.auth import bp as auth_bp + app.register_blueprint(auth_bp, url_prefix='/auth') + from app.errors import bp as errors_bp + app.register_blueprint(errors_bp) + from app.main import bp as main_bp + app.register_blueprint(main_bp) + + return app + +from app import models \ No newline at end of file diff --git a/app/auth/__init__.py b/app/auth/__init__.py new file mode 100644 index 0000000..9416da7 --- /dev/null +++ b/app/auth/__init__.py @@ -0,0 +1,5 @@ +from flask import Blueprint + +bp = Blueprint('auth', __name__) + +from app.auth import forms, routes \ No newline at end of file diff --git a/app/auth/forms.py b/app/auth/forms.py new file mode 100644 index 0000000..7594222 --- /dev/null +++ b/app/auth/forms.py @@ -0,0 +1,27 @@ +from app.models import User +from flask_wtf import FlaskForm +from wtforms import StringField, PasswordField, BooleanField, SubmitField +from wtforms.validators import DataRequired, Email, EqualTo, ValidationError + +class LoginForm(FlaskForm): + email = StringField('Email', validators=[DataRequired(), Email()]) + password = PasswordField('Password', validators=[DataRequired()]) + remember_me = BooleanField('Remember Me') + submit = SubmitField('Sign In', render_kw={"class": "btn btn-primary mt-3"}) + +class RegistrationForm(FlaskForm): + email = StringField('Email', validators=[DataRequired(), Email()]) + password = PasswordField('Password', validators=[DataRequired()]) + password2 = PasswordField( + 'Repeat Password', validators=[DataRequired(), EqualTo('password')]) + submit = SubmitField('Register', render_kw={"class": "btn btn-primary mt-3"}) + + def validate_username(self, username): + user = User.query.filter_by(username=username.data).first() + if user is not None: + raise ValidationError('Please use a different username.') + + def validate_email(self, email): + user = User.query.filter_by(email=email.data).first() + if user is not None: + raise ValidationError('Please use a different email address.') \ No newline at end of file diff --git a/app/auth/routes.py b/app/auth/routes.py new file mode 100644 index 0000000..33c3f58 --- /dev/null +++ b/app/auth/routes.py @@ -0,0 +1,44 @@ +from app import db +from app.auth import bp +from app.auth.forms import LoginForm, RegistrationForm +from app.models import User +from app.utils.routes_utils import render_custom_template as render_template +from flask import flash, redirect, request, url_for +from flask_login import current_user, login_user, logout_user +from werkzeug.urls import url_parse + +@bp.route(f'/register', methods=['GET', 'POST']) +def web_register(): + if current_user.is_authenticated: + return redirect(url_for('main.index')) + form = RegistrationForm() + if form.validate_on_submit(): + user = User(username=form.username.data, email=form.email.data) + user.set_password(form.password.data) + db.session.add(user) + db.session.commit() + flash('Congratulations, you are now a registered user!') + return redirect(url_for('auth.login')) + return render_template('auth/register.html', title='Register', form=form) + +@bp.route(f'/login', methods=['GET', 'POST']) +def web_login(): + if current_user.is_authenticated: + return redirect(url_for('main.index')) + form = LoginForm() + if form.validate_on_submit(): + user = User.query.filter_by(username=form.username.data).first() + if user is None or not user.check_password(form.password.data): + flash('Invalid username or password') + return redirect(url_for('auth.web_login')) + login_user(user, remember=form.remember_me.data) + next_page = request.args.get('next') + if not next_page or url_parse(next_page).netloc != '': + next_page = url_for('main.index') + return redirect(next_page) + return render_template('auth/login.html', title='Sign In', form=form) + +@bp.route(f'/logout') +def web_logout(): + logout_user() + return redirect(url_for('main.index')) \ No newline at end of file diff --git a/app/errors/__init__.py b/app/errors/__init__.py new file mode 100644 index 0000000..004d239 --- /dev/null +++ b/app/errors/__init__.py @@ -0,0 +1,5 @@ +from flask import Blueprint + +bp = Blueprint('errors', __name__) + +from app.errors import handlers \ No newline at end of file diff --git a/app/errors/handlers.py b/app/errors/handlers.py new file mode 100644 index 0000000..d2d6935 --- /dev/null +++ b/app/errors/handlers.py @@ -0,0 +1,12 @@ +from app import db +from app.errors import bp +from flask import render_template + +@bp.app_errorhandler(404) +def not_found_error(error): + return render_template('errors/404.html'), 404 + +@bp.app_errorhandler(500) +def internal_error(error): + db.session.rollback() + return render_template('errors/500.html'), 500 \ No newline at end of file diff --git a/app/forms.py b/app/forms.py deleted file mode 100644 index f6fce45..0000000 --- a/app/forms.py +++ /dev/null @@ -1,61 +0,0 @@ -from app.models import Brand, Category, User -from flask_wtf import FlaskForm -from wtforms import StringField, PasswordField, BooleanField, SubmitField, SelectMultipleField, DateField, IntegerField, SelectField, FloatField -from wtforms.validators import DataRequired, Email, EqualTo, Optional, ValidationError - -class LoginForm(FlaskForm): - username = StringField('Username', validators=[DataRequired()]) - password = PasswordField('Password', validators=[DataRequired()]) - remember_me = BooleanField('Remember Me') - submit = SubmitField('Sign In') - -class RegistrationForm(FlaskForm): - username = StringField('Username', validators=[DataRequired()]) - email = StringField('Email', validators=[DataRequired(), Email()]) - password = PasswordField('Password', validators=[DataRequired()]) - password2 = PasswordField( - 'Repeat Password', validators=[DataRequired(), EqualTo('password')]) - submit = SubmitField('Register') - - def validate_username(self, username): - user = User.query.filter_by(username=username.data).first() - if user is not None: - raise ValidationError('Please use a different username.') - - def validate_email(self, email): - user = User.query.filter_by(email=email.data).first() - if user is not None: - raise ValidationError('Please use a different email address.') - -class NewItemForm(FlaskForm): - id = IntegerField("Product EAN", validators=[DataRequired()]) - name = StringField("Name", validators=[DataRequired()]) - description = StringField("Description", validators=[DataRequired()]) - date = DateField("Insert Date", validators=[DataRequired()]) - price_change = FloatField("Price", validators=[DataRequired()]) - amount_change = IntegerField("Amount", validators=[Optional()]) - category = SelectMultipleField("Categories", choices=[], validators=[Optional()]) - brand = SelectField("Brand", choices=[], validators=[DataRequired()]) - submit = SubmitField("Submit") - - @classmethod - def new(cls): - form = cls() - form.category.choices = [(c.id, c.name) for c in Category.query.order_by("name").all()] - form.brand.choices = [(b.id, b.name) for b in Brand.query.order_by("name").all()] - return form - -class NewCategoryForm(FlaskForm): - name = StringField("Name", validators=[DataRequired()]) - submit = SubmitField("Submit") - -class NewBrandForm(FlaskForm): - name = StringField("Name", validators=[DataRequired()]) - submit = SubmitField("Submit") - -class NeueWGForm(FlaskForm): - wg_name = StringField("Name", validators=[DataRequired()]) - submit = SubmitField("Submit") - -class WGBeitretenForm(FlaskForm): - submit = SubmitField("Submit") \ No newline at end of file diff --git a/app/main/__init__.py b/app/main/__init__.py new file mode 100644 index 0000000..d4304a7 --- /dev/null +++ b/app/main/__init__.py @@ -0,0 +1,5 @@ +from flask import Blueprint + +bp = Blueprint('main', __name__) + +from app.main import forms, routes \ No newline at end of file diff --git a/app/main/forms.py b/app/main/forms.py new file mode 100644 index 0000000..b67420e --- /dev/null +++ b/app/main/forms.py @@ -0,0 +1,37 @@ +from app.models import Brand, Category +from flask_wtf import FlaskForm +from wtforms import DateField, FloatField, IntegerField, SelectField, SelectMultipleField, StringField, SubmitField +from wtforms.validators import DataRequired, Optional + +class NewItemForm(FlaskForm): + id = IntegerField("Product EAN", validators=[DataRequired()]) + name = StringField("Name", validators=[DataRequired()]) + description = StringField("Description", validators=[DataRequired()]) + date = DateField("Insert Date", validators=[DataRequired()]) + price_change = FloatField("Price", validators=[DataRequired()]) + amount_change = IntegerField("Amount", validators=[Optional()]) + category = SelectMultipleField("Categories", choices=[], validators=[Optional()]) + brand = SelectField("Brand", choices=[], validators=[DataRequired()]) + submit = SubmitField("Submit") + + @classmethod + def new(cls): + form = cls() + form.category.choices = [(c.id, c.name) for c in Category.query.order_by("name").all()] + form.brand.choices = [(b.id, b.name) for b in Brand.query.order_by("name").all()] + return form + +class NewCategoryForm(FlaskForm): + name = StringField("Name", validators=[DataRequired()]) + submit = SubmitField("Submit", render_kw={"class": "btn btn-primary mt-3"}) + +class NewBrandForm(FlaskForm): + name = StringField("Name", validators=[DataRequired()]) + submit = SubmitField("Submit", render_kw={"class": "btn btn-primary mt-3"}) + +class NewEstablishmentForm(FlaskForm): + establishment_name = StringField("Name", validators=[DataRequired()]) + submit = SubmitField("Submit", render_kw={"class": "btn btn-primary mt-3"}) + +class JoinEstablishmentForm(FlaskForm): + submit = SubmitField("Submit", render_kw={"class": "btn btn-primary mt-3"}) \ No newline at end of file diff --git a/app/routes.py b/app/main/routes.py similarity index 63% rename from app/routes.py rename to app/main/routes.py index 97dbadc..94c5bbb 100644 --- a/app/routes.py +++ b/app/main/routes.py @@ -1,106 +1,24 @@ -from app import app, db, LOGGER -from app.forms import NewItemForm, LoginForm, RegistrationForm -from app.models import Establishment, LoginToken, User, Item, Brand, PriceChange, AmountChange +from app import db, LOGGER +from app.main.forms import NewItemForm +from app.main import bp +from app.models import AmountChange, Brand, Establishment, LoginToken, Item, PriceChange from app.utils import view_utils, database_utils from app.utils.routes_utils import render_custom_template as render_template from datetime import date -from flask import abort, flash, redirect, request, url_for +from flask import abort, redirect, request, url_for from flask.json import jsonify -from flask_login import current_user, login_required, login_user, logout_user -from werkzeug.urls import url_parse +from flask_login import current_user, login_required -APPNAME = "scan2kasse" - -@app.route(f'/{APPNAME}') +@bp.route('/') +@bp.route('/index') def index(): return render_template("base.html") -@app.route(f'/{APPNAME}/token_authorization') -def token_authorization(): - LOGGER.debug("Token Login") - if not request.json or 'login' not in request.json: - abort(400) - if not LoginToken.query.filter_by(token=request.json['login']).first(): - abort(403) - return jsonify({}), 200 +# @bp.route('/') +# def test(): +# return "Hello World" -@app.route(f'/{APPNAME}/token_insert', methods=['POST']) -def insert(): - match request.json: - case {'user': user, 'items': items, 'date': date}: - failed = database_utils.insert_bought_items(user, items, date) - case {'user': user, 'items': items}: - failed = database_utils.insert_bought_items(user, items) - case _: - abort(400) - if failed: - return jsonify(failed), 400 - return jsonify({'inserted': True}), 201 - -@app.route('/register', methods=['GET', 'POST']) -def web_register(): - if current_user.is_authenticated: - return redirect(url_for('index')) - form = RegistrationForm() - if form.validate_on_submit(): - user = User(username=form.username.data, email=form.email.data) - user.set_password(form.password.data) - db.session.add(user) - db.session.commit() - flash('Congratulations, you are now a registered user!') - return redirect(url_for('login')) - return render_template('register.html', title='Register', form=form) - -@app.route(f'/{APPNAME}/login', methods=['GET', 'POST']) -def web_login(): - if current_user.is_authenticated: - return redirect(url_for('index')) - form = LoginForm() - if form.validate_on_submit(): - user = User.query.filter_by(username=form.username.data).first() - if user is None or not user.check_password(form.password.data): - flash('Invalid username or password') - return redirect(url_for('web_login')) - login_user(user, remember=form.remember_me.data) - next_page = request.args.get('next') - if not next_page or url_parse(next_page).netloc != '': - next_page = url_for('index') - return redirect(next_page) - return render_template('login.html', title='Sign In', form=form) - -@app.route(f'/{APPNAME}/logout') -def web_logout(): - logout_user() - return redirect(url_for('index')) - -@app.route(f'/{APPNAME}/newitem', methods=['GET', 'POST']) -@login_required -def new_item(): - if current_user.is_anonymous: - abort(403) - form=NewItemForm.new() - if form.is_submitted(): - LOGGER.debug("submitted") - if form.validate(): - LOGGER.debug("valid") - else: - LOGGER.debug(form.errors) - if form.validate_on_submit(): - LOGGER.debug("valid form") - brand = Brand.query.get(form.brand.data) - new_item = Item(id = form.id.data, name = form.name.data, brand = brand.id, description = form.description.data) - # if form.category.data: - # category = Category.query.get(id = form.category.data) - # new_item.Category = category - new_item.PriceChange = [PriceChange(Item = new_item, date = date(2021, 12, 1), price = form.price_change.data)] - if form.amount_change.data: - new_item.AmountChange = [AmountChange(Item = new_item, date = date(2021, 12, 1), amount = form.amount_change.data)] - db.session.add(new_item) - db.session.commit() - return redirect(url_for('index')) - return render_template('admin/new_item.html', form=form) - -@app.route(f'/{APPNAME}/overview', methods=['GET']) +@bp.route('/overview', methods=['GET']) @login_required def get_report_from_user(): if current_user.is_anonymous: @@ -130,7 +48,56 @@ def get_report_from_user(): else: return render_template("overview.html", results=result_list) -@app.route(f'/{APPNAME}/overview/register_boughts', methods=['GET']) +@bp.route('/token_authorization') +def token_authorization(): + LOGGER.debug("Token Login") + if not request.json or 'login' not in request.json: + abort(400) + if not LoginToken.query.filter_by(token=request.json['login']).first(): + abort(403) + return jsonify({}), 200 + +@bp.route('/token_insert', methods=['POST']) +def insert(): + match request.json: + case {'user': user, 'items': items, 'date': date}: + failed = database_utils.insert_bought_items(user, items, date) + case {'user': user, 'items': items}: + failed = database_utils.insert_bought_items(user, items) + case _: + abort(400) + if failed: + return jsonify(failed), 400 + return jsonify({'inserted': True}), 201 + +@bp.route('/new_item', methods=['GET', 'POST']) +@login_required +def new_item(): + if current_user.is_anonymous: + abort(403) + form=NewItemForm.new() + if form.is_submitted(): + LOGGER.debug("submitted") + if form.validate(): + LOGGER.debug("valid") + else: + LOGGER.debug(form.errors) + if form.validate_on_submit(): + LOGGER.debug("valid form") + brand = Brand.query.get(form.brand.data) + new_item = Item(id = form.id.data, name = form.name.data, brand = brand.id, description = form.description.data) + # if form.category.data: + # category = Category.query.get(id = form.category.data) + # new_item.Category = category + new_item.PriceChange = [PriceChange(Item = new_item, date = date(2021, 12, 1), price = form.price_change.data)] + if form.amount_change.data: + new_item.AmountChange = [AmountChange(Item = new_item, date = date(2021, 12, 1), amount = form.amount_change.data)] + db.session.add(new_item) + db.session.commit() + return redirect(url_for('index')) + return render_template('admin/new_item.html', form=form) + +@bp.route('/overview/register_boughts', methods=['GET']) @login_required def check_unregistered_items(): if current_user.is_anonymous or not request.args or 'establishment' not in request.args: diff --git a/app/models.py b/app/models.py index 6bc7a60..484e8de 100644 --- a/app/models.py +++ b/app/models.py @@ -4,14 +4,13 @@ from flask_login import UserMixin from werkzeug.security import generate_password_hash, check_password_hash item_category = db.Table("item_category", - db.Column("item", db.ForeignKey("item.id"), primary_key=True), - db.Column("category", db.ForeignKey("category.id"), primary_key=True) + db.Column("item", db.ForeignKey("item.id"), primary_key=True, server_onupdate=db.FetchedValue()), + db.Column("category", db.ForeignKey("category.id"), primary_key=True, server_onupdate=db.FetchedValue()) ) class User(UserMixin, db.Model): id = db.Column(db.BigInteger, primary_key=True) - email = db.Column(db.String(64), nullable=False, unique=True) - username = db.Column(db.String(64), nullable=False, unique=True) + email = db.Column(db.String(255), nullable=False, unique=True) password_hash = db.Column(db.String(128), nullable=False) LoginToken = db.relationship("LoginToken", backref='User', lazy='dynamic') @@ -40,9 +39,10 @@ class Establishment(db.Model): return f"" class LoginToken(db.Model): - user = db.Column(db.ForeignKey('user.id'), primary_key=True) - establishment = db.Column(db.ForeignKey('establishment.id'), primary_key=True) + user = db.Column(db.ForeignKey('user.id'), primary_key=True, server_onupdate=db.FetchedValue()) + establishment = db.Column(db.ForeignKey('establishment.id'), primary_key=True, server_onupdate=db.FetchedValue()) token = db.Column(db.String(15), nullable=True, unique=True) + paid = db.Column(db.BigInteger, nullable=False, server_default=str(0)) def __repr__(self) -> str: return f"LoginToken {self.token}" @@ -66,7 +66,7 @@ class Category(db.Model): class Item(db.Model): id = db.Column(db.BigInteger, primary_key=True) name = db.Column(db.String(64), nullable=False) - brand = db.Column(db.ForeignKey('brand.id'), nullable=False) + brand = db.Column(db.ForeignKey('brand.id'), nullable=False, server_onupdate=db.FetchedValue()) description = db.Column(db.Text, nullable=False) Category = db.relationship("Category", secondary=item_category, lazy="dynamic", back_populates="Item") @@ -78,18 +78,17 @@ class Item(db.Model): return f"" class Bought(db.Model): - token = db.Column(db.ForeignKey('login_token.token'), primary_key=True) - item = db.Column(db.ForeignKey('item.id'), primary_key=True) + token = db.Column(db.ForeignKey('login_token.token'), primary_key=True, server_onupdate=db.FetchedValue()) + item = db.Column(db.ForeignKey('item.id'), primary_key=True, server_onupdate=db.FetchedValue()) date = db.Column(db.Date, primary_key=True) amount = db.Column(db.SmallInteger, nullable=False) registered = db.Column(db.Boolean, nullable=False, server_default=str(False)) - paid = db.Column(db.SmallInteger, nullable=False, server_default=str(0)) def __repr__(self) -> str: return f"" class PriceChange(db.Model): - item = db.Column(db.ForeignKey('item.id'), primary_key=True) + item = db.Column(db.ForeignKey('item.id'), primary_key=True, server_onupdate=db.FetchedValue()) date = db.Column(db.Date, primary_key=True, server_default=str(date(2021, 12, 1))) price = db.Column(db.SmallInteger, nullable=False) @@ -97,7 +96,7 @@ class PriceChange(db.Model): return f"" class AmountChange(db.Model): - item = db.Column(db.ForeignKey('item.id'), primary_key=True) + item = db.Column(db.ForeignKey('item.id'), primary_key=True, server_onupdate=db.FetchedValue()) date = db.Column(db.Date, primary_key=True, server_default=str(date(2021, 12, 1))) amount = db.Column(db.SmallInteger, nullable=False, server_default=str(1)) @@ -107,15 +106,15 @@ class AmountChange(db.Model): class Receipt(db.Model): id = db.Column(db.Numeric(precision=22, scale=0), primary_key=True) date = db.Column(db.Date, nullable=False) + from_user = db.Column(db.ForeignKey("login_token.token"), server_onupdate=db.FetchedValue()) registered = db.Column(db.Boolean, nullable=False, server_default=str(False)) - paid = db.Column(db.SmallInteger, nullable=False, server_default=str(0)) def __repr__(self) -> str: return f"" class ItemReceipt(db.Model): - receipt = db.Column(db.ForeignKey("receipt.id"), primary_key=True) - item = db.Column(db.ForeignKey("item.id"), primary_key=True) + receipt = db.Column(db.ForeignKey("receipt.id"), primary_key=True, server_onupdate=db.FetchedValue()) + item = db.Column(db.ForeignKey("item.id"), primary_key=True, server_onupdate=db.FetchedValue()) amount = db.Column(db.SmallInteger, nullable=False) def __repr__(self) -> str: diff --git a/app/templates/auth/login.html b/app/templates/auth/login.html new file mode 100644 index 0000000..df3621a --- /dev/null +++ b/app/templates/auth/login.html @@ -0,0 +1,19 @@ +{% extends "base.html" %} +{% import 'bootstrap/wtf.html' as wtf %} + +{% block app_content %} +

Sign In

+
+ {{ form.hidden_tag() }} +

+ {{ wtf.form_field(form.email) }} +

+

+ {{ wtf.form_field(form.password) }} +

+

+ {{ wtf.form_field(form.remember_me) }} +

+ {{ wtf.form_field(form.submit, class=form.submit.render_kw["class"]) }} +
+{% endblock %} \ No newline at end of file diff --git a/app/templates/auth/register.html b/app/templates/auth/register.html new file mode 100644 index 0000000..672a0d5 --- /dev/null +++ b/app/templates/auth/register.html @@ -0,0 +1,19 @@ +{% extends "base.html" %} +{% import 'bootstrap/wtf.html' as wtf %} + +{% block app_content %} +

Register

+
+ {{ form.hidden_tag() }} +

+ {{ wtf.form_field(form.email) }} +

+

+ {{ wtf.form_field(form.password) }} +

+

+ {{ wtf.form_field(form.password2) }} +

+ {{ wtf.form_field(form.submit, class=form.submit.render_kw["class"]) }} +
+{% endblock %} \ No newline at end of file diff --git a/app/templates/base.html b/app/templates/base.html index 0ea63e7..b112dc6 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -1,104 +1,116 @@ - - - - - - - - {% if title %} - {{ title }} - {% else %} - Scan2Kasse - {% endif %} - - - -
-
- - - Scan2Kasse - - -
- {% with messages = get_flashed_messages() %} - {% if messages %} +{% extends "bootstrap/base.html" %} + +{% block title %} + {% if title %} + {{ title }} + {% else %} + Scan2Kasse + {% endif %} +{% endblock %} + +{% block metas %} + + +{% endblock %} + +{% block styles %} + + +{% endblock %} + +{% block navbar %} +
+
+ + + Scan2Kasse + + +
+{% endblock %} + +{% block content %} + {% with messages = get_flashed_messages() %} + {% if messages %}
    {% for message in messages %}
  • {{ message }}
  • {% endfor %}
- {% endif %} - {% endwith %} -
-
-
-
- {% block content %}{% endblock %} -
-
-
-
- + {% endif %} + {% endwith %} +
+
+
+
+ {% block app_content %}{% endblock %} +
+
+
+
+{% endblock %} + +{% block scripts %} - \ No newline at end of file + +{% endblock %} \ No newline at end of file diff --git a/app/templates/errors/404.html b/app/templates/errors/404.html new file mode 100644 index 0000000..3fa3377 --- /dev/null +++ b/app/templates/errors/404.html @@ -0,0 +1,6 @@ +{% extends "base.html" %} + +{% block app_content %} +

File Not Found

+

Back

+{% endblock %} \ No newline at end of file diff --git a/app/templates/errors/500.html b/app/templates/errors/500.html new file mode 100644 index 0000000..5f56727 --- /dev/null +++ b/app/templates/errors/500.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} + +{% block app_content %} +

An unexpected error has occurred

+

The administrator has been notified. Sorry for the inconvenience!

+

Back

+{% endblock %} \ No newline at end of file diff --git a/app/templates/login.html b/app/templates/login.html deleted file mode 100644 index 1a3eb64..0000000 --- a/app/templates/login.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "base.html" %} - -{% block content %} -

Sign In

-
- {{ form.hidden_tag() }} -

- {{ form.username.label }}
- {{ form.username(size=32) }} - {% for error in form.username.errors %} - [{{ error }}] - {% endfor %} -

-

- {{ form.password.label }}
- {{ form.password(size=32) }} - {% for error in form.password.errors %} - [{{ error }}] - {% endfor %} -

-

{{ form.remember_me() }} {{ form.remember_me.label }}

-

{{ form.submit() }}

-
-{% endblock %} \ No newline at end of file diff --git a/app/templates/admin/new_item.html b/app/templates/main/new_item.html similarity index 96% rename from app/templates/admin/new_item.html rename to app/templates/main/new_item.html index 52c9c57..5f4c53f 100644 --- a/app/templates/admin/new_item.html +++ b/app/templates/main/new_item.html @@ -1,6 +1,6 @@ {% extends "base.html" %} -{% block content %} +{% block app_content %}
{{ form.hidden_tag() }}
{{form.id.label}}
diff --git a/app/templates/overview.html b/app/templates/main/overview.html similarity index 97% rename from app/templates/overview.html rename to app/templates/main/overview.html index eb4810c..2d9e8c1 100644 --- a/app/templates/overview.html +++ b/app/templates/main/overview.html @@ -1,6 +1,6 @@ {% extends "base.html" %} -{% block content %} +{% block app_content %} {% if establishment %} {% if current_user.id == establishment.owner %}