risto-roadmap #2
311
cmd_group.go
Normal file
311
cmd_group.go
Normal file
@@ -0,0 +1,311 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// handleGroup dispatches group management sub-commands
|
||||||
|
func (c *KVSClient) handleGroup(args []string) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
fmt.Println(red("Usage: group <create|get|update|delete|add-member|remove-member> [options]"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
subCmd := args[0]
|
||||||
|
switch subCmd {
|
||||||
|
case "create":
|
||||||
|
c.handleGroupCreate(args[1:])
|
||||||
|
case "get":
|
||||||
|
c.handleGroupGet(args[1:])
|
||||||
|
case "update":
|
||||||
|
c.handleGroupUpdate(args[1:])
|
||||||
|
case "delete":
|
||||||
|
c.handleGroupDelete(args[1:])
|
||||||
|
case "add-member":
|
||||||
|
c.handleGroupAddMember(args[1:])
|
||||||
|
case "remove-member":
|
||||||
|
c.handleGroupRemoveMember(args[1:])
|
||||||
|
default:
|
||||||
|
fmt.Println(red("Unknown group command:"), subCmd)
|
||||||
|
fmt.Println("Available commands: create, get, update, delete, add-member, remove-member")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleGroupCreate creates a new group
|
||||||
|
func (c *KVSClient) handleGroupCreate(args []string) {
|
||||||
|
if len(args) < 1 {
|
||||||
|
fmt.Println(red("Usage: group create <groupname> [member-uuid1,member-uuid2,...]"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
groupname := args[0]
|
||||||
|
var members []string
|
||||||
|
|
||||||
|
// Parse optional members list
|
||||||
|
if len(args) >= 2 {
|
||||||
|
members = strings.Split(args[1], ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
payload := map[string]interface{}{
|
||||||
|
"groupname": groupname,
|
||||||
|
}
|
||||||
|
if len(members) > 0 {
|
||||||
|
payload["members"] = members
|
||||||
|
}
|
||||||
|
|
||||||
|
respBody, status, err := c.doRequest("POST", "/api/groups", payload)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(red("Error:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != http.StatusOK {
|
||||||
|
fmt.Printf(red("Error creating group (status %d):\n"), status)
|
||||||
|
fmt.Println(string(respBody))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response struct {
|
||||||
|
UUID string `json:"uuid"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(respBody, &response); err != nil {
|
||||||
|
fmt.Println(red("Error parsing response:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(green("Group created successfully"))
|
||||||
|
fmt.Println(cyan("UUID:"), response.UUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleGroupGet retrieves group details
|
||||||
|
func (c *KVSClient) handleGroupGet(args []string) {
|
||||||
|
if len(args) < 1 {
|
||||||
|
fmt.Println(red("Usage: group get <group-uuid>"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
groupUUID := args[0]
|
||||||
|
|
||||||
|
respBody, status, err := c.doRequest("GET", "/api/groups/"+groupUUID, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(red("Error:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == http.StatusNotFound {
|
||||||
|
fmt.Println(yellow("Group not found"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != http.StatusOK {
|
||||||
|
fmt.Printf(red("Error getting group (status %d):\n"), status)
|
||||||
|
fmt.Println(string(respBody))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var group Group
|
||||||
|
if err := json.Unmarshal(respBody, &group); err != nil {
|
||||||
|
fmt.Println(red("Error parsing response:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(cyan("Group Details:"))
|
||||||
|
fmt.Printf(" UUID: %s\n", group.UUID)
|
||||||
|
fmt.Printf(" Name Hash: %s\n", group.NameHash)
|
||||||
|
fmt.Printf(" Members: %v\n", group.Members)
|
||||||
|
fmt.Printf(" Created: %s\n", time.Unix(group.CreatedAt, 0).Format(time.RFC3339))
|
||||||
|
fmt.Printf(" Updated: %s\n", time.Unix(group.UpdatedAt, 0).Format(time.RFC3339))
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleGroupUpdate replaces all members in a group
|
||||||
|
func (c *KVSClient) handleGroupUpdate(args []string) {
|
||||||
|
if len(args) < 2 {
|
||||||
|
fmt.Println(red("Usage: group update <group-uuid> <member-uuid1,member-uuid2,...>"))
|
||||||
|
fmt.Println("Note: This replaces ALL members. Use add-member/remove-member for incremental changes.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
groupUUID := args[0]
|
||||||
|
members := strings.Split(args[1], ",")
|
||||||
|
|
||||||
|
payload := map[string]interface{}{
|
||||||
|
"members": members,
|
||||||
|
}
|
||||||
|
|
||||||
|
respBody, status, err := c.doRequest("PUT", "/api/groups/"+groupUUID, payload)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(red("Error:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == http.StatusNotFound {
|
||||||
|
fmt.Println(yellow("Group not found"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != http.StatusOK {
|
||||||
|
fmt.Printf(red("Error updating group (status %d):\n"), status)
|
||||||
|
fmt.Println(string(respBody))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(green("Group updated successfully"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleGroupDelete deletes a group
|
||||||
|
func (c *KVSClient) handleGroupDelete(args []string) {
|
||||||
|
if len(args) < 1 {
|
||||||
|
fmt.Println(red("Usage: group delete <group-uuid>"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
groupUUID := args[0]
|
||||||
|
|
||||||
|
respBody, status, err := c.doRequest("DELETE", "/api/groups/"+groupUUID, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(red("Error:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == http.StatusNotFound {
|
||||||
|
fmt.Println(yellow("Group not found"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != http.StatusOK {
|
||||||
|
fmt.Printf(red("Error deleting group (status %d):\n"), status)
|
||||||
|
fmt.Println(string(respBody))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(green("Group deleted successfully"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleGroupAddMember adds a member to an existing group
|
||||||
|
func (c *KVSClient) handleGroupAddMember(args []string) {
|
||||||
|
if len(args) < 2 {
|
||||||
|
fmt.Println(red("Usage: group add-member <group-uuid> <user-uuid>"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
groupUUID := args[0]
|
||||||
|
userUUID := args[1]
|
||||||
|
|
||||||
|
// First, get current members
|
||||||
|
respBody, status, err := c.doRequest("GET", "/api/groups/"+groupUUID, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(red("Error:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != http.StatusOK {
|
||||||
|
fmt.Printf(red("Error getting group (status %d):\n"), status)
|
||||||
|
fmt.Println(string(respBody))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var group Group
|
||||||
|
if err := json.Unmarshal(respBody, &group); err != nil {
|
||||||
|
fmt.Println(red("Error parsing response:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user is already a member
|
||||||
|
for _, member := range group.Members {
|
||||||
|
if member == userUUID {
|
||||||
|
fmt.Println(yellow("User is already a member of this group"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new member
|
||||||
|
group.Members = append(group.Members, userUUID)
|
||||||
|
|
||||||
|
// Update group with new members list
|
||||||
|
payload := map[string]interface{}{
|
||||||
|
"members": group.Members,
|
||||||
|
}
|
||||||
|
|
||||||
|
respBody, status, err = c.doRequest("PUT", "/api/groups/"+groupUUID, payload)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(red("Error:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != http.StatusOK {
|
||||||
|
fmt.Printf(red("Error updating group (status %d):\n"), status)
|
||||||
|
fmt.Println(string(respBody))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(green("Member added successfully"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleGroupRemoveMember removes a member from an existing group
|
||||||
|
func (c *KVSClient) handleGroupRemoveMember(args []string) {
|
||||||
|
if len(args) < 2 {
|
||||||
|
fmt.Println(red("Usage: group remove-member <group-uuid> <user-uuid>"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
groupUUID := args[0]
|
||||||
|
userUUID := args[1]
|
||||||
|
|
||||||
|
// First, get current members
|
||||||
|
respBody, status, err := c.doRequest("GET", "/api/groups/"+groupUUID, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(red("Error:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != http.StatusOK {
|
||||||
|
fmt.Printf(red("Error getting group (status %d):\n"), status)
|
||||||
|
fmt.Println(string(respBody))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var group Group
|
||||||
|
if err := json.Unmarshal(respBody, &group); err != nil {
|
||||||
|
fmt.Println(red("Error parsing response:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove member from list
|
||||||
|
newMembers := []string{}
|
||||||
|
found := false
|
||||||
|
for _, member := range group.Members {
|
||||||
|
if member != userUUID {
|
||||||
|
newMembers = append(newMembers, member)
|
||||||
|
} else {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
fmt.Println(yellow("User is not a member of this group"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update group with new members list
|
||||||
|
payload := map[string]interface{}{
|
||||||
|
"members": newMembers,
|
||||||
|
}
|
||||||
|
|
||||||
|
respBody, status, err = c.doRequest("PUT", "/api/groups/"+groupUUID, payload)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(red("Error:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != http.StatusOK {
|
||||||
|
fmt.Printf(red("Error updating group (status %d):\n"), status)
|
||||||
|
fmt.Println(string(respBody))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(green("Member removed successfully"))
|
||||||
|
}
|
@@ -52,6 +52,14 @@ User Management:
|
|||||||
user get <uuid> - Get user details
|
user get <uuid> - Get user details
|
||||||
user create <nickname> - Create new user (admin only)
|
user create <nickname> - Create new user (admin only)
|
||||||
|
|
||||||
|
Group Management:
|
||||||
|
group create <name> [members] - Create new group
|
||||||
|
group get <uuid> - Get group details
|
||||||
|
group update <uuid> <members> - Replace all group members
|
||||||
|
group delete <uuid> - Delete group
|
||||||
|
group add-member <uuid> <user-uuid> - Add member to group
|
||||||
|
group remove-member <uuid> <user-uuid> - Remove member from group
|
||||||
|
|
||||||
System:
|
System:
|
||||||
help - Show this help
|
help - Show this help
|
||||||
exit, quit - Exit shell
|
exit, quit - Exit shell
|
||||||
|
2
main.go
2
main.go
@@ -95,6 +95,8 @@ func main() {
|
|||||||
} else {
|
} else {
|
||||||
client.handleUserList(args)
|
client.handleUserList(args)
|
||||||
}
|
}
|
||||||
|
case "group":
|
||||||
|
client.handleGroup(args)
|
||||||
default:
|
default:
|
||||||
fmt.Println(red("Unknown command:"), cmd)
|
fmt.Println(red("Unknown command:"), cmd)
|
||||||
fmt.Println("Type 'help' for available commands")
|
fmt.Println("Type 'help' for available commands")
|
||||||
|
8
utils.go
8
utils.go
@@ -119,6 +119,14 @@ var completer = readline.NewPrefixCompleter(
|
|||||||
readline.PcItem("get"),
|
readline.PcItem("get"),
|
||||||
readline.PcItem("create"),
|
readline.PcItem("create"),
|
||||||
),
|
),
|
||||||
|
readline.PcItem("group",
|
||||||
|
readline.PcItem("create"),
|
||||||
|
readline.PcItem("get"),
|
||||||
|
readline.PcItem("update"),
|
||||||
|
readline.PcItem("delete"),
|
||||||
|
readline.PcItem("add-member"),
|
||||||
|
readline.PcItem("remove-member"),
|
||||||
|
),
|
||||||
readline.PcItem("help"),
|
readline.PcItem("help"),
|
||||||
readline.PcItem("exit"),
|
readline.PcItem("exit"),
|
||||||
readline.PcItem("quit"),
|
readline.PcItem("quit"),
|
||||||
|
Reference in New Issue
Block a user