Files
futur-web-app/server/internal/service/todo_service.go
2025-11-03 12:24:01 +02:00

182 lines
5.1 KiB
Go

package service
import (
"context"
"errors"
"go-server/internal/models"
"go-server/internal/repository"
"time"
)
type TodoService struct {
todoRepo *repository.TodoRepository
}
func NewTodoService(todoRepo *repository.TodoRepository) *TodoService {
return &TodoService{
todoRepo: todoRepo,
}
}
// CreateTodoRequest represents the request to create a new todo
type CreateTodoRequest struct {
Title string `json:"title" validate:"required,min=1,max=200"`
Description string `json:"description" validate:"max=1000"`
Color string `json:"color" validate:"required,hexcolor"`
}
// UpdateTodoRequest represents the request to update a todo
type UpdateTodoRequest struct {
Title string `json:"title" validate:"required,min=1,max=200"`
Description string `json:"description" validate:"max=1000"`
Color string `json:"color" validate:"required,hexcolor"`
}
// CompleteTodoRequest represents the request to complete a todo
type CompleteTodoRequest struct {
Description string `json:"description" validate:"max=1000"`
}
// CreateTodo creates a new todo for a user
func (s *TodoService) CreateTodo(ctx context.Context, userID models.ULID, req CreateTodoRequest) (*models.Todo, error) {
todo := &models.Todo{
UserID: userID,
Title: req.Title,
Description: req.Description,
Color: req.Color,
IsActive: true,
}
err := s.todoRepo.CreateTodo(ctx, todo)
if err != nil {
return nil, err
}
return todo, nil
}
// GetTodosWithStats gets all todos for a user with completion statistics
func (s *TodoService) GetTodosWithStats(ctx context.Context, userID models.ULID) ([]models.TodoWithStats, error) {
return s.todoRepo.GetTodosWithStats(ctx, userID)
}
// GetTodoByID gets a todo by ID (with user verification)
func (s *TodoService) GetTodoByID(ctx context.Context, todoID, userID models.ULID) (*models.Todo, error) {
return s.todoRepo.GetTodoByID(ctx, todoID, userID)
}
// UpdateTodo updates a todo
func (s *TodoService) UpdateTodo(ctx context.Context, todoID, userID models.ULID, req UpdateTodoRequest) (*models.Todo, error) {
todo, err := s.todoRepo.GetTodoByID(ctx, todoID, userID)
if err != nil {
return nil, err
}
todo.Title = req.Title
todo.Description = req.Description
todo.Color = req.Color
err = s.todoRepo.UpdateTodo(ctx, todo)
if err != nil {
return nil, err
}
return todo, nil
}
// DeleteTodo deletes (deactivates) a todo
func (s *TodoService) DeleteTodo(ctx context.Context, todoID, userID models.ULID) error {
return s.todoRepo.DeleteTodo(ctx, todoID, userID)
}
// CompleteTodo marks a todo as completed for today
func (s *TodoService) CompleteTodo(ctx context.Context, todoID, userID models.ULID, req CompleteTodoRequest) error {
// First check if the todo exists and belongs to the user
todo, err := s.todoRepo.GetTodoByID(ctx, todoID, userID)
if err != nil {
return err
}
// Check if already completed today
completedToday, err := s.todoRepo.CheckTodoCompletedToday(ctx, todoID, userID)
if err != nil {
return err
}
if completedToday {
return errors.New("todo already completed today")
}
// Create completion record
completion := &models.TodoCompletion{
TodoID: todo.ID,
UserID: userID,
CompletedAt: time.Now(),
Description: req.Description,
}
return s.todoRepo.CompleteTodo(ctx, completion)
}
// GetTodaysSummary gets today's todo summary
func (s *TodoService) GetTodaysSummary(ctx context.Context, userID models.ULID) (*models.DailyTodoSummary, error) {
todos, err := s.todoRepo.GetTodosWithStats(ctx, userID)
if err != nil {
return nil, err
}
completedCount := 0
for _, todo := range todos {
if todo.CompletedToday {
completedCount++
}
}
summary := &models.DailyTodoSummary{
Date: time.Now(),
Todos: todos,
CompletedCount: completedCount,
TotalCount: len(todos),
}
return summary, nil
}
// GetActivityLog gets the user's activity log with pagination
func (s *TodoService) GetActivityLog(ctx context.Context, userID models.ULID, limit, offset int) ([]models.TodoCompletion, error) {
if limit <= 0 {
limit = 50 // Default limit
}
if limit > 200 {
limit = 200 // Max limit
}
return s.todoRepo.GetActivityLog(ctx, userID, limit, offset)
}
// GetActivityLogByDate gets activity log for a specific date
func (s *TodoService) GetActivityLogByDate(ctx context.Context, userID models.ULID, date time.Time) ([]models.TodoCompletion, error) {
return s.todoRepo.GetActivityLogByDate(ctx, userID, date)
}
// GetWeeklySummary gets a summary of the past 7 days
func (s *TodoService) GetWeeklySummary(ctx context.Context, userID models.ULID) (map[string][]models.TodoCompletion, error) {
endDate := time.Now().Add(24 * time.Hour) // Include today
startDate := endDate.Add(-7 * 24 * time.Hour) // 7 days ago
completions, err := s.todoRepo.GetCompletionsByDateRange(ctx, userID, startDate, endDate)
if err != nil {
return nil, err
}
// Group by date
dailyCompletions := make(map[string][]models.TodoCompletion)
for _, completion := range completions {
dateKey := completion.CompletedAt.Format("2006-01-02")
dailyCompletions[dateKey] = append(dailyCompletions[dateKey], completion)
}
return dailyCompletions, nil
}