From ed056527299d59e916aee71fae971b0f20948198 Mon Sep 17 00:00:00 2001 From: Todd Knight Date: Wed, 22 Jul 2020 15:10:21 -0700 Subject: [PATCH] Add Handlers for Add/Set/Remove Group Members (#209) * Adding members to groups. * Adding Group membership handler and API methods. * Adding custom methods to permision actions list. --- api/groups/custom.go | 117 +++ api/groups/group.gen.go | 14 +- api/groups/member.gen.go | 15 + api/internal/genapi/input.go | 8 + internal/gen/controller.swagger.json | 222 +++++ .../api/resources/groups/group.pb.go | 237 +++-- .../api/services/group_service.pb.go | 835 ++++++++++++++++-- .../api/services/group_service.pb.gw.go | 369 ++++++++ internal/iam/group_member.go | 15 + internal/iam/repository_group.go | 91 +- internal/iam/repository_group_test.go | 10 +- .../api/resources/groups/v1/group.proto | 29 +- .../api/services/v1/group_service.proto | 83 ++ internal/servers/controller/handler_test.go | 179 ++-- .../handlers/groups/group_service.go | 178 +++- .../handlers/groups/group_service_test.go | 519 ++++++++++- .../controller/handlers/roles/role_service.go | 12 +- internal/types/action/action.go | 9 + 18 files changed, 2587 insertions(+), 355 deletions(-) create mode 100644 api/groups/custom.go create mode 100644 api/groups/member.gen.go diff --git a/api/groups/custom.go b/api/groups/custom.go new file mode 100644 index 000000000..827e3b3e6 --- /dev/null +++ b/api/groups/custom.go @@ -0,0 +1,117 @@ +package groups + +import ( + "context" + "fmt" + + "github.com/hashicorp/watchtower/api" +) + +func (s Group) AddMembers(ctx context.Context, memberIds []string) (*Group, *api.Error, error) { + if s.Client == nil { + return nil, nil, fmt.Errorf("nil client in AddMembers request") + } + // We assume that the client provided has the org and optionally the project id of the request. + + if len(memberIds) == 0 { + return nil, nil, fmt.Errorf("empty memberIds slice") + } + + body := map[string]interface{}{ + "version": s.Version, + "member_ids": memberIds, + } + + req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("groups/%s:add-members", s.Id), body) + if err != nil { + return nil, nil, fmt.Errorf("error creating AddMembers request: %w", err) + } + + resp, err := s.Client.Do(req) + if err != nil { + return nil, nil, fmt.Errorf("error performing client request during AddMembers call: %w", err) + } + + target := new(Group) + apiErr, err := resp.Decode(target) + if err != nil { + return nil, nil, fmt.Errorf("error decoding AddMembers repsonse: %w", err) + } + + target.Client = s.Client + + return target, apiErr, nil +} + +func (s Group) SetMembers(ctx context.Context, memberIds []string) (*Group, *api.Error, error) { + if s.Client == nil { + return nil, nil, fmt.Errorf("nil client in SetMembers request") + } + // We assume that the client provided has the org and optionally the project id of the request. + + body := map[string]interface{}{ + "version": s.Version, + } + if len(memberIds) > 0 { + body["member_ids"] = memberIds + } else if memberIds != nil { + // In this function, a non-nil but empty list means clear out + body["member_ids"] = nil + } + + req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("groups/%s:set-members", s.Id), body) + if err != nil { + return nil, nil, fmt.Errorf("error creating SetMembers request: %w", err) + } + + resp, err := s.Client.Do(req) + if err != nil { + return nil, nil, fmt.Errorf("error performing client request during SetMembers call: %w", err) + } + + target := new(Group) + apiErr, err := resp.Decode(target) + if err != nil { + return nil, nil, fmt.Errorf("error decoding SetMembers repsonse: %w", err) + } + + target.Client = s.Client + + return target, apiErr, nil +} + +func (s Group) RemoveMembers(ctx context.Context, memberIds []string) (*Group, *api.Error, error) { + if s.Client == nil { + return nil, nil, fmt.Errorf("nil client in RemoveMembers request") + } + // We assume that the client provided has the org and optionally the project id of the request. + + if len(memberIds) == 0 { + return nil, nil, fmt.Errorf("empty memberIds slice") + } + + body := map[string]interface{}{ + "version": s.Version, + "member_ids": memberIds, + } + + req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("groups/%s:remove-members", s.Id), body) + if err != nil { + return nil, nil, fmt.Errorf("error creating RemoveMembers request: %w", err) + } + + resp, err := s.Client.Do(req) + if err != nil { + return nil, nil, fmt.Errorf("error performing client request during RemoveMembers call: %w", err) + } + + target := new(Group) + apiErr, err := resp.Decode(target) + if err != nil { + return nil, nil, fmt.Errorf("error decoding RemoveMembers repsonse: %w", err) + } + + target.Client = s.Client + + return target, apiErr, nil +} diff --git a/api/groups/group.gen.go b/api/groups/group.gen.go index 462685a02..e0cfb7861 100644 --- a/api/groups/group.gen.go +++ b/api/groups/group.gen.go @@ -36,11 +36,21 @@ type Group struct { UpdatedTime time.Time `json:"updated_time,omitempty"` // Whether the resource is disabled Disabled *bool `json:"disabled,omitempty"` + // The version can be used in subsiquent write requests to ensure this resource + // has not changed and to fail the write if it has. + // Output only. + Version uint32 `json:"version,omitempty"` + // Contains the list of member ids in this group. + // Output only. + MemberIds []string `json:"member_ids,omitempty"` + // The members of this group. + // Output only. + Members []*Member `json:"members,omitempty"` } func (s *Group) SetDefault(key string) { lowerKey := strings.ToLower(key) - validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "scope": "scope", "updatedtime": "updated_time"} + validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "memberids": "member_ids", "members": "members", "name": "name", "scope": "scope", "updatedtime": "updated_time", "version": "version"} for k, v := range validMap { if k == lowerKey || v == lowerKey { s.defaultFields = strutil.AppendIfMissing(s.defaultFields, v) @@ -51,7 +61,7 @@ func (s *Group) SetDefault(key string) { func (s *Group) UnsetDefault(key string) { lowerKey := strings.ToLower(key) - validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "name": "name", "scope": "scope", "updatedtime": "updated_time"} + validMap := map[string]string{"createdtime": "created_time", "description": "description", "disabled": "disabled", "id": "id", "memberids": "member_ids", "members": "members", "name": "name", "scope": "scope", "updatedtime": "updated_time", "version": "version"} for k, v := range validMap { if k == lowerKey || v == lowerKey { s.defaultFields = strutil.StrListDelete(s.defaultFields, v) diff --git a/api/groups/member.gen.go b/api/groups/member.gen.go new file mode 100644 index 000000000..0f207cf20 --- /dev/null +++ b/api/groups/member.gen.go @@ -0,0 +1,15 @@ +// Code generated by "make api"; DO NOT EDIT. +package groups + +type Member struct { + + // The ID of the member. + // Output only. + Id string `json:"id,omitempty"` + // The type of the member. + // Output only. + Type string `json:"type,omitempty"` + // The scope ID of the member. + // Output only. + ScopeId string `json:"scope_id,omitempty"` +} diff --git a/api/internal/genapi/input.go b/api/internal/genapi/input.go index 6498f109e..e22309af6 100644 --- a/api/internal/genapi/input.go +++ b/api/internal/genapi/input.go @@ -100,6 +100,14 @@ var inputStructs = []*structInfo{ outName: "Group", outPkg: "groups", }, + { + inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/groups/group.pb.go", + inName: "Member", + outFile: os.Getenv("GEN_BASEPATH") + "/api/groups/member.gen.go", + outName: "Member", + outPkg: "groups", + outputOnly: true, + }, { inFile: os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/roles/role.pb.go", inName: "Role", diff --git a/internal/gen/controller.swagger.json b/internal/gen/controller.swagger.json index aac2f10f6..9932552c4 100644 --- a/internal/gen/controller.swagger.json +++ b/internal/gen/controller.swagger.json @@ -241,6 +241,105 @@ ] } }, + "/v1/scopes/*/groups/{id}:add-members": { + "post": { + "summary": "Adds Users as members to a Group", + "operationId": "GroupService_AddGroupMembers", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/controller.api.resources.groups.v1.Group" + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/controller.api.services.v1.AddGroupMembersRequest" + } + } + ], + "tags": [ + "controller.api.services.v1.GroupService" + ] + } + }, + "/v1/scopes/*/groups/{id}:remove-members": { + "post": { + "summary": "Removes the specified members from a Group.", + "operationId": "GroupService_RemoveGroupMembers", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/controller.api.resources.groups.v1.Group" + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/controller.api.services.v1.RemoveGroupMembersRequest" + } + } + ], + "tags": [ + "controller.api.services.v1.GroupService" + ] + } + }, + "/v1/scopes/*/groups/{id}:set-members": { + "post": { + "summary": "Set a Group's members to exactly the list of provided in the request, removing any members that are not specified.", + "operationId": "GroupService_SetGroupMembers", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/controller.api.resources.groups.v1.Group" + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/controller.api.services.v1.SetGroupMembersRequest" + } + } + ], + "tags": [ + "controller.api.services.v1.GroupService" + ] + } + }, "/v1/scopes/*/host-catalogs": { "get": { "summary": "Gets a list of HostCatalogs", @@ -1419,10 +1518,52 @@ "type": "boolean", "format": "boolean", "title": "Whether the resource is disabled" + }, + "version": { + "type": "integer", + "format": "int64", + "description": "The version can be used in subsiquent write requests to ensure this resource\nhas not changed and to fail the write if it has.\nOutput only.", + "readOnly": true + }, + "member_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Contains the list of member ids in this group.\nOutput only.", + "readOnly": true + }, + "members": { + "type": "array", + "items": { + "$ref": "#/definitions/controller.api.resources.groups.v1.Member" + }, + "description": "The members of this group.\nOutput only.", + "readOnly": true } }, "title": "Group contains all fields related to a Group resource" }, + "controller.api.resources.groups.v1.Member": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The ID of the member.\nOutput only.", + "readOnly": true + }, + "type": { + "type": "string", + "description": "The type of the member.\nOutput only.", + "readOnly": true + }, + "scope_id": { + "type": "string", + "description": "The scope ID of the member.\nOutput only.", + "readOnly": true + } + } + }, "controller.api.resources.hosts.v1.Host": { "type": "object", "properties": { @@ -1838,6 +1979,33 @@ }, "title": "User contains all fields related to a User resource" }, + "controller.api.services.v1.AddGroupMembersRequest": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "version": { + "type": "integer", + "format": "int64", + "description": "The version ensures the group hasn't changed since it was last retrieved and if\nit has the request will fail." + }, + "member_ids": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "controller.api.services.v1.AddGroupMembersResponse": { + "type": "object", + "properties": { + "item": { + "$ref": "#/definitions/controller.api.resources.groups.v1.Group" + } + } + }, "controller.api.services.v1.AddRoleGrantsRequest": { "type": "object", "properties": { @@ -2196,6 +2364,33 @@ "controller.api.services.v1.RemoveFromHostSetResponse": { "type": "object" }, + "controller.api.services.v1.RemoveGroupMembersRequest": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "version": { + "type": "integer", + "format": "int64", + "description": "The version ensures the group hasn't changed since it was last retrieved and if\nit has the request will fail." + }, + "member_ids": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "controller.api.services.v1.RemoveGroupMembersResponse": { + "type": "object", + "properties": { + "item": { + "$ref": "#/definitions/controller.api.resources.groups.v1.Group" + } + } + }, "controller.api.services.v1.RemoveRoleGrantsRequest": { "type": "object", "properties": { @@ -2250,6 +2445,33 @@ } } }, + "controller.api.services.v1.SetGroupMembersRequest": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "version": { + "type": "integer", + "format": "int64", + "description": "The version ensures the group hasn't changed since it was last retrieved and if\nit has the request will fail." + }, + "member_ids": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "controller.api.services.v1.SetGroupMembersResponse": { + "type": "object", + "properties": { + "item": { + "$ref": "#/definitions/controller.api.resources.groups.v1.Group" + } + } + }, "controller.api.services.v1.SetRoleGrantsRequest": { "type": "object", "properties": { diff --git a/internal/gen/controller/api/resources/groups/group.pb.go b/internal/gen/controller/api/resources/groups/group.pb.go index 697adf1a3..43dd76849 100644 --- a/internal/gen/controller/api/resources/groups/group.pb.go +++ b/internal/gen/controller/api/resources/groups/group.pb.go @@ -29,6 +29,75 @@ const ( // of the legacy proto package is being used. const _ = proto.ProtoPackageIsVersion4 +type Member struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The ID of the member. + // Output only. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // The type of the member. + // Output only. + Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + // The scope ID of the member. + // Output only. + ScopeId string `protobuf:"bytes,3,opt,name=scope_id,proto3" json:"scope_id,omitempty"` +} + +func (x *Member) Reset() { + *x = Member{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_resources_groups_v1_group_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Member) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Member) ProtoMessage() {} + +func (x *Member) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_resources_groups_v1_group_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Member.ProtoReflect.Descriptor instead. +func (*Member) Descriptor() ([]byte, []int) { + return file_controller_api_resources_groups_v1_group_proto_rawDescGZIP(), []int{0} +} + +func (x *Member) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Member) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *Member) GetScopeId() string { + if x != nil { + return x.ScopeId + } + return "" +} + // Group contains all fields related to a Group resource type Group struct { state protoimpl.MessageState @@ -53,12 +122,22 @@ type Group struct { UpdatedTime *timestamp.Timestamp `protobuf:"bytes,6,opt,name=updated_time,proto3" json:"updated_time,omitempty"` // Whether the resource is disabled Disabled *wrappers.BoolValue `protobuf:"bytes,7,opt,name=disabled,proto3" json:"disabled,omitempty"` + // The version can be used in subsiquent write requests to ensure this resource + // has not changed and to fail the write if it has. + // Output only. + Version uint32 `protobuf:"varint,8,opt,name=version,proto3" json:"version,omitempty"` + // Contains the list of member ids in this group. + // Output only. + MemberIds []string `protobuf:"bytes,9,rep,name=member_ids,json=memberIds,proto3" json:"member_ids,omitempty"` + // The members of this group. + // Output only. + Members []*Member `protobuf:"bytes,10,rep,name=members,proto3" json:"members,omitempty"` } func (x *Group) Reset() { *x = Group{} if protoimpl.UnsafeEnabled { - mi := &file_controller_api_resources_groups_v1_group_proto_msgTypes[0] + mi := &file_controller_api_resources_groups_v1_group_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -71,7 +150,7 @@ func (x *Group) String() string { func (*Group) ProtoMessage() {} func (x *Group) ProtoReflect() protoreflect.Message { - mi := &file_controller_api_resources_groups_v1_group_proto_msgTypes[0] + mi := &file_controller_api_resources_groups_v1_group_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -84,7 +163,7 @@ func (x *Group) ProtoReflect() protoreflect.Message { // Deprecated: Use Group.ProtoReflect.Descriptor instead. func (*Group) Descriptor() ([]byte, []int) { - return file_controller_api_resources_groups_v1_group_proto_rawDescGZIP(), []int{0} + return file_controller_api_resources_groups_v1_group_proto_rawDescGZIP(), []int{1} } func (x *Group) GetId() string { @@ -136,6 +215,27 @@ func (x *Group) GetDisabled() *wrappers.BoolValue { return nil } +func (x *Group) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *Group) GetMemberIds() []string { + if x != nil { + return x.MemberIds + } + return nil +} + +func (x *Group) GetMembers() []*Member { + if x != nil { + return x.Members + } + return nil +} + var File_controller_api_resources_groups_v1_group_proto protoreflect.FileDescriptor var file_controller_api_resources_groups_v1_group_proto_rawDesc = []byte{ @@ -154,40 +254,53 @@ var file_controller_api_resources_groups_v1_group_proto_rawDesc = []byte{ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, - 0xb8, 0x03, 0x0a, 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73, 0x63, 0x6f, - 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, - 0x6f, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x42, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x10, 0xc2, 0xdd, 0x29, 0x0c, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x5e, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x1e, 0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x55, 0x5a, 0x53, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x2f, 0x77, 0x61, 0x74, 0x63, 0x68, 0x74, 0x6f, 0x77, 0x65, 0x72, 0x2f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x3b, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x48, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, + 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x22, 0xb7, 0x04, 0x0a, 0x05, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, + 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x42, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x42, 0x10, 0xc2, 0xdd, 0x29, 0x0c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x5e, 0x0a, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, + 0x1e, 0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0c, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0c, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x08, + 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1d, + 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x09, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x44, 0x0a, + 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x42, 0x55, 0x5a, 0x53, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x77, 0x61, 0x74, 0x63, + 0x68, 0x74, 0x6f, 0x77, 0x65, 0x72, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, + 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x73, 0x3b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -202,26 +315,28 @@ func file_controller_api_resources_groups_v1_group_proto_rawDescGZIP() []byte { return file_controller_api_resources_groups_v1_group_proto_rawDescData } -var file_controller_api_resources_groups_v1_group_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_controller_api_resources_groups_v1_group_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_controller_api_resources_groups_v1_group_proto_goTypes = []interface{}{ - (*Group)(nil), // 0: controller.api.resources.groups.v1.Group - (*scopes.ScopeInfo)(nil), // 1: controller.api.resources.scopes.v1.ScopeInfo - (*wrappers.StringValue)(nil), // 2: google.protobuf.StringValue - (*timestamp.Timestamp)(nil), // 3: google.protobuf.Timestamp - (*wrappers.BoolValue)(nil), // 4: google.protobuf.BoolValue + (*Member)(nil), // 0: controller.api.resources.groups.v1.Member + (*Group)(nil), // 1: controller.api.resources.groups.v1.Group + (*scopes.ScopeInfo)(nil), // 2: controller.api.resources.scopes.v1.ScopeInfo + (*wrappers.StringValue)(nil), // 3: google.protobuf.StringValue + (*timestamp.Timestamp)(nil), // 4: google.protobuf.Timestamp + (*wrappers.BoolValue)(nil), // 5: google.protobuf.BoolValue } var file_controller_api_resources_groups_v1_group_proto_depIdxs = []int32{ - 1, // 0: controller.api.resources.groups.v1.Group.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo - 2, // 1: controller.api.resources.groups.v1.Group.name:type_name -> google.protobuf.StringValue - 2, // 2: controller.api.resources.groups.v1.Group.description:type_name -> google.protobuf.StringValue - 3, // 3: controller.api.resources.groups.v1.Group.created_time:type_name -> google.protobuf.Timestamp - 3, // 4: controller.api.resources.groups.v1.Group.updated_time:type_name -> google.protobuf.Timestamp - 4, // 5: controller.api.resources.groups.v1.Group.disabled:type_name -> google.protobuf.BoolValue - 6, // [6:6] is the sub-list for method output_type - 6, // [6:6] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 2, // 0: controller.api.resources.groups.v1.Group.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo + 3, // 1: controller.api.resources.groups.v1.Group.name:type_name -> google.protobuf.StringValue + 3, // 2: controller.api.resources.groups.v1.Group.description:type_name -> google.protobuf.StringValue + 4, // 3: controller.api.resources.groups.v1.Group.created_time:type_name -> google.protobuf.Timestamp + 4, // 4: controller.api.resources.groups.v1.Group.updated_time:type_name -> google.protobuf.Timestamp + 5, // 5: controller.api.resources.groups.v1.Group.disabled:type_name -> google.protobuf.BoolValue + 0, // 6: controller.api.resources.groups.v1.Group.members:type_name -> controller.api.resources.groups.v1.Member + 7, // [7:7] is the sub-list for method output_type + 7, // [7:7] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name } func init() { file_controller_api_resources_groups_v1_group_proto_init() } @@ -231,6 +346,18 @@ func file_controller_api_resources_groups_v1_group_proto_init() { } if !protoimpl.UnsafeEnabled { file_controller_api_resources_groups_v1_group_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Member); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_resources_groups_v1_group_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Group); i { case 0: return &v.state @@ -249,7 +376,7 @@ func file_controller_api_resources_groups_v1_group_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_controller_api_resources_groups_v1_group_proto_rawDesc, NumEnums: 0, - NumMessages: 1, + NumMessages: 2, NumExtensions: 0, NumServices: 0, }, diff --git a/internal/gen/controller/api/services/group_service.pb.go b/internal/gen/controller/api/services/group_service.pb.go index 463a0f4a1..e09dd99e9 100644 --- a/internal/gen/controller/api/services/group_service.pb.go +++ b/internal/gen/controller/api/services/group_service.pb.go @@ -9,6 +9,7 @@ package services import ( context "context" proto "github.com/golang/protobuf/proto" + wrappers "github.com/golang/protobuf/ptypes/wrappers" _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" groups "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/groups" _ "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/scopes" @@ -536,6 +537,342 @@ func (x *DeleteGroupResponse) GetExisted() bool { return false } +type AddGroupMembersRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // The version ensures the group hasn't changed since it was last retrieved and if + // it has the request will fail. + Version *wrappers.UInt32Value `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` + MemberIds []string `protobuf:"bytes,3,rep,name=member_ids,proto3" json:"member_ids,omitempty"` +} + +func (x *AddGroupMembersRequest) Reset() { + *x = AddGroupMembersRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_group_service_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddGroupMembersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddGroupMembersRequest) ProtoMessage() {} + +func (x *AddGroupMembersRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_group_service_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddGroupMembersRequest.ProtoReflect.Descriptor instead. +func (*AddGroupMembersRequest) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_group_service_proto_rawDescGZIP(), []int{10} +} + +func (x *AddGroupMembersRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *AddGroupMembersRequest) GetVersion() *wrappers.UInt32Value { + if x != nil { + return x.Version + } + return nil +} + +func (x *AddGroupMembersRequest) GetMemberIds() []string { + if x != nil { + return x.MemberIds + } + return nil +} + +type AddGroupMembersResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item *groups.Group `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *AddGroupMembersResponse) Reset() { + *x = AddGroupMembersResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_group_service_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddGroupMembersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddGroupMembersResponse) ProtoMessage() {} + +func (x *AddGroupMembersResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_group_service_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddGroupMembersResponse.ProtoReflect.Descriptor instead. +func (*AddGroupMembersResponse) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_group_service_proto_rawDescGZIP(), []int{11} +} + +func (x *AddGroupMembersResponse) GetItem() *groups.Group { + if x != nil { + return x.Item + } + return nil +} + +type SetGroupMembersRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // The version ensures the group hasn't changed since it was last retrieved and if + // it has the request will fail. + Version *wrappers.UInt32Value `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` + MemberIds []string `protobuf:"bytes,3,rep,name=member_ids,proto3" json:"member_ids,omitempty"` +} + +func (x *SetGroupMembersRequest) Reset() { + *x = SetGroupMembersRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_group_service_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetGroupMembersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetGroupMembersRequest) ProtoMessage() {} + +func (x *SetGroupMembersRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_group_service_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetGroupMembersRequest.ProtoReflect.Descriptor instead. +func (*SetGroupMembersRequest) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_group_service_proto_rawDescGZIP(), []int{12} +} + +func (x *SetGroupMembersRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *SetGroupMembersRequest) GetVersion() *wrappers.UInt32Value { + if x != nil { + return x.Version + } + return nil +} + +func (x *SetGroupMembersRequest) GetMemberIds() []string { + if x != nil { + return x.MemberIds + } + return nil +} + +type SetGroupMembersResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item *groups.Group `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *SetGroupMembersResponse) Reset() { + *x = SetGroupMembersResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_group_service_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetGroupMembersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetGroupMembersResponse) ProtoMessage() {} + +func (x *SetGroupMembersResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_group_service_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetGroupMembersResponse.ProtoReflect.Descriptor instead. +func (*SetGroupMembersResponse) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_group_service_proto_rawDescGZIP(), []int{13} +} + +func (x *SetGroupMembersResponse) GetItem() *groups.Group { + if x != nil { + return x.Item + } + return nil +} + +type RemoveGroupMembersRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // The version ensures the group hasn't changed since it was last retrieved and if + // it has the request will fail. + Version *wrappers.UInt32Value `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` + MemberIds []string `protobuf:"bytes,3,rep,name=member_ids,proto3" json:"member_ids,omitempty"` +} + +func (x *RemoveGroupMembersRequest) Reset() { + *x = RemoveGroupMembersRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_group_service_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveGroupMembersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveGroupMembersRequest) ProtoMessage() {} + +func (x *RemoveGroupMembersRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_group_service_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveGroupMembersRequest.ProtoReflect.Descriptor instead. +func (*RemoveGroupMembersRequest) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_group_service_proto_rawDescGZIP(), []int{14} +} + +func (x *RemoveGroupMembersRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *RemoveGroupMembersRequest) GetVersion() *wrappers.UInt32Value { + if x != nil { + return x.Version + } + return nil +} + +func (x *RemoveGroupMembersRequest) GetMemberIds() []string { + if x != nil { + return x.MemberIds + } + return nil +} + +type RemoveGroupMembersResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item *groups.Group `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *RemoveGroupMembersResponse) Reset() { + *x = RemoveGroupMembersResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_group_service_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveGroupMembersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveGroupMembersResponse) ProtoMessage() {} + +func (x *RemoveGroupMembersResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_group_service_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveGroupMembersResponse.ProtoReflect.Descriptor instead. +func (*RemoveGroupMembersResponse) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_group_service_proto_rawDescGZIP(), []int{15} +} + +func (x *RemoveGroupMembersResponse) GetItem() *groups.Group { + if x != nil { + return x.Item + } + return nil +} + var File_controller_api_services_v1_group_service_proto protoreflect.FileDescriptor var file_controller_api_services_v1_group_service_proto_rawDesc = []byte{ @@ -550,7 +887,9 @@ var file_controller_api_services_v1_group_service_proto_rawDesc = []byte{ 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, - 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, + 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, @@ -606,67 +945,156 @@ var file_controller_api_services_v1_group_service_proto_rawDesc = []byte{ 0x22, 0x2f, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, - 0x64, 0x32, 0xe5, 0x06, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x12, 0xa5, 0x01, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, - 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, + 0x64, 0x22, 0x80, 0x01, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x69, + 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x73, 0x22, 0x58, 0x0a, 0x17, 0x41, 0x64, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x3d, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x80, + 0x01, 0x0a, 0x16, 0x53, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, + 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x73, 0x22, 0x58, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x04, + 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x83, 0x01, 0x0a, 0x19, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x49, 0x6e, + 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x73, 0x22, 0x5b, 0x0a, 0x1a, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x3d, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x32, 0xda, + 0x0c, 0x0a, 0x0c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0xa5, 0x01, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3e, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x20, 0x12, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, - 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, - 0x65, 0x6d, 0x92, 0x41, 0x15, 0x12, 0x13, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, - 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x9d, 0x01, 0x0a, 0x0a, 0x4c, - 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, - 0x12, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x73, 0x92, 0x41, 0x12, 0x12, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, - 0x61, 0x6c, 0x6c, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0xb2, 0x01, 0x0a, 0x0b, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x42, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x21, 0x22, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, - 0x2a, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, - 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x18, 0x12, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, - 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, - 0xb0, 0x01, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x12, + 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, + 0x41, 0x15, 0x12, 0x13, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, + 0x65, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x9d, 0x01, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, + 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x73, 0x92, 0x41, 0x12, 0x12, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6c, 0x6c, + 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0xb2, 0x01, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x42, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, + 0x22, 0x13, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x73, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, + 0x6d, 0x92, 0x41, 0x18, 0x12, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, + 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0xb0, 0x01, 0x0a, + 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x2e, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x40, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x32, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, + 0x73, 0x2f, 0x2a, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, + 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x11, 0x12, 0x0f, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, + 0xa4, 0x01, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x40, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x32, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x34, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x2a, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x7b, 0x69, - 0x64, 0x7d, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, - 0x11, 0x12, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x12, 0xa4, 0x01, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x34, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x2a, 0x18, 0x2f, 0x76, 0x31, + 0x64, 0x7d, 0x92, 0x41, 0x11, 0x12, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x20, 0x61, + 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0xd6, 0x01, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x5a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x22, 0x24, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, - 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x92, 0x41, 0x11, 0x12, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x73, 0x20, 0x61, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x4f, 0x5a, 0x4d, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, - 0x70, 0x2f, 0x77, 0x61, 0x74, 0x63, 0x68, 0x74, 0x6f, 0x77, 0x65, 0x72, 0x2f, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x64, 0x64, 0x2d, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x22, 0x12, 0x20, 0x41, + 0x64, 0x64, 0x73, 0x20, 0x55, 0x73, 0x65, 0x72, 0x73, 0x20, 0x61, 0x73, 0x20, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, + 0xa9, 0x02, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xac, 0x01, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x22, 0x24, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, + 0x73, 0x2f, 0x2a, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, + 0x73, 0x65, 0x74, 0x2d, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, + 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x74, 0x12, 0x72, 0x53, 0x65, 0x74, 0x20, 0x61, 0x20, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x27, 0x73, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x20, 0x74, + 0x6f, 0x20, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x69, + 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x69, + 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2c, 0x20, 0x72, + 0x65, 0x6d, 0x6f, 0x76, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x6d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x74, + 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2e, 0x12, 0xed, 0x01, 0x0a, 0x12, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x12, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x68, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x22, 0x27, 0x2f, 0x76, 0x31, 0x2f, 0x73, + 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x2a, 0x2f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2f, 0x7b, + 0x69, 0x64, 0x7d, 0x3a, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x2d, 0x6d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x73, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x2d, 0x12, 0x2b, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x20, 0x66, 0x72, + 0x6f, 0x6d, 0x20, 0x61, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x42, 0x4f, 0x5a, 0x4d, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2f, 0x77, 0x61, 0x74, 0x63, 0x68, 0x74, 0x6f, 0x77, 0x65, 0x72, 0x2f, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -681,44 +1109,63 @@ func file_controller_api_services_v1_group_service_proto_rawDescGZIP() []byte { return file_controller_api_services_v1_group_service_proto_rawDescData } -var file_controller_api_services_v1_group_service_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_controller_api_services_v1_group_service_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_controller_api_services_v1_group_service_proto_goTypes = []interface{}{ - (*GetGroupRequest)(nil), // 0: controller.api.services.v1.GetGroupRequest - (*GetGroupResponse)(nil), // 1: controller.api.services.v1.GetGroupResponse - (*ListGroupsRequest)(nil), // 2: controller.api.services.v1.ListGroupsRequest - (*ListGroupsResponse)(nil), // 3: controller.api.services.v1.ListGroupsResponse - (*CreateGroupRequest)(nil), // 4: controller.api.services.v1.CreateGroupRequest - (*CreateGroupResponse)(nil), // 5: controller.api.services.v1.CreateGroupResponse - (*UpdateGroupRequest)(nil), // 6: controller.api.services.v1.UpdateGroupRequest - (*UpdateGroupResponse)(nil), // 7: controller.api.services.v1.UpdateGroupResponse - (*DeleteGroupRequest)(nil), // 8: controller.api.services.v1.DeleteGroupRequest - (*DeleteGroupResponse)(nil), // 9: controller.api.services.v1.DeleteGroupResponse - (*groups.Group)(nil), // 10: controller.api.resources.groups.v1.Group - (*field_mask.FieldMask)(nil), // 11: google.protobuf.FieldMask + (*GetGroupRequest)(nil), // 0: controller.api.services.v1.GetGroupRequest + (*GetGroupResponse)(nil), // 1: controller.api.services.v1.GetGroupResponse + (*ListGroupsRequest)(nil), // 2: controller.api.services.v1.ListGroupsRequest + (*ListGroupsResponse)(nil), // 3: controller.api.services.v1.ListGroupsResponse + (*CreateGroupRequest)(nil), // 4: controller.api.services.v1.CreateGroupRequest + (*CreateGroupResponse)(nil), // 5: controller.api.services.v1.CreateGroupResponse + (*UpdateGroupRequest)(nil), // 6: controller.api.services.v1.UpdateGroupRequest + (*UpdateGroupResponse)(nil), // 7: controller.api.services.v1.UpdateGroupResponse + (*DeleteGroupRequest)(nil), // 8: controller.api.services.v1.DeleteGroupRequest + (*DeleteGroupResponse)(nil), // 9: controller.api.services.v1.DeleteGroupResponse + (*AddGroupMembersRequest)(nil), // 10: controller.api.services.v1.AddGroupMembersRequest + (*AddGroupMembersResponse)(nil), // 11: controller.api.services.v1.AddGroupMembersResponse + (*SetGroupMembersRequest)(nil), // 12: controller.api.services.v1.SetGroupMembersRequest + (*SetGroupMembersResponse)(nil), // 13: controller.api.services.v1.SetGroupMembersResponse + (*RemoveGroupMembersRequest)(nil), // 14: controller.api.services.v1.RemoveGroupMembersRequest + (*RemoveGroupMembersResponse)(nil), // 15: controller.api.services.v1.RemoveGroupMembersResponse + (*groups.Group)(nil), // 16: controller.api.resources.groups.v1.Group + (*field_mask.FieldMask)(nil), // 17: google.protobuf.FieldMask + (*wrappers.UInt32Value)(nil), // 18: google.protobuf.UInt32Value } var file_controller_api_services_v1_group_service_proto_depIdxs = []int32{ - 10, // 0: controller.api.services.v1.GetGroupResponse.item:type_name -> controller.api.resources.groups.v1.Group - 10, // 1: controller.api.services.v1.ListGroupsResponse.items:type_name -> controller.api.resources.groups.v1.Group - 10, // 2: controller.api.services.v1.CreateGroupRequest.item:type_name -> controller.api.resources.groups.v1.Group - 10, // 3: controller.api.services.v1.CreateGroupResponse.item:type_name -> controller.api.resources.groups.v1.Group - 10, // 4: controller.api.services.v1.UpdateGroupRequest.item:type_name -> controller.api.resources.groups.v1.Group - 11, // 5: controller.api.services.v1.UpdateGroupRequest.update_mask:type_name -> google.protobuf.FieldMask - 10, // 6: controller.api.services.v1.UpdateGroupResponse.item:type_name -> controller.api.resources.groups.v1.Group - 0, // 7: controller.api.services.v1.GroupService.GetGroup:input_type -> controller.api.services.v1.GetGroupRequest - 2, // 8: controller.api.services.v1.GroupService.ListGroups:input_type -> controller.api.services.v1.ListGroupsRequest - 4, // 9: controller.api.services.v1.GroupService.CreateGroup:input_type -> controller.api.services.v1.CreateGroupRequest - 6, // 10: controller.api.services.v1.GroupService.UpdateGroup:input_type -> controller.api.services.v1.UpdateGroupRequest - 8, // 11: controller.api.services.v1.GroupService.DeleteGroup:input_type -> controller.api.services.v1.DeleteGroupRequest - 1, // 12: controller.api.services.v1.GroupService.GetGroup:output_type -> controller.api.services.v1.GetGroupResponse - 3, // 13: controller.api.services.v1.GroupService.ListGroups:output_type -> controller.api.services.v1.ListGroupsResponse - 5, // 14: controller.api.services.v1.GroupService.CreateGroup:output_type -> controller.api.services.v1.CreateGroupResponse - 7, // 15: controller.api.services.v1.GroupService.UpdateGroup:output_type -> controller.api.services.v1.UpdateGroupResponse - 9, // 16: controller.api.services.v1.GroupService.DeleteGroup:output_type -> controller.api.services.v1.DeleteGroupResponse - 12, // [12:17] is the sub-list for method output_type - 7, // [7:12] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 16, // 0: controller.api.services.v1.GetGroupResponse.item:type_name -> controller.api.resources.groups.v1.Group + 16, // 1: controller.api.services.v1.ListGroupsResponse.items:type_name -> controller.api.resources.groups.v1.Group + 16, // 2: controller.api.services.v1.CreateGroupRequest.item:type_name -> controller.api.resources.groups.v1.Group + 16, // 3: controller.api.services.v1.CreateGroupResponse.item:type_name -> controller.api.resources.groups.v1.Group + 16, // 4: controller.api.services.v1.UpdateGroupRequest.item:type_name -> controller.api.resources.groups.v1.Group + 17, // 5: controller.api.services.v1.UpdateGroupRequest.update_mask:type_name -> google.protobuf.FieldMask + 16, // 6: controller.api.services.v1.UpdateGroupResponse.item:type_name -> controller.api.resources.groups.v1.Group + 18, // 7: controller.api.services.v1.AddGroupMembersRequest.version:type_name -> google.protobuf.UInt32Value + 16, // 8: controller.api.services.v1.AddGroupMembersResponse.item:type_name -> controller.api.resources.groups.v1.Group + 18, // 9: controller.api.services.v1.SetGroupMembersRequest.version:type_name -> google.protobuf.UInt32Value + 16, // 10: controller.api.services.v1.SetGroupMembersResponse.item:type_name -> controller.api.resources.groups.v1.Group + 18, // 11: controller.api.services.v1.RemoveGroupMembersRequest.version:type_name -> google.protobuf.UInt32Value + 16, // 12: controller.api.services.v1.RemoveGroupMembersResponse.item:type_name -> controller.api.resources.groups.v1.Group + 0, // 13: controller.api.services.v1.GroupService.GetGroup:input_type -> controller.api.services.v1.GetGroupRequest + 2, // 14: controller.api.services.v1.GroupService.ListGroups:input_type -> controller.api.services.v1.ListGroupsRequest + 4, // 15: controller.api.services.v1.GroupService.CreateGroup:input_type -> controller.api.services.v1.CreateGroupRequest + 6, // 16: controller.api.services.v1.GroupService.UpdateGroup:input_type -> controller.api.services.v1.UpdateGroupRequest + 8, // 17: controller.api.services.v1.GroupService.DeleteGroup:input_type -> controller.api.services.v1.DeleteGroupRequest + 10, // 18: controller.api.services.v1.GroupService.AddGroupMembers:input_type -> controller.api.services.v1.AddGroupMembersRequest + 12, // 19: controller.api.services.v1.GroupService.SetGroupMembers:input_type -> controller.api.services.v1.SetGroupMembersRequest + 14, // 20: controller.api.services.v1.GroupService.RemoveGroupMembers:input_type -> controller.api.services.v1.RemoveGroupMembersRequest + 1, // 21: controller.api.services.v1.GroupService.GetGroup:output_type -> controller.api.services.v1.GetGroupResponse + 3, // 22: controller.api.services.v1.GroupService.ListGroups:output_type -> controller.api.services.v1.ListGroupsResponse + 5, // 23: controller.api.services.v1.GroupService.CreateGroup:output_type -> controller.api.services.v1.CreateGroupResponse + 7, // 24: controller.api.services.v1.GroupService.UpdateGroup:output_type -> controller.api.services.v1.UpdateGroupResponse + 9, // 25: controller.api.services.v1.GroupService.DeleteGroup:output_type -> controller.api.services.v1.DeleteGroupResponse + 11, // 26: controller.api.services.v1.GroupService.AddGroupMembers:output_type -> controller.api.services.v1.AddGroupMembersResponse + 13, // 27: controller.api.services.v1.GroupService.SetGroupMembers:output_type -> controller.api.services.v1.SetGroupMembersResponse + 15, // 28: controller.api.services.v1.GroupService.RemoveGroupMembers:output_type -> controller.api.services.v1.RemoveGroupMembersResponse + 21, // [21:29] is the sub-list for method output_type + 13, // [13:21] is the sub-list for method input_type + 13, // [13:13] is the sub-list for extension type_name + 13, // [13:13] is the sub-list for extension extendee + 0, // [0:13] is the sub-list for field type_name } func init() { file_controller_api_services_v1_group_service_proto_init() } @@ -847,6 +1294,78 @@ func file_controller_api_services_v1_group_service_proto_init() { return nil } } + file_controller_api_services_v1_group_service_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddGroupMembersRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_group_service_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddGroupMembersResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_group_service_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetGroupMembersRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_group_service_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetGroupMembersResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_group_service_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RemoveGroupMembersRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_group_service_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RemoveGroupMembersResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -854,7 +1373,7 @@ func file_controller_api_services_v1_group_service_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_controller_api_services_v1_group_service_proto_rawDesc, NumEnums: 0, - NumMessages: 10, + NumMessages: 16, NumExtensions: 0, NumServices: 1, }, @@ -911,6 +1430,22 @@ type GroupServiceClient interface { // response itself specifies if the resource existed before the DeleteGroup // request was received. DeleteGroup(ctx context.Context, in *DeleteGroupRequest, opts ...grpc.CallOption) (*DeleteGroupResponse, error) + // AddGroupMembers adds users as members to a group. The provided + // request must include the scope id and the group id which the users + // will be set to. If the any of the ids are missing, malformed or references a non + // existing resource, an error is returned. + AddGroupMembers(ctx context.Context, in *AddGroupMembersRequest, opts ...grpc.CallOption) (*AddGroupMembersResponse, error) + // SetGroupMembers sets the group's members. Any existing members on + // the group are deleted if they are not included in this request. The provided + // request must include the scope id and the group id which the users + // will be set to. If the any of the ids are missing, malformed or references a non + // existing resource, an error is returned. + SetGroupMembers(ctx context.Context, in *SetGroupMembersRequest, opts ...grpc.CallOption) (*SetGroupMembersResponse, error) + // RemoveGroupMembers removes members from the specified group. + // The provided request must include the scope id and the group id which the users + // will be set to. If the any of the ids are missing, malformed or references a non + // existing resource, an error is returned. + RemoveGroupMembers(ctx context.Context, in *RemoveGroupMembersRequest, opts ...grpc.CallOption) (*RemoveGroupMembersResponse, error) } type groupServiceClient struct { @@ -966,6 +1501,33 @@ func (c *groupServiceClient) DeleteGroup(ctx context.Context, in *DeleteGroupReq return out, nil } +func (c *groupServiceClient) AddGroupMembers(ctx context.Context, in *AddGroupMembersRequest, opts ...grpc.CallOption) (*AddGroupMembersResponse, error) { + out := new(AddGroupMembersResponse) + err := c.cc.Invoke(ctx, "/controller.api.services.v1.GroupService/AddGroupMembers", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupServiceClient) SetGroupMembers(ctx context.Context, in *SetGroupMembersRequest, opts ...grpc.CallOption) (*SetGroupMembersResponse, error) { + out := new(SetGroupMembersResponse) + err := c.cc.Invoke(ctx, "/controller.api.services.v1.GroupService/SetGroupMembers", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *groupServiceClient) RemoveGroupMembers(ctx context.Context, in *RemoveGroupMembersRequest, opts ...grpc.CallOption) (*RemoveGroupMembersResponse, error) { + out := new(RemoveGroupMembersResponse) + err := c.cc.Invoke(ctx, "/controller.api.services.v1.GroupService/RemoveGroupMembers", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // GroupServiceServer is the server API for GroupService service. type GroupServiceServer interface { // GetGroup returns a stored Group if present. The provided request must @@ -999,6 +1561,22 @@ type GroupServiceServer interface { // response itself specifies if the resource existed before the DeleteGroup // request was received. DeleteGroup(context.Context, *DeleteGroupRequest) (*DeleteGroupResponse, error) + // AddGroupMembers adds users as members to a group. The provided + // request must include the scope id and the group id which the users + // will be set to. If the any of the ids are missing, malformed or references a non + // existing resource, an error is returned. + AddGroupMembers(context.Context, *AddGroupMembersRequest) (*AddGroupMembersResponse, error) + // SetGroupMembers sets the group's members. Any existing members on + // the group are deleted if they are not included in this request. The provided + // request must include the scope id and the group id which the users + // will be set to. If the any of the ids are missing, malformed or references a non + // existing resource, an error is returned. + SetGroupMembers(context.Context, *SetGroupMembersRequest) (*SetGroupMembersResponse, error) + // RemoveGroupMembers removes members from the specified group. + // The provided request must include the scope id and the group id which the users + // will be set to. If the any of the ids are missing, malformed or references a non + // existing resource, an error is returned. + RemoveGroupMembers(context.Context, *RemoveGroupMembersRequest) (*RemoveGroupMembersResponse, error) } // UnimplementedGroupServiceServer can be embedded to have forward compatible implementations. @@ -1020,6 +1598,15 @@ func (*UnimplementedGroupServiceServer) UpdateGroup(context.Context, *UpdateGrou func (*UnimplementedGroupServiceServer) DeleteGroup(context.Context, *DeleteGroupRequest) (*DeleteGroupResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteGroup not implemented") } +func (*UnimplementedGroupServiceServer) AddGroupMembers(context.Context, *AddGroupMembersRequest) (*AddGroupMembersResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddGroupMembers not implemented") +} +func (*UnimplementedGroupServiceServer) SetGroupMembers(context.Context, *SetGroupMembersRequest) (*SetGroupMembersResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetGroupMembers not implemented") +} +func (*UnimplementedGroupServiceServer) RemoveGroupMembers(context.Context, *RemoveGroupMembersRequest) (*RemoveGroupMembersResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RemoveGroupMembers not implemented") +} func RegisterGroupServiceServer(s *grpc.Server, srv GroupServiceServer) { s.RegisterService(&_GroupService_serviceDesc, srv) @@ -1115,6 +1702,60 @@ func _GroupService_DeleteGroup_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _GroupService_AddGroupMembers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddGroupMembersRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServiceServer).AddGroupMembers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/controller.api.services.v1.GroupService/AddGroupMembers", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServiceServer).AddGroupMembers(ctx, req.(*AddGroupMembersRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _GroupService_SetGroupMembers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetGroupMembersRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServiceServer).SetGroupMembers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/controller.api.services.v1.GroupService/SetGroupMembers", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServiceServer).SetGroupMembers(ctx, req.(*SetGroupMembersRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _GroupService_RemoveGroupMembers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveGroupMembersRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GroupServiceServer).RemoveGroupMembers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/controller.api.services.v1.GroupService/RemoveGroupMembers", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GroupServiceServer).RemoveGroupMembers(ctx, req.(*RemoveGroupMembersRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _GroupService_serviceDesc = grpc.ServiceDesc{ ServiceName: "controller.api.services.v1.GroupService", HandlerType: (*GroupServiceServer)(nil), @@ -1139,6 +1780,18 @@ var _GroupService_serviceDesc = grpc.ServiceDesc{ MethodName: "DeleteGroup", Handler: _GroupService_DeleteGroup_Handler, }, + { + MethodName: "AddGroupMembers", + Handler: _GroupService_AddGroupMembers_Handler, + }, + { + MethodName: "SetGroupMembers", + Handler: _GroupService_SetGroupMembers_Handler, + }, + { + MethodName: "RemoveGroupMembers", + Handler: _GroupService_RemoveGroupMembers_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "controller/api/services/v1/group_service.proto", diff --git a/internal/gen/controller/api/services/group_service.pb.gw.go b/internal/gen/controller/api/services/group_service.pb.gw.go index b0eb7106f..25f3f67c4 100644 --- a/internal/gen/controller/api/services/group_service.pb.gw.go +++ b/internal/gen/controller/api/services/group_service.pb.gw.go @@ -331,6 +331,216 @@ func local_request_GroupService_DeleteGroup_0(ctx context.Context, marshaler run } +func request_GroupService_AddGroupMembers_0(ctx context.Context, marshaler runtime.Marshaler, client GroupServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AddGroupMembersRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + msg, err := client.AddGroupMembers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_GroupService_AddGroupMembers_0(ctx context.Context, marshaler runtime.Marshaler, server GroupServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AddGroupMembersRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + msg, err := server.AddGroupMembers(ctx, &protoReq) + return msg, metadata, err + +} + +func request_GroupService_SetGroupMembers_0(ctx context.Context, marshaler runtime.Marshaler, client GroupServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SetGroupMembersRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + msg, err := client.SetGroupMembers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_GroupService_SetGroupMembers_0(ctx context.Context, marshaler runtime.Marshaler, server GroupServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SetGroupMembersRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + msg, err := server.SetGroupMembers(ctx, &protoReq) + return msg, metadata, err + +} + +func request_GroupService_RemoveGroupMembers_0(ctx context.Context, marshaler runtime.Marshaler, client GroupServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RemoveGroupMembersRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + msg, err := client.RemoveGroupMembers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_GroupService_RemoveGroupMembers_0(ctx context.Context, marshaler runtime.Marshaler, server GroupServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RemoveGroupMembersRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + msg, err := server.RemoveGroupMembers(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterGroupServiceHandlerServer registers the http handlers for service GroupService to "mux". // UnaryRPC :call GroupServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -436,6 +646,66 @@ func RegisterGroupServiceHandlerServer(ctx context.Context, mux *runtime.ServeMu }) + mux.Handle("POST", pattern_GroupService_AddGroupMembers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_GroupService_AddGroupMembers_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_GroupService_AddGroupMembers_0(ctx, mux, outboundMarshaler, w, req, response_GroupService_AddGroupMembers_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_GroupService_SetGroupMembers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_GroupService_SetGroupMembers_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_GroupService_SetGroupMembers_0(ctx, mux, outboundMarshaler, w, req, response_GroupService_SetGroupMembers_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_GroupService_RemoveGroupMembers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_GroupService_RemoveGroupMembers_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_GroupService_RemoveGroupMembers_0(ctx, mux, outboundMarshaler, w, req, response_GroupService_RemoveGroupMembers_0{resp}, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -577,6 +847,66 @@ func RegisterGroupServiceHandlerClient(ctx context.Context, mux *runtime.ServeMu }) + mux.Handle("POST", pattern_GroupService_AddGroupMembers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_GroupService_AddGroupMembers_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_GroupService_AddGroupMembers_0(ctx, mux, outboundMarshaler, w, req, response_GroupService_AddGroupMembers_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_GroupService_SetGroupMembers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_GroupService_SetGroupMembers_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_GroupService_SetGroupMembers_0(ctx, mux, outboundMarshaler, w, req, response_GroupService_SetGroupMembers_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_GroupService_RemoveGroupMembers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_GroupService_RemoveGroupMembers_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_GroupService_RemoveGroupMembers_0(ctx, mux, outboundMarshaler, w, req, response_GroupService_RemoveGroupMembers_0{resp}, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -607,6 +937,33 @@ func (m response_GroupService_UpdateGroup_0) XXX_ResponseBody() interface{} { return response.Item } +type response_GroupService_AddGroupMembers_0 struct { + proto.Message +} + +func (m response_GroupService_AddGroupMembers_0) XXX_ResponseBody() interface{} { + response := m.Message.(*AddGroupMembersResponse) + return response.Item +} + +type response_GroupService_SetGroupMembers_0 struct { + proto.Message +} + +func (m response_GroupService_SetGroupMembers_0) XXX_ResponseBody() interface{} { + response := m.Message.(*SetGroupMembersResponse) + return response.Item +} + +type response_GroupService_RemoveGroupMembers_0 struct { + proto.Message +} + +func (m response_GroupService_RemoveGroupMembers_0) XXX_ResponseBody() interface{} { + response := m.Message.(*RemoveGroupMembersResponse) + return response.Item +} + var ( pattern_GroupService_GetGroup_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "scopes", "groups", "id"}, "", runtime.AssumeColonVerbOpt(true))) @@ -617,6 +974,12 @@ var ( pattern_GroupService_UpdateGroup_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "scopes", "groups", "id"}, "", runtime.AssumeColonVerbOpt(true))) pattern_GroupService_DeleteGroup_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "scopes", "groups", "id"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_GroupService_AddGroupMembers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "scopes", "groups", "id"}, "add-members", runtime.AssumeColonVerbOpt(true))) + + pattern_GroupService_SetGroupMembers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "scopes", "groups", "id"}, "set-members", runtime.AssumeColonVerbOpt(true))) + + pattern_GroupService_RemoveGroupMembers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "scopes", "groups", "id"}, "remove-members", runtime.AssumeColonVerbOpt(true))) ) var ( @@ -629,4 +992,10 @@ var ( forward_GroupService_UpdateGroup_0 = runtime.ForwardResponseMessage forward_GroupService_DeleteGroup_0 = runtime.ForwardResponseMessage + + forward_GroupService_AddGroupMembers_0 = runtime.ForwardResponseMessage + + forward_GroupService_SetGroupMembers_0 = runtime.ForwardResponseMessage + + forward_GroupService_RemoveGroupMembers_0 = runtime.ForwardResponseMessage ) diff --git a/internal/iam/group_member.go b/internal/iam/group_member.go index 7ffe1a4f3..8c523a9d0 100644 --- a/internal/iam/group_member.go +++ b/internal/iam/group_member.go @@ -9,6 +9,21 @@ import ( "google.golang.org/protobuf/proto" ) +// MemberType defines the possible membership types for groups. +type MemberType uint32 + +const ( + UnknownMemberType MemberType = 0 + UserMemberType MemberType = 1 +) + +func (m MemberType) String() string { + return [...]string{ + "unknown", + "user", + }[m] +} + const ( groupMemberViewDefaultTableName = "iam_group_member" groupMemberUserDefaultTable = "iam_group_member_user" diff --git a/internal/iam/repository_group.go b/internal/iam/repository_group.go index f77422cd0..aae2d02d4 100644 --- a/internal/iam/repository_group.go +++ b/internal/iam/repository_group.go @@ -45,22 +45,22 @@ func (r *Repository) CreateGroup(ctx context.Context, group *Group, opt ...Optio // be updated. Fields will be set to NULL if the field is a zero value and // included in fieldMask. Name and Description are the only updatable fields, // If no updatable fields are included in the fieldMaskPaths, then an error is returned. -func (r *Repository) UpdateGroup(ctx context.Context, group *Group, fieldMaskPaths []string, opt ...Option) (*Group, int, error) { +func (r *Repository) UpdateGroup(ctx context.Context, group *Group, fieldMaskPaths []string, opt ...Option) (*Group, []*GroupMember, int, error) { if group == nil { - return nil, db.NoRowsAffected, fmt.Errorf("update group: missing group %w", db.ErrNilParameter) + return nil, nil, db.NoRowsAffected, fmt.Errorf("update group: missing group %w", db.ErrNilParameter) } if group.Group == nil { - return nil, db.NoRowsAffected, fmt.Errorf("update group: missing group store %w", db.ErrNilParameter) + return nil, nil, db.NoRowsAffected, fmt.Errorf("update group: missing group store %w", db.ErrNilParameter) } if group.PublicId == "" { - return nil, db.NoRowsAffected, fmt.Errorf("update group: missing group public id %w", db.ErrInvalidParameter) + return nil, nil, db.NoRowsAffected, fmt.Errorf("update group: missing group public id %w", db.ErrInvalidParameter) } for _, f := range fieldMaskPaths { switch { case strings.EqualFold("name", f): case strings.EqualFold("description", f): default: - return nil, db.NoRowsAffected, fmt.Errorf("update group: field: %s: %w", f, db.ErrInvalidFieldMask) + return nil, nil, db.NoRowsAffected, fmt.Errorf("update group: field: %s: %w", f, db.ErrInvalidFieldMask) } } var dbMask, nullFields []string @@ -72,31 +72,74 @@ func (r *Repository) UpdateGroup(ctx context.Context, group *Group, fieldMaskPat fieldMaskPaths, ) if len(dbMask) == 0 && len(nullFields) == 0 { - return nil, db.NoRowsAffected, fmt.Errorf("update group: %w", db.ErrEmptyFieldMask) + return nil, nil, db.NoRowsAffected, fmt.Errorf("update group: %w", db.ErrEmptyFieldMask) } - g := group.Clone().(*Group) - resource, rowsUpdated, err := r.update(ctx, g, dbMask, nullFields) + var resource Resource + var rowsUpdated int + var members []*GroupMember + _, err := r.writer.DoTx( + ctx, + db.StdRetryCnt, + db.ExpBackoff{}, + func(read db.Reader, w db.Writer) error { + var err error + g := group.Clone().(*Group) + resource, rowsUpdated, err = r.update(ctx, g, dbMask, nullFields) + if err != nil { + return err + } + repo, err := NewRepository(read, w, r.wrapper) + if err != nil { + return fmt.Errorf("update group: failed creating inner repo: %w for %s", err, group.PublicId) + } + members, err = repo.ListGroupMembers(ctx, group.PublicId) + if err != nil { + return fmt.Errorf("update group: listing group members: %w for %s", err, group.PublicId) + } + return nil + }, + ) if err != nil { if db.IsUniqueError(err) { - return nil, db.NoRowsAffected, fmt.Errorf("update group: group %s already exists in org %s: %w", group.Name, group.ScopeId, db.ErrNotUnique) + return nil, nil, db.NoRowsAffected, fmt.Errorf("update group: group %s already exists in org %s: %w", group.Name, group.ScopeId, db.ErrNotUnique) } - return nil, db.NoRowsAffected, fmt.Errorf("update group: %w for %s", err, group.PublicId) + return nil, nil, db.NoRowsAffected, fmt.Errorf("update group: %w for %s", err, group.PublicId) } - return resource.(*Group), rowsUpdated, err + return resource.(*Group), members, rowsUpdated, err } // LookupGroup will look up a group in the repository. If the group is not // found, it will return nil, nil. -func (r *Repository) LookupGroup(ctx context.Context, withPublicId string, opt ...Option) (*Group, error) { +func (r *Repository) LookupGroup(ctx context.Context, withPublicId string, opt ...Option) (*Group, []*GroupMember, error) { if withPublicId == "" { - return nil, fmt.Errorf("lookup group: missing public id %w", db.ErrNilParameter) + return nil, nil, fmt.Errorf("lookup group: missing public id %w", db.ErrNilParameter) } g := allocGroup() g.PublicId = withPublicId - if err := r.reader.LookupByPublicId(ctx, &g); err != nil { - return nil, fmt.Errorf("lookup group: failed %w for %s", err, withPublicId) + var members []*GroupMember + _, err := r.writer.DoTx( + ctx, + db.StdRetryCnt, + db.ExpBackoff{}, + func(read db.Reader, w db.Writer) error { + if err := read.LookupByPublicId(ctx, &g); err != nil { + return fmt.Errorf("lookup group: failed %w for %s", err, withPublicId) + } + repo, err := NewRepository(read, w, r.wrapper) + if err != nil { + return fmt.Errorf("lookup group: failed creating inner repo: %w for %s", err, withPublicId) + } + members, err = repo.ListGroupMembers(ctx, withPublicId) + if err != nil { + return fmt.Errorf("lookup group: listing group members: %w for %s", err, withPublicId) + } + return nil + }, + ) + if err != nil { + return nil, nil, fmt.Errorf("lookup group: failed %w for %s", err, withPublicId) } - return &g, nil + return &g, members, nil } // DeleteGroup will delete a group from the repository. @@ -184,7 +227,7 @@ func (r *Repository) AddGroupMembers(ctx context.Context, groupId string, groupV } updatedGroup := allocGroup() updatedGroup.PublicId = groupId - updatedGroup.Version = uint32(groupVersion) + 1 + updatedGroup.Version = groupVersion + 1 var groupOplogMsg oplog.Message rowsUpdated, err := w.Update(ctx, &updatedGroup, []string{"Version"}, nil, db.NewOplogMsg(&groupOplogMsg), db.WithVersion(&groupVersion)) if err != nil { @@ -271,7 +314,7 @@ func (r *Repository) DeleteGroupMembers(ctx context.Context, groupId string, gro } updatedGroup := allocGroup() updatedGroup.PublicId = groupId - updatedGroup.Version = uint32(groupVersion) + 1 + updatedGroup.Version = groupVersion + 1 var groupOplogMsg oplog.Message rowsUpdated, err := w.Update(ctx, &updatedGroup, []string{"Version"}, nil, db.NewOplogMsg(&groupOplogMsg), db.WithVersion(&groupVersion)) if err != nil { @@ -314,7 +357,7 @@ func (r *Repository) DeleteGroupMembers(ctx context.Context, groupId string, gro // and will return an error. func (r *Repository) SetGroupMembers(ctx context.Context, groupId string, groupVersion uint32, userIds []string, opt ...Option) ([]*GroupMember, int, error) { if groupId == "" { - return nil, db.NoRowsAffected, fmt.Errorf("set group members: missing role id: %w", db.ErrInvalidParameter) + return nil, db.NoRowsAffected, fmt.Errorf("set group members: missing group id: %w", db.ErrInvalidParameter) } if groupVersion == 0 { return nil, db.NoRowsAffected, fmt.Errorf("set group members: version cannot be zero: %w", db.ErrInvalidParameter) @@ -323,7 +366,7 @@ func (r *Repository) SetGroupMembers(ctx context.Context, groupId string, groupV group.PublicId = groupId scope, err := group.GetScope(ctx, r.reader) if err != nil { - return nil, db.NoRowsAffected, fmt.Errorf("set group members: unable to get role %s scope: %w", groupId, err) + return nil, db.NoRowsAffected, fmt.Errorf("set group members: unable to get members %s scope: %w", groupId, err) } // find existing members (since we're using groupVersion, we can safely do @@ -392,7 +435,7 @@ func (r *Repository) SetGroupMembers(ctx context.Context, groupId string, groupV } updatedGroup := allocGroup() updatedGroup.PublicId = groupId - updatedGroup.Version = uint32(groupVersion) + 1 + updatedGroup.Version = groupVersion + 1 var groupOplogMsg oplog.Message rowsUpdated, err := w.Update(ctx, &updatedGroup, []string{"Version"}, nil, db.NewOplogMsg(&groupOplogMsg), db.WithVersion(&groupVersion)) if err != nil { @@ -405,7 +448,7 @@ func (r *Repository) SetGroupMembers(ctx context.Context, groupId string, groupV userOplogMsgs := make([]*oplog.Message, 0, len(deleteMembers)) rowsDeleted, err := w.DeleteItems(ctx, deleteMembers, db.NewOplogMsgs(&userOplogMsgs)) if err != nil { - return fmt.Errorf("set group members: unable to delete user roles: %w", err) + return fmt.Errorf("set group members: unable to delete group member: %w", err) } if rowsDeleted != len(deleteMembers) { return fmt.Errorf("set group members: members deleted %d did not match request for %d", rowsDeleted, len(deleteMembers)) @@ -424,8 +467,8 @@ func (r *Repository) SetGroupMembers(ctx context.Context, groupId string, groupV metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_CREATE.String()) } - // we're done with all the principal writes, so let's write the - // role's update oplog message + // we're done with all the membership writes, so let's write the + // group's update oplog message if err := w.WriteOplogEntryWith(ctx, r.wrapper, groupTicket, metadata, msgs); err != nil { return fmt.Errorf("set group members: unable to write oplog for additions: %w", err) } diff --git a/internal/iam/repository_group_test.go b/internal/iam/repository_group_test.go index c78cb4151..8600d529c 100644 --- a/internal/iam/repository_group_test.go +++ b/internal/iam/repository_group_test.go @@ -161,7 +161,7 @@ func TestRepository_CreateGroup(t *testing.T) { assert.NotNil(grp.CreateTime) assert.NotNil(grp.UpdateTime) - foundGrp, err := repo.LookupGroup(context.Background(), grp.PublicId) + foundGrp, _, err := repo.LookupGroup(context.Background(), grp.PublicId) assert.NoError(err) assert.True(proto.Equal(foundGrp, grp)) @@ -400,7 +400,7 @@ func TestRepository_UpdateGroup(t *testing.T) { if tt.wantDup { g := TestGroup(t, conn, org.PublicId) g.Name = tt.args.name - _, _, err := repo.UpdateGroup(context.Background(), g, tt.args.fieldMaskPaths, tt.args.opt...) + _, _, _, err := repo.UpdateGroup(context.Background(), g, tt.args.fieldMaskPaths, tt.args.opt...) assert.NoError(err) } @@ -426,7 +426,7 @@ func TestRepository_UpdateGroup(t *testing.T) { groupAfterUpdate = resource.(*Group) } } else { - groupAfterUpdate, updatedRows, err = repo.UpdateGroup(context.Background(), &updateGrp, tt.args.fieldMaskPaths, tt.args.opt...) + groupAfterUpdate, _, updatedRows, err = repo.UpdateGroup(context.Background(), &updateGrp, tt.args.fieldMaskPaths, tt.args.opt...) } if tt.wantErr { assert.Error(err) @@ -449,7 +449,7 @@ func TestRepository_UpdateGroup(t *testing.T) { default: assert.NotEqual(u.UpdateTime, groupAfterUpdate.UpdateTime) } - foundGrp, err := repo.LookupGroup(context.Background(), u.PublicId) + foundGrp, _, err := repo.LookupGroup(context.Background(), u.PublicId) assert.NoError(err) assert.True(proto.Equal(groupAfterUpdate, foundGrp)) dbassert := dbassert.New(t, rw) @@ -539,7 +539,7 @@ func TestRepository_DeleteGroup(t *testing.T) { } assert.NoError(err) assert.Equal(tt.wantRowsDeleted, deletedRows) - foundGroup, err := repo.LookupGroup(context.Background(), tt.args.group.PublicId) + foundGroup, _, err := repo.LookupGroup(context.Background(), tt.args.group.PublicId) assert.Error(err) assert.Nil(foundGroup) assert.True(errors.Is(err, db.ErrRecordNotFound)) diff --git a/internal/proto/local/controller/api/resources/groups/v1/group.proto b/internal/proto/local/controller/api/resources/groups/v1/group.proto index 97956bb10..d553d8a4e 100644 --- a/internal/proto/local/controller/api/resources/groups/v1/group.proto +++ b/internal/proto/local/controller/api/resources/groups/v1/group.proto @@ -9,6 +9,20 @@ import "google/protobuf/wrappers.proto"; import "controller/api/resources/scopes/v1/scope.proto"; import "controller/custom_options/v1/masks.proto"; +message Member { + // The ID of the member. + // Output only. + string id = 1; + + // The type of the member. + // Output only. + string type = 2; + + // The scope ID of the member. + // Output only. + string scope_id = 3 [json_name="scope_id"]; +} + // Group contains all fields related to a Group resource message Group { // The ID of the Project @@ -18,7 +32,7 @@ message Group { // Scope information for this resource // Output only. resources.scopes.v1.ScopeInfo scope = 2; - + // Optional name for identification purposes google.protobuf.StringValue name = 3 [(custom_options.v1.mask_mapping) = {this:"name" that: "name"}]; @@ -35,4 +49,17 @@ message Group { // Whether the resource is disabled google.protobuf.BoolValue disabled = 7; + + // The version can be used in subsiquent write requests to ensure this resource + // has not changed and to fail the write if it has. + // Output only. + uint32 version = 8; + + // Contains the list of member ids in this group. + // Output only. + repeated string member_ids = 9; + + // The members of this group. + // Output only. + repeated Member members = 10; } diff --git a/internal/proto/local/controller/api/services/v1/group_service.proto b/internal/proto/local/controller/api/services/v1/group_service.proto index c09b29a10..2f6503a04 100644 --- a/internal/proto/local/controller/api/services/v1/group_service.proto +++ b/internal/proto/local/controller/api/services/v1/group_service.proto @@ -7,6 +7,7 @@ option go_package = "github.com/hashicorp/watchtower/internal/gen/controller/api import "protoc-gen-swagger/options/annotations.proto"; import "google/api/annotations.proto"; import "google/protobuf/field_mask.proto"; +import "google/protobuf/wrappers.proto"; import "controller/api/resources/groups/v1/group.proto"; import "controller/api/resources/scopes/v1/scope.proto"; @@ -87,6 +88,52 @@ service GroupService { summary: "Deletes a Group" }; } + + // AddGroupMembers adds users as members to a group. The provided + // request must include the scope id and the group id which the users + // will be set to. If the any of the ids are missing, malformed or references a non + // existing resource, an error is returned. + rpc AddGroupMembers(AddGroupMembersRequest) returns (AddGroupMembersResponse) { + option (google.api.http) = { + post: "/v1/scopes/*/groups/{id}:add-members" + body: "*" + response_body: "item" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + summary: "Adds Users as members to a Group" + }; + } + + // SetGroupMembers sets the group's members. Any existing members on + // the group are deleted if they are not included in this request. The provided + // request must include the scope id and the group id which the users + // will be set to. If the any of the ids are missing, malformed or references a non + // existing resource, an error is returned. + rpc SetGroupMembers(SetGroupMembersRequest) returns (SetGroupMembersResponse) { + option (google.api.http) = { + post: "/v1/scopes/*/groups/{id}:set-members" + body: "*" + response_body: "item" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + summary: "Set a Group's members to exactly the list of provided in the request, removing any members that are not specified." + }; + } + + // RemoveGroupMembers removes members from the specified group. + // The provided request must include the scope id and the group id which the users + // will be set to. If the any of the ids are missing, malformed or references a non + // existing resource, an error is returned. + rpc RemoveGroupMembers(RemoveGroupMembersRequest) returns (RemoveGroupMembersResponse) { + option (google.api.http) = { + post: "/v1/scopes/*/groups/{id}:remove-members" + body: "*" + response_body: "item" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + summary: "Removes the specified members from a Group." + }; + } } message GetGroupRequest { @@ -132,3 +179,39 @@ message DeleteGroupRequest { message DeleteGroupResponse { bool existed = 1; } + +message AddGroupMembersRequest { + string id = 1; + // The version ensures the group hasn't changed since it was last retrieved and if + // it has the request will fail. + google.protobuf.UInt32Value version = 2; + repeated string member_ids = 3 [json_name="member_ids"]; +} + +message AddGroupMembersResponse { + resources.groups.v1.Group item = 1; +} + +message SetGroupMembersRequest { + string id = 1; + // The version ensures the group hasn't changed since it was last retrieved and if + // it has the request will fail. + google.protobuf.UInt32Value version = 2; + repeated string member_ids = 3 [json_name="member_ids"]; +} + +message SetGroupMembersResponse { + resources.groups.v1.Group item = 1; +} + +message RemoveGroupMembersRequest { + string id = 1; + // The version ensures the group hasn't changed since it was last retrieved and if + // it has the request will fail. + google.protobuf.UInt32Value version = 2; + repeated string member_ids = 3 [json_name="member_ids"]; +} + +message RemoveGroupMembersResponse { + resources.groups.v1.Group item = 1; +} diff --git a/internal/servers/controller/handler_test.go b/internal/servers/controller/handler_test.go index 2e0c289cc..34f4ca34d 100644 --- a/internal/servers/controller/handler_test.go +++ b/internal/servers/controller/handler_test.go @@ -1,103 +1,17 @@ package controller import ( - "context" "encoding/json" "fmt" "io/ioutil" "net/http" - "net/http/httptest" "strings" "testing" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/hashicorp/watchtower/internal/gen/controller/api/services" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestGrpcGatewayRouting(t *testing.T) { - ctx := context.Background() - // The unimplemented result indicates the grpc routing is happening successfully otherwise it would return NotFound. - routed := http.StatusNotImplemented - unrouted := http.StatusNotFound - - cases := []struct { - name string - setup func(mux *runtime.ServeMux) - url string - expectedResult int - }{ - { - name: "users", - setup: func(mux *runtime.ServeMux) { - require.NoError(t, services.RegisterUserServiceHandlerServer(ctx, mux, &services.UnimplementedUserServiceServer{})) - }, - url: "v1/scopes/someid/users", - expectedResult: routed, - }, - { - name: "roles", - setup: func(mux *runtime.ServeMux) { - require.NoError(t, services.RegisterRoleServiceHandlerServer(ctx, mux, &services.UnimplementedRoleServiceServer{})) - }, - url: "v1/scopes/someid/roles", - expectedResult: routed, - }, - { - name: "groups", - setup: func(mux *runtime.ServeMux) { - require.NoError(t, services.RegisterGroupServiceHandlerServer(ctx, mux, &services.UnimplementedGroupServiceServer{})) - }, - url: "v1/scopes/someid/groups", - expectedResult: routed, - }, - { - name: "not routed", - setup: func(mux *runtime.ServeMux) {}, - url: "v1/nothing", - expectedResult: unrouted, - }, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - mux := runtime.NewServeMux() - tc.setup(mux) - - // List request - req := httptest.NewRequest("GET", fmt.Sprintf("http://localhost/%s", tc.url), nil) - resp := httptest.NewRecorder() - mux.ServeHTTP(resp, req) - assert.Equal(t, tc.expectedResult, resp.Result().StatusCode, "Got response %v", resp) - - // Create request - req = httptest.NewRequest("POST", fmt.Sprintf("http://localhost/%s", tc.url), nil) - resp = httptest.NewRecorder() - mux.ServeHTTP(resp, req) - assert.Equal(t, tc.expectedResult, resp.Result().StatusCode, "Got response %v", resp) - - // Get request - req = httptest.NewRequest("GET", fmt.Sprintf("http://localhost/%s/somemadeupid", tc.url), nil) - resp = httptest.NewRecorder() - mux.ServeHTTP(resp, req) - assert.Equal(t, tc.expectedResult, resp.Result().StatusCode, "Got response %v", resp) - - // Update request - req = httptest.NewRequest("PATCH", fmt.Sprintf("http://localhost/%s/somemadeupid", tc.url), nil) - resp = httptest.NewRecorder() - mux.ServeHTTP(resp, req) - assert.Equal(t, tc.expectedResult, resp.Result().StatusCode, "Got response %v", resp) - - // Delete request - req = httptest.NewRequest("DELETE", fmt.Sprintf("http://localhost/%s/somemadeupid", tc.url), nil) - resp = httptest.NewRecorder() - mux.ServeHTTP(resp, req) - assert.Equal(t, tc.expectedResult, resp.Result().StatusCode, "Got response %v", resp) - }) - } -} - func TestAuthenticationHandler(t *testing.T) { c := NewTestController(t, &TestControllerOpts{DefaultOrgId: "o_1234567890"}) defer c.Shutdown() @@ -120,48 +34,63 @@ func TestAuthenticationHandler(t *testing.T) { assert.Truef(t, strings.HasPrefix(tok, pubId), "Token: %q, Id: %q", tok, pubId) } -func TestGrpcGatewayRouting_CustomActions(t *testing.T) { - ctx := context.Background() - // The unimplemented result indicates the grpc routing is happening successfully otherwise it would return NotFound. - routed := http.StatusNotImplemented +func TestHandleImplementedPaths(t *testing.T) { + c := NewTestController(t, &TestControllerOpts{ + DisableAuthorizationFailures: true, + }) + defer c.Shutdown() - cases := []struct { - name string - setup func(mux *runtime.ServeMux) - post_urls []string - }{ - { - name: "roles", - setup: func(mux *runtime.ServeMux) { - require.NoError(t, services.RegisterRoleServiceHandlerServer(ctx, mux, &services.UnimplementedRoleServiceServer{})) - }, - post_urls: []string{ - "v1/scopes/someid/roles/r_anotherid:add-principals", - "v1/scopes/someid/roles/r_anotherid:set-principals", - "v1/scopes/someid/roles/r_anotherid:remove-principals", - "v1/scopes/someid/roles/r_anotherid:add-principals", - "v1/scopes/someid/roles/r_anotherid:set-principals", - "v1/scopes/someid/roles/r_anotherid:remove-principals", - "v1/scopes/someid/roles/r_anotherid:add-grants", - "v1/scopes/someid/roles/r_anotherid:set-grants", - "v1/scopes/someid/roles/r_anotherid:remove-grants", - "v1/scopes/someid/roles/r_anotherid:add-grants", - "v1/scopes/someid/roles/r_anotherid:set-grants", - "v1/scopes/someid/roles/r_anotherid:remove-grants", - }, + for verb, paths := range map[string][]string{ + "GET": { + "v1/scopes/someid", + "v1/scopes/someid/users", + "v1/scopes/someid/users/someid", + "v1/scopes/someid/roles", + "v1/scopes/someid/roles/someid", + "v1/scopes/someid/groups", + "v1/scopes/someid/groups/someid", + "v1/scopes/someid/host-catalogs", + "v1/scopes/someid/host-catalogs/someid", }, - } + "POST": { + // Creation end points + "v1/scopes", + "v1/scopes/someid/users", + "v1/scopes/someid/roles", + "v1/scopes/someid/groups", - for _, tc := range cases { - for _, url := range tc.post_urls { - t.Run(tc.name+"_"+url, func(t *testing.T) { - mux := runtime.NewServeMux() - tc.setup(mux) - - req := httptest.NewRequest("POST", fmt.Sprintf("http://localhost/%s", url), nil) - resp := httptest.NewRecorder() - mux.ServeHTTP(resp, req) - assert.Equal(t, routed, resp.Result().StatusCode, "Got response %v", resp) + // custom methods + "v1/scopes/someid/roles/someid:add-principals", + "v1/scopes/someid/roles/someid:set-principals", + "v1/scopes/someid/roles/someid:remove-principals", + "v1/scopes/someid/roles/someid:add-grants", + "v1/scopes/someid/roles/someid:set-grants", + "v1/scopes/someid/roles/someid:remove-grants", + "v1/scopes/someid/groups/someid:add-members", + "v1/scopes/someid/groups/someid:set-members", + "v1/scopes/someid/groups/someid:remove-members", + }, + "DELETE": { + "v1/scopes/someid", + "v1/scopes/someid/users/someid", + "v1/scopes/someid/roles/someid", + "v1/scopes/someid/groups/someid", + }, + "PATCH": { + "v1/scopes/someid", + "v1/scopes/someid/users/someid", + "v1/scopes/someid/roles/someid", + "v1/scopes/someid/groups/someid", + }, + } { + for _, p := range paths { + t.Run(fmt.Sprintf("%s/%s", verb, p), func(t *testing.T) { + url := fmt.Sprintf("%s/%s", c.ApiAddrs()[0], p) + req, err := http.NewRequest(verb, url, nil) + require.NoError(t, err) + resp, err := http.DefaultClient.Do(req) + require.NoError(t, err) + assert.NotEqualf(t, resp.StatusCode, http.StatusNotFound, "Got response %v, wanted not 404", resp.StatusCode) }) } } diff --git a/internal/servers/controller/handlers/groups/group_service.go b/internal/servers/controller/handlers/groups/group_service.go index 99befabd5..3a74c0d68 100644 --- a/internal/servers/controller/handlers/groups/group_service.go +++ b/internal/servers/controller/handlers/groups/group_service.go @@ -132,22 +132,70 @@ func (s Service) DeleteGroup(ctx context.Context, req *pbs.DeleteGroupRequest) ( return &pbs.DeleteGroupResponse{Existed: existed}, nil } +// AddGroupMembers implements the interface pbs.GroupServiceServer. +func (s Service) AddGroupMembers(ctx context.Context, req *pbs.AddGroupMembersRequest) (*pbs.AddGroupMembersResponse, error) { + authResults := auth.Verify(ctx) + if !authResults.Valid { + return nil, handlers.ForbiddenError() + } + if err := validateAddGroupMembersRequest(req); err != nil { + return nil, err + } + g, err := s.addMembersInRepo(ctx, req.GetId(), req.GetMemberIds(), req.GetVersion().GetValue()) + if err != nil { + return nil, err + } + return &pbs.AddGroupMembersResponse{Item: g}, nil +} + +// SetGroupMembers implements the interface pbs.GroupServiceServer. +func (s Service) SetGroupMembers(ctx context.Context, req *pbs.SetGroupMembersRequest) (*pbs.SetGroupMembersResponse, error) { + authResults := auth.Verify(ctx) + if !authResults.Valid { + return nil, handlers.ForbiddenError() + } + if err := validateSetGroupMembersRequest(req); err != nil { + return nil, err + } + g, err := s.setMembersInRepo(ctx, req.GetId(), req.GetMemberIds(), req.GetVersion().GetValue()) + if err != nil { + return nil, err + } + return &pbs.SetGroupMembersResponse{Item: g}, nil +} + +// RemoveGroupMembers implements the interface pbs.GroupServiceServer. +func (s Service) RemoveGroupMembers(ctx context.Context, req *pbs.RemoveGroupMembersRequest) (*pbs.RemoveGroupMembersResponse, error) { + authResults := auth.Verify(ctx) + if !authResults.Valid { + return nil, handlers.ForbiddenError() + } + if err := validateRemoveGroupMembersRequest(req); err != nil { + return nil, err + } + g, err := s.removeMembersInRepo(ctx, req.GetId(), req.GetMemberIds(), req.GetVersion().GetValue()) + if err != nil { + return nil, err + } + return &pbs.RemoveGroupMembersResponse{Item: g}, nil +} + func (s Service) getFromRepo(ctx context.Context, id string) (*pb.Group, error) { repo, err := s.repoFn() if err != nil { return nil, err } - u, err := repo.LookupGroup(ctx, id) + g, m, err := repo.LookupGroup(ctx, id) if err != nil { if errors.Is(err, db.ErrRecordNotFound) { return nil, handlers.NotFoundErrorf("Group %q doesn't exist.", id) } return nil, err } - if u == nil { + if g == nil { return nil, handlers.NotFoundErrorf("Group %q doesn't exist.", id) } - return toProto(u), nil + return toProto(g, m), nil } func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.Group) (*pb.Group, error) { @@ -173,7 +221,7 @@ func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.Grou if out == nil { return nil, status.Error(codes.Internal, "Unable to create group but no error returned from repository.") } - return toProto(out), nil + return toProto(out, nil), nil } func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []string, item *pb.Group) (*pb.Group, error) { @@ -197,14 +245,14 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []st if err != nil { return nil, err } - out, rowsUpdated, err := repo.UpdateGroup(ctx, u, dbMask) + out, m, rowsUpdated, err := repo.UpdateGroup(ctx, u, dbMask) if err != nil { return nil, status.Errorf(codes.Internal, "Unable to update group: %v.", err) } if rowsUpdated == 0 { return nil, handlers.NotFoundErrorf("Group %q doesn't exist.", id) } - return toProto(out), nil + return toProto(out, m), nil } func (s Service) deleteFromRepo(ctx context.Context, id string) (bool, error) { @@ -233,16 +281,74 @@ func (s Service) listFromRepo(ctx context.Context, scopeId string) ([]*pb.Group, } var outGl []*pb.Group for _, g := range gl { - outGl = append(outGl, toProto(g)) + outGl = append(outGl, toProto(g, nil)) } return outGl, nil } -func toProto(in *iam.Group) *pb.Group { +func (s Service) addMembersInRepo(ctx context.Context, groupId string, userIds []string, version uint32) (*pb.Group, error) { + repo, err := s.repoFn() + if err != nil { + return nil, err + } + _, err = repo.AddGroupMembers(ctx, groupId, version, userIds) + if err != nil { + return nil, status.Errorf(codes.Internal, "Unable to add members to group: %v.", err) + } + out, m, err := repo.LookupGroup(ctx, groupId) + if err != nil { + return nil, status.Errorf(codes.Internal, "Unable to look up group: %v.", err) + } + if out == nil { + return nil, status.Error(codes.Internal, "Unable to lookup group after adding member to it.") + } + return toProto(out, m), nil +} + +func (s Service) setMembersInRepo(ctx context.Context, groupId string, userIds []string, version uint32) (*pb.Group, error) { + repo, err := s.repoFn() + if err != nil { + return nil, err + } + _, _, err = repo.SetGroupMembers(ctx, groupId, version, userIds) + if err != nil { + return nil, status.Errorf(codes.Internal, "Unable to set members on group: %v.", err) + } + out, m, err := repo.LookupGroup(ctx, groupId) + if err != nil { + return nil, status.Errorf(codes.Internal, "Unable to look up group: %v.", err) + } + if out == nil { + return nil, status.Error(codes.Internal, "Unable to lookup group after setting members for it.") + } + return toProto(out, m), nil +} + +func (s Service) removeMembersInRepo(ctx context.Context, groupId string, userIds []string, version uint32) (*pb.Group, error) { + repo, err := s.repoFn() + if err != nil { + return nil, err + } + _, err = repo.DeleteGroupMembers(ctx, groupId, version, userIds) + if err != nil { + return nil, status.Errorf(codes.Internal, "Unable to remove members from group: %v.", err) + } + out, m, err := repo.LookupGroup(ctx, groupId) + if err != nil { + return nil, status.Errorf(codes.Internal, "Unable to look up group: %v.", err) + } + if out == nil { + return nil, status.Error(codes.Internal, "Unable to lookup group after removing members from it.") + } + return toProto(out, m), nil +} + +func toProto(in *iam.Group, members []*iam.GroupMember) *pb.Group { out := pb.Group{ Id: in.GetPublicId(), CreatedTime: in.GetCreateTime().GetTimestamp(), UpdatedTime: in.GetUpdateTime().GetTimestamp(), + Version: in.Version, } if in.GetDescription() != "" { out.Description = &wrapperspb.StringValue{Value: in.GetDescription()} @@ -250,6 +356,14 @@ func toProto(in *iam.Group) *pb.Group { if in.GetName() != "" { out.Name = &wrapperspb.StringValue{Value: in.GetName()} } + for _, m := range members { + out.MemberIds = append(out.MemberIds, m.GetMemberId()) + out.Members = append(out.Members, &pb.Member{ + Id: m.GetMemberId(), + Type: m.GetType(), + ScopeId: m.GetMemberScopeId(), + }) + } return &out } @@ -337,6 +451,54 @@ func validateListRequest(req *pbs.ListGroupsRequest) error { return nil } +func validateAddGroupMembersRequest(req *pbs.AddGroupMembersRequest) error { + badFields := map[string]string{} + if !validId(req.GetId(), iam.GroupPrefix+"_") { + badFields["id"] = "Incorrectly formatted identifier." + } + if req.GetVersion() == nil { + badFields["version"] = "Required field." + } + if len(req.GetMemberIds()) == 0 { + badFields["member_ids"] = "Must be non-empty." + } + if len(badFields) > 0 { + return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields) + } + return nil +} + +func validateSetGroupMembersRequest(req *pbs.SetGroupMembersRequest) error { + badFields := map[string]string{} + if !validId(req.GetId(), iam.GroupPrefix+"_") { + badFields["id"] = "Incorrectly formatted identifier." + } + if req.GetVersion() == nil { + badFields["version"] = "Required field." + } + if len(badFields) > 0 { + return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields) + } + return nil +} + +func validateRemoveGroupMembersRequest(req *pbs.RemoveGroupMembersRequest) error { + badFields := map[string]string{} + if !validId(req.GetId(), iam.GroupPrefix+"_") { + badFields["id"] = "Incorrectly formatted identifier." + } + if req.GetVersion() == nil { + badFields["version"] = "Required field." + } + if len(req.GetMemberIds()) == 0 { + badFields["member_ids"] = "Must be non-empty." + } + if len(badFields) > 0 { + return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields) + } + return nil +} + func validId(id, prefix string) bool { if !strings.HasPrefix(id, prefix) { return false diff --git a/internal/servers/controller/handlers/groups/group_service_test.go b/internal/servers/controller/handlers/groups/group_service_test.go index 693b52213..fd27856f4 100644 --- a/internal/servers/controller/handlers/groups/group_service_test.go +++ b/internal/servers/controller/handlers/groups/group_service_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/golang/protobuf/ptypes" + "github.com/google/go-cmp/cmp" "github.com/hashicorp/watchtower/internal/auth" "github.com/hashicorp/watchtower/internal/db" pb "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/groups" @@ -19,6 +20,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/wrapperspb" "github.com/stretchr/testify/assert" @@ -41,10 +43,47 @@ func createDefaultGroupsAndRepo(t *testing.T) (*iam.Group, *iam.Group, func() (* return og, pg, repoFn } +func equalMembers(g *pb.Group, members []string) bool { + if len(g.Members) != len(members) { + return false + } + for _, m := range members { + var foundInMembers bool + var foundInPrincipalIds bool + for _, v := range g.Members { + if v.Id == m { + foundInMembers = true + } + } + for _, v := range g.MemberIds { + if v == m { + foundInPrincipalIds = true + } + } + if !foundInMembers || !foundInPrincipalIds { + return false + } + } + return true +} + func TestGet(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - og, pg, repo := createDefaultGroupsAndRepo(t) + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrap := db.TestWrapper(t) + repoFn := func() (*iam.Repository, error) { + return iam.NewRepository(rw, rw, wrap) + } + + o, p := iam.TestScopes(t, conn) + u := iam.TestUser(t, conn, o.GetPublicId()) + + og := iam.TestGroup(t, conn, o.GetPublicId(), iam.WithDescription("default"), iam.WithName("default")) + _ = iam.TestGroupMember(t, conn, og.GetPublicId(), u.GetPublicId()) + + pg := iam.TestGroup(t, conn, p.GetPublicId(), iam.WithDescription("default"), iam.WithName("default")) + _ = iam.TestGroupMember(t, conn, pg.GetPublicId(), u.GetPublicId()) + toMerge := &pbs.GetGroupRequest{ Id: og.GetPublicId(), } @@ -56,6 +95,15 @@ func TestGet(t *testing.T) { Description: &wrapperspb.StringValue{Value: og.GetDescription()}, CreatedTime: og.CreateTime.GetTimestamp(), UpdatedTime: og.UpdateTime.GetTimestamp(), + Version: 1, + MemberIds: []string{u.GetPublicId()}, + Members: []*pb.Member{ + { + Id: u.GetPublicId(), + Type: iam.UserMemberType.String(), + ScopeId: u.GetScopeId(), + }, + }, } wantProjGroup := &pb.Group{ @@ -65,6 +113,15 @@ func TestGet(t *testing.T) { Description: &wrapperspb.StringValue{Value: pg.GetDescription()}, CreatedTime: pg.CreateTime.GetTimestamp(), UpdatedTime: pg.UpdateTime.GetTimestamp(), + Version: 1, + MemberIds: []string{u.GetPublicId()}, + Members: []*pb.Member{ + { + Id: u.GetPublicId(), + Type: iam.UserMemberType.String(), + ScopeId: u.GetScopeId(), + }, + }, } cases := []struct { @@ -130,15 +187,16 @@ func TestGet(t *testing.T) { } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) req := proto.Clone(toMerge).(*pbs.GetGroupRequest) proto.Merge(req, tc.req) - s, err := groups.NewService(repo) + s, err := groups.NewService(repoFn) require.NoError(err, "Couldn't create new group service.") got, gErr := s.GetGroup(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), req) assert.Equal(tc.errCode, status.Code(gErr), "GetGroup(%+v) got error %v, wanted %v", req, gErr, tc.errCode) - assert.True(proto.Equal(got, tc.res), "GetGroup(%q) got response\n%q, wanted\n%q", req, got, tc.res) + assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "GetGroup(%q) got response\n%q, wanted\n%q", req, got, tc.res) }) } } @@ -161,6 +219,7 @@ func TestList(t *testing.T) { Scope: &scopes.ScopeInfo{Id: oWithGroups.GetPublicId(), Type: scope.Org.String()}, CreatedTime: og.GetCreateTime().GetTimestamp(), UpdatedTime: og.GetUpdateTime().GetTimestamp(), + Version: 1, }) pg := iam.TestGroup(t, conn, pWithGroups.GetPublicId()) wantProjGroups = append(wantProjGroups, &pb.Group{ @@ -168,6 +227,7 @@ func TestList(t *testing.T) { Scope: &scopes.ScopeInfo{Id: pWithGroups.GetPublicId(), Type: scope.Project.String()}, CreatedTime: pg.GetCreateTime().GetTimestamp(), UpdatedTime: pg.GetUpdateTime().GetTimestamp(), + Version: 1, }) } @@ -374,6 +434,7 @@ func TestCreate(t *testing.T) { Scope: &scopes.ScopeInfo{Id: defaultOGroup.GetScopeId(), Type: scope.Org.String()}, Name: &wrapperspb.StringValue{Value: "name"}, Description: &wrapperspb.StringValue{Value: "desc"}, + Version: 1, }, }, errCode: codes.OK, @@ -393,6 +454,7 @@ func TestCreate(t *testing.T) { Scope: &scopes.ScopeInfo{Id: defaultPGroup.GetScopeId(), Type: scope.Project.String()}, Name: &wrapperspb.StringValue{Value: "name"}, Description: &wrapperspb.StringValue{Value: "desc"}, + Version: 1, }, }, errCode: codes.OK, @@ -449,23 +511,35 @@ func TestCreate(t *testing.T) { got.Item.Id, tc.res.Item.Id = "", "" got.Item.CreatedTime, got.Item.UpdatedTime, tc.res.Item.CreatedTime, tc.res.Item.UpdatedTime = nil, nil, nil, nil } - assert.True(proto.Equal(got, tc.res), "CreateGroup(%q) got response %q, wanted %q", req, got, tc.res) + assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "CreateGroup(%q) got response %q, wanted %q", req, got, tc.res) }) } } func TestUpdate(t *testing.T) { require := require.New(t) - og, pg, repoFn := createDefaultGroupsAndRepo(t) - tested, err := groups.NewService(repoFn) - require.NoError(err, "Error when getting new group service.") + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrap := db.TestWrapper(t) + repoFn := func() (*iam.Repository, error) { + return iam.NewRepository(rw, rw, wrap) + } + + o, p := iam.TestScopes(t, conn) + u := iam.TestUser(t, conn, o.GetPublicId()) + + og := iam.TestGroup(t, conn, o.GetPublicId(), iam.WithDescription("default"), iam.WithName("default")) + _ = iam.TestGroupMember(t, conn, og.GetPublicId(), u.GetPublicId()) + + pg := iam.TestGroup(t, conn, p.GetPublicId(), iam.WithDescription("default"), iam.WithName("default")) + _ = iam.TestGroupMember(t, conn, pg.GetPublicId(), u.GetPublicId()) resetGroups := func() { repo, err := repoFn() require.NoError(err, "Couldn't get a new repo") - og, _, err = repo.UpdateGroup(context.Background(), og, []string{"Name", "Description"}) + og, _, _, err = repo.UpdateGroup(context.Background(), og, []string{"Name", "Description"}) require.NoError(err, "Failed to reset the group") - pg, _, err = repo.UpdateGroup(context.Background(), pg, []string{"Name", "Description"}) + pg, _, _, err = repo.UpdateGroup(context.Background(), pg, []string{"Name", "Description"}) require.NoError(err, "Failed to reset the group") } @@ -475,6 +549,7 @@ func TestUpdate(t *testing.T) { Id: og.GetPublicId(), } + tested, err := groups.NewService(repoFn) cases := []struct { name string scopeId string @@ -483,31 +558,39 @@ func TestUpdate(t *testing.T) { errCode codes.Code }{ { - scopeId: og.GetScopeId(), name: "Update an Existing Group", - req: &pbs.UpdateGroupRequest{ - UpdateMask: &field_mask.FieldMask{ - Paths: []string{"name", "description"}, - }, - Item: &pb.Group{ - Name: &wrapperspb.StringValue{Value: "new"}, - Description: &wrapperspb.StringValue{Value: "desc"}, - }, - }, - res: &pbs.UpdateGroupResponse{ - Item: &pb.Group{ - Id: og.GetPublicId(), - Scope: &scopes.ScopeInfo{Id: og.GetScopeId(), Type: scope.Org.String()}, - Name: &wrapperspb.StringValue{Value: "new"}, - Description: &wrapperspb.StringValue{Value: "desc"}, - CreatedTime: og.GetCreateTime().GetTimestamp(), - }, - }, - errCode: codes.OK, - }, - { scopeId: og.GetScopeId(), + req: &pbs.UpdateGroupRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"name", "description"}, + }, + Item: &pb.Group{ + Name: &wrapperspb.StringValue{Value: "new"}, + Description: &wrapperspb.StringValue{Value: "desc"}, + }, + }, + res: &pbs.UpdateGroupResponse{ + Item: &pb.Group{ + Id: og.GetPublicId(), + Scope: &scopes.ScopeInfo{Id: og.GetScopeId(), Type: scope.Org.String()}, + Name: &wrapperspb.StringValue{Value: "new"}, + Description: &wrapperspb.StringValue{Value: "desc"}, + CreatedTime: og.GetCreateTime().GetTimestamp(), + MemberIds: []string{u.GetPublicId()}, + Members: []*pb.Member{ + { + Id: u.GetPublicId(), + Type: iam.UserMemberType.String(), + ScopeId: u.GetScopeId(), + }, + }, + }, + }, + errCode: codes.OK, + }, + { name: "Multiple Paths in single string", + scopeId: og.GetScopeId(), req: &pbs.UpdateGroupRequest{ UpdateMask: &field_mask.FieldMask{ Paths: []string{"name,description"}, @@ -524,13 +607,21 @@ func TestUpdate(t *testing.T) { Name: &wrapperspb.StringValue{Value: "new"}, Description: &wrapperspb.StringValue{Value: "desc"}, CreatedTime: og.GetCreateTime().GetTimestamp(), + MemberIds: []string{u.GetPublicId()}, + Members: []*pb.Member{ + { + Id: u.GetPublicId(), + Type: iam.UserMemberType.String(), + ScopeId: u.GetScopeId(), + }, + }, }, }, errCode: codes.OK, }, { - scopeId: pg.GetScopeId(), name: "Update an Existing Project Scoped Group", + scopeId: pg.GetScopeId(), req: &pbs.UpdateGroupRequest{ Id: pg.GetPublicId(), UpdateMask: &field_mask.FieldMask{ @@ -548,13 +639,21 @@ func TestUpdate(t *testing.T) { Name: &wrapperspb.StringValue{Value: "new"}, Description: &wrapperspb.StringValue{Value: "desc"}, CreatedTime: pg.GetCreateTime().GetTimestamp(), + MemberIds: []string{u.GetPublicId()}, + Members: []*pb.Member{ + { + Id: u.GetPublicId(), + Type: iam.UserMemberType.String(), + ScopeId: u.GetScopeId(), + }, + }, }, }, errCode: codes.OK, }, { - scopeId: pg.GetScopeId(), name: "Multiple Paths in single string", + scopeId: pg.GetScopeId(), req: &pbs.UpdateGroupRequest{ Id: pg.GetPublicId(), UpdateMask: &field_mask.FieldMask{ @@ -572,6 +671,14 @@ func TestUpdate(t *testing.T) { Name: &wrapperspb.StringValue{Value: "new"}, Description: &wrapperspb.StringValue{Value: "desc"}, CreatedTime: pg.GetCreateTime().GetTimestamp(), + MemberIds: []string{u.GetPublicId()}, + Members: []*pb.Member{ + { + Id: u.GetPublicId(), + Type: iam.UserMemberType.String(), + ScopeId: u.GetScopeId(), + }, + }, }, }, errCode: codes.OK, @@ -627,13 +734,21 @@ func TestUpdate(t *testing.T) { Scope: &scopes.ScopeInfo{Id: og.GetScopeId(), Type: scope.Org.String()}, Description: &wrapperspb.StringValue{Value: "default"}, CreatedTime: og.GetCreateTime().GetTimestamp(), + MemberIds: []string{u.GetPublicId()}, + Members: []*pb.Member{ + { + Id: u.GetPublicId(), + Type: iam.UserMemberType.String(), + ScopeId: u.GetScopeId(), + }, + }, }, }, errCode: codes.OK, }, { - scopeId: og.GetScopeId(), name: "Update Only Name", + scopeId: og.GetScopeId(), req: &pbs.UpdateGroupRequest{ UpdateMask: &field_mask.FieldMask{ Paths: []string{"name"}, @@ -650,13 +765,21 @@ func TestUpdate(t *testing.T) { Name: &wrapperspb.StringValue{Value: "updated"}, Description: &wrapperspb.StringValue{Value: "default"}, CreatedTime: og.GetCreateTime().GetTimestamp(), + MemberIds: []string{u.GetPublicId()}, + Members: []*pb.Member{ + { + Id: u.GetPublicId(), + Type: iam.UserMemberType.String(), + ScopeId: u.GetScopeId(), + }, + }, }, }, errCode: codes.OK, }, { - scopeId: og.GetScopeId(), name: "Update Only Description", + scopeId: og.GetScopeId(), req: &pbs.UpdateGroupRequest{ UpdateMask: &field_mask.FieldMask{ Paths: []string{"description"}, @@ -673,6 +796,14 @@ func TestUpdate(t *testing.T) { Name: &wrapperspb.StringValue{Value: "default"}, Description: &wrapperspb.StringValue{Value: "notignored"}, CreatedTime: og.GetCreateTime().GetTimestamp(), + MemberIds: []string{u.GetPublicId()}, + Members: []*pb.Member{ + { + Id: u.GetPublicId(), + Type: iam.UserMemberType.String(), + ScopeId: u.GetScopeId(), + }, + }, }, }, errCode: codes.OK, @@ -754,8 +885,320 @@ func TestUpdate(t *testing.T) { // Clear all values which are hard to compare against. got.Item.UpdatedTime, tc.res.Item.UpdatedTime = nil, nil + // TODO: Figure out the best way to test version updates. + got.Item.Version = 0 } - assert.True(proto.Equal(got, tc.res), "UpdateGroup(%q) got response %q, wanted %q", req, got, tc.res) + assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "UpdateGroup(%q) got response %q, wanted %q", req, got, tc.res) + }) + } +} + +func TestAddMember(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrap := db.TestWrapper(t) + repoFn := func() (*iam.Repository, error) { + return iam.NewRepository(rw, rw, wrap) + } + s, err := groups.NewService(repoFn) + require.NoError(t, err, "Error when getting new group service.") + + o, p := iam.TestScopes(t, conn) + users := []*iam.User{ + iam.TestUser(t, conn, o.GetPublicId()), + iam.TestUser(t, conn, o.GetPublicId()), + iam.TestUser(t, conn, o.GetPublicId()), + } + + addCases := []struct { + name string + setup func(*iam.Group) + addUsers []string + addGroups []string + resultUsers []string + resultGroups []string + wantErr bool + }{ + { + name: "Add user on empty group", + setup: func(g *iam.Group) {}, + addUsers: []string{users[1].GetPublicId()}, + resultUsers: []string{users[1].GetPublicId()}, + }, + { + name: "Add user on populated group", + setup: func(g *iam.Group) { + iam.TestGroupMember(t, conn, g.GetPublicId(), users[0].GetPublicId()) + }, + addUsers: []string{users[1].GetPublicId()}, + resultUsers: []string{users[0].GetPublicId(), users[1].GetPublicId()}, + }, + { + name: "Add empty on populated group", + setup: func(g *iam.Group) { + iam.TestGroupMember(t, conn, g.GetPublicId(), users[0].GetPublicId()) + iam.TestGroupMember(t, conn, g.GetPublicId(), users[1].GetPublicId()) + }, + wantErr: true, + }, + } + + for _, tc := range addCases { + for _, scp := range []*iam.Scope{o, p} { + t.Run(tc.name+"_"+scp.GetType(), func(t *testing.T) { + grp := iam.TestGroup(t, conn, scp.GetPublicId()) + tc.setup(grp) + req := &pbs.AddGroupMembersRequest{ + Id: grp.GetPublicId(), + Version: &wrapperspb.UInt32Value{Value: grp.GetVersion()}, + MemberIds: tc.addUsers, + } + + got, err := s.AddGroupMembers(auth.DisabledAuthTestContext(auth.WithScopeId(scp.GetPublicId())), req) + if tc.wantErr { + assert.Error(t, err) + return + } + s, ok := status.FromError(err) + require.True(t, ok) + require.NoError(t, err, "Got error: %v", s) + + assert.True(t, equalMembers(got.GetItem(), tc.resultUsers)) + }) + } + } + + grp := iam.TestGroup(t, conn, p.GetPublicId()) + + failCases := []struct { + name string + req *pbs.AddGroupMembersRequest + errCode codes.Code + }{ + { + name: "Bad Group Id", + req: &pbs.AddGroupMembersRequest{ + Id: "bad id", + Version: &wrapperspb.UInt32Value{Value: grp.GetVersion()}, + }, + errCode: codes.InvalidArgument, + }, + } + for _, tc := range failCases { + t.Run(tc.name, func(t *testing.T) { + assert := assert.New(t) + _, gErr := s.AddGroupMembers(auth.DisabledAuthTestContext(auth.WithScopeId(grp.GetScopeId())), tc.req) + assert.Equal(tc.errCode, status.Code(gErr), "AddGroupMembers(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) + }) + } +} + +func TestSetMember(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrap := db.TestWrapper(t) + repoFn := func() (*iam.Repository, error) { + return iam.NewRepository(rw, rw, wrap) + } + s, err := groups.NewService(repoFn) + require.NoError(t, err, "Error when getting new group service.") + + o, p := iam.TestScopes(t, conn) + users := []*iam.User{ + iam.TestUser(t, conn, o.GetPublicId()), + iam.TestUser(t, conn, o.GetPublicId()), + iam.TestUser(t, conn, o.GetPublicId()), + } + + setCases := []struct { + name string + setup func(*iam.Group) + setUsers []string + setGroups []string + resultUsers []string + resultGroups []string + wantErr bool + }{ + { + name: "Set user on empty group", + setup: func(r *iam.Group) {}, + setUsers: []string{users[1].GetPublicId()}, + resultUsers: []string{users[1].GetPublicId()}, + }, + { + name: "Set user on populated group", + setup: func(r *iam.Group) { + iam.TestGroupMember(t, conn, r.GetPublicId(), users[0].GetPublicId()) + }, + setUsers: []string{users[1].GetPublicId()}, + resultUsers: []string{users[1].GetPublicId()}, + }, + { + name: "Set empty on populated group", + setup: func(r *iam.Group) { + iam.TestGroupMember(t, conn, r.GetPublicId(), users[0].GetPublicId()) + iam.TestGroupMember(t, conn, r.GetPublicId(), users[1].GetPublicId()) + }, + setUsers: []string{}, + resultUsers: nil, + }, + } + + for _, tc := range setCases { + for _, scp := range []*iam.Scope{o, p} { + t.Run(tc.name+"_"+scp.GetType(), func(t *testing.T) { + grp := iam.TestGroup(t, conn, scp.GetPublicId()) + tc.setup(grp) + req := &pbs.SetGroupMembersRequest{ + Id: grp.GetPublicId(), + Version: &wrapperspb.UInt32Value{Value: grp.GetVersion()}, + MemberIds: tc.setUsers, + } + + got, err := s.SetGroupMembers(auth.DisabledAuthTestContext(auth.WithScopeId(scp.GetPublicId())), req) + if tc.wantErr { + assert.Error(t, err) + return + } + s, ok := status.FromError(err) + require.True(t, ok) + require.NoError(t, err, "Got error: %v", s) + + assert.True(t, equalMembers(got.GetItem(), append(tc.resultUsers, tc.resultGroups...))) + }) + } + } + + grp := iam.TestGroup(t, conn, p.GetPublicId()) + + failCases := []struct { + name string + req *pbs.SetGroupMembersRequest + errCode codes.Code + }{ + { + name: "Bad Group Id", + req: &pbs.SetGroupMembersRequest{ + Id: "bad id", + Version: &wrapperspb.UInt32Value{Value: grp.GetVersion()}, + }, + errCode: codes.InvalidArgument, + }, + } + for _, tc := range failCases { + t.Run(tc.name, func(t *testing.T) { + assert := assert.New(t) + _, gErr := s.SetGroupMembers(auth.DisabledAuthTestContext(auth.WithScopeId(grp.GetScopeId())), tc.req) + assert.Equal(tc.errCode, status.Code(gErr), "SetGroupMembers(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) + }) + } +} + +func TestRemoveMember(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrap := db.TestWrapper(t) + repoFn := func() (*iam.Repository, error) { + return iam.NewRepository(rw, rw, wrap) + } + s, err := groups.NewService(repoFn) + require.NoError(t, err, "Error when getting new grp service.") + + o, p := iam.TestScopes(t, conn) + users := []*iam.User{ + iam.TestUser(t, conn, o.GetPublicId()), + iam.TestUser(t, conn, o.GetPublicId()), + iam.TestUser(t, conn, o.GetPublicId()), + } + + addCases := []struct { + name string + setup func(*iam.Group) + removeUsers []string + removeGroups []string + resultUsers []string + resultGroups []string + wantErr bool + }{ + { + name: "Remove user on empty group", + setup: func(r *iam.Group) {}, + removeUsers: []string{users[1].GetPublicId()}, + wantErr: true, + }, + { + name: "Remove 1 of 2 users from group", + setup: func(r *iam.Group) { + iam.TestGroupMember(t, conn, r.GetPublicId(), users[0].GetPublicId()) + iam.TestGroupMember(t, conn, r.GetPublicId(), users[1].GetPublicId()) + }, + removeUsers: []string{users[1].GetPublicId()}, + resultUsers: []string{users[0].GetPublicId()}, + }, + { + name: "Remove all users from group", + setup: func(r *iam.Group) { + iam.TestGroupMember(t, conn, r.GetPublicId(), users[0].GetPublicId()) + iam.TestGroupMember(t, conn, r.GetPublicId(), users[1].GetPublicId()) + }, + removeUsers: []string{users[0].GetPublicId(), users[1].GetPublicId()}, + resultUsers: []string{}, + }, + { + name: "Remove empty on populated group", + setup: func(r *iam.Group) { + iam.TestGroupMember(t, conn, r.GetPublicId(), users[0].GetPublicId()) + }, + wantErr: true, + }, + } + + for _, tc := range addCases { + for _, scp := range []*iam.Scope{o, p} { + t.Run(tc.name+"_"+scp.GetType(), func(t *testing.T) { + grp := iam.TestGroup(t, conn, scp.GetPublicId()) + tc.setup(grp) + req := &pbs.RemoveGroupMembersRequest{ + Id: grp.GetPublicId(), + Version: &wrapperspb.UInt32Value{Value: grp.GetVersion()}, + MemberIds: tc.removeUsers, + } + + got, err := s.RemoveGroupMembers(auth.DisabledAuthTestContext(auth.WithScopeId(scp.GetPublicId())), req) + if tc.wantErr { + assert.Error(t, err) + return + } + s, ok := status.FromError(err) + require.True(t, ok) + require.NoError(t, err, "Got error: %v", s) + + assert.True(t, equalMembers(got.GetItem(), tc.resultUsers)) + }) + } + } + + grp := iam.TestGroup(t, conn, p.GetPublicId()) + + failCases := []struct { + name string + req *pbs.AddGroupMembersRequest + errCode codes.Code + }{ + { + name: "Bad Group Id", + req: &pbs.AddGroupMembersRequest{ + Id: "bad id", + Version: &wrapperspb.UInt32Value{Value: grp.GetVersion()}, + }, + errCode: codes.InvalidArgument, + }, + } + for _, tc := range failCases { + t.Run(tc.name, func(t *testing.T) { + assert := assert.New(t) + _, gErr := s.AddGroupMembers(auth.DisabledAuthTestContext(auth.WithScopeId(grp.GetScopeId())), tc.req) + assert.Equal(tc.errCode, status.Code(gErr), "AddGroupMembers(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) }) } } diff --git a/internal/servers/controller/handlers/roles/role_service.go b/internal/servers/controller/handlers/roles/role_service.go index ecacec99b..d3767f6a4 100644 --- a/internal/servers/controller/handlers/roles/role_service.go +++ b/internal/servers/controller/handlers/roles/role_service.go @@ -358,14 +358,14 @@ func (s Service) addPrinciplesInRepo(ctx context.Context, roleId string, princip } _, err = repo.AddPrincipalRoles(ctx, roleId, version, principalIds) if err != nil { - return nil, status.Errorf(codes.Internal, "Unable to add principles to role: %v.", err) + return nil, status.Errorf(codes.Internal, "Unable to add principals to role: %v.", err) } out, pr, roleGrants, err := repo.LookupRole(ctx, roleId) if err != nil { return nil, status.Errorf(codes.Internal, "Unable to look up role: %v.", err) } if out == nil { - return nil, status.Error(codes.Internal, "Unable to lookup role after adding principles to it.") + return nil, status.Error(codes.Internal, "Unable to lookup role after adding principals to it.") } return toProto(out, pr, roleGrants), nil } @@ -377,14 +377,14 @@ func (s Service) setPrinciplesInRepo(ctx context.Context, roleId string, princip } _, _, err = repo.SetPrincipalRoles(ctx, roleId, version, principalIds) if err != nil { - return nil, status.Errorf(codes.Internal, "Unable to set principles on role: %v.", err) + return nil, status.Errorf(codes.Internal, "Unable to set principals on role: %v.", err) } out, pr, roleGrants, err := repo.LookupRole(ctx, roleId) if err != nil { return nil, status.Errorf(codes.Internal, "Unable to look up role: %v.", err) } if out == nil { - return nil, status.Error(codes.Internal, "Unable to lookup role after setting principles for it.") + return nil, status.Error(codes.Internal, "Unable to lookup role after setting principals for it.") } return toProto(out, pr, roleGrants), nil } @@ -396,14 +396,14 @@ func (s Service) removePrinciplesInRepo(ctx context.Context, roleId string, prin } _, err = repo.DeletePrincipalRoles(ctx, roleId, version, principalIds) if err != nil { - return nil, status.Errorf(codes.Internal, "Unable to remove principles from role: %v.", err) + return nil, status.Errorf(codes.Internal, "Unable to remove principals from role: %v.", err) } out, pr, roleGrants, err := repo.LookupRole(ctx, roleId) if err != nil { return nil, status.Errorf(codes.Internal, "Unable to look up role: %v.", err) } if out == nil { - return nil, status.Error(codes.Internal, "Unable to lookup role after removing principles from it.") + return nil, status.Error(codes.Internal, "Unable to lookup role after removing principals from it.") } return toProto(out, pr, roleGrants), nil } diff --git a/internal/types/action/action.go b/internal/types/action/action.go index b7e9e0f15..a17e35b48 100644 --- a/internal/types/action/action.go +++ b/internal/types/action/action.go @@ -22,6 +22,9 @@ const ( SetPrincipals Type = 13 RemovePrincipals Type = 14 Deauthenticate Type = 15 + AddMembers Type = 16 + SetMembers Type = 17 + RemoveMembers Type = 18 ) var Map = map[string]Type{ @@ -40,6 +43,9 @@ var Map = map[string]Type{ SetPrincipals.String(): SetPrincipals, RemovePrincipals.String(): RemovePrincipals, Deauthenticate.String(): Deauthenticate, + AddMembers.String(): AddMembers, + SetMembers.String(): SetMembers, + RemoveMembers.String(): RemoveMembers, } func (a Type) String() string { @@ -60,5 +66,8 @@ func (a Type) String() string { "set-principals", "remove-principals", "deauthenticate", + "add-members", + "set-members", + "remove-members", }[a] }