147 lines
4.9 KiB
Python
147 lines
4.9 KiB
Python
from datetime import datetime
|
|
from flask import Flask, render_template, request, jsonify
|
|
from flask_sqlalchemy import SQLAlchemy
|
|
from sqlalchemy import func
|
|
import os
|
|
|
|
app = Flask(__name__)
|
|
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL')
|
|
db = SQLAlchemy(app)
|
|
|
|
# Models
|
|
class Player(db.Model):
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
name = db.Column(db.String(50), nullable=False, unique=True)
|
|
|
|
class Date(db.Model):
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
date_str = db.Column(db.String(20), nullable=False, unique=True) # e.g. '08/05/25'
|
|
|
|
class Attendance(db.Model):
|
|
"""
|
|
Attendance record for a player on a date.
|
|
status: 'yes', 'no', 'maybe', or blank (None)
|
|
"""
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
date_id = db.Column(db.Integer, db.ForeignKey('date.id'), nullable=False)
|
|
player_id = db.Column(db.Integer, db.ForeignKey('player.id'), nullable=False)
|
|
status = db.Column(db.String(10)) # 'yes', 'no', 'maybe', or blank
|
|
|
|
__table_args__ = (db.UniqueConstraint('date_id', 'player_id', name='_date_player_uc'),)
|
|
|
|
class GuestName(db.Model):
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
date_id = db.Column(db.Integer, db.ForeignKey('date.id'), nullable=False, unique=True)
|
|
name = db.Column(db.String(50), nullable=False)
|
|
|
|
def get_initial_data():
|
|
# Ensure tables exist
|
|
db.create_all()
|
|
# If no players, insert defaults
|
|
if Player.query.count() == 0:
|
|
for name in ["Alice", "Bob", "Charlie", "David", "Eve", "Frank", "Grace", "Hannah"]:
|
|
db.session.add(Player(name=name))
|
|
db.session.commit()
|
|
if not GuestName.query.first():
|
|
# Set default guest name for all dates
|
|
pass
|
|
|
|
def parse_date(date_str):
|
|
return datetime.strptime(date_str, '%d/%m/%y')
|
|
|
|
def db_to_json():
|
|
players = [p.name for p in Player.query.order_by(Player.id)]
|
|
guest = "Guest"
|
|
dates = sorted([d.date_str for d in Date.query.all()], key=parse_date)
|
|
attendance = {}
|
|
for att in Attendance.query.all():
|
|
date = Date.query.get(att.date_id).date_str
|
|
player = Player.query.get(att.player_id)
|
|
colIdx = players.index(player.name) if player.name in players else len(players) # guest is last
|
|
key = f"{date}|{colIdx}"
|
|
attendance[key] = True if att.status == 'yes' else 'no'
|
|
guest_names = {Date.query.get(g.date_id).date_str: g.name for g in GuestName.query.all()}
|
|
return {
|
|
"players": players,
|
|
"guest": guest,
|
|
"dates": dates,
|
|
"attendance": attendance,
|
|
"guestNames": guest_names
|
|
}
|
|
|
|
def json_to_db(data):
|
|
try:
|
|
db.session.query(Attendance).delete()
|
|
db.session.commit()
|
|
db.session.query(GuestName).delete()
|
|
db.session.commit()
|
|
db.session.query(Date).delete()
|
|
db.session.commit()
|
|
db.session.query(Player).delete()
|
|
db.session.commit()
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
print("Error during deletion:", e)
|
|
raise
|
|
|
|
# Insert players from JSON
|
|
for name in data.get("players", []):
|
|
db.session.add(Player(name=name))
|
|
db.session.commit()
|
|
|
|
# Insert dates and attendance
|
|
for date_str in data.get("dates", []):
|
|
date = Date(date_str=date_str)
|
|
db.session.add(date)
|
|
db.session.commit()
|
|
for idx, player_name in enumerate(data["players"] + [data["guest"]]):
|
|
key = f"{date_str}|{idx}"
|
|
status = data["attendance"].get(key)
|
|
if status:
|
|
player = Player.query.filter_by(name=player_name).first()
|
|
if player:
|
|
# Save status as 'yes', 'no', or 'maybe'
|
|
db.session.add(Attendance(date_id=date.id, player_id=player.id, status='yes' if status is True else status if status in ['no', 'maybe'] else None))
|
|
guest_name = data.get("guestNames", {}).get(date_str)
|
|
if guest_name:
|
|
db.session.add(GuestName(date_id=date.id, name=guest_name))
|
|
db.session.commit()
|
|
|
|
|
|
|
|
@app.route('/')
|
|
def index():
|
|
return render_template('index.html')
|
|
|
|
@app.route('/reports')
|
|
def reports():
|
|
return render_template('reports.html')
|
|
|
|
@app.route('/api/data', methods=['GET'])
|
|
def get_data():
|
|
get_initial_data()
|
|
return jsonify(db_to_json())
|
|
|
|
@app.route('/api/data', methods=['POST'])
|
|
def update_data():
|
|
data = request.json
|
|
json_to_db(data)
|
|
return jsonify({"status": "success"})
|
|
|
|
# Optional: export from DB as JSON (for compatibility)
|
|
@app.route('/export-data')
|
|
def export_data():
|
|
from flask import Response
|
|
get_initial_data()
|
|
data = db_to_json()
|
|
return Response(
|
|
response=json.dumps(data, indent=2),
|
|
mimetype='application/json',
|
|
headers={'Content-Disposition': 'attachment;filename=attendance_data.json'}
|
|
)
|
|
|
|
if __name__ == '__main__':
|
|
import os
|
|
port = int(os.environ.get('PORT', 5000))
|
|
app.run(host='0.0.0.0', port=port, debug=False)
|