Add Seasons.
This commit is contained in:
48
app.py
48
app.py
@@ -2,7 +2,7 @@ import functools
|
|||||||
from flask import Flask, g, render_template, request, redirect, session
|
from flask import Flask, g, render_template, request, redirect, session
|
||||||
|
|
||||||
import db
|
import db
|
||||||
import model
|
import models
|
||||||
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
@@ -76,7 +76,45 @@ def landing():
|
|||||||
@app.route('/seasons')
|
@app.route('/seasons')
|
||||||
@authorize
|
@authorize
|
||||||
def seasons():
|
def seasons():
|
||||||
return render_template('seasons.html')
|
sql, args = db.load_season()
|
||||||
|
results = db. query_db(sql, args, cls=models.Season)
|
||||||
|
model = {
|
||||||
|
'seasons': results,
|
||||||
|
'columns': [
|
||||||
|
('game', 'Game'),
|
||||||
|
('description', 'Season Description'),
|
||||||
|
('start', 'Started At'),
|
||||||
|
('end', 'Ended At')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return render_template('seasons.html', model=model)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/newseason', methods=['GET'])
|
||||||
|
@authorize
|
||||||
|
def new_season():
|
||||||
|
return render_template('editseason.html', model={})
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/seasons/edit/<id>')
|
||||||
|
@authorize
|
||||||
|
def edit_season(id: int):
|
||||||
|
sql, args = db.load_season(id)
|
||||||
|
loaded = db.query_db(sql, args, one=True, cls=models.Season)
|
||||||
|
return render_template('editseason.html', model=loaded)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/saveseason', methods=['POST'])
|
||||||
|
@authorize
|
||||||
|
def save_season():
|
||||||
|
try:
|
||||||
|
season = models.Season.from_form(request.form)
|
||||||
|
except AttributeError as err:
|
||||||
|
print(err)
|
||||||
|
return render_template('editseason.html', model={})
|
||||||
|
sql, args = db.save_season_query(season)
|
||||||
|
res = db.update_db(sql, args)
|
||||||
|
return redirect('/seasons')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/newplayer', methods=['GET'])
|
@app.route('/newplayer', methods=['GET'])
|
||||||
@@ -87,9 +125,9 @@ def new_player():
|
|||||||
|
|
||||||
@app.route('/saveplayer', methods=['POST'])
|
@app.route('/saveplayer', methods=['POST'])
|
||||||
@authorize
|
@authorize
|
||||||
def update_player():
|
def save_player():
|
||||||
data = request.form
|
data = request.form
|
||||||
player = model.Player(
|
player = models.Player(
|
||||||
id=data.get('id', None),
|
id=data.get('id', None),
|
||||||
real_name=data['real_name'],
|
real_name=data['real_name'],
|
||||||
alias=data['alias'],
|
alias=data['alias'],
|
||||||
@@ -153,7 +191,7 @@ def new_drink():
|
|||||||
@app.route('/savedrink', methods=['POST'])
|
@app.route('/savedrink', methods=['POST'])
|
||||||
@authorize
|
@authorize
|
||||||
def save_drink():
|
def save_drink():
|
||||||
drink = model.Drink.from_form(request.form)
|
drink = models.Drink.from_form(request.form)
|
||||||
res = db.save_drink(drink)
|
res = db.save_drink(drink)
|
||||||
return redirect('/drinks')
|
return redirect('/drinks')
|
||||||
|
|
||||||
|
|||||||
36
db.py
36
db.py
@@ -2,7 +2,7 @@ import sqlite3
|
|||||||
import logging as log
|
import logging as log
|
||||||
from flask import g
|
from flask import g
|
||||||
|
|
||||||
import model
|
import models
|
||||||
|
|
||||||
|
|
||||||
DATABASE = 'es_debug.db'
|
DATABASE = 'es_debug.db'
|
||||||
@@ -18,12 +18,14 @@ def connect_db():
|
|||||||
return db
|
return db
|
||||||
|
|
||||||
|
|
||||||
def query_db(query, args=(), one=False):
|
def query_db(query, args=(), one=False, cls=None):
|
||||||
"""Runs an SQL query on an new database connection, returning the fetched rows"""
|
"""Runs an SQL query on an new database connection, returning the fetched rv"""
|
||||||
log.info(f'Running query ({query})\nwith arguments ({args})')
|
log.info(f'Running query ({query})\nwith arguments ({args})')
|
||||||
cur = connect_db().execute(query, args)
|
cur = connect_db().execute(query, args)
|
||||||
rv = cur.fetchall()
|
rv = cur.fetchall()
|
||||||
cur.close()
|
cur.close()
|
||||||
|
if cls:
|
||||||
|
rv = [cls(**row) for row in rv]
|
||||||
return (rv[0] if rv else None) if one else rv
|
return (rv[0] if rv else None) if one else rv
|
||||||
|
|
||||||
|
|
||||||
@@ -79,7 +81,7 @@ def load_players(id=None):
|
|||||||
args = (id, )
|
args = (id, )
|
||||||
sql += ' order by player.id'
|
sql += ' order by player.id'
|
||||||
rows = query_db(sql, args)
|
rows = query_db(sql, args)
|
||||||
players = [model.Player(**row) for row in rows]
|
players = [models.Player(**row) for row in rows]
|
||||||
return players
|
return players
|
||||||
|
|
||||||
|
|
||||||
@@ -91,7 +93,7 @@ def load_drinks(id=None):
|
|||||||
args = (id, )
|
args = (id, )
|
||||||
sql += ' order by drink.id'
|
sql += ' order by drink.id'
|
||||||
rows = query_db(sql, args)
|
rows = query_db(sql, args)
|
||||||
drinks = [model.Drink(**row) for row in rows]
|
drinks = [models.Drink(**row) for row in rows]
|
||||||
return drinks
|
return drinks
|
||||||
|
|
||||||
|
|
||||||
@@ -120,5 +122,27 @@ def load_enemies(id=None):
|
|||||||
args = (id, )
|
args = (id, )
|
||||||
sql += ' order by enemy.id'
|
sql += ' order by enemy.id'
|
||||||
rows = query_db(sql, args)
|
rows = query_db(sql, args)
|
||||||
enemies = [model.Enemy(**row) for row in rows]
|
enemies = [models.Enemy(**row) for row in rows]
|
||||||
return enemies
|
return enemies
|
||||||
|
|
||||||
|
|
||||||
|
def save_season_query(season):
|
||||||
|
if not season.id:
|
||||||
|
sql = 'insert into season values (?, ?, ?, ?, ?)'
|
||||||
|
args = (None, season.game, season.description, season.start, season.end)
|
||||||
|
else:
|
||||||
|
sql = 'update season ' \
|
||||||
|
'set game=?, description=?, start=?, end=? ' \
|
||||||
|
'where id==?'
|
||||||
|
args = (season.game, season.description, season.start, season.end, season.id)
|
||||||
|
return sql, args
|
||||||
|
|
||||||
|
|
||||||
|
def load_season(id=None):
|
||||||
|
sql = 'select * from season'
|
||||||
|
args = ()
|
||||||
|
if id:
|
||||||
|
sql += ' where season.id = ?'
|
||||||
|
args = (id, )
|
||||||
|
sql += ' order by season.start'
|
||||||
|
return sql, args
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from _ctypes import ArgumentError
|
import datetime
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
INVALID_STR = 'Form entry "{}" is invalid'
|
INVALID_STR = 'Form entry "{}" is invalid'
|
||||||
@@ -35,12 +35,12 @@ class Drink:
|
|||||||
|
|
||||||
name = form.get('name', None)
|
name = form.get('name', None)
|
||||||
if not name:
|
if not name:
|
||||||
raise ArgumentError('Form data contains no field "name"')
|
raise AttributeError('Form data contains no field "name"')
|
||||||
name = str(name)
|
name = str(name)
|
||||||
|
|
||||||
vol = form.get('vol', None)
|
vol = form.get('vol', None)
|
||||||
if not vol:
|
if not vol:
|
||||||
raise ArgumentError('Form data contains no field "vol"')
|
raise AttributeError('Form data contains no field "vol"')
|
||||||
vol = float(vol)
|
vol = float(vol)
|
||||||
|
|
||||||
self = cls(id=id, name=name, vol=vol)
|
self = cls(id=id, name=name, vol=vol)
|
||||||
@@ -60,13 +60,49 @@ class Enemy:
|
|||||||
|
|
||||||
name = form.get('name', None)
|
name = form.get('name', None)
|
||||||
if not name:
|
if not name:
|
||||||
raise ArgumentError(INVALID_STR.format('name'))
|
raise AttributeError(INVALID_STR.format('name'))
|
||||||
name = str(name)
|
name = str(name)
|
||||||
|
|
||||||
boss = form.get('boss', '')
|
boss = form.get('boss', '')
|
||||||
if boss not in [True, False, 'True', 'False']:
|
if boss not in [True, False, 'True', 'False']:
|
||||||
raise ArgumentError(INVALID_STR.format('boss'))
|
raise AttributeError(INVALID_STR.format('boss'))
|
||||||
|
|
||||||
self = cls(id=id, name=name, boss=boss)
|
self = cls(id=id, name=name, boss=boss)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Season:
|
||||||
|
id: int
|
||||||
|
game: str
|
||||||
|
description: str
|
||||||
|
start: datetime.date
|
||||||
|
end: datetime.date
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_form(cls, form):
|
||||||
|
id = form.get('id', None)
|
||||||
|
id = int(id) if id else None
|
||||||
|
|
||||||
|
game = form.get('game', None)
|
||||||
|
if not game:
|
||||||
|
raise AttributeError(INVALID_STR.format('game'))
|
||||||
|
game = str(game)
|
||||||
|
|
||||||
|
description = form.get('description', None)
|
||||||
|
|
||||||
|
start = form.get('start', None)
|
||||||
|
try:
|
||||||
|
start = datetime.date.fromisoformat(start)
|
||||||
|
except Exception:
|
||||||
|
raise AttributeError(INVALID_STR.format('start'))
|
||||||
|
|
||||||
|
end = form.get('end', None)
|
||||||
|
if end:
|
||||||
|
try:
|
||||||
|
end = datetime.date.fromisoformat(end)
|
||||||
|
except Exception:
|
||||||
|
raise INVALID_STR.format('end')
|
||||||
|
|
||||||
|
self = cls(id, game, description, start, end)
|
||||||
|
return self
|
||||||
79
templates/editseason.html
Normal file
79
templates/editseason.html
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% set active_page = "seasons" %}
|
||||||
|
{% block title %}Seasons{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form class="needs-validation" novalidate action="/saveseason" method="post">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="id">ID</label>
|
||||||
|
<input name="id"
|
||||||
|
type="text"
|
||||||
|
class="form-control"
|
||||||
|
id="id"
|
||||||
|
value="{{ model['id'] }}"
|
||||||
|
readonly>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="game">Game Name</label>
|
||||||
|
<input name="game"
|
||||||
|
type="text"
|
||||||
|
class="form-control"
|
||||||
|
id="game"
|
||||||
|
placeholder="The game name..."
|
||||||
|
value="{{ model['game'] }}"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="description">Season Description</label>
|
||||||
|
<input name="description"
|
||||||
|
type="text"
|
||||||
|
class="form-control"
|
||||||
|
id="description"
|
||||||
|
placeholder="The season description..."
|
||||||
|
value="{{ model['description'] }}"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="start">Season Start</label>
|
||||||
|
<input name="start"
|
||||||
|
type="date"
|
||||||
|
class="form-control"
|
||||||
|
id="start"
|
||||||
|
placeholder="YYYY-MM-DD"
|
||||||
|
value="{{ model['start'] }}"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="end">Season End</label>
|
||||||
|
<input name="end"
|
||||||
|
type="date"
|
||||||
|
class="form-control"
|
||||||
|
id="start"
|
||||||
|
placeholder="Season end date..."
|
||||||
|
value="{{ model['end'] }}">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Example starter JavaScript for disabling form submissions if there are invalid fields
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
// Fetch all the forms we want to apply custom Bootstrap validation styles to
|
||||||
|
let forms = document.getElementsByClassName('needs-validation');
|
||||||
|
// Loop over them and prevent submission
|
||||||
|
let validation = Array.prototype.filter.call(forms, function (form) {
|
||||||
|
form.addEventListener('submit', function (event) {
|
||||||
|
if (form.checkValidity() === false) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
form.classList.add('was-validated');
|
||||||
|
}, false);
|
||||||
|
});
|
||||||
|
}, false);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@@ -3,5 +3,48 @@
|
|||||||
{% block title %}Seasons{% endblock %}
|
{% block title %}Seasons{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% if g.is_editor %}
|
||||||
|
<div class="btn-toolbar" role="toolbar">
|
||||||
|
<a class="btn btn-primary" href="/newseason" role="button">New Season</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if not model.seasons %}
|
||||||
There are no seasons.
|
There are no seasons.
|
||||||
|
{% else %}
|
||||||
|
<table class="table table-hover table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{% for prop, caption in model.columns %}
|
||||||
|
<th scope="col" class="col-sm-auto text-center">{{ caption }}</th>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<th scope="col" class="col-sm-auto text-center"></th>
|
||||||
|
|
||||||
|
{% if g.is_editor %}
|
||||||
|
<th scope="col" class="col-sm-auto text-center">Editor</th>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in model.seasons %}
|
||||||
|
<tr>
|
||||||
|
{% for prop, caption in model.columns %}
|
||||||
|
<td class="col-sm-auto text-center">{{ item[prop] }}</td>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<td class="col-sm-auto text-center">
|
||||||
|
<a class="btn btn-dark" href="/seasons/{{ item.id }}">Show</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
{% if g.is_editor %}
|
||||||
|
<td class="col-sm-auto text-center">
|
||||||
|
<a class="btn btn-dark" href="/seasons/edit/{{ item.id }}">Edit</a>
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user