package models import ( "context" "time" ) type Task struct { ID string `json:"id" db:"task_id"` UserID string `json:"-" db:"user_id"` ItemID string `json:"itemId" db:"item_id"` ProjectID string `json:"projectId" db:"project_id"` ItemAmount int `json:"itemAmount" db:"item_amount"` Name string `json:"name" db:"name"` Description string `json:"description" db:"description"` Icon string `json:"icon" db:"icon"` Active bool `json:"active" db:"active"` CreatedTime time.Time `json:"createdTime" db:"created_time"` EndTime *time.Time `json:"endTime" db:"end_time"` StatusTag *string `json:"statusTag" db:"status_tag"` } func (task *Task) Update(update TaskUpdate) { if update.ItemID != nil { task.ItemID = *update.ItemID } if update.ItemAmount != nil { task.ItemAmount = *update.ItemAmount } if update.Name != nil { task.Name = *update.Name } if update.Description != nil { task.Description = *update.Description } if update.Active != nil { task.Active = *update.Active } if update.EndTime != nil { endTimeCopy := update.EndTime.UTC() task.EndTime = &endTimeCopy } if update.ClearEndTime { task.EndTime = nil } if update.StatusTag != nil { task.StatusTag = update.StatusTag } if update.ClearStatusTag { task.StatusTag = nil } if update.ProjectID != nil { task.ProjectID = *update.ProjectID } } type TaskUpdate struct { ItemID *string `json:"itemId"` ItemAmount *int `json:"itemAmount"` Name *string `json:"name"` Description *string `json:"description"` Active *bool `json:"active"` EndTime *time.Time `json:"endTime"` ClearEndTime bool `json:"clearEndTime"` StatusTag *string `json:"statusTag"` ClearStatusTag bool `json:"clearStatusTag"` ProjectID *string `json:"projectId"` } type TaskLink struct { TaskID string `json:"taskId" db:"task_id"` ProjectID string `json:"projectId" db:"project_id"` } type TaskWithProject struct { Task Project *Project `json:"project,omitempty"` } type TaskResult struct { Task Item *Item `json:"item"` Logs []*LogWithSecondaryItem `json:"logs"` CompletedAmount int `json:"completedAmount"` Project *Project `json:"project,omitempty"` } type TaskFilter struct { UserID string Active *bool Expiring *bool IDs []string ItemIDs []string ProjectIDs []string } var taskStatusOrder = []string{"", "to do", "on hold", "completed", "failed", "declined"} type TaskSorter struct { Data []*TaskResult Fields []string } func (s *TaskSorter) Valid() bool { for _, field := range s.Fields { switch field { case "name", "-name", "createdTime", "-createdTime", "amount", "-amount", "status", "-status": default: return false } } return true } func (s TaskSorter) Len() int { return len(s.Data) } func (s TaskSorter) Less(i, j int) bool { a := s.Data[i] b := s.Data[j] for _, field := range s.Fields { switch field { case "status", "-status": as := "" if a.StatusTag != nil { as = *a.StatusTag } bs := "" if b.StatusTag != nil { bs = *b.StatusTag } if as != bs { asi := 1000 bsi := 1000 for i, sn := range taskStatusOrder { if sn == as { asi = i } if sn == bs { bsi = i } } if field == "-status" { return asi > bsi } else { return asi < bsi } } case "amount": if a.ItemAmount != b.ItemAmount { return a.ItemAmount < b.ItemAmount } case "-amount": if a.ItemAmount != b.ItemAmount { return a.ItemAmount > b.ItemAmount } case "name": if a.Name != b.Name { return a.Name < b.Name } case "-name": if a.Name != b.Name { return a.Name > b.Name } case "-time": return a.CreatedTime.After(b.CreatedTime) case "time": return a.CreatedTime.Before(b.CreatedTime) } } return a.CreatedTime.Before(b.CreatedTime) } func (s TaskSorter) Swap(i, j int) { s.Data[i], s.Data[j] = s.Data[j], s.Data[i] } type TaskRepository interface { Find(ctx context.Context, id string) (*Task, error) List(ctx context.Context, filter TaskFilter) ([]*Task, error) ListWithLinks(ctx context.Context, filter TaskFilter) ([]*Task, []*TaskLink, error) Insert(ctx context.Context, task Task) error Update(ctx context.Context, task Task) error CreateLink(ctx context.Context, link TaskLink) error DeleteLink(ctx context.Context, link TaskLink) error UnlinkTask(ctx context.Context, task Task) error UnlinkProject(ctx context.Context, project Project) error Delete(ctx context.Context, task Task) error }