Fix map
This commit is contained in:
@@ -2,5 +2,6 @@
|
|||||||
max-line-length = 120
|
max-line-length = 120
|
||||||
exclude =
|
exclude =
|
||||||
venv
|
venv
|
||||||
|
.venv
|
||||||
__pycache__
|
__pycache__
|
||||||
alembic
|
alembic
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
"""prejmenovani date_time u WeatherInfo
|
||||||
|
|
||||||
|
Revision ID: db036549f318
|
||||||
|
Revises: e3620deb41b6
|
||||||
|
Create Date: 2025-09-16 09:26:04.082396
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import mysql
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'db036549f318'
|
||||||
|
down_revision = 'e3620deb41b6'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
op.create_unique_constraint(None, 'airport', ['openaip_id'])
|
||||||
|
op.create_index(op.f('ix_flight_turn_point_order'), 'flight_turn_point', ['order'], unique=False)
|
||||||
|
op.alter_column(
|
||||||
|
"weather_info", "datetime", new_column_name="date_time", existing_type=sa.DateTime, nullable=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
op.alter_column(
|
||||||
|
"weather_info", "date_time", new_column_name="datetime",
|
||||||
|
existing_type=sa.DateTime, nullable=False
|
||||||
|
)
|
||||||
|
|
||||||
|
op.drop_index(op.f('ix_flight_turn_point_order'), table_name='flight_turn_point')
|
||||||
|
op.drop_constraint(None, 'airport', type_='unique')
|
||||||
|
# ### end Alembic commands ###
|
||||||
+1
-1
@@ -2,7 +2,7 @@ import os
|
|||||||
|
|
||||||
# https://docs.gunicorn.org/en/stable/settings.html#settings
|
# https://docs.gunicorn.org/en/stable/settings.html#settings
|
||||||
|
|
||||||
workers = os.cpu_count()
|
workers = 1 if os.environ.get("APP_ENV") == "development" else os.cpu_count()
|
||||||
bind = "0.0.0.0:8000"
|
bind = "0.0.0.0:8000"
|
||||||
worker_class = "uvicorn.workers.UvicornWorker"
|
worker_class = "uvicorn.workers.UvicornWorker"
|
||||||
worker_connections = 1000 # default
|
worker_connections = 1000 # default
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ services:
|
|||||||
- 3306:3306
|
- 3306:3306
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
|
environment:
|
||||||
|
MARIADB_ROOT_PASSWORD: "rootroot"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
# - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
# - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
||||||
- db-data:/var/lib/mysql:rw
|
- db-data:/var/lib/mysql:rw
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Literal
|
from typing import Literal, Any
|
||||||
from database import models
|
from database import models
|
||||||
from database.transaction import get_session
|
from database.transaction import get_session
|
||||||
from external.weather import weather_api
|
from external.weather import weather_api
|
||||||
from logger import log
|
from logger import log
|
||||||
|
|
||||||
|
|
||||||
async def get_weather(date_time: datetime, gps: tuple[float, float]):
|
async def get_weather(date_time: datetime | str, gps: tuple[float, float]) -> dict[str, Any] | None:
|
||||||
try:
|
try:
|
||||||
weather = await weather_api.get_weather_for_hour(date_time.astimezone(), gps=gps)
|
weather = await weather_api.get_weather_for_hour(date_time.astimezone(), gps=gps)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -14,7 +14,7 @@ async def get_weather(date_time: datetime, gps: tuple[float, float]):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"datetime": date_time, # nemuzu pouzit weather['datetime'], protoze to mi vraci jen cele hodiny
|
"date_time": 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'],
|
||||||
|
|||||||
@@ -1,482 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
import datetime
|
|
||||||
from typing import Set, List
|
|
||||||
from sqlalchemy import String, DateTime, ForeignKey, Text, Integer, func, Table, Column, Boolean, select, Float, Enum
|
|
||||||
from sqlalchemy.dialects.mysql import JSON
|
|
||||||
from sqlalchemy.orm import Mapped, relationship, mapped_column, DeclarativeBase
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
|
||||||
|
|
||||||
|
|
||||||
class BaseModel(DeclarativeBase):
|
|
||||||
excluded_columns_in_dict = ("deleted",)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _get_column_names(cls):
|
|
||||||
return [col.name for col in cls.__table__.columns]
|
|
||||||
|
|
||||||
def as_dict(self):
|
|
||||||
return {c: getattr(self, c) for c in self._get_column_names() if c not in self.excluded_columns_in_dict}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
async def get_one(cls, db_session: AsyncSession, **kwargs):
|
|
||||||
return (await db_session.scalars(select(cls).filter_by(**kwargs))).one()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
async def create(cls, db_session: AsyncSession, data: dict):
|
|
||||||
model = cls(**{col: data[col] for col in cls._get_column_names() if col in data})
|
|
||||||
db_session.add(model)
|
|
||||||
await db_session.flush()
|
|
||||||
|
|
||||||
return model
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
async def update(cls, db_session: AsyncSession, data: dict, obj: BaseModel = None, id: int = None):
|
|
||||||
if not obj and not id:
|
|
||||||
raise ValueError("Provide either obj or id!")
|
|
||||||
|
|
||||||
if not obj:
|
|
||||||
obj = await cls.get_one(db_session, id=id)
|
|
||||||
for key, value in data.items():
|
|
||||||
if key in cls._get_column_names() and getattr(obj, key) != value:
|
|
||||||
setattr(obj, key, value)
|
|
||||||
|
|
||||||
return obj
|
|
||||||
|
|
||||||
|
|
||||||
user_is_in_organization = Table(
|
|
||||||
"user_is_in_organization",
|
|
||||||
BaseModel.metadata,
|
|
||||||
Column("user_id", Integer, ForeignKey("user.id"), primary_key=True),
|
|
||||||
Column("organization_id", Integer, ForeignKey("organization.id"), primary_key=True)
|
|
||||||
)
|
|
||||||
|
|
||||||
flight_has_copilot = Table(
|
|
||||||
"flight_has_copilot",
|
|
||||||
BaseModel.metadata,
|
|
||||||
Column("flight_id", ForeignKey("flight.id"), primary_key=True),
|
|
||||||
Column("copilot_id", ForeignKey("copilot.id"), primary_key=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",
|
|
||||||
BaseModel.metadata,
|
|
||||||
Column("copilot_id", ForeignKey("copilot.id"), primary_key=True),
|
|
||||||
Column("photo_id", ForeignKey("photo.id"), primary_key=True),
|
|
||||||
)
|
|
||||||
|
|
||||||
airport_has_reporting_point = Table(
|
|
||||||
"airport_has_reporting_point",
|
|
||||||
BaseModel.metadata,
|
|
||||||
Column("airport_id", ForeignKey("airport.id"), primary_key=True),
|
|
||||||
Column("reporting_point_id", ForeignKey("reporting_point.id"), primary_key=True),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Airspace(BaseModel):
|
|
||||||
__tablename__ = "airspace"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
country: Mapped[str] = mapped_column(String(8), nullable=False, index=True)
|
|
||||||
name: Mapped[str] = mapped_column(String(128), nullable=False, unique=True)
|
|
||||||
type: Mapped[str] = mapped_column(String(8), nullable=False, index=True)
|
|
||||||
lower_limit: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
||||||
lower_alt_unit: Mapped[str] = mapped_column(String(8), nullable=False)
|
|
||||||
upper_limit: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
||||||
upper_alt_unit: Mapped[str] = mapped_column(String(8), nullable=False)
|
|
||||||
bounds: Mapped[list[tuple[float, float]]] = mapped_column(JSON())
|
|
||||||
|
|
||||||
|
|
||||||
class FlightPlan(BaseModel):
|
|
||||||
__tablename__ = "flight_plan"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
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_editable_by_copilot: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
|
||||||
track_id: Mapped[int] = mapped_column(Integer, ForeignKey('track.id'), nullable=True)
|
|
||||||
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
|
||||||
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_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
||||||
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[List['FlightPlanMarker']] = relationship()
|
|
||||||
created_by: Mapped['User'] = relationship()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Track(BaseModel):
|
|
||||||
__tablename__ = "track"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
bounds: Mapped[list[tuple[float, float]]] = mapped_column(JSON())
|
|
||||||
min_speed: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
max_speed: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
avg_speed: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
max_altitude: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
avg_altitude: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
total_duration: Mapped[int] = mapped_column(Integer, nullable=True, comment="Total duration in seconds")
|
|
||||||
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
||||||
|
|
||||||
flight: Mapped['Flight'] = relationship()
|
|
||||||
track_points: Mapped[list['TrackPoint']] = relationship()
|
|
||||||
|
|
||||||
|
|
||||||
class TrackPoint(BaseModel):
|
|
||||||
__tablename__ = "track_point"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
timestamp: Mapped[datetime] = mapped_column(DateTime, nullable=False, index=True)
|
|
||||||
track_id: Mapped[int] = mapped_column(Integer, ForeignKey('track.id'))
|
|
||||||
gps_latitude: Mapped[float] = mapped_column(Float, nullable=False)
|
|
||||||
gps_longitude: Mapped[float] = mapped_column(Float, nullable=False)
|
|
||||||
terrain_elevation: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
speed: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
altitude: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
magnetic_variation: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
|
|
||||||
track: Mapped['Track'] = relationship()
|
|
||||||
|
|
||||||
|
|
||||||
class FlightPlanMarker(BaseModel):
|
|
||||||
__tablename__ = "flight_plan_marker"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
flight_plan_id: Mapped[int] = mapped_column(Integer, ForeignKey('flight_plan.id'))
|
|
||||||
airport_id: Mapped[int] = mapped_column(Integer, ForeignKey("airport.id"), nullable=True)
|
|
||||||
point_of_interest_id: Mapped[int] = mapped_column(Integer, ForeignKey("point_of_interest.id"), nullable=True)
|
|
||||||
weather_info_id: Mapped[int] = mapped_column(Integer, ForeignKey('weather_info.id'), nullable=True)
|
|
||||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
||||||
type: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
||||||
position: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
||||||
gps_latitude: Mapped[float] = mapped_column(Float, nullable=False)
|
|
||||||
gps_longitude: Mapped[float] = mapped_column(Float, nullable=False)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Airport(BaseModel):
|
|
||||||
__tablename__ = "airport"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
||||||
openaip_id: Mapped[str] = mapped_column(String(32), nullable=True, unique=True)
|
|
||||||
icao_code: Mapped[str] = mapped_column(String(8), nullable=False)
|
|
||||||
gps_latitude: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
gps_longitude: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
elevation: Mapped[int] = mapped_column(Integer, nullable=True)
|
|
||||||
airport_type: Mapped[str] = mapped_column(Enum("airport", "ull", "heliport"), nullable=False, server_default='airport') # noqa
|
|
||||||
use_in_gpx_guess: Mapped[bool] = mapped_column(Boolean, server_default='1')
|
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
||||||
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'), nullable=True) # automaticky import nebude mit ID # noqa
|
|
||||||
|
|
||||||
runways: Mapped[list['Runway']] = relationship('Runway')
|
|
||||||
frequencies: Mapped[list['Frequency']] = relationship()
|
|
||||||
created_by: Mapped['User'] = relationship()
|
|
||||||
|
|
||||||
|
|
||||||
class Runway(BaseModel):
|
|
||||||
__tablename__ = "runway"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
airport_id: Mapped[int] = mapped_column(Integer, ForeignKey('airport.id'))
|
|
||||||
heading: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
||||||
designator: Mapped[str] = mapped_column(String(4), nullable=False)
|
|
||||||
surface: Mapped[str] = mapped_column(Enum("asphalt", "concrete", "grass", "other"), nullable=False, server_default="other") # noqa
|
|
||||||
length: Mapped[int] = mapped_column(Integer, nullable=True)
|
|
||||||
width: Mapped[int] = mapped_column(Integer, nullable=True)
|
|
||||||
|
|
||||||
|
|
||||||
class Frequency(BaseModel):
|
|
||||||
__tablename__ = "frequency"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
airport_id: Mapped[int] = mapped_column(Integer, ForeignKey('airport.id'), nullable=True)
|
|
||||||
airspace_id: Mapped[int] = mapped_column(Integer, ForeignKey('airspace.id'), nullable=True)
|
|
||||||
frequency: Mapped[str] = mapped_column(String(7), nullable=False)
|
|
||||||
name: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
||||||
|
|
||||||
|
|
||||||
class ReportingPoint(BaseModel):
|
|
||||||
__tablename__ = "reporting_point"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
openaip_id: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
||||||
name: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
||||||
gps_latitude: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
gps_longitude: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
|
|
||||||
|
|
||||||
class PointOfInterestType(BaseModel):
|
|
||||||
__tablename__ = "point_of_interest_type"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
||||||
icon: Mapped[str] = mapped_column(String(128), nullable=False, server_default='marker')
|
|
||||||
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
|
||||||
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
||||||
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
|
||||||
|
|
||||||
created_by: Mapped['User'] = relationship()
|
|
||||||
points_of_interest: Mapped[List[PointOfInterest]] = relationship()
|
|
||||||
|
|
||||||
|
|
||||||
class PointOfInterest(BaseModel):
|
|
||||||
__tablename__ = "point_of_interest"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
||||||
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
|
||||||
url_slug: Mapped[str] = mapped_column(String(128), nullable=False, server_default="")
|
|
||||||
title_photo_id: Mapped[int] = mapped_column(Integer, ForeignKey('photo.id'), nullable=True)
|
|
||||||
gps_latitude: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
gps_longitude: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
type_id: Mapped[int] = mapped_column(Integer, ForeignKey("point_of_interest_type.id"), nullable=True)
|
|
||||||
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
|
||||||
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
||||||
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
|
||||||
|
|
||||||
type: Mapped[PointOfInterestType] = relationship()
|
|
||||||
created_by: Mapped['User'] = relationship()
|
|
||||||
title_photo: Mapped['Photo'] = relationship(foreign_keys=[title_photo_id])
|
|
||||||
|
|
||||||
|
|
||||||
class Photo(BaseModel):
|
|
||||||
__tablename__ = "photo"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
name: Mapped[str] = mapped_column(String(128), nullable=False, server_default="")
|
|
||||||
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
|
||||||
filename: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
||||||
filename_extension: Mapped[str] = mapped_column(String(4), nullable=False)
|
|
||||||
cache_key: Mapped[str] = mapped_column(String(128), nullable=True)
|
|
||||||
width: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
||||||
height: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
||||||
exposed_at: Mapped[datetime] = mapped_column(DateTime, nullable=True)
|
|
||||||
gps_latitude: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
gps_longitude: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
gps_altitude: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
terrain_elevation: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
aircraft_id: Mapped[int] = mapped_column(Integer, ForeignKey("aircraft.id"), nullable=True)
|
|
||||||
point_of_interest_id: Mapped[int] = mapped_column(Integer, ForeignKey("point_of_interest.id"), nullable=True)
|
|
||||||
flight_id: Mapped[int] = mapped_column(Integer, ForeignKey("flight.id"), nullable=False)
|
|
||||||
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
|
||||||
created_by_copilot_id: Mapped[int] = mapped_column(Integer, ForeignKey('copilot.id'), nullable=True)
|
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
||||||
|
|
||||||
flight: Mapped['Flight'] = relationship(foreign_keys=[flight_id])
|
|
||||||
point_of_interest: Mapped['PointOfInterest'] = relationship(foreign_keys=[point_of_interest_id])
|
|
||||||
adjustment: Mapped['PhotoAdjustment'] = relationship(passive_deletes=True)
|
|
||||||
created_by: Mapped['User'] = relationship()
|
|
||||||
aircraft: Mapped['Aircraft'] = relationship(foreign_keys=[aircraft_id])
|
|
||||||
copilots: Mapped[List['Copilot']] = relationship(secondary=copilot_has_photo)
|
|
||||||
|
|
||||||
|
|
||||||
class PhotoAdjustment(BaseModel):
|
|
||||||
__tablename__ = "photo_adjustment"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
photo_id: Mapped[int] = mapped_column(Integer, ForeignKey('photo.id', ondelete='CASCADE'), nullable=False)
|
|
||||||
rotate: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
contrast: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
brightness: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
saturation: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
sharpness: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
|
|
||||||
crop_left: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
crop_top: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
crop_width: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
crop_height: Mapped[float] = mapped_column(Float, nullable=True)
|
|
||||||
|
|
||||||
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
||||||
photo: Mapped['Photo'] = relationship()
|
|
||||||
|
|
||||||
|
|
||||||
class Aircraft(BaseModel):
|
|
||||||
__tablename__ = "aircraft"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
call_sign: Mapped[str] = mapped_column(String(16), nullable=False)
|
|
||||||
title_photo_id: Mapped[int] = mapped_column(Integer, ForeignKey('photo.id'), nullable=True)
|
|
||||||
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
|
||||||
manufacturer: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
|
||||||
model: Mapped[str] = mapped_column(String(30), nullable=False, server_default="")
|
|
||||||
seats: Mapped[str] = mapped_column(Integer, nullable=False)
|
|
||||||
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
|
||||||
organization_id: Mapped[int] = mapped_column(Integer, ForeignKey('organization.id'), nullable=True)
|
|
||||||
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'), nullable=False)
|
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
||||||
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
|
||||||
|
|
||||||
organization: Mapped['Organization'] = relationship()
|
|
||||||
flights: Mapped[Set['Flight']] = relationship()
|
|
||||||
created_by: Mapped['User'] = relationship()
|
|
||||||
|
|
||||||
|
|
||||||
class Organization(BaseModel):
|
|
||||||
__tablename__ = "organization"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
||||||
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
||||||
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
|
||||||
|
|
||||||
users: Mapped[Set['User']] = relationship(secondary=user_is_in_organization)
|
|
||||||
created_by: Mapped['User'] = relationship()
|
|
||||||
|
|
||||||
|
|
||||||
class FlightTurnPoint(BaseModel):
|
|
||||||
__tablename__ = "flight_turn_point"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
flight_id: Mapped[int] = mapped_column(Integer, ForeignKey("flight.id"), nullable=False)
|
|
||||||
point_of_interest_id: Mapped[int] = mapped_column(Integer, ForeignKey("point_of_interest.id"), nullable=True)
|
|
||||||
airport_id: Mapped[int] = mapped_column(Integer, ForeignKey("airport.id"), nullable=True)
|
|
||||||
landing_duration: Mapped[int] = mapped_column(Integer, nullable=True)
|
|
||||||
order: Mapped[int] = mapped_column(Integer, index=True)
|
|
||||||
|
|
||||||
flight: Mapped['Flight'] = relationship()
|
|
||||||
point_of_interest: Mapped['PointOfInterest'] = relationship()
|
|
||||||
airport: Mapped['Airport'] = relationship()
|
|
||||||
|
|
||||||
|
|
||||||
class WeatherInfo(BaseModel):
|
|
||||||
__tablename__ = "weather_info"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
qnh: Mapped[int] = mapped_column(Integer, nullable=True)
|
|
||||||
temperature_surface: Mapped[Float] = mapped_column(Float, nullable=True)
|
|
||||||
dewpoint_surface: Mapped[Float] = mapped_column(Float, nullable=True)
|
|
||||||
rain: Mapped[Float] = mapped_column(Float, nullable=True)
|
|
||||||
cloudcover_low: Mapped[Float] = mapped_column(Float, nullable=True)
|
|
||||||
cloudcover_total: Mapped[Float] = mapped_column(Float, nullable=True)
|
|
||||||
wind_speed_surface: Mapped[Float] = mapped_column(Float, nullable=True)
|
|
||||||
wind_direction_surface: Mapped[Float] = mapped_column(Float, nullable=True)
|
|
||||||
datetime: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
|
||||||
|
|
||||||
|
|
||||||
class Event(BaseModel):
|
|
||||||
__tablename__ = "event"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
||||||
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
|
||||||
url_slug: Mapped[str] = mapped_column(String(128), nullable=False, server_default="")
|
|
||||||
date_from: Mapped[datetime] = mapped_column(DateTime, nullable=True)
|
|
||||||
date_to: Mapped[datetime] = mapped_column(DateTime, nullable=True)
|
|
||||||
organization_id: Mapped[int] = mapped_column(Integer, ForeignKey('organization.id'), nullable=True)
|
|
||||||
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
|
||||||
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
||||||
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
|
||||||
|
|
||||||
organization: Mapped['Organization'] = relationship()
|
|
||||||
created_by: Mapped['User'] = relationship()
|
|
||||||
|
|
||||||
|
|
||||||
class Flight(BaseModel):
|
|
||||||
__tablename__ = "flight"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
name: Mapped[str] = mapped_column(String(128), nullable=False, server_default="")
|
|
||||||
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
|
||||||
debriefing_notes: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
|
||||||
url_slug: Mapped[str] = mapped_column(String(128), nullable=False, server_default="")
|
|
||||||
event_id: Mapped[int] = mapped_column(Integer, ForeignKey("event.id"), nullable=True)
|
|
||||||
title_photo_id: Mapped[int] = mapped_column(Integer, ForeignKey('photo.id'), nullable=True)
|
|
||||||
takeoff_airport_id: Mapped[int] = mapped_column(Integer, ForeignKey("airport.id"), nullable=True)
|
|
||||||
landing_airport_id: Mapped[int] = mapped_column(Integer, ForeignKey("airport.id"), nullable=True)
|
|
||||||
takeoff_datetime: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
|
||||||
landing_datetime: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
|
||||||
duration_total: Mapped[int] = mapped_column(Integer, nullable=True)
|
|
||||||
duration_pic: Mapped[int] = mapped_column(Integer, nullable=True)
|
|
||||||
flight_plan_id: Mapped[int] = mapped_column(Integer, ForeignKey('flight_plan.id'), nullable=True)
|
|
||||||
track_id: Mapped[int] = mapped_column(Integer, ForeignKey('track.id'), nullable=True)
|
|
||||||
gpx_track_filename: Mapped[str] = mapped_column(String(128), nullable=True) # deprecated
|
|
||||||
has_terrain_elevation: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) # deprecated
|
|
||||||
aircraft_id: Mapped[int] = mapped_column(Integer, ForeignKey('aircraft.id'))
|
|
||||||
takeoff_weather_info_id: Mapped[int] = mapped_column(Integer, ForeignKey('weather_info.id'), nullable=True)
|
|
||||||
landing_weather_info_id: Mapped[int] = mapped_column(Integer, ForeignKey('weather_info.id'), nullable=True)
|
|
||||||
landings: Mapped[int] = mapped_column(Integer, default=1)
|
|
||||||
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
|
||||||
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
||||||
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
|
||||||
|
|
||||||
takeoff_airport: Mapped['Airport'] = relationship(foreign_keys=[takeoff_airport_id])
|
|
||||||
landing_airport: Mapped['Airport'] = relationship(foreign_keys=[landing_airport_id])
|
|
||||||
weather_info_landing: Mapped[WeatherInfo] = relationship(foreign_keys=[landing_weather_info_id])
|
|
||||||
weather_info_takeoff: Mapped[WeatherInfo] = relationship(foreign_keys=[takeoff_weather_info_id])
|
|
||||||
turn_points: Mapped[list['FlightTurnPoint']] = relationship()
|
|
||||||
event: Mapped['Event'] = relationship()
|
|
||||||
copilots: Mapped[List['Copilot']] = relationship(secondary=flight_has_copilot)
|
|
||||||
aircraft: Mapped['Aircraft'] = relationship()
|
|
||||||
photos: Mapped[List['Photo']] = relationship(foreign_keys=[Photo.flight_id])
|
|
||||||
created_by: Mapped['User'] = relationship()
|
|
||||||
title_photo: Mapped['Photo'] = relationship(foreign_keys=[title_photo_id])
|
|
||||||
track: Mapped['Track'] = relationship()
|
|
||||||
|
|
||||||
class Copilot(BaseModel):
|
|
||||||
__tablename__ = "copilot"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
||||||
url_slug: Mapped[str] = mapped_column(String(128), nullable=False, server_default="")
|
|
||||||
title_photo_id: Mapped[int] = mapped_column(Integer, ForeignKey('photo.id'), nullable=True)
|
|
||||||
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
|
||||||
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
||||||
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
|
||||||
|
|
||||||
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()
|
|
||||||
photos: Mapped[List['Photo']] = relationship(secondary=copilot_has_photo)
|
|
||||||
title_photo: Mapped['Photo'] = relationship(foreign_keys=[title_photo_id])
|
|
||||||
|
|
||||||
|
|
||||||
class User(BaseModel):
|
|
||||||
__tablename__ = "user"
|
|
||||||
excluded_columns_in_dict = ('password_hashed',)
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
email: Mapped[str] = mapped_column(String(128), nullable=False, unique=True)
|
|
||||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
||||||
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
|
||||||
public_username: Mapped[str] = mapped_column(String(128), nullable=True, unique=True)
|
|
||||||
avatar_image_filename: Mapped[str] = mapped_column(String(128), nullable=True)
|
|
||||||
title_image_filename: Mapped[str] = mapped_column(String(128), nullable=True)
|
|
||||||
password_hashed: Mapped[str] = mapped_column(String(60), nullable=False)
|
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
|
||||||
|
|
||||||
flights: Mapped[Set['Flight']] = relationship()
|
|
||||||
organizations: Mapped[Set['Organization']] = relationship(secondary=user_is_in_organization)
|
|
||||||
|
|
||||||
|
|
||||||
class PasswordResetToken(BaseModel):
|
|
||||||
__tablename__ = "password_reset_token"
|
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
|
||||||
user_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
|
||||||
token: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
||||||
valid_until: Mapped[datetime] = mapped_column(DateTime, nullable=True)
|
|
||||||
|
|
||||||
user: Mapped['User'] = relationship()
|
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
from database.models.airport import Airport, Runway, ReportingPoint, airport_has_reporting_point, Frequency
|
||||||
|
from database.models.aircraft import Aircraft
|
||||||
|
from database.models.airspace import Airspace
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
from database.models.copilot import Copilot, copilot_has_photo
|
||||||
|
from database.models.event import Event
|
||||||
|
from database.models.flight import Flight, FlightTurnPoint, Track, TrackPoint, flight_has_copilot
|
||||||
|
from database.models.flight_plan import FlightPlan, flight_plan_has_copilot, FlightPlanMarker
|
||||||
|
from database.models.orgnization import Organization
|
||||||
|
from database.models.password_reset_token import PasswordResetToken
|
||||||
|
from database.models.photo import PhotoAdjustment, Photo
|
||||||
|
from database.models.point_of_interest import PointOfInterest, PointOfInterestType
|
||||||
|
from database.models.user import User, user_is_in_organization
|
||||||
|
from database.models.weather_info import WeatherInfo
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"Aircraft",
|
||||||
|
"Airport",
|
||||||
|
"Runway",
|
||||||
|
"ReportingPoint",
|
||||||
|
"Airspace",
|
||||||
|
"BaseModel",
|
||||||
|
"Copilot",
|
||||||
|
"Event",
|
||||||
|
"Flight",
|
||||||
|
"FlightTurnPoint",
|
||||||
|
"FlightPlan",
|
||||||
|
"FlightPlanMarker",
|
||||||
|
"Frequency",
|
||||||
|
"Track",
|
||||||
|
"TrackPoint",
|
||||||
|
"Organization",
|
||||||
|
"PasswordResetToken",
|
||||||
|
"Photo",
|
||||||
|
"PhotoAdjustment",
|
||||||
|
"PointOfInterest",
|
||||||
|
"PointOfInterestType",
|
||||||
|
"WeatherInfo",
|
||||||
|
"User",
|
||||||
|
"airport_has_reporting_point",
|
||||||
|
"flight_has_copilot",
|
||||||
|
"flight_plan_has_copilot",
|
||||||
|
"user_is_in_organization",
|
||||||
|
"copilot_has_photo",
|
||||||
|
]
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy import String, Boolean, Table, ForeignKey, Column, Integer, Text, DateTime, func, Float
|
||||||
|
from sqlalchemy.orm import mapped_column, Mapped, relationship
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Aircraft(BaseModel):
|
||||||
|
__tablename__ = "aircraft"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
call_sign: Mapped[str] = mapped_column(String(16), nullable=False)
|
||||||
|
title_photo_id: Mapped[int] = mapped_column(Integer, ForeignKey('photo.id'), nullable=True)
|
||||||
|
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
||||||
|
manufacturer: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
||||||
|
model: Mapped[str] = mapped_column(String(30), nullable=False, server_default="")
|
||||||
|
seats: Mapped[str] = mapped_column(Integer, nullable=False)
|
||||||
|
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
||||||
|
organization_id: Mapped[int] = mapped_column(Integer, ForeignKey('organization.id'), nullable=True)
|
||||||
|
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'), nullable=False)
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||||
|
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
||||||
|
|
||||||
|
organization: Mapped['Organization'] = relationship()
|
||||||
|
flights: Mapped[set['Flight']] = relationship()
|
||||||
|
created_by: Mapped['User'] = relationship()
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy import String, Boolean, Table, ForeignKey, Column, Integer, Text, DateTime, func, Float, Enum
|
||||||
|
from sqlalchemy.orm import mapped_column, Mapped, relationship
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
|
||||||
|
airport_has_reporting_point = Table(
|
||||||
|
"airport_has_reporting_point",
|
||||||
|
BaseModel.metadata,
|
||||||
|
Column("airport_id", ForeignKey("airport.id"), primary_key=True),
|
||||||
|
Column("reporting_point_id", ForeignKey("reporting_point.id"), primary_key=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Airport(BaseModel):
|
||||||
|
__tablename__ = "airport"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||||
|
openaip_id: Mapped[str] = mapped_column(String(32), nullable=True, unique=True)
|
||||||
|
icao_code: Mapped[str] = mapped_column(String(8), nullable=False)
|
||||||
|
gps_latitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
gps_longitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
elevation: Mapped[int] = mapped_column(Integer, nullable=True)
|
||||||
|
airport_type: Mapped[str] = mapped_column(
|
||||||
|
Enum("airport", "ull", "heliport"),
|
||||||
|
nullable=False,
|
||||||
|
server_default='airport'
|
||||||
|
)
|
||||||
|
use_in_gpx_guess: Mapped[bool] = mapped_column(Boolean, server_default='1')
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||||
|
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'), nullable=True) # automaticky import nebude mit ID # noqa
|
||||||
|
|
||||||
|
runways: Mapped[list['Runway']] = relationship('Runway')
|
||||||
|
frequencies: Mapped[list['Frequency']] = relationship()
|
||||||
|
created_by: Mapped['User'] = relationship()
|
||||||
|
|
||||||
|
|
||||||
|
class Runway(BaseModel):
|
||||||
|
__tablename__ = "runway"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
airport_id: Mapped[int] = mapped_column(Integer, ForeignKey('airport.id'))
|
||||||
|
heading: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||||
|
designator: Mapped[str] = mapped_column(String(4), nullable=False)
|
||||||
|
surface: Mapped[str] = mapped_column(Enum("asphalt", "concrete", "grass", "other"), nullable=False, server_default="other") # noqa
|
||||||
|
length: Mapped[int] = mapped_column(Integer, nullable=True)
|
||||||
|
width: Mapped[int] = mapped_column(Integer, nullable=True)
|
||||||
|
|
||||||
|
|
||||||
|
class Frequency(BaseModel):
|
||||||
|
__tablename__ = "frequency"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
airport_id: Mapped[int] = mapped_column(Integer, ForeignKey('airport.id'), nullable=True)
|
||||||
|
airspace_id: Mapped[int] = mapped_column(Integer, ForeignKey('airspace.id'), nullable=True)
|
||||||
|
frequency: Mapped[str] = mapped_column(String(7), nullable=False)
|
||||||
|
name: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class ReportingPoint(BaseModel):
|
||||||
|
__tablename__ = "reporting_point"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
openaip_id: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||||
|
name: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||||
|
gps_latitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
gps_longitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
from sqlalchemy import String, JSON
|
||||||
|
from sqlalchemy.orm import mapped_column, Mapped
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Airspace(BaseModel):
|
||||||
|
__tablename__ = "airspace"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
country: Mapped[str] = mapped_column(String(8), nullable=False, index=True)
|
||||||
|
name: Mapped[str] = mapped_column(String(128), nullable=False, unique=True)
|
||||||
|
type: Mapped[str] = mapped_column(String(8), nullable=False, index=True)
|
||||||
|
lower_limit: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||||
|
lower_alt_unit: Mapped[str] = mapped_column(String(8), nullable=False)
|
||||||
|
upper_limit: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||||
|
upper_alt_unit: Mapped[str] = mapped_column(String(8), nullable=False)
|
||||||
|
bounds: Mapped[list[tuple[float, float]]] = mapped_column(JSON())
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
from sqlalchemy import select
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from sqlalchemy.orm import DeclarativeBase
|
||||||
|
|
||||||
|
|
||||||
|
class BaseModel(DeclarativeBase):
|
||||||
|
excluded_columns_in_dict = ("deleted",)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_column_names(cls):
|
||||||
|
return [col.name for col in cls.__table__.columns]
|
||||||
|
|
||||||
|
def as_dict(self):
|
||||||
|
return {c: getattr(self, c) for c in self._get_column_names() if c not in self.excluded_columns_in_dict}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_one(cls, db_session: AsyncSession, **kwargs):
|
||||||
|
return (await db_session.scalars(select(cls).filter_by(**kwargs))).one()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def create(cls, db_session: AsyncSession, data: dict):
|
||||||
|
model = cls(**{col: data[col] for col in cls._get_column_names() if col in data})
|
||||||
|
db_session.add(model)
|
||||||
|
await db_session.flush()
|
||||||
|
|
||||||
|
return model
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def update(cls, db_session: AsyncSession, data: dict, obj: BaseModel = None, id: int = None):
|
||||||
|
if not obj and not id:
|
||||||
|
raise ValueError("Provide either obj or id!")
|
||||||
|
|
||||||
|
if not obj:
|
||||||
|
obj = await cls.get_one(db_session, id=id)
|
||||||
|
for key, value in data.items():
|
||||||
|
if key in cls._get_column_names() and getattr(obj, key) != value:
|
||||||
|
setattr(obj, key, value)
|
||||||
|
|
||||||
|
return obj
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy import String, Boolean, Table, ForeignKey, Column, Integer, DateTime, func
|
||||||
|
from sqlalchemy.orm import mapped_column, Mapped, relationship
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
from database.models.flight import flight_has_copilot
|
||||||
|
from database.models.flight_plan import flight_plan_has_copilot
|
||||||
|
|
||||||
|
copilot_has_photo = Table(
|
||||||
|
"copilot_has_photo",
|
||||||
|
BaseModel.metadata,
|
||||||
|
Column("copilot_id", ForeignKey("copilot.id"), primary_key=True),
|
||||||
|
Column("photo_id", ForeignKey("photo.id"), primary_key=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Copilot(BaseModel):
|
||||||
|
__tablename__ = "copilot"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||||
|
url_slug: Mapped[str] = mapped_column(String(128), nullable=False, server_default="")
|
||||||
|
title_photo_id: Mapped[int] = mapped_column(Integer, ForeignKey('photo.id'), nullable=True)
|
||||||
|
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
||||||
|
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||||
|
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
||||||
|
|
||||||
|
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()
|
||||||
|
photos: Mapped[list['Photo']] = relationship(secondary=copilot_has_photo)
|
||||||
|
title_photo: Mapped['Photo'] = relationship(foreign_keys=[title_photo_id])
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy import String, Boolean, Table, ForeignKey, Column, Integer, Text, DateTime, func, Float
|
||||||
|
from sqlalchemy.orm import mapped_column, Mapped, relationship
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Event(BaseModel):
|
||||||
|
__tablename__ = "event"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||||
|
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
||||||
|
url_slug: Mapped[str] = mapped_column(String(128), nullable=False, server_default="")
|
||||||
|
date_from: Mapped[datetime] = mapped_column(DateTime, nullable=True)
|
||||||
|
date_to: Mapped[datetime] = mapped_column(DateTime, nullable=True)
|
||||||
|
organization_id: Mapped[int] = mapped_column(Integer, ForeignKey('organization.id'), nullable=True)
|
||||||
|
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
||||||
|
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||||
|
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
||||||
|
|
||||||
|
organization: Mapped['Organization'] = relationship()
|
||||||
|
created_by: Mapped['User'] = relationship()
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy import String, Boolean, Table, ForeignKey, Column, Integer, Text, DateTime, func, Float, JSON
|
||||||
|
from sqlalchemy.orm import mapped_column, Mapped, relationship
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
|
||||||
|
flight_has_copilot = Table(
|
||||||
|
"flight_has_copilot",
|
||||||
|
BaseModel.metadata,
|
||||||
|
Column("flight_id", ForeignKey("flight.id"), primary_key=True),
|
||||||
|
Column("copilot_id", ForeignKey("copilot.id"), primary_key=True),
|
||||||
|
Column("token", String(64), unique=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FlightTurnPoint(BaseModel):
|
||||||
|
__tablename__ = "flight_turn_point"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
flight_id: Mapped[int] = mapped_column(Integer, ForeignKey("flight.id"), nullable=False)
|
||||||
|
point_of_interest_id: Mapped[int] = mapped_column(Integer, ForeignKey("point_of_interest.id"), nullable=True)
|
||||||
|
airport_id: Mapped[int] = mapped_column(Integer, ForeignKey("airport.id"), nullable=True)
|
||||||
|
landing_duration: Mapped[int] = mapped_column(Integer, nullable=True)
|
||||||
|
order: Mapped[int] = mapped_column(Integer, index=True)
|
||||||
|
|
||||||
|
flight: Mapped['Flight'] = relationship()
|
||||||
|
point_of_interest: Mapped['PointOfInterest'] = relationship()
|
||||||
|
airport: Mapped['Airport'] = relationship()
|
||||||
|
|
||||||
|
|
||||||
|
class Flight(BaseModel):
|
||||||
|
__tablename__ = "flight"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
name: Mapped[str] = mapped_column(String(128), nullable=False, server_default="")
|
||||||
|
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
||||||
|
debriefing_notes: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
||||||
|
url_slug: Mapped[str] = mapped_column(String(128), nullable=False, server_default="")
|
||||||
|
event_id: Mapped[int] = mapped_column(Integer, ForeignKey("event.id"), nullable=True)
|
||||||
|
title_photo_id: Mapped[int] = mapped_column(Integer, ForeignKey('photo.id'), nullable=True)
|
||||||
|
takeoff_airport_id: Mapped[int] = mapped_column(Integer, ForeignKey("airport.id"), nullable=True)
|
||||||
|
landing_airport_id: Mapped[int] = mapped_column(Integer, ForeignKey("airport.id"), nullable=True)
|
||||||
|
takeoff_datetime: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
||||||
|
landing_datetime: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
||||||
|
duration_total: Mapped[int] = mapped_column(Integer, nullable=True)
|
||||||
|
duration_pic: Mapped[int] = mapped_column(Integer, nullable=True)
|
||||||
|
flight_plan_id: Mapped[int] = mapped_column(Integer, ForeignKey('flight_plan.id'), nullable=True)
|
||||||
|
track_id: Mapped[int] = mapped_column(Integer, ForeignKey('track.id'), nullable=True)
|
||||||
|
gpx_track_filename: Mapped[str] = mapped_column(String(128), nullable=True) # deprecated
|
||||||
|
has_terrain_elevation: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) # deprecated
|
||||||
|
aircraft_id: Mapped[int] = mapped_column(Integer, ForeignKey('aircraft.id'))
|
||||||
|
takeoff_weather_info_id: Mapped[int] = mapped_column(Integer, ForeignKey('weather_info.id'), nullable=True)
|
||||||
|
landing_weather_info_id: Mapped[int] = mapped_column(Integer, ForeignKey('weather_info.id'), nullable=True)
|
||||||
|
landings: Mapped[int] = mapped_column(Integer, default=1)
|
||||||
|
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
||||||
|
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||||
|
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
||||||
|
|
||||||
|
takeoff_airport: Mapped['Airport'] = relationship(foreign_keys=[takeoff_airport_id])
|
||||||
|
landing_airport: Mapped['Airport'] = relationship(foreign_keys=[landing_airport_id])
|
||||||
|
weather_info_landing: Mapped['WeatherInfo'] = relationship(foreign_keys=[landing_weather_info_id])
|
||||||
|
weather_info_takeoff: Mapped['WeatherInfo'] = relationship(foreign_keys=[takeoff_weather_info_id])
|
||||||
|
turn_points: Mapped[list['FlightTurnPoint']] = relationship()
|
||||||
|
event: Mapped['Event'] = relationship()
|
||||||
|
copilots: Mapped[list['Copilot']] = relationship(secondary=flight_has_copilot)
|
||||||
|
aircraft: Mapped['Aircraft'] = relationship()
|
||||||
|
created_by: Mapped['User'] = relationship()
|
||||||
|
title_photo: Mapped['Photo'] = relationship(foreign_keys=[title_photo_id])
|
||||||
|
track: Mapped['Track'] = relationship()
|
||||||
|
|
||||||
|
|
||||||
|
class Track(BaseModel):
|
||||||
|
__tablename__ = "track"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
bounds: Mapped[list[tuple[float, float]]] = mapped_column(JSON())
|
||||||
|
min_speed: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
max_speed: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
avg_speed: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
max_altitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
avg_altitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
total_duration: Mapped[int] = mapped_column(Integer, nullable=True, comment="Total duration in seconds")
|
||||||
|
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||||
|
|
||||||
|
flight: Mapped['Flight'] = relationship()
|
||||||
|
track_points: Mapped[list['TrackPoint']] = relationship()
|
||||||
|
|
||||||
|
|
||||||
|
class TrackPoint(BaseModel):
|
||||||
|
__tablename__ = "track_point"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
timestamp: Mapped[datetime] = mapped_column(DateTime, nullable=False, index=True)
|
||||||
|
track_id: Mapped[int] = mapped_column(Integer, ForeignKey('track.id'))
|
||||||
|
gps_latitude: Mapped[float] = mapped_column(Float, nullable=False)
|
||||||
|
gps_longitude: Mapped[float] = mapped_column(Float, nullable=False)
|
||||||
|
terrain_elevation: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
speed: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
altitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
magnetic_variation: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
|
||||||
|
track: Mapped['Track'] = relationship()
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from sqlalchemy import String, Boolean, Table, ForeignKey, Column, Integer, Text, DateTime, func, Float
|
||||||
|
from sqlalchemy.orm import mapped_column, Mapped, relationship
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
|
||||||
|
class FlightPlan(BaseModel):
|
||||||
|
__tablename__ = "flight_plan"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
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_editable_by_copilot: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
||||||
|
track_id: Mapped[int] = mapped_column(Integer, ForeignKey('track.id'), nullable=True)
|
||||||
|
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
||||||
|
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_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||||
|
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[list['FlightPlanMarker']] = relationship()
|
||||||
|
created_by: Mapped['User'] = relationship()
|
||||||
|
|
||||||
|
|
||||||
|
class FlightPlanMarker(BaseModel):
|
||||||
|
__tablename__ = "flight_plan_marker"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
flight_plan_id: Mapped[int] = mapped_column(Integer, ForeignKey('flight_plan.id'))
|
||||||
|
airport_id: Mapped[int] = mapped_column(Integer, ForeignKey("airport.id"), nullable=True)
|
||||||
|
point_of_interest_id: Mapped[int] = mapped_column(Integer, ForeignKey("point_of_interest.id"), nullable=True)
|
||||||
|
weather_info_id: Mapped[int] = mapped_column(Integer, ForeignKey('weather_info.id'), nullable=True)
|
||||||
|
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||||
|
type: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||||
|
position: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||||
|
gps_latitude: Mapped[float] = mapped_column(Float, nullable=False)
|
||||||
|
gps_longitude: Mapped[float] = mapped_column(Float, nullable=False)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from sqlalchemy import String, Boolean, Table, ForeignKey, Column, Integer, Text, DateTime, func, Float
|
||||||
|
from sqlalchemy.orm import mapped_column, Mapped, relationship
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
from database.models.user import user_is_in_organization
|
||||||
|
|
||||||
|
|
||||||
|
class Organization(BaseModel):
|
||||||
|
__tablename__ = "organization"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||||
|
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||||
|
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
||||||
|
|
||||||
|
users: Mapped[set['User']] = relationship(secondary=user_is_in_organization)
|
||||||
|
created_by: Mapped['User'] = relationship()
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy import String, ForeignKey, Integer, DateTime
|
||||||
|
from sqlalchemy.orm import mapped_column, Mapped, relationship
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordResetToken(BaseModel):
|
||||||
|
__tablename__ = "password_reset_token"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
user_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
||||||
|
token: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||||
|
valid_until: Mapped[datetime] = mapped_column(DateTime, nullable=True)
|
||||||
|
|
||||||
|
user: Mapped['User'] = relationship()
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy import String, ForeignKey, Integer, Text, DateTime, func, Float
|
||||||
|
from sqlalchemy.orm import mapped_column, Mapped, relationship
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Photo(BaseModel):
|
||||||
|
__tablename__ = "photo"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
name: Mapped[str] = mapped_column(String(128), nullable=False, server_default="")
|
||||||
|
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
||||||
|
filename: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||||
|
filename_extension: Mapped[str] = mapped_column(String(4), nullable=False)
|
||||||
|
cache_key: Mapped[str] = mapped_column(String(128), nullable=True)
|
||||||
|
width: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||||
|
height: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||||
|
exposed_at: Mapped[datetime] = mapped_column(DateTime, nullable=True)
|
||||||
|
gps_latitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
gps_longitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
gps_altitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
terrain_elevation: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
aircraft_id: Mapped[int] = mapped_column(Integer, ForeignKey("aircraft.id"), nullable=True)
|
||||||
|
point_of_interest_id: Mapped[int] = mapped_column(Integer, ForeignKey("point_of_interest.id"), nullable=True)
|
||||||
|
flight_id: Mapped[int] = mapped_column(Integer, ForeignKey("flight.id"), nullable=False)
|
||||||
|
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
||||||
|
created_by_copilot_id: Mapped[int] = mapped_column(Integer, ForeignKey('copilot.id'), nullable=True)
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||||
|
|
||||||
|
flight: Mapped['Flight'] = relationship(foreign_keys=[flight_id])
|
||||||
|
point_of_interest: Mapped['PointOfInterest'] = relationship(foreign_keys=[point_of_interest_id])
|
||||||
|
adjustment: Mapped['PhotoAdjustment'] = relationship(passive_deletes=True)
|
||||||
|
created_by: Mapped['User'] = relationship()
|
||||||
|
aircraft: Mapped['Aircraft'] = relationship(foreign_keys=[aircraft_id])
|
||||||
|
# copilots: Mapped[list['Copilot']] = relationship(secondary=copilot_has_photo)
|
||||||
|
|
||||||
|
|
||||||
|
class PhotoAdjustment(BaseModel):
|
||||||
|
__tablename__ = "photo_adjustment"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
photo_id: Mapped[int] = mapped_column(Integer, ForeignKey('photo.id', ondelete='CASCADE'), nullable=False)
|
||||||
|
rotate: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
contrast: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
brightness: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
saturation: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
sharpness: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
|
||||||
|
crop_left: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
crop_top: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
crop_width: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
crop_height: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
|
||||||
|
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||||
|
photo: Mapped['Photo'] = relationship()
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy import String, Boolean, Table, ForeignKey, Column, Integer, Text, DateTime, func, Float
|
||||||
|
from sqlalchemy.orm import mapped_column, Mapped, relationship
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class PointOfInterestType(BaseModel):
|
||||||
|
__tablename__ = "point_of_interest_type"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||||
|
icon: Mapped[str] = mapped_column(String(128), nullable=False, server_default='marker')
|
||||||
|
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
||||||
|
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||||
|
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
||||||
|
|
||||||
|
created_by: Mapped['User'] = relationship()
|
||||||
|
points_of_interest: Mapped[list['PointOfInterest']] = relationship()
|
||||||
|
|
||||||
|
|
||||||
|
class PointOfInterest(BaseModel):
|
||||||
|
__tablename__ = "point_of_interest"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||||
|
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
||||||
|
url_slug: Mapped[str] = mapped_column(String(128), nullable=False, server_default="")
|
||||||
|
title_photo_id: Mapped[int] = mapped_column(Integer, ForeignKey('photo.id'), nullable=True)
|
||||||
|
gps_latitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
gps_longitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
type_id: Mapped[int] = mapped_column(Integer, ForeignKey("point_of_interest_type.id"), nullable=True)
|
||||||
|
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
||||||
|
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||||
|
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
||||||
|
|
||||||
|
type: Mapped[PointOfInterestType] = relationship()
|
||||||
|
created_by: Mapped['User'] = relationship()
|
||||||
|
title_photo: Mapped['Photo'] = relationship(foreign_keys=[title_photo_id])
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
import datetime
|
||||||
|
from typing import Set
|
||||||
|
from sqlalchemy import String, DateTime, ForeignKey, Text, Integer, func, Table, Column
|
||||||
|
from sqlalchemy.orm import Mapped, relationship, mapped_column
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
|
||||||
|
user_is_in_organization = Table(
|
||||||
|
"user_is_in_organization",
|
||||||
|
BaseModel.metadata,
|
||||||
|
Column("user_id", Integer, ForeignKey("user.id"), primary_key=True),
|
||||||
|
Column("organization_id", Integer, ForeignKey("organization.id"), primary_key=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class User(BaseModel):
|
||||||
|
__tablename__ = "user"
|
||||||
|
excluded_columns_in_dict = ('password_hashed',)
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
email: Mapped[str] = mapped_column(String(128), nullable=False, unique=True)
|
||||||
|
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||||
|
description: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
|
||||||
|
public_username: Mapped[str] = mapped_column(String(128), nullable=True, unique=True)
|
||||||
|
avatar_image_filename: Mapped[str] = mapped_column(String(128), nullable=True)
|
||||||
|
title_image_filename: Mapped[str] = mapped_column(String(128), nullable=True)
|
||||||
|
password_hashed: Mapped[str] = mapped_column(String(60), nullable=False)
|
||||||
|
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||||
|
|
||||||
|
flights: Mapped[Set['Flight']] = relationship()
|
||||||
|
organizations: Mapped[Set['Organization']] = relationship(secondary=user_is_in_organization)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy import Integer, DateTime, Float
|
||||||
|
from sqlalchemy.orm import mapped_column, Mapped
|
||||||
|
from database.models.base_model import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class WeatherInfo(BaseModel):
|
||||||
|
__tablename__ = "weather_info"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
qnh: Mapped[int] = mapped_column(Integer, nullable=True)
|
||||||
|
temperature_surface: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
dewpoint_surface: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
rain: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
cloudcover_low: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
cloudcover_total: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
wind_speed_surface: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
wind_direction_surface: Mapped[float] = mapped_column(Float, nullable=True)
|
||||||
|
date_time: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
||||||
Vendored
+8
-5
@@ -43,10 +43,13 @@ class Weather:
|
|||||||
async def download_weather_for_day(self, date: datetime.date, gps: Tuple[float, float]):
|
async def download_weather_for_day(self, date: datetime.date, gps: Tuple[float, float]):
|
||||||
url = self.get_weather_info_url(start_date=date, end_date=date, gps=gps)
|
url = self.get_weather_info_url(start_date=date, end_date=date, gps=gps)
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
try:
|
||||||
async with session.get(url) as resp:
|
async with aiohttp.ClientSession() as session:
|
||||||
resp.raise_for_status()
|
async with session.get(url) as resp:
|
||||||
return await resp.json()
|
resp.raise_for_status()
|
||||||
|
return await resp.json()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error in downloading weather: {e}, {type(e)}")
|
||||||
|
|
||||||
async def get_weather_for_hour(
|
async def get_weather_for_hour(
|
||||||
self, date_time: datetime.datetime, gps: Tuple[float, float]
|
self, date_time: datetime.datetime, gps: Tuple[float, float]
|
||||||
@@ -56,7 +59,7 @@ class Weather:
|
|||||||
# TODO: kontrola timezone!
|
# TODO: kontrola timezone!
|
||||||
idx = date_time.hour
|
idx = date_time.hour
|
||||||
result_data = {metric: data['hourly'][metric][idx] for metric in self.METRICS}
|
result_data = {metric: data['hourly'][metric][idx] for metric in self.METRICS}
|
||||||
result_data['datetime'] = datetime.datetime.strptime(data['hourly']['time'][idx], "%Y-%m-%dT%H:%M")
|
result_data['date_time'] = datetime.datetime.strptime(data['hourly']['time'][idx], "%Y-%m-%dT%H:%M")
|
||||||
|
|
||||||
return result_data
|
return result_data
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ from fastapi import BackgroundTasks, Depends, Security
|
|||||||
from fastapi_jwt import JwtAuthorizationCredentials
|
from fastapi_jwt import JwtAuthorizationCredentials
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from strawberry.fastapi import BaseContext
|
from strawberry.fastapi import BaseContext
|
||||||
|
|
||||||
|
from logger import log
|
||||||
from database import async_session, models
|
from database import async_session, models
|
||||||
from jwt import access_security
|
from jwt import access_security
|
||||||
|
|
||||||
@@ -20,6 +22,8 @@ async def setup_graphql_context(credentials: JwtAuthorizationCredentials = Secur
|
|||||||
user_id = credentials['id'] if credentials else None
|
user_id = credentials['id'] if credentials else None
|
||||||
organization_ids = set()
|
organization_ids = set()
|
||||||
|
|
||||||
|
log.error(user_id)
|
||||||
|
|
||||||
if user_id:
|
if user_id:
|
||||||
async with async_session() as db:
|
async with async_session() as db:
|
||||||
organization_ids = set((await db.scalars(
|
organization_ids = set((await db.scalars(
|
||||||
|
|||||||
@@ -26,10 +26,14 @@ class BaseDataloader:
|
|||||||
|
|
||||||
class SingleModelByIdDataloader(BaseDataloader):
|
class SingleModelByIdDataloader(BaseDataloader):
|
||||||
async def load(self, ids: list[int]):
|
async def load(self, ids: list[int]):
|
||||||
|
ids_set = {id_ for id_ in set(ids) if id_ is not None}
|
||||||
|
if not ids_set:
|
||||||
|
return [None for _ in ids]
|
||||||
|
|
||||||
async with async_session() as session:
|
async with async_session() as session:
|
||||||
query = (
|
query = (
|
||||||
self.query_builder.get_simple_query(extra_select=[self.relationship_column], include_deleted=True)
|
self.query_builder.get_simple_query(extra_select=[self.relationship_column], include_deleted=True)
|
||||||
.filter(self.relationship_column.in_(set(ids)))
|
.filter(self.relationship_column.in_(ids_set))
|
||||||
.filter(*self.filters)
|
.filter(*self.filters)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -62,13 +66,13 @@ class MultiModelsDataloader(BaseDataloader):
|
|||||||
order_by = [model.id.desc()] # defaultne radit od nejnovejsich zaznamu
|
order_by = [model.id.desc()] # defaultne radit od nejnovejsich zaznamu
|
||||||
self.order_by = order_by
|
self.order_by = order_by
|
||||||
|
|
||||||
def get_query(self, ids: list[int]):
|
def get_query(self, ids: set[int]):
|
||||||
query = (
|
query = (
|
||||||
self.query_builder.get_simple_query(
|
self.query_builder.get_simple_query(
|
||||||
extra_select=[self.relationship_column] + self.extra_select,
|
extra_select=[self.relationship_column] + self.extra_select,
|
||||||
order_by=self.order_by
|
order_by=self.order_by
|
||||||
)
|
)
|
||||||
.filter(self.relationship_column.in_(set(ids)))
|
.filter(self.relationship_column.in_(ids))
|
||||||
.filter(*self.filters)
|
.filter(*self.filters)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -80,8 +84,12 @@ class MultiModelsDataloader(BaseDataloader):
|
|||||||
|
|
||||||
return query
|
return query
|
||||||
|
|
||||||
async def load(self, ids: list[int]):
|
async def load(self, ids: list[int]) -> list:
|
||||||
query = self.get_query(ids)
|
ids_set = {id_ for id_ in set(ids) if id_ is not None}
|
||||||
|
if not ids_set:
|
||||||
|
return [[] for _ in ids]
|
||||||
|
|
||||||
|
query = self.get_query(ids_set)
|
||||||
|
|
||||||
async with async_session() as db:
|
async with async_session() as db:
|
||||||
data = (await db.execute(query)).all()
|
data = (await db.execute(query)).all()
|
||||||
|
|||||||
+12
-14
@@ -2,27 +2,25 @@ import logging
|
|||||||
import sys
|
import sys
|
||||||
from colorlog import ColoredFormatter
|
from colorlog import ColoredFormatter
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
log.setLevel(logging.DEBUG)
|
log.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
stdoutHandler = logging.StreamHandler(stream=sys.stdout)
|
stdoutHandler = logging.StreamHandler(stream=sys.stdout)
|
||||||
stdoutHandler.setLevel(logging.DEBUG)
|
stdoutHandler.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
fmt = ColoredFormatter(
|
fmt = ColoredFormatter(
|
||||||
"%(log_color)s[%(levelname)s]%(reset)s %(blue)s%(message)s%(reset)s %(light_black)s[%(filename)s:%(lineno)d]]%(reset)s",
|
"%(log_color)s[%(levelname)s]%(reset)s %(blue)s%(message)s%(reset)s %(light_black)s[%(filename)s:%(lineno)d]]%(reset)s",
|
||||||
datefmt=None,
|
datefmt=None,
|
||||||
reset=True,
|
reset=True,
|
||||||
log_colors={
|
log_colors={
|
||||||
'DEBUG': 'cyan',
|
'DEBUG': 'cyan',
|
||||||
'INFO': 'green',
|
'INFO': 'green',
|
||||||
'WARNING': 'yellow',
|
'WARNING': 'yellow',
|
||||||
'ERROR': 'red',
|
'ERROR': 'red',
|
||||||
'CRITICAL': 'red,bg_white',
|
'CRITICAL': 'red,bg_white',
|
||||||
},
|
},
|
||||||
secondary_log_colors={},
|
secondary_log_colors={},
|
||||||
style='%'
|
style='%'
|
||||||
)
|
)
|
||||||
stdoutHandler.setFormatter(fmt)
|
stdoutHandler.setFormatter(fmt)
|
||||||
log.addHandler(stdoutHandler)
|
log.addHandler(stdoutHandler)
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ class App:
|
|||||||
async def sitemap():
|
async def sitemap():
|
||||||
return await SitemapEndpoint().on_get()
|
return await SitemapEndpoint().on_get()
|
||||||
|
|
||||||
|
|
||||||
# musi byt na konci
|
# musi byt na konci
|
||||||
app.include_router(auth.router)
|
app.include_router(auth.router)
|
||||||
app.include_router(forgotten_password.router)
|
app.include_router(forgotten_password.router)
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
import os
|
import os
|
||||||
from typing import Optional
|
|
||||||
from config import API_URL
|
from config import API_URL
|
||||||
from logger import log
|
from logger import log
|
||||||
|
|
||||||
PHOTO_BASE_PATH = ""
|
|
||||||
AIRCRAFT_BASE_PATH = ""
|
|
||||||
FLIGHT_BASE_PATH = ""
|
|
||||||
FLIGHT_GPX_TRACK_PATH = "/app/uploads/tracks"
|
FLIGHT_GPX_TRACK_PATH = "/app/uploads/tracks"
|
||||||
AIRCRAFT_UPLOAD_DEST_PATH = "/app/uploads/aircrafts/"
|
|
||||||
|
|
||||||
|
|
||||||
def get_photo_basepath(flight_id: int) -> str:
|
def get_photo_basepath(flight_id: int) -> str:
|
||||||
|
|||||||
+1
-2
@@ -1,14 +1,13 @@
|
|||||||
from fastapi import BackgroundTasks, Security, APIRouter
|
from fastapi import BackgroundTasks, Security, APIRouter
|
||||||
from fastapi_jwt import JwtAuthorizationCredentials
|
from fastapi_jwt import JwtAuthorizationCredentials
|
||||||
from starlette.responses import Response
|
from starlette.responses import Response
|
||||||
|
|
||||||
from endpoints.login import LoginInput, LoginEndpoint, RefreshEndpoint, LogoutEndpoint
|
from endpoints.login import LoginInput, LoginEndpoint, RefreshEndpoint, LogoutEndpoint
|
||||||
from endpoints.registration import RegistrationInput, RegistrationEndpoint
|
from endpoints.registration import RegistrationInput, RegistrationEndpoint
|
||||||
from jwt import access_security, refresh_security
|
from jwt import access_security, refresh_security
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@router.post("/registration", status_code=201)
|
@router.post("/registration", status_code=201)
|
||||||
async def registration(user: RegistrationInput, background_tasks: BackgroundTasks):
|
async def registration(user: RegistrationInput, background_tasks: BackgroundTasks):
|
||||||
return await RegistrationEndpoint().on_post(user, background_tasks)
|
return await RegistrationEndpoint().on_post(user, background_tasks)
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|||||||
|
|
||||||
sys.path.insert(0, "/app/src")
|
sys.path.insert(0, "/app/src")
|
||||||
|
|
||||||
from utils.flight_plan_helpers import refresh_markers_weather_info
|
from utils.flight_plan_helpers import refresh_markers_weather_info # noqa
|
||||||
from database.models import FlightPlan
|
from database.models import FlightPlan # noqa
|
||||||
from database import models
|
from database import models # noqa
|
||||||
from database.transaction import get_session
|
from database.transaction import get_session # noqa
|
||||||
|
|
||||||
|
|
||||||
async def get_plans(db: AsyncSession) -> list[Any] | Result[tuple[FlightPlan, Any]]:
|
async def get_plans(db: AsyncSession) -> list[Any] | Result[tuple[FlightPlan, Any]]:
|
||||||
|
|||||||
Reference in New Issue
Block a user