mirror of
https://github.com/boolean-maybe/tiki
synced 2026-04-21 13:37:20 +00:00
143 lines
3.7 KiB
Go
143 lines
3.7 KiB
Go
package task
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/boolean-maybe/tiki/config"
|
|
)
|
|
|
|
// Priority validation constants
|
|
const (
|
|
MinPriority = 1
|
|
MaxPriority = 5
|
|
DefaultPriority = 3 // Medium
|
|
)
|
|
|
|
// ValidateTitle returns an error message if the task title is invalid.
|
|
func ValidateTitle(t *Task) string {
|
|
title := strings.TrimSpace(t.Title)
|
|
if title == "" {
|
|
return "title is required"
|
|
}
|
|
const maxTitleLength = 200
|
|
if len(title) > maxTitleLength {
|
|
return fmt.Sprintf("title exceeds maximum length of %d characters", maxTitleLength)
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// ValidateStatus returns an error message if the task status is invalid.
|
|
func ValidateStatus(t *Task) string {
|
|
if config.GetStatusRegistry().IsValid(string(t.Status)) {
|
|
return ""
|
|
}
|
|
return fmt.Sprintf("invalid status value: %s", t.Status)
|
|
}
|
|
|
|
// ValidateType returns an error message if the task type is invalid.
|
|
func ValidateType(t *Task) string {
|
|
if requireTypeRegistry().IsValid(t.Type) {
|
|
return ""
|
|
}
|
|
return fmt.Sprintf("invalid type value: %s", t.Type)
|
|
}
|
|
|
|
// ValidatePriority returns an error message if the task priority is out of range.
|
|
func ValidatePriority(t *Task) string {
|
|
if t.Priority < MinPriority || t.Priority > MaxPriority {
|
|
return fmt.Sprintf("priority must be between %d and %d", MinPriority, MaxPriority)
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// ValidatePoints returns an error message if story points are out of range.
|
|
func ValidatePoints(t *Task) string {
|
|
if t.Points == 0 {
|
|
return ""
|
|
}
|
|
const minPoints = 1
|
|
maxPoints := config.GetMaxPoints()
|
|
if t.Points < minPoints || t.Points > maxPoints {
|
|
return fmt.Sprintf("story points must be between %d and %d", minPoints, maxPoints)
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// ValidateDependsOn returns an error message if any dependency ID is malformed.
|
|
func ValidateDependsOn(t *Task) string {
|
|
for _, dep := range t.DependsOn {
|
|
if !IsValidTikiIDFormat(dep) {
|
|
return fmt.Sprintf("invalid tiki ID format: %s (expected TIKI-XXXXXX)", dep)
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// ValidateDue returns an error message if the due date is not normalized to midnight UTC.
|
|
func ValidateDue(t *Task) string {
|
|
if t.Due.IsZero() {
|
|
return ""
|
|
}
|
|
if t.Due.Hour() != 0 || t.Due.Minute() != 0 || t.Due.Second() != 0 || t.Due.Nanosecond() != 0 || t.Due.Location() != time.UTC {
|
|
return "due date must be normalized to midnight UTC (use date-only format)"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// ValidateRecurrence returns an error message if the recurrence pattern is invalid.
|
|
func ValidateRecurrence(t *Task) string {
|
|
if t.Recurrence == RecurrenceNone {
|
|
return ""
|
|
}
|
|
if !IsValidRecurrence(t.Recurrence) {
|
|
return fmt.Sprintf("invalid recurrence pattern: %s", t.Recurrence)
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// IsValidPriority checks if a priority value is within the valid range.
|
|
func IsValidPriority(priority int) bool {
|
|
return priority >= MinPriority && priority <= MaxPriority
|
|
}
|
|
|
|
// IsValidPoints checks if a points value is within the valid range.
|
|
func IsValidPoints(points int) bool {
|
|
if points == 0 {
|
|
return true
|
|
}
|
|
if points < 0 {
|
|
return false
|
|
}
|
|
return points <= config.GetMaxPoints()
|
|
}
|
|
|
|
// IsValidTikiIDFormat checks if a string matches the TIKI-XXXXXX format
|
|
// where X is an uppercase alphanumeric character.
|
|
func IsValidTikiIDFormat(id string) bool {
|
|
if len(id) != 11 || id[:5] != "TIKI-" {
|
|
return false
|
|
}
|
|
for _, c := range id[5:] {
|
|
if (c < 'A' || c > 'Z') && (c < '0' || c > '9') {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// AllValidators returns the complete list of field validation functions.
|
|
// Each returns an error message (empty string = valid).
|
|
func AllValidators() []func(*Task) string {
|
|
return []func(*Task) string{
|
|
ValidateTitle,
|
|
ValidateStatus,
|
|
ValidateType,
|
|
ValidatePriority,
|
|
ValidatePoints,
|
|
ValidateDependsOn,
|
|
ValidateDue,
|
|
ValidateRecurrence,
|
|
}
|
|
}
|