Skip to content
Snippets Groups Projects
Unverified Commit c1ef4bf6 authored by Sandro Lutz's avatar Sandro Lutz
Browse files

Add models and controllers

parent 77ebd6d5
No related branches found
No related tags found
No related merge requests found
Showing
with 500 additions and 11 deletions
.cache/
.data/
.vscode/
__pycache__/
.gitlab-ci.yml
.gitignore
......
.data/
.cache/
.vscode/
instance/
__pycache__/
.ash_history
FROM python:3.7-alpine
# Create user w/o password
RUN adduser -D smtpd
# Switch user
USER smtpd
EXPOSE 1025
# Start python mock smtp server
ENTRYPOINT ["python", "-m", "smtpd", "-n", "-c", "DebuggingServer", "0.0.0.0:1025"]
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_bootstrap import Bootstrap
from flask_mail import Mail
# db variable initialization
# global variable initialization
db = SQLAlchemy()
mail = Mail()
# initialize flask app and configure
app = Flask(__name__, instance_relative_config=True)
app.config.from_pyfile('config.py')
def create_app():
# initialize flask app and configure
app = Flask(__name__, instance_relative_config=True)
app.config.from_pyfile('config.py')
# initialize ORM
db.init_app(app)
# initialize Mail
mail.init_app(app)
# add database migration from flask-migrate
Migrate(app, db)
# initialize ORM
db.init_app(app)
@app.route('/')
def hello_world():
return 'Hello, World!'
# add database migration from flask-migrate
Migrate(app, db)
# add flask-bootstrap
Bootstrap(app)
from app import models
from app import controllers
from .errorpages import create_error_pages
create_error_pages(app)
# add all blueprints
from .login import login_bp
app.register_blueprint(login_bp)
from .bouncer import bouncer_bp
app.register_blueprint(bouncer_bp)
# @app.route('/')
# def hello_world():
# print(app.config.get('TOTAL_SPOTS'))
# return 'Hello, World!'
return app
from flask import Blueprint
bouncer_bp = Blueprint('bouncer', __name__)
from . import views
from flask import flash, redirect, render_template, url_for, request, abort, make_response, session
from . import bouncer_bp
from ..login.auth import login_required
@bouncer_bp.route('/')
def home():
"""
Handle requests to the /logout route
"""
return make_response(render_template('bouncer/home.html', title='Home'))
import threading
from app import models
from app import db
from .exceptions import ReservationExpiredError
class Controller():
lock = threading.Lock()
@classmethod
def create_record_from_reservation(cls, reservation):
with cls.lock:
if reservation.is_valid:
record = models.Record()
report.user = reservation.user
report.organisation = organisation
report.product = product
db.session.add(report)
db.session.commit()
else:
raise ReservationExpiredError
@classmethod
def create_new_record(cls, user, ):
with cls.lock:
pass
from .record import RecordController
from .free_spot import FreeSpotController
\ No newline at end of file
import threading
from datetime import datetime
from sqlalchemy import DateTime, cast, func
from flask import current_app
from app import models
from app import db
from .lock import Lock
from ..exceptions import NoFreeSpotError
class FreeSpotController():
spot_lock = Lock.spot_lock
@classmethod
def has_free_spots(cls):
with cls.spot_lock:
return cls._has_free_spots()
@classmethod
def get_free_spots(cls):
with cls.spot_lock:
return cls._get_free_spots()
@classmethod
def check_free_spots(cls):
if not cls._has_free_spots:
raise NoFreeSpotError
# ---------- PRIVATE METHODS BELOW ----------
@classmethod
def _get_free_spots(cls):
total_spots = current_app.config.get('TOTAL_SPOTS')
now = datetime.now()
active_records_count = db.session.query(func.count(models.Record._id)) \
.filter(cast(models.Record.time_start,DateTime) <= now) \
.filter(cast(models.Record.time_end,DateTime) >= now) \
.scalar()
valid_reservations_count = db.session.query(func.count(models.Reservation._id)) \
.filter(cast(models.Reservation.time_start,DateTime) <= now) \
.filter(cast(models.Reservation.time_end,DateTime) >= now) \
.scalar()
# check total of active records and valid reservations.
return total_spots - active_records_count - valid_reservations_count
@classmethod
def _has_free_spots(cls):
return cls._get_free_spots() > 0
\ No newline at end of file
import threading
class Lock():
spot_lock = threading.Lock()
import threading
from datetime import datetime
from sqlalchemy import DateTime, cast, func
from app import db
from app.models import Record
from .lock import Lock
from .free_spot import FreeSpotController
from ..exceptions import ReservationExpiredError, UserNotConfirmedError
class RecordController():
spot_lock = Lock.spot_lock
@classmethod
def create(cls, user):
with cls.spot_lock:
if not user.is_confirmed:
raise UserNotConfirmedError
FreeSpotController.check_free_spots()
record = Record()
record.user = user
record.time_start = datetime.now()
record.time_end = None
record.name = reservation.name
db.session.add(record)
db.session.commit()
@classmethod
def create_from_reservation(cls, reservation):
with cls.spot_lock:
if not user.is_confirmed:
raise UserNotConfirmedError
if reservation.is_valid:
time_start = datetime.now()
reservation.time_end = time_start
record = models.Record()
record.user = reservation.user
record.time_start = time_start
record.time_end = None
record.name = reservation.name
db.session.add(record)
db.session.commit()
else:
raise ReservationExpiredError
@classmethod
def has_active_record(cls, user):
return cls.get_active_record(user) is not None
@staticmethod
def get_active_record(user):
now = datetime.now()
return Record.query \
.filter(cast(Record.time_start,DateTime) <= now) \
.filter(cast(Record.time_end,DateTime) > now)
@classmethod
def terminate(cls, record):
with cls.spot_lock:
record.time_end = datetime.now()
db.session.commit()
import threading
from datetime import datetime, timedelta
from sqlalchemy import DateTime, cast, func
from flask import current_app
from app import db
from app.models import Reservation
from .lock import Lock
from ..exceptions import ReservationExpiredError, NoFreeSpotError, UserNotConfirmedError
class ReservationController():
spot_lock = Lock.spot_lock
@classmethod
def create(cls, user):
with cls.spot_lock:
cls.check_free_spots()
if not user.is_confirmed:
raise UserNotConfirmedError
record = Reservation()
record.user = user
record.name = name
record.time_start = datetime.now()
record.time_end = datetime.now() + current_app.config('RESERVATION_DURATION', timedelta(hours=1))
db.session.add(record)
db.session.commit()
@classmethod
def has_active_reservation(cls, user):
return cls.get_active_reservation(user) is not None
@staticmethod
def get_active_reservation(user):
now = datetime.now()
return Reservation.query \
.filter(cast(Reservation.time_start,DateTime) <= now) \
.filter(cast(Reservation.time_end,DateTime) > now)
@classmethod
def cancel(cls, reservation):
with cls.spot_lock:
reservation.time_end = datetime.now()
db.session.commit()
import threading
from datetime import datetime, timedelta
from sqlalchemy import DateTime, cast, func
from flask_mail import Message
from flask import current_app
from app import db, mail
from app.models import User
from .lock import Lock
from .reservation import ReservationController
from .record import RecordController
from ..exceptions import ActiveReservationExistsError, \
ActiveRecordExistsError, NoActiveRecordError, ReservationExpiredError, \
NoFreeSpotError
class UserController():
@classmethod
def create(cls, name, email, telegram_id=None, telegram_chat_id=None, password=None):
user = User()
user.name = name
user.email = email
user.telegram_id = telegram_id
user.telegram_chat_id = telegram_chat_id
user.generate_new_token()
if password is not None:
user.set_password(password)
db.session.add(user)
db.session.commit()
cls.send_confirm_email(user)
@staticmethod
def get(user_id):
return User.query.get(user_id)
@staticmethod
def reserve(user):
if ReservationController.has_active_reservation(user):
raise ActiveReservationExistsError
if RecordController.has_active_record(user):
raise ActiveRecordExistsError
return ReservationController.create(user)
@staticmethod
def start_record(user):
if RecordController.has_active_record(user):
raise ActiveRecordExistsError
reservation = ReservationController.get_active_reservation(user)
if reservation is not None:
RecordController.create_from_reservation(reservation)
else:
RecordController.create(user)
@staticmethod
def terminate_record(user):
record = RecordController.get_active_record(user)
if record is None:
raise NoActiveRecordError
RecordController.terminate(record)
@staticmethod
def send_password_reset_email(user):
user.generate_new_token()
sesssion.commit()
msg = Message(render_template('email.password_reset', user=user),
recipients=[user.email])
mail.send(msg)
@staticmethod
def _send_confirm_email(user):
msg = Message(render_template('email.confirm', user=user),
recipients=[user.email])
mail.send(msg)
from flask import render_template
def create_error_pages(app):
@app.errorhandler(401)
def page_unauthorized(e):
return render_template('error/401.html', title='Unauthorized'), 401
@app.errorhandler(403)
def page_forbidden(e):
return render_template('error/403.html', title='Forbidden'), 403
@app.errorhandler(404)
def page_not_found(e):
return render_template('error/404.html', title='Page not found'), 404
@app.errorhandler(500)
def page_server_error(e):
return render_template('error/500.html', title='Internal Server Error'), 500
# User-defined exceptions
class Error(Exception):
"""Base class for other exceptions"""
pass
class NoFreeSpotError(Error):
"""Raised when no free spots are available"""
pass
class ReservationExpiredError(Error):
"""Raised when the reservation has expired"""
pass
class ActiveReservationExistsError(Error):
"""Raised when there is already an active reservation
for the given user."""
pass
class ActiveRecordExistsError(Error):
"""Raised when there is already an active record
for the given user."""
pass
class NoActiveRecordError(Error):
"""Raised when there is no active record for the given user."""
class UserNotConfirmedError(Error):
"""Raised when user has no confirmed email address"""
pass
from flask import Blueprint
login_bp = Blueprint('login', __name__)
from . import views
import json
from functools import wraps
from flask import request, redirect, abort, session
from app import db
from ..models import User
def login_required(f):
"""
Requires that the user is logged in.
This is a wrapper for the @login_required decorator.
Error 403: shwon if trying to access with an api key (Authorization header).
"""
@wraps(f)
def wrapped(*args, **kwargs):
if session['userID'] is None or User.query.get(session['userID']) is None:
abort(403)
return f(*args, **kwargs)
return wrapped
from flask import flash, redirect, render_template, url_for, request, abort, make_response
from . import login_bp
@login_bp.route('/register', methods=['GET', 'POST'])
def register():
# TODO
return make_response(render_template('login/register.html', title='Register'))
@login_bp.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] != 'admin' or request.form['password'] != 'admin':
error = 'Invalid Credentials. Please try again.'
else:
return redirect(url_for('home'))
return make_response(render_template('login/login.html', title='Login'))
@login_bp.route('/password_reset', methods=['GET', 'POST'])
def password_reset(token, email):
return make_response(render_template('login/password_reset.html', title='Password Reset'))
@login_bp.route('/logout')
def logout():
session['userID'] = None
if authenticated:
return make_response(render_template('login/logout.html', title='Logout'))
return redirect(url_for('bouncer.home'))
from .user import User
from .record import Record
from .reservation import Reservation
from app import db
from datetime import datetime, timedelta
class Record(db.Model):
"""
Record entry.
"""
__tablename__ = 'records'
_id = db.Column(db.Integer, primary_key=True)
time_start = db.Column(db.DateTime, nullable=False, server_default=db.func.now())
time_end = db.Column(db.DateTime, nullable=True)
# relation to user
user_id = db.Column(db.Integer, db.ForeignKey('users._id'))
user = db.relationship('User', back_populates='records')
@property
def is_active(self):
return self.time_end is None or self.time_end - datetime.now() > timedelta(seconds=0)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment