package models import ( "time" "gorm.io/gorm" ) type Project struct { ID uint `json:"id" gorm:"primaryKey"` Name string `json:"name" gorm:"not null"` Description string `json:"description"` GiteaOrg string `json:"gitea_org"` Status string `json:"status" gorm:"default:'planning'"` Priority string `json:"priority" gorm:"default:'medium'"` StartDate *time.Time `json:"start_date"` EndDate *time.Time `json:"end_date"` OwnerID uint `json:"owner_id"` Owner User `json:"owner" gorm:"foreignKey:OwnerID"` Members []ProjectMember `json:"members" gorm:"foreignKey:ProjectID"` Epics []Epic `json:"epics" gorm:"foreignKey:ProjectID"` Stories []Story `json:"stories" gorm:"foreignKey:ProjectID"` Tasks []Task `json:"tasks" gorm:"foreignKey:ProjectID"` Sprints []Sprint `json:"sprints" gorm:"foreignKey:ProjectID"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } type ProjectMember struct { ID uint `json:"id" gorm:"primaryKey"` ProjectID uint `json:"project_id"` UserID uint `json:"user_id"` Role string `json:"role" gorm:"default:'developer'"` User User `json:"user" gorm:"foreignKey:UserID"` JoinedAt time.Time `json:"joined_at"` } type ProjectStatus string const ( ProjectStatusActive ProjectStatus = "active" ProjectStatusArchived ProjectStatus = "archived" ProjectStatusPlanning ProjectStatus = "planning" ) type ProjectPriority string const ( PriorityLow ProjectPriority = "low" PriorityMedium ProjectPriority = "medium" PriorityHigh ProjectPriority = "high" PriorityCritical ProjectPriority = "critical" ) type ProjectMemberRole string const ( ProjectRoleOwner ProjectMemberRole = "owner" ProjectRoleManager ProjectMemberRole = "manager" ProjectRoleDeveloper ProjectMemberRole = "developer" ProjectRoleTester ProjectMemberRole = "tester" ProjectRoleViewer ProjectMemberRole = "viewer" ) func (p *Project) BeforeCreate(tx *gorm.DB) error { return nil } func (p *Project) GetMembers() ([]User, error) { var users []User err := DB.Joins("JOIN project_members ON users.id = project_members.user_id"). Where("project_members.project_id = ?", p.ID). Find(&users).Error return users, err } func (p *Project) AddMember(userID uint, role string) error { member := ProjectMember{ ProjectID: p.ID, UserID: userID, Role: role, JoinedAt: time.Now(), } return DB.Create(&member).Error } func (p *Project) RemoveMember(userID uint) error { return DB.Where("project_id = ? AND user_id = ?", p.ID, userID).Delete(&ProjectMember{}).Error } func (p *Project) GetProgress() (float64, error) { var totalTasks int64 var completedTasks int64 err := DB.Model(&Task{}).Where("project_id = ?", p.ID).Count(&totalTasks).Error if err != nil { return 0, err } if totalTasks == 0 { return 0, nil } err = DB.Model(&Task{}).Where("project_id = ? AND status = 'done'", p.ID).Count(&completedTasks).Error if err != nil { return 0, err } return float64(completedTasks) / float64(totalTasks) * 100, nil } func CreateProject(project *Project) error { return DB.Create(project).Error } func GetProjectByID(id uint) (*Project, error) { var project Project err := DB.Preload("Owner").Preload("Members.User").First(&project, id).Error return &project, err } func GetProjectsByUser(userID uint) ([]Project, error) { var projects []Project err := DB.Where("owner_id = ?", userID). Or("id IN (SELECT project_id FROM project_members WHERE user_id = ?)", userID). Preload("Owner"). Find(&projects).Error return projects, err } func UpdateProject(project *Project) error { return DB.Save(project).Error } func DeleteProject(id uint) error { return DB.Delete(&Project{}, id).Error } func ListProjects(offset, limit int, filters map[string]interface{}) ([]Project, int64, error) { var projects []Project var total int64 query := DB.Model(&Project{}) for key, value := range filters { switch key { case "status": query = query.Where("status = ?", value) case "priority": query = query.Where("priority = ?", value) case "owner_id": query = query.Where("owner_id = ?", value) } } err := query.Count(&total).Error if err != nil { return nil, 0, err } err = query.Preload("Owner").Offset(offset).Limit(limit).Find(&projects).Error return projects, total, err }