313 lines
7.8 KiB
Go
313 lines
7.8 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
"project-dashboard/api/utils"
|
|
"project-dashboard/models"
|
|
"strconv"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type CreateProjectRequest struct {
|
|
Name string `json:"name" binding:"required"`
|
|
Description string `json:"description"`
|
|
Color string `json:"color"`
|
|
}
|
|
|
|
type UpdateProjectRequest struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
Status string `json:"status"`
|
|
Color string `json:"color"`
|
|
}
|
|
|
|
type AddMemberRequest struct {
|
|
UserID uint `json:"user_id" binding:"required"`
|
|
Role string `json:"role"`
|
|
}
|
|
|
|
// CreateProject creates a new project
|
|
func CreateProject(c *gin.Context) {
|
|
user, exists := c.Get("user")
|
|
if !exists {
|
|
utils.ErrorResponse(c, http.StatusUnauthorized, "User not authenticated")
|
|
return
|
|
}
|
|
|
|
userObj := user.(*models.User)
|
|
|
|
var req CreateProjectRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
utils.ValidationErrorResponse(c, gin.H{
|
|
"error": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
project := models.Project{
|
|
Name: req.Name,
|
|
Description: req.Description,
|
|
Color: req.Color,
|
|
OwnerID: userObj.ID,
|
|
Status: "active",
|
|
}
|
|
|
|
if project.Color == "" {
|
|
project.Color = "#3b82f6"
|
|
}
|
|
|
|
if err := models.GetDB().Create(&project).Error; err != nil {
|
|
utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to create project")
|
|
return
|
|
}
|
|
|
|
// Add owner as project member
|
|
member := models.ProjectMember{
|
|
ProjectID: project.ID,
|
|
UserID: userObj.ID,
|
|
Role: "owner",
|
|
}
|
|
models.GetDB().Create(&member)
|
|
|
|
// Load project with relationships
|
|
models.GetDB().Preload("Owner").Preload("Members").First(&project, project.ID)
|
|
|
|
utils.SuccessResponse(c, http.StatusCreated, "Project created successfully", project)
|
|
}
|
|
|
|
// GetProjects returns all projects for the current user
|
|
func GetProjects(c *gin.Context) {
|
|
user, exists := c.Get("user")
|
|
if !exists {
|
|
utils.ErrorResponse(c, http.StatusUnauthorized, "User not authenticated")
|
|
return
|
|
}
|
|
|
|
userObj := user.(*models.User)
|
|
|
|
var projects []models.Project
|
|
|
|
// Get projects where user is owner or member
|
|
if err := models.GetDB().
|
|
Preload("Owner").
|
|
Preload("Members").
|
|
Where("owner_id = ? OR id IN (SELECT project_id FROM project_members WHERE user_id = ?)",
|
|
userObj.ID, userObj.ID).
|
|
Find(&projects).Error; err != nil {
|
|
utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to fetch projects")
|
|
return
|
|
}
|
|
|
|
utils.SuccessResponse(c, http.StatusOK, "Projects retrieved successfully", projects)
|
|
}
|
|
|
|
// GetProject returns a specific project
|
|
func GetProject(c *gin.Context) {
|
|
project, exists := c.Get("project")
|
|
if !exists {
|
|
utils.ErrorResponse(c, http.StatusNotFound, "Project not found")
|
|
return
|
|
}
|
|
|
|
projectObj := project.(*models.Project)
|
|
|
|
// Load additional relationships
|
|
models.GetDB().
|
|
Preload("Owner").
|
|
Preload("Members").
|
|
Preload("Tasks").
|
|
Preload("Files").
|
|
First(projectObj, projectObj.ID)
|
|
|
|
utils.SuccessResponse(c, http.StatusOK, "Project retrieved successfully", projectObj)
|
|
}
|
|
|
|
// UpdateProject updates a project
|
|
func UpdateProject(c *gin.Context) {
|
|
project, exists := c.Get("project")
|
|
if !exists {
|
|
utils.ErrorResponse(c, http.StatusNotFound, "Project not found")
|
|
return
|
|
}
|
|
|
|
projectObj := project.(*models.Project)
|
|
user, _ := c.Get("user")
|
|
userObj := user.(*models.User)
|
|
|
|
// Check if user is owner or manager
|
|
role := projectObj.GetMemberRole(userObj.ID)
|
|
if role != "owner" && role != "manager" {
|
|
utils.ErrorResponse(c, http.StatusForbidden, "Insufficient permissions")
|
|
return
|
|
}
|
|
|
|
var req UpdateProjectRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
utils.ValidationErrorResponse(c, gin.H{
|
|
"error": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
// Update fields
|
|
if req.Name != "" {
|
|
projectObj.Name = req.Name
|
|
}
|
|
if req.Description != "" {
|
|
projectObj.Description = req.Description
|
|
}
|
|
if req.Status != "" {
|
|
projectObj.Status = req.Status
|
|
}
|
|
if req.Color != "" {
|
|
projectObj.Color = req.Color
|
|
}
|
|
|
|
if err := models.GetDB().Save(projectObj).Error; err != nil {
|
|
utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to update project")
|
|
return
|
|
}
|
|
|
|
utils.SuccessResponse(c, http.StatusOK, "Project updated successfully", projectObj)
|
|
}
|
|
|
|
// DeleteProject deletes a project
|
|
func DeleteProject(c *gin.Context) {
|
|
project, exists := c.Get("project")
|
|
if !exists {
|
|
utils.ErrorResponse(c, http.StatusNotFound, "Project not found")
|
|
return
|
|
}
|
|
|
|
projectObj := project.(*models.Project)
|
|
user, _ := c.Get("user")
|
|
userObj := user.(*models.User)
|
|
|
|
// Only owner can delete project
|
|
if !projectObj.IsOwner(userObj.ID) {
|
|
utils.ErrorResponse(c, http.StatusForbidden, "Only project owner can delete project")
|
|
return
|
|
}
|
|
|
|
if err := models.GetDB().Delete(projectObj).Error; err != nil {
|
|
utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to delete project")
|
|
return
|
|
}
|
|
|
|
utils.SuccessResponse(c, http.StatusOK, "Project deleted successfully", nil)
|
|
}
|
|
|
|
// AddMember adds a member to the project
|
|
func AddMember(c *gin.Context) {
|
|
project, exists := c.Get("project")
|
|
if !exists {
|
|
utils.ErrorResponse(c, http.StatusNotFound, "Project not found")
|
|
return
|
|
}
|
|
|
|
projectObj := project.(*models.Project)
|
|
user, _ := c.Get("user")
|
|
userObj := user.(*models.User)
|
|
|
|
// Check if user has permission to add members
|
|
role := projectObj.GetMemberRole(userObj.ID)
|
|
if role != "owner" && role != "manager" {
|
|
utils.ErrorResponse(c, http.StatusForbidden, "Insufficient permissions")
|
|
return
|
|
}
|
|
|
|
var req AddMemberRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
utils.ValidationErrorResponse(c, gin.H{
|
|
"error": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
// Check if user exists
|
|
var targetUser models.User
|
|
if err := models.GetDB().First(&targetUser, req.UserID).Error; err != nil {
|
|
utils.ErrorResponse(c, http.StatusNotFound, "User not found")
|
|
return
|
|
}
|
|
|
|
// Check if user is already a member
|
|
if projectObj.HasMember(req.UserID) {
|
|
utils.ErrorResponse(c, http.StatusConflict, "User is already a member of this project")
|
|
return
|
|
}
|
|
|
|
// Set default role
|
|
if req.Role == "" {
|
|
req.Role = "member"
|
|
}
|
|
|
|
member := models.ProjectMember{
|
|
ProjectID: projectObj.ID,
|
|
UserID: req.UserID,
|
|
Role: req.Role,
|
|
}
|
|
|
|
if err := models.GetDB().Create(&member).Error; err != nil {
|
|
utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to add member")
|
|
return
|
|
}
|
|
|
|
// Load updated project
|
|
models.GetDB().Preload("Members").First(projectObj, projectObj.ID)
|
|
|
|
utils.SuccessResponse(c, http.StatusOK, "Member added successfully", projectObj)
|
|
}
|
|
|
|
// RemoveMember removes a member from the project
|
|
func RemoveMember(c *gin.Context) {
|
|
project, exists := c.Get("project")
|
|
if !exists {
|
|
utils.ErrorResponse(c, http.StatusNotFound, "Project not found")
|
|
return
|
|
}
|
|
|
|
projectObj := project.(*models.Project)
|
|
user, _ := c.Get("user")
|
|
userObj := user.(*models.User)
|
|
|
|
// Check if user has permission to remove members
|
|
role := projectObj.GetMemberRole(userObj.ID)
|
|
if role != "owner" && role != "manager" {
|
|
utils.ErrorResponse(c, http.StatusForbidden, "Insufficient permissions")
|
|
return
|
|
}
|
|
|
|
userIDStr := c.Param("user_id")
|
|
if userIDStr == "" {
|
|
utils.ErrorResponse(c, http.StatusBadRequest, "User ID required")
|
|
return
|
|
}
|
|
|
|
userID, err := strconv.ParseUint(userIDStr, 10, 32)
|
|
if err != nil {
|
|
utils.ErrorResponse(c, http.StatusBadRequest, "Invalid user ID")
|
|
return
|
|
}
|
|
|
|
// Check if user is a member
|
|
if !projectObj.HasMember(uint(userID)) {
|
|
utils.ErrorResponse(c, http.StatusNotFound, "User is not a member of this project")
|
|
return
|
|
}
|
|
|
|
// Remove member
|
|
if err := models.GetDB().
|
|
Where("project_id = ? AND user_id = ?", projectObj.ID, uint(userID)).
|
|
Delete(&models.ProjectMember{}).Error; err != nil {
|
|
utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to remove member")
|
|
return
|
|
}
|
|
|
|
// Load updated project
|
|
models.GetDB().Preload("Members").First(projectObj, projectObj.ID)
|
|
|
|
utils.SuccessResponse(c, http.StatusOK, "Member removed successfully", projectObj)
|
|
}
|