You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
5.5 KiB

from fastapi import FastAPI
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware # CORS
from datetime import datetime
from uuid import uuid4
import sqlite3
# use database residing here
DB_LOCATION = (
"db/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
origins = [ # CORS
"*",
]
app.add_middleware( # CORS
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/new_session", responses={503: {"description": "Unable to initiate session"}})
async def new_session():
"""Start a new session"""
# add session to the database
time = datetime.utcnow().replace(microsecond=0).isoformat()
tries = 3 # something is very wrong with our random, if we miss 3 times
for i in range(tries):
try:
# generate a cookie
cookie = uuid4().hex
cur.execute(
"""INSERT INTO sessions(cookie, time)
VALUES(:cookie, :time)
""",
{"cookie": cookie, "time": time},
)
con.commit()
except sqlite3.IntegrityError as e:
if i < tries - 1 and str(e) == "UNIQUE constraint failed: sessions.cookie":
continue
elif str(e) == "UNIQUE constraint failed: sessions.cookie":
return JSONResponse(status_code=503)
else:
raise
break
# return new session cookie
return {"cookie": cookie}
@app.get(
"/next_picture/{cookie}",
responses={
204: {"description": "All available images have been appraised"},
409: {"description": "Uninitiated session"},
},
)
async def next_picture(cookie: str):
"""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 JSONResponse(status_code=409)
# 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 JSONResponse(status_code=204)
@app.get(
"/rate_picture/{cookie}/{picture_id}/{mark}",
responses={
406: {"description": "Already appraised"},
409: {"description": "Uninitiated session"},
},
)
async def rate_picture(cookie: str, 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 JSONResponse(status_code=409)
# 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},
)
con.commit()
except sqlite3.IntegrityError as e:
if str(e) == "UNIQUE constraint failed: marks.imgid, marks.sessionid":
return JSONResponse(status_code=406)
return {"status": "success"}
@app.get("/photo_points")
def photo_points():
"""Get points with the url of a photo and the rate"""
return [
{
"id": 0,
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/JPEG_example_down.jpg/350px-JPEG_example_down.jpg",
"lon": 37.34542,
"lat": 55.12323,
"rate": 36 # percentage of likes
},
{
"id": 1,
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/JPEG_example_down.jpg/350px-JPEG_example_down.jpg",
"lon": 37.34342,
"lat": 55.12423,
"rate": 62 # percentage of likes
},
{
"id": 2,
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/JPEG_example_down.jpg/350px-JPEG_example_down.jpg",
"lon": 37.34642,
"lat": 55.12223,
"rate": 43 # percentage of likes
},
{
"id": 3,
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/JPEG_example_down.jpg/350px-JPEG_example_down.jpg",
"lon": 37.34342,
"lat": 55.12923,
"rate": 90 # percentage of likes
}
]