diff --git a/cmd/hf/main.go b/cmd/hf/main.go index cbea4e5..001b8a6 100644 --- a/cmd/hf/main.go +++ b/cmd/hf/main.go @@ -224,6 +224,12 @@ func handleGroup(group help.Group, args []string) { case "monitor": handleMonitorCommand(sub.Name, remaining) return + case "schedule-type": + handleScheduleTypeCommand(sub.Name, remaining) + return + case "assign-schedule-type": + handleAssignScheduleType(remaining) + return } if len(args) > 0 && args[0] == "update-discord-id" { @@ -1133,3 +1139,47 @@ func handleMonitorAPIKeyCommand(args []string, tokenFlag string) { output.Errorf("unknown monitor api-key subcommand: %s", subCmd) } } + +func handleScheduleTypeCommand(subCmd string, args []string) { + tokenFlag := "" + var filtered []string + for i := 0; i < len(args); i++ { + switch args[i] { + case "--token": + if i+1 < len(args) { + i++ + tokenFlag = args[i] + } + default: + filtered = append(filtered, args[i]) + } + } + + switch subCmd { + case "list": + commands.RunScheduleTypeList(tokenFlag) + case "create": + commands.RunScheduleTypeCreate(filtered, tokenFlag) + case "delete": + commands.RunScheduleTypeDelete(filtered, tokenFlag) + default: + output.Errorf("hf schedule-type %s is not implemented yet", subCmd) + } +} + +func handleAssignScheduleType(args []string) { + tokenFlag := "" + var filtered []string + for i := 0; i < len(args); i++ { + switch args[i] { + case "--token": + if i+1 < len(args) { + i++ + tokenFlag = args[i] + } + default: + filtered = append(filtered, args[i]) + } + } + commands.RunAssignScheduleType(filtered, tokenFlag) +} diff --git a/internal/commands/schedule_type.go b/internal/commands/schedule_type.go new file mode 100644 index 0000000..9d93167 --- /dev/null +++ b/internal/commands/schedule_type.go @@ -0,0 +1,165 @@ +package commands + +import ( + "bytes" + "encoding/json" + "fmt" + + "git.hangman-lab.top/zhi/HarborForge.Cli/internal/client" + "git.hangman-lab.top/zhi/HarborForge.Cli/internal/config" + "git.hangman-lab.top/zhi/HarborForge.Cli/internal/output" +) + +type scheduleTypeResponse struct { + ID int `json:"id"` + Name string `json:"name"` + WorkFrom int `json:"work_from"` + WorkTo int `json:"work_to"` + EntertainmentFrom int `json:"entertainment_from"` + EntertainmentTo int `json:"entertainment_to"` +} + +// RunScheduleTypeList implements `hf schedule-type list`. +func RunScheduleTypeList(tokenFlag string) { + token := ResolveToken(tokenFlag) + cfg, err := config.Load() + if err != nil { + output.Errorf("config error: %v", err) + } + c := client.New(cfg.BaseURL, token) + data, err := c.Get("/schedule-types/") + if err != nil { + output.Errorf("failed to list schedule types: %v", err) + } + + var types []scheduleTypeResponse + if err := json.Unmarshal(data, &types); err != nil { + output.Errorf("invalid response: %v", err) + } + + if output.JSONMode { + output.PrintJSON(types) + return + } + + if len(types) == 0 { + fmt.Println("No schedule types defined.") + return + } + + fmt.Printf("%-4s %-20s %-12s %-12s\n", "ID", "Name", "Work", "Entertainment") + fmt.Printf("%-4s %-20s %-12s %-12s\n", "----", "--------------------", "------------", "------------") + for _, t := range types { + fmt.Printf("%-4d %-20s %02d:00-%02d:00 %02d:00-%02d:00\n", + t.ID, t.Name, t.WorkFrom, t.WorkTo, t.EntertainmentFrom, t.EntertainmentTo) + } +} + +// RunScheduleTypeCreate implements `hf schedule-type create --work - --entertainment -`. +func RunScheduleTypeCreate(args []string, tokenFlag string) { + token := ResolveToken(tokenFlag) + + if len(args) < 1 { + output.Error("usage: hf schedule-type create --work - --entertainment -") + } + + name := args[0] + workFrom, workTo, entFrom, entTo := -1, -1, -1, -1 + + for i := 1; i < len(args); i++ { + switch args[i] { + case "--work": + if i+1 < len(args) { + i++ + fmt.Sscanf(args[i], "%d-%d", &workFrom, &workTo) + } + case "--entertainment": + if i+1 < len(args) { + i++ + fmt.Sscanf(args[i], "%d-%d", &entFrom, &entTo) + } + } + } + + if workFrom < 0 || workTo < 0 || entFrom < 0 || entTo < 0 { + output.Error("usage: hf schedule-type create --work - --entertainment -\n e.g.: hf schedule-type create standard --work 8-18 --entertainment 19-23") + } + + body := map[string]any{ + "name": name, + "work_from": workFrom, + "work_to": workTo, + "entertainment_from": entFrom, + "entertainment_to": entTo, + } + + cfg, err := config.Load() + if err != nil { + output.Errorf("config error: %v", err) + } + + jsonBody, _ := json.Marshal(body) + c := client.New(cfg.BaseURL, token) + data, err := c.Post("/schedule-types/", bytes.NewReader(jsonBody)) + if err != nil { + output.Errorf("failed to create schedule type: %v", err) + } + + var resp scheduleTypeResponse + json.Unmarshal(data, &resp) + fmt.Printf("Created schedule type: %s (id=%d, work=%02d:00-%02d:00, entertainment=%02d:00-%02d:00)\n", + resp.Name, resp.ID, resp.WorkFrom, resp.WorkTo, resp.EntertainmentFrom, resp.EntertainmentTo) +} + +// RunScheduleTypeDelete implements `hf schedule-type delete `. +func RunScheduleTypeDelete(args []string, tokenFlag string) { + token := ResolveToken(tokenFlag) + + if len(args) < 1 { + output.Error("usage: hf schedule-type delete ") + } + + cfg, err := config.Load() + if err != nil { + output.Errorf("config error: %v", err) + } + + c := client.New(cfg.BaseURL, token) + _, err = c.Delete("/schedule-types/" + args[0]) + if err != nil { + output.Errorf("failed to delete schedule type: %v", err) + } + fmt.Printf("Deleted schedule type %s\n", args[0]) +} + +// RunAssignScheduleType implements `hf assign-schedule-type `. +func RunAssignScheduleType(args []string, tokenFlag string) { + token := ResolveToken(tokenFlag) + + if len(args) < 2 { + output.Error("usage: hf assign-schedule-type ") + } + + agentID := args[0] + scheduleName := args[1] + + body := map[string]string{ + "schedule_type_name": scheduleName, + } + + cfg, err := config.Load() + if err != nil { + output.Errorf("config error: %v", err) + } + + jsonBody, _ := json.Marshal(body) + c := client.New(cfg.BaseURL, token) + data, err := c.Put("/schedule-types/agent/"+agentID+"/assign", bytes.NewReader(jsonBody)) + if err != nil { + output.Errorf("failed to assign schedule type: %v", err) + } + + var resp map[string]any + json.Unmarshal(data, &resp) + fmt.Printf("Assigned schedule type '%s' to agent '%s'\n", scheduleName, agentID) +} diff --git a/internal/help/surface.go b/internal/help/surface.go index 38a9d48..a8962c4 100644 --- a/internal/help/surface.go +++ b/internal/help/surface.go @@ -180,6 +180,16 @@ func CommandSurface() []Group { {Name: "api-key", Description: "Manage monitor API keys", Permitted: has(perms, "monitor.manage")}, }, }, + { + Name: "schedule-type", + Description: "Manage work/entertainment schedule types", + SubCommands: []Command{ + {Name: "list", Description: "List schedule types", Permitted: has(perms, "schedule_type.read")}, + {Name: "create", Description: "Create a schedule type", Permitted: has(perms, "schedule_type.manage")}, + {Name: "delete", Description: "Delete a schedule type", Permitted: has(perms, "schedule_type.manage")}, + }, + }, + {Name: "assign-schedule-type", Description: "Assign a schedule type to an agent: assign-schedule-type ", Permitted: has(perms, "schedule_type.manage")}, } for i := range groups {