Files
HarborForge.Backend/app/models/models.py
zhi 271d5140e6 feat(users): switch account management to single-role model
- add users.role_id for one global role per account
- seed protected account-manager role with account.create permission
- default new accounts to guest role
- block admin role assignment through user management
- allow account-manager permission to create accounts
2026-03-21 08:44:19 +00:00

109 lines
3.7 KiB
Python

from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Enum, Boolean, JSON, Time
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from app.core.config import Base
from app.models.role_permission import Role
import enum
class TaskType(str, enum.Enum):
"""Task type enum."""
ISSUE = "issue"
MAINTENANCE = "maintenance"
RESEARCH = "research"
REVIEW = "review"
STORY = "story"
TEST = "test"
RESOLUTION = "resolution"
class TaskStatus(str, enum.Enum):
OPEN = "open"
PENDING = "pending"
UNDERGOING = "undergoing"
COMPLETED = "completed"
CLOSED = "closed"
class TaskPriority(str, enum.Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
class Comment(Base):
__tablename__ = "comments"
id = Column(Integer, primary_key=True, index=True)
content = Column(Text, nullable=False)
task_id = Column(Integer, ForeignKey("tasks.id"), nullable=False)
author_id = Column(Integer, ForeignKey("users.id"), nullable=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
author = relationship("User", back_populates="comments")
class Project(Base):
__tablename__ = "projects"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(100), unique=True, nullable=False)
project_code = Column(String(16), unique=True, index=True, nullable=True)
owner_name = Column(String(128), nullable=False)
sub_projects = Column(String(512), nullable=True)
related_projects = Column(String(512), nullable=True)
repo = Column(String(512), nullable=True)
description = Column(Text, nullable=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
owner_id = Column(Integer, ForeignKey("users.id"), nullable=False)
members = relationship("ProjectMember", back_populates="project", cascade="all, delete-orphan")
owner = relationship("User", back_populates="owned_projects")
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
username = Column(String(50), unique=True, nullable=False)
email = Column(String(100), unique=True, nullable=False)
hashed_password = Column(String(255), nullable=True)
full_name = Column(String(100), nullable=True)
is_active = Column(Boolean, default=True)
is_admin = Column(Boolean, default=False)
role_id = Column(Integer, ForeignKey("roles.id"), nullable=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
role = relationship("Role", foreign_keys=[role_id])
owned_projects = relationship("Project", back_populates="owner")
comments = relationship("Comment", back_populates="author")
project_memberships = relationship("ProjectMember", back_populates="user")
@property
def role_name(self):
return self.role.name if self.role else None
class ProjectMember(Base):
__tablename__ = "project_members"
id = Column(Integer, primary_key=True, index=True)
project_id = Column(Integer, ForeignKey("projects.id"), nullable=False)
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
role_id = Column(Integer, ForeignKey("roles.id"), nullable=False)
role = relationship("Role")
project = relationship("Project", back_populates="members")
user = relationship("User", back_populates="project_memberships")
class ProjectCodeCounter(Base):
__tablename__ = "project_code_counters"
id = Column(Integer, primary_key=True, index=True)
prefix = Column(String(16), unique=True, index=True, nullable=False)
next_value = Column(Integer, default=0)