package app import ( "context" "errors" "fmt" "net/http" "os" "path/filepath" "strings" "time" ) func cliToken(args []string) error { if len(args) < 1 { return errors.New("usage: gitocean token ") } cfg, err := loadConfig() if err != nil { return err } switch args[0] { case "list": jsonOut := len(args) > 1 && args[1] == "--json" if len(args) > 2 || (len(args) == 2 && !jsonOut) { return errors.New("usage: gitocean token list [--json]") } var out []TokenInfo if err := apiRequest(context.Background(), cfg.Server, http.MethodGet, "/api/tokens", cfg.Token, nil, &out); err != nil { return err } if jsonOut { printJSON(out) return nil } for _, t := range out { status := "revoked/expired" if t.Active { status = "active" } fmt.Printf("%-6d %-15s created=%s expires=%s\n", t.ID, status, t.CreatedAt.Format(time.RFC3339), t.ExpiresAt.Format(time.RFC3339)) } return nil case "revoke": if len(args) != 2 { return errors.New("usage: gitocean token revoke TOKEN_ID") } return apiRequest(context.Background(), cfg.Server, http.MethodDelete, "/api/tokens/"+args[1], cfg.Token, nil, nil) case "prune": return apiRequest(context.Background(), cfg.Server, http.MethodPost, "/api/tokens/prune", cfg.Token, nil, nil) default: return fmt.Errorf("unknown token command %q", args[0]) } } func cliAdmin(args []string) error { if len(args) < 2 { return errors.New("usage: gitocean admin users list | repos list | storage check | tokens prune") } cfg, err := loadConfig() if err != nil { return err } switch args[0] + " " + args[1] { case "users list": var out []User if err := apiRequest(context.Background(), cfg.Server, http.MethodGet, "/api/admin/users", cfg.Token, nil, &out); err != nil { return err } for _, u := range out { fmt.Printf("%-20s %-30s admin=%v\n", u.Username, u.Email, u.IsAdmin) } return nil case "users delete": if len(args) != 3 { return errors.New("usage: gitocean admin users delete USER") } return apiRequest(context.Background(), cfg.Server, http.MethodDelete, "/api/admin/users/"+strings.ToLower(args[2]), cfg.Token, nil, nil) case "repos list": var out []Repository if err := apiRequest(context.Background(), cfg.Server, http.MethodGet, "/api/admin/repos", cfg.Token, nil, &out); err != nil { return err } printRepoTable(out) return nil case "storage check": serverCfg, err := loadServerConfig(defaultServerConfigPath()) if err != nil { return err } return filepath.Walk(filepath.Join(serverCfg.Storage, "repos"), func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info != nil && info.IsDir() && strings.HasSuffix(path, ".git") { fmt.Println(path) } return nil }) case "tokens prune": return apiRequest(context.Background(), cfg.Server, http.MethodPost, "/api/admin/tokens/prune", cfg.Token, nil, nil) default: return errors.New("usage: gitocean admin users list | repos list | storage check | tokens prune") } } func cliBackup(args []string) error { if len(args) != 2 { return errors.New("usage: gitocean backup create FILE | restore FILE") } cfg, err := loadServerConfig(defaultServerConfigPath()) if err != nil { return err } switch args[0] { case "create": return createBackup(cfg, args[1]) case "restore": return restoreBackup(cfg, args[1]) default: return errors.New("usage: gitocean backup create FILE | restore FILE") } }