Lepsi stahovani informaci o pocasi
This commit is contained in:
@@ -14,7 +14,7 @@ async def get_weather(date_time: datetime, gps: tuple[float, float]):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"datetime": weather['datetime'],
|
"datetime": date_time, # nemuzu pouzit weather['datetime'], protoze to mi vraci jen cele hodiny
|
||||||
"qnh": weather['pressure_msl'],
|
"qnh": weather['pressure_msl'],
|
||||||
"temperature_surface": weather['temperature_2m'],
|
"temperature_surface": weather['temperature_2m'],
|
||||||
"dewpoint_surface": weather['dewpoint_2m'],
|
"dewpoint_surface": weather['dewpoint_2m'],
|
||||||
@@ -44,18 +44,27 @@ async def download_weather_for_flight(date_time: datetime, flight_id: int, airpo
|
|||||||
await models.Flight.update(db, obj=flight, data={f"{type_}_weather_info_id": weather_model.id})
|
await models.Flight.update(db, obj=flight, data={f"{type_}_weather_info_id": weather_model.id})
|
||||||
|
|
||||||
|
|
||||||
async def download_weather_for_plan(date_time: datetime, flight_plan_id: int, gps: tuple[float, float]):
|
async def download_weather_for_plan_marker(date_time: datetime, marker_id: int):
|
||||||
|
async with get_session() as db:
|
||||||
|
marker = await models.FlightPlanMarker.get_one(db, id=marker_id)
|
||||||
|
|
||||||
|
if not marker.gps_latitude or not marker.gps_longitude:
|
||||||
|
return
|
||||||
|
|
||||||
|
gps = (marker.gps_latitude, marker.gps_longitude)
|
||||||
|
marker_weather_info_id = marker.weather_info_id
|
||||||
|
|
||||||
data = await get_weather(date_time, gps)
|
data = await get_weather(date_time, gps)
|
||||||
|
if not data:
|
||||||
|
return
|
||||||
|
|
||||||
async with get_session() as db:
|
async with get_session() as db:
|
||||||
plan = await models.FlightPlan.get_one(db, id=flight_plan_id)
|
if marker_weather_info_id:
|
||||||
|
await models.WeatherInfo.update(db, id=marker_weather_info_id, data=data)
|
||||||
if plan.weather_info_id:
|
|
||||||
await models.WeatherInfo.update(db, id=plan.weather_info.id, data=data)
|
|
||||||
else:
|
else:
|
||||||
weather_model = await models.WeatherInfo.create(db, data=data)
|
weather_model = await models.WeatherInfo.create(db, data=data)
|
||||||
await models.FlightPlan.update(
|
await models.FlightPlanMarker.update(
|
||||||
db,
|
db,
|
||||||
obj=plan,
|
id=marker_id,
|
||||||
data={"weather_info_id": weather_model.id}
|
data={"weather_info_id": weather_model.id}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -168,6 +168,8 @@ class FlightPlanMarker(BaseModel):
|
|||||||
gps_longitude: Mapped[float] = mapped_column(Float, nullable=False)
|
gps_longitude: Mapped[float] = mapped_column(Float, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Airport(BaseModel):
|
class Airport(BaseModel):
|
||||||
__tablename__ = "airport"
|
__tablename__ = "airport"
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ airport_dataloader = create_dataloader(models.Airport)
|
|||||||
aircraft_dataloader = create_dataloader(models.Aircraft)
|
aircraft_dataloader = create_dataloader(models.Aircraft)
|
||||||
event_dataloader = create_dataloader(models.Event)
|
event_dataloader = create_dataloader(models.Event)
|
||||||
organizations_dataloader = create_dataloader(models.Organization)
|
organizations_dataloader = create_dataloader(models.Organization)
|
||||||
airport_weather_info_loader = create_dataloader(models.WeatherInfo)
|
weather_info_loader = create_dataloader(models.WeatherInfo)
|
||||||
track_dataloader = create_dataloader(models.Track)
|
track_dataloader = create_dataloader(models.Track)
|
||||||
poi_dataloader = create_dataloader(models.PointOfInterest)
|
poi_dataloader = create_dataloader(models.PointOfInterest)
|
||||||
poi_type_dataloader = create_dataloader(models.PointOfInterestType)
|
poi_type_dataloader = create_dataloader(models.PointOfInterestType)
|
||||||
|
|||||||
@@ -62,9 +62,9 @@ class AircraftMutation:
|
|||||||
@error_logging
|
@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().update(id, user_id=info.context.user_id, data=input)
|
return await AircraftMutationResolver().update(id, info.context, data=input)
|
||||||
|
|
||||||
@strawberry.mutation
|
@strawberry.mutation
|
||||||
@authenticated_user_only()
|
@authenticated_user_only()
|
||||||
async def delete_aircraft(self, info, id: int) -> Aircraft:
|
async def delete_aircraft(self, info, id: int) -> Aircraft:
|
||||||
return await AircraftMutationResolver().delete(info.context.user_id, id)
|
return await AircraftMutationResolver().delete(info.context, id)
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ from graphql_schema.entities.types.types import Airport
|
|||||||
class AirportQueries:
|
class AirportQueries:
|
||||||
@strawberry.field()
|
@strawberry.field()
|
||||||
@error_logging
|
@error_logging
|
||||||
# @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)
|
||||||
|
|
||||||
|
|||||||
@@ -50,4 +50,4 @@ class FlightPlanMutation:
|
|||||||
@error_logging
|
@error_logging
|
||||||
@authenticated_user_only()
|
@authenticated_user_only()
|
||||||
async def edit_flight_plan(root, info, id: int, input: EditFlightPlanInput) -> FlightPlan:
|
async def edit_flight_plan(root, info, id: int, input: EditFlightPlanInput) -> FlightPlan:
|
||||||
return await FlightPlanMutationResolver().update(id, input, info.context.user_id)
|
return await FlightPlanMutationResolver().update(info.context, id, input)
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
from operator import or_
|
from operator import or_
|
||||||
from typing import Set, Optional
|
from typing import Set, Optional
|
||||||
|
|
||||||
from sqlalchemy import and_
|
from sqlalchemy import and_
|
||||||
|
|
||||||
from database import models
|
from database import models
|
||||||
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.helpers.combobox import handle_combobox_save
|
||||||
@@ -77,7 +75,7 @@ class AircraftMutationResolver(BaseMutationResolver):
|
|||||||
|
|
||||||
return await self._do_create(db, data=input_data)
|
return await self._do_create(db, data=input_data)
|
||||||
|
|
||||||
async def update(self, id: int, user_id: int, data: EditAircraftInput) -> Aircraft:
|
async def update(self, context, id: int, data: EditAircraftInput) -> Aircraft:
|
||||||
update_data = data.to_dict()
|
update_data = data.to_dict()
|
||||||
async with get_session() as db:
|
async with get_session() as db:
|
||||||
if data.organization:
|
if data.organization:
|
||||||
@@ -85,7 +83,7 @@ class AircraftMutationResolver(BaseMutationResolver):
|
|||||||
db,
|
db,
|
||||||
models.Organization,
|
models.Organization,
|
||||||
input=data.organization,
|
input=data.organization,
|
||||||
user_id=user_id,
|
user_id=context.user_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
return await self._do_update(db, id, update_data)
|
return await self._do_update(db, id, update_data)
|
||||||
|
|||||||
@@ -116,14 +116,14 @@ class BaseMutationResolver(BaseResolver):
|
|||||||
async with get_session() as db:
|
async with get_session() as db:
|
||||||
return await self._do_create(db, input_data)
|
return await self._do_create(db, input_data)
|
||||||
|
|
||||||
async def update(self, id: int, data: BaseGraphqlInputType, user_id: int) -> GQL_TYPE:
|
async def update(self, context, id: int, data: BaseGraphqlInputType, user_id: int) -> GQL_TYPE:
|
||||||
async with get_session() as db:
|
async with get_session() as db:
|
||||||
item = await self._get_one(db, id, user_id)
|
item = await self._get_one(db, id, user_id)
|
||||||
return await self._do_update(db, item, data.to_dict())
|
return await self._do_update(db, item, data.to_dict())
|
||||||
|
|
||||||
async def delete(self, user_id: int, id: int, **kwargs) -> GQL_TYPE:
|
async def delete(self, context, id: int, **kwargs) -> GQL_TYPE:
|
||||||
async with get_session() as db:
|
async with get_session() as db:
|
||||||
model = await self._get_one(db, id, user_id)
|
model = await self._get_one(db, id, context.user_id)
|
||||||
|
|
||||||
if hasattr(self.model, "deleted"):
|
if hasattr(self.model, "deleted"):
|
||||||
model = await self.model.update(db, obj=model, data=dict(deleted=True))
|
model = await self.model.update(db, obj=model, data=dict(deleted=True))
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ class FlightMutationResolver(BaseMutationResolver):
|
|||||||
if input.track is not None:
|
if input.track is not None:
|
||||||
await handle_track_edit(db=db, flight_id=flight.id, track=input.track, user_id=user_id)
|
await handle_track_edit(db=db, flight_id=flight.id, track=input.track, user_id=user_id)
|
||||||
|
|
||||||
if data['gpx_track_filename']:
|
if 'gpx_track_filename' in data:
|
||||||
await save_track_from_gpx_to_db(gpx_filename=data['gpx_track_filename'], flight_id=flight.id)
|
await save_track_from_gpx_to_db(gpx_filename=data['gpx_track_filename'], flight_id=flight.id)
|
||||||
|
|
||||||
schedule_background_tasks(flight.id, data, context)
|
schedule_background_tasks(flight.id, data, context)
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ from graphql_schema.entities.resolvers.base import BaseMutationResolver, BaseQue
|
|||||||
from graphql_schema.entities.resolvers.flight import handle_aircraft_save
|
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.flight_plan_helpers import refresh_markers_weather_info
|
||||||
|
from utils.list_utils import evenly_spaced_elements
|
||||||
from utils.str_utils import random_str
|
from utils.str_utils import random_str
|
||||||
|
|
||||||
|
|
||||||
@@ -47,61 +49,24 @@ class FlightPlanMutationResolver(BaseMutationResolver):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(graphql_type=FlightPlan, model=models.FlightPlan)
|
super().__init__(graphql_type=FlightPlan, model=models.FlightPlan)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def save_markers(db, flight_plan: models.FlightPlan, markers: list):
|
|
||||||
position = 0
|
|
||||||
|
|
||||||
for marker in markers:
|
|
||||||
|
|
||||||
if marker.type == 'poi':
|
|
||||||
assert bool(marker.point_of_interest_id)
|
|
||||||
|
|
||||||
if marker.type == 'airport':
|
|
||||||
assert bool(marker.airport_id)
|
|
||||||
|
|
||||||
await models.FlightPlanMarker.create(db, data={
|
|
||||||
"position": position,
|
|
||||||
"flight_plan_id": flight_plan.id,
|
|
||||||
"airport_id": marker.airport_id,
|
|
||||||
"point_of_interest_id": marker.point_of_interest_id,
|
|
||||||
"type": marker.type,
|
|
||||||
"name": marker.name,
|
|
||||||
"gps_latitude": marker.gps_latitude,
|
|
||||||
"gps_longitude": marker.gps_longitude
|
|
||||||
})
|
|
||||||
position += 1
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def reset_plan_markers(db, flight_plan: models.FlightPlan):
|
|
||||||
await db.execute(
|
|
||||||
delete(models.FlightPlanMarker)
|
|
||||||
.filter(models.FlightPlanMarker.flight_plan_id == flight_plan.id)
|
|
||||||
)
|
|
||||||
|
|
||||||
async def create(self, context, data: CreateFlightPlanInput) -> FlightPlan:
|
async def create(self, context, data: CreateFlightPlanInput) -> FlightPlan:
|
||||||
input_data = data.to_dict()
|
input_data = data.to_dict()
|
||||||
input_data['created_by_id'] = context.user_id
|
input_data['created_by_id'] = context.user_id
|
||||||
|
|
||||||
async with get_session() as db:
|
async with get_session() as db:
|
||||||
flight_plan = await self._do_create(db, data=input_data)
|
flight_plan = await self._do_create(db, data=input_data)
|
||||||
await self.save_markers(db, flight_plan, data.markers)
|
markers = await self.save_markers(db, flight_plan, data.markers)
|
||||||
|
await refresh_markers_weather_info(
|
||||||
|
planned_takeoff_datetime=flight_plan.planned_takeoff_datetime,
|
||||||
|
planned_speed=flight_plan.planned_speed,
|
||||||
|
markers=markers,
|
||||||
|
background_tasks=context.background_tasks
|
||||||
|
)
|
||||||
return flight_plan
|
return flight_plan
|
||||||
|
|
||||||
async def save_copilots(self, db, flight_plan_id: int, copilots: list, user_id: int):
|
async def update(self, context, id: int, data: EditFlightPlanInput) -> FlightPlan:
|
||||||
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:
|
|
||||||
input_data = data.to_dict()
|
input_data = data.to_dict()
|
||||||
|
user_id = context.user_id
|
||||||
|
|
||||||
async with get_session() as db:
|
async with get_session() as db:
|
||||||
flight_plan_model = await self._get_one(db, id=id, created_by_id=user_id)
|
flight_plan_model = await self._get_one(db, id=id, created_by_id=user_id)
|
||||||
@@ -109,19 +74,29 @@ class FlightPlanMutationResolver(BaseMutationResolver):
|
|||||||
if data.aircraft is not None:
|
if data.aircraft is not None:
|
||||||
input_data['aircraft_id'] = await handle_aircraft_save(db, user_id, data.aircraft)
|
input_data['aircraft_id'] = await handle_aircraft_save(db, user_id, data.aircraft)
|
||||||
|
|
||||||
|
markers = []
|
||||||
if data.markers is not None:
|
if data.markers is not None:
|
||||||
await self.reset_plan_markers(db, flight_plan_model)
|
await self.reset_plan_markers(db, flight_plan_model)
|
||||||
await self.save_markers(db, flight_plan_model, data.markers)
|
markers = await self.save_markers(db, flight_plan_model, data.markers)
|
||||||
|
await refresh_markers_weather_info(
|
||||||
|
planned_takeoff_datetime=flight_plan_model.planned_takeoff_datetime,
|
||||||
|
planned_speed=flight_plan_model.planned_speed,
|
||||||
|
markers=markers,
|
||||||
|
background_tasks=context.background_tasks
|
||||||
|
)
|
||||||
|
|
||||||
if flight_plan_model.is_default_name:
|
if flight_plan_model.is_default_name:
|
||||||
if data.markers:
|
if not markers:
|
||||||
markers = data.markers
|
markers = await db.scalars(
|
||||||
else:
|
select(models.FlightPlanMarker)
|
||||||
markers = (await db.scalars(select(models.FlightPlanMarker).filter(models.FlightPlanMarker.flight_plan_id == id))).all()
|
.filter(models.FlightPlanMarker.flight_plan_id == id)
|
||||||
|
).all()
|
||||||
|
|
||||||
used_markers = evenly_spaced_elements(markers, 5)
|
used_markers = evenly_spaced_elements(markers, 5)
|
||||||
input_data['name'] = " - ".join(m.name for m in used_markers)
|
input_data['name'] = " - ".join(m.name for m in used_markers)
|
||||||
|
|
||||||
|
# TODO: pokud se zmenila rychlost nebo datum/cas letu, je potreba stahnout nove pocasi!
|
||||||
|
|
||||||
if data.copilots is not None:
|
if data.copilots is not None:
|
||||||
await self.save_copilots(
|
await self.save_copilots(
|
||||||
db,
|
db,
|
||||||
@@ -134,8 +109,49 @@ class FlightPlanMutationResolver(BaseMutationResolver):
|
|||||||
return flight_plan
|
return flight_plan
|
||||||
|
|
||||||
|
|
||||||
def evenly_spaced_elements(lst: list, count: int) -> list:
|
@staticmethod
|
||||||
if count > len(lst):
|
async def save_markers(db, flight_plan: models.FlightPlan, markers: list):
|
||||||
return lst
|
position = 0
|
||||||
interval = (len(lst) - 1) / (count - 1) if count > 1 else 0
|
|
||||||
return [lst[int(round(i * interval))] for i in range(count)]
|
marker_objects = []
|
||||||
|
for marker in markers:
|
||||||
|
if marker.type == 'poi':
|
||||||
|
assert bool(marker.point_of_interest_id)
|
||||||
|
|
||||||
|
if marker.type == 'airport':
|
||||||
|
assert bool(marker.airport_id)
|
||||||
|
|
||||||
|
marker_obj = await models.FlightPlanMarker.create(db, data={
|
||||||
|
"position": position,
|
||||||
|
"flight_plan_id": flight_plan.id,
|
||||||
|
"airport_id": marker.airport_id,
|
||||||
|
"point_of_interest_id": marker.point_of_interest_id,
|
||||||
|
"type": marker.type,
|
||||||
|
"name": marker.name,
|
||||||
|
"gps_latitude": marker.gps_latitude,
|
||||||
|
"gps_longitude": marker.gps_longitude
|
||||||
|
})
|
||||||
|
marker_objects.append(marker_obj)
|
||||||
|
position += 1
|
||||||
|
|
||||||
|
return marker_objects
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def reset_plan_markers(db, flight_plan: models.FlightPlan):
|
||||||
|
await db.execute(
|
||||||
|
delete(models.FlightPlanMarker)
|
||||||
|
.filter(models.FlightPlanMarker.flight_plan_id == flight_plan.id)
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
))
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from graphql_schema.dataloaders.multi_models import (
|
|||||||
)
|
)
|
||||||
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,
|
||||||
airport_weather_info_loader, organizations_dataloader, flight_dataloader, photo_adjustment_dataloader,
|
weather_info_loader, organizations_dataloader, flight_dataloader, photo_adjustment_dataloader,
|
||||||
photo_dataloader, user_dataloader, track_dataloader
|
photo_dataloader, user_dataloader, track_dataloader
|
||||||
)
|
)
|
||||||
from graphql_schema.permissions import IsAuthenticated
|
from graphql_schema.permissions import IsAuthenticated
|
||||||
@@ -162,10 +162,10 @@ class Flight:
|
|||||||
title_photo: Optional[Photo] = strawberry.field(resolver=lambda root: photo_dataloader.load(root.title_photo_id))
|
title_photo: Optional[Photo] = strawberry.field(resolver=lambda root: photo_dataloader.load(root.title_photo_id))
|
||||||
turn_points: List[FlightTurnPoint] = strawberry.field(resolver=lambda root: flight_turn_points_dataloader.load(root.id))
|
turn_points: List[FlightTurnPoint] = strawberry.field(resolver=lambda root: flight_turn_points_dataloader.load(root.id))
|
||||||
takeoff_weather_info: Optional[WeatherInfo] = strawberry.field(
|
takeoff_weather_info: Optional[WeatherInfo] = strawberry.field(
|
||||||
resolver=lambda root: airport_weather_info_loader.load(root.takeoff_weather_info_id)
|
resolver=lambda root: weather_info_loader.load(root.takeoff_weather_info_id)
|
||||||
)
|
)
|
||||||
landing_weather_info: Optional[WeatherInfo] = strawberry.field(
|
landing_weather_info: Optional[WeatherInfo] = strawberry.field(
|
||||||
resolver=lambda root: airport_weather_info_loader.load(root.landing_weather_info_id)
|
resolver=lambda root: weather_info_loader.load(root.landing_weather_info_id)
|
||||||
)
|
)
|
||||||
photos: List[Photo] = strawberry.field(resolver=lambda root: photos_dataloader.load(root.id))
|
photos: List[Photo] = strawberry.field(resolver=lambda root: photos_dataloader.load(root.id))
|
||||||
track: Optional[Track] = strawberry.field(resolver=lambda root: track_dataloader.load(root.track_id))
|
track: Optional[Track] = strawberry.field(resolver=lambda root: track_dataloader.load(root.track_id))
|
||||||
@@ -181,7 +181,9 @@ class Flight:
|
|||||||
|
|
||||||
@strawberry_sqlalchemy_type(model=models.FlightPlanMarker)
|
@strawberry_sqlalchemy_type(model=models.FlightPlanMarker)
|
||||||
class FlightPlanMarker:
|
class FlightPlanMarker:
|
||||||
pass
|
weather_info: Optional[WeatherInfo] = strawberry.field(
|
||||||
|
resolver=lambda root: weather_info_loader.load(root.weather_info_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@strawberry.type
|
@strawberry.type
|
||||||
|
|||||||
@@ -1,22 +1,60 @@
|
|||||||
from sqlalchemy import select
|
import asyncio
|
||||||
|
import sys
|
||||||
|
from collections import defaultdict
|
||||||
|
from typing import Any
|
||||||
|
from fastapi import BackgroundTasks
|
||||||
|
from sqlalchemy import select, Result
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
sys.path.insert(0, "/app/src")
|
||||||
|
|
||||||
|
from utils.flight_plan_helpers import refresh_markers_weather_info
|
||||||
|
from database.models import FlightPlan
|
||||||
from database import models
|
from database import models
|
||||||
from database.transaction import get_session
|
from database.transaction import get_session
|
||||||
|
|
||||||
|
|
||||||
class FlighPlanWeather:
|
async def get_plans(db: AsyncSession) -> list[Any] | Result[tuple[FlightPlan, Any]]:
|
||||||
@staticmethod
|
markers_without_weather = (await db.scalars(
|
||||||
async def get_plans() -> list:
|
|
||||||
async with get_session() as db:
|
|
||||||
markers_without_weather = (await db.execute(
|
|
||||||
select(models.FlightPlanMarker).filter(models.FlightPlanMarker.weather_info_id.is_(None))
|
select(models.FlightPlanMarker).filter(models.FlightPlanMarker.weather_info_id.is_(None))
|
||||||
))
|
))
|
||||||
flight_plan_ids = {m.flight_plan_id for m in markers_without_weather}
|
flight_plan_ids = {m.flight_plan_id for m in markers_without_weather}
|
||||||
|
flight_plan_ids.add(11)
|
||||||
if not flight_plan_ids:
|
if not flight_plan_ids:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
return (await db.execute(
|
return (await db.execute(
|
||||||
select(models.FlightPlan, models.FlightPlan.markers)
|
select(models.FlightPlan, models.FlightPlanMarker)
|
||||||
|
.join(models.FlightPlan.markers)
|
||||||
|
.filter(models.FlightPlan.planned_takeoff_datetime.is_not(None))
|
||||||
.filter(models.FlightPlan.id.in_(flight_plan_ids))
|
.filter(models.FlightPlan.id.in_(flight_plan_ids))
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
async def download_flight_plan_weather():
|
||||||
|
tasks = BackgroundTasks()
|
||||||
|
|
||||||
|
async with get_session() as db:
|
||||||
|
plans_with_markers_without_weather = await get_plans(db)
|
||||||
|
|
||||||
|
markers_by_plan = defaultdict(list)
|
||||||
|
for plan, marker in plans_with_markers_without_weather:
|
||||||
|
markers_by_plan[plan].append(marker)
|
||||||
|
|
||||||
|
for plan, markers in markers_by_plan.items():
|
||||||
|
await refresh_markers_weather_info(
|
||||||
|
plan.planned_takeoff_datetime,
|
||||||
|
plan.planned_speed, markers,
|
||||||
|
background_tasks=tasks
|
||||||
|
)
|
||||||
|
|
||||||
|
await tasks()
|
||||||
|
|
||||||
|
|
||||||
|
async def run_all():
|
||||||
|
await asyncio.gather(download_flight_plan_weather())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.run_until_complete(run_all())
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
from datetime import datetime, timedelta
|
||||||
|
from fastapi import BackgroundTasks
|
||||||
|
from background_jobs.weather import download_weather_for_plan_marker
|
||||||
|
from database import models
|
||||||
|
from utils.gps import get_distance
|
||||||
|
|
||||||
|
|
||||||
|
async def refresh_markers_weather_info(
|
||||||
|
planned_takeoff_datetime: datetime, planned_speed: float,
|
||||||
|
markers: list[models.FlightPlanMarker], background_tasks: BackgroundTasks
|
||||||
|
):
|
||||||
|
if not planned_takeoff_datetime:
|
||||||
|
return
|
||||||
|
|
||||||
|
marker_date_time = planned_takeoff_datetime
|
||||||
|
previous_marker = markers[0] if markers else None
|
||||||
|
for marker in markers:
|
||||||
|
if marker_date_time:
|
||||||
|
# TODO: tohle by se melo volat i v pripade zmeny planovaneho casu vzletu i planovane rychlosti
|
||||||
|
distance_from_prev = get_distance(
|
||||||
|
a=(previous_marker.gps_latitude, previous_marker.gps_longitude),
|
||||||
|
b=(marker.gps_latitude, marker.gps_longitude)
|
||||||
|
)
|
||||||
|
time_from_prev_sec = distance_from_prev / planned_speed * 3600 # pracuji v km/h
|
||||||
|
marker_date_time = marker_date_time + timedelta(seconds=time_from_prev_sec)
|
||||||
|
|
||||||
|
background_tasks.add_task(
|
||||||
|
download_weather_for_plan_marker,
|
||||||
|
marker_id=marker.id, date_time=marker_date_time
|
||||||
|
)
|
||||||
|
previous_marker = marker
|
||||||
@@ -12,3 +12,10 @@ def chunks(items: list | dict, n: int) -> typing.Generator:
|
|||||||
it = iter(items)
|
it = iter(items)
|
||||||
for i in range(0, len(items), n):
|
for i in range(0, len(items), n):
|
||||||
yield {k: items[k] for k in islice(it, n)}
|
yield {k: items[k] for k in islice(it, n)}
|
||||||
|
|
||||||
|
|
||||||
|
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)]
|
||||||
|
|||||||
Reference in New Issue
Block a user