first commit

This commit is contained in:
2025-09-12 12:38:11 +02:00
commit 0db2fd0314
46 changed files with 23221 additions and 0 deletions

312
backend/api/projects.go Normal file
View 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)
}