forked from cardosofelipe/fast-next-template
Add organization management and admin-specific APIs
- Introduced schemas for organizations, including creation, updates, and responses. - Created models for `Organization` and `UserOrganization` with role-based access control and relationships. - Implemented admin APIs for managing users, organizations, and bulk actions. - Added advanced filtering, sorting, and pagination for user and organization queries. - Updated `CRUD` logic to support organization-specific operations and member management. - Enhanced database with necessary indexes and validation for improved performance and data integrity.
This commit is contained in:
@@ -9,8 +9,11 @@ from .base import TimestampMixin, UUIDMixin
|
||||
# Import models
|
||||
from .user import User
|
||||
from .user_session import UserSession
|
||||
from .organization import Organization
|
||||
from .user_organization import UserOrganization, OrganizationRole
|
||||
|
||||
__all__ = [
|
||||
'Base', 'TimestampMixin', 'UUIDMixin',
|
||||
'User', 'UserSession',
|
||||
'Organization', 'UserOrganization', 'OrganizationRole',
|
||||
]
|
||||
31
backend/app/models/organization.py
Normal file
31
backend/app/models/organization.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# app/models/organization.py
|
||||
from sqlalchemy import Column, String, Boolean, Text, Index
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from .base import Base, TimestampMixin, UUIDMixin
|
||||
|
||||
|
||||
class Organization(Base, UUIDMixin, TimestampMixin):
|
||||
"""
|
||||
Organization model for multi-tenant support.
|
||||
Users can belong to multiple organizations with different roles.
|
||||
"""
|
||||
__tablename__ = 'organizations'
|
||||
|
||||
name = Column(String(255), nullable=False, index=True)
|
||||
slug = Column(String(255), unique=True, nullable=False, index=True)
|
||||
description = Column(Text, nullable=True)
|
||||
is_active = Column(Boolean, default=True, nullable=False, index=True)
|
||||
settings = Column(JSONB, default={})
|
||||
|
||||
# Relationships
|
||||
user_organizations = relationship("UserOrganization", back_populates="organization", cascade="all, delete-orphan")
|
||||
|
||||
__table_args__ = (
|
||||
Index('ix_organizations_name_active', 'name', 'is_active'),
|
||||
Index('ix_organizations_slug_active', 'slug', 'is_active'),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Organization {self.name} ({self.slug})>"
|
||||
@@ -1,5 +1,6 @@
|
||||
from sqlalchemy import Column, String, Boolean, DateTime
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from .base import Base, TimestampMixin, UUIDMixin
|
||||
|
||||
@@ -17,5 +18,8 @@ class User(Base, UUIDMixin, TimestampMixin):
|
||||
preferences = Column(JSONB)
|
||||
deleted_at = Column(DateTime(timezone=True), nullable=True, index=True)
|
||||
|
||||
# Relationships
|
||||
user_organizations = relationship("UserOrganization", back_populates="user", cascade="all, delete-orphan")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<User {self.email}>"
|
||||
50
backend/app/models/user_organization.py
Normal file
50
backend/app/models/user_organization.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# app/models/user_organization.py
|
||||
from enum import Enum as PyEnum
|
||||
|
||||
from sqlalchemy import Column, ForeignKey, Boolean, String, Index, Enum
|
||||
from sqlalchemy.dialects.postgresql import UUID as PGUUID
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from .base import Base, TimestampMixin
|
||||
|
||||
|
||||
class OrganizationRole(str, PyEnum):
|
||||
"""
|
||||
Built-in organization roles.
|
||||
These provide a baseline role system that can be optionally used.
|
||||
Projects can extend this or implement their own permission system.
|
||||
"""
|
||||
OWNER = "owner" # Full control over organization
|
||||
ADMIN = "admin" # Can manage users and settings
|
||||
MEMBER = "member" # Regular member with standard access
|
||||
GUEST = "guest" # Limited read-only access
|
||||
|
||||
|
||||
class UserOrganization(Base, TimestampMixin):
|
||||
"""
|
||||
Junction table for many-to-many relationship between Users and Organizations.
|
||||
Includes role information for flexible RBAC.
|
||||
"""
|
||||
__tablename__ = 'user_organizations'
|
||||
|
||||
user_id = Column(PGUUID(as_uuid=True), ForeignKey('users.id', ondelete='CASCADE'), primary_key=True)
|
||||
organization_id = Column(PGUUID(as_uuid=True), ForeignKey('organizations.id', ondelete='CASCADE'), primary_key=True)
|
||||
|
||||
role = Column(Enum(OrganizationRole), default=OrganizationRole.MEMBER, nullable=False, index=True)
|
||||
is_active = Column(Boolean, default=True, nullable=False, index=True)
|
||||
|
||||
# Optional: Custom permissions override for specific users
|
||||
custom_permissions = Column(String(500), nullable=True) # JSON array of permission strings
|
||||
|
||||
# Relationships
|
||||
user = relationship("User", back_populates="user_organizations")
|
||||
organization = relationship("Organization", back_populates="user_organizations")
|
||||
|
||||
__table_args__ = (
|
||||
Index('ix_user_org_user_active', 'user_id', 'is_active'),
|
||||
Index('ix_user_org_org_active', 'organization_id', 'is_active'),
|
||||
Index('ix_user_org_role', 'role'),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<UserOrganization user={self.user_id} org={self.organization_id} role={self.role}>"
|
||||
Reference in New Issue
Block a user