From d074074b0395dc7df392fc8fb58e763f94969b5e Mon Sep 17 00:00:00 2001 From: lvrossem Date: Mon, 17 Apr 2023 15:38:25 -0600 Subject: [PATCH] More and more refactors --- src/crud/highscores.py | 8 ++- src/crud/learnableprogress.py | 84 ++++++++++++++++++++++++++++++++ src/crud/users.py | 12 ++--- src/enums.py | 18 ------- src/main.py | 26 +++++++++- src/schemas/courseprogress.py | 5 +- src/schemas/highscores.py | 4 +- src/schemas/learnableprogress.py | 9 ++-- src/schemas/users.py | 6 ++- tests/test_highscores.py | 2 +- tests/test_users.py | 7 ++- 11 files changed, 139 insertions(+), 42 deletions(-) diff --git a/src/crud/highscores.py b/src/crud/highscores.py index 5acd8d3..db045da 100644 --- a/src/crud/highscores.py +++ b/src/crud/highscores.py @@ -97,7 +97,9 @@ def create_high_score( db.add(db_high_score) db.commit() db.refresh(db_high_score) - return Score(score_value=db_high_score.score_value, time=str(db_high_score.time)) + return Score( + score_value=db_high_score.score_value, time=str(db_high_score.time) + ) old_high_score = ( db.query(HighScore) @@ -112,6 +114,8 @@ def create_high_score( db.delete(old_high_score) return add_to_db() else: - return Score(score_value=old_high_score.score_value, time=str(old_high_score.time)) + return Score( + score_value=old_high_score.score_value, time=str(old_high_score.time) + ) else: return add_to_db() diff --git a/src/crud/learnableprogress.py b/src/crud/learnableprogress.py index e69de29..f7bae1a 100644 --- a/src/crud/learnableprogress.py +++ b/src/crud/learnableprogress.py @@ -0,0 +1,84 @@ +from fastapi import HTTPException +from sqlalchemy.orm import Session + +from src.enums import CourseEnum +from src.models import CourseProgress, LearnableProgress, User +from src.schemas.learnableprogress import SavedLearnableProgress + + +def create_learnable( + db: Session, user: User, course: CourseEnum, learnable: SavedLearnableProgress +): + """Create a new learnable""" + if learnable.index < 0: + raise HTTPException(status_code=400, detail="Negative index not allowed") + + if learnable.in_use is None: + raise HTTPException( + status_code=400, detail="Please indicate whether the learnable is in use" + ) + + if len(learnable.name) < 1: + raise HTTPException( + status_code=400, detail="No name was provided for the learnable" + ) + + potential_duplicate = ( + db.query(LearnableProgress) + .filter(LearnableProgress.name == learnable.name) + .first() + ) + + if potential_duplicate: + raise HTTPException( + status_code=400, detail="No duplicate learnable names allowed" + ) + + db_course = ( + db.query(CourseProgress) + .filter( + CourseProgress.owner_id == user.user_id, CourseProgress.course == course + ) + .first() + ) + + db_learnable = LearnableProgress( + index=learnable.index, + in_use=learnable.in_use, + name=learnable.name, + progress=0.0, + course_progress_id=db_course.course_progress_id, + ) + + db.add(db_learnable) + db.commit() + + +def patch_learnable(db: Session, user: User, learnable: SavedLearnableProgress): + """Patch an existing learnable""" + db_learnable = ( + db.query(LearnableProgress) + .filter(LearnableProgress.name == learnable.name) + .first() + ) + + if not db_learnable: + raise HTTPException( + status_code=400, detail="Learnable with provided name not found" + ) + + if learnable.index < -1: + raise HTTPException(status_code=400, detail="Invalid learnable index") + elif learnable.index > -1: + db_learnable.index = learnable.index + + if learnable.in_use is not None: + db_learnable.in_use = learnable.in_use + + if len(learnable.name) > 0: + db_learnable.name = learnable.name + + # TODO: chek progress semantics + + db.add(db_learnable) + db.commit() diff --git a/src/crud/users.py b/src/crud/users.py index bd467b6..c05f457 100644 --- a/src/crud/users.py +++ b/src/crud/users.py @@ -2,16 +2,14 @@ from fastapi import HTTPException from passlib.context import CryptContext from sqlalchemy.orm import Session -from src.models import User from src.crud.highscores import (get_highest_high_scores, get_most_recent_high_scores) -from src.schemas.users import UserCreate from src.enums import CourseEnum, MinigameEnum -from src.models import CourseProgress, LearnableProgress -from src.schemas.highscores import SavedMinigameProgress +from src.models import CourseProgress, LearnableProgress, User from src.schemas.courseprogress import SavedCourseProgress +from src.schemas.highscores import SavedMinigameProgress from src.schemas.learnableprogress import SavedLearnableProgress -from src.schemas.users import SavedUser +from src.schemas.users import SavedUser, UserCreate pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") @@ -28,7 +26,7 @@ def check_empty_fields(username: str, password: str, avatar_index: int): def patch_user(db: Session, username: str, user: UserCreate): """Changes the username and/or the password of a User""" - #check_empty_fields(user.username, user.password, user.avatar_index) + # check_empty_fields(user.username, user.password, user.avatar_index) db_user = get_user_by_username(db, username) potential_duplicate = get_user_by_username(db, user.username) if potential_duplicate: @@ -46,6 +44,8 @@ def patch_user(db: Session, username: str, user: UserCreate): if user.avatar_index > -1: db_user.avatar_index = user.avatar_index + elif user.avatar_index < -1: + raise HTTPException(status_code=400, detail="Invalid avatar index") db_user.playtime += user.playtime db.commit() diff --git a/src/enums.py b/src/enums.py index 3ec4085..3488439 100644 --- a/src/enums.py +++ b/src/enums.py @@ -2,24 +2,6 @@ from fastapi_utils.enums import StrEnum from sqlalchemy.types import Enum, TypeDecorator -class StrEnumType(TypeDecorator): - impl = Enum - - def __init__(self, enum_class, **kw): - self.enum_class = enum_class - super().__init__(enum_class, **kw) - - def process_bind_param(self, value, dialect): - if value is None: - return None - return value.value - - def process_result_value(self, value, dialect): - if value is None: - return None - return self.enum_class(value) - - class MinigameEnum(StrEnum): SpellingBee = "SpellingBee" Hangman = "Hangman" diff --git a/src/main.py b/src/main.py index b2b2d16..1852e37 100644 --- a/src/main.py +++ b/src/main.py @@ -9,10 +9,11 @@ sys.path.append("..") from src.crud import authentication as crud_authentication from src.crud import courseprogress as crud_courseprogress from src.crud import highscores as crud_highscores +from src.crud import learnableprogress as crud_learnables from src.crud import users as crud_users from src.database import Base, engine, get_db from src.enums import CourseEnum, MinigameEnum -from src.schemas import courseprogress, highscores, users +from src.schemas import courseprogress, highscores, learnableprogress, users app = FastAPI() @@ -23,6 +24,7 @@ Base.metadata.create_all(bind=engine) async def root(): return {"message": "Hello world!"} + """ @app.get("/allusers", response_model=List[users.SavedUser]) async def read_users(db: Session = Depends(get_db)): @@ -38,6 +40,7 @@ async def read_user( return crud_users.get_user_by_username(db, current_user_name) """ + @app.patch("/users") async def patch_current_user( user: users.UserCreate, @@ -123,3 +126,24 @@ async def patch_course_progress( return crud_courseprogress.patch_course_progress( db, current_user, course, course_progress ) + + +@app.post("/learnables/{course}") +async def create_learnable( + course: CourseEnum, + learnable: learnableprogress.SavedLearnableProgress, + current_user_name: str = Depends(crud_authentication.get_current_user_name), + db: Session = Depends(get_db), +): + current_user = crud_users.get_user_by_username(db, current_user_name) + crud_learnables.create_learnable(db, current_user, course, learnable) + + +@app.patch("/learnables") +async def create_learnable( + learnable: learnableprogress.SavedLearnableProgress, + current_user_name: str = Depends(crud_authentication.get_current_user_name), + db: Session = Depends(get_db), +): + current_user = crud_users.get_user_by_username(db, current_user_name) + crud_learnables.patch_learnable(db, current_user, learnable) diff --git a/src/schemas/courseprogress.py b/src/schemas/courseprogress.py index 1fef0a1..808ef3f 100644 --- a/src/schemas/courseprogress.py +++ b/src/schemas/courseprogress.py @@ -1,8 +1,9 @@ +from typing import List + from pydantic import BaseModel from src.enums import CourseEnum from src.schemas.learnableprogress import SavedLearnableProgress -from typing import List class CourseProgressBase(BaseModel): @@ -30,4 +31,4 @@ class SavedCourseProgress(BaseModel): learnables: List[SavedLearnableProgress] class Config: - orm_mode = True \ No newline at end of file + orm_mode = True diff --git a/src/schemas/highscores.py b/src/schemas/highscores.py index 75eed72..ae92f15 100644 --- a/src/schemas/highscores.py +++ b/src/schemas/highscores.py @@ -1,8 +1,8 @@ +from typing import List + from pydantic import BaseModel from src.enums import MinigameEnum -from typing import List - class HighScoreBase(BaseModel): diff --git a/src/schemas/learnableprogress.py b/src/schemas/learnableprogress.py index 257b4a3..c558e6d 100644 --- a/src/schemas/learnableprogress.py +++ b/src/schemas/learnableprogress.py @@ -1,7 +1,8 @@ from pydantic import BaseModel + class SavedLearnableProgress(BaseModel): - index: int - in_use: bool - name: str - progress: float \ No newline at end of file + index: int = -1 + in_use: bool = None + name: str = "" + progress: float = -1.0 diff --git a/src/schemas/users.py b/src/schemas/users.py index 24a22f4..a2699a9 100644 --- a/src/schemas/users.py +++ b/src/schemas/users.py @@ -1,7 +1,9 @@ -from pydantic import BaseModel from typing import List -from src.schemas.highscores import SavedMinigameProgress + +from pydantic import BaseModel + from src.schemas.courseprogress import SavedCourseProgress +from src.schemas.highscores import SavedMinigameProgress class UserBase(BaseModel): diff --git a/tests/test_highscores.py b/tests/test_highscores.py index c9f31cc..2c6e86b 100644 --- a/tests/test_highscores.py +++ b/tests/test_highscores.py @@ -3,7 +3,7 @@ import random import pytest from src.enums import MinigameEnum -from tests.base import client, password, avatar_index, register_user +from tests.base import avatar_index, client, password, register_user from tests.config.database import clear_db diff --git a/tests/test_users.py b/tests/test_users.py index 0710496..9c18d39 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -8,7 +8,6 @@ patched_password = "New password" patched_avatar_index = 2 - @pytest.mark.asyncio async def test_patch_user(): """Test the patching of a user's username, password and avatar""" @@ -62,7 +61,7 @@ async def test_patch_user_with_empty_fields(): "username": "", "password": patched_password, "avatar_index": patched_avatar_index, - "playtime": 0.0 + "playtime": 0.0, }, headers=headers, ) @@ -74,7 +73,7 @@ async def test_patch_user_with_empty_fields(): "username": username, "password": patched_password, "avatar_index": -1, - "playtime": 0.0 + "playtime": 0.0, }, headers=headers, ) @@ -86,7 +85,7 @@ async def test_patch_user_with_empty_fields(): "username": username, "password": "", "avatar_index": patched_avatar_index, - "playtime": 0.0 + "playtime": 0.0, }, headers=headers, )