Skip to content

Commit 6d3adb4

Browse files
mycollablabclaude
andcommitted
Implement full AXL parity (Phases 1–16, ~200 resources)
Adds ~27k lines across 108 files to bring AXL coverage from ~6% to near-full parity. Client layer (internal/client/): - axl_hunt, axl_features, axl_appusers, axl_actions: hunt groups/lists/pilots, call park, pickup groups, meet-me, app users, user groups, CTI route points, phone/device actions - axl_templates, axl_sip: device config templates, SIP profiles/security/realms/dial rules - axl_network, axl_media: locations, regions, SRST, DHCP, media resources, MOH - axl_dialplan (extended): called/calling party transforms, route filters, AAR, time periods - axl_ldap, axl_mobility, axl_voicemail: LDAP, remote destinations, device mobility, voicemail - axl_h323, axl_vpn, axl_security: H.323 gateways/phones/trunks, VPN, credential policies - axl_admin: UC services, service profiles, application servers, SNMP, service parameters - axl_presence, axl_uc_features: presence groups, conference now, MLPP, FAC, CMC - axl_wireless, axl_ime, axl_ccd: WiFi, IME federation, CCD/SAF - axl_readonly: cluster version, process node services, route plan, licensed users Command layer (cmd/): ~80 new top-level commands following consolidated single-file CRUD pattern; all self-register via init() without modifying root.go (except Phase 1 additions). skill/SKILL.md: Refactored from exhaustive per-command tables to discovery-based design — grouped taxonomy + cucm --help directive replaces 175-line static command tables; non- discoverable content (SQL schema, type codes, association JOIN patterns) preserved in full. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent adfc84b commit 6d3adb4

108 files changed

Lines changed: 26891 additions & 317 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmd/app_users.go

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package cmd
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
7+
"github.com/cloverhound/cucm-cli/internal/appconfig"
8+
"github.com/cloverhound/cucm-cli/internal/auth"
9+
"github.com/cloverhound/cucm-cli/internal/client"
10+
"github.com/cloverhound/cucm-cli/internal/output"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
var appUsersCmd = &cobra.Command{
15+
Use: "app-users",
16+
Aliases: []string{"au", "app-user"},
17+
Short: "Manage application users",
18+
Long: `List, get, add, update, and remove CUCM application users.`,
19+
}
20+
21+
var auListUserid string
22+
23+
var auListCmd = &cobra.Command{
24+
Use: "list",
25+
Short: "List application users",
26+
RunE: runAUList,
27+
}
28+
29+
func runAUList(cmd *cobra.Command, args []string) error {
30+
clusterName, err := resolveCluster(cmd)
31+
if err != nil { return err }
32+
cfg, err := appconfig.LoadConfig()
33+
if err != nil { return fmt.Errorf("failed to load config: %w", err) }
34+
clusterCfg, err := appconfig.GetCluster(cfg, clusterName)
35+
if err != nil { return err }
36+
user, pass, err := auth.ResolveCreds(clusterCfg, auth.CredTypeAXL)
37+
if err != nil { return fmt.Errorf("failed to resolve credentials: %w", err) }
38+
results, err := client.ListAppUser(clusterCfg.Host, user, pass, clusterCfg.Version, auListUserid, maxFlag)
39+
if err != nil { return fmt.Errorf("failed to list app users: %w", err) }
40+
return output.Print(results, outputFlag)
41+
}
42+
43+
var auGetCmd = &cobra.Command{
44+
Use: "get <userid>",
45+
Short: "Get application user details",
46+
Args: cobra.ExactArgs(1),
47+
RunE: runAUGet,
48+
}
49+
50+
func runAUGet(cmd *cobra.Command, args []string) error {
51+
clusterName, err := resolveCluster(cmd)
52+
if err != nil { return err }
53+
cfg, err := appconfig.LoadConfig()
54+
if err != nil { return fmt.Errorf("failed to load config: %w", err) }
55+
clusterCfg, err := appconfig.GetCluster(cfg, clusterName)
56+
if err != nil { return err }
57+
user, pass, err := auth.ResolveCreds(clusterCfg, auth.CredTypeAXL)
58+
if err != nil { return fmt.Errorf("failed to resolve credentials: %w", err) }
59+
result, err := client.GetAppUser(clusterCfg.Host, user, pass, clusterCfg.Version, args[0])
60+
if err != nil { return fmt.Errorf("failed to get app user: %w", err) }
61+
return output.Print(result, outputFlag)
62+
}
63+
64+
var (
65+
auAddUserid string
66+
auAddPassword string
67+
auAddDescription string
68+
auAddPresenceGroup string
69+
)
70+
71+
var auAddCmd = &cobra.Command{
72+
Use: "add",
73+
Short: "Add an application user",
74+
RunE: runAUAdd,
75+
}
76+
77+
func runAUAdd(cmd *cobra.Command, args []string) error {
78+
if auAddUserid == "" { return fmt.Errorf("--userid is required") }
79+
clusterName, err := resolveCluster(cmd)
80+
if err != nil { return err }
81+
cfg, err := appconfig.LoadConfig()
82+
if err != nil { return fmt.Errorf("failed to load config: %w", err) }
83+
clusterCfg, err := appconfig.GetCluster(cfg, clusterName)
84+
if err != nil { return err }
85+
user, pass, err := auth.ResolveCreds(clusterCfg, auth.CredTypeAXL)
86+
if err != nil { return fmt.Errorf("failed to resolve credentials: %w", err) }
87+
params := map[string]string{
88+
"userid": auAddUserid,
89+
"password": auAddPassword,
90+
"description": auAddDescription,
91+
"presenceGroupName": auAddPresenceGroup,
92+
}
93+
if err := client.AddAppUser(clusterCfg.Host, user, pass, clusterCfg.Version, params); err != nil {
94+
if errors.Is(err, client.ErrDryRun) { return nil }
95+
return fmt.Errorf("failed to add app user: %w", err)
96+
}
97+
fmt.Printf("Application user '%s' added successfully\n", auAddUserid)
98+
return nil
99+
}
100+
101+
var (
102+
auUpdatePassword string
103+
auUpdateDescription string
104+
auUpdatePresenceGroup string
105+
)
106+
107+
var auUpdateCmd = &cobra.Command{
108+
Use: "update <userid>",
109+
Short: "Update an application user",
110+
Args: cobra.ExactArgs(1),
111+
RunE: runAUUpdate,
112+
}
113+
114+
func runAUUpdate(cmd *cobra.Command, args []string) error {
115+
clusterName, err := resolveCluster(cmd)
116+
if err != nil { return err }
117+
cfg, err := appconfig.LoadConfig()
118+
if err != nil { return fmt.Errorf("failed to load config: %w", err) }
119+
clusterCfg, err := appconfig.GetCluster(cfg, clusterName)
120+
if err != nil { return err }
121+
user, pass, err := auth.ResolveCreds(clusterCfg, auth.CredTypeAXL)
122+
if err != nil { return fmt.Errorf("failed to resolve credentials: %w", err) }
123+
params := make(map[string]string)
124+
if auUpdatePassword != "" { params["password"] = auUpdatePassword }
125+
if auUpdateDescription != "" { params["description"] = auUpdateDescription }
126+
if auUpdatePresenceGroup != "" { params["presenceGroupName"] = auUpdatePresenceGroup }
127+
if err := client.UpdateAppUser(clusterCfg.Host, user, pass, clusterCfg.Version, args[0], params); err != nil {
128+
if errors.Is(err, client.ErrDryRun) { return nil }
129+
return fmt.Errorf("failed to update app user: %w", err)
130+
}
131+
fmt.Printf("Application user '%s' updated successfully\n", args[0])
132+
return nil
133+
}
134+
135+
var auRemoveCmd = &cobra.Command{
136+
Use: "remove <userid>",
137+
Short: "Remove an application user",
138+
Args: cobra.ExactArgs(1),
139+
RunE: runAURemove,
140+
}
141+
142+
func runAURemove(cmd *cobra.Command, args []string) error {
143+
clusterName, err := resolveCluster(cmd)
144+
if err != nil { return err }
145+
cfg, err := appconfig.LoadConfig()
146+
if err != nil { return fmt.Errorf("failed to load config: %w", err) }
147+
clusterCfg, err := appconfig.GetCluster(cfg, clusterName)
148+
if err != nil { return err }
149+
user, pass, err := auth.ResolveCreds(clusterCfg, auth.CredTypeAXL)
150+
if err != nil { return fmt.Errorf("failed to resolve credentials: %w", err) }
151+
if err := client.RemoveAppUser(clusterCfg.Host, user, pass, clusterCfg.Version, args[0]); err != nil {
152+
if errors.Is(err, client.ErrDryRun) { return nil }
153+
return fmt.Errorf("failed to remove app user: %w", err)
154+
}
155+
fmt.Printf("Application user '%s' removed successfully\n", args[0])
156+
return nil
157+
}
158+
159+
func init() {
160+
appUsersCmd.AddCommand(auListCmd, auGetCmd, auAddCmd, auUpdateCmd, auRemoveCmd)
161+
auListCmd.Flags().StringVar(&auListUserid, "userid", "%", "Userid filter")
162+
auAddCmd.Flags().StringVar(&auAddUserid, "userid", "", "Userid (required)")
163+
auAddCmd.Flags().StringVar(&auAddPassword, "password", "", "Password")
164+
auAddCmd.Flags().StringVar(&auAddDescription, "description", "", "Description")
165+
auAddCmd.Flags().StringVar(&auAddPresenceGroup, "presence-group", "Standard Presence group", "Presence group name")
166+
auUpdateCmd.Flags().StringVar(&auUpdatePassword, "password", "", "Password")
167+
auUpdateCmd.Flags().StringVar(&auUpdateDescription, "description", "", "Description")
168+
auUpdateCmd.Flags().StringVar(&auUpdatePresenceGroup, "presence-group", "", "Presence group name")
169+
}

0 commit comments

Comments
 (0)