3636
3737@asynccontextmanager
3838async def lifespan (app : FastAPI ):
39- # Init DB tables
4039 async with engine .begin () as conn :
4140 await conn .run_sync (models .Base .metadata .create_all )
4241
@@ -59,6 +58,10 @@ async def lifespan(app: FastAPI):
5958 name = "Demon Tower" ,
6059 description = "The legendary Demon. Hard challenge." ,
6160 required_power = 7500 , xp_reward = 500 , image_name = "demon.png" , owner = "all" ))
61+ await crud .create_dungeon (db , schemas .DungeonCreate (
62+ name = "Boss St. Egano" ,
63+ description = "The legendary Boss. Ultimate challenge." ,
64+ required_power = 99999 , xp_reward = 9999 , image_name = "stegano.jpg" , owner = "all" ))
6265 print ("Initial dungeons created." )
6366 else :
6467 print ("Dungeons already exist, skipping initial creation." )
@@ -70,7 +73,6 @@ async def lifespan(app: FastAPI):
7073 try :
7174 yield
7275 finally :
73- # Optional: Task canceln (wenn du willst)
7476 task .cancel ()
7577
7678
@@ -136,11 +138,8 @@ async def register(user: schemas.UserCreate, db=Depends(get_async_db)):
136138 if db_user :
137139 raise HTTPException (status_code = 400 , detail = "Username (or Variation of it) is already taken!" )
138140 try :
139- # 1. User anlegen
140141 user_obj = await crud .create_user (db = db , user = user , username_key = normalform )
141- # 2. User mit allen Items-Relationen nochmal laden (joinedload in crud!)
142142 user_full = await crud .get_user_by_username (db , user_obj .username )
143- # 3. Jetzt das User-Objekt zurückgeben – Items sind garantiert geladen!
144143 return user_full
145144 except ValueError as e :
146145 raise HTTPException (status_code = 400 , detail = str (e ))
@@ -172,7 +171,6 @@ async def read_users_me(token: str = Depends(oauth2_scheme), db=Depends(get_asyn
172171 user = result .unique ().scalar_one_or_none ()
173172 if not user :
174173 raise HTTPException (status_code = 401 , detail = "User not found" )
175- # <<< HIER: Power mit Items summieren wie im Leaderboard!
176174 item_power = sum (item .bonus for item in user .items )
177175 user .power = user .power + item_power
178176 return user
@@ -187,7 +185,7 @@ async def create_item_for_user(item: schemas.ItemCreate, token: str = Depends(oa
187185 raise HTTPException (status_code = 401 , detail = "Invalid credentials" )
188186 return await crud .create_item_for_user (db = db , item = item , user_id = user .id )
189187
190- @app .get ("/users/" , response_model = List [schemas .User ]) # you can make a lighter schema for listing if needed
188+ @app .get ("/users/" , response_model = List [schemas .User ])
191189async def read_users (
192190 db = Depends (get_async_db ),
193191 limit : int = 10 ,
@@ -593,16 +591,38 @@ async def cleanup_old_records():
593591 user upload folders asynchronously.
594592 """
595593 while True :
596- await asyncio .sleep (240 )
594+ await asyncio .sleep (30 )
597595 db_gen = get_async_db ()
598596 db = await anext (db_gen )
599597 try :
600- ten_minutes_ago = datetime .utcnow () - timedelta (minutes = 10 )
598+ ten_minutes_ago = datetime .utcnow () - timedelta (minutes = 1 )
601599
602600 users_to_delete_query = await db .execute (
603- select (models .User .username ).where (models .User .created_at < ten_minutes_ago )
601+ select (models .User .id , models . User . username ).where (models .User .created_at < ten_minutes_ago )
604602 )
605- deleted_usernames = [u [0 ] for u in users_to_delete_query .all ()]
603+ deleted_users = users_to_delete_query .all ()
604+ deleted_user_ids = [u [0 ] for u in deleted_users ]
605+ deleted_usernames = [u [1 ] for u in deleted_users ]
606+
607+ if deleted_user_ids :
608+ await db .execute (
609+ models .Inventory .__table__ .delete ().where (
610+ models .Inventory .user_id .in_ (deleted_user_ids )
611+ )
612+ )
613+
614+ await db .execute (
615+ models .CompletedDungeon .__table__ .delete ().where (
616+ models .CompletedDungeon .user_id .in_ (deleted_user_ids )
617+ )
618+ )
619+
620+ await db .execute (
621+ models .Fight .__table__ .delete ().where (
622+ (models .Fight .attacker_id .in_ (deleted_user_ids )) |
623+ (models .Fight .defender_id .in_ (deleted_user_ids ))
624+ )
625+ )
606626
607627 await db .execute (
608628 models .Fight .__table__ .delete ().where (
@@ -613,7 +633,6 @@ async def cleanup_old_records():
613633 dungeons_subquery = select (models .Dungeon .id ).where (
614634 (models .Dungeon .one_time_clear == False ) | (models .Dungeon .one_time_clear == None )
615635 )
616-
617636 await db .execute (
618637 models .CompletedDungeon .__table__ .delete ().where (
619638 models .CompletedDungeon .completion_timestamp < ten_minutes_ago ,
@@ -659,6 +678,7 @@ async def cleanup_old_records():
659678 await db_gen .aclose ()
660679
661680
681+
662682@app .post ("/images/upload" , status_code = status .HTTP_201_CREATED )
663683async def upload_dungeon_image (file : UploadFile = File (...),
664684 current_user : schemas .User = Depends (get_current_active_user )):
@@ -684,10 +704,19 @@ async def upload_dungeon_image(file: UploadFile = File(...),
684704
685705 return {"filename" : safe_filename , "detail" : "Image uploaded successfully to user directory." }
686706
707+ UPLOADS_DIR = os .path .abspath ("uploads" )
708+
687709@app .get ("/images/{filename:path}" )
688- async def get_private_dungeon_image (filename : str , current_user : schemas .User = Depends (get_current_active_user )):
710+ async def get_private_dungeon_image (
711+ filename : str ,
712+ current_user : schemas .User = Depends (get_current_active_user )
713+ ):
714+ user_image_path = os .path .abspath (
715+ os .path .join (UPLOADS_DIR , current_user .username , filename )
716+ )
689717
690- user_image_path = f"uploads/{ current_user .username } /{ filename } "
718+ if not user_image_path .startswith (UPLOADS_DIR + os .sep ):
719+ raise HTTPException (status_code = 404 , detail = "Image not found or you do not have permission to access it." )
691720
692721 if not os .path .exists (user_image_path ):
693722 raise HTTPException (status_code = 404 , detail = "Image not found or you do not have permission to access it." )
0 commit comments