Initial commit: Gitea Project Management System
Features: - Complete project management system with Epic/Story/Task hierarchy - Vue.js 3 + Element Plus frontend with kanban board - Go backend with Gin framework and GORM - OAuth2 integration with Gitea - Docker containerization with MySQL - RESTful API for project, task, and user management - JWT authentication and authorization - Responsive web interface with dashboard
This commit is contained in:
163
internal/models/project.go
Normal file
163
internal/models/project.go
Normal file
@@ -0,0 +1,163 @@
|
||||
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
|
||||
}
|
Reference in New Issue
Block a user