Files
PROJECT-CONTORL/backend/app/models/project_template.py
2026-01-11 08:37:21 +08:00

130 lines
5.0 KiB
Python

"""Project Template model for reusable project configurations.
Allows users to create templates with predefined task statuses and custom fields
that can be used to quickly set up new projects.
"""
import uuid
from sqlalchemy import Column, String, Text, Boolean, DateTime, ForeignKey, JSON
from sqlalchemy.orm import relationship, synonym
from sqlalchemy.sql import func
from app.core.database import Base
class ProjectTemplate(Base):
"""Template for creating projects with predefined configurations.
A template stores:
- Basic project metadata (name, description)
- Predefined task statuses (stored as JSON)
- Predefined custom field definitions (stored as JSON)
When a project is created from a template, the TaskStatus and CustomField
records are copied to the new project.
"""
__tablename__ = "pjctrl_project_templates"
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
name = Column(String(200), nullable=False)
description = Column(Text, nullable=True)
# Template owner
owner_id = Column(String(36), ForeignKey("pjctrl_users.id"), nullable=False)
# Whether the template is available to all users or just the owner
is_public = Column(Boolean, default=False, nullable=False)
# Soft delete flag
is_active = Column(Boolean, default=True, nullable=False)
# Predefined task statuses as JSON array
# Format: [{"name": "To Do", "color": "#808080", "position": 0, "is_done": false}, ...]
task_statuses = Column(JSON, nullable=True)
# Predefined custom field definitions as JSON array
# Format: [{"name": "Priority", "field_type": "dropdown", "options": [...], ...}, ...]
custom_fields = Column(JSON, nullable=True)
# Optional default project settings
default_security_level = Column(String(20), default="department", nullable=True)
created_at = Column(DateTime, server_default=func.now(), nullable=False)
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now(), nullable=False)
# Relationships
owner = relationship("User", foreign_keys=[owner_id])
# Backward-compatible aliases for older code/tests
created_by = synonym("owner_id")
default_statuses = synonym("task_statuses")
# Default template data for system templates
SYSTEM_TEMPLATES = [
{
"name": "Basic Project",
"description": "A simple project template with standard task statuses.",
"is_public": True,
"task_statuses": [
{"name": "To Do", "color": "#808080", "position": 0, "is_done": False},
{"name": "In Progress", "color": "#0066cc", "position": 1, "is_done": False},
{"name": "Done", "color": "#00cc66", "position": 2, "is_done": True},
],
"custom_fields": [],
},
{
"name": "Software Development",
"description": "Template for software development projects with extended workflow.",
"is_public": True,
"task_statuses": [
{"name": "Backlog", "color": "#808080", "position": 0, "is_done": False},
{"name": "To Do", "color": "#3366cc", "position": 1, "is_done": False},
{"name": "In Progress", "color": "#0066cc", "position": 2, "is_done": False},
{"name": "Code Review", "color": "#cc6600", "position": 3, "is_done": False},
{"name": "Testing", "color": "#9933cc", "position": 4, "is_done": False},
{"name": "Done", "color": "#00cc66", "position": 5, "is_done": True},
],
"custom_fields": [
{
"name": "Story Points",
"field_type": "number",
"is_required": False,
"position": 0,
},
{
"name": "Sprint",
"field_type": "dropdown",
"options": ["Sprint 1", "Sprint 2", "Sprint 3", "Backlog"],
"is_required": False,
"position": 1,
},
],
},
{
"name": "Marketing Campaign",
"description": "Template for marketing campaign management.",
"is_public": True,
"task_statuses": [
{"name": "Planning", "color": "#808080", "position": 0, "is_done": False},
{"name": "Content Creation", "color": "#cc6600", "position": 1, "is_done": False},
{"name": "Review", "color": "#9933cc", "position": 2, "is_done": False},
{"name": "Scheduled", "color": "#0066cc", "position": 3, "is_done": False},
{"name": "Published", "color": "#00cc66", "position": 4, "is_done": True},
],
"custom_fields": [
{
"name": "Channel",
"field_type": "dropdown",
"options": ["Email", "Social Media", "Website", "Print", "Event"],
"is_required": False,
"position": 0,
},
{
"name": "Target Audience",
"field_type": "text",
"is_required": False,
"position": 1,
},
],
},
]