Add pyproject.toml for consolidated project configuration and replace Black, isort, and Flake8 with Ruff

- Introduced `pyproject.toml` to centralize backend tool configurations (e.g., Ruff, mypy, coverage, pytest).
- Replaced Black, isort, and Flake8 with Ruff for linting, formatting, and import sorting.
- Updated `requirements.txt` to include Ruff and remove replaced tools.
- Added `Makefile` to streamline development workflows with commands for linting, formatting, type-checking, testing, and cleanup.
This commit is contained in:
2025-11-10 11:55:15 +01:00
parent a5c671c133
commit c589b565f0
86 changed files with 4572 additions and 3956 deletions

View File

@@ -1,10 +1,10 @@
# app/schemas/organizations.py
import re
from datetime import datetime
from typing import Optional, Dict, Any, List
from typing import Any
from uuid import UUID
from pydantic import BaseModel, field_validator, ConfigDict, Field
from pydantic import BaseModel, ConfigDict, Field, field_validator
from app.models.user_organization import OrganizationRole
@@ -12,85 +12,94 @@ from app.models.user_organization import OrganizationRole
# Organization Schemas
class OrganizationBase(BaseModel):
"""Base organization schema with common fields."""
name: str = Field(..., min_length=1, max_length=255)
slug: Optional[str] = Field(None, min_length=1, max_length=255)
description: Optional[str] = None
is_active: bool = True
settings: Optional[Dict[str, Any]] = {}
@field_validator('slug')
name: str = Field(..., min_length=1, max_length=255)
slug: str | None = Field(None, min_length=1, max_length=255)
description: str | None = None
is_active: bool = True
settings: dict[str, Any] | None = {}
@field_validator("slug")
@classmethod
def validate_slug(cls, v: Optional[str]) -> Optional[str]:
def validate_slug(cls, v: str | None) -> str | None:
"""Validate slug format: lowercase, alphanumeric, hyphens only."""
if v is None:
return v
if not re.match(r'^[a-z0-9-]+$', v):
raise ValueError('Slug must contain only lowercase letters, numbers, and hyphens')
if v.startswith('-') or v.endswith('-'):
raise ValueError('Slug cannot start or end with a hyphen')
if '--' in v:
raise ValueError('Slug cannot contain consecutive hyphens')
if not re.match(r"^[a-z0-9-]+$", v):
raise ValueError(
"Slug must contain only lowercase letters, numbers, and hyphens"
)
if v.startswith("-") or v.endswith("-"):
raise ValueError("Slug cannot start or end with a hyphen")
if "--" in v:
raise ValueError("Slug cannot contain consecutive hyphens")
return v
@field_validator('name')
@field_validator("name")
@classmethod
def validate_name(cls, v: str) -> str:
"""Validate organization name."""
if not v or v.strip() == "":
raise ValueError('Organization name cannot be empty')
raise ValueError("Organization name cannot be empty")
return v.strip()
class OrganizationCreate(OrganizationBase):
"""Schema for creating a new organization."""
name: str = Field(..., min_length=1, max_length=255)
slug: str = Field(..., min_length=1, max_length=255)
class OrganizationUpdate(BaseModel):
"""Schema for updating an organization."""
name: Optional[str] = Field(None, min_length=1, max_length=255)
slug: Optional[str] = Field(None, min_length=1, max_length=255)
description: Optional[str] = None
is_active: Optional[bool] = None
settings: Optional[Dict[str, Any]] = None
@field_validator('slug')
name: str | None = Field(None, min_length=1, max_length=255)
slug: str | None = Field(None, min_length=1, max_length=255)
description: str | None = None
is_active: bool | None = None
settings: dict[str, Any] | None = None
@field_validator("slug")
@classmethod
def validate_slug(cls, v: Optional[str]) -> Optional[str]:
def validate_slug(cls, v: str | None) -> str | None:
"""Validate slug format."""
if v is None:
return v
if not re.match(r'^[a-z0-9-]+$', v):
raise ValueError('Slug must contain only lowercase letters, numbers, and hyphens')
if v.startswith('-') or v.endswith('-'):
raise ValueError('Slug cannot start or end with a hyphen')
if '--' in v:
raise ValueError('Slug cannot contain consecutive hyphens')
if not re.match(r"^[a-z0-9-]+$", v):
raise ValueError(
"Slug must contain only lowercase letters, numbers, and hyphens"
)
if v.startswith("-") or v.endswith("-"):
raise ValueError("Slug cannot start or end with a hyphen")
if "--" in v:
raise ValueError("Slug cannot contain consecutive hyphens")
return v
@field_validator('name')
@field_validator("name")
@classmethod
def validate_name(cls, v: Optional[str]) -> Optional[str]:
def validate_name(cls, v: str | None) -> str | None:
"""Validate organization name."""
if v is not None and (not v or v.strip() == ""):
raise ValueError('Organization name cannot be empty')
raise ValueError("Organization name cannot be empty")
return v.strip() if v else v
class OrganizationResponse(OrganizationBase):
"""Schema for organization API responses."""
id: UUID
created_at: datetime
updated_at: Optional[datetime] = None
member_count: Optional[int] = 0
updated_at: datetime | None = None
member_count: int | None = 0
model_config = ConfigDict(from_attributes=True)
class OrganizationListResponse(BaseModel):
"""Schema for paginated organization list responses."""
organizations: List[OrganizationResponse]
organizations: list[OrganizationResponse]
total: int
page: int
page_size: int
@@ -100,44 +109,49 @@ class OrganizationListResponse(BaseModel):
# User-Organization Relationship Schemas
class UserOrganizationBase(BaseModel):
"""Base schema for user-organization relationship."""
role: OrganizationRole = OrganizationRole.MEMBER
is_active: bool = True
custom_permissions: Optional[str] = None
custom_permissions: str | None = None
class UserOrganizationCreate(BaseModel):
"""Schema for adding a user to an organization."""
user_id: UUID
role: OrganizationRole = OrganizationRole.MEMBER
custom_permissions: Optional[str] = None
custom_permissions: str | None = None
class UserOrganizationUpdate(BaseModel):
"""Schema for updating user's role in an organization."""
role: Optional[OrganizationRole] = None
is_active: Optional[bool] = None
custom_permissions: Optional[str] = None
role: OrganizationRole | None = None
is_active: bool | None = None
custom_permissions: str | None = None
class UserOrganizationResponse(BaseModel):
"""Schema for user-organization relationship responses."""
user_id: UUID
organization_id: UUID
role: OrganizationRole
is_active: bool
custom_permissions: Optional[str] = None
custom_permissions: str | None = None
created_at: datetime
updated_at: Optional[datetime] = None
updated_at: datetime | None = None
model_config = ConfigDict(from_attributes=True)
class OrganizationMemberResponse(BaseModel):
"""Schema for organization member information."""
user_id: UUID
email: str
first_name: str
last_name: Optional[str] = None
last_name: str | None = None
role: OrganizationRole
is_active: bool
joined_at: datetime
@@ -147,7 +161,8 @@ class OrganizationMemberResponse(BaseModel):
class OrganizationMemberListResponse(BaseModel):
"""Schema for paginated organization member list."""
members: List[OrganizationMemberResponse]
members: list[OrganizationMemberResponse]
total: int
page: int
page_size: int