@@ -0,0 +1,117 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gardomatic.kleiax.de/internal/platform/validate"
|
||||
)
|
||||
|
||||
// TaskTriggerType identifies how a species task template calculates its due window.
|
||||
type TaskTriggerType string
|
||||
|
||||
// TaskDurationUnit is the calendar unit used for offsets and durations.
|
||||
type TaskDurationUnit string
|
||||
|
||||
// TaskTemplateOrigin identifies whether a template was entered manually or derived from species data.
|
||||
type TaskTemplateOrigin string
|
||||
|
||||
// Supported task duration units.
|
||||
const (
|
||||
TaskDurationDay TaskDurationUnit = "day"
|
||||
TaskDurationWeek TaskDurationUnit = "week"
|
||||
TaskDurationMonth TaskDurationUnit = "month"
|
||||
)
|
||||
|
||||
// Supported task trigger types.
|
||||
const (
|
||||
// TaskTriggerMonthOfYear repeats within a calendar-year date window.
|
||||
TaskTriggerMonthOfYear TaskTriggerType = "month_of_year"
|
||||
// TaskTriggerRelativeToPlanting is offset from the planting date.
|
||||
TaskTriggerRelativeToPlanting TaskTriggerType = "relative_to_planting"
|
||||
// TaskTriggerRelativeToLastTask is offset from the last completion.
|
||||
TaskTriggerRelativeToLastTask TaskTriggerType = "relative_to_last_task"
|
||||
TaskTriggerRelativeToSowing TaskTriggerType = "relative_to_sowing"
|
||||
TaskTriggerRelativeToHarvest TaskTriggerType = "relative_to_harvest"
|
||||
TaskTriggerRelativeToSpeciesPlanting TaskTriggerType = "relative_to_species_planting"
|
||||
)
|
||||
|
||||
// Supported template origins.
|
||||
const (
|
||||
TaskTemplateOriginManual TaskTemplateOrigin = "manual"
|
||||
TaskTemplateOriginSeasonSowing TaskTemplateOrigin = "season_sowing"
|
||||
TaskTemplateOriginSeasonPlanting TaskTemplateOrigin = "season_planting"
|
||||
TaskTemplateOriginSeasonHarvest TaskTemplateOrigin = "season_harvest"
|
||||
)
|
||||
|
||||
// SpeciesTaskTemplateModelInterface persists recurring rules for species tasks.
|
||||
type SpeciesTaskTemplateModelInterface interface {
|
||||
Insert(template SpeciesTaskTemplate) (SpeciesTaskTemplate, error)
|
||||
Get(gardenID, id int) (SpeciesTaskTemplate, error)
|
||||
GetAllForSpecies(gardenID, speciesID int) ([]SpeciesTaskTemplate, error)
|
||||
Update(gardenID int, template SpeciesTaskTemplate) (SpeciesTaskTemplate, error)
|
||||
Delete(gardenID, id int) error
|
||||
}
|
||||
|
||||
// ValidateSpeciesTaskTemplate applies scheduling and recurrence rules to a
|
||||
// species task template.
|
||||
func ValidateSpeciesTaskTemplate(v *validate.Validator, template SpeciesTaskTemplate) {
|
||||
v.Check(strings.TrimSpace(template.Title) != "", "title", "must be provided")
|
||||
v.Check(len(template.Title) <= 500, "title", "must not be more than 500 bytes long")
|
||||
v.Check(len(template.Description) <= 10_000, "description", "must not be more than 10000 bytes long")
|
||||
v.Check(template.Priority >= -100 && template.Priority <= 100, "priority", "must be between -100 and 100")
|
||||
v.Check(template.TriggerType == TaskTriggerMonthOfYear || template.TriggerType == TaskTriggerRelativeToPlanting || template.TriggerType == TaskTriggerRelativeToLastTask || template.TriggerType == TaskTriggerRelativeToSowing || template.TriggerType == TaskTriggerRelativeToHarvest || template.TriggerType == TaskTriggerRelativeToSpeciesPlanting, "trigger_type", "is invalid")
|
||||
v.Check(template.Origin == TaskTemplateOriginManual || template.Origin == TaskTemplateOriginSeasonSowing || template.Origin == TaskTemplateOriginSeasonPlanting || template.Origin == TaskTemplateOriginSeasonHarvest, "origin", "is invalid")
|
||||
if template.TriggerType == TaskTriggerMonthOfYear {
|
||||
v.Check(template.MonthFrom != nil && *template.MonthFrom >= 1 && *template.MonthFrom <= 12, "month_from", "must be between 1 and 12")
|
||||
validateTemplateDay(v, "day_from", template.DayFrom)
|
||||
v.Check(template.DayFrom != nil, "day_from", "must be provided")
|
||||
} else {
|
||||
v.Check(template.TriggerOffset >= 0, "trigger_offset", "must not be negative")
|
||||
}
|
||||
v.Check(template.Duration >= 0, "duration", "must not be negative")
|
||||
v.Check(validTaskDurationUnit(template.DurationUnit), "duration_unit", "is invalid")
|
||||
v.Check(validTaskDurationUnit(template.TriggerOffsetUnit), "trigger_offset_unit", "is invalid")
|
||||
v.Check(template.Recurrence == TaskRecurrenceNone || template.Recurrence == TaskRecurrenceDaily || template.Recurrence == TaskRecurrenceWeekly || template.Recurrence == TaskRecurrenceMonthly || template.Recurrence == TaskRecurrenceYearly, "recurrence", "is invalid")
|
||||
if template.Recurrence != TaskRecurrenceNone {
|
||||
v.Check(template.RecurrenceInterval > 0, "recurrence_interval", "must be greater than zero")
|
||||
}
|
||||
}
|
||||
|
||||
func validTaskDurationUnit(unit TaskDurationUnit) bool {
|
||||
return unit == TaskDurationDay || unit == TaskDurationWeek || unit == TaskDurationMonth
|
||||
}
|
||||
|
||||
func validateTemplateDay(v *validate.Validator, field string, value *int) {
|
||||
if value != nil {
|
||||
v.Check(*value >= 1 && *value <= 31, field, "must be between 1 and 31")
|
||||
}
|
||||
}
|
||||
|
||||
// SpeciesTaskTemplate defines a recurring task rule for a species.
|
||||
type SpeciesTaskTemplate struct {
|
||||
ID int `json:"id"`
|
||||
SpeciesID int `json:"species_id"`
|
||||
Origin TaskTemplateOrigin `json:"origin"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
TriggerType TaskTriggerType `json:"trigger_type"`
|
||||
MonthFrom *int `json:"month_from,omitempty"`
|
||||
DayFrom *int `json:"day_from,omitempty"`
|
||||
MonthTo *int `json:"month_to,omitempty"`
|
||||
DayTo *int `json:"day_to,omitempty"`
|
||||
OffsetDaysFrom *int `json:"offset_days_from,omitempty"`
|
||||
OffsetDaysTo *int `json:"offset_days_to,omitempty"`
|
||||
IntervalDays *int `json:"interval_days,omitempty"`
|
||||
TriggerOffset int `json:"trigger_offset"`
|
||||
TriggerOffsetUnit TaskDurationUnit `json:"trigger_offset_unit"`
|
||||
Duration int `json:"duration"`
|
||||
DurationUnit TaskDurationUnit `json:"duration_unit"`
|
||||
Recurrence TaskRecurrence `json:"recurrence,omitempty"`
|
||||
RecurrenceInterval int `json:"recurrence_interval"`
|
||||
Priority int `json:"priority"`
|
||||
Active bool `json:"active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
Reference in New Issue
Block a user