vicky-remi-wedding-website/france/france_rsvp/database.py

100 lines
2.6 KiB
Python

import contextlib
from datetime import datetime
import logging
import os
import sqlite3
logger = logging.getLogger(__name__)
DATABASE_FILE = os.environ['DATABASE']
assert os.path.isfile(DATABASE_FILE)
@contextlib.contextmanager
def get_db():
db = sqlite3.connect(DATABASE_FILE)
try:
yield db
finally:
db.close()
def get_people_and_replies(code):
with get_db() as db:
return list(db.execute(
'''\
SELECT
persons.id, persons.name,
(
SELECT rsvp FROM replies
WHERE
replies.person_id = persons.id
AND replies.date = (
SELECT MAX(date)
FROM replies
WHERE person_id = persons.id
)
) AS rsvp
FROM
persons
WHERE
persons.code = :code;
''',
dict(code=code),
))
def record_reply(code, persons):
assert isinstance(persons, dict)
with get_db() as db:
# Check the IDs of people match
expected_people_ids = set(
row[0]
for row in db.execute(
'''\
SELECT
id
FROM
persons
WHERE
code = :code;
''',
dict(code=code),
)
)
if not expected_people_ids:
logger.warning("Got reply with invalid code %r", code)
raise ValueError("Invalid code")
for person_id in persons.keys():
if person_id not in expected_people_ids:
logger.warning(
"Got invalid person id=%d for code %r",
person_id,
code,
)
raise ValueError("Invalid person")
# Insert update
cursor = db.cursor()
date = datetime.utcnow()
for person_id, rsvp in persons.items():
if rsvp not in ('yes', 'no'):
raise ValueError("Invalid rsvp %r", rsvp)
cursor.execute(
'''\
INSERT INTO replies(person_id, date, rsvp)
VALUES(:id, :date, :rsvp);
''',
dict(id=person_id, date=date, rsvp=rsvp),
)
cursor.execute('COMMIT;')
logger.info(
"Recorded update for code=%r date=%r persons: %s",
code,
date,
' '.join('%d=%s' % p for p in sorted(persons.items())),
)