Error logging, uprava dotazovani na seznam letu u kopilota

This commit is contained in:
Michal Kváček
2023-11-07 17:45:26 +01:00
parent e3ab6ba7f0
commit bd5b84c9e7
17 changed files with 88 additions and 136 deletions
-1
View File
@@ -7,7 +7,6 @@ from logger import log
async def download_weather(date_time: datetime, flight_id: int, airport_id: int, type_: Literal['landing', 'takeoff']): async def download_weather(date_time: datetime, flight_id: int, airport_id: int, type_: Literal['landing', 'takeoff']):
log.error("AAAAAAAAAAAAAAAAAAAAAAAAAAA")
async with get_session() as db: async with get_session() as db:
airport = await models.Airport.get_one(db, airport_id) airport = await models.Airport.get_one(db, airport_id)
gps = (airport.gps_latitude, airport.gps_longitude) gps = (airport.gps_latitude, airport.gps_longitude)
+4
View File
@@ -1,4 +1,5 @@
from functools import wraps from functools import wraps
from fastapi import HTTPException
from graphql import GraphQLError from graphql import GraphQLError
from sqlalchemy.exc import NoResultFound from sqlalchemy.exc import NoResultFound
@@ -10,5 +11,8 @@ def error_logging(func):
return await func(*args, **kwargs) return await func(*args, **kwargs)
except NoResultFound as e: except NoResultFound as e:
raise GraphQLError("Not found", original_error=e) raise GraphQLError("Not found", original_error=e)
except HTTPException as e:
if e.status_code == 401:
raise GraphQLError("Not authorized", original_error=e)
return decorator return decorator
@@ -29,6 +29,17 @@ flights_by_copilot_dataloader = DataLoader(
cache=False cache=False
) )
public_flights_by_copilot_dataloader = DataLoader(
load_fn=MultiModelsDataloader(
models.Flight,
relationship_column=models.Copilot.id,
extra_join=[models.Flight.copilots],
filters=[models.Flight.is_public.is_(True)],
order_by=[models.Flight.takeoff_datetime.desc()]
).load,
cache=False
)
flights_by_aircraft_dataloader = DataLoader( flights_by_aircraft_dataloader = DataLoader(
load_fn=MultiModelsDataloader( load_fn=MultiModelsDataloader(
models.Flight, models.Flight,
+5
View File
@@ -1,6 +1,7 @@
from typing import List from typing import List
import strawberry import strawberry
from decorators.endpoints import authenticated_user_only from decorators.endpoints import authenticated_user_only
from decorators.error_logging import error_logging
from .resolvers.aircraft import AircraftMutationResolver, AircraftQueryResolver from .resolvers.aircraft import AircraftMutationResolver, AircraftQueryResolver
from graphql_schema.entities.types.mutation_input import CreateAircraftInput, EditAircraftInput from graphql_schema.entities.types.mutation_input import CreateAircraftInput, EditAircraftInput
from graphql_schema.entities.types.types import Aircraft from graphql_schema.entities.types.types import Aircraft
@@ -9,6 +10,7 @@ from graphql_schema.entities.types.types import Aircraft
@strawberry.type @strawberry.type
class AircraftQueries: class AircraftQueries:
@strawberry.field() @strawberry.field()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def aircrafts(root, info) -> List[Aircraft]: async def aircrafts(root, info) -> List[Aircraft]:
return await AircraftQueryResolver().get_list( return await AircraftQueryResolver().get_list(
@@ -17,6 +19,7 @@ class AircraftQueries:
) )
@strawberry.field() @strawberry.field()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def aircraft(root, info, id: int) -> Aircraft: async def aircraft(root, info, id: int) -> Aircraft:
return await AircraftQueryResolver().get_one( return await AircraftQueryResolver().get_one(
@@ -27,11 +30,13 @@ class AircraftQueries:
@strawberry.type @strawberry.type
class AircraftMutation: class AircraftMutation:
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def create_aircraft(root, info, input: CreateAircraftInput) -> Aircraft: async def create_aircraft(root, info, input: CreateAircraftInput) -> Aircraft:
return await AircraftMutationResolver().create_new(input, info.context.user_id) return await AircraftMutationResolver().create_new(input, info.context.user_id)
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def edit_aircraft(root, info, id: int, input: EditAircraftInput) -> Aircraft: async def edit_aircraft(root, info, id: int, input: EditAircraftInput) -> Aircraft:
return await AircraftMutationResolver().edit(id, user_id=info.context.user_id, data=input) return await AircraftMutationResolver().edit(id, user_id=info.context.user_id, data=input)
+3
View File
@@ -1,6 +1,7 @@
from typing import List from typing import List
import strawberry import strawberry
from database import models from database import models
from decorators.error_logging import error_logging
from decorators.endpoints import authenticated_user_only from decorators.endpoints import authenticated_user_only
from graphql_schema.entities.resolvers.base import BaseQueryResolver from graphql_schema.entities.resolvers.base import BaseQueryResolver
from graphql_schema.entities.types.types import Airport from graphql_schema.entities.types.types import Airport
@@ -9,11 +10,13 @@ from graphql_schema.entities.types.types import Airport
@strawberry.type @strawberry.type
class AirportQueries: class AirportQueries:
@strawberry.field() @strawberry.field()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def airports(root, info) -> List[Airport]: async def airports(root, info) -> List[Airport]:
return await BaseQueryResolver(Airport, models.Airport).get_list(info.context.user_id) return await BaseQueryResolver(Airport, models.Airport).get_list(info.context.user_id)
@strawberry.field() @strawberry.field()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def airport(root, info, id: int) -> Airport: async def airport(root, info, id: int) -> Airport:
return await BaseQueryResolver(Airport, models.Airport).get_one(id, user_id=info.context.user_id) return await BaseQueryResolver(Airport, models.Airport).get_one(id, user_id=info.context.user_id)
+8 -3
View File
@@ -2,8 +2,9 @@ from typing import List, Optional
import strawberry import strawberry
from fastapi import HTTPException from fastapi import HTTPException
from starlette.status import HTTP_401_UNAUTHORIZED from starlette.status import HTTP_401_UNAUTHORIZED
from strawberry.types import Info
from database import models from database import models
from decorators.error_logging import error_logging
from decorators.endpoints import authenticated_user_only from decorators.endpoints import authenticated_user_only
from graphql_schema.entities.resolvers.base import BaseMutationResolver from graphql_schema.entities.resolvers.base import BaseMutationResolver
from graphql_schema.entities.resolvers.copilot import CopilotQueryResolver from graphql_schema.entities.resolvers.copilot import CopilotQueryResolver
@@ -14,12 +15,14 @@ from graphql_schema.entities.types.types import Copilot
@strawberry.type @strawberry.type
class CopilotQueries: class CopilotQueries:
@strawberry.field() @strawberry.field()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def copilots(root, info) -> List[Copilot]: async def copilots(root, info: Info) -> List[Copilot]:
return await CopilotQueryResolver().get_list(info.context.user_id) return await CopilotQueryResolver().get_list(info.context.user_id)
@strawberry.field() @strawberry.field()
async def copilot(root, info, id: int, pilot_username: Optional[str] = None) -> Copilot: @error_logging
async def copilot(root, info: Info, id: int, pilot_username: Optional[str] = None) -> Copilot:
if not info.context.user_id and not pilot_username: if not info.context.user_id and not pilot_username:
raise HTTPException(HTTP_401_UNAUTHORIZED) raise HTTPException(HTTP_401_UNAUTHORIZED)
@@ -33,6 +36,7 @@ class CopilotQueries:
@strawberry.type @strawberry.type
class CopilotMutation: class CopilotMutation:
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def create_copilot(root, info, input: CreateCopilotInput) -> Copilot: async def create_copilot(root, info, input: CreateCopilotInput) -> Copilot:
return await BaseMutationResolver(Copilot, models.Copilot).create( return await BaseMutationResolver(Copilot, models.Copilot).create(
@@ -41,6 +45,7 @@ class CopilotMutation:
) )
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def edit_copilot(root, info, id: int, input: EditCopilotInput) -> Copilot: async def edit_copilot(root, info, id: int, input: EditCopilotInput) -> Copilot:
return await BaseMutationResolver(Copilot, models.Copilot).update(id, input, info.context.user_id) return await BaseMutationResolver(Copilot, models.Copilot).update(id, input, info.context.user_id)
+5
View File
@@ -4,6 +4,7 @@ from fastapi import HTTPException
from starlette.status import HTTP_401_UNAUTHORIZED from starlette.status import HTTP_401_UNAUTHORIZED
from database import models from database import models
from decorators.endpoints import authenticated_user_only from decorators.endpoints import authenticated_user_only
from decorators.error_logging import error_logging
from graphql_schema.entities.resolvers.base import BaseMutationResolver from graphql_schema.entities.resolvers.base import BaseMutationResolver
from graphql_schema.entities.resolvers.event import EventQueryResolver from graphql_schema.entities.resolvers.event import EventQueryResolver
from graphql_schema.entities.types.mutation_input import CreateEventInput, EditEventInput from graphql_schema.entities.types.mutation_input import CreateEventInput, EditEventInput
@@ -13,6 +14,7 @@ from graphql_schema.entities.types.types import Event
@strawberry.type @strawberry.type
class EventQueries: class EventQueries:
@strawberry.field() @strawberry.field()
@error_logging
async def events(root, info, username: Optional[str] = None) -> List[Event]: async def events(root, info, username: Optional[str] = None) -> List[Event]:
if not info.context.user_id and not username: if not info.context.user_id and not username:
raise HTTPException(HTTP_401_UNAUTHORIZED) raise HTTPException(HTTP_401_UNAUTHORIZED)
@@ -24,6 +26,7 @@ class EventQueries:
) )
@strawberry.field() @strawberry.field()
@error_logging
async def event(root, info, id: int, username: Optional[str] = None) -> Event: async def event(root, info, id: int, username: Optional[str] = None) -> Event:
if not info.context.user_id and not username: if not info.context.user_id and not username:
raise HTTPException(HTTP_401_UNAUTHORIZED) raise HTTPException(HTTP_401_UNAUTHORIZED)
@@ -38,11 +41,13 @@ class EventQueries:
@strawberry.type @strawberry.type
class EventMutation: class EventMutation:
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def create_event(root, info, input: CreateEventInput) -> Event: async def create_event(root, info, input: CreateEventInput) -> Event:
return await BaseMutationResolver(Event, models.Event).create(input.to_dict(), info.context.user_id) return await BaseMutationResolver(Event, models.Event).create(input.to_dict(), info.context.user_id)
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def edit_event(root, info, id: int, input: EditEventInput) -> Event: async def edit_event(root, info, id: int, input: EditEventInput) -> Event:
return await BaseMutationResolver(Event, models.Event).update(id, input, info.context.user_id) return await BaseMutationResolver(Event, models.Event).update(id, input, info.context.user_id)
+4
View File
@@ -18,6 +18,7 @@ from graphql_schema.entities.types.types import Flight
class FlightQueries: class FlightQueries:
@strawberry.field() @strawberry.field()
@error_logging
async def flights(root, info, username: Optional[str] = None) -> List[Flight]: async def flights(root, info, username: Optional[str] = None) -> List[Flight]:
if not info.context.user_id and not username: if not info.context.user_id and not username:
raise HTTPException(HTTP_401_UNAUTHORIZED) raise HTTPException(HTTP_401_UNAUTHORIZED)
@@ -36,6 +37,7 @@ class FlightQueries:
@strawberry.type @strawberry.type
class FlightMutation: class FlightMutation:
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def create_flight(self, info, input: CreateFlightInput) -> Flight: async def create_flight(self, info, input: CreateFlightInput) -> Flight:
data = input.to_dict() data = input.to_dict()
@@ -77,11 +79,13 @@ class FlightMutation:
return flight return flight
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def edit_flight(self, info, id: int, input: EditFlightInput) -> Flight: async def edit_flight(self, info, id: int, input: EditFlightInput) -> Flight:
return await FlightMutationResolver().update(info.context, id, input) return await FlightMutationResolver().update(info.context, id, input)
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def delete_flight(self, info, id: int) -> Flight: async def delete_flight(self, info, id: int) -> Flight:
return await FlightMutationResolver().delete(info.context.user_id, id) return await FlightMutationResolver().delete(info.context.user_id, id)
@@ -6,6 +6,7 @@ from sqlalchemy.exc import IntegrityError
from database import models from database import models
from decorators.endpoints import authenticated_user_only from decorators.endpoints import authenticated_user_only
from database.transaction import get_session from database.transaction import get_session
from decorators.error_logging import error_logging
from graphql_schema.entities.resolvers.base import BaseQueryResolver, BaseMutationResolver from graphql_schema.entities.resolvers.base import BaseQueryResolver, BaseMutationResolver
from graphql_schema.entities.types.mutation_input import CreateOrganizationInput, EditOrganizationInput from graphql_schema.entities.types.mutation_input import CreateOrganizationInput, EditOrganizationInput
from graphql_schema.entities.types.types import Organization from graphql_schema.entities.types.types import Organization
@@ -14,6 +15,7 @@ from graphql_schema.entities.types.types import Organization
@strawberry.type @strawberry.type
class OrganizationQueries: class OrganizationQueries:
@strawberry.field() @strawberry.field()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def organizations(root, info) -> List[Organization]: async def organizations(root, info) -> List[Organization]:
return await BaseQueryResolver(Organization, models.Organization).get_list( return await BaseQueryResolver(Organization, models.Organization).get_list(
@@ -21,6 +23,7 @@ class OrganizationQueries:
) )
@strawberry.field() @strawberry.field()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def organization(root, info, id: int) -> Organization: async def organization(root, info, id: int) -> Organization:
return await BaseQueryResolver(Organization, models.Organization).get_one(id, info.context.user_id) return await BaseQueryResolver(Organization, models.Organization).get_one(id, info.context.user_id)
@@ -30,6 +33,7 @@ class OrganizationQueries:
class OrganizationMutation: class OrganizationMutation:
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def create_organization(root, info, input: CreateOrganizationInput) -> Organization: async def create_organization(root, info, input: CreateOrganizationInput) -> Organization:
return await BaseMutationResolver(Organization, models.Organization).create( return await BaseMutationResolver(Organization, models.Organization).create(
@@ -38,6 +42,7 @@ class OrganizationMutation:
) )
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def edit_organization(root, info, id: int, input: EditOrganizationInput) -> Organization: async def edit_organization(root, info, id: int, input: EditOrganizationInput) -> Organization:
async with get_session() as db: async with get_session() as db:
@@ -55,6 +60,7 @@ class OrganizationMutation:
class OrganizationUserMutation: class OrganizationUserMutation:
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def add_to_organization(root, info, organization_id: int) -> Organization: async def add_to_organization(root, info, organization_id: int) -> Organization:
async with get_session() as db: async with get_session() as db:
@@ -75,6 +81,7 @@ class OrganizationUserMutation:
return Organization(**organization.as_dict()) return Organization(**organization.as_dict())
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def remove_from_organization(root, info, organization_id: int) -> Organization: async def remove_from_organization(root, info, organization_id: int) -> Organization:
async with get_session() as db: async with get_session() as db:
+8
View File
@@ -2,6 +2,7 @@ from typing import List
import strawberry import strawberry
from database import models from database import models
from decorators.endpoints import authenticated_user_only from decorators.endpoints import authenticated_user_only
from decorators.error_logging import error_logging
from graphql_schema.entities.resolvers.base import BaseQueryResolver from graphql_schema.entities.resolvers.base import BaseQueryResolver
from graphql_schema.entities.resolvers.photo import PhotoMutationResolver from graphql_schema.entities.resolvers.photo import PhotoMutationResolver
from graphql_schema.entities.types.types import Photo from graphql_schema.entities.types.types import Photo
@@ -11,10 +12,12 @@ from graphql_schema.entities.types.mutation_input import EditPhotoInput, UploadP
@strawberry.type @strawberry.type
class PhotoQueries: class PhotoQueries:
@strawberry.field() @strawberry.field()
@error_logging
async def photos(root, info) -> List[Photo]: async def photos(root, info) -> List[Photo]:
return await BaseQueryResolver(Photo, models.Photo).get_list(user_id=info.context.user_id) return await BaseQueryResolver(Photo, models.Photo).get_list(user_id=info.context.user_id)
@strawberry.field() @strawberry.field()
@error_logging
async def photo(root, info, id: int) -> Photo: async def photo(root, info, id: int) -> Photo:
return await BaseQueryResolver(Photo, models.Photo).get_one(id, user_id=info.context.user_id) return await BaseQueryResolver(Photo, models.Photo).get_one(id, user_id=info.context.user_id)
@@ -22,16 +25,19 @@ class PhotoQueries:
@strawberry.type @strawberry.type
class PhotoMutation: class PhotoMutation:
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def upload_photo(self, info, input: UploadPhotoInput) -> Photo: async def upload_photo(self, info, input: UploadPhotoInput) -> Photo:
return await PhotoMutationResolver().upload(info, input) return await PhotoMutationResolver().upload(info, input)
@strawberry.mutation() @strawberry.mutation()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def edit_photo(self, info, id: int, input: EditPhotoInput) -> Photo: async def edit_photo(self, info, id: int, input: EditPhotoInput) -> Photo:
return await PhotoMutationResolver().update(id, input, info.context.user_id) return await PhotoMutationResolver().update(id, input, info.context.user_id)
@strawberry.mutation() @strawberry.mutation()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def change_orientation(self, info, id: int, direction: str) -> Photo: async def change_orientation(self, info, id: int, direction: str) -> Photo:
return await PhotoMutationResolver().change_orientation( return await PhotoMutationResolver().change_orientation(
@@ -42,11 +48,13 @@ class PhotoMutation:
) )
@strawberry.mutation() @strawberry.mutation()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def adjust_photo(self, info, id: int, adjustment: AdjustmentInput) -> Photo: async def adjust_photo(self, info, id: int, adjustment: AdjustmentInput) -> Photo:
return await PhotoMutationResolver().adjust(id, info=info, user_id=info.context.user_id, adjustment=adjustment) return await PhotoMutationResolver().adjust(id, info=info, user_id=info.context.user_id, adjustment=adjustment)
@strawberry.mutation() @strawberry.mutation()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def delete_photo(self, info, id: int) -> Photo: async def delete_photo(self, info, id: int) -> Photo:
return await PhotoMutationResolver().delete(user_id=info.context.user_id, id=id) return await PhotoMutationResolver().delete(user_id=info.context.user_id, id=id)
+5
View File
@@ -3,6 +3,7 @@ import strawberry
from database import models from database import models
from decorators.endpoints import authenticated_user_only from decorators.endpoints import authenticated_user_only
from database.transaction import get_session from database.transaction import get_session
from decorators.error_logging import error_logging
from graphql_schema.entities.helpers.combobox import handle_combobox_save from graphql_schema.entities.helpers.combobox import handle_combobox_save
from graphql_schema.entities.resolvers.base import BaseQueryResolver, BaseMutationResolver from graphql_schema.entities.resolvers.base import BaseQueryResolver, BaseMutationResolver
from graphql_schema.entities.types.types import PointOfInterest from graphql_schema.entities.types.types import PointOfInterest
@@ -12,6 +13,7 @@ from graphql_schema.entities.types.mutation_input import CreatePointOfInterestIn
@strawberry.type @strawberry.type
class PointOfInterestQueries: class PointOfInterestQueries:
@strawberry.field() @strawberry.field()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def points_of_interest(root, info) -> List[PointOfInterest]: async def points_of_interest(root, info) -> List[PointOfInterest]:
return await BaseQueryResolver(PointOfInterest, models.PointOfInterest).get_list(info.context.user_id) return await BaseQueryResolver(PointOfInterest, models.PointOfInterest).get_list(info.context.user_id)
@@ -25,6 +27,7 @@ class PointOfInterestQueries:
@strawberry.type @strawberry.type
class PointOfInterestMutation: class PointOfInterestMutation:
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
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()
@@ -40,6 +43,7 @@ class PointOfInterestMutation:
) )
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def edit_point_of_interest(root, info, id: int, input: EditPointOfInterestInput) -> PointOfInterest: async def edit_point_of_interest(root, info, id: int, input: EditPointOfInterestInput) -> PointOfInterest:
input_data = input.to_dict() input_data = input.to_dict()
@@ -59,6 +63,7 @@ class PointOfInterestMutation:
return PointOfInterest(**updated_poi.as_dict()) return PointOfInterest(**updated_poi.as_dict())
@strawberry.mutation @strawberry.mutation
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def delete_point_of_interest(self, info, id: int) -> PointOfInterest: async def delete_point_of_interest(self, info, id: int) -> PointOfInterest:
return await BaseMutationResolver(PointOfInterest, models.PointOfInterest).delete(info.context.user_id, id=id) return await BaseMutationResolver(PointOfInterest, models.PointOfInterest).delete(info.context.user_id, id=id)
+3
View File
@@ -2,6 +2,7 @@ from typing import List
import strawberry import strawberry
from database import models from database import models
from decorators.endpoints import authenticated_user_only from decorators.endpoints import authenticated_user_only
from decorators.error_logging import error_logging
from graphql_schema.entities.resolvers.base import BaseQueryResolver from graphql_schema.entities.resolvers.base import BaseQueryResolver
from graphql_schema.entities.types.types import PointOfInterestType from graphql_schema.entities.types.types import PointOfInterestType
@@ -10,11 +11,13 @@ from graphql_schema.entities.types.types import PointOfInterestType
class PointOfInterestTypeQueries: class PointOfInterestTypeQueries:
@strawberry.field() @strawberry.field()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def point_of_interest_types(root, info) -> List[PointOfInterestType]: async def point_of_interest_types(root, info) -> List[PointOfInterestType]:
return await BaseQueryResolver(PointOfInterestType, models.PointOfInterestType).get_list(info.context.user_id) return await BaseQueryResolver(PointOfInterestType, models.PointOfInterestType).get_list(info.context.user_id)
@strawberry.field() @strawberry.field()
@error_logging
@authenticated_user_only() @authenticated_user_only()
async def point_of_interest_type(root, info, id: int) -> PointOfInterestType: async def point_of_interest_type(root, info, id: int) -> PointOfInterestType:
return await BaseQueryResolver(PointOfInterestType, models.PointOfInterestType).get_one( return await BaseQueryResolver(PointOfInterestType, models.PointOfInterestType).get_one(
+9 -2
View File
@@ -10,7 +10,7 @@ from graphql_schema.dataloaders.multi_models import (
poi_photos_dataloader, flight_by_poi_dataloader, flight_copilots_dataloader, flight_track_dataloader, poi_photos_dataloader, flight_by_poi_dataloader, flight_copilots_dataloader, flight_track_dataloader,
photos_dataloader, flights_by_aircraft_dataloader, users_in_organization_dataloader, photos_dataloader, flights_by_aircraft_dataloader, users_in_organization_dataloader,
aircrafts_from_organization_dataloader, user_organizations_dataloader, flights_by_event_dataloader, aircrafts_from_organization_dataloader, user_organizations_dataloader, flights_by_event_dataloader,
flights_by_copilot_dataloader, public_flights_by_event_dataloader flights_by_copilot_dataloader, public_flights_by_event_dataloader, public_flights_by_copilot_dataloader
) )
from graphql_schema.dataloaders.single_model import ( from graphql_schema.dataloaders.single_model import (
poi_dataloader, poi_type_dataloader, event_dataloader, aircraft_dataloader, airport_dataloader, cover_photo_loader, poi_dataloader, poi_type_dataloader, event_dataloader, aircraft_dataloader, airport_dataloader, cover_photo_loader,
@@ -145,7 +145,14 @@ class Flight:
@strawberry_sqlalchemy_type(models.Copilot) @strawberry_sqlalchemy_type(models.Copilot)
class Copilot: class Copilot:
flights: List[Flight] = strawberry.field(resolver=lambda root: flights_by_copilot_dataloader.load(root.id)) async def resolve_flights(root, info):
dataloader = public_flights_by_copilot_dataloader
if info.context.user_id:
dataloader = flights_by_event_dataloader
return await dataloader.load(root.id)
flights: List[Flight] = strawberry.field(resolver=resolve_flights)
@strawberry_sqlalchemy_type(models.Aircraft) @strawberry_sqlalchemy_type(models.Aircraft)
+3 -3
View File
@@ -4,13 +4,13 @@ from graphql import GraphQLError
from passlib.hash import bcrypt from passlib.hash import bcrypt
from sqlalchemy import select from sqlalchemy import select
from strawberry.file_uploads import Upload from strawberry.file_uploads import Upload
from background_jobs.photo import resize_photo
from database import models from database import models
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 database.transaction import get_session from database.transaction import get_session
from graphql_schema.entities.types.types import User from graphql_schema.entities.types.types import User
from utils.file import delete_file from utils.file import delete_file
from utils.image import resize_image
from utils.upload import handle_file_upload from utils.upload import handle_file_upload
@@ -72,7 +72,7 @@ class EditUserMutation:
data['avatar_image_filename'] = await handle_file_upload(input.avatar_image, user_image_path) data['avatar_image_filename'] = await handle_file_upload(input.avatar_image, user_image_path)
info.context.background_tasks.add_task( info.context.background_tasks.add_task(
resize_image, path=user_image_path, filename=data['avatar_image_filename'], new_width=400 resize_photo, path=user_image_path, filename=data['avatar_image_filename'], new_width=400
) )
if input.title_image: if input.title_image:
@@ -81,7 +81,7 @@ class EditUserMutation:
data['title_image_filename'] = await handle_file_upload(input.title_image, user_image_path) data['title_image_filename'] = await handle_file_upload(input.title_image, user_image_path)
info.context.background_tasks.add_task( info.context.background_tasks.add_task(
resize_image, path=user_image_path, filename=data['title_image_filename'], new_width=800 resize_photo, path=user_image_path, filename=data['title_image_filename'], new_width=800
) )
if input.old_password and input.new_password: if input.old_password and input.new_password:
+6 -1
View File
@@ -3,6 +3,7 @@ from datetime import timedelta
from typing import Optional from typing import Optional
from fastapi import FastAPI, APIRouter, Depends, Security from fastapi import FastAPI, APIRouter, Depends, Security
from fastapi_jwt import JwtAuthorizationCredentials, JwtAccessBearerCookie, JwtRefreshBearerCookie from fastapi_jwt import JwtAuthorizationCredentials, JwtAccessBearerCookie, JwtRefreshBearerCookie
from graphql import GraphQLError
from sqlalchemy import select from sqlalchemy import select
from starlette.background import BackgroundTasks from starlette.background import BackgroundTasks
from starlette.middleware.cors import CORSMiddleware from starlette.middleware.cors import CORSMiddleware
@@ -35,7 +36,11 @@ class App:
def create_app(self): def create_app(self):
if SENTRY_DSN: if SENTRY_DSN:
sentry_sdk.init(dsn=SENTRY_DSN, enable_tracing=True) sentry_sdk.init(
dsn=SENTRY_DSN,
enable_tracing=True,
ignore_errors = [GraphQLError]
)
app = FastAPI() app = FastAPI()
+4 -2
View File
@@ -10,5 +10,7 @@ def delete_file(path: str, silent: bool = False):
def check_directories(path: str): def check_directories(path: str):
if not os.path.isdir(path): try:
os.makedirs(path) os.makedirs(path, exist_ok=True)
except OSError:
pass
+3 -124
View File
@@ -1,10 +1,9 @@
import io import io
import math import math
from datetime import datetime from datetime import datetime
from typing import Optional, Tuple from typing import Optional, Tuple
import exif import exif
from PIL import Image, UnidentifiedImageError from PIL import Image
from PIL.ImageEnhance import Brightness, Contrast, Color, Sharpness from PIL.ImageEnhance import Brightness, Contrast, Color, Sharpness
from utils.file import check_directories from utils.file import check_directories
from utils.gps import gps_to_decimal from utils.gps import gps_to_decimal
@@ -130,129 +129,9 @@ class PhotoEditor:
def write_to_file( def write_to_file(
self, quality: int = 90, dest_path: Optional[str] = None, dest_filename: Optional[str] = None self, quality: int = 90, dest_path: Optional[str] = None, dest_filename: Optional[str] = None
) -> str: ) -> str:
check_directories(dest_path or self.path)
dest = f"{dest_path or self.path}/{dest_filename or self.filename}" dest = f"{dest_path or self.path}/{dest_filename or self.filename}"
check_directories(dest)
self.img.save(dest, 'JPEG', quality=quality) self.img.save(dest, 'JPEG', quality=quality)
return dest return dest
# -----------
# odsud niz to bude vse asi na smazani, vse by mela umet trida PhotoEditor
async def resize_image(
path: str, filename: str, new_width: int, quality: int = 90,
dest_path: Optional[str] = None,
dest_filename: Optional[str] = None
):
if not dest_path:
dest_path = path
if not dest_filename:
dest_filename = filename
try:
image = Image.open(f"{path}/{filename}")
width, height = image.size
new_height = int(new_width * height / width)
image = image.resize((new_width, new_height), Image.LANCZOS)
check_directories(dest_path)
image.save(f"{dest_path}/{dest_filename}", 'JPEG', quality=quality)
return new_width, new_height
except UnidentifiedImageError:
pass
def crop_image_after_rotate(
original_width: int, original_height: int, rotated_width: int, rotated_height: int, degrees: float
) -> Tuple[int, int]:
aspect_ratio = float(original_width) / original_height
rotated_aspect_ratio = float(rotated_width) / rotated_height
angle = math.fabs(degrees) * math.pi / 180
if aspect_ratio < 1:
total_height = float(original_width) / rotated_aspect_ratio
else:
total_height = float(original_height)
h = total_height / (aspect_ratio * math.sin(angle) + math.cos(angle))
w = h * aspect_ratio
return round(w), round(h)
async def rotate_image_no_crop(
path: str,
filename: str,
angle: float,
dest_path: Optional[str] = None,
dest_filename: Optional[str] = None
):
if not dest_path:
dest_path = path
if not dest_filename:
dest_filename = filename
img = Image.open(f"{path}/{filename}")
rotated_img = img.rotate(angle, Image.BICUBIC, expand=True)
check_directories(dest_path)
rotated_img.save(f"{dest_path}/{dest_filename}", 'JPEG', quality=100)
async def adjust_image(
path: str,
filename: str,
rotate: float,
brightness: float,
contrast: float,
saturation: float,
sharpness: float,
crop: dict,
dest_path: Optional[str] = None,
dest_filename: Optional[str] = None
):
if not dest_path:
dest_path = path
if not dest_filename:
dest_filename = filename
img = Image.open(f"{path}/{filename}")
if rotate:
rotated_img = img.rotate(rotate, Image.BICUBIC, expand=True)
width, height = img.size
rotated_width, rotated_height = rotated_img.size
new_width, new_height = crop_image_after_rotate(width, height, rotated_width, rotated_height, rotate)
left = round((rotated_width - new_width) / 2)
top = round((rotated_height - new_height) / 2)
img = rotated_img.crop((left, top, left + new_width, top + new_height))
adjustments = [
(Brightness, brightness),
(Contrast, contrast),
(Color, saturation),
(Sharpness, sharpness)
]
for adj, value in adjustments:
img = adj(img).enhance(value)
if crop:
w, h = img.size
left = crop['left'] * w
top = crop['top'] * h
width = crop['width'] * w
height = crop['height'] * h
img = img.crop((left, top, left + width, top + height))
img.save(f"{dest_path}/{dest_filename}", 'JPEG', quality=100)