import os from flask import Flask, render_template, redirect, url_for, request, flash from flask_migrate import Migrate from werkzeug.security import generate_password_hash, check_password_hash from flask_login import (LoginManager, login_user, login_required, logout_user, current_user) from misc import datetime, date, time, currDay, ZoneInfo, currVersion, currCommit from db import (db, Period, Task, Event, User) from forms import (TaskForm, EventForm, PeriodForm, SignupForm, LoginForm, SettingsForm) from backgroundTasks import scheduleCreateEvents from create_events import createEvents basedir = os.path.abspath(os.path.dirname(__file__)) app = Flask(__name__) app.config['SECRET_KEY'] = 'HwG55rpe83jcaglifXm8NuF4WEeXyJV4' app.config['SQLALCHEMY_DATABASE_URI'] =\ 'sqlite:///' + os.path.join(basedir, os.environ['SQLITE_DB']) app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db.init_app(app) # init migration migrate = Migrate() migrate.init_app(app, db) # Schedule creation of events every hour with app.app_context(): scheduleCreateEvents(app, db, currDay, Period, Event, createEvents) # Authentication stuff login_manager = LoginManager() login_manager.login_view = 'login' login_manager.init_app(app) if 'SIGNUP_ENABLED' in os.environ: if os.environ['SIGNUP_ENABLED'] == "YES": signup_enabled = True else: signup_enabled = False else: signup_enabled = False @login_manager.user_loader def load_user(user_id): return User.query.get(int(user_id)) # Context processor injects current version and commit @app.context_processor def injectVerCommit(): return dict(currVersion=currVersion, currCommit=currCommit) # Index route @app.route('/') def index(): return redirect('/events') # Authentication routes @app.route('/login', methods=['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): userName = form.userName.data password = form.password.data user = User.query.filter_by(userName=userName).first() if not user or not check_password_hash(user.password, password): flash('Credentials incorrect! Please try again') return redirect(url_for('login')) login_user(user) return redirect(url_for('events')) return render_template('login.html', form=form) @app.route('/createaccount', methods=['GET', 'POST']) def createAccount(): if signup_enabled == True: form = SignupForm() if form.validate_on_submit(): usernameExists = User.query.filter_by(userName=form.userName.data).first() if usernameExists: flash('Username already exists') return redirect(url_for('createAccount')) new_user = User(email=form.email.data, userName=form.userName.data, realName=form.realName.data, password=generate_password_hash(form.password.data, method='sha256')) db.session.add(new_user) db.session.commit() return redirect(url_for('login')) return render_template('createAccount.html', form=form) else: return 'Account creation is currently disabled' @app.route('/logout') @login_required def logout(): logout_user() return redirect(url_for('index')) @app.route('/settings', methods=('GET', 'POST')) @login_required def settings(): user = User.query.get_or_404(current_user.id) form = SettingsForm(obj=user) if form.validate_on_submit(): user.realName = form.realName.data user.timezone = form.timezone.data if form.password.data != '': user.password = generate_password_hash(form.password.data, method='sha256') db.session.commit() return render_template('settings.html', form=form) # Periods routes @app.route('/periods') @login_required def periods(): periods = Period.query.all() return render_template('periods.html', periods=periods, datetime=datetime) @app.route('/period/new', methods=('GET', 'POST')) @login_required def newPeriod(): form = PeriodForm() if form.validate_on_submit(): period = Period(periodTime=form.periodTime.data, weekendSchedule=form.weekendSchedule.data ) db.session.add(period) db.session.commit() return redirect(f'/period/edit/{period.period}') return render_template('newPeriod.html', form=form) @app.route('/period/edit/', methods=('GET', 'POST')) @login_required def editPeriod(periodNum): period = Period.query.get_or_404(periodNum) form = PeriodForm(obj=period) if form.validate_on_submit(): period.periodTime = form.periodTime.data period.weekendSchedule = form.weekendSchedule.data db.session.commit() return redirect(f'/period/edit/{periodNum}') return render_template('editPeriod.html', period=period, form=form, datetime=datetime) @app.post('/period/delete/') @login_required def delete_period(periodNum): period = Period.query.get_or_404(periodNum) db.session.delete(period) db.session.commit() return redirect('/periods') # Events routes @app.route('/events') @login_required def events(): events = Event.query.all() periods = Period.query.all() return render_template('events.html', events=events, periods=periods, datetime=datetime, date=date, ZoneInfo=ZoneInfo) @app.route('/event/edit//', methods=('GET', 'POST')) @login_required def editEvent(event_id): event = Event.query.get_or_404(event_id) form = EventForm(obj=event) if form.validate_on_submit(): if hasattr(form.selectedTask.data, 'id'): event.task_id = form.selectedTask.data.id else: event.task_id = None db.session.commit() return redirect('/events') return render_template('editEvent.html', event=event, form=form, datetime=datetime) # Tasks routes @app.route('/tasks') @login_required def tasks(): tasks = Task.query.all() return render_template('tasks.html', str=str, tasks=tasks, datetime=datetime, date=date) @app.route('/task//') @login_required def task(task_id): task = Task.query.get_or_404(task_id) return render_template('task.html', str=str, task=task, datetime=datetime, date=date) @app.route('/task/new', methods=('GET', 'POST')) @login_required def newTask(): form = TaskForm() if form.validate_on_submit(): task = Task(title=form.title.data, description=form.description.data, created_timestamp=int(time.time())) db.session.add(task) db.session.commit() return redirect(f'/task/{task.id}') return render_template('newtask.html', form=form) @app.route('/task//edit', methods=('GET', 'POST')) @login_required def editTask(task_id): task = Task.query.get_or_404(task_id) form = TaskForm(obj=task) if form.validate_on_submit(): task.title=form.title.data task.description=form.description.data db.session.commit() return redirect(f'/task/{task_id}') return render_template('edittask.html', task=task, form=form) @app.post('/task//delete') @login_required def delete_task(task_id): task = Task.query.get_or_404(task_id) db.session.delete(task) db.session.commit() return redirect('/tasks')