forked from Hay1tsme/artemis
mai2: rework photo uploads, relates to #67
This commit is contained in:
@ -1,11 +1,14 @@
|
||||
from typing import List
|
||||
from starlette.routing import Route, Mount
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import Response, RedirectResponse
|
||||
from os import path
|
||||
from starlette.responses import Response, RedirectResponse, FileResponse
|
||||
from os import path, walk, remove
|
||||
import yaml
|
||||
import jinja2
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from PIL import ImageFile
|
||||
import re
|
||||
import shutil
|
||||
|
||||
from core.frontend import FE_Base, UserSession, PermissionOffset
|
||||
from core.config import CoreConfig
|
||||
@ -31,7 +34,8 @@ class Mai2Frontend(FE_Base):
|
||||
Route("/", self.render_GET, methods=['GET']),
|
||||
Mount("/playlog", routes=[
|
||||
Route("/", self.render_GET_playlog, methods=['GET']),
|
||||
Route("/{index}", self.render_GET_playlog, methods=['GET']),
|
||||
Route("/{index:int}", self.render_GET_playlog, methods=['GET']),
|
||||
Route("/photos", self.render_GET_photos, methods=['GET']),
|
||||
]),
|
||||
Mount("/events", routes=[
|
||||
Route("/", self.render_events, methods=['GET']),
|
||||
@ -41,6 +45,7 @@ class Mai2Frontend(FE_Base):
|
||||
]),
|
||||
Route("/update.name", self.update_name, methods=['POST']),
|
||||
Route("/version.change", self.version_change, methods=['POST']),
|
||||
Route("/photo/{photo_id}", self.get_photo, methods=['GET']),
|
||||
]
|
||||
|
||||
async def render_GET(self, request: Request) -> bytes:
|
||||
@ -140,6 +145,50 @@ class Mai2Frontend(FE_Base):
|
||||
else:
|
||||
return RedirectResponse("/gate/", 303)
|
||||
|
||||
async def render_GET_photos(self, request: Request) -> bytes:
|
||||
template = self.environment.get_template(
|
||||
"titles/mai2/templates/mai2_photos.jinja"
|
||||
)
|
||||
usr_sesh = self.validate_session(request)
|
||||
if not usr_sesh:
|
||||
usr_sesh = UserSession()
|
||||
|
||||
if usr_sesh.user_id > 0:
|
||||
if usr_sesh.maimai_version < 0:
|
||||
return RedirectResponse("/game/mai2/", 303)
|
||||
|
||||
photos = await self.data.profile.get_user_photos_by_user(usr_sesh.user_id)
|
||||
|
||||
photos_fixed = []
|
||||
for photo in photos:
|
||||
if datetime.now().timestamp() > (photo['when_upload'] + timedelta(days=7)).timestamp():
|
||||
await self.data.profile.delete_user_photo_by_id(photo['id'])
|
||||
|
||||
if path.exists(f"{self.game_cfg.uploads.photos_dir}/{photo['id']}.jpeg"):
|
||||
remove(f"{self.game_cfg.uploads.photos_dir}/{photo['id']}.jpeg")
|
||||
|
||||
if path.exists(f"{self.game_cfg.uploads.photos_dir}/{photo['id']}"):
|
||||
shutil.rmtree(f"{self.game_cfg.uploads.photos_dir}/{photo['id']}")
|
||||
|
||||
continue
|
||||
|
||||
photos_fixed.append({
|
||||
"id": photo['id'],
|
||||
"playlog_num": photo['playlog_num'],
|
||||
"track_num": photo['track_num'],
|
||||
"when_upload": photo['when_upload'],
|
||||
})
|
||||
|
||||
return Response(template.render(
|
||||
title=f"{self.core_config.server.name} | {self.nav_name}",
|
||||
game_list=self.environment.globals["game_list"],
|
||||
sesh=vars(usr_sesh),
|
||||
photos=photos_fixed,
|
||||
expire_days=7,
|
||||
), media_type="text/html; charset=utf-8")
|
||||
else:
|
||||
return RedirectResponse("/gate/", 303)
|
||||
|
||||
async def update_name(self, request: Request) -> bytes:
|
||||
usr_sesh = self.validate_session(request)
|
||||
if not usr_sesh:
|
||||
@ -299,3 +348,76 @@ class Mai2Frontend(FE_Base):
|
||||
await self.data.static.update_event_by_id(int(event_id), new_enabled, new_start_date)
|
||||
|
||||
return RedirectResponse("/game/mai2/events/?s=1", 303)
|
||||
|
||||
async def get_photo(self, request: Request) -> RedirectResponse:
|
||||
usr_sesh = self.validate_session(request)
|
||||
if not usr_sesh:
|
||||
return RedirectResponse("/gate/", 303)
|
||||
|
||||
photo_jpeg = request.path_params.get("photo_id", None)
|
||||
if not photo_jpeg:
|
||||
return Response(status_code=400)
|
||||
|
||||
matcher = re.match(r"^([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}).jpeg$", photo_jpeg)
|
||||
if not matcher:
|
||||
return Response(status_code=400)
|
||||
|
||||
photo_id = matcher.groups()[0]
|
||||
photo_info = await self.data.profile.get_user_photo_by_id(photo_id)
|
||||
if not photo_info:
|
||||
return Response(status_code=404)
|
||||
|
||||
if photo_info["user"] != usr_sesh.user_id:
|
||||
return Response(status_code=403)
|
||||
|
||||
out_folder = f"{self.game_cfg.uploads.photos_dir}/{photo_id}"
|
||||
|
||||
if datetime.now().timestamp() > (photo_info['when_upload'] + timedelta(days=7)).timestamp():
|
||||
await self.data.profile.delete_user_photo_by_id(photo_info['id'])
|
||||
if path.exists(f"{out_folder}.jpeg"):
|
||||
remove(f"{out_folder}.jpeg")
|
||||
|
||||
if path.exists(f"{out_folder}"):
|
||||
shutil.rmtree(out_folder)
|
||||
|
||||
return Response(status_code=404)
|
||||
|
||||
if path.exists(f"{out_folder}"):
|
||||
print("path exists")
|
||||
max_idx = 0
|
||||
p = ImageFile.Parser()
|
||||
for _, _, files in walk("out_folder"):
|
||||
if not files:
|
||||
break
|
||||
|
||||
matcher = re.match("^(\d+)_(\d+)$", files[0])
|
||||
if not matcher:
|
||||
break
|
||||
|
||||
max_idx = int(matcher.groups()[1])
|
||||
|
||||
if max_idx + 1 != len(files):
|
||||
self.logger.error(f"Expected {max_idx + 1} files, found {len(files)}")
|
||||
max_idx = 0
|
||||
break
|
||||
|
||||
if max_idx == 0:
|
||||
return Response(status_code=500)
|
||||
|
||||
for i in range(max_idx + 1):
|
||||
with open(f"{out_folder}/{i}_{max_idx}", "rb") as f:
|
||||
p.feed(f.read())
|
||||
try:
|
||||
im = p.close()
|
||||
im.save(f"{out_folder}.jpeg")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"{photo_id} failed PIL validation! - {e}")
|
||||
|
||||
shutil.rmtree(out_folder)
|
||||
|
||||
if path.exists(f"{out_folder}.jpeg"):
|
||||
print(f"{out_folder}.jpeg exists")
|
||||
return FileResponse(f"{out_folder}.jpeg")
|
||||
|
||||
return Response(status_code=404)
|
||||
|
Reference in New Issue
Block a user