from datetime import datetime from sqlmodel import Field, SQLModel, Relationship, String from pydantic import BaseModel from gisaf.models.metadata import gisaf_admin class UserRoleLink(SQLModel, table=True): __tablename__: str = "roles_users" # type: ignore __table_args__ = gisaf_admin.table_args user_id: int | None = Field( default=None, foreign_key=gisaf_admin.table("user.id"), primary_key=True ) role_id: int | None = Field( default=None, foreign_key=gisaf_admin.table("role.id"), primary_key=True ) class UserBase(SQLModel): username: str email: str disabled: bool | None = False class User(UserBase, table=True): __table_args__ = gisaf_admin.table_args id: int = Field(primary_key=True) username: str = Field(String(255), unique=True, index=True) email: str = Field(sa_type=String(50), unique=True) password: str = Field(sa_type=String(255)) active: bool = True confirmed_at: datetime | None = None last_login_at: datetime | None = None current_login_at: datetime | None = None last_login_ip: str | None = Field(sa_type=String(255), default=None) current_login_ip: str | None = Field(sa_type=String(255), default=None) login_count: int = 0 roles: list["Role"] = Relationship(back_populates="users", link_model=UserRoleLink) def can_view(self, model) -> bool: role = getattr(model, "viewable_role", None) if role: return self.has_role(role) else: return True def has_role(self, role: str) -> bool: return role in (role.name for role in self.roles) class RoleBase(SQLModel): name: str = Field(unique=True) class RoleWithDescription(RoleBase): description: str | None class Role(RoleWithDescription, table=True): __table_args__ = gisaf_admin.table_args id: int | None = Field(default=None, primary_key=True) users: list[User] = Relationship(back_populates="roles", link_model=UserRoleLink) class UserReadNoRoles(UserBase): id: int email: str | None # type: ignore class RoleRead(RoleBase): id: int users: list[UserReadNoRoles] = [] class RoleReadNoUsers(RoleBase): id: int class UserRead(UserBase): id: int email: str | None # type: ignore roles: list[RoleReadNoUsers] = [] def can_view(self, model) -> bool: role = getattr(model, "viewable_role", None) if role: return self.has_role(role) else: return True def has_role(self, role: str) -> bool: return role in (role.name for role in self.roles) # class ACL(BaseModel): # user_id: int # role_ids: list[int]