Refaktoring, bugifxy
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user