package client import ( "fmt" "net/http" "net/url" "task/internal/command" "task/internal/ticket" ) // Executor implements command.Executor via daemon mutation endpoints. type Executor struct{ c *Client } func (c *Client) Executor() *Executor { return &Executor{c: c} } func (e *Executor) Do(cmd command.Command) error { switch c := cmd.(type) { case *command.CreateTicket: var out ticket.Ticket if err := e.c.do(http.MethodPost, "/v1/tickets", c.Ticket, &out); err != nil { return err } c.Ticket = out return nil case *command.UpdateTicket: return e.c.do(http.MethodPatch, "/v1/tickets/"+url.PathEscape(c.After.ID), c.After, nil) case *command.DeleteTicket: return e.c.do(http.MethodDelete, "/v1/tickets/"+url.PathEscape(c.Snapshot.ID), nil, nil) case *command.MoveTicket: var out ticket.Ticket if err := e.c.do(http.MethodPost, "/v1/tickets/"+url.PathEscape(c.Before.ID)+"/move", map[string]string{ "toProjectId": c.After.ProjectID, }, &out); err != nil { return err } c.After = out return nil case *command.AddTimeEntry: var out ticket.TimeEntry if err := e.c.do(http.MethodPost, "/v1/time", c.Entry, &out); err != nil { return err } c.Entry = out return nil case *command.RemoveTimeEntry: return e.c.do(http.MethodDelete, "/v1/time/"+url.PathEscape(c.Snapshot.ID), nil, nil) case *command.UpdateTimeEntry: return e.c.do(http.MethodPatch, "/v1/time/"+url.PathEscape(c.After.ID), c.After, nil) default: return fmt.Errorf("unsupported command type %T", cmd) } } func (e *Executor) Undo() error { return e.c.do(http.MethodPost, "/v1/undo", map[string]any{}, nil) } func (e *Executor) Redo() error { return e.c.do(http.MethodPost, "/v1/redo", map[string]any{}, nil) } func (e *Executor) CanUndo() bool { st, err := e.status() if err != nil { return false } return st.CanUndo } func (e *Executor) CanRedo() bool { st, err := e.status() if err != nil { return false } return st.CanRedo } func (e *Executor) LastUndoName() string { st, _ := e.status() return st.LastUndoName } func (e *Executor) LastRedoName() string { st, _ := e.status() return st.LastRedoName } type historyStatus struct { CanUndo bool `json:"canUndo"` CanRedo bool `json:"canRedo"` LastUndoName string `json:"lastUndoName"` LastRedoName string `json:"lastRedoName"` } func (e *Executor) status() (historyStatus, error) { var st historyStatus err := e.c.do(http.MethodGet, "/v1/history", nil, &st) return st, err }