mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-24 13:48:49 +08:00
NOISSUE: Listing of shared things with users & Update SDK (#1923)
* NOISSUE - Fix Bugs (#20) * fix bugs Signed-off-by: Arvindh <arvindh91@gmail.com> * fix bugs Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * Add Connect Disconnect endpoints (#23) * fix bugs Signed-off-by: Arvindh <arvindh91@gmail.com> * fix bugs Signed-off-by: Arvindh <arvindh91@gmail.com> * fix list of things in a channel and Add connect disconnect endpoint Signed-off-by: Arvindh <arvindh91@gmail.com> * fix list of things in a channel and Add connect disconnect endpoint Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * Add: Things share with users (#25) * fix list of things in a channel and Add connect disconnect endpoint Signed-off-by: Arvindh <arvindh91@gmail.com> * add: things share with other users Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * Add: Listing of things, channels, groups, users (#26) * add: listing of channels, users, groups, things Signed-off-by: Arvindh <arvindh91@gmail.com> * add: listing of channels, users, groups, things Signed-off-by: Arvindh <arvindh91@gmail.com> * add: listing of channels, users, groups, things Signed-off-by: Arvindh <arvindh91@gmail.com> * add: listing of channels, users, groups, things Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * Add: List of user groups & removed repeating code in groups (#29) * removed repeating code in list groups Signed-off-by: Arvindh <arvindh91@gmail.com> * add: list of user group Signed-off-by: Arvindh <arvindh91@gmail.com> * fix: otel handler operator name for endpoints Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * add: listing of shared things and users Signed-off-by: Arvindh <arvindh91@gmail.com> * fix: listing of shared things and users Signed-off-by: Arvindh <arvindh91@gmail.com> * add: new SDK Signed-off-by: Arvindh <arvindh91@gmail.com> * add: new SDK Signed-off-by: Arvindh <arvindh91@gmail.com> * fix: comment Signed-off-by: Arvindh <arvindh91@gmail.com> * fix: sdk function names Signed-off-by: Arvindh <arvindh91@gmail.com> * update: api spec Signed-off-by: Arvindh <arvindh91@gmail.com> * fix: channels connect request Signed-off-by: Arvindh <arvindh91@gmail.com> * fix: listing of clients and groups Signed-off-by: Arvindh <arvindh91@gmail.com> * fix: CLI Signed-off-by: Arvindh <arvindh91@gmail.com> * fix: array len comparision Signed-off-by: Arvindh <arvindh91@gmail.com> * fix: nginx Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Co-authored-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
This commit is contained in:
parent
b4e7e859fb
commit
cd82cc5a43
@ -540,60 +540,6 @@ paths:
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/channels/{chanID}/assign:
|
||||
post:
|
||||
summary: Assigns a member to a channel
|
||||
description: |
|
||||
Assigns a specific member to a channel that is identifier by the channel ID.
|
||||
tags:
|
||||
- Channels
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/chanID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/AssignReq"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
description: Thing shared.
|
||||
"400":
|
||||
description: Failed due to malformed thing's ID.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/channels/{chanID}/unassign:
|
||||
post:
|
||||
summary: Unassigns a member from a channel
|
||||
description: |
|
||||
Unassigns a specific member from a channel that is identifier by the channel ID.
|
||||
tags:
|
||||
- Channels
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/chanID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/AssignReq"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
description: Thing unshared.
|
||||
"400":
|
||||
description: Failed due to malformed thing's ID.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/channels/{chanID}/users/assign:
|
||||
post:
|
||||
summary: Assigns a member to a channel
|
||||
|
@ -690,60 +690,6 @@ paths:
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/groups/{groupID}/members/assign:
|
||||
post:
|
||||
summary: Assigns a member to a group
|
||||
description: |
|
||||
Assigns a specific member to a group that is identifier by the group ID.
|
||||
tags:
|
||||
- Groups
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GroupID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/AssignReq"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
description: Member assigned.
|
||||
"400":
|
||||
description: Failed due to malformed group's ID.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/groups/{groupID}/members/unassign:
|
||||
post:
|
||||
summary: Unassigns a member to a group
|
||||
description: |
|
||||
Unassigns a specific member to a group that is identifier by the group ID.
|
||||
tags:
|
||||
- Groups
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/GroupID"
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/AssignReq"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
description: Member assigned.
|
||||
"400":
|
||||
description: Failed due to malformed group's ID.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/groups/{groupID}/users/assign:
|
||||
post:
|
||||
summary: Assigns a user to a group
|
||||
|
142
cli/channels.go
142
cli/channels.go
@ -166,12 +166,152 @@ var cmdChannels = []cobra.Command{
|
||||
logJSON(channel)
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "assign user <relation> <user_ids> <channel_id> <user_auth_token>",
|
||||
Short: "Assign user",
|
||||
Long: "Assign user to a channel\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli channels assign user <relation> '[\"<user_id_1>\", \"<user_id_2>\"]' <channel_id> $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 5 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
var userIDs []string
|
||||
if err := json.Unmarshal([]byte(args[1]), &userIDs); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
if err := sdk.AddUserToChannel(args[2], mfxsdk.UsersRelationRequest{Relation: args[0], UserIDs: userIDs}, args[3]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "unassign user <relation> <user_ids> <channel_id> <user_auth_token>",
|
||||
Short: "Unassign user",
|
||||
Long: "Unassign user from a channel\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli channels unassign user <relation> '[\"<user_id_1>\", \"<user_id_2>\"]' <channel_id> $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 5 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
var userIDs []string
|
||||
if err := json.Unmarshal([]byte(args[1]), &userIDs); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
if err := sdk.RemoveUserFromChannel(args[2], mfxsdk.UsersRelationRequest{Relation: args[0], UserIDs: userIDs}, args[3]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "assign group <group_ids> <channel_id> <user_auth_token>",
|
||||
Short: "Assign group",
|
||||
Long: "Assign group to a channel\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli channels assign group '[\"<group_id_1>\", \"<group_id_2>\"]' <channel_id> $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 5 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
var groupIDs []string
|
||||
if err := json.Unmarshal([]byte(args[0]), &groupIDs); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
if err := sdk.AddUserGroupToChannel(args[1], mfxsdk.UserGroupsRequest{UserGroupIDs: groupIDs}, args[2]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "unassign group <group_ids> <channel_id> <user_auth_token>",
|
||||
Short: "Unassign group",
|
||||
Long: "Unassign group from a channel\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli channels unassign group '[\"<group_id_1>\", \"<group_id_2>\"]' <channel_id> $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 5 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
var groupIDs []string
|
||||
if err := json.Unmarshal([]byte(args[0]), &groupIDs); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
if err := sdk.RemoveUserGroupFromChannel(args[1], mfxsdk.UserGroupsRequest{UserGroupIDs: groupIDs}, args[2]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "users <channel_id> <user_auth_token>",
|
||||
Short: "List users",
|
||||
Long: "List users of a channel\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli channels users <channel_id> $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
pm := mfxsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
ul, err := sdk.ListChannelUsers(args[0], pm, args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSON(ul)
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "groups <channel_id> <user_auth_token>",
|
||||
Short: "List groups",
|
||||
Long: "List groups of a channel\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli channels groups <channel_id> $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
pm := mfxsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
ul, err := sdk.ListChannelUserGroups(args[0], pm, args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSON(ul)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// NewChannelsCmd returns channels command.
|
||||
func NewChannelsCmd() *cobra.Command {
|
||||
cmd := cobra.Command{
|
||||
Use: "channels [create | get | update | delete | connections | not-connected]",
|
||||
Use: "channels [create | get | update | delete | connections | not-connected | assign | unassign | users | groups]",
|
||||
Short: "Channels management",
|
||||
Long: `Channels management: create, get, update or delete Channel and get list of Things connected or not connected to a Channel`,
|
||||
}
|
||||
|
@ -142,22 +142,22 @@ var cmdGroups = []cobra.Command{
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "assign <allowed_actions> <member_id> <group_id> <user_auth_token>",
|
||||
Short: "Assign member",
|
||||
Long: "Assign members to a group\n" +
|
||||
Use: "assign user <relation> <user_ids> <group_id> <user_auth_token>",
|
||||
Short: "Assign user",
|
||||
Long: "Assign user to a group\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli groups assign '[\"<allowed_action>\", \"<allowed_action>\"]' <member_id> <group_id> $USERTOKEN\n",
|
||||
"\tmainflux-cli groups assign user <relation> '[\"<user_id_1>\", \"<user_id_2>\"]' <group_id> $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 4 {
|
||||
if len(args) != 5 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
var actions []string
|
||||
if err := json.Unmarshal([]byte(args[0]), &actions); err != nil {
|
||||
var userIDs []string
|
||||
if err := json.Unmarshal([]byte(args[1]), &userIDs); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
if err := sdk.Assign(actions, args[1], args[2], args[3]); err != nil {
|
||||
if err := sdk.AddUserToGroup(args[2], mfxsdk.UsersRelationRequest{Relation: args[0], UserIDs: userIDs}, args[3]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
@ -165,29 +165,35 @@ var cmdGroups = []cobra.Command{
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "unassign <member_id> <group_id> <user_auth_token>",
|
||||
Short: "Unassign member",
|
||||
Long: "Unassign member from a group\n" +
|
||||
Use: "unassign user <relation> <user_ids> <group_id> <user_auth_token>",
|
||||
Short: "Unassign user",
|
||||
Long: "Unassign user from a group\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli groups unassign <member_id> <group_id> $USERTOKEN\n",
|
||||
"\tmainflux-cli groups unassign user <relation> '[\"<user_id_1>\", \"<user_id_2>\"]' <group_id> $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 3 {
|
||||
if len(args) != 5 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
if err := sdk.Unassign(args[0], args[1], args[2]); err != nil {
|
||||
var userIDs []string
|
||||
if err := json.Unmarshal([]byte(args[1]), &userIDs); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
if err := sdk.RemoveUserFromGroup(args[2], mfxsdk.UsersRelationRequest{Relation: args[0], UserIDs: userIDs}, args[3]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Use: "members <group_id> <user_auth_token>",
|
||||
Short: "Members list",
|
||||
Long: "List group's members\n" +
|
||||
Use: "users <group_id> <user_auth_token>",
|
||||
Short: "List users",
|
||||
Long: "List users in a group\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli groups members <group_id> $USERTOKEN",
|
||||
"\tmainflux-cli groups users <group_id> $USERTOKEN",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Use)
|
||||
@ -198,20 +204,20 @@ var cmdGroups = []cobra.Command{
|
||||
Limit: Limit,
|
||||
Status: Status,
|
||||
}
|
||||
up, err := sdk.Members(args[0], pm, args[1])
|
||||
users, err := sdk.ListGroupUsers(args[0], pm, args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
logJSON(up)
|
||||
logJSON(users)
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "membership <member_id> <user_auth_token>",
|
||||
Short: "Membership list",
|
||||
Long: "List memberships of a member\n" +
|
||||
Use: "channels <group_id> <user_auth_token>",
|
||||
Short: "List channels",
|
||||
Long: "List channels in a group\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli groups membership <member_id> $USERTOKEN",
|
||||
"\tmainflux-cli groups channels <group_id> $USERTOKEN",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Use)
|
||||
@ -220,13 +226,14 @@ var cmdGroups = []cobra.Command{
|
||||
pm := mfxsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
Status: Status,
|
||||
}
|
||||
up, err := sdk.Memberships(args[0], pm, args[1])
|
||||
channels, err := sdk.ListGroupChannels(args[0], pm, args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
logJSON(up)
|
||||
logJSON(channels)
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -276,7 +283,7 @@ var cmdGroups = []cobra.Command{
|
||||
// NewGroupsCmd returns users command.
|
||||
func NewGroupsCmd() *cobra.Command {
|
||||
cmd := cobra.Command{
|
||||
Use: "groups [create | get | update | delete | assign | unassign | members | membership]",
|
||||
Use: "groups [create | get | update | delete | assign | unassign | users | channels ]",
|
||||
Short: "Groups management",
|
||||
Long: `Groups management: create, update, delete group and assign and unassign member to groups"`,
|
||||
}
|
||||
|
228
cli/policies.go
228
cli/policies.go
@ -1,228 +0,0 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
mfxsdk "github.com/mainflux/mainflux/pkg/sdk/go"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
users = "users"
|
||||
things = "things"
|
||||
)
|
||||
|
||||
var cmdPolicies = []cobra.Command{
|
||||
{
|
||||
Use: "create [ users | things ] <subject_id> <object_id> <actions> <user_auth_token>",
|
||||
Short: "Create policy",
|
||||
Long: "Create a new policy\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli policies create users <user_id> <group_id> '[\"c_list\"]' $USERTOKEN\n" +
|
||||
"\tmainflux-cli policies create things <thing_id> <channel_id> '[\"m_write\"]' $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 5 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
|
||||
var actions []string
|
||||
if err := json.Unmarshal([]byte(args[3]), &actions); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
policy := mfxsdk.Policy{
|
||||
Subject: args[1],
|
||||
Object: args[2],
|
||||
Actions: actions,
|
||||
}
|
||||
|
||||
switch args[0] {
|
||||
case things:
|
||||
if err := sdk.CreateThingPolicy(policy, args[4]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
case users:
|
||||
if err := sdk.CreateUserPolicy(policy, args[4]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
default:
|
||||
logUsage(cmd.Use)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "update [ users | things ] <subject_id> <object_id> <actions> <user_auth_token>",
|
||||
Short: "Update policy",
|
||||
Long: "Update policy\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli policies update users <user_id> <group_id> '[\"c_list\"]' $USERTOKEN\n" +
|
||||
"\tmainflux-cli policies update things <thing_id> <channel_id> '[\"m_write\"]' $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 5 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
|
||||
var actions []string
|
||||
if err := json.Unmarshal([]byte(args[3]), &actions); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
policy := mfxsdk.Policy{
|
||||
Subject: args[1],
|
||||
Object: args[2],
|
||||
Actions: actions,
|
||||
}
|
||||
|
||||
switch args[0] {
|
||||
case things:
|
||||
if err := sdk.UpdateThingPolicy(policy, args[4]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
case users:
|
||||
if err := sdk.UpdateUserPolicy(policy, args[4]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
default:
|
||||
logUsage(cmd.Use)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "list [ users | things ] <user_auth_token>",
|
||||
Short: "List policies",
|
||||
Long: "List policies\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli policies list users $USERTOKEN\n" +
|
||||
"\tmainflux-cli policies list things $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
pm := mfxsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
switch args[0] {
|
||||
case things:
|
||||
policies, err := sdk.ListThingPolicies(pm, args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
logJSON(policies)
|
||||
return
|
||||
case users:
|
||||
policies, err := sdk.ListUserPolicies(pm, args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSON(policies)
|
||||
return
|
||||
default:
|
||||
logUsage(cmd.Use)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "remove [ users | things ] <subject_id> <object_id> <user_auth_token>",
|
||||
Short: "Remove policy",
|
||||
Long: "Removes a policy with the provided object and subject\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli policies remove users <user_id> <group_id> $USERTOKEN\n" +
|
||||
"\tmainflux-cli policies remove things <thing_id> <channel_id> $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
|
||||
policy := mfxsdk.Policy{
|
||||
Subject: args[1],
|
||||
Object: args[2],
|
||||
}
|
||||
switch args[0] {
|
||||
case things:
|
||||
if err := sdk.DeleteThingPolicy(policy, args[3]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
case users:
|
||||
if err := sdk.DeleteUserPolicy(policy, args[3]); err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
default:
|
||||
logUsage(cmd.Use)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "authorize [ users | things ] <subject_id> <object_id> <action> <entity_type> <user_auth_token>",
|
||||
Short: "Authorize access request",
|
||||
Long: "Authorize subject over object with provided actions\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli policies authorize users <user_id> <group_id> \"c_list\" <entity_type> $USERTOKEN\n" +
|
||||
"\tmainflux-cli policies authorize things <thing_id> <channel_id> \"m_read\" <entity_type> $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 6 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
|
||||
areq := mfxsdk.AccessRequest{
|
||||
Subject: args[1],
|
||||
Object: args[2],
|
||||
Action: args[3],
|
||||
EntityType: args[4],
|
||||
}
|
||||
|
||||
switch args[0] {
|
||||
case users:
|
||||
ok, err := sdk.AuthorizeUser(areq, args[5])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
logJSON(ok)
|
||||
case things:
|
||||
ok, _, err := sdk.AuthorizeThing(areq, args[5])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
logJSON(ok)
|
||||
default:
|
||||
logUsage(cmd.Use)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// NewPolicyCmd returns policies command.
|
||||
func NewPolicyCmd() *cobra.Command {
|
||||
cmd := cobra.Command{
|
||||
Use: "policies [create | update | list | remove | authorize ]",
|
||||
Short: "Policies management",
|
||||
Long: `Policies management: create or update or list or delete or check policies`,
|
||||
}
|
||||
|
||||
for i := range cmdPolicies {
|
||||
cmd.AddCommand(&cmdPolicies[i])
|
||||
}
|
||||
|
||||
return &cmd
|
||||
}
|
@ -215,23 +215,45 @@ var cmdThings = []cobra.Command{
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "share <channel_id> <user_id> <allowed_actions> <user_auth_token>",
|
||||
Use: "share <thing_id> <user_id> <relation> <user_auth_token>",
|
||||
Short: "Share thing with a user",
|
||||
Long: "Share thing with a user\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli things share <channel_id> <user_id> '[\"c_list\", \"c_delete\"]' $USERTOKEN\n",
|
||||
"\tmainflux-cli things share <thing_id> <user_id> <relation> $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
var actions []string
|
||||
if err := json.Unmarshal([]byte(args[2]), &actions); err != nil {
|
||||
req := mfxsdk.UsersRelationRequest{
|
||||
Relation: args[2],
|
||||
UserIDs: []string{args[1]},
|
||||
}
|
||||
err := sdk.ShareThing(args[0], req, args[3])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
err := sdk.ShareThing(args[0], args[1], actions, args[3])
|
||||
logOK()
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "unshare <thing_id> <user_id> <relation> <user_auth_token>",
|
||||
Short: "Unshare thing with a user",
|
||||
Long: "Unshare thing with a user\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli things share <thing_id> <user_id> <relation> $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 4 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
req := mfxsdk.UsersRelationRequest{
|
||||
Relation: args[2],
|
||||
UserIDs: []string{args[1]},
|
||||
}
|
||||
err := sdk.UnshareThing(args[0], req, args[3])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
@ -312,12 +334,36 @@ var cmdThings = []cobra.Command{
|
||||
logJSON(cl)
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "users <thing_id> <user_auth_token>",
|
||||
Short: "List users",
|
||||
Long: "List users of a thing\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli things users <thing_id> $USERTOKEN\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
pm := mfxsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
ul, err := sdk.ListThingUsers(args[0], pm, args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSON(ul)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// NewThingsCmd returns things command.
|
||||
func NewThingsCmd() *cobra.Command {
|
||||
cmd := cobra.Command{
|
||||
Use: "things [create | get | update | delete | share | connect | disconnect | connections | not-connected]",
|
||||
Use: "things [create | get | update | delete | share | connect | disconnect | connections | not-connected | users ]",
|
||||
Short: "Things management",
|
||||
Long: `Things management: create, get, update, delete or share Thing, connect or disconnect Thing from Channel and get the list of Channels connected or disconnected from a Thing`,
|
||||
}
|
||||
|
82
cli/users.go
82
cli/users.go
@ -333,12 +333,92 @@ var cmdUsers = []cobra.Command{
|
||||
logJSON(user)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Use: "channels <user_id> <user_auth_token>",
|
||||
Short: "List channels",
|
||||
Long: "List channels of user\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli users channels <user_id> <user_auth_token>\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
|
||||
pm := mfxsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
|
||||
users, err := sdk.ListUserChannels(args[0], pm, args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSON(users)
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Use: "things <user_id> <user_auth_token>",
|
||||
Short: "List things",
|
||||
Long: "List things of user\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli users things <user_id> <user_auth_token>\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
|
||||
pm := mfxsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
|
||||
users, err := sdk.ListUserThings(args[0], pm, args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSON(users)
|
||||
},
|
||||
},
|
||||
{
|
||||
Use: "groups <user_id> <user_auth_token>",
|
||||
Short: "List groups",
|
||||
Long: "List groups of user\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli users groups <user_id> <user_auth_token>\n",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
logUsage(cmd.Use)
|
||||
return
|
||||
}
|
||||
|
||||
pm := mfxsdk.PageMetadata{
|
||||
Offset: Offset,
|
||||
Limit: Limit,
|
||||
}
|
||||
|
||||
users, err := sdk.ListUserGroups(args[0], pm, args[1])
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
logJSON(users)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// NewUsersCmd returns users command.
|
||||
func NewUsersCmd() *cobra.Command {
|
||||
cmd := cobra.Command{
|
||||
Use: "users [create | get | update | token | password | enable | disable]",
|
||||
Use: "users [create | get | update | token | password | enable | disable | channels | things | groups]",
|
||||
Short: "Users management",
|
||||
Long: `Users management: create accounts and tokens"`,
|
||||
}
|
||||
|
@ -61,7 +61,6 @@ func main() {
|
||||
bootstrapCmd := cli.NewBootstrapCmd()
|
||||
certsCmd := cli.NewCertsCmd()
|
||||
subscriptionsCmd := cli.NewSubscriptionCmd()
|
||||
policiesCmd := cli.NewPolicyCmd()
|
||||
configCmd := cli.NewConfigCmd()
|
||||
|
||||
// Root Commands
|
||||
@ -75,7 +74,6 @@ func main() {
|
||||
rootCmd.AddCommand(bootstrapCmd)
|
||||
rootCmd.AddCommand(certsCmd)
|
||||
rootCmd.AddCommand(subscriptionsCmd)
|
||||
rootCmd.AddCommand(policiesCmd)
|
||||
rootCmd.AddCommand(configCmd)
|
||||
|
||||
// Root Flags
|
||||
|
@ -50,10 +50,15 @@ http {
|
||||
|
||||
server_name localhost;
|
||||
|
||||
location ~ ^/(channels)/(.+)/(things)/(.+) {
|
||||
include snippets/proxy-headers.conf;
|
||||
add_header Access-Control-Expose-Headers Location;
|
||||
proxy_pass http://things:${MF_THINGS_HTTP_PORT};
|
||||
}
|
||||
# Proxy pass to users & groups id to things service for listing of channels
|
||||
# /users/{userID}/channels - Listing of channels belongs to userID
|
||||
# /groups/{userGroupID}/channels - Listing of channels belongs to userGroupID
|
||||
location ~ ^/(users|groups)/(.+)/channels {
|
||||
location ~ ^/(users|groups)/(.+)/(channels|things) {
|
||||
include snippets/proxy-headers.conf;
|
||||
add_header Access-Control-Expose-Headers Location;
|
||||
if ($request_method = GET) {
|
||||
@ -66,14 +71,14 @@ http {
|
||||
# Proxy pass to channel id to users service for listing of channels
|
||||
# /channels/{channelID}/users - Listing of Users belongs to channelID
|
||||
# /channels/{channelID}/groups - Listing of User Groups belongs to channelID
|
||||
location ~ ^/channels/(.+)/(users|groups) {
|
||||
include snippets/proxy-headers.conf;
|
||||
add_header Access-Control-Expose-Headers Location;
|
||||
if ($request_method = GET) {
|
||||
proxy_pass http://users:${MF_USERS_HTTP_PORT};
|
||||
break;
|
||||
}
|
||||
proxy_pass http://things:${MF_THINGS_HTTP_PORT};
|
||||
location ~ ^/(channels|things)/(.+)/(users|groups) {
|
||||
include snippets/proxy-headers.conf;
|
||||
add_header Access-Control-Expose-Headers Location;
|
||||
if ($request_method = GET) {
|
||||
proxy_pass http://users:${MF_USERS_HTTP_PORT};
|
||||
break;
|
||||
}
|
||||
proxy_pass http://things:${MF_THINGS_HTTP_PORT};
|
||||
}
|
||||
# Proxy pass to users service
|
||||
location ~ ^/(users|groups|password|authorize) {
|
||||
|
@ -216,8 +216,10 @@ func (svc service) ListGroups(ctx context.Context, token string, memberKind, mem
|
||||
return groups.Page{}, fmt.Errorf("invalid member kind")
|
||||
}
|
||||
|
||||
if len(ids) <= 0 {
|
||||
return groups.Page{}, errors.ErrNotFound
|
||||
if len(ids) == 0 {
|
||||
return groups.Page{
|
||||
PageMeta: gm.PageMeta,
|
||||
}, nil
|
||||
}
|
||||
return svc.groups.RetrieveByIDs(ctx, gm, ids...)
|
||||
}
|
||||
|
@ -146,6 +146,131 @@ func (sdk mfSDK) UpdateChannel(c Channel, token string) (Channel, errors.SDKErro
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) AddUserToChannel(channelID string, req UsersRelationRequest, token string) errors.SDKError {
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s/%s", sdk.thingsURL, channelsEndpoint, channelID, usersEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) RemoveUserFromChannel(channelID string, req UsersRelationRequest, token string) errors.SDKError {
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s/%s", sdk.thingsURL, channelsEndpoint, channelID, usersEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodDelete, url, token, data, nil, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ListChannelUsers(channelID string, pm PageMetadata, token string) (UsersPage, errors.SDKError) {
|
||||
url, err := sdk.withQueryParams(sdk.thingsURL, fmt.Sprintf("%s/%s/%s", channelsEndpoint, channelID, usersEndpoint), pm)
|
||||
if err != nil {
|
||||
return UsersPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return UsersPage{}, sdkerr
|
||||
}
|
||||
up := UsersPage{}
|
||||
if err := json.Unmarshal(body, &up); err != nil {
|
||||
return UsersPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return up, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) AddUserGroupToChannel(channelID string, req UserGroupsRequest, token string) errors.SDKError {
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s/%s", sdk.thingsURL, channelsEndpoint, channelID, groupsEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) RemoveUserGroupFromChannel(channelID string, req UserGroupsRequest, token string) errors.SDKError {
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s/%s", sdk.thingsURL, channelsEndpoint, channelID, groupsEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodDelete, url, token, data, nil, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ListChannelUserGroups(channelID string, pm PageMetadata, token string) (GroupsPage, errors.SDKError) {
|
||||
url, err := sdk.withQueryParams(sdk.thingsURL, fmt.Sprintf("%s/%s/%s", channelsEndpoint, channelID, groupsEndpoint), pm)
|
||||
if err != nil {
|
||||
return GroupsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return GroupsPage{}, sdkerr
|
||||
}
|
||||
gp := GroupsPage{}
|
||||
if err := json.Unmarshal(body, &gp); err != nil {
|
||||
return GroupsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return gp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Connect(conn Connection, token string) errors.SDKError {
|
||||
data, err := json.Marshal(conn)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.thingsURL, connectEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusOK)
|
||||
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Disconnect(connIDs Connection, token string) errors.SDKError {
|
||||
data, err := json.Marshal(connIDs)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.thingsURL, disconnectEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusNoContent)
|
||||
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ConnectThing(thingID, channelID, token string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s/%s/%s", sdk.thingsURL, channelsEndpoint, channelID, thingsEndpoint, thingID)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, nil, nil, http.StatusNoContent)
|
||||
|
||||
return sdkerr
|
||||
|
||||
}
|
||||
|
||||
func (sdk mfSDK) DisconnectThing(thingID, channelID, token string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s/%s/%s", sdk.thingsURL, channelsEndpoint, channelID, thingsEndpoint, thingID)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodDelete, url, token, nil, nil, http.StatusNoContent)
|
||||
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) EnableChannel(id, token string) (Channel, errors.SDKError) {
|
||||
return sdk.changeChannelStatus(id, enableEndpoint, token)
|
||||
}
|
||||
|
@ -57,25 +57,6 @@ func (sdk mfSDK) CreateGroup(g Group, token string) (Group, errors.SDKError) {
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Memberships(clientID string, pm PageMetadata, token string) (MembershipsPage, errors.SDKError) {
|
||||
url, err := sdk.withQueryParams(fmt.Sprintf("%s/%s/%s", sdk.usersURL, usersEndpoint, clientID), "memberships", pm)
|
||||
if err != nil {
|
||||
return MembershipsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return MembershipsPage{}, sdkerr
|
||||
}
|
||||
|
||||
var tp MembershipsPage
|
||||
if err := json.Unmarshal(body, &tp); err != nil {
|
||||
return MembershipsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return tp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Groups(pm PageMetadata, token string) (GroupsPage, errors.SDKError) {
|
||||
url, err := sdk.withQueryParams(sdk.usersURL, groupsEndpoint, pm)
|
||||
if err != nil {
|
||||
@ -164,6 +145,64 @@ func (sdk mfSDK) DisableGroup(id, token string) (Group, errors.SDKError) {
|
||||
return sdk.changeGroupStatus(id, disableEndpoint, token)
|
||||
}
|
||||
|
||||
func (sdk mfSDK) AddUserToGroup(groupID string, req UsersRelationRequest, token string) errors.SDKError {
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s/%s", sdk.usersURL, groupsEndpoint, groupID, usersEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) RemoveUserFromGroup(groupID string, req UsersRelationRequest, token string) errors.SDKError {
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s/%s", sdk.usersURL, groupsEndpoint, groupID, usersEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodDelete, url, token, data, nil, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ListGroupUsers(groupID string, pm PageMetadata, token string) (GroupsPage, errors.SDKError) {
|
||||
url, err := sdk.withQueryParams(sdk.usersURL, fmt.Sprintf("%s/%s/%s", groupsEndpoint, groupID, usersEndpoint), pm)
|
||||
if err != nil {
|
||||
return GroupsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return GroupsPage{}, sdkerr
|
||||
}
|
||||
gp := GroupsPage{}
|
||||
if err := json.Unmarshal(body, &gp); err != nil {
|
||||
return GroupsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return gp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ListGroupChannels(groupID string, pm PageMetadata, token string) (GroupsPage, errors.SDKError) {
|
||||
url, err := sdk.withQueryParams(sdk.usersURL, fmt.Sprintf("%s/%s/%s", groupsEndpoint, groupID, channelsEndpoint), pm)
|
||||
if err != nil {
|
||||
return GroupsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return GroupsPage{}, sdkerr
|
||||
}
|
||||
gp := GroupsPage{}
|
||||
if err := json.Unmarshal(body, &gp); err != nil {
|
||||
return GroupsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return gp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) changeGroupStatus(id, status, token string) (Group, errors.SDKError) {
|
||||
url := fmt.Sprintf("%s/%s/%s/%s", sdk.usersURL, groupsEndpoint, id, status)
|
||||
|
||||
|
@ -1,253 +0,0 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/mainflux/mainflux/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
policyEndpoint = "policies"
|
||||
authorizeEndpoint = "authorize"
|
||||
accessEndpoint = "access"
|
||||
)
|
||||
|
||||
// Policy represents an argument struct for making a policy related function calls.
|
||||
type Policy struct {
|
||||
OwnerID string `json:"owner_id"`
|
||||
Subject string `json:"subject"`
|
||||
Object string `json:"object"`
|
||||
Actions []string `json:"actions"`
|
||||
External bool `json:"external,omitempty"` // This is specificially used in things service. If set to true, it means the subject is userID otherwise it is thingID.
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type AccessRequest struct {
|
||||
Subject string `json:"subject,omitempty"`
|
||||
Object string `json:"object,omitempty"`
|
||||
Action string `json:"action,omitempty"`
|
||||
EntityType string `json:"entity_type,omitempty"`
|
||||
}
|
||||
|
||||
func (sdk mfSDK) AuthorizeUser(accessReq AccessRequest, token string) (bool, errors.SDKError) {
|
||||
data, err := json.Marshal(accessReq)
|
||||
if err != nil {
|
||||
return false, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.usersURL, authorizeEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return false, sdkerr
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) CreateUserPolicy(p Policy, token string) errors.SDKError {
|
||||
data, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.usersURL, policyEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusCreated)
|
||||
if sdkerr != nil {
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) UpdateUserPolicy(p Policy, token string) errors.SDKError {
|
||||
data, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.usersURL, policyEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPut, url, token, data, nil, http.StatusNoContent)
|
||||
if sdkerr != nil {
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ListUserPolicies(pm PageMetadata, token string) (PolicyPage, errors.SDKError) {
|
||||
url, err := sdk.withQueryParams(sdk.usersURL, policyEndpoint, pm)
|
||||
if err != nil {
|
||||
return PolicyPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return PolicyPage{}, sdkerr
|
||||
}
|
||||
|
||||
var pp PolicyPage
|
||||
if err := json.Unmarshal(body, &pp); err != nil {
|
||||
return PolicyPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return pp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) DeleteUserPolicy(p Policy, token string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s/%s", sdk.usersURL, policyEndpoint, p.Subject, p.Object)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodDelete, url, token, nil, nil, http.StatusNoContent)
|
||||
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) CreateThingPolicy(p Policy, token string) errors.SDKError {
|
||||
data, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.thingsURL, policyEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusCreated)
|
||||
if sdkerr != nil {
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) UpdateThingPolicy(p Policy, token string) errors.SDKError {
|
||||
data, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.thingsURL, policyEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPut, url, token, data, nil, http.StatusNoContent)
|
||||
if sdkerr != nil {
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ListThingPolicies(pm PageMetadata, token string) (PolicyPage, errors.SDKError) {
|
||||
url, err := sdk.withQueryParams(sdk.thingsURL, policyEndpoint, pm)
|
||||
if err != nil {
|
||||
return PolicyPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return PolicyPage{}, sdkerr
|
||||
}
|
||||
|
||||
var pp PolicyPage
|
||||
if err := json.Unmarshal(body, &pp); err != nil {
|
||||
return PolicyPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return pp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) DeleteThingPolicy(p Policy, token string) errors.SDKError {
|
||||
url := fmt.Sprintf("%s/%s/%s/%s", sdk.thingsURL, policyEndpoint, p.Subject, p.Object)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodDelete, url, token, nil, nil, http.StatusNoContent)
|
||||
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Assign(actions []string, userID, groupID, token string) errors.SDKError {
|
||||
policy := Policy{
|
||||
Subject: userID,
|
||||
Object: groupID,
|
||||
Actions: actions,
|
||||
}
|
||||
return sdk.CreateUserPolicy(policy, token)
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Unassign(userID, groupID, token string) errors.SDKError {
|
||||
policy := Policy{
|
||||
Subject: userID,
|
||||
Object: groupID,
|
||||
}
|
||||
|
||||
return sdk.DeleteUserPolicy(policy, token)
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Connect(conn Connection, token string) errors.SDKError {
|
||||
data, err := json.Marshal(conn)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.thingsURL, connectEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusOK)
|
||||
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) Disconnect(connIDs Connection, token string) errors.SDKError {
|
||||
data, err := json.Marshal(connIDs)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", sdk.thingsURL, disconnectEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusNoContent)
|
||||
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ConnectThing(thingID, channelID, token string) errors.SDKError {
|
||||
policy := Policy{
|
||||
Subject: thingID,
|
||||
Object: channelID,
|
||||
}
|
||||
|
||||
return sdk.CreateThingPolicy(policy, token)
|
||||
}
|
||||
|
||||
func (sdk mfSDK) DisconnectThing(thingID, channelID, token string) errors.SDKError {
|
||||
policy := Policy{
|
||||
Subject: thingID,
|
||||
Object: channelID,
|
||||
}
|
||||
|
||||
return sdk.DeleteThingPolicy(policy, token)
|
||||
}
|
||||
|
||||
func (sdk mfSDK) AuthorizeThing(accessReq AccessRequest, token string) (bool, string, errors.SDKError) {
|
||||
data, err := json.Marshal(accessReq)
|
||||
if err != nil {
|
||||
return false, "", errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s/%s", sdk.thingsURL, channelsEndpoint, accessReq.Object, accessEndpoint)
|
||||
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return false, "", sdkerr
|
||||
}
|
||||
resp := canAccessRes{}
|
||||
if err := json.Unmarshal(body, &resp); err != nil {
|
||||
return false, "", errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return resp.Authorized, resp.ThingID, nil
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -39,12 +39,20 @@ type UserPasswordReq struct {
|
||||
|
||||
// Connection contains thing and channel ID that are connected.
|
||||
type Connection struct {
|
||||
ThingID string `json:"thing_id,omitempty"`
|
||||
ChannelID string `json:"channel_id,omitempty"`
|
||||
Permission string `json:"permission,omitempty"`
|
||||
ThingID string `json:"thing_id,omitempty"`
|
||||
ChannelID string `json:"channel_id,omitempty"`
|
||||
}
|
||||
|
||||
type tokenReq struct {
|
||||
Identity string `json:"identity"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
type UsersRelationRequest struct {
|
||||
Relation string `json:"relation"`
|
||||
UserIDs []string `json:"user_ids"`
|
||||
}
|
||||
|
||||
type UserGroupsRequest struct {
|
||||
UserGroupIDs []string `json:"group_ids"`
|
||||
}
|
||||
|
@ -63,13 +63,6 @@ type MembershipsPage struct {
|
||||
Memberships []Group `json:"memberships"`
|
||||
}
|
||||
|
||||
// PolicyPage contains page related metadata as well as list
|
||||
// of Policies that belong to the page.
|
||||
type PolicyPage struct {
|
||||
PageMetadata
|
||||
Policies []Policy `json:"policies"`
|
||||
}
|
||||
|
||||
type revokeCertsRes struct {
|
||||
RevocationTime time.Time `json:"revocation_time"`
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ type PageMetadata struct {
|
||||
Action string `json:"action,omitempty"`
|
||||
Subject string `json:"subject,omitempty"`
|
||||
Object string `json:"object,omitempty"`
|
||||
Permission string `json:"permission,omitempty"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Owner string `json:"owner,omitempty"`
|
||||
SharedBy string `json:"shared_by,omitempty"`
|
||||
@ -135,17 +136,6 @@ type SDK interface {
|
||||
// fmt.Println(users)
|
||||
Users(pm PageMetadata, token string) (UsersPage, errors.SDKError)
|
||||
|
||||
// Members retrieves everything that is assigned to a group identified by groupID.
|
||||
//
|
||||
// example:
|
||||
// pm := sdk.PageMetadata{
|
||||
// Offset: 0,
|
||||
// Limit: 10,
|
||||
// }
|
||||
// members, _ := sdk.Members("groupID", pm, "token")
|
||||
// fmt.Println(members)
|
||||
Members(groupID string, meta PageMetadata, token string) (MembersPage, errors.SDKError)
|
||||
|
||||
// UserProfile returns user logged in.
|
||||
//
|
||||
// example:
|
||||
@ -257,6 +247,42 @@ type SDK interface {
|
||||
// fmt.Println(token)
|
||||
RefreshToken(token string) (Token, errors.SDKError)
|
||||
|
||||
// ListUserChannels list all channels belongs a particular user id.
|
||||
//
|
||||
// example:
|
||||
// pm := sdk.PageMetadata{
|
||||
// Offset: 0,
|
||||
// Limit: 10,
|
||||
// Permission: "edit", // available Options: "administrator", "delete", edit", "view", "share", "owner", "admin", "editor", "viewer"
|
||||
// }
|
||||
// channels, _ := sdk.ListUserChannels("user_id_1", pm, "token")
|
||||
// fmt.Println(channels)
|
||||
ListUserChannels(userID string, pm PageMetadata, token string) (ChannelsPage, errors.SDKError)
|
||||
|
||||
// ListUserGroups list all groups belongs a particular user id.
|
||||
//
|
||||
// example:
|
||||
// pm := sdk.PageMetadata{
|
||||
// Offset: 0,
|
||||
// Limit: 10,
|
||||
// Permission: "edit", // available Options: "administrator", "delete", edit", "view", "share", "owner", "admin", "editor", "viewer"
|
||||
// }
|
||||
// groups, _ := sdk.ListUserGroups("user_id_1", pm, "token")
|
||||
// fmt.Println(channels)
|
||||
ListUserGroups(userID string, pm PageMetadata, token string) (GroupsPage, errors.SDKError)
|
||||
|
||||
// ListUserThings list all things belongs a particular user id.
|
||||
//
|
||||
// example:
|
||||
// pm := sdk.PageMetadata{
|
||||
// Offset: 0,
|
||||
// Limit: 10,
|
||||
// Permission: "edit", // available Options: "administrator", "delete", edit", "view", "share", "owner", "admin", "editor", "viewer"
|
||||
// }
|
||||
// things, _ := sdk.ListUserThings("user_id_1", pm, "token")
|
||||
// fmt.Println(things)
|
||||
ListUserThings(userID string, pm PageMetadata, token string) (ThingsPage, errors.SDKError)
|
||||
|
||||
// CreateThing registers new thing and returns its id.
|
||||
//
|
||||
// example:
|
||||
@ -386,17 +412,39 @@ type SDK interface {
|
||||
// fmt.Println(id)
|
||||
IdentifyThing(key string) (string, errors.SDKError)
|
||||
|
||||
// ShareThing shares thing with other user. It assumes that you have
|
||||
// already created a group and added things to it. It also assumes that
|
||||
// you have required policy to share a thing with the specified user.
|
||||
//
|
||||
// The `ShareThing` method calls the `Connect` method with the
|
||||
// subject as `userID` rather than `thingID`.
|
||||
// ShareThing shares thing with other users.
|
||||
//
|
||||
// example:
|
||||
// err := sdk.ShareThing("channelID", "userID", []string{"c_list", "c_delete"}, "token")
|
||||
// req := sdk.UsersRelationRequest{
|
||||
// Relation: "viewer", // available options: "owner", "admin", "editor", "viewer"
|
||||
// UserIDs: ["user_id_1", "user_id_2", "user_id_3"]
|
||||
// }
|
||||
// err := sdk.ShareThing("thing_id", req, "token")
|
||||
// fmt.Println(err)
|
||||
ShareThing(channelID, userID string, actions []string, token string) errors.SDKError
|
||||
ShareThing(thingID string, req UsersRelationRequest, token string) errors.SDKError
|
||||
|
||||
// UnshareThing unshare a thing with other users.
|
||||
//
|
||||
// example:
|
||||
// req := sdk.UsersRelationRequest{
|
||||
// Relation: "viewer", // available options: "owner", "admin", "editor", "viewer"
|
||||
// UserIDs: ["user_id_1", "user_id_2", "user_id_3"]
|
||||
// }
|
||||
// err := sdk.UnshareThing("thing_id", req, "token")
|
||||
// fmt.Println(err)
|
||||
UnshareThing(thingID string, req UsersRelationRequest, token string) errors.SDKError
|
||||
|
||||
// ListThingUsers all users in a thing.
|
||||
//
|
||||
// example:
|
||||
// pm := sdk.PageMetadata{
|
||||
// Offset: 0,
|
||||
// Limit: 10,
|
||||
// Permission: "edit", // available Options: "administrator", "delete", edit", "view", "share", "owner", "admin", "editor", "viewer"
|
||||
// }
|
||||
// users, _ := sdk.ListThingUsers("thing_id", pm, "token")
|
||||
// fmt.Println(users)
|
||||
ListThingUsers(thingID string, pm PageMetadata, token string) (UsersPage, errors.SDKError)
|
||||
|
||||
// CreateGroup creates new group and returns its id.
|
||||
//
|
||||
@ -411,18 +459,6 @@ type SDK interface {
|
||||
// fmt.Println(group)
|
||||
CreateGroup(group Group, token string) (Group, errors.SDKError)
|
||||
|
||||
// Memberships
|
||||
//
|
||||
// example:
|
||||
// pm := sdk.PageMetadata{
|
||||
// Offset: 0,
|
||||
// Limit: 10,
|
||||
// Name: "My Group",
|
||||
// }
|
||||
// groups, _ := sdk.Memberships("userID", pm, "token")
|
||||
// fmt.Println(groups)
|
||||
Memberships(clientID string, pm PageMetadata, token string) (MembershipsPage, errors.SDKError)
|
||||
|
||||
// Groups returns page of groups.
|
||||
//
|
||||
// example:
|
||||
@ -494,6 +530,52 @@ type SDK interface {
|
||||
// fmt.Println(group)
|
||||
DisableGroup(id, token string) (Group, errors.SDKError)
|
||||
|
||||
// AddUserToGroup add user to a group.
|
||||
//
|
||||
// example:
|
||||
// req := sdk.UsersRelationRequest{
|
||||
// Relation: "viewer", // available options: "owner", "admin", "editor", "viewer"
|
||||
// UserIDs: ["user_id_1", "user_id_2", "user_id_3"]
|
||||
// }
|
||||
// group, _ := sdk.AddUserToGroup("groupID",req, "token")
|
||||
// fmt.Println(group)
|
||||
AddUserToGroup(groupID string, req UsersRelationRequest, token string) errors.SDKError
|
||||
|
||||
// RemoveUserFromGroup remove user from a group.
|
||||
//
|
||||
// example:
|
||||
// req := sdk.UsersRelationRequest{
|
||||
// Relation: "viewer", // available options: "owner", "admin", "editor", "viewer"
|
||||
// UserIDs: ["user_id_1", "user_id_2", "user_id_3"]
|
||||
// }
|
||||
// group, _ := sdk.RemoveUserFromGroup("groupID",req, "token")
|
||||
// fmt.Println(group)
|
||||
RemoveUserFromGroup(groupID string, req UsersRelationRequest, token string) errors.SDKError
|
||||
|
||||
// ListGroupUsers list all users in the group id .
|
||||
//
|
||||
// example:
|
||||
// pm := sdk.PageMetadata{
|
||||
// Offset: 0,
|
||||
// Limit: 10,
|
||||
// Permission: "edit", // available Options: "administrator", "delete", edit", "view", "share", "owner", "admin", "editor", "viewer"
|
||||
// }
|
||||
// groups, _ := sdk.ListGroupUsers("groupID", pm, "token")
|
||||
// fmt.Println(groups)
|
||||
ListGroupUsers(groupID string, pm PageMetadata, token string) (GroupsPage, errors.SDKError)
|
||||
|
||||
// ListGroupChannels list all channels in the group id .
|
||||
//
|
||||
// example:
|
||||
// pm := sdk.PageMetadata{
|
||||
// Offset: 0,
|
||||
// Limit: 10,
|
||||
// Permission: "edit", // available Options: "administrator", "delete", edit", "view", "share", "owner", "admin", "editor", "viewer"
|
||||
// }
|
||||
// groups, _ := sdk.ListGroupChannels("groupID", pm, "token")
|
||||
// fmt.Println(groups)
|
||||
ListGroupChannels(groupID string, pm PageMetadata, token string) (GroupsPage, errors.SDKError)
|
||||
|
||||
// CreateChannel creates new channel and returns its id.
|
||||
//
|
||||
// example:
|
||||
@ -587,156 +669,78 @@ type SDK interface {
|
||||
// fmt.Println(channel)
|
||||
DisableChannel(id, token string) (Channel, errors.SDKError)
|
||||
|
||||
// CreateUserPolicy creates a policy for the given subject, so that, after
|
||||
// CreateUserPolicy, `subject` has a `relation` on `object`. Returns a non-nil
|
||||
// error in case of failures.
|
||||
//
|
||||
// The subject in this case is the `userID` and the object is the `groupID`.
|
||||
// AddUserToChannel add user to a channel.
|
||||
//
|
||||
// example:
|
||||
// policy := sdk.Policy{
|
||||
// Subject: "userID:1",
|
||||
// Object: "groupID:1",
|
||||
// Actions: []string{"g_add"},
|
||||
// }
|
||||
// err := sdk.CreateUserPolicy(policy, "token")
|
||||
// fmt.Println(err)
|
||||
CreateUserPolicy(policy Policy, token string) errors.SDKError
|
||||
// req := sdk.UsersRelationRequest{
|
||||
// Relation: "viewer", // available options: "owner", "admin", "editor", "viewer"
|
||||
// UserIDs: ["user_id_1", "user_id_2", "user_id_3"]
|
||||
// }
|
||||
// err := sdk.AddUserToChannel("channel_id", req, "token")
|
||||
// fmt.Println(err)
|
||||
AddUserToChannel(channelID string, req UsersRelationRequest, token string) errors.SDKError
|
||||
|
||||
// UpdateUserPolicy updates policies based on the given policy structure.
|
||||
//
|
||||
// The subject in this case is the `userID` and the object is the `groupID`.
|
||||
|
||||
// example:
|
||||
// policy := sdk.Policy{
|
||||
// Subject: "userID:1",
|
||||
// Object: "groupID:1",
|
||||
// Actions: []string{"g_add"},
|
||||
// }
|
||||
// err := sdk.UpdateUserPolicy(policy, "token")
|
||||
// fmt.Println(err)
|
||||
UpdateUserPolicy(p Policy, token string) errors.SDKError
|
||||
|
||||
// ListUserPolicies lists policies based on the given policy structure.
|
||||
// RemoveUserFromChannel remove user from a group.
|
||||
//
|
||||
// example:
|
||||
// pm := sdk.PageMetadata{
|
||||
// Offset: 0,
|
||||
// Limit: 10,
|
||||
// Subject: "userID:1",
|
||||
// }
|
||||
// policies, _ := sdk.ListUserPolicies(pm, "token")
|
||||
// fmt.Println(policies)
|
||||
ListUserPolicies(pm PageMetadata, token string) (PolicyPage, errors.SDKError)
|
||||
// req := sdk.UsersRelationRequest{
|
||||
// Relation: "viewer", // available options: "owner", "admin", "editor", "viewer"
|
||||
// UserIDs: ["user_id_1", "user_id_2", "user_id_3"]
|
||||
// }
|
||||
// err := sdk.RemoveUserFromChannel("channel_id", req, "token")
|
||||
// fmt.Println(err)
|
||||
RemoveUserFromChannel(channelID string, req UsersRelationRequest, token string) errors.SDKError
|
||||
|
||||
// DeleteUserPolicy deletes policies.
|
||||
//
|
||||
// The subject in this case is the `userID` and the object is the `groupID`.
|
||||
// ListChannelUsers list all users in a channel .
|
||||
//
|
||||
// example:
|
||||
// policy := sdk.Policy{
|
||||
// Subject: "userID:1",
|
||||
// Object: "groupID:1",
|
||||
// }
|
||||
// err := sdk.DeleteUserPolicy(policy, "token")
|
||||
// fmt.Println(err)
|
||||
DeleteUserPolicy(policy Policy, token string) errors.SDKError
|
||||
// pm := sdk.PageMetadata{
|
||||
// Offset: 0,
|
||||
// Limit: 10,
|
||||
// Permission: "edit", // available Options: "administrator", "delete", edit", "view", "share", "owner", "admin", "editor", "viewer"
|
||||
// }
|
||||
// users, _ := sdk.ListChannelUsers("channel_id", pm, "token")
|
||||
// fmt.Println(users)
|
||||
ListChannelUsers(channelID string, pm PageMetadata, token string) (UsersPage, errors.SDKError)
|
||||
|
||||
// CreateThingPolicy creates a policy for the given subject, so that, after
|
||||
// CreateThingPolicy, `subject` has a `relation` on `object`. Returns a non-nil
|
||||
// error in case of failures.
|
||||
//
|
||||
// The subject in this case can be a `thingID` or a `userID` and the object is the `channelID`.
|
||||
// AddUserGroupToChannel add user group to a channel.
|
||||
//
|
||||
// example:
|
||||
// policy := sdk.Policy{
|
||||
// Subject: "thingID:1",
|
||||
// Object: "channelID:1",
|
||||
// Actions: []string{"m_write"},
|
||||
// }
|
||||
// err := sdk.CreateThingPolicy(policy, "token")
|
||||
// fmt.Println(err)
|
||||
CreateThingPolicy(policy Policy, token string) errors.SDKError
|
||||
// req := sdk.UserGroupsRequest{
|
||||
// GroupsIDs: ["group_id_1", "group_id_2", "group_id_3"]
|
||||
// }
|
||||
// err := sdk.AddUserGroupToChannel("channel_id",req, "token")
|
||||
// fmt.Println(err)
|
||||
AddUserGroupToChannel(channelID string, req UserGroupsRequest, token string) errors.SDKError
|
||||
|
||||
// UpdateThingPolicy updates policies based on the given policy structure.
|
||||
//
|
||||
// The subject in this case can be a `thingID` or a `userID` and the object is the `channelID`.
|
||||
// RemoveUserGroupFromChannel remove user group from a channel.
|
||||
//
|
||||
// example:
|
||||
// policy := sdk.Policy{
|
||||
// Subject: "thingID:1",
|
||||
// Object: "channelID:1",
|
||||
// Actions: []string{"m_write"},
|
||||
// }
|
||||
// err := sdk.UpdateThingPolicy(policy, "token")
|
||||
// fmt.Println(err)
|
||||
UpdateThingPolicy(p Policy, token string) errors.SDKError
|
||||
// req := sdk.UserGroupsRequest{
|
||||
// GroupsIDs: ["group_id_1", "group_id_2", "group_id_3"]
|
||||
// }
|
||||
// err := sdk.RemoveUserGroupFromChannel("channel_id",req, "token")
|
||||
// fmt.Println(err)
|
||||
RemoveUserGroupFromChannel(channelID string, req UserGroupsRequest, token string) errors.SDKError
|
||||
|
||||
// ListThingPolicies lists policies based on the given policy structure.
|
||||
// ListChannelUserGroups list all user groups in a channel.
|
||||
//
|
||||
// example:
|
||||
// pm := sdk.PageMetadata{
|
||||
// Offset: 0,
|
||||
// Limit: 10,
|
||||
// Subject: "thingID:1",
|
||||
// }
|
||||
// policies, _ := sdk.ListThingPolicies(pm, "token")
|
||||
// fmt.Println(policies)
|
||||
ListThingPolicies(pm PageMetadata, token string) (PolicyPage, errors.SDKError)
|
||||
|
||||
// DeleteThingPolicy deletes policies.
|
||||
//
|
||||
// The subject in this case can be a `thingID` or a `userID` and the object is the `channelID`.
|
||||
//
|
||||
// example:
|
||||
// policy := sdk.Policy{
|
||||
// Subject: "thingID:1",
|
||||
// Object: "channelID:1",
|
||||
// }
|
||||
// err := sdk.DeleteThingPolicy(policy, "token")
|
||||
// fmt.Println(err)
|
||||
DeleteThingPolicy(policy Policy, token string) errors.SDKError
|
||||
|
||||
// AuthorizeUser returns true if the given policy structure allows the action.
|
||||
//
|
||||
// The subject in this case is the `userID` and the object is the `groupID`.
|
||||
//
|
||||
// example:
|
||||
// aReq := sdk.AccessRequest{
|
||||
// Subject: "userID:1",
|
||||
// Object: "groupID:1",
|
||||
// Actions: "g_add",
|
||||
// EntityType: "clients",
|
||||
// }
|
||||
// ok, _ := sdk.AuthorizeUser(aReq, "token")
|
||||
// fmt.Println(ok)
|
||||
AuthorizeUser(accessReq AccessRequest, token string) (bool, errors.SDKError)
|
||||
|
||||
// Assign assigns users to a group with the given actions.
|
||||
//
|
||||
// The `Assign` method calls the `CreateUserPolicy` method under the hood.
|
||||
//
|
||||
// example:
|
||||
// err := sdk.Assign([]string{"g_add"}, "userID:1", "groupID:1", "token")
|
||||
// fmt.Println(err)
|
||||
Assign(action []string, userID, groupID, token string) errors.SDKError
|
||||
|
||||
// Unassign removes a user from a group.
|
||||
//
|
||||
// The `Unassign` method calls the `DeleteUserPolicy` method under the hood.
|
||||
//
|
||||
// example:
|
||||
// err := sdk.Unassign("userID:1", "groupID:1", "token")
|
||||
// fmt.Println(err)
|
||||
Unassign(userID, groupID, token string) errors.SDKError
|
||||
// pm := sdk.PageMetadata{
|
||||
// Offset: 0,
|
||||
// Limit: 10,
|
||||
// Permission: "view",
|
||||
// }
|
||||
// groups, _ := sdk.ListChannelUserGroups("channel_id_1", pm, "token")
|
||||
// fmt.Println(groups)
|
||||
ListChannelUserGroups(channelID string, pm PageMetadata, token string) (GroupsPage, errors.SDKError)
|
||||
|
||||
// Connect bulk connects things to channels specified by id.
|
||||
//
|
||||
// example:
|
||||
// conns := sdk.Connection{
|
||||
// ChannelIDs: []string{"thingID:1", "thingID:2"},
|
||||
// ThingIDs: []string{"channelID:1", "channelID:2"},
|
||||
// Actions: []string{"m_read"},
|
||||
// ChannelID: "channel_id_1",
|
||||
// ThingID: "thing_id_1",
|
||||
// }
|
||||
// err := sdk.Connect(conns, "token")
|
||||
// fmt.Println(err)
|
||||
@ -746,8 +750,8 @@ type SDK interface {
|
||||
//
|
||||
// example:
|
||||
// conns := sdk.Connection{
|
||||
// ChannelIDs: []string{"thingID:1", "thingID:2"},
|
||||
// ThingIDs: []string{"channelID:1", "channelID:2"},
|
||||
// ChannelID: "channel_id_1",
|
||||
// ThingID: "thing_id_1",
|
||||
// }
|
||||
// err := sdk.Disconnect(conns, "token")
|
||||
// fmt.Println(err)
|
||||
@ -771,19 +775,6 @@ type SDK interface {
|
||||
// fmt.Println(err)
|
||||
DisconnectThing(thingID, chanID, token string) errors.SDKError
|
||||
|
||||
// AuthorizeThing returns true if the given policy structure allows the action.
|
||||
//
|
||||
// example:
|
||||
// aReq := sdk.AccessRequest{
|
||||
// Subject: "thingID",
|
||||
// Object: "channelID",
|
||||
// Actions: "m_read",
|
||||
// EntityType: "things",
|
||||
// }
|
||||
// ok, _ := sdk.AuthorizeThing(aReq "token")
|
||||
// fmt.Println(ok)
|
||||
AuthorizeThing(accessReq AccessRequest, token string) (bool, string, errors.SDKError)
|
||||
|
||||
// SendMessage send message to specified channel.
|
||||
//
|
||||
// example:
|
||||
|
@ -17,6 +17,8 @@ const (
|
||||
connectEndpoint = "connect"
|
||||
disconnectEndpoint = "disconnect"
|
||||
identifyEndpoint = "identify"
|
||||
shareEndpoint = "share"
|
||||
unshareEndpoint = "unshare"
|
||||
)
|
||||
|
||||
// Thing represents mainflux thing.
|
||||
@ -254,13 +256,44 @@ func (sdk mfSDK) IdentifyThing(key string) (string, errors.SDKError) {
|
||||
return i.ID, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ShareThing(groupID, userID string, actions []string, token string) errors.SDKError {
|
||||
policy := Policy{
|
||||
Subject: userID,
|
||||
Object: groupID,
|
||||
Actions: actions,
|
||||
External: true,
|
||||
func (sdk mfSDK) ShareThing(thingID string, req UsersRelationRequest, token string) errors.SDKError {
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return sdk.CreateThingPolicy(policy, token)
|
||||
url := fmt.Sprintf("%s/%s/%s/%s", sdk.thingsURL, thingsEndpoint, thingID, unshareEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) UnshareThing(thingID string, req UsersRelationRequest, token string) errors.SDKError {
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s/%s/%s", sdk.thingsURL, thingsEndpoint, thingID, shareEndpoint)
|
||||
|
||||
_, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, data, nil, http.StatusOK)
|
||||
return sdkerr
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ListThingUsers(thingID string, pm PageMetadata, token string) (UsersPage, errors.SDKError) {
|
||||
url, err := sdk.withQueryParams(sdk.thingsURL, fmt.Sprintf("%s/%s/%s", thingsEndpoint, thingID, usersEndpoint), pm)
|
||||
if err != nil {
|
||||
return UsersPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return UsersPage{}, sdkerr
|
||||
}
|
||||
up := UsersPage{}
|
||||
if err := json.Unmarshal(body, &up); err != nil {
|
||||
return UsersPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return up, nil
|
||||
}
|
||||
|
@ -267,6 +267,58 @@ func (sdk mfSDK) UpdateUserOwner(user User, token string) (User, errors.SDKError
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ListUserChannels(userID string, pm PageMetadata, token string) (ChannelsPage, errors.SDKError) {
|
||||
url, err := sdk.withQueryParams(sdk.usersURL, fmt.Sprintf("%s/%s/%s", usersEndpoint, userID, channelsEndpoint), pm)
|
||||
if err != nil {
|
||||
return ChannelsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return ChannelsPage{}, sdkerr
|
||||
}
|
||||
cp := ChannelsPage{}
|
||||
if err := json.Unmarshal(body, &cp); err != nil {
|
||||
return ChannelsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return cp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ListUserGroups(userID string, pm PageMetadata, token string) (GroupsPage, errors.SDKError) {
|
||||
url, err := sdk.withQueryParams(sdk.usersURL, fmt.Sprintf("%s/%s/%s", usersEndpoint, userID, groupsEndpoint), pm)
|
||||
if err != nil {
|
||||
return GroupsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return GroupsPage{}, sdkerr
|
||||
}
|
||||
gp := GroupsPage{}
|
||||
if err := json.Unmarshal(body, &gp); err != nil {
|
||||
return GroupsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return gp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) ListUserThings(userID string, pm PageMetadata, token string) (ThingsPage, errors.SDKError) {
|
||||
url, err := sdk.withQueryParams(sdk.usersURL, fmt.Sprintf("%s/%s/%s", usersEndpoint, userID, thingsEndpoint), pm)
|
||||
if err != nil {
|
||||
return ThingsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
_, body, sdkerr := sdk.processRequest(http.MethodGet, url, token, nil, nil, http.StatusOK)
|
||||
if sdkerr != nil {
|
||||
return ThingsPage{}, sdkerr
|
||||
}
|
||||
tp := ThingsPage{}
|
||||
if err := json.Unmarshal(body, &tp); err != nil {
|
||||
return ThingsPage{}, errors.NewSDKError(err)
|
||||
}
|
||||
|
||||
return tp, nil
|
||||
}
|
||||
|
||||
func (sdk mfSDK) EnableUser(id, token string) (User, errors.SDKError) {
|
||||
return sdk.changeClientStatus(token, id, enableEndpoint)
|
||||
}
|
||||
|
@ -67,26 +67,6 @@ func groupsHandler(svc groups.Service, r *chi.Mux, logger logger.Logger) http.Ha
|
||||
opts...,
|
||||
), "disable_channel").ServeHTTP)
|
||||
|
||||
// Instead of having this endpoint /channels/{groupID}/assign separately,
|
||||
// we can have two separate endpoints for each member kind
|
||||
// users (/channels/{groupID}/users) & user_groups (/channels/{groupID}/groups)
|
||||
r.Post("/{groupID}/assign", otelhttp.NewHandler(kithttp.NewServer(
|
||||
assignUsersGroupsEndpoint(svc),
|
||||
decodeAssignUsersGroupsRequest,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "assign_members").ServeHTTP)
|
||||
|
||||
// Instead of having this endpoint /channels/{groupID}/unassign separately,
|
||||
// we can have two separate endpoints for each member kind
|
||||
// users (/channels/{groupID}/users) & user_groups (/channels/{groupID}/groups)
|
||||
r.Post("/{groupID}/unassign", otelhttp.NewHandler(kithttp.NewServer(
|
||||
unassignUsersGroupsEndpoint(svc),
|
||||
decodeUnassignUsersGroupsRequest,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "unassign_members").ServeHTTP)
|
||||
|
||||
// Request to add users to a channel
|
||||
// This endpoint can be used alternative to /channels/{groupID}/members
|
||||
r.Post("/{groupID}/users/assign", otelhttp.NewHandler(kithttp.NewServer(
|
||||
@ -192,38 +172,6 @@ func groupsHandler(svc groups.Service, r *chi.Mux, logger logger.Logger) http.Ha
|
||||
return r
|
||||
}
|
||||
|
||||
func decodeAssignUsersGroupsRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
||||
}
|
||||
|
||||
req := assignUsersGroupsRequest{
|
||||
token: apiutil.ExtractBearerToken(r),
|
||||
groupID: chi.URLParam(r, "groupID"),
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeUnassignUsersGroupsRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
||||
}
|
||||
|
||||
req := unassignUsersGroupsRequest{
|
||||
token: apiutil.ExtractBearerToken(r),
|
||||
groupID: chi.URLParam(r, "groupID"),
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeAssignUsersRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
|
||||
|
@ -108,6 +108,7 @@ func clientsHandler(svc things.Service, r *chi.Mux, logger mflog.Logger) http.Ha
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "thing_delete_share").ServeHTTP)
|
||||
|
||||
})
|
||||
|
||||
// Ideal location: things service, channels endpoint
|
||||
@ -122,6 +123,12 @@ func clientsHandler(svc things.Service, r *chi.Mux, logger mflog.Logger) http.Ha
|
||||
opts...,
|
||||
), "list_things_by_channel_id").ServeHTTP)
|
||||
|
||||
r.Get("/users/{userID}/things", otelhttp.NewHandler(kithttp.NewServer(
|
||||
listClientsEndpoint(svc),
|
||||
decodeListClients,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "list_user_things").ServeHTTP)
|
||||
return r
|
||||
}
|
||||
|
||||
@ -185,6 +192,7 @@ func decodeListClients(_ context.Context, r *http.Request) (interface{}, error)
|
||||
name: n,
|
||||
tag: t,
|
||||
permission: p,
|
||||
userID: chi.URLParam(r, "userID"),
|
||||
owner: ownerID,
|
||||
}
|
||||
return req, nil
|
||||
|
@ -92,7 +92,7 @@ func listClientsEndpoint(svc things.Service) endpoint.Endpoint {
|
||||
Permission: req.permission,
|
||||
Metadata: req.metadata,
|
||||
}
|
||||
page, err := svc.ListClients(ctx, req.token, pm)
|
||||
page, err := svc.ListClients(ctx, req.token, req.userID, pm)
|
||||
if err != nil {
|
||||
return mfclients.ClientsPage{}, err
|
||||
}
|
||||
@ -254,36 +254,6 @@ func buildMembersResponse(cp mfclients.MembersPage) memberPageRes {
|
||||
return res
|
||||
}
|
||||
|
||||
func assignUsersGroupsEndpoint(svc groups.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(assignUsersGroupsRequest)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
if err := svc.Assign(ctx, req.token, req.groupID, req.Relation, req.MemberKind, req.Members...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return assignUsersGroupsRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func unassignUsersGroupsEndpoint(svc groups.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(unassignUsersGroupsRequest)
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
if err := svc.Unassign(ctx, req.token, req.groupID, req.Relation, req.MemberKind, req.Members...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return unassignUsersGroupsRes{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func assignUsersEndpoint(svc groups.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(assignUsersRequest)
|
||||
|
@ -75,6 +75,7 @@ type listClientsReq struct {
|
||||
owner string
|
||||
permission string
|
||||
visibility string
|
||||
userID string
|
||||
metadata mfclients.Metadata
|
||||
}
|
||||
|
||||
@ -378,10 +379,9 @@ func (req *connectChannelThingRequest) validate() error {
|
||||
}
|
||||
|
||||
type disconnectChannelThingRequest struct {
|
||||
token string
|
||||
ThingID string `json:"thing_id,omitempty"`
|
||||
ChannelID string `json:"channel_id,omitempty"`
|
||||
Permission string `json:"permission,omitempty"`
|
||||
token string
|
||||
ThingID string `json:"thing_id,omitempty"`
|
||||
ChannelID string `json:"channel_id,omitempty"`
|
||||
}
|
||||
|
||||
func (req *disconnectChannelThingRequest) validate() error {
|
||||
|
@ -49,7 +49,7 @@ func (lm *loggingMiddleware) ViewClient(ctx context.Context, token, id string) (
|
||||
return lm.svc.ViewClient(ctx, token, id)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) ListClients(ctx context.Context, token string, pm mfclients.Page) (cp mfclients.ClientsPage, err error) {
|
||||
func (lm *loggingMiddleware) ListClients(ctx context.Context, token string, reqUserID string, pm mfclients.Page) (cp mfclients.ClientsPage, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method list_things using token %s took %s to complete", token, time.Since(begin))
|
||||
if err != nil {
|
||||
@ -58,7 +58,7 @@ func (lm *loggingMiddleware) ListClients(ctx context.Context, token string, pm m
|
||||
}
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
|
||||
}(time.Now())
|
||||
return lm.svc.ListClients(ctx, token, pm)
|
||||
return lm.svc.ListClients(ctx, token, reqUserID, pm)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) UpdateClient(ctx context.Context, token string, client mfclients.Client) (c mfclients.Client, err error) {
|
||||
|
@ -46,12 +46,12 @@ func (ms *metricsMiddleware) ViewClient(ctx context.Context, token, id string) (
|
||||
return ms.svc.ViewClient(ctx, token, id)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) ListClients(ctx context.Context, token string, pm mfclients.Page) (mfclients.ClientsPage, error) {
|
||||
func (ms *metricsMiddleware) ListClients(ctx context.Context, token string, reqUserID string, pm mfclients.Page) (mfclients.ClientsPage, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "list_things").Add(1)
|
||||
ms.latency.With("method", "list_things").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.ListClients(ctx, token, pm)
|
||||
return ms.svc.ListClients(ctx, token, reqUserID, pm)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) UpdateClient(ctx context.Context, token string, client mfclients.Client) (mfclients.Client, error) {
|
||||
|
@ -188,12 +188,14 @@ func (vce viewClientEvent) Encode() (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
type listClientEvent struct {
|
||||
reqUserID string
|
||||
mfclients.Page
|
||||
}
|
||||
|
||||
func (lce listClientEvent) Encode() (map[string]interface{}, error) {
|
||||
val := map[string]interface{}{
|
||||
"operation": clientList,
|
||||
"reqUserID": lce.reqUserID,
|
||||
"total": lce.Total,
|
||||
"offset": lce.Offset,
|
||||
"limit": lce.Limit,
|
||||
|
@ -118,12 +118,13 @@ func (es *eventStore) ViewClient(ctx context.Context, token, id string) (mfclien
|
||||
return cli, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) ListClients(ctx context.Context, token string, pm mfclients.Page) (mfclients.ClientsPage, error) {
|
||||
cp, err := es.svc.ListClients(ctx, token, pm)
|
||||
func (es *eventStore) ListClients(ctx context.Context, token string, reqUserID string, pm mfclients.Page) (mfclients.ClientsPage, error) {
|
||||
cp, err := es.svc.ListClients(ctx, token, reqUserID, pm)
|
||||
if err != nil {
|
||||
return cp, err
|
||||
}
|
||||
event := listClientEvent{
|
||||
reqUserID,
|
||||
pm,
|
||||
}
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
|
@ -133,27 +133,78 @@ func (svc service) ViewClient(ctx context.Context, token string, id string) (mfc
|
||||
return svc.clients.RetrieveByID(ctx, id)
|
||||
}
|
||||
|
||||
func (svc service) ListClients(ctx context.Context, token string, pm mfclients.Page) (mfclients.ClientsPage, error) {
|
||||
func (svc service) ListClients(ctx context.Context, token string, reqUserID string, pm mfclients.Page) (mfclients.ClientsPage, error) {
|
||||
var ids []string
|
||||
|
||||
userID, err := svc.identify(ctx, token)
|
||||
if err != nil {
|
||||
return mfclients.ClientsPage{}, err
|
||||
}
|
||||
|
||||
tids, err := svc.auth.ListAllObjects(ctx, &mainflux.ListObjectsReq{
|
||||
SubjectType: userType,
|
||||
Subject: userID,
|
||||
Permission: pm.Permission,
|
||||
ObjectType: thingType,
|
||||
})
|
||||
if err != nil {
|
||||
return mfclients.ClientsPage{}, err
|
||||
switch {
|
||||
case (reqUserID != "" && reqUserID != userID):
|
||||
if _, err := svc.authorize(ctx, userType, tokenKind, userID, ownerPermission, userType, reqUserID); err != nil {
|
||||
return mfclients.ClientsPage{}, err
|
||||
}
|
||||
rtids, err := svc.listClientIDs(ctx, reqUserID, pm.Permission)
|
||||
if err != nil {
|
||||
return mfclients.ClientsPage{}, err
|
||||
}
|
||||
ids, err = svc.filterAllowedThingIDs(ctx, userID, pm.Permission, rtids)
|
||||
if err != nil {
|
||||
return mfclients.ClientsPage{}, err
|
||||
}
|
||||
default:
|
||||
ids, err = svc.listClientIDs(ctx, userID, pm.Permission)
|
||||
if err != nil {
|
||||
return mfclients.ClientsPage{}, err
|
||||
}
|
||||
}
|
||||
|
||||
pm.IDs = tids.Policies
|
||||
if len(ids) == 0 {
|
||||
return mfclients.ClientsPage{
|
||||
Page: mfclients.Page{Total: 0, Limit: pm.Limit, Offset: pm.Offset},
|
||||
}, nil
|
||||
}
|
||||
|
||||
pm.IDs = ids
|
||||
|
||||
return svc.clients.RetrieveAllByIDs(ctx, pm)
|
||||
}
|
||||
|
||||
func (svc service) listClientIDs(ctx context.Context, userID, permission string) ([]string, error) {
|
||||
tids, err := svc.auth.ListAllObjects(ctx, &mainflux.ListObjectsReq{
|
||||
SubjectType: userType,
|
||||
Subject: userID,
|
||||
Permission: permission,
|
||||
ObjectType: thingType,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tids.Policies, nil
|
||||
}
|
||||
|
||||
func (svc service) filterAllowedThingIDs(ctx context.Context, userID, permission string, thingIDs []string) ([]string, error) {
|
||||
var ids []string
|
||||
tids, err := svc.auth.ListAllObjects(ctx, &mainflux.ListObjectsReq{
|
||||
SubjectType: userType,
|
||||
Subject: userID,
|
||||
Permission: permission,
|
||||
ObjectType: thingType,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, thingID := range thingIDs {
|
||||
for _, tid := range tids.Policies {
|
||||
if thingID == tid {
|
||||
ids = append(ids, thingID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
func (svc service) UpdateClient(ctx context.Context, token string, cli mfclients.Client) (mfclients.Client, error) {
|
||||
userID, err := svc.authorize(ctx, userType, tokenKind, token, editPermission, thingType, cli.ID)
|
||||
if err != nil {
|
||||
@ -258,6 +309,7 @@ func (svc service) Share(ctx context.Context, token, id, relation string, userid
|
||||
}
|
||||
|
||||
for _, userid := range userids {
|
||||
|
||||
addPolicyReq := &mainflux.AddPolicyReq{
|
||||
SubjectType: userType,
|
||||
Subject: userid,
|
||||
@ -265,6 +317,7 @@ func (svc service) Share(ctx context.Context, token, id, relation string, userid
|
||||
ObjectType: thingType,
|
||||
Object: id,
|
||||
}
|
||||
|
||||
res, err := svc.auth.AddPolicy(ctx, addPolicyReq)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -273,7 +326,6 @@ func (svc service) Share(ctx context.Context, token, id, relation string, userid
|
||||
return errors.ErrAuthorization
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -284,6 +336,7 @@ func (svc service) Unshare(ctx context.Context, token, id, relation string, user
|
||||
}
|
||||
|
||||
for _, userid := range userids {
|
||||
|
||||
delPolicyReq := &mainflux.DeletePolicyReq{
|
||||
SubjectType: userType,
|
||||
Subject: userid,
|
||||
@ -291,6 +344,7 @@ func (svc service) Unshare(ctx context.Context, token, id, relation string, user
|
||||
ObjectType: thingType,
|
||||
Object: id,
|
||||
}
|
||||
|
||||
res, err := svc.auth.DeletePolicy(ctx, delPolicyReq)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -299,7 +353,6 @@ func (svc service) Unshare(ctx context.Context, token, id, relation string, user
|
||||
return errors.ErrAuthorization
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -336,6 +389,7 @@ func (svc service) ListClientsByGroup(ctx context.Context, token, groupID string
|
||||
}
|
||||
|
||||
pm.IDs = tids.Policies
|
||||
|
||||
cp, err := svc.clients.RetrieveAllByIDs(ctx, pm)
|
||||
if err != nil {
|
||||
return mfclients.MembersPage{}, err
|
||||
|
@ -591,7 +591,7 @@ func TestListClients(t *testing.T) {
|
||||
repoCall1 = auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&mainflux.ListObjectsRes{}, errors.ErrAuthorization)
|
||||
}
|
||||
repoCall2 := cRepo.On("RetrieveAllByIDs", context.Background(), mock.Anything).Return(tc.response, tc.err)
|
||||
page, err := svc.ListClients(context.Background(), tc.token, tc.page)
|
||||
page, err := svc.ListClients(context.Background(), tc.token, "", tc.page)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
assert.Equal(t, tc.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page))
|
||||
repoCall.Unset()
|
||||
@ -949,7 +949,7 @@ func TestEnableClient(t *testing.T) {
|
||||
repoCall := auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: validToken}).Return(&mainflux.IdentityRes{Id: validID}, nil)
|
||||
repoCall1 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&mainflux.ListObjectsRes{}, nil)
|
||||
repoCall2 := cRepo.On("RetrieveAllByIDs", context.Background(), mock.Anything).Return(tc.response, nil)
|
||||
page, err := svc.ListClients(context.Background(), validToken, pm)
|
||||
page, err := svc.ListClients(context.Background(), validToken, "", pm)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
size := uint64(len(page.Clients))
|
||||
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size))
|
||||
@ -1074,7 +1074,7 @@ func TestDisableClient(t *testing.T) {
|
||||
repoCall := auth.On("Identify", mock.Anything, &mainflux.IdentityReq{Token: validToken}).Return(&mainflux.IdentityRes{Id: validID}, nil)
|
||||
repoCall1 := auth.On("ListAllObjects", mock.Anything, mock.Anything).Return(&mainflux.ListObjectsRes{}, nil)
|
||||
repoCall2 := cRepo.On("RetrieveAllByIDs", context.Background(), mock.Anything).Return(tc.response, nil)
|
||||
page, err := svc.ListClients(context.Background(), validToken, pm)
|
||||
page, err := svc.ListClients(context.Background(), validToken, "", pm)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
size := uint64(len(page.Clients))
|
||||
assert.Equal(t, tc.size, size, fmt.Sprintf("%s: expected size %d got %d\n", tc.desc, tc.size, size))
|
||||
|
@ -21,7 +21,7 @@ type Service interface {
|
||||
ViewClient(ctx context.Context, token, id string) (clients.Client, error)
|
||||
|
||||
// ListClients retrieves clients list for a valid auth token.
|
||||
ListClients(ctx context.Context, token string, pm clients.Page) (clients.ClientsPage, error)
|
||||
ListClients(ctx context.Context, token string, reqUserID string, pm clients.Page) (clients.ClientsPage, error)
|
||||
|
||||
// ListClientsByGroup retrieves data about subset of things that are
|
||||
// connected or not connected to specified channel and belong to the user identified by
|
||||
|
@ -41,10 +41,10 @@ func (tm *tracingMiddleware) ViewClient(ctx context.Context, token string, id st
|
||||
}
|
||||
|
||||
// ListClients traces the "ListClients" operation of the wrapped policies.Service.
|
||||
func (tm *tracingMiddleware) ListClients(ctx context.Context, token string, pm mfclients.Page) (mfclients.ClientsPage, error) {
|
||||
func (tm *tracingMiddleware) ListClients(ctx context.Context, token string, reqUserID string, pm mfclients.Page) (mfclients.ClientsPage, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_list_clients")
|
||||
defer span.End()
|
||||
return tm.svc.ListClients(ctx, token, pm)
|
||||
return tm.svc.ListClients(ctx, token, reqUserID, pm)
|
||||
}
|
||||
|
||||
// UpdateClient traces the "UpdateClient" operation of the wrapped policies.Service.
|
||||
@ -128,7 +128,6 @@ func (tm *tracingMiddleware) Authorize(ctx context.Context, req *mainflux.Author
|
||||
func (tm *tracingMiddleware) Share(ctx context.Context, token, id string, relation string, userids ...string) error {
|
||||
ctx, span := tm.tracer.Start(ctx, "share", trace.WithAttributes(attribute.String("id", id), attribute.String("relation", relation), attribute.StringSlice("user_ids", userids)))
|
||||
defer span.End()
|
||||
|
||||
return tm.svc.Share(ctx, token, id, relation, userids...)
|
||||
}
|
||||
|
||||
@ -136,6 +135,5 @@ func (tm *tracingMiddleware) Share(ctx context.Context, token, id string, relati
|
||||
func (tm *tracingMiddleware) Unshare(ctx context.Context, token, id string, relation string, userids ...string) error {
|
||||
ctx, span := tm.tracer.Start(ctx, "unshare", trace.WithAttributes(attribute.String("id", id), attribute.String("relation", relation), attribute.StringSlice("user_ids", userids)))
|
||||
defer span.End()
|
||||
|
||||
return tm.svc.Unshare(ctx, token, id, relation, userids...)
|
||||
}
|
||||
|
@ -224,17 +224,19 @@ func Provision(conf Config) error {
|
||||
fmt.Printf("[[channels]]\nchannel_id = \"%s\"\n\n", cIDs[i])
|
||||
}
|
||||
|
||||
for i := 0; i < conf.Num; i++ {
|
||||
conIDs := sdk.Connection{
|
||||
ChannelID: cIDs[i],
|
||||
ThingID: tIDs[i],
|
||||
}
|
||||
|
||||
if err := s.Connect(conIDs, token.AccessToken); err != nil {
|
||||
log.Fatalf("Failed to connect thing %s to channel %s: %s", conIDs.ThingID, conIDs.ChannelID, err)
|
||||
for _, cID := range cIDs {
|
||||
for _, tID := range tIDs {
|
||||
conIDs := sdk.Connection{
|
||||
ThingID: tID,
|
||||
ChannelID: cID,
|
||||
}
|
||||
if err := s.Connect(conIDs, token.AccessToken); err != nil {
|
||||
log.Fatalf("Failed to connect things %s to channels %s: %s", tID, cID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -138,8 +138,8 @@ func clientsHandler(svc users.Service, r *chi.Mux, logger mflog.Logger) http.Han
|
||||
// and users service can access spiceDB and get the user list with user_group_id.
|
||||
// Request to get list of users present in the user_group_id {groupID}
|
||||
r.Get("/groups/{groupID}/users", otelhttp.NewHandler(kithttp.NewServer(
|
||||
listMembersEndpoint(svc),
|
||||
decodeListMembersRequest,
|
||||
listMembersByGroupEndpoint(svc),
|
||||
decodeListMembersByGroup,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "list_users_by_user_group_id").ServeHTTP)
|
||||
@ -148,16 +148,20 @@ func clientsHandler(svc users.Service, r *chi.Mux, logger mflog.Logger) http.Han
|
||||
// Reason for placing here :
|
||||
// SpiceDB provides list of user ids in given channel_id
|
||||
// and users service can access spiceDB and get the user list with channel_id.
|
||||
// Request to get list of users present in the user_group_id {groupID}
|
||||
// The ideal placeholder name should be {channelID}, but gapi.DecodeListGroupsRequest uses {groupID} as a placeholder for the ID.
|
||||
// So here, we are using {groupID} as the placeholder.
|
||||
r.Get("/channels/{groupID}/users", otelhttp.NewHandler(kithttp.NewServer(
|
||||
listMembersEndpoint(svc),
|
||||
decodeListMembersRequest,
|
||||
// Request to get list of users present in the user_group_id {channelID}
|
||||
r.Get("/channels/{channelID}/users", otelhttp.NewHandler(kithttp.NewServer(
|
||||
listMembersByChannelEndpoint(svc),
|
||||
decodeListMembersByChannel,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "list_users_by_channel_id").ServeHTTP)
|
||||
|
||||
r.Get("/things/{thingID}/users", otelhttp.NewHandler(kithttp.NewServer(
|
||||
listMembersByThingEndpoint(svc),
|
||||
decodeListMembersByThing,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "list_users_by_thing_id").ServeHTTP)
|
||||
return r
|
||||
}
|
||||
|
||||
@ -398,62 +402,98 @@ func decodeChangeClientStatus(_ context.Context, r *http.Request) (interface{},
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeListMembersRequest(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
s, err := apiutil.ReadStringQuery(r, api.StatusKey, api.DefClientStatus)
|
||||
func decodeListMembersByGroup(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
page, err := queryPageParams(r)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
return nil, err
|
||||
}
|
||||
o, err := apiutil.ReadNumQuery[uint64](r, api.OffsetKey, api.DefOffset)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
l, err := apiutil.ReadNumQuery[uint64](r, api.LimitKey, api.DefLimit)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
m, err := apiutil.ReadMetadataQuery(r, api.MetadataKey, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
n, err := apiutil.ReadStringQuery(r, api.NameKey, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
i, err := apiutil.ReadStringQuery(r, api.IdentityKey, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
t, err := apiutil.ReadStringQuery(r, api.TagKey, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
oid, err := apiutil.ReadStringQuery(r, api.OwnerKey, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
st, err := mfclients.ToStatus(s)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
p, err := apiutil.ReadStringQuery(r, api.PermissionKey, api.DefPermission)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
req := listMembersReq{
|
||||
token: apiutil.ExtractBearerToken(r),
|
||||
Page: mfclients.Page{
|
||||
Status: st,
|
||||
Offset: o,
|
||||
Limit: l,
|
||||
Metadata: m,
|
||||
Identity: i,
|
||||
Name: n,
|
||||
Tag: t,
|
||||
Owner: oid,
|
||||
Permission: p,
|
||||
},
|
||||
groupID: chi.URLParam(r, "groupID"),
|
||||
req := listMembersByObjectReq{
|
||||
token: apiutil.ExtractBearerToken(r),
|
||||
Page: page,
|
||||
objectID: chi.URLParam(r, "groupID"),
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeListMembersByChannel(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
page, err := queryPageParams(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req := listMembersByObjectReq{
|
||||
token: apiutil.ExtractBearerToken(r),
|
||||
Page: page,
|
||||
objectID: chi.URLParam(r, "channelID"),
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeListMembersByThing(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
page, err := queryPageParams(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req := listMembersByObjectReq{
|
||||
token: apiutil.ExtractBearerToken(r),
|
||||
Page: page,
|
||||
objectID: chi.URLParam(r, "thingID"),
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func queryPageParams(r *http.Request) (mfclients.Page, error) {
|
||||
s, err := apiutil.ReadStringQuery(r, api.StatusKey, api.DefClientStatus)
|
||||
if err != nil {
|
||||
return mfclients.Page{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
o, err := apiutil.ReadNumQuery[uint64](r, api.OffsetKey, api.DefOffset)
|
||||
if err != nil {
|
||||
return mfclients.Page{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
l, err := apiutil.ReadNumQuery[uint64](r, api.LimitKey, api.DefLimit)
|
||||
if err != nil {
|
||||
return mfclients.Page{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
m, err := apiutil.ReadMetadataQuery(r, api.MetadataKey, nil)
|
||||
if err != nil {
|
||||
return mfclients.Page{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
n, err := apiutil.ReadStringQuery(r, api.NameKey, "")
|
||||
if err != nil {
|
||||
return mfclients.Page{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
i, err := apiutil.ReadStringQuery(r, api.IdentityKey, "")
|
||||
if err != nil {
|
||||
return mfclients.Page{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
t, err := apiutil.ReadStringQuery(r, api.TagKey, "")
|
||||
if err != nil {
|
||||
return mfclients.Page{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
oid, err := apiutil.ReadStringQuery(r, api.OwnerKey, "")
|
||||
if err != nil {
|
||||
return mfclients.Page{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
st, err := mfclients.ToStatus(s)
|
||||
if err != nil {
|
||||
return mfclients.Page{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
p, err := apiutil.ReadStringQuery(r, api.PermissionKey, api.DefPermission)
|
||||
if err != nil {
|
||||
return mfclients.Page{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
return mfclients.Page{
|
||||
Status: st,
|
||||
Offset: o,
|
||||
Limit: l,
|
||||
Metadata: m,
|
||||
Identity: i,
|
||||
Name: n,
|
||||
Tag: t,
|
||||
Owner: oid,
|
||||
Permission: p,
|
||||
}, nil
|
||||
}
|
||||
|
@ -102,14 +102,50 @@ func listClientsEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
}
|
||||
}
|
||||
|
||||
func listMembersEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
func listMembersByGroupEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listMembersReq)
|
||||
req := request.(listMembersByObjectReq)
|
||||
req.objectKind = "groups"
|
||||
if err := req.validate(); err != nil {
|
||||
return memberPageRes{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
page, err := svc.ListMembers(ctx, req.token, req.groupID, req.Page)
|
||||
page, err := svc.ListMembers(ctx, req.token, req.objectKind, req.objectID, req.Page)
|
||||
if err != nil {
|
||||
return memberPageRes{}, err
|
||||
}
|
||||
|
||||
return buildMembersResponse(page), nil
|
||||
}
|
||||
}
|
||||
|
||||
func listMembersByChannelEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listMembersByObjectReq)
|
||||
// In spiceDB schema, using the same 'group' type for both channels and groups, rather than having a separate type for channels.
|
||||
req.objectKind = "groups"
|
||||
if err := req.validate(); err != nil {
|
||||
return memberPageRes{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
page, err := svc.ListMembers(ctx, req.token, req.objectKind, req.objectID, req.Page)
|
||||
if err != nil {
|
||||
return memberPageRes{}, err
|
||||
}
|
||||
|
||||
return buildMembersResponse(page), nil
|
||||
}
|
||||
}
|
||||
|
||||
func listMembersByThingEndpoint(svc users.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listMembersByObjectReq)
|
||||
req.objectKind = "things"
|
||||
if err := req.validate(); err != nil {
|
||||
return memberPageRes{}, errors.Wrap(apiutil.ErrValidation, err)
|
||||
}
|
||||
|
||||
page, err := svc.ListMembers(ctx, req.token, req.objectKind, req.objectID, req.Page)
|
||||
if err != nil {
|
||||
return memberPageRes{}, err
|
||||
}
|
||||
|
@ -83,24 +83,6 @@ func groupsHandler(svc groups.Service, r *chi.Mux, logger logger.Logger) http.Ha
|
||||
opts...,
|
||||
), "disable_group").ServeHTTP)
|
||||
|
||||
// Instead of this endpoint /{groupID}/members/assign separately, we can simply use /{groupID}/users
|
||||
// because this group is intended exclusively for users. No other entity could not be added
|
||||
r.Post("/{groupID}/members/assign", otelhttp.NewHandler(kithttp.NewServer(
|
||||
gapi.AssignMembersEndpoint(svc, "", "users"),
|
||||
gapi.DecodeAssignMembersRequest,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "assign_members").ServeHTTP)
|
||||
|
||||
// Instead of maintaining this endpoint /{groupID}/members/unassign separately, we can simply use /{groupID}/users
|
||||
// because this group is intended exclusively for users. No other entity could not be added
|
||||
r.Post("/{groupID}/members/unassign", otelhttp.NewHandler(kithttp.NewServer(
|
||||
gapi.UnassignMembersEndpoint(svc, "", "users"),
|
||||
gapi.DecodeUnassignMembersRequest,
|
||||
api.EncodeResponse,
|
||||
opts...,
|
||||
), "unassign_members").ServeHTTP)
|
||||
|
||||
r.Post("/{groupID}/users/assign", otelhttp.NewHandler(kithttp.NewServer(
|
||||
assignUsersEndpoint(svc),
|
||||
decodeAssignUsersRequest,
|
||||
|
@ -252,16 +252,16 @@ func (lm *loggingMiddleware) DisableClient(ctx context.Context, token, id string
|
||||
|
||||
// ListMembers logs the list_members request. It logs the group id, token and the time it took to complete the request.
|
||||
// If the request fails, it logs the error.
|
||||
func (lm *loggingMiddleware) ListMembers(ctx context.Context, token, groupID string, cp mfclients.Page) (mp mfclients.MembersPage, err error) {
|
||||
func (lm *loggingMiddleware) ListMembers(ctx context.Context, token, objectKind, objectID string, cp mfclients.Page) (mp mfclients.MembersPage, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method list_members %d members for group with id %s and token %s took %s to complete", mp.Total, groupID, token, time.Since(begin))
|
||||
message := fmt.Sprintf("Method list_members %d members for object kind %s and object id %s and token %s took %s to complete", mp.Total, objectKind, objectID, token, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
return
|
||||
}
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
|
||||
}(time.Now())
|
||||
return lm.svc.ListMembers(ctx, token, groupID, cp)
|
||||
return lm.svc.ListMembers(ctx, token, objectKind, objectID, cp)
|
||||
}
|
||||
|
||||
// Identify logs the identify request. It logs the token and the time it took to complete the request.
|
||||
|
@ -175,12 +175,12 @@ func (ms *metricsMiddleware) DisableClient(ctx context.Context, token string, id
|
||||
}
|
||||
|
||||
// ListMembers instruments ListMembers method with metrics.
|
||||
func (ms *metricsMiddleware) ListMembers(ctx context.Context, token, groupID string, pm mfclients.Page) (mp mfclients.MembersPage, err error) {
|
||||
func (ms *metricsMiddleware) ListMembers(ctx context.Context, token, objectKind, objectID string, pm mfclients.Page) (mp mfclients.MembersPage, err error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "list_members").Add(1)
|
||||
ms.latency.With("method", "list_members").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
return ms.svc.ListMembers(ctx, token, groupID, pm)
|
||||
return ms.svc.ListMembers(ctx, token, objectKind, objectID, pm)
|
||||
}
|
||||
|
||||
// Identify instruments Identify method with metrics.
|
||||
|
@ -83,19 +83,23 @@ func (req listClientsReq) validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type listMembersReq struct {
|
||||
type listMembersByObjectReq struct {
|
||||
mfclients.Page
|
||||
token string
|
||||
groupID string
|
||||
token string
|
||||
objectKind string
|
||||
objectID string
|
||||
}
|
||||
|
||||
func (req listMembersReq) validate() error {
|
||||
func (req listMembersByObjectReq) validate() error {
|
||||
if req.token == "" {
|
||||
return apiutil.ErrBearerToken
|
||||
}
|
||||
if req.groupID == "" {
|
||||
if req.objectID == "" {
|
||||
return apiutil.ErrMissingID
|
||||
}
|
||||
if req.objectKind == "" {
|
||||
return apiutil.ErrMissingMemberKind
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -26,8 +26,8 @@ type Service interface {
|
||||
// ListClients retrieves clients list for a valid auth token.
|
||||
ListClients(ctx context.Context, token string, pm clients.Page) (clients.ClientsPage, error)
|
||||
|
||||
// ListMembers retrieves everything that is assigned to a group identified by groupID.
|
||||
ListMembers(ctx context.Context, token, groupID string, pm clients.Page) (clients.MembersPage, error)
|
||||
// ListMembers retrieves everything that is assigned to a group/thing identified by objectID.
|
||||
ListMembers(ctx context.Context, token, objectKind, objectID string, pm clients.Page) (clients.MembersPage, error)
|
||||
|
||||
// UpdateClient updates the client's name and metadata.
|
||||
UpdateClient(ctx context.Context, token string, client clients.Client) (clients.Client, error)
|
||||
|
@ -290,16 +290,18 @@ func (lce listClientEvent) Encode() (map[string]interface{}, error) {
|
||||
|
||||
type listClientByGroupEvent struct {
|
||||
mfclients.Page
|
||||
channelID string
|
||||
objectKind string
|
||||
objectID string
|
||||
}
|
||||
|
||||
func (lcge listClientByGroupEvent) Encode() (map[string]interface{}, error) {
|
||||
val := map[string]interface{}{
|
||||
"operation": clientListByGroup,
|
||||
"total": lcge.Total,
|
||||
"offset": lcge.Offset,
|
||||
"limit": lcge.Limit,
|
||||
"channel_id": lcge.channelID,
|
||||
"operation": clientListByGroup,
|
||||
"total": lcge.Total,
|
||||
"offset": lcge.Offset,
|
||||
"limit": lcge.Limit,
|
||||
"object_kind": lcge.objectKind,
|
||||
"object_id": lcge.objectID,
|
||||
}
|
||||
|
||||
if lcge.Name != "" {
|
||||
|
@ -160,13 +160,13 @@ func (es *eventStore) ListClients(ctx context.Context, token string, pm mfclient
|
||||
return cp, nil
|
||||
}
|
||||
|
||||
func (es *eventStore) ListMembers(ctx context.Context, token, groupID string, pm mfclients.Page) (mfclients.MembersPage, error) {
|
||||
mp, err := es.svc.ListMembers(ctx, token, groupID, pm)
|
||||
func (es *eventStore) ListMembers(ctx context.Context, token, objectKind, objectID string, pm mfclients.Page) (mfclients.MembersPage, error) {
|
||||
mp, err := es.svc.ListMembers(ctx, token, objectKind, objectID, pm)
|
||||
if err != nil {
|
||||
return mp, err
|
||||
}
|
||||
event := listClientByGroupEvent{
|
||||
pm, groupID,
|
||||
pm, objectKind, objectID,
|
||||
}
|
||||
|
||||
if err := es.Publish(ctx, event); err != nil {
|
||||
|
@ -17,11 +17,13 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
userKind = "users"
|
||||
tokenKind = "token"
|
||||
userKind = "users"
|
||||
tokenKind = "token"
|
||||
thingsKind = "things"
|
||||
|
||||
userType = "user"
|
||||
groupType = "group"
|
||||
thingType = "thing"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -145,52 +147,11 @@ func (svc service) ListClients(ctx context.Context, token string, pm mfclients.P
|
||||
if err != nil {
|
||||
return mfclients.ClientsPage{}, err
|
||||
}
|
||||
|
||||
// switch err := svc.authorize(ctx, id, clientsObjectKey, listRelationKey); err {
|
||||
// // If the user is admin, fetch all users from database.
|
||||
// case nil:
|
||||
// switch {
|
||||
// // visibility = all
|
||||
// case pm.SharedBy == myKey && pm.Owner == myKey:
|
||||
// pm.SharedBy = ""
|
||||
// pm.Owner = ""
|
||||
// // visibility = shared
|
||||
// case pm.SharedBy == myKey && pm.Owner != myKey:
|
||||
// pm.SharedBy = id
|
||||
// pm.Owner = ""
|
||||
// // visibility = mine
|
||||
// case pm.Owner == myKey && pm.SharedBy != myKey:
|
||||
// pm.Owner = id
|
||||
// pm.SharedBy = ""
|
||||
// }
|
||||
|
||||
// // If the user is not admin, fetch users that they own or are shared with them.
|
||||
// default:
|
||||
// switch {
|
||||
// // visibility = all
|
||||
// case pm.SharedBy == myKey && pm.Owner == myKey:
|
||||
// pm.SharedBy = id
|
||||
// pm.Owner = id
|
||||
// // visibility = shared
|
||||
// case pm.SharedBy == myKey && pm.Owner != myKey:
|
||||
// pm.SharedBy = id
|
||||
// pm.Owner = ""
|
||||
// // visibility = mine
|
||||
// case pm.Owner == myKey && pm.SharedBy != myKey:
|
||||
// pm.Owner = id
|
||||
// pm.SharedBy = ""
|
||||
// default:
|
||||
// pm.Owner = id
|
||||
// }
|
||||
// pm.Action = listRelationKey
|
||||
// }
|
||||
pm.Owner = id
|
||||
|
||||
clients, err := svc.clients.RetrieveAll(ctx, pm)
|
||||
if err != nil {
|
||||
return mfclients.ClientsPage{}, err
|
||||
}
|
||||
|
||||
return clients, nil
|
||||
}
|
||||
|
||||
@ -413,19 +374,32 @@ func (svc service) changeClientStatus(ctx context.Context, token string, client
|
||||
return svc.clients.ChangeStatus(ctx, client)
|
||||
}
|
||||
|
||||
func (svc service) ListMembers(ctx context.Context, token, groupID string, pm mfclients.Page) (mfclients.MembersPage, error) {
|
||||
if _, err := svc.authorize(ctx, userType, tokenKind, token, pm.Permission, groupType, groupID); err != nil {
|
||||
func (svc service) ListMembers(ctx context.Context, token, objectKind string, objectID string, pm mfclients.Page) (mfclients.MembersPage, error) {
|
||||
var objectType string
|
||||
switch objectKind {
|
||||
case thingsKind:
|
||||
objectType = thingType
|
||||
default:
|
||||
objectType = groupType
|
||||
}
|
||||
|
||||
if _, err := svc.authorize(ctx, userType, tokenKind, token, pm.Permission, objectType, objectID); err != nil {
|
||||
return mfclients.MembersPage{}, err
|
||||
}
|
||||
uids, err := svc.auth.ListAllSubjects(ctx, &mainflux.ListSubjectsReq{
|
||||
SubjectType: userType,
|
||||
Permission: pm.Permission,
|
||||
Object: groupID,
|
||||
ObjectType: groupType,
|
||||
Object: objectID,
|
||||
ObjectType: objectType,
|
||||
})
|
||||
if err != nil {
|
||||
return mfclients.MembersPage{}, err
|
||||
}
|
||||
if len(uids.Policies) == 0 {
|
||||
return mfclients.MembersPage{
|
||||
Page: mfclients.Page{Total: 0, Offset: pm.Offset, Limit: pm.Limit},
|
||||
}, nil
|
||||
}
|
||||
|
||||
pm.IDs = uids.Policies
|
||||
|
||||
@ -433,6 +407,7 @@ func (svc service) ListMembers(ctx context.Context, token, groupID string, pm mf
|
||||
if err != nil {
|
||||
return mfclients.MembersPage{}, err
|
||||
}
|
||||
|
||||
return mfclients.MembersPage{
|
||||
Page: cp.Page,
|
||||
Members: cp.Clients,
|
||||
|
@ -1321,7 +1321,7 @@ func TestListMembers(t *testing.T) {
|
||||
repoCall1 := auth.On("Authorize", mock.Anything, mock.Anything).Return(&mainflux.AuthorizeRes{Authorized: true}, nil)
|
||||
repoCall2 := auth.On("ListAllSubjects", mock.Anything, mock.Anything).Return(&mainflux.ListSubjectsRes{}, nil)
|
||||
repoCall3 := cRepo.On("RetrieveAll", context.Background(), tc.page).Return(mfclients.ClientsPage{Page: tc.response.Page, Clients: tc.response.Members}, tc.err)
|
||||
page, err := svc.ListMembers(context.Background(), tc.token, tc.groupID, tc.page)
|
||||
page, err := svc.ListMembers(context.Background(), tc.token, "groups", tc.groupID, tc.page)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
assert.Equal(t, tc.response, page, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, page))
|
||||
if tc.err == nil {
|
||||
|
@ -172,11 +172,11 @@ func (tm *tracingMiddleware) DisableClient(ctx context.Context, token, id string
|
||||
}
|
||||
|
||||
// ListMembers traces the "ListMembers" operation of the wrapped clients.Service.
|
||||
func (tm *tracingMiddleware) ListMembers(ctx context.Context, token, groupID string, pm mfclients.Page) (mfclients.MembersPage, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_list_members", trace.WithAttributes(attribute.String("group_id", groupID)))
|
||||
func (tm *tracingMiddleware) ListMembers(ctx context.Context, token, objectKind, objectID string, pm mfclients.Page) (mfclients.MembersPage, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "svc_list_members", trace.WithAttributes(attribute.String("object_kind", objectKind)), trace.WithAttributes(attribute.String("object_id", objectID)))
|
||||
defer span.End()
|
||||
|
||||
return tm.svc.ListMembers(ctx, token, groupID, pm)
|
||||
return tm.svc.ListMembers(ctx, token, objectKind, objectID, pm)
|
||||
}
|
||||
|
||||
// Identify traces the "Identify" operation of the wrapped clients.Service.
|
||||
|
Loading…
x
Reference in New Issue
Block a user