feat: Implement multi-tenancy support in middleware and security layers

- Enhanced TenantMiddleware to validate tenant information from JWT tokens.
- Added LicenseValidationMiddleware to check tenant licenses before processing requests.
- Updated security utilities to extract tenant information from tokens and validate company access.
- Introduced CompanyStore to manage active company state and handle company switching in the frontend.
- Modified API routes to include company_id in requests for better resource management.
- Improved logging and error handling throughout the middleware and API layers.
- Updated frontend components to reflect changes in company management and selection.
- Added new API route for fetching user's companies with proper authentication handling.
This commit is contained in:
2025-11-11 14:00:56 -06:00
parent e1eb6bbd01
commit 52b8fcd434
242 changed files with 7067 additions and 3274 deletions

View File

@@ -5,6 +5,7 @@ DTOs for FractionRuleOctave.
from pydantic import BaseModel
from typing import Optional
class FractionRuleOctaveBaseDTO(BaseModel):
PERMISSION: str
LINE: int
@@ -16,9 +17,11 @@ class FractionRuleOctaveBaseDTO(BaseModel):
UNIT_COST_ME: Optional[float]
UNIT_MEASURE: Optional[str]
class FractionRuleOctaveCreateDTO(FractionRuleOctaveBaseDTO):
pass
class FractionRuleOctaveResponseDTO(FractionRuleOctaveBaseDTO):
class Config:
from_attributes = True
from_attributes = True

View File

@@ -1,4 +1,11 @@
from sqlalchemy import Integer, String, ForeignKey, PrimaryKeyConstraint, ForeignKeyConstraint, UniqueConstraint
from sqlalchemy import (
Integer,
String,
ForeignKey,
PrimaryKeyConstraint,
ForeignKeyConstraint,
UniqueConstraint,
)
from sqlalchemy.orm import Mapped, mapped_column
from core.database import Base
@@ -6,18 +13,28 @@ from core.database import Base
class FractionRuleOctave(Base):
__tablename__ = "fraction_rule_octave"
__table_args__ = (
PrimaryKeyConstraint('id', name='fraction_rule_octave_pkey'),
ForeignKeyConstraint(['tenant_id'], ['a76.tenants.id'], name='fk_fraction_rule_octave_tenant'),
ForeignKeyConstraint(['company_id'], ['a76.company.id'], name='fk_fraction_rule_octave_company'),
UniqueConstraint('tenant_id', 'company_id', 'permission', 'line', 'fraction', name='uq_fraction_rule_octave_permission_line_fraction'),
{"schema": "a76"}
PrimaryKeyConstraint("id", name="fraction_rule_octave_pkey"),
ForeignKeyConstraint(
["tenant_id"], ["a76.tenants.id"], name="fk_fraction_rule_octave_tenant"
),
ForeignKeyConstraint(
["company_id"], ["a76.company.id"], name="fk_fraction_rule_octave_company"
),
UniqueConstraint(
"tenant_id",
"company_id",
"permission",
"line",
"fraction",
name="uq_fraction_rule_octave_permission_line_fraction",
),
{"schema": "a76"},
)
id: Mapped[int] = mapped_column(Integer, primary_key=True)
tenant_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True)
company_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True)
permission: Mapped[str] = mapped_column(String(20))
line: Mapped[int] = mapped_column(Integer)
fraction: Mapped[str] = mapped_column(String(10))

View File

@@ -12,8 +12,7 @@ router = APIRouter(prefix="/fraction_rule_octave", tags=["FractionRuleOctave"])
@router.get("/", response_model=List[FractionRuleOctaveResponseDTO])
async def list_fractions(
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user)
):
"""
List all FractionRuleOctave entries.
@@ -28,13 +27,15 @@ async def list_fractions(
return db.query(FractionRuleOctaveService).all()
@router.get("/{permission}/{line}/{fraction}", response_model=FractionRuleOctaveResponseDTO)
@router.get(
"/{permission}/{line}/{fraction}", response_model=FractionRuleOctaveResponseDTO
)
async def read_fraction(
permission: str,
line: int,
fraction: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
current_user: dict = Depends(get_current_user),
):
"""
Get a specific FractionRuleOctave by its composite key.
@@ -52,11 +53,15 @@ async def read_fraction(
return frac
@router.post("/", response_model=FractionRuleOctaveResponseDTO, status_code=status.HTTP_201_CREATED)
@router.post(
"/",
response_model=FractionRuleOctaveResponseDTO,
status_code=status.HTTP_201_CREATED,
)
async def create_frac(
frac_data: FractionRuleOctaveCreateDTO,
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
current_user: dict = Depends(get_current_user),
):
"""
Create a new FractionRuleOctave entry.
@@ -71,13 +76,15 @@ async def create_frac(
return FractionRuleOctaveService.create_frac(db, frac_data)
@router.delete("/{permission}/{line}/{fraction}", status_code=status.HTTP_204_NO_CONTENT)
@router.delete(
"/{permission}/{line}/{fraction}", status_code=status.HTTP_204_NO_CONTENT
)
async def delete_fraction(
permission: str,
line: int,
fraction: str,
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user)
current_user: dict = Depends(get_current_user),
):
"""
Delete a FractionRuleOctave by its composite key.
@@ -91,4 +98,4 @@ async def delete_fraction(
frac = FractionRuleOctaveService.delete_fraction(db, permission, line, fraction)
if not frac:
raise HTTPException(status_code=404, detail="FractionRuleOctave not found")
raise HTTPException(status_code=404, detail="FractionRuleOctave not found")

View File

@@ -5,14 +5,21 @@ from . import models, dto
Service layer for FractionRuleOctave.
"""
class FractionRuleOctaveService:
@staticmethod
def get_fraction_by_permission_line(db: Session, permission: str, line: int, fraction: str):
return db.query(models.FractionRuleOctave).filter(
models.FractionRuleOctave.permission == permission,
models.FractionRuleOctave.line == line,
models.FractionRuleOctave.fraction == fraction
).first()
def get_fraction_by_permission_line(
db: Session, permission: str, line: int, fraction: str
):
return (
db.query(models.FractionRuleOctave)
.filter(
models.FractionRuleOctave.permission == permission,
models.FractionRuleOctave.line == line,
models.FractionRuleOctave.fraction == fraction,
)
.first()
)
@staticmethod
def create_frac(db: Session, frac_data: dto.FractionRuleOctaveCreateDTO):
@@ -24,8 +31,10 @@ class FractionRuleOctaveService:
@staticmethod
def delete_fraction(db: Session, permission: str, line: int, fraction: str):
frac = FractionRuleOctaveService.get_fraction_by_permission_line(db, permission, line, fraction)
frac = FractionRuleOctaveService.get_fraction_by_permission_line(
db, permission, line, fraction
)
if frac:
db.delete(frac)
db.commit()
return frac
return frac