Add user rating support!
It took me too long to complete it, I hope this thing will work for more than 10 minutes. It also breaks when user rated a level that was already rated.
This commit is contained in:
parent
270cae46b2
commit
44b79518a5
3 changed files with 113 additions and 24 deletions
|
@ -53,6 +53,10 @@ class User(BaseModel):
|
||||||
Username: str = "magmaus3"
|
Username: str = "magmaus3"
|
||||||
Email: str = "user@example.com"
|
Email: str = "user@example.com"
|
||||||
|
|
||||||
|
# Ratings have to be stored in the following format: {mapID: rating},
|
||||||
|
# where rating is either 1 or 5, or None.
|
||||||
|
Ratings: dict = {}
|
||||||
|
|
||||||
|
|
||||||
class Notification(BaseModel):
|
class Notification(BaseModel):
|
||||||
"""Pydantic model for Notifications
|
"""Pydantic model for Notifications
|
||||||
|
|
|
@ -37,6 +37,8 @@ def auth_check(Authorization):
|
||||||
- wrongpass = wrong password
|
- wrongpass = wrong password
|
||||||
- [dictionary] = query
|
- [dictionary] = query
|
||||||
"""
|
"""
|
||||||
|
if Authorization is None:
|
||||||
|
return False, "noauth"
|
||||||
username, password = Authorization.split(":")
|
username, password = Authorization.split(":")
|
||||||
|
|
||||||
query = user_collection.find_one({"Username": username})
|
query = user_collection.find_one({"Username": username})
|
||||||
|
|
|
@ -2,6 +2,7 @@ from datetime import datetime
|
||||||
from fastapi import FastAPI, Form, File, UploadFile, Header, HTTPException, Body
|
from fastapi import FastAPI, Form, File, UploadFile, Header, HTTPException, Body
|
||||||
from fastapi.responses import PlainTextResponse
|
from fastapi.responses import PlainTextResponse
|
||||||
from fastapi.exceptions import RequestValidationError
|
from fastapi.exceptions import RequestValidationError
|
||||||
|
from pydantic import BaseModel
|
||||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||||
|
|
||||||
from typing import Union, Optional, Any
|
from typing import Union, Optional, Any
|
||||||
|
@ -166,23 +167,33 @@ async def getMap(mapID: int):
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/v1/map/{mapID}/start")
|
@app.post("/api/v1/map/{mapID}/start")
|
||||||
async def startMap(mapID: int):
|
async def startMap(
|
||||||
query = db.maps_collection.find_one({"ID": mapID})
|
mapID: int,
|
||||||
del query["_id"]
|
Authorization: Union[str, None] = Header(default=None)
|
||||||
|
):
|
||||||
|
authcheck = db.auth_check(Authorization)
|
||||||
|
if not authcheck[0] and authcheck[1] == "nouser":
|
||||||
|
raise HTTPException(404, detail="User not found")
|
||||||
|
elif not authcheck[0] and authcheck[1] == "wrongpass":
|
||||||
|
raise HTTPException(403, detail="Wrong password")
|
||||||
|
elif authcheck[0]:
|
||||||
|
userData = types.User(**authcheck[1])
|
||||||
|
query = db.maps_collection.find_one({"ID": mapID})
|
||||||
|
del query["_id"]
|
||||||
|
|
||||||
returned_resp = {
|
returned_resp = {
|
||||||
"BestDeaths": 0,
|
"BestDeaths": 0,
|
||||||
"BestPlaytime": 0,
|
"BestPlaytime": 0,
|
||||||
"Clear": False,
|
"Clear": False,
|
||||||
"CurMap": query,
|
"CurMap": query,
|
||||||
"Difficulty": 0,
|
"Difficulty": 0,
|
||||||
"Followed": False,
|
"Followed": False,
|
||||||
"Played": True,
|
"Played": True,
|
||||||
"Rating": 5,
|
"Rating": userData.Ratings[str(mapID)] if str(mapID) in userData.Ratings else -1,
|
||||||
"TagIDs": "1,8,9",
|
"TagIDs": query["TagIDs"],
|
||||||
"TagNames": "Boss/Avoidance,Music,Art",
|
"TagNames": query["TagNames"],
|
||||||
}
|
}
|
||||||
return returned_resp
|
return returned_resp
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/v1/map/{mapID}/stop")
|
@app.post("/api/v1/map/{mapID}/stop")
|
||||||
|
@ -213,12 +224,10 @@ async def stopMapPlay(
|
||||||
)
|
)
|
||||||
if query is not None:
|
if query is not None:
|
||||||
del query["_id"]
|
del query["_id"]
|
||||||
print(__import__("json").dumps(query, indent=4))
|
|
||||||
|
|
||||||
BestUserTime = None
|
BestUserTime = None
|
||||||
BestTime = None
|
BestTime = None
|
||||||
if query is not None and "Leaderboard" in query:
|
if query is not None and "Leaderboard" in query:
|
||||||
print("-" * 3)
|
|
||||||
for i in query["Leaderboard"]:
|
for i in query["Leaderboard"]:
|
||||||
if i["UserID"] == userData.ID:
|
if i["UserID"] == userData.ID:
|
||||||
if BestUserTime is None or BestUserTime > i["BestPlaytime"]:
|
if BestUserTime is None or BestUserTime > i["BestPlaytime"]:
|
||||||
|
@ -227,10 +236,7 @@ async def stopMapPlay(
|
||||||
BestTime = i["BestPlaytime"]
|
BestTime = i["BestPlaytime"]
|
||||||
if len(query["Leaderboard"]) <= 1 and i["UserID"] != userData.ID:
|
if len(query["Leaderboard"]) <= 1 and i["UserID"] != userData.ID:
|
||||||
FirstClear = True
|
FirstClear = True
|
||||||
print(BestUserTime, BestTime)
|
|
||||||
if BestUserTime is None or playtime < BestUserTime:
|
if BestUserTime is None or playtime < BestUserTime:
|
||||||
print(BestUserTime)
|
|
||||||
|
|
||||||
updateQuery = db.maps_collection.update_one(
|
updateQuery = db.maps_collection.update_one(
|
||||||
{"ID": mapID},
|
{"ID": mapID},
|
||||||
{"$pull": {"Leaderboard": {"UserID": userData.ID}},
|
{"$pull": {"Leaderboard": {"UserID": userData.ID}},
|
||||||
|
@ -271,7 +277,6 @@ async def stopMapPlay(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if BestTime is None or playtime < BestTime:
|
if BestTime is None or playtime < BestTime:
|
||||||
print(BestTime, playtime)
|
|
||||||
NewMapRecord = True
|
NewMapRecord = True
|
||||||
|
|
||||||
hook.execute_hooks(
|
hook.execute_hooks(
|
||||||
|
@ -368,6 +373,84 @@ async def upload_map(
|
||||||
return {"MapCode": MapCode}
|
return {"MapCode": MapCode}
|
||||||
# raise HTTPException(501)
|
# raise HTTPException(501)
|
||||||
|
|
||||||
|
class Rating(BaseModel):
|
||||||
|
Rating: int
|
||||||
|
|
||||||
|
@app.post("/api/v1/map/{mapID}/rating")
|
||||||
|
async def rateMap(mapID: int, Rating: Rating, Authorization: Union[str, None] = Header(default=None)):
|
||||||
|
authcheck = db.auth_check(Authorization)
|
||||||
|
if not authcheck[0] and authcheck[1] == "nouser":
|
||||||
|
raise HTTPException(404, detail="User not found")
|
||||||
|
elif not authcheck[0] and authcheck[1] == "wrongpass":
|
||||||
|
raise HTTPException(403, detail="Wrong password")
|
||||||
|
elif authcheck[0]:
|
||||||
|
userData = types.User(**authcheck[1])
|
||||||
|
|
||||||
|
userRating = userData.Ratings[str(mapID)] if str(mapID) in userData.Ratings else 0
|
||||||
|
print(userRating, type(userRating))
|
||||||
|
|
||||||
|
|
||||||
|
if Rating.Rating == 5:
|
||||||
|
if userRating is not None and userRating == 5:
|
||||||
|
raise HTTPException(400, detail="Map already rated! Set rating in request to -1 to unrate.")
|
||||||
|
additional = {}
|
||||||
|
if userRating == 1:
|
||||||
|
additional = {"NumThumbsDown": -1}
|
||||||
|
query = db.maps_collection.update_one({"ID": mapID}, {"$inc": {"NumThumbsUp":1, "NumRatings": 1, **additional}})
|
||||||
|
userRating = 5
|
||||||
|
elif Rating.Rating == 1:
|
||||||
|
if userRating is not None and userRating == 1:
|
||||||
|
raise HTTPException(400, detail="Map already rated! Set rating in request to -1 to unrate.")
|
||||||
|
additional = {}
|
||||||
|
if userRating == 5:
|
||||||
|
additional = {"NumThumbsUp": -1}
|
||||||
|
query = db.maps_collection.update_one({"ID": mapID}, {"$inc": {"NumThumbsDown": 1, "NumRatings": 1, **additional}})
|
||||||
|
userRating = 1
|
||||||
|
elif Rating.Rating == -1:
|
||||||
|
if userRating is None or userRating == -1:
|
||||||
|
raise HTTPException(400, detail="Map is not rated!")
|
||||||
|
key = ""
|
||||||
|
if userRating == 5:
|
||||||
|
key = "NumThumbsUp"
|
||||||
|
elif userRating == 1:
|
||||||
|
key = "NumThumbsDown"
|
||||||
|
else:
|
||||||
|
raise HTTPException(400, detail=f"Previous rating was not 5 or 1. It was {userRating} [{repr(type(userRating))}]")
|
||||||
|
query = db.maps_collection.update_one({"ID": mapID}, {"$inc": {"NumRatings": -1, key: -1}})
|
||||||
|
userRating = -1
|
||||||
|
query = db.maps_collection.find_one({"ID": mapID})
|
||||||
|
|
||||||
|
print(userRating, "+")
|
||||||
|
userQuery = db.user_collection.update_one({"ID": userData.ID}, {"$set": {f"Ratings.{mapID}": userRating} })
|
||||||
|
print(userQuery.raw_result)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"Exists": True,
|
||||||
|
"TagIDs": query["TagIDs"],
|
||||||
|
"TagNames": query["TagNames"],
|
||||||
|
"UserMap": {
|
||||||
|
"BestDeaths": 0,
|
||||||
|
"BestFullPlaytime": 0,
|
||||||
|
"BestFullPlaytimeTime": None,
|
||||||
|
"BestPlaytime": 0,
|
||||||
|
"BestPlaytimeTime": None,
|
||||||
|
"BestReplay": "",
|
||||||
|
"Clear": False,
|
||||||
|
"Difficulty": 0,
|
||||||
|
"FirstClearInvalid": False,
|
||||||
|
"FirstClearPlaytime": 0,
|
||||||
|
"FirstClearTime": False,
|
||||||
|
"FirstDeathTimeValid": False,
|
||||||
|
"FirstDeaths": -1,
|
||||||
|
"FirstPlayRecorded": True,
|
||||||
|
"FirstPlaytime": -1,
|
||||||
|
"FullClear": False,
|
||||||
|
"MapID": mapID,
|
||||||
|
"Played": True,
|
||||||
|
"Rating": userRating,
|
||||||
|
"UserID": userData.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@app.get("/api/v1/map/{mapID}/besttimes/{maxEntries}")
|
@app.get("/api/v1/map/{mapID}/besttimes/{maxEntries}")
|
||||||
async def getMapLeaderboard(mapID: int, maxEntries: int = 5):
|
async def getMapLeaderboard(mapID: int, maxEntries: int = 5):
|
||||||
|
@ -497,14 +580,14 @@ async def reportContent(
|
||||||
async def featuredlist():
|
async def featuredlist():
|
||||||
"""Returns the list id of the weekly levels list."""
|
"""Returns the list id of the weekly levels list."""
|
||||||
# FIXME Add playlists
|
# FIXME Add playlists
|
||||||
return
|
raise HTTPException(404, detail="Not available due to lack of playlist support.")
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/v1/followcheck")
|
@app.get("/api/v1/followcheck")
|
||||||
async def followcheck():
|
async def followcheck():
|
||||||
"""Check, if creators that the user follows uploaded new levels."""
|
"""Check, if creators that the user follows uploaded new levels."""
|
||||||
# FIXME: Stub
|
# FIXME: Stub
|
||||||
return 1
|
raise HTTPException(404, detail="Not available due to follows not being implemented.")
|
||||||
|
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
|
|
Loading…
Reference in a new issue