Refaktoring, bugifxy

This commit is contained in:
Michal Kváček
2023-08-28 22:02:02 +02:00
parent b70223896c
commit 5d85e0c0f6
7 changed files with 72 additions and 56 deletions
+2 -3
View File
@@ -1,6 +1,5 @@
import os import os
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.orm import sessionmaker
def get_database_url(): def get_database_url():
@@ -19,4 +18,4 @@ def create_db_engine():
engine = create_db_engine() engine = create_db_engine()
async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) async_session = async_sessionmaker(engine, expire_on_commit=True, class_=AsyncSession)
-1
View File
@@ -18,7 +18,6 @@ class PhotoDataloader:
select(Photo) select(Photo)
.filter(getattr(Photo, self.relationship_column).in_(ids)) .filter(getattr(Photo, self.relationship_column).in_(ids))
)).all() )).all()
photos_by_relationship_id = defaultdict(list) photos_by_relationship_id = defaultdict(list)
for photo in models: for photo in models:
photos_by_relationship_id[getattr(photo, self.relationship_column)].append(photo) photos_by_relationship_id[getattr(photo, self.relationship_column)].append(photo)
-3
View File
@@ -173,9 +173,6 @@ class CreateFlightMutation:
) )
await db.flush() await db.flush()
print("XXXXXXXXXXXXX", weather_takeoff, weather_takeoff.id)
flight = await models.Flight.create(db, data={ flight = await models.Flight.create(db, data={
**data, **data,
"takeoff_weather_info_id": weather_takeoff.id, "takeoff_weather_info_id": weather_takeoff.id,
+45 -14
View File
@@ -1,11 +1,18 @@
from typing import List from typing import List, Optional, Annotated, TYPE_CHECKING
import strawberry import strawberry
from sqlalchemy import select, update from sqlalchemy import select, update
from strawberry.file_uploads import Upload from strawberry.file_uploads import Upload
from database import models from database import models
from decorators.endpoints import authenticated_user_only from decorators.endpoints import authenticated_user_only
from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type, strawberry_sqlalchemy_input from graphql_schema.dataloaders.poi import poi_dataloader
from graphql_schema.entities.poi import PointOfInterest
from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type
from graphql_schema.types import ComboboxInput
from upload_utils import get_public_url, handle_file_upload, delete_file, parse_exif_info, generate_thumbnail, file_exists, resize_image from upload_utils import get_public_url, handle_file_upload, delete_file, parse_exif_info, generate_thumbnail, file_exists, resize_image
from .helpers.flight import handle_combobox_save
if TYPE_CHECKING:
from .poi import PointOfInterest
@strawberry_sqlalchemy_type(models.Photo) @strawberry_sqlalchemy_type(models.Photo)
@@ -20,8 +27,15 @@ class Photo:
return get_public_url(f"photos/{root.flight_id}/thumbs/{root.filename}") return get_public_url(f"photos/{root.flight_id}/thumbs/{root.filename}")
async def load_poi(root):
if not root.point_of_interest_id:
return None
return await poi_dataloader.load(root.point_of_interest_id)
url: str = strawberry.field(resolver=resolve_url) url: str = strawberry.field(resolver=resolve_url)
thumbnail_url: str = strawberry.field(resolver=resolve_thumb_url) thumbnail_url: str = strawberry.field(resolver=resolve_thumb_url)
point_of_interest: Optional[Annotated["PointOfInterest", strawberry.lazy('.poi')]] = strawberry.field(resolver=load_poi)
def get_base_query(user_id: int): def get_base_query(user_id: int):
@@ -46,11 +60,13 @@ class PhotoQueries:
@strawberry.type @strawberry.type
class UploadPhotoMutation: class UploadPhotoMutation:
@strawberry_sqlalchemy_input(models.Photo, exclude_fields=[ @strawberry.input
"id", "filename", "is_flight_cover", "exposed_at", "gps_latitude", "gps_longitude", "gps_altitude"
])
class UploadPhotoInput: class UploadPhotoInput:
photo: Upload photo: Upload
flight_id: int
name: Optional[str] = None
description: Optional[str] = None
point_of_interest: Optional[ComboboxInput] = None
@strawberry.mutation @strawberry.mutation
@authenticated_user_only() @authenticated_user_only()
@@ -59,11 +75,11 @@ class UploadPhotoMutation:
filename = await handle_file_upload(input.photo, path) filename = await handle_file_upload(input.photo, path)
info.context.background_tasks.add_task(resize_image, path=path, filename=filename, new_width=2500) info.context.background_tasks.add_task(resize_image, path=path, filename=filename, new_width=2500)
info.context.background_tasks.add_task(generate_thumbnail, path=path, filename=filename, new_width=300) info.context.background_tasks.add_task(generate_thumbnail, path=path, filename=filename)
exif_info = await parse_exif_info(path, filename) exif_info = await parse_exif_info(path, filename)
created_photo = await models.Photo.create(data={ return await models.Photo.create(data={
"flight_id": input.flight_id, "flight_id": input.flight_id,
"name": input.name, "name": input.name,
"filename": filename, "filename": filename,
@@ -76,14 +92,15 @@ class UploadPhotoMutation:
"created_by_id": info.context.user_id, "created_by_id": info.context.user_id,
}, db_session=info.context.db) }, db_session=info.context.db)
return created_photo
@strawberry.type @strawberry.type
class EditPhotoMutation: class EditPhotoMutation:
@strawberry_sqlalchemy_input(models.Photo, exclude_fields=["id"], all_optional=True) @strawberry.input
class EditPhotoInput: class EditPhotoInput:
pass name: Optional[str] = None
description: Optional[str] = None
point_of_interest: Optional[ComboboxInput] = None
is_flight_cover: Optional[bool] = None
@strawberry.mutation() @strawberry.mutation()
@authenticated_user_only() @authenticated_user_only()
@@ -91,7 +108,22 @@ class EditPhotoMutation:
query = get_base_query(info.context.user_id) query = get_base_query(info.context.user_id)
photo = (await info.context.db.scalars(query.filter(models.Photo.id == id))).one() photo = (await info.context.db.scalars(query.filter(models.Photo.id == id))).one()
updated_model = await models.Photo.update(info.context.db, obj=photo, data=input.to_dict()) data = {
key: getattr(input, key) for key in ('name', 'description', 'is_flight_cover')
if getattr(input, key) is not None
}
if input.point_of_interest:
data['point_of_interest_id'] = await handle_combobox_save(
info.context.db,
models.PointOfInterest,
input.point_of_interest,
info.context.user_id,
extra_data={
"description": ""
}
)
updated_model = await models.Photo.update(info.context.db, obj=photo, data=data)
if input.is_flight_cover: if input.is_flight_cover:
# reset other covers # reset other covers
@@ -99,7 +131,6 @@ class EditPhotoMutation:
update(models.Photo) update(models.Photo)
.filter(models.Photo.flight_id == photo.flight_id) .filter(models.Photo.flight_id == photo.flight_id)
.filter(models.Photo.id != id).values(is_flight_cover=False)) .filter(models.Photo.id != id).values(is_flight_cover=False))
) )
return updated_model return updated_model
@@ -118,7 +149,7 @@ class DeletePhotoMutation:
delete_file(f"{base_path}/{photo.filename}") delete_file(f"{base_path}/{photo.filename}")
delete_file(f"{base_path}/thumbs/{photo.filename}") delete_file(f"{base_path}/thumbs/{photo.filename}")
except Exception as e: except Exception as e:
print("ERROR", e) print(e)
await info.context.db.delete(photo) await info.context.db.delete(photo)
+3 -4
View File
@@ -7,14 +7,13 @@ from graphql_schema.dataloaders.flight import flight_by_poi_dataloader
from graphql_schema.dataloaders.photos import poi_photos_dataloader from graphql_schema.dataloaders.photos import poi_photos_dataloader
from graphql_schema.dataloaders.poi import poi_type_dataloader from graphql_schema.dataloaders.poi import poi_type_dataloader
from graphql_schema.entities.helpers.flight import handle_combobox_save from graphql_schema.entities.helpers.flight import handle_combobox_save
from graphql_schema.entities.photo import Photo
from graphql_schema.entities.poi_type import PointOfInterestType from graphql_schema.entities.poi_type import PointOfInterestType
from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type, strawberry_sqlalchemy_input from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type, strawberry_sqlalchemy_input
from graphql_schema.types import ComboboxInput from graphql_schema.types import ComboboxInput
if TYPE_CHECKING: if TYPE_CHECKING:
from .flight import Flight from .flight import Flight
from .photo import Photo
@strawberry_sqlalchemy_type(models.PointOfInterest) @strawberry_sqlalchemy_type(models.PointOfInterest)
class PointOfInterest: class PointOfInterest:
@@ -28,7 +27,7 @@ class PointOfInterest:
return await flight_by_poi_dataloader.load(root.id) return await flight_by_poi_dataloader.load(root.id)
type: Optional[PointOfInterestType] = strawberry.field(resolver=load_type) type: Optional[PointOfInterestType] = strawberry.field(resolver=load_type)
photos: List[Photo] = strawberry.field(resolver=load_photos) photos: List[Annotated["Photo", strawberry.lazy('.photo')]] = strawberry.field(resolver=load_photos)
flights: List[Annotated["Flight", strawberry.lazy('.flight')]] = strawberry.field(resolver=load_flights) flights: List[Annotated["Flight", strawberry.lazy('.flight')]] = strawberry.field(resolver=load_flights)
@@ -72,7 +71,6 @@ class PointOfInterestQueries:
return (await info.context.db.scalars(query)).one() return (await info.context.db.scalars(query)).one()
@strawberry.type @strawberry.type
class CreatePointOfInterestMutation: class CreatePointOfInterestMutation:
@strawberry_sqlalchemy_input(models.PointOfInterest, exclude_fields=['id', 'type_id']) @strawberry_sqlalchemy_input(models.PointOfInterest, exclude_fields=['id', 'type_id'])
@@ -84,6 +82,7 @@ class CreatePointOfInterestMutation:
async def create_point_of_interest(root, info, input: CreatePointOfInterestInput) -> PointOfInterest: async def create_point_of_interest(root, info, input: CreatePointOfInterestInput) -> PointOfInterest:
input_data = input.to_dict() input_data = input.to_dict()
if input.type:
input_data['type_id'] = await handle_combobox_save( input_data['type_id'] = await handle_combobox_save(
info.context.db, info.context.db,
models.PointOfInterestType, models.PointOfInterestType,
+6 -10
View File
@@ -10,7 +10,7 @@ from database import models
from database.models import User from database.models import User
from decorators.endpoints import authenticated_user_only from decorators.endpoints import authenticated_user_only
from decorators.error_logging import error_logging from decorators.error_logging import error_logging
from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type, strawberry_sqlalchemy_input from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_type
from upload_utils import handle_file_upload, delete_file, get_public_url, resize_image from upload_utils import handle_file_upload, delete_file, get_public_url, resize_image
@@ -46,22 +46,18 @@ class UserQueries:
@authenticated_user_only() @authenticated_user_only()
@error_logging @error_logging
async def logged_user(root, info) -> User: async def logged_user(root, info) -> User:
user = (await info.context.db.scalars( return (await info.context.db.scalars(
select(models.User).filter_by(id=info.context.user_id) select(models.User).filter_by(id=info.context.user_id)
)).one() )).one()
print(user)
return user
@strawberry.type @strawberry.type
class EditUserMutation: class EditUserMutation:
@strawberry_sqlalchemy_input( @strawberry.input
models.User,
exclude_fields=['id', 'email', 'avatar_image_filename', 'password_hashed', 'title_image_filename'],
all_optional=True
)
class EditUserInput: class EditUserInput:
name: Optional[str] = None
description: Optional[str] = None
public_username: Optional[str] = None
old_password: Optional[str] = None old_password: Optional[str] = None
new_password: Optional[str] = None new_password: Optional[str] = None
avatar_image: Optional[Upload] = None avatar_image: Optional[Upload] = None
+8 -13
View File
@@ -63,7 +63,6 @@ async def parse_exif_info(path: str, filename: str) -> dict:
async def resize_image(path: str, filename: str, new_width: int, quality: int = 90, dest_path: str = None, dest_filename: str = None): async def resize_image(path: str, filename: str, new_width: int, quality: int = 90, dest_path: str = None, dest_filename: str = None):
print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
if not dest_path: if not dest_path:
dest_path = path dest_path = path
@@ -81,20 +80,16 @@ async def resize_image(path: str, filename: str, new_width: int, quality: int =
image.save(f"{dest_path}/{dest_filename}", 'JPEG', quality=quality) image.save(f"{dest_path}/{dest_filename}", 'JPEG', quality=quality)
except UnidentifiedImageError as e: except UnidentifiedImageError as e:
pass pass
print(e)
print("AAA^^^^^^^^^^^^AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
async def generate_thumbnail(path: str, filename: str, size: Tuple[int, int], quality: int = 90): async def generate_thumbnail(path: str, filename: str, quality: int = 90):
try: return await resize_image(
image = Image.open(f"{path}/{filename}") path, filename,
image = image.thumbnail(size, Image.LANCZOS) new_width=300,
check_directories(f"{path}/thumbs/") dest_path=f"{path}/thumbs/",
image.save(f"{path}/thumbs/{filename}", 'JPEG', quality=quality) dest_filename=filename,
quality=quality
return await resize_image(path, filename, size, dest_path=f"{path}/thumbs/", dest_filename=filename) )
except UnidentifiedImageError:
pass
def delete_file(path: str, silent: bool = False): def delete_file(path: str, silent: bool = False):