1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5// Package validate provides input validation helpers.
6package validate
7
8import (
9 "errors"
10 "fmt"
11 "strings"
12
13 "git.secluded.site/go-lunatask"
14 "github.com/google/uuid"
15
16 "git.secluded.site/lune/internal/deeplink"
17)
18
19// ErrInvalidID indicates an ID is not a valid UUID.
20var ErrInvalidID = errors.New("invalid ID: expected UUID format")
21
22// ErrInvalidReference indicates the input is not a valid UUID or deep link.
23var ErrInvalidReference = errors.New("invalid reference: expected UUID or lunatask:// deep link")
24
25// ID validates that the given string is a valid Lunatask ID (UUID).
26func ID(id string) error {
27 if _, err := uuid.Parse(id); err != nil {
28 return fmt.Errorf("%w: %s", ErrInvalidID, id)
29 }
30
31 return nil
32}
33
34// Reference parses a UUID or Lunatask deep link and returns the normalised UUID.
35// Accepts formats:
36// - UUID: "3bbf1923-64ae-4bcf-96a9-9bb86c799dab"
37// - Deep link: "lunatask://areas/3bbf1923-64ae-4bcf-96a9-9bb86c799dab"
38func Reference(input string) (string, error) {
39 id, err := deeplink.ParseID(input)
40 if err != nil {
41 return "", fmt.Errorf("%w: %s", ErrInvalidReference, input)
42 }
43
44 return id, nil
45}
46
47// ErrInvalidStatus indicates the status value is not recognized.
48var ErrInvalidStatus = errors.New("invalid status")
49
50// TaskStatus validates and normalizes a task status string.
51// Returns the corresponding lunatask.TaskStatus or an error if invalid.
52func TaskStatus(input string) (lunatask.TaskStatus, error) {
53 status := lunatask.TaskStatus(strings.ToLower(input))
54
55 switch status {
56 case lunatask.StatusLater, lunatask.StatusNext, lunatask.StatusStarted,
57 lunatask.StatusWaiting, lunatask.StatusCompleted:
58 return status, nil
59 default:
60 return "", fmt.Errorf("%w: %s", ErrInvalidStatus, input)
61 }
62}
63
64// ErrInvalidMotivation indicates the motivation value is not recognized.
65var ErrInvalidMotivation = errors.New("invalid motivation")
66
67// Motivation validates and normalizes a motivation string.
68// Returns the corresponding lunatask.Motivation or an error if invalid.
69func Motivation(input string) (lunatask.Motivation, error) {
70 motivation := lunatask.Motivation(strings.ToLower(input))
71
72 switch motivation {
73 case lunatask.MotivationUnknown, lunatask.MotivationMust,
74 lunatask.MotivationShould, lunatask.MotivationWant:
75 return motivation, nil
76 default:
77 return "", fmt.Errorf("%w: %s", ErrInvalidMotivation, input)
78 }
79}
80
81// ErrInvalidRelationship indicates the relationship strength is not recognized.
82var ErrInvalidRelationship = errors.New("invalid relationship strength")
83
84// RelationshipStrength validates and normalizes a relationship strength string.
85// Returns the corresponding lunatask.RelationshipStrength or an error if invalid.
86func RelationshipStrength(input string) (lunatask.RelationshipStrength, error) {
87 rel := lunatask.RelationshipStrength(strings.ToLower(input))
88
89 switch rel {
90 case lunatask.RelationshipFamily, lunatask.RelationshipIntimateFriend,
91 lunatask.RelationshipCloseFriend, lunatask.RelationshipCasualFriend,
92 lunatask.RelationshipAcquaintance, lunatask.RelationshipBusiness,
93 lunatask.RelationshipAlmostStranger:
94 return rel, nil
95 default:
96 return "", fmt.Errorf("%w: %s", ErrInvalidRelationship, input)
97 }
98}