doneth.at/app/main.py

200 lines
5.7 KiB
Python

from flask import Blueprint, render_template, redirect, url_for, abort, request
from flask_login import current_user, login_required
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, IntegerField
from wtforms.validators import DataRequired, Length, NumberRange
from .db import db, Accomplishment
from datetime import datetime, timedelta
import time
from .days import Day
main = Blueprint('main', __name__)
class NewAccomplishementForm(FlaskForm):
text = StringField(
'Accomplishment',
validators=[
DataRequired(), Length(max=256)])
submit_5 = SubmitField('5 XP')
submit_10 = SubmitField('10 XP')
submit_15 = SubmitField('15 XP')
def handle_accomplishment_submission(form):
accomplishment = Accomplishment()
accomplishment.user_id = current_user.id
accomplishment.text = form.text.data
accomplishment.difficulty = 5
if form.submit_10.data:
accomplishment.difficulty = 10
elif form.submit_15.data:
accomplishment.difficulty = 15
accomplishment.time = Day.today(current_user).timestamp
db.session.add(accomplishment)
db.session.commit()
return redirect(url_for('main.index'))
def parse_day(day_string, user):
day = None
if day_string == "today":
day = Day.today(user)
else:
day = Day.from_str(day_string, user)
return day
def get_day_template_data(day_string, user):
day = parse_day(day_string, user)
accomplishments = list(reversed(
Accomplishment.get_day(current_user, day)))
total = sum(a.difficulty for a in accomplishments)
yesterday = day - 1
tomorrow = day + 1
if tomorrow.is_future:
tomorrow = None
return {
"day": day,
"links": {
"yesterday": url_for('main.index', day=yesterday.url),
"tomorrow": url_for('main.index', day=tomorrow.url) if tomorrow is not None else None
},
"accomplishments": accomplishments,
"total_xp": sum(a.difficulty for a in accomplishments),
"ts": int(time.time()), # timestamp for cachebusting
}
@main.route('/', defaults={'day': 'today'}, methods=['GET', 'POST'])
@main.route('/day/<day>')
def index(day):
if not current_user.is_authenticated:
# TODO: handle the case when the user is on /day/<something> and is not logged in
return render_template('index.html')
form = NewAccomplishementForm()
if form.validate_on_submit():
return handle_accomplishment_submission(form)
return render_template(
'main/app.html',
form=form,
**get_day_template_data(day, current_user)
)
@main.route('/day/<day>/edit')
@login_required
def edit_day(day):
form = NewAccomplishementForm()
if form.validate_on_submit():
return handle_accomplishment_submission(form)
return render_template(
'main/app.html',
form=form,
edit=True,
**get_day_template_data(day, current_user)
)
class DeleteForm(FlaskForm):
submit = SubmitField('Delete')
@main.route('/accomplishment/<accomplishment_id>/delete', methods=['GET', 'POST'])
@login_required
def delete_accomplishment(accomplishment_id):
a = Accomplishment.query.get_or_404(accomplishment_id)
if a.user_id != current_user.id:
abort(403)
# TODO: fix: we're using from_str when it's a datetime in the db? it works on sqlite but
back_url = url_for('main.edit_day', day=Day.from_str(a.time, user).url)
form = DeleteForm()
if form.validate_on_submit():
db.session.delete(a)
db.session.commit()
return redirect(back_url)
return render_template(
'main/delete.html',
form=form,
accomplishment=a,
cancel=back_url)
class EditForm(FlaskForm):
text = StringField(
'Accomplishment',
validators=[DataRequired(), Length(max=256)]
)
difficulty = IntegerField(
'Difficulty (XP)',
validators=[DataRequired(), NumberRange(max=100, min=-100)]
)
submit = SubmitField('Save')
@main.route('/accomplishment/<accomplishment_id>/edit', methods=['GET', 'POST'])
@login_required
def edit_accomplishment(accomplishment_id):
a = Accomplishment.query.get_or_404(accomplishment_id)
if a.user_id != current_user.id:
abort(403)
back_url = url_for('main.edit_day', day=Day.from_timestamp(
a.time, current_user).url)
form = EditForm(obj=a)
if form.validate_on_submit():
a.text = form.text.data
a.difficulty = form.difficulty.data
db.session.commit()
return redirect(back_url)
return render_template('main/edit.html', form=form, cancel=back_url)
@main.route('/day/<day>/add', methods=['GET', 'POST'])
@login_required
def add_day(day):
day = parse_day(day, current_user)
form = EditForm()
back_url = ""
from_top = ("from" in request.args) and ("top" in request.args["from"])
# to the bottom
# bottom to top I stop
# at the core I've forgotten
# in the middle of my thoughts
# taken far from my safety
# the picture is there
back_to_day = url_for('main.index', day=day.url)
back_to_edit = url_for('main.edit_day', day=day.url)
if form.validate_on_submit():
accomplishment = Accomplishment()
accomplishment.user_id = current_user.id
accomplishment.text = form.text.data
accomplishment.difficulty = form.difficulty.data
accomplishment.time = day.timestamp
db.session.add(accomplishment)
db.session.commit()
return redirect(back_to_day)
return render_template(
'main/edit.html',
day=day,
form=form,
edit=True,
cancel=back_to_day if from_top else back_to_edit
)