Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions cmd/auth_assign_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,21 @@ var authAssignRoleCmd = &cobra.Command{
if accountID != "" {
// Account-scoped role assignment
req := client.NewRequest(`
mutation AssignAccountGroupRole($request: UserRolesUpsertAccountGroupInput!) {
userroles_upsert_account_group(request: $request) {
mutation AssignAccountGroupRole($role: auth_account_group_roles_upsert_one_input!) {
userroles_upsert_account_group(role: $role) {
status
message
}
}
`)
req.Var("request", map[string]any{
"group_id": groupID,
"role": role,
"account_id": accountID,
req.Var("role", map[string]any{
"group_id": groupID,
"account_roles": []map[string]string{
{
"account_id": accountID,
"role": role,
},
},
})

var respData struct {
Expand All @@ -59,14 +63,14 @@ var authAssignRoleCmd = &cobra.Command{
} else {
// Tenant-level role assignment
req := client.NewRequest(`
mutation AssignGroupRole($request: UserRolesUpsertGroupInput!) {
userroles_upsert_group(request: $request) {
mutation AssignGroupRole($role: auth_tenant_group_roles_upsert_one_input!) {
userroles_upsert_group(role: $role) {
status
message
}
}
`)
req.Var("request", map[string]any{
req.Var("role", map[string]any{
"group_id": groupID,
"role": role,
})
Expand Down
102 changes: 79 additions & 23 deletions cmd/auth_groups.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package cmd

import (
"bytes"
"encoding/json"
"strings"

"github.com/nudgebee/nbctl/pkg/client"
Expand All @@ -13,6 +15,47 @@ var authGroupsCmd = &cobra.Command{
Short: "Manage tenant user groups",
}

type groupRoleItem struct {
Role string `json:"role"`
EntityType string `json:"entity_type"`
EntityID string `json:"entity_id"`
}

type groupRolesField []groupRoleItem

func (g *groupRolesField) UnmarshalJSON(data []byte) error {
trimmed := bytes.TrimSpace(data)
if len(trimmed) == 0 || string(trimmed) == "null" || string(trimmed) == `""` {
*g = nil
return nil
}
Comment thread
blue4209211 marked this conversation as resolved.
Comment thread
blue4209211 marked this conversation as resolved.

var items []groupRoleItem
err := json.Unmarshal(trimmed, &items)
if err == nil {
*g = items
return nil
}

var str string
if errStr := json.Unmarshal(trimmed, &str); errStr != nil {
return err
Comment thread
blue4209211 marked this conversation as resolved.
}
Comment on lines +33 to +43

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If json.Unmarshal(data, &str) fails, calling json.Unmarshal(data, &items) again is redundant because we already know it failed from the first attempt. Instead, we can capture the original error from the first unmarshal attempt and return it directly.

Suggested change
var items []groupRoleItem
if err := json.Unmarshal(data, &items); err == nil {
*g = items
return nil
}
var str string
if errStr := json.Unmarshal(data, &str); errStr != nil {
return json.Unmarshal(data, &items)
}
var items []groupRoleItem
err := json.Unmarshal(data, &items)
if err == nil {
*g = items
return nil
}
var str string
if errStr := json.Unmarshal(data, &str); errStr != nil {
return err
}


str = strings.TrimSpace(str)
if str == "" || str == "null" {
*g = nil
return nil
}

if errArr := json.Unmarshal([]byte(str), &items); errArr != nil {
return errArr
}

*g = items
return nil
}
Comment thread
blue4209211 marked this conversation as resolved.
Comment thread
blue4209211 marked this conversation as resolved.

var authGroupsListCmd = &cobra.Command{
Use: "list",
Short: "List user groups with assigned roles and member count",
Expand All @@ -26,8 +69,8 @@ var authGroupsListCmd = &cobra.Command{
id
name
description
roles
user_count
group_roles
member_count
created_at
}
}
Expand All @@ -37,12 +80,12 @@ var authGroupsListCmd = &cobra.Command{
var respData struct {
UsergroupsList struct {
Rows []struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Roles []string `json:"roles"`
UserCount int `json:"user_count"`
CreatedAt string `json:"created_at"`
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
GroupRoles groupRolesField `json:"group_roles"`
MemberCount int `json:"member_count"`
CreatedAt string `json:"created_at"`
} `json:"rows"`
} `json:"usergroups_list"`
}
Expand All @@ -61,16 +104,23 @@ var authGroupsListCmd = &cobra.Command{
}
var rows []groupRow
for _, r := range respData.UsergroupsList.Rows {
var roles []string
for _, item := range r.GroupRoles {
if item.Role != "" {
roles = append(roles, item.Role)
}
}
Comment thread
blue4209211 marked this conversation as resolved.

rolesStr := "-"
if len(r.Roles) > 0 {
rolesStr = strings.Join(r.Roles, ", ")
if len(roles) > 0 {
rolesStr = strings.Join(roles, ", ")
}
rows = append(rows, groupRow{
ID: r.ID,
Name: r.Name,
Description: r.Description,
Roles: rolesStr,
UserCount: r.UserCount,
UserCount: r.MemberCount,
CreatedAt: r.CreatedAt,
})
}
Expand Down Expand Up @@ -103,32 +153,38 @@ var authGroupsCreateCmd = &cobra.Command{
graphqlClient := client.NewClient()

req := client.NewRequest(`
mutation CreateUserGroup($request: UserGroupCreateInput!) {
usergroup_create(request: $request) {
mutation CreateUserGroup($name: String!, $description: String) {
usergroup_create(name: $name, description: $description) {
id
name
status
}
}
`)
req.Var("request", map[string]any{
"name": groupName,
"description": desc,
})
req.Var("name", groupName)
if desc != "" {
req.Var("description", desc)
} else {
Comment thread
blue4209211 marked this conversation as resolved.
req.Var("description", nil)
}
Comment thread
blue4209211 marked this conversation as resolved.
Comment thread
blue4209211 marked this conversation as resolved.

var respData struct {
UsergroupCreate struct {
ID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
ID string `json:"id"`
} `json:"usergroup_create"`
}

if err := graphqlClient.Run(cmd.Context(), req, &respData); err != nil {
return err
}

format.GetFormat().Print(respData.UsergroupCreate)
format.GetFormat().Print(struct {
ID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
}{
ID: respData.UsergroupCreate.ID,
Name: groupName,
Status: "created",
})
return nil
},
}
Expand Down
82 changes: 60 additions & 22 deletions cmd/auth_roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"strings"

"github.com/nudgebee/nbctl/pkg/client"
"github.com/nudgebee/nbctl/pkg/format"
Expand All @@ -26,9 +27,11 @@ var authRolesListCmd = &cobra.Command{
value
}
customroles_list {
id
name
description
roles {
id
name
description
}
}
}
`)
Expand All @@ -38,10 +41,12 @@ var authRolesListCmd = &cobra.Command{
DisplayName string `json:"display_name"`
Value string `json:"value"`
} `json:"roles_list"`
CustomrolesList []struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
CustomrolesList struct {
Roles []struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
} `json:"roles"`
} `json:"customroles_list"`
}

Expand Down Expand Up @@ -76,7 +81,7 @@ var authRolesListCmd = &cobra.Command{
Description: "-",
})
}
for _, cr := range respData.CustomrolesList {
for _, cr := range respData.CustomrolesList.Roles {
rows = append(rows, roleRow{
Type: "Custom",
Name: cr.Name,
Expand Down Expand Up @@ -111,36 +116,69 @@ var authRolesCreateCmd = &cobra.Command{

graphqlClient := client.NewClient()

type customRolePermissionInput struct {
Module string `json:"module"`
Class string `json:"class,omitempty"`
}
Comment thread
blue4209211 marked this conversation as resolved.

var permInputs []customRolePermissionInput
for _, p := range permissions {
p = strings.TrimSpace(p)
if p == "" {
continue
}
parts := strings.SplitN(p, ":", 2)
if len(parts) == 2 {
module := strings.TrimSpace(parts[0])
class := strings.TrimSpace(parts[1])
if module == "" {
continue
}
permInputs = append(permInputs, customRolePermissionInput{
Module: module,
Class: class,
})
} else {
Comment thread
blue4209211 marked this conversation as resolved.
permInputs = append(permInputs, customRolePermissionInput{
Comment thread
blue4209211 marked this conversation as resolved.
Module: p,
})
}
Comment thread
blue4209211 marked this conversation as resolved.
}
Comment thread
blue4209211 marked this conversation as resolved.
Comment thread
blue4209211 marked this conversation as resolved.

req := client.NewRequest(`
mutation CreateCustomRole($request: CustomRoleCreateInput!) {
customroles_create(request: $request) {
mutation CreateCustomRole($name: String!, $description: String, $permissions: [CustomRolePermissionInput!]) {
customroles_create(name: $name, description: $description, permissions: $permissions) {
id
name
status
}
}
`)

input := map[string]any{
"name": roleName,
"description": desc,
"permissions": permissions,
req.Var("name", roleName)
if desc != "" {
req.Var("description", desc)
} else {
req.Var("description", nil)
}
Comment thread
blue4209211 marked this conversation as resolved.
req.Var("request", input)
req.Var("permissions", permInputs)

var respData struct {
CustomrolesCreate struct {
ID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
ID string `json:"id"`
} `json:"customroles_create"`
}

if err := graphqlClient.Run(cmd.Context(), req, &respData); err != nil {
return err
}

format.GetFormat().Print(respData.CustomrolesCreate)
format.GetFormat().Print(struct {
ID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
}{
ID: respData.CustomrolesCreate.ID,
Name: roleName,
Status: "created",
})
return nil
},
}
Expand Down
Loading