first commit
This commit is contained in:
312
backend/api/projects.go
Normal file
312
backend/api/projects.go
Normal file
@@ -0,0 +1,312 @@
|
||||
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)
|
||||
}
|
Reference in New Issue
Block a user