Add ruff linter/formatter for Python
- Add ruff as dev dependency - Configure ruff in pyproject.toml with strict 88-char line limit - Ignore B008 (FastAPI Depends pattern is standard) - Allow longer lines in tests for readability - Fix all lint issues in source files - Add Makefile targets: lint-backend, format-backend, fix-backend
This commit is contained in:
parent
69bc8413e0
commit
6c218130e9
31 changed files with 1234 additions and 876 deletions
|
|
@ -1,5 +1,6 @@
|
|||
"""Pydantic schemas for API request/response models."""
|
||||
from datetime import datetime, date, time
|
||||
|
||||
from datetime import date, datetime, time
|
||||
from typing import Generic, TypeVar
|
||||
|
||||
from pydantic import BaseModel, EmailStr, field_validator
|
||||
|
|
@ -9,6 +10,7 @@ from shared_constants import NOTE_MAX_LENGTH
|
|||
|
||||
class UserCredentials(BaseModel):
|
||||
"""Base model for user email/password."""
|
||||
|
||||
email: EmailStr
|
||||
password: str
|
||||
|
||||
|
|
@ -19,6 +21,7 @@ UserLogin = UserCredentials
|
|||
|
||||
class UserResponse(BaseModel):
|
||||
"""Response model for authenticated user info."""
|
||||
|
||||
id: int
|
||||
email: str
|
||||
roles: list[str]
|
||||
|
|
@ -27,6 +30,7 @@ class UserResponse(BaseModel):
|
|||
|
||||
class RegisterWithInvite(BaseModel):
|
||||
"""Request model for registration with invite."""
|
||||
|
||||
email: EmailStr
|
||||
password: str
|
||||
invite_identifier: str
|
||||
|
|
@ -34,12 +38,14 @@ class RegisterWithInvite(BaseModel):
|
|||
|
||||
class SumRequest(BaseModel):
|
||||
"""Request model for sum calculation."""
|
||||
|
||||
a: float
|
||||
b: float
|
||||
|
||||
|
||||
class SumResponse(BaseModel):
|
||||
"""Response model for sum calculation."""
|
||||
|
||||
a: float
|
||||
b: float
|
||||
result: float
|
||||
|
|
@ -47,6 +53,7 @@ class SumResponse(BaseModel):
|
|||
|
||||
class CounterRecordResponse(BaseModel):
|
||||
"""Response model for a counter audit record."""
|
||||
|
||||
id: int
|
||||
user_email: str
|
||||
value_before: int
|
||||
|
|
@ -56,6 +63,7 @@ class CounterRecordResponse(BaseModel):
|
|||
|
||||
class SumRecordResponse(BaseModel):
|
||||
"""Response model for a sum audit record."""
|
||||
|
||||
id: int
|
||||
user_email: str
|
||||
a: float
|
||||
|
|
@ -69,6 +77,7 @@ RecordT = TypeVar("RecordT", bound=BaseModel)
|
|||
|
||||
class PaginatedResponse(BaseModel, Generic[RecordT]):
|
||||
"""Generic paginated response wrapper."""
|
||||
|
||||
records: list[RecordT]
|
||||
total: int
|
||||
page: int
|
||||
|
|
@ -82,6 +91,7 @@ PaginatedSumRecords = PaginatedResponse[SumRecordResponse]
|
|||
|
||||
class ProfileResponse(BaseModel):
|
||||
"""Response model for profile data."""
|
||||
|
||||
contact_email: str | None
|
||||
telegram: str | None
|
||||
signal: str | None
|
||||
|
|
@ -91,6 +101,7 @@ class ProfileResponse(BaseModel):
|
|||
|
||||
class ProfileUpdate(BaseModel):
|
||||
"""Request model for updating profile."""
|
||||
|
||||
contact_email: str | None = None
|
||||
telegram: str | None = None
|
||||
signal: str | None = None
|
||||
|
|
@ -99,6 +110,7 @@ class ProfileUpdate(BaseModel):
|
|||
|
||||
class InviteCheckResponse(BaseModel):
|
||||
"""Response for invite check endpoint."""
|
||||
|
||||
valid: bool
|
||||
status: str | None = None
|
||||
error: str | None = None
|
||||
|
|
@ -106,11 +118,13 @@ class InviteCheckResponse(BaseModel):
|
|||
|
||||
class InviteCreate(BaseModel):
|
||||
"""Request model for creating an invite."""
|
||||
|
||||
godfather_id: int
|
||||
|
||||
|
||||
class InviteResponse(BaseModel):
|
||||
"""Response model for invite data (admin view)."""
|
||||
|
||||
id: int
|
||||
identifier: str
|
||||
godfather_id: int
|
||||
|
|
@ -125,6 +139,7 @@ class InviteResponse(BaseModel):
|
|||
|
||||
class UserInviteResponse(BaseModel):
|
||||
"""Response model for a user's invite (simpler than admin view)."""
|
||||
|
||||
id: int
|
||||
identifier: str
|
||||
status: str
|
||||
|
|
@ -138,6 +153,7 @@ PaginatedInviteRecords = PaginatedResponse[InviteResponse]
|
|||
|
||||
class AdminUserResponse(BaseModel):
|
||||
"""Minimal user info for admin dropdowns."""
|
||||
|
||||
id: int
|
||||
email: str
|
||||
|
||||
|
|
@ -146,11 +162,13 @@ class AdminUserResponse(BaseModel):
|
|||
# Availability Schemas
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class TimeSlot(BaseModel):
|
||||
"""A single time slot (start and end time)."""
|
||||
|
||||
start_time: time
|
||||
end_time: time
|
||||
|
||||
|
||||
@field_validator("start_time", "end_time")
|
||||
@classmethod
|
||||
def validate_15min_boundary(cls, v: time) -> time:
|
||||
|
|
@ -164,23 +182,27 @@ class TimeSlot(BaseModel):
|
|||
|
||||
class AvailabilityDay(BaseModel):
|
||||
"""Availability for a single day."""
|
||||
|
||||
date: date
|
||||
slots: list[TimeSlot]
|
||||
|
||||
|
||||
class AvailabilityResponse(BaseModel):
|
||||
"""Response model for availability query."""
|
||||
|
||||
days: list[AvailabilityDay]
|
||||
|
||||
|
||||
class SetAvailabilityRequest(BaseModel):
|
||||
"""Request to set availability for a specific date."""
|
||||
|
||||
date: date
|
||||
slots: list[TimeSlot]
|
||||
|
||||
|
||||
class CopyAvailabilityRequest(BaseModel):
|
||||
"""Request to copy availability from one day to others."""
|
||||
|
||||
source_date: date
|
||||
target_dates: list[date]
|
||||
|
||||
|
|
@ -189,20 +211,24 @@ class CopyAvailabilityRequest(BaseModel):
|
|||
# Booking Schemas
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class BookableSlot(BaseModel):
|
||||
"""A bookable 15-minute slot."""
|
||||
|
||||
start_time: datetime
|
||||
end_time: datetime
|
||||
|
||||
|
||||
class AvailableSlotsResponse(BaseModel):
|
||||
"""Response for available slots on a given date."""
|
||||
|
||||
date: date
|
||||
slots: list[BookableSlot]
|
||||
|
||||
|
||||
class BookingRequest(BaseModel):
|
||||
"""Request to book an appointment."""
|
||||
|
||||
slot_start: datetime
|
||||
note: str | None = None
|
||||
|
||||
|
|
@ -216,6 +242,7 @@ class BookingRequest(BaseModel):
|
|||
|
||||
class AppointmentResponse(BaseModel):
|
||||
"""Response model for an appointment."""
|
||||
|
||||
id: int
|
||||
user_id: int
|
||||
user_email: str
|
||||
|
|
@ -234,8 +261,10 @@ PaginatedAppointments = PaginatedResponse[AppointmentResponse]
|
|||
# Meta/Constants Schemas
|
||||
# =============================================================================
|
||||
|
||||
|
||||
class ConstantsResponse(BaseModel):
|
||||
"""Response model for shared constants."""
|
||||
|
||||
permissions: list[str]
|
||||
roles: list[str]
|
||||
invite_statuses: list[str]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue