Ukladani metadat k planum
This commit is contained in:
@@ -0,0 +1,58 @@
|
|||||||
|
"""add flight plan meta information
|
||||||
|
|
||||||
|
Revision ID: 790ba00fc021
|
||||||
|
Revises: f7ab4bdac987
|
||||||
|
Create Date: 2024-04-29 16:40:09.829317
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import mysql
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '790ba00fc021'
|
||||||
|
down_revision = 'f7ab4bdac987'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('flight_plan_has_copilot',
|
||||||
|
sa.Column('flight_plan_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('copilot_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('token', sa.String(length=64), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['copilot_id'], ['copilot.id'], ),
|
||||||
|
sa.ForeignKeyConstraint(['flight_plan_id'], ['flight_plan.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('flight_plan_id', 'copilot_id'),
|
||||||
|
sa.UniqueConstraint('token')
|
||||||
|
)
|
||||||
|
op.add_column('flight_plan', sa.Column('is_default_name', sa.Boolean(), server_default='0', nullable=False))
|
||||||
|
op.add_column('flight_plan', sa.Column('is_editable_by_copilot', sa.Boolean(), server_default='0', nullable=False))
|
||||||
|
op.add_column('flight_plan', sa.Column('planned_speed', sa.Integer(), nullable=False))
|
||||||
|
op.add_column('flight_plan', sa.Column('planned_takeoff_datetime', sa.DateTime(), nullable=True))
|
||||||
|
op.add_column('flight_plan', sa.Column('aircraft_id', sa.Integer(), nullable=True))
|
||||||
|
op.alter_column('flight_plan', 'name',
|
||||||
|
existing_type=mysql.VARCHAR(length=128),
|
||||||
|
type_=sa.String(length=256),
|
||||||
|
existing_nullable=False)
|
||||||
|
op.create_foreign_key(None, 'flight_plan', 'aircraft', ['aircraft_id'], ['id'])
|
||||||
|
op.drop_column('point_of_interest_type', 'openaip_id')
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('point_of_interest_type', sa.Column('openaip_id', mysql.VARCHAR(length=32), nullable=False))
|
||||||
|
op.drop_constraint(None, 'flight_plan', type_='foreignkey')
|
||||||
|
op.alter_column('flight_plan', 'name',
|
||||||
|
existing_type=sa.String(length=256),
|
||||||
|
type_=mysql.VARCHAR(length=128),
|
||||||
|
existing_nullable=False)
|
||||||
|
op.drop_column('flight_plan', 'aircraft_id')
|
||||||
|
op.drop_column('flight_plan', 'planned_takeoff_datetime')
|
||||||
|
op.drop_column('flight_plan', 'planned_speed')
|
||||||
|
op.drop_column('flight_plan', 'is_editable_by_copilot')
|
||||||
|
op.drop_column('flight_plan', 'is_default_name')
|
||||||
|
op.drop_table('flight_plan_has_copilot')
|
||||||
|
# ### end Alembic commands ###
|
||||||
+18
-1
@@ -59,6 +59,14 @@ flight_has_copilot = Table(
|
|||||||
Column("token", String(64), unique=True)
|
Column("token", String(64), unique=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
flight_plan_has_copilot = Table(
|
||||||
|
"flight_plan_has_copilot",
|
||||||
|
BaseModel.metadata,
|
||||||
|
Column("flight_plan_id", ForeignKey("flight_plan.id"), primary_key=True),
|
||||||
|
Column("copilot_id", ForeignKey("copilot.id"), primary_key=True),
|
||||||
|
Column("token", String(64), unique=True)
|
||||||
|
)
|
||||||
|
|
||||||
copilot_has_photo = Table(
|
copilot_has_photo = Table(
|
||||||
"copilot_has_photo",
|
"copilot_has_photo",
|
||||||
BaseModel.metadata,
|
BaseModel.metadata,
|
||||||
@@ -93,12 +101,20 @@ class FlightPlan(BaseModel):
|
|||||||
__tablename__ = "flight_plan"
|
__tablename__ = "flight_plan"
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
name: Mapped[str] = mapped_column(String(256), nullable=False)
|
||||||
|
is_default_name: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
||||||
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
||||||
|
is_editable_by_copilot: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
||||||
|
planned_speed: Mapped[int] = mapped_column(Integer, nullable=False, default=150)
|
||||||
|
planned_takeoff_datetime: Mapped[datetime] = mapped_column(DateTime, nullable=True)
|
||||||
|
aircraft_id: Mapped[int] = mapped_column(Integer, ForeignKey("aircraft.id"), nullable=True)
|
||||||
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
||||||
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')
|
||||||
|
|
||||||
|
copilots: Mapped[List['Copilot']] = relationship(secondary=flight_plan_has_copilot)
|
||||||
|
aircraft: Mapped['Aircraft'] = relationship()
|
||||||
|
markers: Mapped['FlightPlanMarker'] = relationship()
|
||||||
created_by: Mapped['User'] = relationship()
|
created_by: Mapped['User'] = relationship()
|
||||||
|
|
||||||
|
|
||||||
@@ -403,6 +419,7 @@ class Copilot(BaseModel):
|
|||||||
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
||||||
|
|
||||||
flights: Mapped[Set['Flight']] = relationship(secondary=flight_has_copilot)
|
flights: Mapped[Set['Flight']] = relationship(secondary=flight_has_copilot)
|
||||||
|
flight_plans: Mapped[Set['FlightPlan']] = relationship(secondary=flight_plan_has_copilot)
|
||||||
created_by: Mapped['User'] = relationship()
|
created_by: Mapped['User'] = relationship()
|
||||||
photos: Mapped[List['Photo']] = relationship(secondary=copilot_has_photo)
|
photos: Mapped[List['Photo']] = relationship(secondary=copilot_has_photo)
|
||||||
title_photo: Mapped['Photo'] = relationship(foreign_keys=[title_photo_id])
|
title_photo: Mapped['Photo'] = relationship(foreign_keys=[title_photo_id])
|
||||||
|
|||||||
@@ -20,9 +20,25 @@ flight_copilots_dataloader = DataLoader(
|
|||||||
models.flight_has_copilot.c.flight_id == models.Flight.id,
|
models.flight_has_copilot.c.flight_id == models.Flight.id,
|
||||||
models.flight_has_copilot.c.copilot_id == models.Copilot.id,
|
models.flight_has_copilot.c.copilot_id == models.Copilot.id,
|
||||||
],
|
],
|
||||||
extra_join=[models.Copilot.flights]).load,
|
extra_join=[models.Copilot.flights]
|
||||||
|
).load,
|
||||||
cache=False)
|
cache=False)
|
||||||
|
|
||||||
|
|
||||||
|
flight_plan_copilots_dataloader = DataLoader(
|
||||||
|
load_fn=FlightCopilotDataloader(
|
||||||
|
models.Copilot,
|
||||||
|
relationship_column=models.FlightPlan.id,
|
||||||
|
extra_select=[models.flight_plan_has_copilot.c.token],
|
||||||
|
# filters=[
|
||||||
|
# models.flight_plan_has_copilot.c.flight_plan_id == models.FlightPlan.id,
|
||||||
|
# models.flight_plan_has_copilot.c.copilot_id == models.Copilot.id,
|
||||||
|
# ],
|
||||||
|
extra_join=[models.Copilot.flight_plans]
|
||||||
|
).load,
|
||||||
|
cache=False
|
||||||
|
)
|
||||||
|
|
||||||
reporting_points_dataloader = DataLoader(
|
reporting_points_dataloader = DataLoader(
|
||||||
load_fn=MultiModelsDataloader(
|
load_fn=MultiModelsDataloader(
|
||||||
models.ReportingPoint,
|
models.ReportingPoint,
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ class BaseQueryResolver(BaseResolver):
|
|||||||
|
|
||||||
|
|
||||||
class BaseMutationResolver(BaseResolver):
|
class BaseMutationResolver(BaseResolver):
|
||||||
async def _get_one(self, db: AsyncSession, id: int, created_by_id: int) -> models.BaseModel:
|
async def _get_one(self, db: AsyncSession, id: int, created_by_id: int):
|
||||||
query = self.query_builder.get_simple_query(created_by_id=created_by_id).filter(self.model.id == id)
|
query = self.query_builder.get_simple_query(created_by_id=created_by_id).filter(self.model.id == id)
|
||||||
return (await db.scalars(query)).one()
|
return (await db.scalars(query)).one()
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
from sqlalchemy import delete
|
import asyncio
|
||||||
|
|
||||||
|
from sqlalchemy import delete, select
|
||||||
|
from sqlalchemy.dialects.mysql import insert
|
||||||
|
|
||||||
from database import models
|
from database import models
|
||||||
|
from database.models import flight_plan_has_copilot
|
||||||
from database.transaction import get_session
|
from database.transaction import get_session
|
||||||
|
from graphql_schema.entities.helpers.combobox import handle_combobox_save
|
||||||
from graphql_schema.entities.resolvers.base import BaseMutationResolver
|
from graphql_schema.entities.resolvers.base import BaseMutationResolver
|
||||||
|
from graphql_schema.entities.resolvers.flight import handle_aircraft_save
|
||||||
from graphql_schema.entities.types.mutation_input import CreateFlightPlanInput, EditFlightPlanInput
|
from graphql_schema.entities.types.mutation_input import CreateFlightPlanInput, EditFlightPlanInput
|
||||||
from graphql_schema.entities.types.types import FlightPlan
|
from graphql_schema.entities.types.types import FlightPlan
|
||||||
|
from utils.str_utils import random_str
|
||||||
|
|
||||||
|
|
||||||
class FlightPlanMutationResolver(BaseMutationResolver):
|
class FlightPlanMutationResolver(BaseMutationResolver):
|
||||||
@@ -41,13 +49,55 @@ class FlightPlanMutationResolver(BaseMutationResolver):
|
|||||||
await self.save_markers(db, flight_plan, data.markers)
|
await self.save_markers(db, flight_plan, data.markers)
|
||||||
return flight_plan
|
return flight_plan
|
||||||
|
|
||||||
|
async def save_copilots(self, db, flight_plan_id: int, copilots: list, user_id: int):
|
||||||
|
await db.execute(delete(flight_plan_has_copilot).filter_by(flight_plan_id=flight_plan_id))
|
||||||
|
copilots = await asyncio.gather(*[
|
||||||
|
handle_combobox_save(db, models.Copilot, copilot, user_id) for copilot in copilots
|
||||||
|
])
|
||||||
|
|
||||||
|
for copilot_id in copilots:
|
||||||
|
await db.execute(insert(flight_plan_has_copilot).values(
|
||||||
|
flight_plan_id=flight_plan_id,
|
||||||
|
copilot_id=copilot_id,
|
||||||
|
token=random_str(64)
|
||||||
|
))
|
||||||
|
|
||||||
async def update(self, id: int, data: EditFlightPlanInput, user_id: int) -> FlightPlan:
|
async def update(self, id: int, data: EditFlightPlanInput, user_id: int) -> FlightPlan:
|
||||||
input_data = data.to_dict()
|
input_data = data.to_dict()
|
||||||
|
|
||||||
async with get_session() as db:
|
async with get_session() as db:
|
||||||
flight_plan = await self._do_update(db, id, input_data)
|
flight_plan_model = await self._get_one(db, id=id, created_by_id=user_id)
|
||||||
|
|
||||||
await self.reset_plan_markers(db, flight_plan)
|
if data.aircraft is not None:
|
||||||
await self.save_markers(db, flight_plan, data.markers)
|
input_data['aircraft_id'] = await handle_aircraft_save(db, user_id, data.aircraft)
|
||||||
|
|
||||||
|
if data.markers is not None:
|
||||||
|
await self.reset_plan_markers(db, flight_plan_model)
|
||||||
|
await self.save_markers(db, flight_plan_model, data.markers)
|
||||||
|
|
||||||
|
if flight_plan_model.is_default_name:
|
||||||
|
if data.markers:
|
||||||
|
markers = data.markers
|
||||||
|
else:
|
||||||
|
markers = (await db.scalars(select(models.FlightPlanMarker).filter(models.FlightPlanMarker.flight_plan_id == id))).all()
|
||||||
|
|
||||||
|
used_markers = evenly_spaced_elements(markers, 5)
|
||||||
|
input_data['name'] = " - ".join(m.name for m in used_markers)
|
||||||
|
|
||||||
|
if data.copilots is not None:
|
||||||
|
await self.save_copilots(
|
||||||
|
db,
|
||||||
|
flight_plan_id=id,
|
||||||
|
copilots=data.copilots,
|
||||||
|
user_id=user_id
|
||||||
|
)
|
||||||
|
|
||||||
|
flight_plan = await self._do_update(db, obj=flight_plan_model, data=input_data)
|
||||||
return flight_plan
|
return flight_plan
|
||||||
|
|
||||||
|
|
||||||
|
def evenly_spaced_elements(lst: list, count: int) -> list:
|
||||||
|
if count > len(lst):
|
||||||
|
return lst
|
||||||
|
interval = (len(lst) - 1) / (count - 1) if count > 1 else 0
|
||||||
|
return [lst[int(round(i * interval))] for i in range(count)]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import strawberry
|
|||||||
from strawberry.file_uploads import Upload
|
from strawberry.file_uploads import Upload
|
||||||
from database import models
|
from database import models
|
||||||
from graphql_schema.entities.types.base import BaseGraphqlInputType
|
from graphql_schema.entities.types.base import BaseGraphqlInputType
|
||||||
|
from graphql_schema.entities.types.types import Aircraft
|
||||||
from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_input
|
from graphql_schema.sqlalchemy_to_strawberry_type import strawberry_sqlalchemy_input
|
||||||
|
|
||||||
|
|
||||||
@@ -36,7 +37,9 @@ class CreateFlightPlanInput(BaseGraphqlInputType):
|
|||||||
|
|
||||||
@strawberry_sqlalchemy_input(model=models.FlightPlan, exclude_fields=["id", "markers"], all_optional=True)
|
@strawberry_sqlalchemy_input(model=models.FlightPlan, exclude_fields=["id", "markers"], all_optional=True)
|
||||||
class EditFlightPlanInput(BaseGraphqlInputType):
|
class EditFlightPlanInput(BaseGraphqlInputType):
|
||||||
markers: list[FlightPlanMarkerInput]
|
markers: Optional[list[FlightPlanMarkerInput]] = None
|
||||||
|
copilots: Optional[list[ComboboxInput]] = None
|
||||||
|
aircraft: Optional[ComboboxInput] = None
|
||||||
|
|
||||||
|
|
||||||
@strawberry_sqlalchemy_input(model=models.Copilot, exclude_fields=["id"], all_optional=True)
|
@strawberry_sqlalchemy_input(model=models.Copilot, exclude_fields=["id"], all_optional=True)
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ from graphql_schema.dataloaders.multi_models import (
|
|||||||
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, public_flights_by_copilot_dataloader,
|
flights_by_copilot_dataloader, public_flights_by_event_dataloader, public_flights_by_copilot_dataloader,
|
||||||
photo_copilots_dataloader, photos_aircraft_dataloader, copilots_in_photo_dataloader, flight_plan_markers_dataloader, reporting_points_dataloader
|
photo_copilots_dataloader, photos_aircraft_dataloader, copilots_in_photo_dataloader, flight_plan_markers_dataloader,
|
||||||
|
reporting_points_dataloader, flight_plan_copilots_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,
|
poi_dataloader, poi_type_dataloader, event_dataloader, aircraft_dataloader, airport_dataloader,
|
||||||
@@ -227,12 +228,18 @@ class FlightPlan:
|
|||||||
)
|
)
|
||||||
return navigation
|
return navigation
|
||||||
|
|
||||||
|
@authenticated_user_only(raise_when_unauthorized=False, return_value_unauthorized=[])
|
||||||
|
async def load_copilots(root):
|
||||||
|
return await flight_plan_copilots_dataloader.load(root.id)
|
||||||
|
|
||||||
markers: list[FlightPlanMarker] = strawberry.field(
|
markers: list[FlightPlanMarker] = strawberry.field(
|
||||||
resolver=lambda root: flight_plan_markers_dataloader.load(root.id)
|
resolver=lambda root: flight_plan_markers_dataloader.load(root.id)
|
||||||
)
|
)
|
||||||
track: Optional[list[FlightPlanTrack]] = strawberry.field(
|
track: Optional[list[FlightPlanTrack]] = strawberry.field(
|
||||||
resolver=resolve_track
|
resolver=resolve_track
|
||||||
)
|
)
|
||||||
|
copilots: List[Copilot] = strawberry.field(resolver=load_copilots)
|
||||||
|
aircraft: Optional[Aircraft] = strawberry.field(resolver=lambda root: aircraft_dataloader.load(root.aircraft_id))
|
||||||
|
|
||||||
|
|
||||||
@strawberry_sqlalchemy_type(models.Copilot)
|
@strawberry_sqlalchemy_type(models.Copilot)
|
||||||
|
|||||||
Reference in New Issue
Block a user