Mazani letu (zatim jen zaklad), nastaveni cover fotky

This commit is contained in:
Michal Kváček
2023-07-24 17:31:28 +02:00
parent 81d4c73a1f
commit 77dd5538d3
7 changed files with 91 additions and 34 deletions
+1
View File
@@ -99,6 +99,7 @@ class PointOfInterest(BaseModel):
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now()) created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0') deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
photos: Mapped[List[Photo]] = relationship()
type: Mapped[PointOfInterestType] = relationship() type: Mapped[PointOfInterestType] = relationship()
created_by: Mapped['User'] = relationship() created_by: Mapped['User'] = relationship()
+20 -11
View File
@@ -1,23 +1,32 @@
from collections import defaultdict from collections import defaultdict
from typing import List from typing import List, Literal
from sqlalchemy import select from sqlalchemy import select
from strawberry.dataloader import DataLoader from strawberry.dataloader import DataLoader
from database import async_session from database import async_session
from database.models import Photo from database.models import Photo
async def load_collection(ids: List[int]): class PhotoDataloader:
def __init__(self, relationship_column: Literal['flight_id', 'point_of_interest_id']) -> None:
super().__init__()
self.relationship_column = relationship_column
async def load_collection(self, ids: List[int]):
async with async_session() as session: async with async_session() as session:
models = (await session.scalars(select(Photo).filter(Photo.flight_id.in_(ids)))).all() models = (await session.scalars(
select(Photo)
.filter(getattr(Photo, self.relationship_column).in_(ids))
)).all()
photos_by_flight_id = defaultdict(list) photos_by_relationship_id = defaultdict(list)
for photo in models: for photo in models:
photos_by_flight_id[photo.flight_id].append(photo) photos_by_relationship_id[getattr(photo, self.relationship_column)].append(photo)
return [photos_by_flight_id[id_] for id_ in ids] return [photos_by_relationship_id[id_] for id_ in ids]
async def load(ids: List[int]): async def flight_cover_photo_load(ids: List[int]):
async with async_session() as session: async with async_session() as session:
models = ( models = (
await session.scalars( await session.scalars(
@@ -25,10 +34,10 @@ async def load(ids: List[int]):
.filter(Photo.is_flight_cover.is_(True)) .filter(Photo.is_flight_cover.is_(True))
.filter(Photo.flight_id.in_(ids))) .filter(Photo.flight_id.in_(ids)))
).all() ).all()
photos = {p.id: p for p in models} photos = {p.flight_id: p for p in models}
return [photos.get(id_) for id_ in ids] return [photos.get(id_) for id_ in ids]
photos_dataloader = DataLoader(load_fn=load_collection, cache=False) cover_photo_loader = DataLoader(load_fn=flight_cover_photo_load, cache=False)
photos_dataloader = DataLoader(load_fn=PhotoDataloader("flight_id").load_collection, cache=False)
cover_photo_loader = DataLoader(load_fn=load, cache=False) poi_photos_dataloader = DataLoader(load_fn=PhotoDataloader("point_of_interest_id").load_collection, cache=False)
+3 -1
View File
@@ -11,7 +11,9 @@ AIRCRAFT_UPLOAD_DEST_PATH = "/app/uploads/aircrafts/"
@strawberry_sqlalchemy_type(models.Aircraft) @strawberry_sqlalchemy_type(models.Aircraft)
class Aircraft: class Aircraft:
photo_url: Optional[str] = strawberry.field(resolver=lambda root: get_public_url(root.photo_filename)) photo_url: Optional[str] = strawberry.field(
resolver=lambda root: get_public_url(f"aircrafts/{root.photo_filename}") if root.photo_filename else None
)
def get_base_query(user_id: int): def get_base_query(user_id: int):
+18 -1
View File
@@ -88,6 +88,7 @@ def get_base_query(user_id: int):
return ( return (
select(models.Flight) select(models.Flight)
.filter(models.Flight.created_by_id == user_id) .filter(models.Flight.created_by_id == user_id)
.filter(models.Flight.deleted.is_(False))
.order_by(models.Flight.id.desc()) .order_by(models.Flight.id.desc())
) )
@@ -178,7 +179,7 @@ async def handle_copilot_edit(db: AsyncSession, copilot: CopilotInput, user_id:
@strawberry.type @strawberry.type
class EditFlightMutation: class EditFlightMutation:
@strawberry_sqlalchemy_input(models.Flight, exclude_fields=["id", "copilot_id"], all_optional=True) @strawberry_sqlalchemy_input(models.Flight, exclude_fields=["id", "copilot_id", "deleted"], all_optional=True)
class EditFlightInput: class EditFlightInput:
track: Optional[List[PointOfInterestInput]] = None track: Optional[List[PointOfInterestInput]] = None
copilot: Optional[CopilotInput] = None copilot: Optional[CopilotInput] = None
@@ -196,3 +197,19 @@ class EditFlightMutation:
flight.copilot_id = await handle_copilot_edit(info.context.db, input.copilot, info.context.user_id) flight.copilot_id = await handle_copilot_edit(info.context.db, input.copilot, info.context.user_id)
return flight return flight
@strawberry.type
class DeleteFlightMutation:
@strawberry.mutation
async def delete_flight(self, info, id: int) -> Flight:
flight = (
(await info.context.db.scalars(
get_base_query(info.context.user_id)
.filter(models.Flight.id == id))
)
.one()
)
flight.deleted = True
return flight
+15 -2
View File
@@ -1,6 +1,6 @@
from typing import List from typing import List
import strawberry import strawberry
from sqlalchemy import select 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 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
@@ -49,11 +49,13 @@ class UploadPhotoMutation:
# todo: udelat nahled do thumbs slozky # todo: udelat nahled do thumbs slozky
is_flight_cover = False # TODO: pokud k letu neexistuje zadna fotka, vybrat nahodne jednu a tu nastavit jako cover
created_photo = await models.Photo.create(data={ created_photo = 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,
"description": input.description, "description": input.description,
"is_flight_cover": is_flight_cover,
"created_by_id": info.context.user_id, "created_by_id": info.context.user_id,
}, db_session=info.context.db) }, db_session=info.context.db)
@@ -71,7 +73,18 @@ 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()
return await models.Photo.update(info.context.db, obj=photo, data=input.to_dict()) updated_model = await models.Photo.update(info.context.db, obj=photo, data=input.to_dict())
if input.is_flight_cover:
# reset other covers
(await info.context.db.execute(
update(models.Photo)
.filter(models.Photo.flight_id == photo.flight_id)
.filter(models.Photo.id != id).values(is_flight_cover=False))
)
return updated_model
@strawberry.type @strawberry.type
+26 -15
View File
@@ -1,23 +1,36 @@
from typing import List, Optional from typing import List
import strawberry import strawberry
from strawberry.file_uploads import Upload from sqlalchemy import select, or_
from sqlalchemy import select
from database import models from database import models
from graphql_schema.dataloaders.photos import poi_photos_dataloader
from graphql_schema.entities.photo import Photo
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
@strawberry_sqlalchemy_type(models.PointOfInterest) @strawberry_sqlalchemy_type(models.PointOfInterest)
class PointOfInterest: class PointOfInterest:
pass async def load_photos(root):
return await poi_photos_dataloader.load(root.id)
photos: List[Photo] = strawberry.field(resolver=load_photos)
def get_base_query(user_id: int): def get_base_query(user_id: int, only_my: bool = False):
return ( query = (
select(models.PointOfInterest) select(models.PointOfInterest)
.filter(models.PointOfInterest.created_by_id == user_id)
.filter(models.PointOfInterest.deleted.is_(False)) .filter(models.PointOfInterest.deleted.is_(False))
) )
if only_my:
query = query.filter(models.PointOfInterest.created_by_id == user_id)
else:
query = query.filter(or_(
models.PointOfInterest.created_by_id == user_id,
models.PointOfInterest.is_public.is_(True)
))
return query
@strawberry.type @strawberry.type
class PointOfInterestQueries: class PointOfInterestQueries:
@@ -48,8 +61,6 @@ class CreatePointOfInterestMutation:
@strawberry.mutation @strawberry.mutation
async def create_point_of_interest(root, info, input: CreatePointOfInterestInput) -> PointOfInterest: async def create_point_of_interest(root, info, input: CreatePointOfInterestInput) -> PointOfInterest:
# TODO: kontrola organizace
input_data = input.to_dict() input_data = input.to_dict()
return await models.PointOfInterest.create( return await models.PointOfInterest.create(
info.context.db, info.context.db,
@@ -62,16 +73,16 @@ class CreatePointOfInterestMutation:
@strawberry.type @strawberry.type
class EditPointOfInterestMutation: class EditPointOfInterestMutation:
@strawberry_sqlalchemy_input(models.PointOfInterest, exclude_fields=['photo_filename']) @strawberry_sqlalchemy_input(models.PointOfInterest, exclude_fields=['id'])
class EditPointOfInterestInput: class EditPointOfInterestInput:
photo: Optional[Upload] pass
@strawberry.mutation @strawberry.mutation
async def edit_PointOfInterest(root, info, id: int, input: EditPointOfInterestInput) -> PointOfInterest: async def edit_point_of_interest(root, info, id: int, input: EditPointOfInterestInput) -> PointOfInterest:
# TODO: kontrola organizace # TODO: kontrola organizace
# TODO: kontrola opravneni na akci # TODO: kontrola opravneni na akci
poi = await models.PointOfInterest.get_one(info.context.db, id) poi = (await get_base_query(info.context.user_id, only_my=True).filter(models.Photo.id == id)).one()
return await models.PointOfInterest.update(info.context.db, obj=poi, data=input.to_dict()) return await models.PointOfInterest.update(info.context.db, obj=poi, data=input.to_dict())
@@ -80,6 +91,6 @@ class DeletePointOfInterestMutation:
@strawberry.mutation @strawberry.mutation
async def delete_point_of_interest(self, info, id: int) -> PointOfInterest: async def delete_point_of_interest(self, info, id: int) -> PointOfInterest:
# TODO: kontrola opravneni na akci poi = (await get_base_query(info.context.user_id, only_my=True).filter(models.Photo.id == id)).one()
return await models.PointOfInterest.update(info.context.db, id=id, data=dict(deleted=True)) return await models.PointOfInterest.update(info.context.db, obj=poi, data=dict(deleted=True))
+6 -2
View File
@@ -1,15 +1,19 @@
from strawberry.tools import merge_types from strawberry.tools import merge_types
from graphql_schema.entities.aircraft import CreateAircraftMutation, EditAircraftMutation, DeleteAircraftMutation from graphql_schema.entities.aircraft import CreateAircraftMutation, EditAircraftMutation, DeleteAircraftMutation
from graphql_schema.entities.flight import CreateFlightMutation, EditFlightMutation from graphql_schema.entities.flight import CreateFlightMutation, EditFlightMutation, DeleteFlightMutation
from graphql_schema.entities.photo import UploadPhotoMutation, DeletePhotoMutation, EditPhotoMutation from graphql_schema.entities.photo import UploadPhotoMutation, DeletePhotoMutation, EditPhotoMutation
from graphql_schema.entities.poi import CreatePointOfInterestMutation, EditPointOfInterestMutation
Mutation = merge_types("Mutation", ( Mutation = merge_types("Mutation", (
CreateAircraftMutation, CreateAircraftMutation,
EditAircraftMutation, EditAircraftMutation,
DeleteAircraftMutation, DeleteAircraftMutation,
EditFlightMutation, EditFlightMutation,
DeleteFlightMutation,
CreateFlightMutation, CreateFlightMutation,
UploadPhotoMutation, UploadPhotoMutation,
EditPhotoMutation, EditPhotoMutation,
DeletePhotoMutation DeletePhotoMutation,
CreatePointOfInterestMutation,
EditPointOfInterestMutation,
)) ))