Skip to content

Commit

Permalink
Add detailed state for tasks, fixes for UI
Browse files Browse the repository at this point in the history
  • Loading branch information
Micah Fitzgerald committed Aug 22, 2024
1 parent 90528ed commit 12acaa1
Show file tree
Hide file tree
Showing 19 changed files with 631 additions and 149 deletions.
4 changes: 1 addition & 3 deletions backend/main/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@

@asynccontextmanager
async def lifespan(app: FastAPI):
# Load the ML model
await convoy_service.init_models()
await convoy_service.init_models(drop=False)
yield
# Clean up the ML models and release the resources


app = FastAPI(generate_unique_id_function=custom_generate_unique_id, separate_input_output_schemas=False, lifespan=lifespan)
Expand Down
28 changes: 25 additions & 3 deletions backend/main/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import datetime
import enum
from typing import List, Optional

import validators
Expand All @@ -10,6 +11,8 @@
computed_field,
field_serializer,
field_validator,
model_validator,
root_validator,
)
from sqlalchemy import CheckConstraint, ForeignKey, Numeric, String
from sqlalchemy.orm import (
Expand All @@ -24,7 +27,20 @@

schema = "convoy"


class TaskDueState(enum.Enum):
OVERDUE = 'OVERDUE'
DUE = 'DUE'
UPCOMING = 'UPCOMING'
COMPLETED = 'COMPLETED'

class DueReason(enum.Enum):
TIME = 'TIME'
METER = 'METER'
BOTH = 'BOTH'
NOT_DUE = 'NOT_DUE'
class TaskDetailedState(BaseModel):
state: TaskDueState
due_reason: DueReason = Field(default=DueReason.NOT_DUE)
class Base(DeclarativeBase):
pass

Expand All @@ -37,7 +53,7 @@ class MeterReading(Base):
machine_id: Mapped[str] = mapped_column(ForeignKey("machine.id"))
machine: Mapped["Machine"] = relationship(back_populates="meter_readings", lazy="joined")

__table_args__ = (CheckConstraint("value > 0", name="check_value_positive"), {})
__table_args__ = (CheckConstraint("value >= 0", name="check_value_positive"), {})

@classmethod
def from_schema(cls, schema: "MeterReadingSchema"):
Expand Down Expand Up @@ -233,7 +249,7 @@ def serialize_dt2(self, dt: datetime.date, _info):
else:
return None
due_days_ago: Optional[int] = Field(default=None)

detailed_state: Optional[TaskDetailedState] = Field(default=None)

class TaskCompleteSchema(BaseModel):
notes: Optional[str] = None
Expand Down Expand Up @@ -305,3 +321,9 @@ class MachineUpdateSchema(BaseModel):
image: Optional[str] = None
purchase_date: Optional[datetime.date] = None
normalize_date = field_validator("purchase_date", mode="before")(parse_date)

class TasksByStateSchema(BaseModel):
overdue: List[TaskSchema] = Field(default=[])
due: List[TaskSchema] = Field(default=[])
upcoming: List[TaskSchema] = Field(default=[])
completed: List[TaskSchema] = Field(default=[])
130 changes: 103 additions & 27 deletions backend/main/router.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import datetime
from typing import List

from fastapi import APIRouter, Depends
Expand All @@ -15,6 +16,7 @@
Task,
TaskCompleteSchema,
TaskCreateSchema,
TasksByStateSchema,
TaskSchema,
)
from .service import ConvoyService
Expand All @@ -26,54 +28,104 @@


@router.patch("/api/v1/machines/{machine_id}", response_model=MachineSchema)
async def update_machine(machine_id: str, new_machine: MachineUpdateSchema, service: ConvoyService = Depends(get_service)) -> MachineSchema:
updated = await service.update_machine(machine_id, new_machine.model_dump(exclude_none=True, exclude_unset=True))
return updated
async def update_machine(
machine_id: str,
new_machine: MachineUpdateSchema,
service: ConvoyService = Depends(get_service),
) -> MachineSchema:
updated = await service.update_machine(
machine_id, new_machine.model_dump(exclude_none=True, exclude_unset=True)
)
return await service.machine_to_schema(updated)


@router.delete("/api/v1/machines/{machine_id}", response_model=MachineSchema)
async def delete_machine(machine_id: str, service: ConvoyService = Depends(get_service)) -> MachineSchema:
return MachineSchema.model_validate(await service.delete_machine(machine_id))
async def delete_machine(
machine_id: str, service: ConvoyService = Depends(get_service)
) -> MachineSchema:
return await service.machine_to_schema(await service.delete_machine(machine_id))


@router.post("/api/v1/machines", response_model=MachineSchema)
async def create_machine(new_machine: MachineSchema, service: ConvoyService = Depends(get_service)) -> MachineSchema:
return MachineSchema.model_validate(await service.create_machine(Machine.from_schema(new_machine)))
async def create_machine(
new_machine: MachineSchema, service: ConvoyService = Depends(get_service)
) -> MachineSchema:
machine = Machine.from_schema(new_machine)
machine.meter_readings = [
MeterReading(
timestamp=datetime.datetime.now(), value=new_machine.current_meter_reading
)
]
return await service.machine_to_schema(await service.create_machine(machine))


@router.get("/api/v1/machines/{machine_id}", response_model=MachineSchema)
async def get_machine(machine_id: str, service: ConvoyService = Depends(get_service)) -> MachineSchema:
return MachineSchema.model_validate(await service.get_machine(machine_id))
async def get_machine(
machine_id: str, service: ConvoyService = Depends(get_service)
) -> MachineSchema:
return await service.machine_to_schema(await service.get_machine(machine_id))


@router.post("/api/v1/machines/{machine_id}/readings", response_model=MeterReadingSchema)
async def create_reading(machine_id: str, reading: MeterReadingSchema, service: ConvoyService = Depends(get_service)) -> MeterReadingSchema:
@router.post(
"/api/v1/machines/{machine_id}/readings", response_model=MeterReadingSchema
)
async def create_reading(
machine_id: str,
reading: MeterReadingSchema,
service: ConvoyService = Depends(get_service),
) -> MeterReadingSchema:
if not reading.machine_id:
reading.machine_id = machine_id
reading = await service.record_reading(machine_id, MeterReading.from_schema(reading))
reading = await service.record_reading(
machine_id, MeterReading.from_schema(reading)
)
return MeterReadingSchema.model_validate(reading)


@router.get("/api/v1/machines", response_model=List[MachineSchema])
async def get_machines(service: ConvoyService = Depends(get_service)) -> List[MachineSchema]:
return [MachineSchema.model_validate(m) for m in await service.get_machines()]
async def get_machines(
service: ConvoyService = Depends(get_service),
) -> List[MachineSchema]:
return [await service.machine_to_schema(m) for m in await service.get_machines()]


@router.delete("/api/v1/machines/{machine_id}/tasks/{task_id}", response_model=TaskSchema)
async def delete_task(task_id: str, machine_id: str, service: ConvoyService = Depends(get_service)) -> TaskSchema:
@router.delete(
"/api/v1/machines/{machine_id}/tasks/{task_id}", response_model=TaskSchema
)
async def delete_task(
task_id: str, machine_id: str, service: ConvoyService = Depends(get_service)
) -> TaskSchema:
return TaskSchema.model_validate(await service.delete_task(machine_id, task_id))


@router.get("/api/v1/machines/{machine_id}/tasks/{task_id}", response_model=TaskSchema)
async def get_task(task_id: str, machine_id: str, service: ConvoyService = Depends(get_service)) -> TaskSchema:
async def get_task(
task_id: str, machine_id: str, service: ConvoyService = Depends(get_service)
) -> TaskSchema:
return TaskSchema.model_validate(await service.get_task(machine_id, task_id))


@router.get("/api/v1/machines/{machine_id}/tasks", response_model=List[TaskSchema])
async def get_tasks(machine_id: str, service: ConvoyService = Depends(get_service)) -> List[TaskSchema]:
async def get_tasks(
machine_id: str, service: ConvoyService = Depends(get_service)
) -> List[TaskSchema]:
return [TaskSchema.model_validate(t) for t in await service.get_tasks(machine_id)]


@router.get("/api/v1/tasks", response_model=List[TaskSchema])
async def get_all_tasks(
service: ConvoyService = Depends(get_service),
) -> List[TaskSchema]:
return [TaskSchema.model_validate(t) for t in await service.get_all_tasks()]


@router.get("/api/v1/tasks/by-state", response_model=TasksByStateSchema)
async def get_all_tasks_by_state(
service: ConvoyService = Depends(get_service),
) -> TasksByStateSchema:
return await service.get_all_tasks_by_state()


@router.post("/api/v1/machines/{machine_id}/tasks", response_model=TaskSchema)
async def create_task(
machine_id: str,
Expand All @@ -83,10 +135,22 @@ async def create_task(
created: Task = await service.create_task(machine_id, Task.from_schema(task))
return TaskSchema.model_validate(created)

@router.post("/api/v1/machines/{machine_id}/tasks/{task_id}/complete", response_model=TaskSchema)
async def complete_task(task: TaskCompleteSchema, machine_id: str, task_id: str, service: ConvoyService = Depends(get_service)) -> TaskSchema:

@router.post(
"/api/v1/machines/{machine_id}/tasks/{task_id}/complete", response_model=TaskSchema
)
async def complete_task(
task: TaskCompleteSchema,
machine_id: str,
task_id: str,
service: ConvoyService = Depends(get_service),
) -> TaskSchema:
updated = await service.complete_task(
machine_id, task_id, completed_date=task.completed_date, completed_meter_reading=task.completed_meter_reading, notes=task.notes
machine_id,
task_id,
completed_date=task.completed_date,
completed_meter_reading=task.completed_meter_reading,
notes=task.notes,
)
return updated

Expand All @@ -97,26 +161,38 @@ async def update_supply(
supply: SupplyUpdateSchema,
service: ConvoyService = Depends(get_service),
) -> SupplySchema:
updated = await service.update_supply(supply_id, supply.model_dump(exclude_none=True, exclude_unset=True))
updated = await service.update_supply(
supply_id, supply.model_dump(exclude_none=True, exclude_unset=True)
)
return SupplySchema.model_validate(updated)


@router.get("/api/v1/supplies", response_model=List[SupplySchema])
async def get_supplies(service: ConvoyService = Depends(get_service)) -> List[SupplySchema]:
async def get_supplies(
service: ConvoyService = Depends(get_service),
) -> List[SupplySchema]:
return [SupplySchema.model_validate(s) for s in await service.get_supplies()]


@router.post("/api/v1/supplies", response_model=SupplySchema)
async def create_supply(supply: SupplySchema, service: ConvoyService = Depends(get_service)) -> SupplySchema:
return SupplySchema.model_validate(await service.create_supply(Supply.from_schema(supply)))
async def create_supply(
supply: SupplySchema, service: ConvoyService = Depends(get_service)
) -> SupplySchema:
return SupplySchema.model_validate(
await service.create_supply(Supply.from_schema(supply))
)


@router.delete("/api/v1/supplies/{supply_id}", response_model=SupplySchema)
async def delete_supply(supply_id, service: ConvoyService = Depends(get_service)) -> SupplySchema:
async def delete_supply(
supply_id, service: ConvoyService = Depends(get_service)
) -> SupplySchema:
deleted = await service.delete_supply(supply_id)
return deleted


@router.get("/api/v1/supplies/{supply_id}", response_model=SupplySchema)
async def get_supply(supply_id, service: ConvoyService = Depends(get_service)) -> SupplySchema:
async def get_supply(
supply_id, service: ConvoyService = Depends(get_service)
) -> SupplySchema:
return SupplySchema.model_validate(await service.get_supply(supply_id))
Loading

0 comments on commit 12acaa1

Please sign in to comment.