Error logging, uprava dotazovani na seznam letu u kopilota
This commit is contained in:
@@ -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']):
|
||||
log.error("AAAAAAAAAAAAAAAAAAAAAAAAAAA")
|
||||
async with get_session() as db:
|
||||
airport = await models.Airport.get_one(db, airport_id)
|
||||
gps = (airport.gps_latitude, airport.gps_longitude)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from functools import wraps
|
||||
from fastapi import HTTPException
|
||||
from graphql import GraphQLError
|
||||
from sqlalchemy.exc import NoResultFound
|
||||
|
||||
@@ -10,5 +11,8 @@ def error_logging(func):
|
||||
return await func(*args, **kwargs)
|
||||
except NoResultFound as 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
|
||||
|
||||
@@ -29,6 +29,17 @@ flights_by_copilot_dataloader = DataLoader(
|
||||
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(
|
||||
load_fn=MultiModelsDataloader(
|
||||
models.Flight,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from typing import List
|
||||
import strawberry
|
||||
from decorators.endpoints import authenticated_user_only
|
||||
from decorators.error_logging import error_logging
|
||||
from .resolvers.aircraft import AircraftMutationResolver, AircraftQueryResolver
|
||||
from graphql_schema.entities.types.mutation_input import CreateAircraftInput, EditAircraftInput
|
||||
from graphql_schema.entities.types.types import Aircraft
|
||||
@@ -9,6 +10,7 @@ from graphql_schema.entities.types.types import Aircraft
|
||||
@strawberry.type
|
||||
class AircraftQueries:
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def aircrafts(root, info) -> List[Aircraft]:
|
||||
return await AircraftQueryResolver().get_list(
|
||||
@@ -17,6 +19,7 @@ class AircraftQueries:
|
||||
)
|
||||
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def aircraft(root, info, id: int) -> Aircraft:
|
||||
return await AircraftQueryResolver().get_one(
|
||||
@@ -27,11 +30,13 @@ class AircraftQueries:
|
||||
@strawberry.type
|
||||
class AircraftMutation:
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def create_aircraft(root, info, input: CreateAircraftInput) -> Aircraft:
|
||||
return await AircraftMutationResolver().create_new(input, info.context.user_id)
|
||||
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def edit_aircraft(root, info, id: int, input: EditAircraftInput) -> Aircraft:
|
||||
return await AircraftMutationResolver().edit(id, user_id=info.context.user_id, data=input)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from typing import List
|
||||
import strawberry
|
||||
from database import models
|
||||
from decorators.error_logging import error_logging
|
||||
from decorators.endpoints import authenticated_user_only
|
||||
from graphql_schema.entities.resolvers.base import BaseQueryResolver
|
||||
from graphql_schema.entities.types.types import Airport
|
||||
@@ -9,11 +10,13 @@ from graphql_schema.entities.types.types import Airport
|
||||
@strawberry.type
|
||||
class AirportQueries:
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def airports(root, info) -> List[Airport]:
|
||||
return await BaseQueryResolver(Airport, models.Airport).get_list(info.context.user_id)
|
||||
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def airport(root, info, id: int) -> Airport:
|
||||
return await BaseQueryResolver(Airport, models.Airport).get_one(id, user_id=info.context.user_id)
|
||||
|
||||
@@ -2,8 +2,9 @@ from typing import List, Optional
|
||||
import strawberry
|
||||
from fastapi import HTTPException
|
||||
from starlette.status import HTTP_401_UNAUTHORIZED
|
||||
|
||||
from strawberry.types import Info
|
||||
from database import models
|
||||
from decorators.error_logging import error_logging
|
||||
from decorators.endpoints import authenticated_user_only
|
||||
from graphql_schema.entities.resolvers.base import BaseMutationResolver
|
||||
from graphql_schema.entities.resolvers.copilot import CopilotQueryResolver
|
||||
@@ -14,12 +15,14 @@ from graphql_schema.entities.types.types import Copilot
|
||||
@strawberry.type
|
||||
class CopilotQueries:
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
@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)
|
||||
|
||||
@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:
|
||||
raise HTTPException(HTTP_401_UNAUTHORIZED)
|
||||
|
||||
@@ -33,6 +36,7 @@ class CopilotQueries:
|
||||
@strawberry.type
|
||||
class CopilotMutation:
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def create_copilot(root, info, input: CreateCopilotInput) -> Copilot:
|
||||
return await BaseMutationResolver(Copilot, models.Copilot).create(
|
||||
@@ -41,6 +45,7 @@ class CopilotMutation:
|
||||
)
|
||||
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def edit_copilot(root, info, id: int, input: EditCopilotInput) -> Copilot:
|
||||
return await BaseMutationResolver(Copilot, models.Copilot).update(id, input, info.context.user_id)
|
||||
|
||||
@@ -4,6 +4,7 @@ from fastapi import HTTPException
|
||||
from starlette.status import HTTP_401_UNAUTHORIZED
|
||||
from database import models
|
||||
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.event import EventQueryResolver
|
||||
from graphql_schema.entities.types.mutation_input import CreateEventInput, EditEventInput
|
||||
@@ -13,6 +14,7 @@ from graphql_schema.entities.types.types import Event
|
||||
@strawberry.type
|
||||
class EventQueries:
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
async def events(root, info, username: Optional[str] = None) -> List[Event]:
|
||||
if not info.context.user_id and not username:
|
||||
raise HTTPException(HTTP_401_UNAUTHORIZED)
|
||||
@@ -24,6 +26,7 @@ class EventQueries:
|
||||
)
|
||||
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
async def event(root, info, id: int, username: Optional[str] = None) -> Event:
|
||||
if not info.context.user_id and not username:
|
||||
raise HTTPException(HTTP_401_UNAUTHORIZED)
|
||||
@@ -38,11 +41,13 @@ class EventQueries:
|
||||
@strawberry.type
|
||||
class EventMutation:
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def create_event(root, info, input: CreateEventInput) -> Event:
|
||||
return await BaseMutationResolver(Event, models.Event).create(input.to_dict(), info.context.user_id)
|
||||
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def edit_event(root, info, id: int, input: EditEventInput) -> Event:
|
||||
return await BaseMutationResolver(Event, models.Event).update(id, input, info.context.user_id)
|
||||
|
||||
@@ -18,6 +18,7 @@ from graphql_schema.entities.types.types import Flight
|
||||
class FlightQueries:
|
||||
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
async def flights(root, info, username: Optional[str] = None) -> List[Flight]:
|
||||
if not info.context.user_id and not username:
|
||||
raise HTTPException(HTTP_401_UNAUTHORIZED)
|
||||
@@ -36,6 +37,7 @@ class FlightQueries:
|
||||
@strawberry.type
|
||||
class FlightMutation:
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def create_flight(self, info, input: CreateFlightInput) -> Flight:
|
||||
data = input.to_dict()
|
||||
@@ -77,11 +79,13 @@ class FlightMutation:
|
||||
return flight
|
||||
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def edit_flight(self, info, id: int, input: EditFlightInput) -> Flight:
|
||||
return await FlightMutationResolver().update(info.context, id, input)
|
||||
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def delete_flight(self, info, id: int) -> Flight:
|
||||
return await FlightMutationResolver().delete(info.context.user_id, id)
|
||||
|
||||
@@ -6,6 +6,7 @@ from sqlalchemy.exc import IntegrityError
|
||||
from database import models
|
||||
from decorators.endpoints import authenticated_user_only
|
||||
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.types.mutation_input import CreateOrganizationInput, EditOrganizationInput
|
||||
from graphql_schema.entities.types.types import Organization
|
||||
@@ -14,6 +15,7 @@ from graphql_schema.entities.types.types import Organization
|
||||
@strawberry.type
|
||||
class OrganizationQueries:
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def organizations(root, info) -> List[Organization]:
|
||||
return await BaseQueryResolver(Organization, models.Organization).get_list(
|
||||
@@ -21,6 +23,7 @@ class OrganizationQueries:
|
||||
)
|
||||
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def organization(root, info, id: int) -> Organization:
|
||||
return await BaseQueryResolver(Organization, models.Organization).get_one(id, info.context.user_id)
|
||||
@@ -30,6 +33,7 @@ class OrganizationQueries:
|
||||
class OrganizationMutation:
|
||||
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def create_organization(root, info, input: CreateOrganizationInput) -> Organization:
|
||||
return await BaseMutationResolver(Organization, models.Organization).create(
|
||||
@@ -38,6 +42,7 @@ class OrganizationMutation:
|
||||
)
|
||||
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def edit_organization(root, info, id: int, input: EditOrganizationInput) -> Organization:
|
||||
async with get_session() as db:
|
||||
@@ -55,6 +60,7 @@ class OrganizationMutation:
|
||||
class OrganizationUserMutation:
|
||||
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def add_to_organization(root, info, organization_id: int) -> Organization:
|
||||
async with get_session() as db:
|
||||
@@ -75,6 +81,7 @@ class OrganizationUserMutation:
|
||||
return Organization(**organization.as_dict())
|
||||
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def remove_from_organization(root, info, organization_id: int) -> Organization:
|
||||
async with get_session() as db:
|
||||
|
||||
@@ -2,6 +2,7 @@ from typing import List
|
||||
import strawberry
|
||||
from database import models
|
||||
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.photo import PhotoMutationResolver
|
||||
from graphql_schema.entities.types.types import Photo
|
||||
@@ -11,10 +12,12 @@ from graphql_schema.entities.types.mutation_input import EditPhotoInput, UploadP
|
||||
@strawberry.type
|
||||
class PhotoQueries:
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
async def photos(root, info) -> List[Photo]:
|
||||
return await BaseQueryResolver(Photo, models.Photo).get_list(user_id=info.context.user_id)
|
||||
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
async def photo(root, info, id: int) -> Photo:
|
||||
return await BaseQueryResolver(Photo, models.Photo).get_one(id, user_id=info.context.user_id)
|
||||
|
||||
@@ -22,16 +25,19 @@ class PhotoQueries:
|
||||
@strawberry.type
|
||||
class PhotoMutation:
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def upload_photo(self, info, input: UploadPhotoInput) -> Photo:
|
||||
return await PhotoMutationResolver().upload(info, input)
|
||||
|
||||
@strawberry.mutation()
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def edit_photo(self, info, id: int, input: EditPhotoInput) -> Photo:
|
||||
return await PhotoMutationResolver().update(id, input, info.context.user_id)
|
||||
|
||||
@strawberry.mutation()
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def change_orientation(self, info, id: int, direction: str) -> Photo:
|
||||
return await PhotoMutationResolver().change_orientation(
|
||||
@@ -42,11 +48,13 @@ class PhotoMutation:
|
||||
)
|
||||
|
||||
@strawberry.mutation()
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
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)
|
||||
|
||||
@strawberry.mutation()
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def delete_photo(self, info, id: int) -> Photo:
|
||||
return await PhotoMutationResolver().delete(user_id=info.context.user_id, id=id)
|
||||
|
||||
@@ -3,6 +3,7 @@ import strawberry
|
||||
from database import models
|
||||
from decorators.endpoints import authenticated_user_only
|
||||
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.resolvers.base import BaseQueryResolver, BaseMutationResolver
|
||||
from graphql_schema.entities.types.types import PointOfInterest
|
||||
@@ -12,6 +13,7 @@ from graphql_schema.entities.types.mutation_input import CreatePointOfInterestIn
|
||||
@strawberry.type
|
||||
class PointOfInterestQueries:
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def points_of_interest(root, info) -> List[PointOfInterest]:
|
||||
return await BaseQueryResolver(PointOfInterest, models.PointOfInterest).get_list(info.context.user_id)
|
||||
@@ -25,6 +27,7 @@ class PointOfInterestQueries:
|
||||
@strawberry.type
|
||||
class PointOfInterestMutation:
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def create_point_of_interest(root, info, input: CreatePointOfInterestInput) -> PointOfInterest:
|
||||
input_data = input.to_dict()
|
||||
@@ -40,6 +43,7 @@ class PointOfInterestMutation:
|
||||
)
|
||||
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def edit_point_of_interest(root, info, id: int, input: EditPointOfInterestInput) -> PointOfInterest:
|
||||
input_data = input.to_dict()
|
||||
@@ -59,6 +63,7 @@ class PointOfInterestMutation:
|
||||
return PointOfInterest(**updated_poi.as_dict())
|
||||
|
||||
@strawberry.mutation
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def delete_point_of_interest(self, info, id: int) -> PointOfInterest:
|
||||
return await BaseMutationResolver(PointOfInterest, models.PointOfInterest).delete(info.context.user_id, id=id)
|
||||
|
||||
@@ -2,6 +2,7 @@ from typing import List
|
||||
import strawberry
|
||||
from database import models
|
||||
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.types.types import PointOfInterestType
|
||||
|
||||
@@ -10,11 +11,13 @@ from graphql_schema.entities.types.types import PointOfInterestType
|
||||
class PointOfInterestTypeQueries:
|
||||
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def point_of_interest_types(root, info) -> List[PointOfInterestType]:
|
||||
return await BaseQueryResolver(PointOfInterestType, models.PointOfInterestType).get_list(info.context.user_id)
|
||||
|
||||
@strawberry.field()
|
||||
@error_logging
|
||||
@authenticated_user_only()
|
||||
async def point_of_interest_type(root, info, id: int) -> PointOfInterestType:
|
||||
return await BaseQueryResolver(PointOfInterestType, models.PointOfInterestType).get_one(
|
||||
|
||||
@@ -10,7 +10,7 @@ from graphql_schema.dataloaders.multi_models import (
|
||||
poi_photos_dataloader, flight_by_poi_dataloader, flight_copilots_dataloader, flight_track_dataloader,
|
||||
photos_dataloader, flights_by_aircraft_dataloader, users_in_organization_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 (
|
||||
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)
|
||||
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)
|
||||
|
||||
@@ -4,13 +4,13 @@ from graphql import GraphQLError
|
||||
from passlib.hash import bcrypt
|
||||
from sqlalchemy import select
|
||||
from strawberry.file_uploads import Upload
|
||||
from background_jobs.photo import resize_photo
|
||||
from database import models
|
||||
from decorators.endpoints import authenticated_user_only
|
||||
from decorators.error_logging import error_logging
|
||||
from database.transaction import get_session
|
||||
from graphql_schema.entities.types.types import User
|
||||
from utils.file import delete_file
|
||||
from utils.image import resize_image
|
||||
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)
|
||||
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:
|
||||
@@ -81,7 +81,7 @@ class EditUserMutation:
|
||||
|
||||
data['title_image_filename'] = await handle_file_upload(input.title_image, user_image_path)
|
||||
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:
|
||||
|
||||
+6
-1
@@ -3,6 +3,7 @@ from datetime import timedelta
|
||||
from typing import Optional
|
||||
from fastapi import FastAPI, APIRouter, Depends, Security
|
||||
from fastapi_jwt import JwtAuthorizationCredentials, JwtAccessBearerCookie, JwtRefreshBearerCookie
|
||||
from graphql import GraphQLError
|
||||
from sqlalchemy import select
|
||||
from starlette.background import BackgroundTasks
|
||||
from starlette.middleware.cors import CORSMiddleware
|
||||
@@ -35,7 +36,11 @@ class App:
|
||||
|
||||
def create_app(self):
|
||||
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()
|
||||
|
||||
|
||||
+4
-2
@@ -10,5 +10,7 @@ def delete_file(path: str, silent: bool = False):
|
||||
|
||||
|
||||
def check_directories(path: str):
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path)
|
||||
try:
|
||||
os.makedirs(path, exist_ok=True)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
+3
-124
@@ -1,10 +1,9 @@
|
||||
import io
|
||||
|
||||
import math
|
||||
from datetime import datetime
|
||||
from typing import Optional, Tuple
|
||||
import exif
|
||||
from PIL import Image, UnidentifiedImageError
|
||||
from PIL import Image
|
||||
from PIL.ImageEnhance import Brightness, Contrast, Color, Sharpness
|
||||
from utils.file import check_directories
|
||||
from utils.gps import gps_to_decimal
|
||||
@@ -130,129 +129,9 @@ class PhotoEditor:
|
||||
def write_to_file(
|
||||
self, quality: int = 90, dest_path: Optional[str] = None, dest_filename: Optional[str] = None
|
||||
) -> str:
|
||||
check_directories(dest_path or self.path)
|
||||
|
||||
dest = f"{dest_path or self.path}/{dest_filename or self.filename}"
|
||||
|
||||
check_directories(dest)
|
||||
|
||||
self.img.save(dest, 'JPEG', quality=quality)
|
||||
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user