Files
evening_detective_server/internal/services/task_service/service.go
T
2026-10-07 23:09:17 +07:00

101 lines
2.8 KiB
Go

// Package task_service implements the shared developer board.
package task_service
import (
"context"
"strings"
"time"
"unicode/utf8"
"evening_detective_server/internal/repos/tasks_repo"
)
var (
ErrInvalidTask = tasks_repo.ErrInvalidTask
ErrNotFound = tasks_repo.ErrNotFound
ErrConflict = tasks_repo.ErrConflict
ErrInvalidAssignee = tasks_repo.ErrInvalidAssignee
)
type Task = tasks_repo.Task
type Assignee = tasks_repo.Assignee
type ITasksRepo interface {
List(context.Context) ([]*Task, error)
ListAssignees(context.Context) ([]Assignee, error)
Create(context.Context, Task) (*Task, error)
Update(context.Context, Task) (*Task, error)
SetStatus(context.Context, int, int, string) (*Task, error)
Delete(context.Context, int, int) error
}
type TaskService struct{ repo ITasksRepo }
func NewTaskService(repo ITasksRepo) *TaskService { return &TaskService{repo: repo} }
func (s *TaskService) List(ctx context.Context) ([]*Task, error) { return s.repo.List(ctx) }
func (s *TaskService) ListAssignees(ctx context.Context) ([]Assignee, error) {
return s.repo.ListAssignees(ctx)
}
// ParseDueDate preserves calendar dates without a local time zone conversion.
func ParseDueDate(value string) (*time.Time, error) {
if value == "" {
return nil, nil
}
date, err := time.Parse("2006-01-02", value)
if err != nil || date.Year() < 1 {
return nil, ErrInvalidTask
}
return &date, nil
}
func validStatus(status string) bool {
return status == "new" || status == "in_progress" || status == "review" || status == "done"
}
func validate(task *Task) error {
task.Title = strings.TrimSpace(task.Title)
if task.Title == "" || strings.ContainsRune(task.Title, 0) || strings.ContainsRune(task.Description, 0) ||
utf8.RuneCountInString(task.Title) > 255 ||
utf8.RuneCountInString(task.Description) > 10000 || !validStatus(task.Status) ||
(task.AssigneeID != nil && *task.AssigneeID <= 0) {
return ErrInvalidTask
}
return nil
}
func (s *TaskService) Create(ctx context.Context, task Task) (*Task, error) {
if task.Status == "" {
task.Status = "new"
}
if err := validate(&task); err != nil {
return nil, err
}
return s.repo.Create(ctx, task)
}
func (s *TaskService) Update(ctx context.Context, task Task) (*Task, error) {
if task.ID <= 0 || task.Version <= 0 {
return nil, ErrInvalidTask
}
if err := validate(&task); err != nil {
return nil, err
}
return s.repo.Update(ctx, task)
}
func (s *TaskService) SetStatus(ctx context.Context, id, version int, status string) (*Task, error) {
if id <= 0 || version <= 0 || !validStatus(status) {
return nil, ErrInvalidTask
}
return s.repo.SetStatus(ctx, id, version, status)
}
func (s *TaskService) Delete(ctx context.Context, id, version int) error {
if id <= 0 || version <= 0 {
return ErrInvalidTask
}
return s.repo.Delete(ctx, id, version)
}