from fastapi import FastAPI import sqlite3 # use database residing here DB_LOCATION = ( "../testbox/photovoter.dblite" # Q: any allowances for this being not OUR database? ) app = FastAPI() con = sqlite3.connect(DB_LOCATION) con.row_factory = sqlite3.Row cur = con.cursor() # NB! single is enough for now, we might require multiple later @app.get("/new_session") async def new_session(): """Start a new session""" # add session to the database # return new session cookie return {"session_id": 42} @app.get("/next_picture/{cookie}") async def next_picture(cookie: int): """Request new picture to rate.""" # check if the cookie is valid cur.execute( """SELECT sessionid FROM sessions WHERE cookie = :cookie LIMIT 1""", {"cookie": cookie}, ) sessionid = cur.fetchone() if sessionid is None: return { "picture_id": -2, "picture_uri": "/path/to/new/session/placeholder", # FIXME[2] } # Q: do we return something specific, or just use convention here? # take not rated picture from the database # do not insert anything in the database yet # return this picture # SELECT all images EXCEPT images with marks from the current session -> # -> SELECT paths for these images # FIXME[0]: can this be done better? cur.execute( """SELECT imgid, resizedpath FROM images WHERE imgid IN (SELECT imgid FROM images EXCEPT SELECT imgid FROM marks WHERE sessionid = :sessionid) LIMIT 1 """, {"sessionid": sessionid["sessionid"]}, ) r = cur.fetchone() if r is not None: return {"picture_id": r["imgid"], "picture_uri": r["resizedpath"]} else: # All available pics have been voted for by this sessionid return { "picture_id": -1, "picture_uri": "/path/to/you/are/done/placeholder", # FIXME[1] } # Q: do we return something specific, or just use a convention here? @app.get("/rate_picture/{session_id}/{picture_id}/{mark}") async def rate_picture(session_id: int, picture_id: int, mark: int): """Submit a rating for the picture""" # check if the cookie is valid cur.execute( """SELECT sessionid FROM sessions WHERE cookie = :cookie LIMIT 1""", {"cookie": cookie}, ) sessionid = cur.fetchone() if sessionid is None: return { "status": "failure" # FIXME[2] } # Q: do we return something specific, or just use convention here? # add new mark to the session table try: cur.execute( """INSERT INTO marks(imgid, sessionid, mark) VALUES(:imgid,:sessionid,:mark) """, {"imgid": picture_id, "sessionid": sessionid["sessionid"], "mark": mark}, ) except sqlite3.IntegrityError as e: if str(e) == "UNIQUE constraint failed: marks.imgid, marks.sessionid": return {"status": "already rated"} cur.commit() return {"status": "success"}