Files
dumbassDashboard/backend/api/tasks.go
2025-09-12 12:38:11 +02:00

360 lines
8.6 KiB
Go

package api
import (
"net/http"
"project-dashboard/api/utils"
"project-dashboard/models"
"time"
"github.com/gin-gonic/gin"
)
type CreateTaskRequest struct {
Title string `json:"title" binding:"required"`
Description string `json:"description"`
Priority string `json:"priority"`
DueDate string `json:"due_date"`
AssignedToID *uint `json:"assigned_to_id"`
}
type UpdateTaskRequest struct {
Title string `json:"title"`
Description string `json:"description"`
Status string `json:"status"`
Priority string `json:"priority"`
DueDate string `json:"due_date"`
AssignedToID *uint `json:"assigned_to_id"`
Position *int `json:"position"`
}
type CreateSubtaskRequest struct {
Title string `json:"title" binding:"required"`
Description string `json:"description"`
AssignedToID *uint `json:"assigned_to_id"`
}
type CreateCommentRequest struct {
Content string `json:"content" binding:"required"`
}
// CreateTask creates a new task
func CreateTask(c *gin.Context) {
user, exists := c.Get("user")
if !exists {
utils.ErrorResponse(c, http.StatusUnauthorized, "User not authenticated")
return
}
userObj := user.(*models.User)
project, _ := c.Get("project")
projectObj := project.(*models.Project)
var req CreateTaskRequest
if err := c.ShouldBindJSON(&req); err != nil {
utils.ValidationErrorResponse(c, gin.H{
"error": err.Error(),
})
return
}
task := models.Task{
Title: req.Title,
Description: req.Description,
Priority: req.Priority,
ProjectID: projectObj.ID,
CreatedByID: userObj.ID,
AssignedToID: req.AssignedToID,
Status: "todo",
}
if task.Priority == "" {
task.Priority = "medium"
}
// Parse due date if provided
if req.DueDate != "" {
if dueDate, err := time.Parse("2006-01-02T15:04:05Z07:00", req.DueDate); err == nil {
task.DueDate = &dueDate
}
}
if err := models.GetDB().Create(&task).Error; err != nil {
utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to create task")
return
}
// Load task with relationships
models.GetDB().
Preload("Project").
Preload("AssignedTo").
Preload("CreatedBy").
First(&task, task.ID)
utils.SuccessResponse(c, http.StatusCreated, "Task created successfully", task)
}
// GetTasks returns all tasks for a project
func GetTasks(c *gin.Context) {
project, exists := c.Get("project")
if !exists {
utils.ErrorResponse(c, http.StatusNotFound, "Project not found")
return
}
projectObj := project.(*models.Project)
var tasks []models.Task
if err := models.GetDB().
Preload("AssignedTo").
Preload("CreatedBy").
Preload("Comments").
Preload("Files").
Preload("Subtasks").
Preload("Labels").
Where("project_id = ?", projectObj.ID).
Order("position ASC, created_at DESC").
Find(&tasks).Error; err != nil {
utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to fetch tasks")
return
}
utils.SuccessResponse(c, http.StatusOK, "Tasks retrieved successfully", tasks)
}
// GetTask returns a specific task
func GetTask(c *gin.Context) {
project, _ := c.Get("project")
projectObj := project.(*models.Project)
taskID := c.Param("task_id")
if taskID == "" {
utils.ErrorResponse(c, http.StatusBadRequest, "Task ID required")
return
}
var task models.Task
if err := models.GetDB().
Preload("Project").
Preload("AssignedTo").
Preload("CreatedBy").
Preload("Comments").
Preload("Comments.User").
Preload("Files").
Preload("Subtasks").
Preload("Subtasks.AssignedTo").
Preload("Labels").
Where("id = ? AND project_id = ?", taskID, projectObj.ID).
First(&task).Error; err != nil {
utils.ErrorResponse(c, http.StatusNotFound, "Task not found")
return
}
utils.SuccessResponse(c, http.StatusOK, "Task retrieved successfully", task)
}
// UpdateTask updates a task
func UpdateTask(c *gin.Context) {
project, _ := c.Get("project")
projectObj := project.(*models.Project)
taskID := c.Param("task_id")
if taskID == "" {
utils.ErrorResponse(c, http.StatusBadRequest, "Task ID required")
return
}
var task models.Task
if err := models.GetDB().
Where("id = ? AND project_id = ?", taskID, projectObj.ID).
First(&task).Error; err != nil {
utils.ErrorResponse(c, http.StatusNotFound, "Task not found")
return
}
var req UpdateTaskRequest
if err := c.ShouldBindJSON(&req); err != nil {
utils.ValidationErrorResponse(c, gin.H{
"error": err.Error(),
})
return
}
// Update fields
if req.Title != "" {
task.Title = req.Title
}
if req.Description != "" {
task.Description = req.Description
}
if req.Status != "" {
task.Status = req.Status
if req.Status == "done" {
task.MarkAsCompleted()
}
}
if req.Priority != "" {
task.Priority = req.Priority
}
if req.AssignedToID != nil {
task.AssignedToID = req.AssignedToID
}
if req.Position != nil {
task.Position = *req.Position
}
// Parse due date if provided
if req.DueDate != "" {
if dueDate, err := time.Parse("2006-01-02T15:04:05Z07:00", req.DueDate); err == nil {
task.DueDate = &dueDate
}
}
if err := models.GetDB().Save(&task).Error; err != nil {
utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to update task")
return
}
// Load updated task with relationships
models.GetDB().
Preload("AssignedTo").
Preload("CreatedBy").
Preload("Comments").
Preload("Files").
Preload("Subtasks").
Preload("Labels").
First(&task, task.ID)
utils.SuccessResponse(c, http.StatusOK, "Task updated successfully", task)
}
// DeleteTask deletes a task
func DeleteTask(c *gin.Context) {
project, _ := c.Get("project")
projectObj := project.(*models.Project)
taskID := c.Param("task_id")
if taskID == "" {
utils.ErrorResponse(c, http.StatusBadRequest, "Task ID required")
return
}
var task models.Task
if err := models.GetDB().
Where("id = ? AND project_id = ?", taskID, projectObj.ID).
First(&task).Error; err != nil {
utils.ErrorResponse(c, http.StatusNotFound, "Task not found")
return
}
if err := models.GetDB().Delete(&task).Error; err != nil {
utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to delete task")
return
}
utils.SuccessResponse(c, http.StatusOK, "Task deleted successfully", nil)
}
// CreateSubtask creates a new subtask
func CreateSubtask(c *gin.Context) {
project, _ := c.Get("project")
projectObj := project.(*models.Project)
taskID := c.Param("task_id")
if taskID == "" {
utils.ErrorResponse(c, http.StatusBadRequest, "Task ID required")
return
}
// Verify task exists and belongs to project
var task models.Task
if err := models.GetDB().
Where("id = ? AND project_id = ?", taskID, projectObj.ID).
First(&task).Error; err != nil {
utils.ErrorResponse(c, http.StatusNotFound, "Task not found")
return
}
var req CreateSubtaskRequest
if err := c.ShouldBindJSON(&req); err != nil {
utils.ValidationErrorResponse(c, gin.H{
"error": err.Error(),
})
return
}
subtask := models.Subtask{
Title: req.Title,
Description: req.Description,
ParentTaskID: task.ID,
AssignedToID: req.AssignedToID,
Status: "todo",
}
if err := models.GetDB().Create(&subtask).Error; err != nil {
utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to create subtask")
return
}
// Load subtask with relationships
models.GetDB().
Preload("AssignedTo").
First(&subtask, subtask.ID)
utils.SuccessResponse(c, http.StatusCreated, "Subtask created successfully", subtask)
}
// AddComment adds a comment to a task
func AddComment(c *gin.Context) {
user, exists := c.Get("user")
if !exists {
utils.ErrorResponse(c, http.StatusUnauthorized, "User not authenticated")
return
}
userObj := user.(*models.User)
project, _ := c.Get("project")
projectObj := project.(*models.Project)
taskID := c.Param("task_id")
if taskID == "" {
utils.ErrorResponse(c, http.StatusBadRequest, "Task ID required")
return
}
// Verify task exists and belongs to project
var task models.Task
if err := models.GetDB().
Where("id = ? AND project_id = ?", taskID, projectObj.ID).
First(&task).Error; err != nil {
utils.ErrorResponse(c, http.StatusNotFound, "Task not found")
return
}
var req CreateCommentRequest
if err := c.ShouldBindJSON(&req); err != nil {
utils.ValidationErrorResponse(c, gin.H{
"error": err.Error(),
})
return
}
comment := models.Comment{
Content: req.Content,
TaskID: task.ID,
UserID: userObj.ID,
}
if err := models.GetDB().Create(&comment).Error; err != nil {
utils.ErrorResponse(c, http.StatusInternalServerError, "Failed to create comment")
return
}
// Load comment with user
models.GetDB().
Preload("User").
First(&comment, comment.ID)
utils.SuccessResponse(c, http.StatusCreated, "Comment added successfully", comment)
}