Migrate from Gin to Echo framework and add comprehensive integration tests
Major changes: - Migrate all handlers from Gin to Echo framework - Add new apperrors, echohelpers, and validator packages - Update middleware for Echo compatibility - Add ArchivedHandler to task categorization chain (archived tasks go to cancelled_tasks column) - Add 6 new integration tests: - RecurringTaskLifecycle: NextDueDate advancement for weekly/monthly tasks - MultiUserSharing: Complex sharing with user removal - TaskStateTransitions: All state transitions and kanban column changes - DateBoundaryEdgeCases: Threshold boundary testing - CascadeOperations: Residence deletion cascade effects - MultiUserOperations: Shared residence collaboration - Add single-purpose repository functions for kanban columns (GetOverdueTasks, GetDueSoonTasks, etc.) - Fix RemoveUser route param mismatch (userId -> user_id) - Fix determineExpectedColumn helper to correctly prioritize in_progress over overdue 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,16 +8,18 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/treytartt/casera-api/internal/apperrors"
|
||||
"github.com/treytartt/casera-api/internal/dto/requests"
|
||||
"github.com/treytartt/casera-api/internal/dto/responses"
|
||||
"github.com/treytartt/casera-api/internal/models"
|
||||
"github.com/treytartt/casera-api/internal/repositories"
|
||||
)
|
||||
|
||||
// Task-related errors
|
||||
// Task-related errors (DEPRECATED - kept for reference, use apperrors instead)
|
||||
// TODO: Migrate handlers to use apperrors instead of these constants
|
||||
var (
|
||||
ErrTaskNotFound = errors.New("task not found")
|
||||
ErrTaskAccessDenied = errors.New("you do not have access to this task")
|
||||
ErrTaskNotFound = errors.New("task not found")
|
||||
ErrTaskAccessDenied = errors.New("you do not have access to this task")
|
||||
ErrTaskAlreadyCancelled = errors.New("task is already cancelled")
|
||||
ErrTaskAlreadyArchived = errors.New("task is already archived")
|
||||
ErrCompletionNotFound = errors.New("task completion not found")
|
||||
@@ -71,18 +73,18 @@ func (s *TaskService) GetTask(taskID, userID uint) (*responses.TaskResponse, err
|
||||
task, err := s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrTaskNotFound
|
||||
return nil, apperrors.NotFound("error.task_not_found")
|
||||
}
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Check access via residence
|
||||
hasAccess, err := s.residenceRepo.HasAccess(task.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrTaskAccessDenied
|
||||
return nil, apperrors.Forbidden("error.task_access_denied")
|
||||
}
|
||||
|
||||
resp := responses.NewTaskResponse(task)
|
||||
@@ -95,7 +97,7 @@ func (s *TaskService) ListTasks(userID uint, now time.Time) (*responses.KanbanBo
|
||||
// Get all residence IDs accessible to user (lightweight - no preloads)
|
||||
residenceIDs, err := s.residenceRepo.FindResidenceIDsByUser(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
if len(residenceIDs) == 0 {
|
||||
@@ -110,7 +112,7 @@ func (s *TaskService) ListTasks(userID uint, now time.Time) (*responses.KanbanBo
|
||||
// Get kanban data aggregated across all residences using user's timezone-aware time
|
||||
board, err := s.taskRepo.GetKanbanDataForMultipleResidences(residenceIDs, 30, now)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
resp := responses.NewKanbanBoardResponseForAll(board)
|
||||
@@ -126,10 +128,10 @@ func (s *TaskService) GetTasksByResidence(residenceID, userID uint, daysThreshol
|
||||
// Check access
|
||||
hasAccess, err := s.residenceRepo.HasAccess(residenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrResidenceAccessDenied
|
||||
return nil, apperrors.Forbidden("error.residence_access_denied")
|
||||
}
|
||||
|
||||
if daysThreshold <= 0 {
|
||||
@@ -139,7 +141,7 @@ func (s *TaskService) GetTasksByResidence(residenceID, userID uint, daysThreshol
|
||||
// Get kanban data using user's timezone-aware time
|
||||
board, err := s.taskRepo.GetKanbanData(residenceID, daysThreshold, now)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
resp := responses.NewKanbanBoardResponse(board, residenceID)
|
||||
@@ -155,10 +157,10 @@ func (s *TaskService) CreateTask(req *requests.CreateTaskRequest, userID uint, n
|
||||
// Check residence access
|
||||
hasAccess, err := s.residenceRepo.HasAccess(req.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrResidenceAccessDenied
|
||||
return nil, apperrors.Forbidden("error.residence_access_denied")
|
||||
}
|
||||
|
||||
dueDate := req.DueDate.ToTimePtr()
|
||||
@@ -180,13 +182,13 @@ func (s *TaskService) CreateTask(req *requests.CreateTaskRequest, userID uint, n
|
||||
}
|
||||
|
||||
if err := s.taskRepo.Create(task); err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Reload with relations
|
||||
task, err = s.taskRepo.FindByID(task.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
return &responses.TaskWithSummaryResponse{
|
||||
@@ -201,18 +203,18 @@ func (s *TaskService) UpdateTask(taskID, userID uint, req *requests.UpdateTaskRe
|
||||
task, err := s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrTaskNotFound
|
||||
return nil, apperrors.NotFound("error.task_not_found")
|
||||
}
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Check access
|
||||
hasAccess, err := s.residenceRepo.HasAccess(task.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrTaskAccessDenied
|
||||
return nil, apperrors.Forbidden("error.task_access_denied")
|
||||
}
|
||||
|
||||
// Apply updates
|
||||
@@ -260,13 +262,13 @@ func (s *TaskService) UpdateTask(taskID, userID uint, req *requests.UpdateTaskRe
|
||||
}
|
||||
|
||||
if err := s.taskRepo.Update(task); err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Reload
|
||||
task, err = s.taskRepo.FindByID(task.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
return &responses.TaskWithSummaryResponse{
|
||||
@@ -280,22 +282,22 @@ func (s *TaskService) DeleteTask(taskID, userID uint) (*responses.DeleteWithSumm
|
||||
task, err := s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrTaskNotFound
|
||||
return nil, apperrors.NotFound("error.task_not_found")
|
||||
}
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Check access
|
||||
hasAccess, err := s.residenceRepo.HasAccess(task.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrTaskAccessDenied
|
||||
return nil, apperrors.Forbidden("error.task_access_denied")
|
||||
}
|
||||
|
||||
if err := s.taskRepo.Delete(taskID); err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
return &responses.DeleteWithSummaryResponse{
|
||||
@@ -312,28 +314,28 @@ func (s *TaskService) MarkInProgress(taskID, userID uint, now time.Time) (*respo
|
||||
task, err := s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrTaskNotFound
|
||||
return nil, apperrors.NotFound("error.task_not_found")
|
||||
}
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Check access
|
||||
hasAccess, err := s.residenceRepo.HasAccess(task.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrTaskAccessDenied
|
||||
return nil, apperrors.Forbidden("error.task_access_denied")
|
||||
}
|
||||
|
||||
if err := s.taskRepo.MarkInProgress(taskID); err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Reload
|
||||
task, err = s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
return &responses.TaskWithSummaryResponse{
|
||||
@@ -348,32 +350,32 @@ func (s *TaskService) CancelTask(taskID, userID uint, now time.Time) (*responses
|
||||
task, err := s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrTaskNotFound
|
||||
return nil, apperrors.NotFound("error.task_not_found")
|
||||
}
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Check access
|
||||
hasAccess, err := s.residenceRepo.HasAccess(task.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrTaskAccessDenied
|
||||
return nil, apperrors.Forbidden("error.task_access_denied")
|
||||
}
|
||||
|
||||
if task.IsCancelled {
|
||||
return nil, ErrTaskAlreadyCancelled
|
||||
return nil, apperrors.BadRequest("error.task_already_cancelled")
|
||||
}
|
||||
|
||||
if err := s.taskRepo.Cancel(taskID); err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Reload
|
||||
task, err = s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
return &responses.TaskWithSummaryResponse{
|
||||
@@ -388,28 +390,28 @@ func (s *TaskService) UncancelTask(taskID, userID uint, now time.Time) (*respons
|
||||
task, err := s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrTaskNotFound
|
||||
return nil, apperrors.NotFound("error.task_not_found")
|
||||
}
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Check access
|
||||
hasAccess, err := s.residenceRepo.HasAccess(task.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrTaskAccessDenied
|
||||
return nil, apperrors.Forbidden("error.task_access_denied")
|
||||
}
|
||||
|
||||
if err := s.taskRepo.Uncancel(taskID); err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Reload
|
||||
task, err = s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
return &responses.TaskWithSummaryResponse{
|
||||
@@ -424,32 +426,32 @@ func (s *TaskService) ArchiveTask(taskID, userID uint, now time.Time) (*response
|
||||
task, err := s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrTaskNotFound
|
||||
return nil, apperrors.NotFound("error.task_not_found")
|
||||
}
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Check access
|
||||
hasAccess, err := s.residenceRepo.HasAccess(task.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrTaskAccessDenied
|
||||
return nil, apperrors.Forbidden("error.task_access_denied")
|
||||
}
|
||||
|
||||
if task.IsArchived {
|
||||
return nil, ErrTaskAlreadyArchived
|
||||
return nil, apperrors.BadRequest("error.task_already_archived")
|
||||
}
|
||||
|
||||
if err := s.taskRepo.Archive(taskID); err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Reload
|
||||
task, err = s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
return &responses.TaskWithSummaryResponse{
|
||||
@@ -464,28 +466,28 @@ func (s *TaskService) UnarchiveTask(taskID, userID uint, now time.Time) (*respon
|
||||
task, err := s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrTaskNotFound
|
||||
return nil, apperrors.NotFound("error.task_not_found")
|
||||
}
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Check access
|
||||
hasAccess, err := s.residenceRepo.HasAccess(task.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrTaskAccessDenied
|
||||
return nil, apperrors.Forbidden("error.task_access_denied")
|
||||
}
|
||||
|
||||
if err := s.taskRepo.Unarchive(taskID); err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Reload
|
||||
task, err = s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
return &responses.TaskWithSummaryResponse{
|
||||
@@ -503,18 +505,18 @@ func (s *TaskService) CreateCompletion(req *requests.CreateTaskCompletionRequest
|
||||
task, err := s.taskRepo.FindByID(req.TaskID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrTaskNotFound
|
||||
return nil, apperrors.NotFound("error.task_not_found")
|
||||
}
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Check access
|
||||
hasAccess, err := s.residenceRepo.HasAccess(task.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrTaskAccessDenied
|
||||
return nil, apperrors.Forbidden("error.task_access_denied")
|
||||
}
|
||||
|
||||
completedAt := time.Now().UTC()
|
||||
@@ -532,7 +534,7 @@ func (s *TaskService) CreateCompletion(req *requests.CreateTaskCompletionRequest
|
||||
}
|
||||
|
||||
if err := s.taskRepo.CreateCompletion(completion); err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Update next_due_date and in_progress based on frequency
|
||||
@@ -589,7 +591,7 @@ func (s *TaskService) CreateCompletion(req *requests.CreateTaskCompletionRequest
|
||||
// Reload completion with user info and images
|
||||
completion, err = s.taskRepo.FindCompletionByID(completion.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Reload task with updated completions (so client can update kanban column)
|
||||
@@ -622,18 +624,18 @@ func (s *TaskService) QuickComplete(taskID uint, userID uint) error {
|
||||
task, err := s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return ErrTaskNotFound
|
||||
return apperrors.NotFound("error.task_not_found")
|
||||
}
|
||||
return err
|
||||
return apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Check access
|
||||
hasAccess, err := s.residenceRepo.HasAccess(task.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return err
|
||||
return apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return ErrTaskAccessDenied
|
||||
return apperrors.Forbidden("error.task_access_denied")
|
||||
}
|
||||
|
||||
completedAt := time.Now().UTC()
|
||||
@@ -646,7 +648,7 @@ func (s *TaskService) QuickComplete(taskID uint, userID uint) error {
|
||||
}
|
||||
|
||||
if err := s.taskRepo.CreateCompletion(completion); err != nil {
|
||||
return err
|
||||
return apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Update next_due_date and in_progress based on frequency
|
||||
@@ -692,7 +694,7 @@ func (s *TaskService) QuickComplete(taskID uint, userID uint) error {
|
||||
}
|
||||
if err := s.taskRepo.Update(task); err != nil {
|
||||
log.Error().Err(err).Uint("task_id", task.ID).Msg("Failed to update task after quick completion")
|
||||
return err // Return error so caller knows the update failed
|
||||
return apperrors.Internal(err) // Return error so caller knows the update failed
|
||||
}
|
||||
log.Info().Uint("task_id", task.ID).Msg("QuickComplete: Task updated successfully")
|
||||
|
||||
@@ -771,18 +773,18 @@ func (s *TaskService) GetCompletion(completionID, userID uint) (*responses.TaskC
|
||||
completion, err := s.taskRepo.FindCompletionByID(completionID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrCompletionNotFound
|
||||
return nil, apperrors.NotFound("error.completion_not_found")
|
||||
}
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Check access via task's residence
|
||||
hasAccess, err := s.residenceRepo.HasAccess(completion.Task.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrTaskAccessDenied
|
||||
return nil, apperrors.Forbidden("error.task_access_denied")
|
||||
}
|
||||
|
||||
resp := responses.NewTaskCompletionResponse(completion)
|
||||
@@ -794,7 +796,7 @@ func (s *TaskService) ListCompletions(userID uint) ([]responses.TaskCompletionRe
|
||||
// Get all residence IDs (lightweight - no preloads)
|
||||
residenceIDs, err := s.residenceRepo.FindResidenceIDsByUser(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
if len(residenceIDs) == 0 {
|
||||
@@ -803,7 +805,7 @@ func (s *TaskService) ListCompletions(userID uint) ([]responses.TaskCompletionRe
|
||||
|
||||
completions, err := s.taskRepo.FindCompletionsByUser(userID, residenceIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
return responses.NewTaskCompletionListResponse(completions), nil
|
||||
@@ -814,22 +816,22 @@ func (s *TaskService) DeleteCompletion(completionID, userID uint) (*responses.De
|
||||
completion, err := s.taskRepo.FindCompletionByID(completionID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrCompletionNotFound
|
||||
return nil, apperrors.NotFound("error.completion_not_found")
|
||||
}
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Check access
|
||||
hasAccess, err := s.residenceRepo.HasAccess(completion.Task.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrTaskAccessDenied
|
||||
return nil, apperrors.Forbidden("error.task_access_denied")
|
||||
}
|
||||
|
||||
if err := s.taskRepo.DeleteCompletion(completionID); err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
return &responses.DeleteWithSummaryResponse{
|
||||
@@ -844,24 +846,24 @@ func (s *TaskService) GetCompletionsByTask(taskID, userID uint) ([]responses.Tas
|
||||
task, err := s.taskRepo.FindByID(taskID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrTaskNotFound
|
||||
return nil, apperrors.NotFound("error.task_not_found")
|
||||
}
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
// Check access via residence
|
||||
hasAccess, err := s.residenceRepo.HasAccess(task.ResidenceID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrTaskAccessDenied
|
||||
return nil, apperrors.Forbidden("error.task_access_denied")
|
||||
}
|
||||
|
||||
// Get completions for the task
|
||||
completions, err := s.taskRepo.FindCompletionsByTask(taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
return responses.NewTaskCompletionListResponse(completions), nil
|
||||
@@ -873,7 +875,7 @@ func (s *TaskService) GetCompletionsByTask(taskID, userID uint) ([]responses.Tas
|
||||
func (s *TaskService) GetCategories() ([]responses.TaskCategoryResponse, error) {
|
||||
categories, err := s.taskRepo.GetAllCategories()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
result := make([]responses.TaskCategoryResponse, len(categories))
|
||||
@@ -887,7 +889,7 @@ func (s *TaskService) GetCategories() ([]responses.TaskCategoryResponse, error)
|
||||
func (s *TaskService) GetPriorities() ([]responses.TaskPriorityResponse, error) {
|
||||
priorities, err := s.taskRepo.GetAllPriorities()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
result := make([]responses.TaskPriorityResponse, len(priorities))
|
||||
@@ -901,7 +903,7 @@ func (s *TaskService) GetPriorities() ([]responses.TaskPriorityResponse, error)
|
||||
func (s *TaskService) GetFrequencies() ([]responses.TaskFrequencyResponse, error) {
|
||||
frequencies, err := s.taskRepo.GetAllFrequencies()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, apperrors.Internal(err)
|
||||
}
|
||||
|
||||
result := make([]responses.TaskFrequencyResponse, len(frequencies))
|
||||
|
||||
Reference in New Issue
Block a user