mirror of
https://github.com/Sosokker/go-chi-oapi-codegen-todolist.git
synced 2025-12-19 14:04:07 +01:00
193 lines
5.6 KiB
Go
193 lines
5.6 KiB
Go
package service
|
|
|
|
import (
|
|
"fmt"
|
|
"net/mail"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/Sosokker/todolist-backend/internal/domain"
|
|
)
|
|
|
|
const (
|
|
MinUsernameLength = 3
|
|
MaxUsernameLength = 50
|
|
MinPasswordLength = 6
|
|
MinTagNameLength = 1
|
|
MaxTagNameLength = 50
|
|
MaxTagIconLength = 30
|
|
MinTodoTitleLength = 1
|
|
MinSubtaskDescLength = 1
|
|
)
|
|
|
|
// Regex for simple hex color validation (#RRGGBB)
|
|
var hexColorRegex = regexp.MustCompile(`^#[0-9a-fA-F]{6}$`)
|
|
|
|
// ValidateUsername checks username constraints.
|
|
func ValidateUsername(username string) error {
|
|
if len(username) < MinUsernameLength || len(username) > MaxUsernameLength {
|
|
return fmt.Errorf("username must be between %d and %d characters: %w", MinUsernameLength, MaxUsernameLength, domain.ErrValidation)
|
|
}
|
|
// Add other constraints like allowed characters if needed
|
|
return nil
|
|
}
|
|
|
|
// ValidateEmail checks if the email format is valid.
|
|
func ValidateEmail(email string) error {
|
|
if _, err := mail.ParseAddress(email); err != nil {
|
|
return fmt.Errorf("invalid email format: %w", domain.ErrValidation)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidatePassword checks password length.
|
|
func ValidatePassword(password string) error {
|
|
if len(password) < MinPasswordLength {
|
|
return fmt.Errorf("password must be at least %d characters: %w", MinPasswordLength, domain.ErrValidation)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateSignupInput validates the input for user registration.
|
|
func ValidateSignupInput(creds SignupCredentials) error {
|
|
if err := ValidateUsername(creds.Username); err != nil {
|
|
return err
|
|
}
|
|
if err := ValidateEmail(creds.Email); err != nil {
|
|
return err
|
|
}
|
|
if err := ValidatePassword(creds.Password); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateLoginInput validates the input for user login.
|
|
func ValidateLoginInput(creds LoginCredentials) error {
|
|
if err := ValidateEmail(creds.Email); err != nil {
|
|
return err
|
|
}
|
|
if creds.Password == "" { // Password presence check
|
|
return fmt.Errorf("password is required: %w", domain.ErrValidation)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// IsValidHexColor checks if a string is a valid #RRGGBB hex color.
|
|
func IsValidHexColor(color string) bool {
|
|
return hexColorRegex.MatchString(color)
|
|
}
|
|
|
|
// ValidateTagName checks tag name constraints.
|
|
func ValidateTagName(name string) error {
|
|
trimmed := strings.TrimSpace(name)
|
|
if len(trimmed) < MinTagNameLength || len(trimmed) > MaxTagNameLength {
|
|
return fmt.Errorf("tag name must be between %d and %d characters: %w", MinTagNameLength, MaxTagNameLength, domain.ErrValidation)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateTagIcon checks tag icon constraints.
|
|
func ValidateTagIcon(icon *string) error {
|
|
if icon != nil && len(*icon) > MaxTagIconLength {
|
|
return fmt.Errorf("tag icon cannot be longer than %d characters: %w", MaxTagIconLength, domain.ErrValidation)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateCreateTagInput validates input for creating a tag.
|
|
func ValidateCreateTagInput(input CreateTagInput) error {
|
|
if err := ValidateTagName(input.Name); err != nil {
|
|
return err
|
|
}
|
|
if input.Color != nil && !IsValidHexColor(*input.Color) {
|
|
return fmt.Errorf("invalid color format (must be #RRGGBB): %w", domain.ErrValidation)
|
|
}
|
|
if err := ValidateTagIcon(input.Icon); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateUpdateTagInput validates input for updating a tag.
|
|
func ValidateUpdateTagInput(input UpdateTagInput) error {
|
|
if input.Name != nil {
|
|
if err := ValidateTagName(*input.Name); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if input.Color != nil && !IsValidHexColor(*input.Color) {
|
|
return fmt.Errorf("invalid color format (must be #RRGGBB): %w", domain.ErrValidation)
|
|
}
|
|
if err := ValidateTagIcon(input.Icon); err != nil { // Check pointer directly
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateTodoTitle checks title constraints.
|
|
func ValidateTodoTitle(title string) error {
|
|
if len(strings.TrimSpace(title)) < MinTodoTitleLength {
|
|
return fmt.Errorf("todo title cannot be empty: %w", domain.ErrValidation)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateCreateTodoInput validates input for creating a todo.
|
|
func ValidateCreateTodoInput(input CreateTodoInput) error {
|
|
if err := ValidateTodoTitle(input.Title); err != nil {
|
|
return err
|
|
}
|
|
// Optional: Validate Status enum value if needed
|
|
// Optional: Validate Deadline is not in the past?
|
|
return nil
|
|
}
|
|
|
|
// ValidateUpdateTodoInput validates input for updating a todo.
|
|
func ValidateUpdateTodoInput(input UpdateTodoInput) error {
|
|
if input.Title != nil {
|
|
if err := ValidateTodoTitle(*input.Title); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
// Optional: Validate Status enum value if needed
|
|
// Optional: Validate Deadline is not in the past?
|
|
return nil
|
|
}
|
|
|
|
// ValidateSubtaskDescription checks description constraints.
|
|
func ValidateSubtaskDescription(desc string) error {
|
|
if len(strings.TrimSpace(desc)) < MinSubtaskDescLength {
|
|
return fmt.Errorf("subtask description cannot be empty: %w", domain.ErrValidation)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateCreateSubtaskInput validates input for creating a subtask.
|
|
func ValidateCreateSubtaskInput(input CreateSubtaskInput) error {
|
|
return ValidateSubtaskDescription(input.Description)
|
|
}
|
|
|
|
// ValidateUpdateSubtaskInput validates input for updating a subtask.
|
|
func ValidateUpdateSubtaskInput(input UpdateSubtaskInput) error {
|
|
if input.Description != nil {
|
|
if err := ValidateSubtaskDescription(*input.Description); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateListParams checks basic pagination parameters.
|
|
func ValidateListParams(limit, offset int) error {
|
|
if limit < 0 {
|
|
return fmt.Errorf("limit cannot be negative: %w", domain.ErrValidation)
|
|
}
|
|
if offset < 0 {
|
|
return fmt.Errorf("offset cannot be negative: %w", domain.ErrValidation)
|
|
}
|
|
// Add max limit check if desired
|
|
// if limit > MaxListLimit { ... }
|
|
return nil
|
|
}
|