diff --git a/api/hosts/host_catalog_test.go b/api/hosts/host_catalog_test.go index f100753c3..a51b8aada 100644 --- a/api/hosts/host_catalog_test.go +++ b/api/hosts/host_catalog_test.go @@ -66,7 +66,7 @@ func TestCatalogs_Crud(t *testing.T) { } // TODO: Get better coverage for expected errors and error formats. -func TestProject_Errors(t *testing.T) { +func TestCatalogs_Errors(t *testing.T) { assert := assert.New(t) tc := controller.NewTestController(t, nil) defer tc.Shutdown() diff --git a/api/internal/genapi/create.go b/api/internal/genapi/create.go index b03d690af..5f605adc6 100644 --- a/api/internal/genapi/create.go +++ b/api/internal/genapi/create.go @@ -34,6 +34,11 @@ var createFuncs = map[string][]*createInfo{ targetType: "Project", path: `"projects"`, }, + { + baseType: "Organization", + targetType: "users.User", + path: `"users"`, + }, { baseType: "Project", targetType: "hosts.HostCatalog", diff --git a/api/internal/genapi/delete.go b/api/internal/genapi/delete.go index 0574b5a81..14c8d12d8 100644 --- a/api/internal/genapi/delete.go +++ b/api/internal/genapi/delete.go @@ -22,6 +22,11 @@ var deleteFuncs = map[string][]*deleteInfo{ "Project", "projects", }, + { + "Organization", + "users.User", + "users", + }, { "Project", "hosts.HostCatalog", diff --git a/api/internal/genapi/input.go b/api/internal/genapi/input.go index b228c9fb4..436d37d67 100644 --- a/api/internal/genapi/input.go +++ b/api/internal/genapi/input.go @@ -103,6 +103,17 @@ var inputStructs = []*structInfo{ "", templateTypeResource, }, + { + os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/users/user.pb.go", + "User", + os.Getenv("GEN_BASEPATH") + "/api/users/user.gen.go", + "User", + "users", + "", + "", + "", + templateTypeResource, + }, { os.Getenv("GEN_BASEPATH") + "/internal/gen/controller/api/resources/hosts/host_catalog.pb.go", "StaticHostCatalogDetails", diff --git a/api/internal/genapi/read.go b/api/internal/genapi/read.go index 7fcd23806..f1383d4e9 100644 --- a/api/internal/genapi/read.go +++ b/api/internal/genapi/read.go @@ -22,6 +22,11 @@ var readFuncs = map[string][]*readInfo{ targetType: "Project", path: "projects", }, + { + baseType: "Organization", + targetType: "users.User", + path: "users", + }, { baseType: "Project", targetType: "hosts.HostCatalog", diff --git a/api/internal/genapi/update.go b/api/internal/genapi/update.go index 61e9a7ffc..4073915da 100644 --- a/api/internal/genapi/update.go +++ b/api/internal/genapi/update.go @@ -22,6 +22,11 @@ var updateFuncs = map[string][]*updateInfo{ targetType: "Project", path: "projects", }, + { + baseType: "Organization", + targetType: "users.User", + path: "users", + }, { baseType: "Project", targetType: "hosts.HostCatalog", diff --git a/api/scopes/create.gen.go b/api/scopes/create.gen.go index 0f80adcc8..5c4606a97 100644 --- a/api/scopes/create.gen.go +++ b/api/scopes/create.gen.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/watchtower/api" "github.com/hashicorp/watchtower/api/hosts" + "github.com/hashicorp/watchtower/api/users" ) func (s Organization) CreateProject(ctx context.Context, r *Project) (*Project, *api.Error, error) { @@ -48,6 +49,44 @@ func (s Organization) CreateProject(ctx context.Context, r *Project) (*Project, return target, apiErr, nil } +func (s Organization) CreateUser(ctx context.Context, r *users.User) (*users.User, *api.Error, error) { + if s.Client == nil { + return nil, nil, fmt.Errorf("nil client in Createusers.User request") + } + if s.Id == "" { + + // Assume the client has been configured with organization already and + // move on + + } else { + // If it's explicitly set here, override anything that might be in the + // client + + ctx = context.WithValue(ctx, "org", s.Id) + + } + + req, err := s.Client.NewRequest(ctx, "POST", "users", r) + if err != nil { + return nil, nil, fmt.Errorf("error creating Createusers.User request: %w", err) + } + + resp, err := s.Client.Do(req) + if err != nil { + return nil, nil, fmt.Errorf("error performing client request during Createusers.User call: %w", err) + } + + target := new(users.User) + apiErr, err := resp.Decode(target) + if err != nil { + return nil, nil, fmt.Errorf("error decoding Createusers.User repsonse: %w", err) + } + + target.Client = s.Client + + return target, apiErr, nil +} + func (s Project) CreateHostCatalog(ctx context.Context, r *hosts.HostCatalog) (*hosts.HostCatalog, *api.Error, error) { if s.Client == nil { return nil, nil, fmt.Errorf("nil client in Createhosts.HostCatalog request") diff --git a/api/scopes/delete.gen.go b/api/scopes/delete.gen.go index 978ae062b..adb930f25 100644 --- a/api/scopes/delete.gen.go +++ b/api/scopes/delete.gen.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/watchtower/api" "github.com/hashicorp/watchtower/api/hosts" + "github.com/hashicorp/watchtower/api/users" ) // DeleteProject returns true iff the Project existed when the delete attempt was made. @@ -53,6 +54,50 @@ func (s Organization) DeleteProject(ctx context.Context, r *Project) (bool, *api return target.Existed, apiErr, nil } +// DeleteUser returns true iff the users.User existed when the delete attempt was made. +func (s Organization) DeleteUser(ctx context.Context, r *users.User) (bool, *api.Error, error) { + if s.Client == nil { + return false, nil, fmt.Errorf("nil client in DeleteUser request") + } + if s.Id == "" { + + // Assume the client has been configured with organization already and + // move on + + } else { + // If it's explicitly set here, override anything that might be in the + // client + + ctx = context.WithValue(ctx, "org", s.Id) + + } + if r.Id == "" { + return false, nil, fmt.Errorf("empty users.User ID field in DeleteUser request") + } + + req, err := s.Client.NewRequest(ctx, "DELETE", fmt.Sprintf("%s/%s", "users", r.Id), nil) + if err != nil { + return false, nil, fmt.Errorf("error creating DeleteUser request: %w", err) + } + + resp, err := s.Client.Do(req) + if err != nil { + return false, nil, fmt.Errorf("error performing client request during DeleteUser call: %w", err) + } + + type deleteResponse struct { + Existed bool + } + target := &deleteResponse{} + + apiErr, err := resp.Decode(target) + if err != nil { + return false, nil, fmt.Errorf("error decoding DeleteUser repsonse: %w", err) + } + + return target.Existed, apiErr, nil +} + // DeleteHostCatalog returns true iff the hosts.HostCatalog existed when the delete attempt was made. func (s Project) DeleteHostCatalog(ctx context.Context, r *hosts.HostCatalog) (bool, *api.Error, error) { if s.Client == nil { diff --git a/api/scopes/read.gen.go b/api/scopes/read.gen.go index 151983dc0..07ec60e47 100644 --- a/api/scopes/read.gen.go +++ b/api/scopes/read.gen.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/watchtower/api" "github.com/hashicorp/watchtower/api/hosts" + "github.com/hashicorp/watchtower/api/users" ) func (s Organization) ReadProject(ctx context.Context, r *Project) (*Project, *api.Error, error) { @@ -51,6 +52,47 @@ func (s Organization) ReadProject(ctx context.Context, r *Project) (*Project, *a return target, apiErr, nil } +func (s Organization) ReadUser(ctx context.Context, r *users.User) (*users.User, *api.Error, error) { + if s.Client == nil { + return nil, nil, fmt.Errorf("nil client in ReadUser request") + } + if s.Id == "" { + + // Assume the client has been configured with organization already and + // move on + + } else { + // If it's explicitly set here, override anything that might be in the + // client + + ctx = context.WithValue(ctx, "org", s.Id) + + } + if r.Id == "" { + return nil, nil, fmt.Errorf("empty users.User ID field in ReadUser request") + } + + req, err := s.Client.NewRequest(ctx, "GET", fmt.Sprintf("%s/%s", "users", r.Id), r) + if err != nil { + return nil, nil, fmt.Errorf("error creating ReadUser request: %w", err) + } + + resp, err := s.Client.Do(req) + if err != nil { + return nil, nil, fmt.Errorf("error performing client request during ReadUser call: %w", err) + } + + target := new(users.User) + apiErr, err := resp.Decode(target) + if err != nil { + return nil, nil, fmt.Errorf("error decoding ReadUser repsonse: %w", err) + } + + target.Client = s.Client + + return target, apiErr, nil +} + func (s Project) ReadHostCatalog(ctx context.Context, r *hosts.HostCatalog) (*hosts.HostCatalog, *api.Error, error) { if s.Client == nil { return nil, nil, fmt.Errorf("nil client in ReadHostCatalog request") diff --git a/api/scopes/update.gen.go b/api/scopes/update.gen.go index 27fba7cf7..d18bbc612 100644 --- a/api/scopes/update.gen.go +++ b/api/scopes/update.gen.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/watchtower/api" "github.com/hashicorp/watchtower/api/hosts" + "github.com/hashicorp/watchtower/api/users" ) func (s Organization) UpdateProject(ctx context.Context, r *Project) (*Project, *api.Error, error) { @@ -51,6 +52,47 @@ func (s Organization) UpdateProject(ctx context.Context, r *Project) (*Project, return target, apiErr, nil } +func (s Organization) UpdateUser(ctx context.Context, r *users.User) (*users.User, *api.Error, error) { + if s.Client == nil { + return nil, nil, fmt.Errorf("nil client in CreateUser request") + } + if s.Id == "" { + + // Assume the client has been configured with organization already and + // move on + + } else { + // If it's explicitly set here, override anything that might be in the + // client + + ctx = context.WithValue(ctx, "org", s.Id) + + } + + id := r.Id + r.Id = "" + + req, err := s.Client.NewRequest(ctx, "PATCH", fmt.Sprintf("%s/%s", "users", id), r) + if err != nil { + return nil, nil, fmt.Errorf("error creating CreateUser request: %w", err) + } + + resp, err := s.Client.Do(req) + if err != nil { + return nil, nil, fmt.Errorf("error performing client request during UpdateUser call: %w", err) + } + + target := new(users.User) + apiErr, err := resp.Decode(target) + if err != nil { + return nil, nil, fmt.Errorf("error decoding UpdateUser repsonse: %w", err) + } + + target.Client = s.Client + + return target, apiErr, nil +} + func (s Project) UpdateHostCatalog(ctx context.Context, r *hosts.HostCatalog) (*hosts.HostCatalog, *api.Error, error) { if s.Client == nil { return nil, nil, fmt.Errorf("nil client in CreateHostCatalog request") diff --git a/api/users/user.gen.go b/api/users/user.gen.go new file mode 100644 index 000000000..eb036001e --- /dev/null +++ b/api/users/user.gen.go @@ -0,0 +1,53 @@ +// Code generated by "make api"; DO NOT EDIT. +package users + +import ( + "encoding/json" + "time" + + "github.com/fatih/structs" + + "github.com/hashicorp/watchtower/api" + "github.com/hashicorp/watchtower/api/internal/strutil" +) + +type User struct { + Client *api.Client `json:"-"` + + defaultFields []string + + // The ID of the Project + // Output only. + Id string `json:"id,omitempty"` + // Optional name for identification purposes + Name *string `json:"name,omitempty"` + // Optional user-set descripton for identification purposes + Description *string `json:"description,omitempty"` + // The time this resource was created + // Output only. + CreatedTime time.Time `json:"created_time,omitempty"` + // The time this resource was last updated. + // Output only. + UpdatedTime time.Time `json:"updated_time,omitempty"` + // Whether the resource is disabled + Disabled *bool `json:"disabled,omitempty"` +} + +func (s *User) SetDefault(key string) { + s.defaultFields = strutil.AppendIfMissing(s.defaultFields, key) +} + +func (s *User) UnsetDefault(key string) { + s.defaultFields = strutil.StrListDelete(s.defaultFields, key) +} + +func (s User) MarshalJSON() ([]byte, error) { + m := structs.Map(s) + if m == nil { + m = make(map[string]interface{}) + } + for _, k := range s.defaultFields { + m[k] = nil + } + return json.Marshal(m) +} diff --git a/api/users/user_test.go b/api/users/user_test.go new file mode 100644 index 000000000..fdeed59a1 --- /dev/null +++ b/api/users/user_test.go @@ -0,0 +1,98 @@ +package users_test + +import ( + "net/http" + "testing" + + "github.com/hashicorp/watchtower/api" + "github.com/hashicorp/watchtower/api/scopes" + "github.com/hashicorp/watchtower/api/users" + "github.com/hashicorp/watchtower/internal/iam" + "github.com/hashicorp/watchtower/internal/servers/controller" + "github.com/stretchr/testify/assert" +) + +func TestUser_Crud(t *testing.T) { + tc := controller.NewTestController(t, nil) + defer tc.Shutdown() + + client := tc.Client() + org := &scopes.Organization{ + Client: client, + } + + checkUser := func(step string, u *users.User, apiErr *api.Error, err error, wantedName string) { + assert := assert.New(t) + assert.NoError(err, step) + if !assert.Nil(apiErr, step) && apiErr.Message != nil { + t.Errorf("ApiError message: %q", *apiErr.Message) + } + assert.NotNil(u, "returned project", step) + gotName := "" + if u.Name != nil { + gotName = *u.Name + } + assert.Equal(wantedName, gotName, step) + } + + u, apiErr, err := org.CreateUser(tc.Context(), &users.User{Name: api.String("foo")}) + checkUser("create", u, apiErr, err, "foo") + + u, apiErr, err = org.ReadUser(tc.Context(), &users.User{Id: u.Id}) + checkUser("read", u, apiErr, err, "foo") + + u = &users.User{Id: u.Id} + u.Name = api.String("bar") + u, apiErr, err = org.UpdateUser(tc.Context(), u) + checkUser("update", u, apiErr, err, "bar") + + u = &users.User{Id: u.Id} + u.SetDefault("name") + u, apiErr, err = org.UpdateUser(tc.Context(), u) + checkUser("update", u, apiErr, err, "") + + existed, apiErr, err := org.DeleteUser(tc.Context(), u) + assert.NoError(t, err) + assert.True(t, existed, "Expected existing user when deleted, but it wasn't.") + + existed, apiErr, err = org.DeleteUser(tc.Context(), u) + assert.NoError(t, err) + assert.False(t, existed, "Expected user to not exist when deleted, but it did.") +} + +func TestUser_Errors(t *testing.T) { + assert := assert.New(t) + tc := controller.NewTestController(t, nil) + defer tc.Shutdown() + ctx := tc.Context() + + client := tc.Client() + org := &scopes.Organization{ + Client: client, + } + + u, apiErr, err := org.CreateUser(ctx, &users.User{Name: api.String("first")}) + assert.NoError(err) + assert.Nil(apiErr) + assert.NotNil(u) + + // Create another resource with the same name. + _, apiErr, err = org.CreateUser(ctx, &users.User{Name: api.String("first")}) + assert.NoError(err) + assert.NotNil(apiErr) + + _, apiErr, err = org.ReadUser(ctx, &users.User{Id: iam.UserPrefix + "_doesntexis"}) + assert.NoError(err) + assert.NotNil(apiErr) + assert.EqualValues(*apiErr.Status, http.StatusNotFound) + + _, apiErr, err = org.ReadUser(ctx, &users.User{Id: "invalid id"}) + assert.NoError(err) + assert.NotNil(apiErr) + assert.EqualValues(*apiErr.Status, http.StatusBadRequest) + + _, apiErr, err = org.UpdateUser(ctx, &users.User{Id: u.Id}) + assert.NoError(err) + assert.NotNil(apiErr) + assert.EqualValues(*apiErr.Status, http.StatusBadRequest) +} diff --git a/internal/gen/controller.swagger.json b/internal/gen/controller.swagger.json index a825a0bad..95637dfab 100644 --- a/internal/gen/controller.swagger.json +++ b/internal/gen/controller.swagger.json @@ -1569,6 +1569,171 @@ "controller.api.services.v1.HostCatalogService" ] } + }, + "/v1/orgs/{org_id}/users": { + "get": { + "summary": "Lists all Users", + "operationId": "UserService_ListUsers", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/controller.api.services.v1.ListUsersResponse" + } + } + }, + "parameters": [ + { + "name": "org_id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "view", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "controller.api.services.v1.UserService" + ] + }, + "post": { + "summary": "Creates a single User", + "operationId": "UserService_CreateUser", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/controller.api.resources.users.v1.User" + } + } + }, + "parameters": [ + { + "name": "org_id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/controller.api.resources.users.v1.User" + } + } + ], + "tags": [ + "controller.api.services.v1.UserService" + ] + } + }, + "/v1/orgs/{org_id}/users/{id}": { + "get": { + "summary": "Gets a single User", + "operationId": "UserService_GetUser", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/controller.api.resources.users.v1.User" + } + } + }, + "parameters": [ + { + "name": "org_id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "view", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "controller.api.services.v1.UserService" + ] + }, + "delete": { + "summary": "Deletes a User", + "operationId": "UserService_DeleteUser", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/controller.api.services.v1.DeleteUserResponse" + } + } + }, + "parameters": [ + { + "name": "org_id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "controller.api.services.v1.UserService" + ] + }, + "patch": { + "summary": "Updates a User", + "operationId": "UserService_UpdateUser", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/controller.api.resources.users.v1.User" + } + } + }, + "parameters": [ + { + "name": "org_id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/controller.api.resources.users.v1.User" + } + } + ], + "tags": [ + "controller.api.services.v1.UserService" + ] + } } }, "definitions": { @@ -1750,6 +1915,42 @@ }, "title": "Project contains all fields related to a Project resource" }, + "controller.api.resources.users.v1.User": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The ID of the Project\nOutput only.", + "readOnly": true + }, + "name": { + "type": "string", + "title": "Optional name for identification purposes" + }, + "description": { + "type": "string", + "title": "Optional user-set descripton for identification purposes" + }, + "created_time": { + "type": "string", + "format": "date-time", + "description": "The time this resource was created\nOutput only.", + "readOnly": true + }, + "updated_time": { + "type": "string", + "format": "date-time", + "description": "The time this resource was last updated.\nOutput only.", + "readOnly": true + }, + "disabled": { + "type": "boolean", + "format": "boolean", + "title": "Whether the resource is disabled" + } + }, + "title": "User contains all fields related to a User resource" + }, "controller.api.services.v1.AddToHostSetResponse": { "type": "object" }, @@ -1797,6 +1998,17 @@ } } }, + "controller.api.services.v1.CreateUserResponse": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/controller.api.resources.users.v1.User" + } + } + }, "controller.api.services.v1.DeleteHostCatalogResponse": { "type": "object", "properties": { @@ -1833,6 +2045,15 @@ } } }, + "controller.api.services.v1.DeleteUserResponse": { + "type": "object", + "properties": { + "existed": { + "type": "boolean", + "format": "boolean" + } + } + }, "controller.api.services.v1.GetHostCatalogResponse": { "type": "object", "properties": { @@ -1865,6 +2086,14 @@ } } }, + "controller.api.services.v1.GetUserResponse": { + "type": "object", + "properties": { + "item": { + "$ref": "#/definitions/controller.api.resources.users.v1.User" + } + } + }, "controller.api.services.v1.ListHostCatalogsResponse": { "type": "object", "properties": { @@ -1909,6 +2138,17 @@ } } }, + "controller.api.services.v1.ListUsersResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/controller.api.resources.users.v1.User" + } + } + } + }, "controller.api.services.v1.RemoveFromHostSetResponse": { "type": "object" }, @@ -1944,6 +2184,14 @@ } } }, + "controller.api.services.v1.UpdateUserResponse": { + "type": "object", + "properties": { + "item": { + "$ref": "#/definitions/controller.api.resources.users.v1.User" + } + } + }, "google.protobuf.FieldMask": { "type": "object", "properties": { diff --git a/internal/gen/controller/api/resources/users/user.pb.go b/internal/gen/controller/api/resources/users/user.pb.go new file mode 100644 index 000000000..cf2dfe7d8 --- /dev/null +++ b/internal/gen/controller/api/resources/users/user.pb.go @@ -0,0 +1,237 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.24.0 +// protoc v3.11.4 +// source: controller/api/resources/users/v1/user.proto + +package users + +import ( + proto "github.com/golang/protobuf/proto" + timestamp "github.com/golang/protobuf/ptypes/timestamp" + wrappers "github.com/golang/protobuf/ptypes/wrappers" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +// User contains all fields related to a User resource +type User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The ID of the Project + // Output only. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // Optional name for identification purposes + Name *wrappers.StringValue `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // Optional user-set descripton for identification purposes + Description *wrappers.StringValue `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + // The time this resource was created + // Output only. + CreatedTime *timestamp.Timestamp `protobuf:"bytes,4,opt,name=created_time,proto3" json:"created_time,omitempty"` + // The time this resource was last updated. + // Output only. + UpdatedTime *timestamp.Timestamp `protobuf:"bytes,5,opt,name=updated_time,proto3" json:"updated_time,omitempty"` + // Whether the resource is disabled + Disabled *wrappers.BoolValue `protobuf:"bytes,6,opt,name=disabled,proto3" json:"disabled,omitempty"` +} + +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_resources_users_v1_user_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_resources_users_v1_user_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 User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { + return file_controller_api_resources_users_v1_user_proto_rawDescGZIP(), []int{0} +} + +func (x *User) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *User) GetName() *wrappers.StringValue { + if x != nil { + return x.Name + } + return nil +} + +func (x *User) GetDescription() *wrappers.StringValue { + if x != nil { + return x.Description + } + return nil +} + +func (x *User) GetCreatedTime() *timestamp.Timestamp { + if x != nil { + return x.CreatedTime + } + return nil +} + +func (x *User) GetUpdatedTime() *timestamp.Timestamp { + if x != nil { + return x.UpdatedTime + } + return nil +} + +func (x *User) GetDisabled() *wrappers.BoolValue { + if x != nil { + return x.Disabled + } + return nil +} + +var File_controller_api_resources_users_v1_user_proto protoreflect.FileDescriptor + +var file_controller_api_resources_users_v1_user_proto_rawDesc = []byte{ + 0x0a, 0x2c, 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, 0x75, 0x73, 0x65, 0x72, 0x73, + 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21, + 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, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x76, + 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 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, 0x22, 0xc0, 0x02, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x30, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 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, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 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, + 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, 0x04, 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, 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, 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, 0x06, 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, 0x53, 0x5a, 0x51, 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, 0x75, + 0x73, 0x65, 0x72, 0x73, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_controller_api_resources_users_v1_user_proto_rawDescOnce sync.Once + file_controller_api_resources_users_v1_user_proto_rawDescData = file_controller_api_resources_users_v1_user_proto_rawDesc +) + +func file_controller_api_resources_users_v1_user_proto_rawDescGZIP() []byte { + file_controller_api_resources_users_v1_user_proto_rawDescOnce.Do(func() { + file_controller_api_resources_users_v1_user_proto_rawDescData = protoimpl.X.CompressGZIP(file_controller_api_resources_users_v1_user_proto_rawDescData) + }) + return file_controller_api_resources_users_v1_user_proto_rawDescData +} + +var file_controller_api_resources_users_v1_user_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_controller_api_resources_users_v1_user_proto_goTypes = []interface{}{ + (*User)(nil), // 0: controller.api.resources.users.v1.User + (*wrappers.StringValue)(nil), // 1: google.protobuf.StringValue + (*timestamp.Timestamp)(nil), // 2: google.protobuf.Timestamp + (*wrappers.BoolValue)(nil), // 3: google.protobuf.BoolValue +} +var file_controller_api_resources_users_v1_user_proto_depIdxs = []int32{ + 1, // 0: controller.api.resources.users.v1.User.name:type_name -> google.protobuf.StringValue + 1, // 1: controller.api.resources.users.v1.User.description:type_name -> google.protobuf.StringValue + 2, // 2: controller.api.resources.users.v1.User.created_time:type_name -> google.protobuf.Timestamp + 2, // 3: controller.api.resources.users.v1.User.updated_time:type_name -> google.protobuf.Timestamp + 3, // 4: controller.api.resources.users.v1.User.disabled:type_name -> google.protobuf.BoolValue + 5, // [5:5] is the sub-list for method output_type + 5, // [5:5] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_controller_api_resources_users_v1_user_proto_init() } +func file_controller_api_resources_users_v1_user_proto_init() { + if File_controller_api_resources_users_v1_user_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_controller_api_resources_users_v1_user_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*User); 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{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_controller_api_resources_users_v1_user_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_controller_api_resources_users_v1_user_proto_goTypes, + DependencyIndexes: file_controller_api_resources_users_v1_user_proto_depIdxs, + MessageInfos: file_controller_api_resources_users_v1_user_proto_msgTypes, + }.Build() + File_controller_api_resources_users_v1_user_proto = out.File + file_controller_api_resources_users_v1_user_proto_rawDesc = nil + file_controller_api_resources_users_v1_user_proto_goTypes = nil + file_controller_api_resources_users_v1_user_proto_depIdxs = nil +} diff --git a/internal/gen/controller/api/services/user_service.pb.go b/internal/gen/controller/api/services/user_service.pb.go new file mode 100644 index 000000000..b1a9b6f15 --- /dev/null +++ b/internal/gen/controller/api/services/user_service.pb.go @@ -0,0 +1,1189 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.24.0 +// protoc v3.11.4 +// source: controller/api/services/v1/user_service.proto + +package services + +import ( + context "context" + proto "github.com/golang/protobuf/proto" + _ "github.com/golang/protobuf/ptypes/wrappers" + _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" + users "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/users" + _ "google.golang.org/genproto/googleapis/api/annotations" + field_mask "google.golang.org/genproto/protobuf/field_mask" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type GetUserRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OrgId string `protobuf:"bytes,1,opt,name=org_id,json=orgId,proto3" json:"org_id,omitempty"` + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + View string `protobuf:"bytes,3,opt,name=view,proto3" json:"view,omitempty"` +} + +func (x *GetUserRequest) Reset() { + *x = GetUserRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserRequest) ProtoMessage() {} + +func (x *GetUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_user_service_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 GetUserRequest.ProtoReflect.Descriptor instead. +func (*GetUserRequest) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_user_service_proto_rawDescGZIP(), []int{0} +} + +func (x *GetUserRequest) GetOrgId() string { + if x != nil { + return x.OrgId + } + return "" +} + +func (x *GetUserRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *GetUserRequest) GetView() string { + if x != nil { + return x.View + } + return "" +} + +type GetUserResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item *users.User `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *GetUserResponse) Reset() { + *x = GetUserResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserResponse) ProtoMessage() {} + +func (x *GetUserResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[1] + 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 GetUserResponse.ProtoReflect.Descriptor instead. +func (*GetUserResponse) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_user_service_proto_rawDescGZIP(), []int{1} +} + +func (x *GetUserResponse) GetItem() *users.User { + if x != nil { + return x.Item + } + return nil +} + +type ListUsersRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OrgId string `protobuf:"bytes,1,opt,name=org_id,json=orgId,proto3" json:"org_id,omitempty"` + View string `protobuf:"bytes,2,opt,name=view,proto3" json:"view,omitempty"` +} + +func (x *ListUsersRequest) Reset() { + *x = ListUsersRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListUsersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListUsersRequest) ProtoMessage() {} + +func (x *ListUsersRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[2] + 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 ListUsersRequest.ProtoReflect.Descriptor instead. +func (*ListUsersRequest) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_user_service_proto_rawDescGZIP(), []int{2} +} + +func (x *ListUsersRequest) GetOrgId() string { + if x != nil { + return x.OrgId + } + return "" +} + +func (x *ListUsersRequest) GetView() string { + if x != nil { + return x.View + } + return "" +} + +type ListUsersResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Items []*users.User `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` +} + +func (x *ListUsersResponse) Reset() { + *x = ListUsersResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListUsersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListUsersResponse) ProtoMessage() {} + +func (x *ListUsersResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[3] + 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 ListUsersResponse.ProtoReflect.Descriptor instead. +func (*ListUsersResponse) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_user_service_proto_rawDescGZIP(), []int{3} +} + +func (x *ListUsersResponse) GetItems() []*users.User { + if x != nil { + return x.Items + } + return nil +} + +type CreateUserRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OrgId string `protobuf:"bytes,1,opt,name=org_id,json=orgId,proto3" json:"org_id,omitempty"` + Item *users.User `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *CreateUserRequest) Reset() { + *x = CreateUserRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateUserRequest) ProtoMessage() {} + +func (x *CreateUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[4] + 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 CreateUserRequest.ProtoReflect.Descriptor instead. +func (*CreateUserRequest) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_user_service_proto_rawDescGZIP(), []int{4} +} + +func (x *CreateUserRequest) GetOrgId() string { + if x != nil { + return x.OrgId + } + return "" +} + +func (x *CreateUserRequest) GetItem() *users.User { + if x != nil { + return x.Item + } + return nil +} + +type CreateUserResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty"` + Item *users.User `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *CreateUserResponse) Reset() { + *x = CreateUserResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateUserResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateUserResponse) ProtoMessage() {} + +func (x *CreateUserResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[5] + 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 CreateUserResponse.ProtoReflect.Descriptor instead. +func (*CreateUserResponse) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_user_service_proto_rawDescGZIP(), []int{5} +} + +func (x *CreateUserResponse) GetUri() string { + if x != nil { + return x.Uri + } + return "" +} + +func (x *CreateUserResponse) GetItem() *users.User { + if x != nil { + return x.Item + } + return nil +} + +type UpdateUserRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OrgId string `protobuf:"bytes,1,opt,name=org_id,json=orgId,proto3" json:"org_id,omitempty"` + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + Item *users.User `protobuf:"bytes,3,opt,name=item,proto3" json:"item,omitempty"` + UpdateMask *field_mask.FieldMask `protobuf:"bytes,4,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` +} + +func (x *UpdateUserRequest) Reset() { + *x = UpdateUserRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserRequest) ProtoMessage() {} + +func (x *UpdateUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[6] + 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 UpdateUserRequest.ProtoReflect.Descriptor instead. +func (*UpdateUserRequest) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_user_service_proto_rawDescGZIP(), []int{6} +} + +func (x *UpdateUserRequest) GetOrgId() string { + if x != nil { + return x.OrgId + } + return "" +} + +func (x *UpdateUserRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateUserRequest) GetItem() *users.User { + if x != nil { + return x.Item + } + return nil +} + +func (x *UpdateUserRequest) GetUpdateMask() *field_mask.FieldMask { + if x != nil { + return x.UpdateMask + } + return nil +} + +type UpdateUserResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item *users.User `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *UpdateUserResponse) Reset() { + *x = UpdateUserResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserResponse) ProtoMessage() {} + +func (x *UpdateUserResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[7] + 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 UpdateUserResponse.ProtoReflect.Descriptor instead. +func (*UpdateUserResponse) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_user_service_proto_rawDescGZIP(), []int{7} +} + +func (x *UpdateUserResponse) GetItem() *users.User { + if x != nil { + return x.Item + } + return nil +} + +type DeleteUserRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OrgId string `protobuf:"bytes,1,opt,name=org_id,json=orgId,proto3" json:"org_id,omitempty"` + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *DeleteUserRequest) Reset() { + *x = DeleteUserRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteUserRequest) ProtoMessage() {} + +func (x *DeleteUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[8] + 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 DeleteUserRequest.ProtoReflect.Descriptor instead. +func (*DeleteUserRequest) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_user_service_proto_rawDescGZIP(), []int{8} +} + +func (x *DeleteUserRequest) GetOrgId() string { + if x != nil { + return x.OrgId + } + return "" +} + +func (x *DeleteUserRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type DeleteUserResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Existed bool `protobuf:"varint,1,opt,name=existed,proto3" json:"existed,omitempty"` +} + +func (x *DeleteUserResponse) Reset() { + *x = DeleteUserResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteUserResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteUserResponse) ProtoMessage() {} + +func (x *DeleteUserResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_user_service_proto_msgTypes[9] + 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 DeleteUserResponse.ProtoReflect.Descriptor instead. +func (*DeleteUserResponse) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_user_service_proto_rawDescGZIP(), []int{9} +} + +func (x *DeleteUserResponse) GetExisted() bool { + if x != nil { + return x.Existed + } + return false +} + +var File_controller_api_services_v1_user_service_proto protoreflect.FileDescriptor + +var file_controller_api_services_v1_user_service_proto_rawDesc = []byte{ + 0x0a, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x1a, 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, 0x1a, 0x2c, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2f, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 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, 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, 0x2c, 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, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4b, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x12, 0x0a, 0x04, 0x76, 0x69, 0x65, 0x77, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x76, 0x69, 0x65, 0x77, 0x22, 0x4e, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 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, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, + 0x69, 0x74, 0x65, 0x6d, 0x22, 0x3d, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x76, 0x69, 0x65, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x76, + 0x69, 0x65, 0x77, 0x22, 0x52, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 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, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x67, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, + 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, + 0x67, 0x49, 0x64, 0x12, 0x3b, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x27, 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, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x22, 0x63, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x3b, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 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, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xb4, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6f, + 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, + 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x3b, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x27, 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, 0x75, 0x73, 0x65, 0x72, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, + 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, + 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x51, 0x0a, 0x12, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x27, 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, 0x75, 0x73, 0x65, 0x72, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, + 0x3a, 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x2e, 0x0a, 0x12, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 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, 0xe4, 0x06, 0x0a, 0x0b, + 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xa5, 0x01, 0x0a, 0x07, + 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x2a, 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, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 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, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x12, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x72, + 0x67, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x75, 0x73, 0x65, 0x72, + 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x14, 0x12, + 0x12, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x55, + 0x73, 0x65, 0x72, 0x12, 0x9d, 0x01, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x73, 0x12, 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, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 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, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x72, 0x67, 0x73, + 0x2f, 0x7b, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x92, + 0x41, 0x11, 0x12, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x55, 0x73, + 0x65, 0x72, 0x73, 0x12, 0xb2, 0x01, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 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, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 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, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x45, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x6f, + 0x72, 0x67, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, + 0x17, 0x12, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, + 0x67, 0x6c, 0x65, 0x20, 0x55, 0x73, 0x65, 0x72, 0x12, 0xb0, 0x01, 0x0a, 0x0a, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 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, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 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, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x43, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x32, 0x1c, + 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x72, 0x67, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, + 0x7d, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04, 0x69, 0x74, + 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x10, 0x12, 0x0e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x55, 0x73, 0x65, 0x72, 0x12, 0xa4, 0x01, 0x0a, 0x0a, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 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, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 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, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x37, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1e, 0x2a, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x72, 0x67, 0x73, 0x2f, 0x7b, 0x6f, 0x72, 0x67, + 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x92, + 0x41, 0x10, 0x12, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x55, 0x73, + 0x65, 0x72, 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 ( + file_controller_api_services_v1_user_service_proto_rawDescOnce sync.Once + file_controller_api_services_v1_user_service_proto_rawDescData = file_controller_api_services_v1_user_service_proto_rawDesc +) + +func file_controller_api_services_v1_user_service_proto_rawDescGZIP() []byte { + file_controller_api_services_v1_user_service_proto_rawDescOnce.Do(func() { + file_controller_api_services_v1_user_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_controller_api_services_v1_user_service_proto_rawDescData) + }) + return file_controller_api_services_v1_user_service_proto_rawDescData +} + +var file_controller_api_services_v1_user_service_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_controller_api_services_v1_user_service_proto_goTypes = []interface{}{ + (*GetUserRequest)(nil), // 0: controller.api.services.v1.GetUserRequest + (*GetUserResponse)(nil), // 1: controller.api.services.v1.GetUserResponse + (*ListUsersRequest)(nil), // 2: controller.api.services.v1.ListUsersRequest + (*ListUsersResponse)(nil), // 3: controller.api.services.v1.ListUsersResponse + (*CreateUserRequest)(nil), // 4: controller.api.services.v1.CreateUserRequest + (*CreateUserResponse)(nil), // 5: controller.api.services.v1.CreateUserResponse + (*UpdateUserRequest)(nil), // 6: controller.api.services.v1.UpdateUserRequest + (*UpdateUserResponse)(nil), // 7: controller.api.services.v1.UpdateUserResponse + (*DeleteUserRequest)(nil), // 8: controller.api.services.v1.DeleteUserRequest + (*DeleteUserResponse)(nil), // 9: controller.api.services.v1.DeleteUserResponse + (*users.User)(nil), // 10: controller.api.resources.users.v1.User + (*field_mask.FieldMask)(nil), // 11: google.protobuf.FieldMask +} +var file_controller_api_services_v1_user_service_proto_depIdxs = []int32{ + 10, // 0: controller.api.services.v1.GetUserResponse.item:type_name -> controller.api.resources.users.v1.User + 10, // 1: controller.api.services.v1.ListUsersResponse.items:type_name -> controller.api.resources.users.v1.User + 10, // 2: controller.api.services.v1.CreateUserRequest.item:type_name -> controller.api.resources.users.v1.User + 10, // 3: controller.api.services.v1.CreateUserResponse.item:type_name -> controller.api.resources.users.v1.User + 10, // 4: controller.api.services.v1.UpdateUserRequest.item:type_name -> controller.api.resources.users.v1.User + 11, // 5: controller.api.services.v1.UpdateUserRequest.update_mask:type_name -> google.protobuf.FieldMask + 10, // 6: controller.api.services.v1.UpdateUserResponse.item:type_name -> controller.api.resources.users.v1.User + 0, // 7: controller.api.services.v1.UserService.GetUser:input_type -> controller.api.services.v1.GetUserRequest + 2, // 8: controller.api.services.v1.UserService.ListUsers:input_type -> controller.api.services.v1.ListUsersRequest + 4, // 9: controller.api.services.v1.UserService.CreateUser:input_type -> controller.api.services.v1.CreateUserRequest + 6, // 10: controller.api.services.v1.UserService.UpdateUser:input_type -> controller.api.services.v1.UpdateUserRequest + 8, // 11: controller.api.services.v1.UserService.DeleteUser:input_type -> controller.api.services.v1.DeleteUserRequest + 1, // 12: controller.api.services.v1.UserService.GetUser:output_type -> controller.api.services.v1.GetUserResponse + 3, // 13: controller.api.services.v1.UserService.ListUsers:output_type -> controller.api.services.v1.ListUsersResponse + 5, // 14: controller.api.services.v1.UserService.CreateUser:output_type -> controller.api.services.v1.CreateUserResponse + 7, // 15: controller.api.services.v1.UserService.UpdateUser:output_type -> controller.api.services.v1.UpdateUserResponse + 9, // 16: controller.api.services.v1.UserService.DeleteUser:output_type -> controller.api.services.v1.DeleteUserResponse + 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 +} + +func init() { file_controller_api_services_v1_user_service_proto_init() } +func file_controller_api_services_v1_user_service_proto_init() { + if File_controller_api_services_v1_user_service_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_controller_api_services_v1_user_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_user_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_user_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListUsersRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_user_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListUsersResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_user_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateUserRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_user_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateUserResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_user_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_user_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_user_service_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteUserRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_user_service_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteUserResponse); 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{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_controller_api_services_v1_user_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 10, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_controller_api_services_v1_user_service_proto_goTypes, + DependencyIndexes: file_controller_api_services_v1_user_service_proto_depIdxs, + MessageInfos: file_controller_api_services_v1_user_service_proto_msgTypes, + }.Build() + File_controller_api_services_v1_user_service_proto = out.File + file_controller_api_services_v1_user_service_proto_rawDesc = nil + file_controller_api_services_v1_user_service_proto_goTypes = nil + file_controller_api_services_v1_user_service_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// UserServiceClient is the client API for UserService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type UserServiceClient interface { + // GetUser returns a stored User if present. The provided request + // must include the org and user id for the user being retrieved. If + // any of those ids are missing, malformed or reference a non existing + // resource an error is returned. + GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) + // ListUsers returns a list of stored users which exist inside the org + // referenced inside the request. The request must include the org id for + // the users being retrieved. If the org id is missing, malformed, or + // reference a non existing organization, an error is returned. + ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (*ListUsersResponse, error) + // CreateUser creates and stores a user in watchtower. The provided + // request must include the org id in which the user will be created. + // If the org id is missing, malformed or references a non existing + // organization, an error is returned. If a name is provided that is in + // use in another user in the same organization, an error is returned. + CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error) + // UpdateUser updates an existing user in watchtower. The provided + // user must not have any read only fields set. The update mask must be + // included in the request and contain at least 1 mutable field. To unset + // a field's value, include the field in the update mask and don't set it + // in the provided user. An error is returned if either the organization + // or user ids are missing or reference a non existing resource. An error + // is also returned if the request attempts to update the name to one that is + // already in use in this organization. + UpdateUser(ctx context.Context, in *UpdateUserRequest, opts ...grpc.CallOption) (*UpdateUserResponse, error) + // DeleteUser removes a user from Watchtower. If the provided org or user ids + // are malformed or not provided an error is returned. No error is returned + // if either ids reference resources that do not exist as the response itself + // specifies if the resource existed before the DeleteUser request was + // received. + DeleteUser(ctx context.Context, in *DeleteUserRequest, opts ...grpc.CallOption) (*DeleteUserResponse, error) +} + +type userServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewUserServiceClient(cc grpc.ClientConnInterface) UserServiceClient { + return &userServiceClient{cc} +} + +func (c *userServiceClient) GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) { + out := new(GetUserResponse) + err := c.cc.Invoke(ctx, "/controller.api.services.v1.UserService/GetUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (*ListUsersResponse, error) { + out := new(ListUsersResponse) + err := c.cc.Invoke(ctx, "/controller.api.services.v1.UserService/ListUsers", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error) { + out := new(CreateUserResponse) + err := c.cc.Invoke(ctx, "/controller.api.services.v1.UserService/CreateUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) UpdateUser(ctx context.Context, in *UpdateUserRequest, opts ...grpc.CallOption) (*UpdateUserResponse, error) { + out := new(UpdateUserResponse) + err := c.cc.Invoke(ctx, "/controller.api.services.v1.UserService/UpdateUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) DeleteUser(ctx context.Context, in *DeleteUserRequest, opts ...grpc.CallOption) (*DeleteUserResponse, error) { + out := new(DeleteUserResponse) + err := c.cc.Invoke(ctx, "/controller.api.services.v1.UserService/DeleteUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UserServiceServer is the server API for UserService service. +type UserServiceServer interface { + // GetUser returns a stored User if present. The provided request + // must include the org and user id for the user being retrieved. If + // any of those ids are missing, malformed or reference a non existing + // resource an error is returned. + GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) + // ListUsers returns a list of stored users which exist inside the org + // referenced inside the request. The request must include the org id for + // the users being retrieved. If the org id is missing, malformed, or + // reference a non existing organization, an error is returned. + ListUsers(context.Context, *ListUsersRequest) (*ListUsersResponse, error) + // CreateUser creates and stores a user in watchtower. The provided + // request must include the org id in which the user will be created. + // If the org id is missing, malformed or references a non existing + // organization, an error is returned. If a name is provided that is in + // use in another user in the same organization, an error is returned. + CreateUser(context.Context, *CreateUserRequest) (*CreateUserResponse, error) + // UpdateUser updates an existing user in watchtower. The provided + // user must not have any read only fields set. The update mask must be + // included in the request and contain at least 1 mutable field. To unset + // a field's value, include the field in the update mask and don't set it + // in the provided user. An error is returned if either the organization + // or user ids are missing or reference a non existing resource. An error + // is also returned if the request attempts to update the name to one that is + // already in use in this organization. + UpdateUser(context.Context, *UpdateUserRequest) (*UpdateUserResponse, error) + // DeleteUser removes a user from Watchtower. If the provided org or user ids + // are malformed or not provided an error is returned. No error is returned + // if either ids reference resources that do not exist as the response itself + // specifies if the resource existed before the DeleteUser request was + // received. + DeleteUser(context.Context, *DeleteUserRequest) (*DeleteUserResponse, error) +} + +// UnimplementedUserServiceServer can be embedded to have forward compatible implementations. +type UnimplementedUserServiceServer struct { +} + +func (*UnimplementedUserServiceServer) GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented") +} +func (*UnimplementedUserServiceServer) ListUsers(context.Context, *ListUsersRequest) (*ListUsersResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListUsers not implemented") +} +func (*UnimplementedUserServiceServer) CreateUser(context.Context, *CreateUserRequest) (*CreateUserResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateUser not implemented") +} +func (*UnimplementedUserServiceServer) UpdateUser(context.Context, *UpdateUserRequest) (*UpdateUserResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateUser not implemented") +} +func (*UnimplementedUserServiceServer) DeleteUser(context.Context, *DeleteUserRequest) (*DeleteUserResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteUser not implemented") +} + +func RegisterUserServiceServer(s *grpc.Server, srv UserServiceServer) { + s.RegisterService(&_UserService_serviceDesc, srv) +} + +func _UserService_GetUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).GetUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/controller.api.services.v1.UserService/GetUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).GetUser(ctx, req.(*GetUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_ListUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListUsersRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).ListUsers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/controller.api.services.v1.UserService/ListUsers", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).ListUsers(ctx, req.(*ListUsersRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_CreateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).CreateUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/controller.api.services.v1.UserService/CreateUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).CreateUser(ctx, req.(*CreateUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_UpdateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).UpdateUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/controller.api.services.v1.UserService/UpdateUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).UpdateUser(ctx, req.(*UpdateUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_DeleteUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).DeleteUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/controller.api.services.v1.UserService/DeleteUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).DeleteUser(ctx, req.(*DeleteUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _UserService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "controller.api.services.v1.UserService", + HandlerType: (*UserServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetUser", + Handler: _UserService_GetUser_Handler, + }, + { + MethodName: "ListUsers", + Handler: _UserService_ListUsers_Handler, + }, + { + MethodName: "CreateUser", + Handler: _UserService_CreateUser_Handler, + }, + { + MethodName: "UpdateUser", + Handler: _UserService_UpdateUser_Handler, + }, + { + MethodName: "DeleteUser", + Handler: _UserService_DeleteUser_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "controller/api/services/v1/user_service.proto", +} diff --git a/internal/gen/controller/api/services/user_service.pb.gw.go b/internal/gen/controller/api/services/user_service.pb.gw.go new file mode 100644 index 000000000..64e3c3eec --- /dev/null +++ b/internal/gen/controller/api/services/user_service.pb.gw.go @@ -0,0 +1,770 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: controller/api/services/v1/user_service.proto + +/* +Package services is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package services + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +var ( + filter_UserService_GetUser_0 = &utilities.DoubleArray{Encoding: map[string]int{"org_id": 0, "id": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} +) + +func request_UserService_GetUser_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetUserRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["org_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id") + } + + protoReq.OrgId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", 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) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_GetUser_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.GetUser(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_UserService_GetUser_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetUserRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["org_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id") + } + + protoReq.OrgId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", 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) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_GetUser_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.GetUser(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_UserService_ListUsers_0 = &utilities.DoubleArray{Encoding: map[string]int{"org_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_UserService_ListUsers_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListUsersRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["org_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id") + } + + protoReq.OrgId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_ListUsers_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ListUsers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_UserService_ListUsers_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListUsersRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["org_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id") + } + + protoReq.OrgId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_ListUsers_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ListUsers(ctx, &protoReq) + return msg, metadata, err + +} + +func request_UserService_CreateUser_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CreateUserRequest + 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.Item); 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["org_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id") + } + + protoReq.OrgId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", err) + } + + msg, err := client.CreateUser(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_UserService_CreateUser_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CreateUserRequest + 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.Item); 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["org_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id") + } + + protoReq.OrgId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", err) + } + + msg, err := server.CreateUser(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_UserService_UpdateUser_0 = &utilities.DoubleArray{Encoding: map[string]int{"item": 0, "org_id": 1, "id": 2}, Base: []int{1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 1, 1, 2, 3, 4}} +) + +func request_UserService_UpdateUser_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateUserRequest + 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.Item); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { + _, md := descriptor.ForMessage(protoReq.Item) + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), md); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.UpdateMask = fieldMask + } + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["org_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id") + } + + protoReq.OrgId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", 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) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_UpdateUser_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UpdateUser(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_UserService_UpdateUser_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateUserRequest + 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.Item); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { + _, md := descriptor.ForMessage(protoReq.Item) + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), md); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.UpdateMask = fieldMask + } + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["org_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id") + } + + protoReq.OrgId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", 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) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_UpdateUser_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.UpdateUser(ctx, &protoReq) + return msg, metadata, err + +} + +func request_UserService_DeleteUser_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DeleteUserRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["org_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id") + } + + protoReq.OrgId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", 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.DeleteUser(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_UserService_DeleteUser_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DeleteUserRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["org_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id") + } + + protoReq.OrgId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", 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.DeleteUser(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterUserServiceHandlerServer registers the http handlers for service UserService to "mux". +// UnaryRPC :call UserServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +func RegisterUserServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server UserServiceServer) error { + + mux.Handle("GET", pattern_UserService_GetUser_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_UserService_GetUser_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_GetUser_0(ctx, mux, outboundMarshaler, w, req, response_UserService_GetUser_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_UserService_ListUsers_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_UserService_ListUsers_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_ListUsers_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_UserService_CreateUser_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_UserService_CreateUser_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_CreateUser_0(ctx, mux, outboundMarshaler, w, req, response_UserService_CreateUser_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PATCH", pattern_UserService_UpdateUser_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_UserService_UpdateUser_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_UpdateUser_0(ctx, mux, outboundMarshaler, w, req, response_UserService_UpdateUser_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_UserService_DeleteUser_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_UserService_DeleteUser_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_DeleteUser_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterUserServiceHandlerFromEndpoint is same as RegisterUserServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterUserServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterUserServiceHandler(ctx, mux, conn) +} + +// RegisterUserServiceHandler registers the http handlers for service UserService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterUserServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterUserServiceHandlerClient(ctx, mux, NewUserServiceClient(conn)) +} + +// RegisterUserServiceHandlerClient registers the http handlers for service UserService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "UserServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "UserServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "UserServiceClient" to call the correct interceptors. +func RegisterUserServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client UserServiceClient) error { + + mux.Handle("GET", pattern_UserService_GetUser_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_UserService_GetUser_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_GetUser_0(ctx, mux, outboundMarshaler, w, req, response_UserService_GetUser_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_UserService_ListUsers_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_UserService_ListUsers_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_ListUsers_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_UserService_CreateUser_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_UserService_CreateUser_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_CreateUser_0(ctx, mux, outboundMarshaler, w, req, response_UserService_CreateUser_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PATCH", pattern_UserService_UpdateUser_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_UserService_UpdateUser_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_UpdateUser_0(ctx, mux, outboundMarshaler, w, req, response_UserService_UpdateUser_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_UserService_DeleteUser_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_UserService_DeleteUser_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_DeleteUser_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +type response_UserService_GetUser_0 struct { + proto.Message +} + +func (m response_UserService_GetUser_0) XXX_ResponseBody() interface{} { + response := m.Message.(*GetUserResponse) + return response.Item +} + +type response_UserService_CreateUser_0 struct { + proto.Message +} + +func (m response_UserService_CreateUser_0) XXX_ResponseBody() interface{} { + response := m.Message.(*CreateUserResponse) + return response.Item +} + +type response_UserService_UpdateUser_0 struct { + proto.Message +} + +func (m response_UserService_UpdateUser_0) XXX_ResponseBody() interface{} { + response := m.Message.(*UpdateUserResponse) + return response.Item +} + +var ( + pattern_UserService_GetUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "orgs", "org_id", "users", "id"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_UserService_ListUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"v1", "orgs", "org_id", "users"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_UserService_CreateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"v1", "orgs", "org_id", "users"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_UserService_UpdateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "orgs", "org_id", "users", "id"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_UserService_DeleteUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "orgs", "org_id", "users", "id"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_UserService_GetUser_0 = runtime.ForwardResponseMessage + + forward_UserService_ListUsers_0 = runtime.ForwardResponseMessage + + forward_UserService_CreateUser_0 = runtime.ForwardResponseMessage + + forward_UserService_UpdateUser_0 = runtime.ForwardResponseMessage + + forward_UserService_DeleteUser_0 = runtime.ForwardResponseMessage +) diff --git a/internal/proto/local/controller/api/resources/users/v1/user.proto b/internal/proto/local/controller/api/resources/users/v1/user.proto new file mode 100644 index 000000000..2e58969fb --- /dev/null +++ b/internal/proto/local/controller/api/resources/users/v1/user.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; + +package controller.api.resources.users.v1; + +option go_package = "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/users;users"; + +import "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; + +// User contains all fields related to a User resource +message User { + // The ID of the Project + // Output only. + string id = 1; + + // Optional name for identification purposes + google.protobuf.StringValue name = 2; + + // Optional user-set descripton for identification purposes + google.protobuf.StringValue description = 3; + + // The time this resource was created + // Output only. + google.protobuf.Timestamp created_time = 4 [json_name="created_time"]; + + // The time this resource was last updated. + // Output only. + google.protobuf.Timestamp updated_time = 5 [json_name="updated_time"]; + + // Whether the resource is disabled + google.protobuf.BoolValue disabled = 6; +} diff --git a/internal/proto/local/controller/api/services/v1/user_service.proto b/internal/proto/local/controller/api/services/v1/user_service.proto new file mode 100644 index 000000000..8a5914171 --- /dev/null +++ b/internal/proto/local/controller/api/services/v1/user_service.proto @@ -0,0 +1,139 @@ +syntax = "proto3"; + +package controller.api.services.v1; + +option go_package = "github.com/hashicorp/watchtower/internal/gen/controller/api/services;services"; + +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/users/v1/user.proto"; + +service UserService { + + // GetUser returns a stored User if present. The provided request + // must include the org and user id for the user being retrieved. If + // any of those ids are missing, malformed or reference a non existing + // resource an error is returned. + rpc GetUser(GetUserRequest) returns (GetUserResponse) { + option (google.api.http) = { + get: "/v1/orgs/{org_id}/users/{id}" + response_body: "item" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + summary: "Gets a single User" + }; + } + + // ListUsers returns a list of stored users which exist inside the org + // referenced inside the request. The request must include the org id for + // the users being retrieved. If the org id is missing, malformed, or + // reference a non existing organization, an error is returned. + rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) { + option (google.api.http) = { + get: "/v1/orgs/{org_id}/users" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + summary: "Lists all Users" + }; + } + + // CreateUser creates and stores a user in watchtower. The provided + // request must include the org id in which the user will be created. + // If the org id is missing, malformed or references a non existing + // organization, an error is returned. If a name is provided that is in + // use in another user in the same organization, an error is returned. + rpc CreateUser(CreateUserRequest) returns (CreateUserResponse) { + option (google.api.http) = { + post: "/v1/orgs/{org_id}/users" + body: "item" + response_body: "item" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + summary: "Creates a single User" + }; + } + + // UpdateUser updates an existing user in watchtower. The provided + // user must not have any read only fields set. The update mask must be + // included in the request and contain at least 1 mutable field. To unset + // a field's value, include the field in the update mask and don't set it + // in the provided user. An error is returned if either the organization + // or user ids are missing or reference a non existing resource. An error + // is also returned if the request attempts to update the name to one that is + // already in use in this organization. + rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse) { + option (google.api.http) = { + patch: "/v1/orgs/{org_id}/users/{id}" + body: "item" + response_body: "item" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + summary: "Updates a User" + }; + } + + // DeleteUser removes a user from Watchtower. If the provided org or user ids + // are malformed or not provided an error is returned. No error is returned + // if either ids reference resources that do not exist as the response itself + // specifies if the resource existed before the DeleteUser request was + // received. + rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse) { + option (google.api.http) = { + delete: "/v1/orgs/{org_id}/users/{id}" + }; + option (grpc.gateway.protoc_gen_swagger.options.openapiv2_operation) = { + summary: "Deletes a User" + }; + } +} + +message GetUserRequest { + string org_id = 1; + string id = 2; + string view = 3; +} + +message GetUserResponse { + resources.users.v1.User item = 1; +} + +message ListUsersRequest { + string org_id = 1; + string view = 2; +} + +message ListUsersResponse { + repeated resources.users.v1.User items = 1; +} + +message CreateUserRequest { + string org_id = 1; + resources.users.v1.User item = 2; +} + +message CreateUserResponse { + string uri = 1; + resources.users.v1.User item = 2; +} + +message UpdateUserRequest { + string org_id = 1; + string id = 2; + resources.users.v1.User item = 3; + google.protobuf.FieldMask update_mask = 4; +} + +message UpdateUserResponse { + resources.users.v1.User item = 1; +} + +message DeleteUserRequest { + string org_id = 1; + string id = 2; +} + +message DeleteUserResponse { + bool existed = 1; +} diff --git a/internal/servers/controller/cors_test.go b/internal/servers/controller/cors_test.go index fbc711a57..d7f18e7fc 100644 --- a/internal/servers/controller/cors_test.go +++ b/internal/servers/controller/cors_test.go @@ -162,9 +162,10 @@ func TestHandler_CORS(t *testing.T) { // Create a client with the right address client := tc.Client() client.SetAddr(tc.ApiAddrs()[c.listenerNum-1]) + client.SetOrg("o_1234567890") // Create the request - req, err := client.NewRequest(tc.Context(), c.method, "orgs/o_1234567890/projects", nil) + req, err := client.NewRequest(tc.Context(), c.method, "projects", nil) assert.NoError(t, err) // Append headers diff --git a/internal/servers/controller/handler.go b/internal/servers/controller/handler.go index 195b68740..e9e36fc17 100644 --- a/internal/servers/controller/handler.go +++ b/internal/servers/controller/handler.go @@ -21,6 +21,7 @@ import ( "github.com/hashicorp/watchtower/internal/servers/controller/handlers/host_sets" "github.com/hashicorp/watchtower/internal/servers/controller/handlers/hosts" "github.com/hashicorp/watchtower/internal/servers/controller/handlers/projects" + "github.com/hashicorp/watchtower/internal/servers/controller/handlers/users" ) type HandlerProperties struct { @@ -84,6 +85,13 @@ func handleGrpcGateway(c *Controller) (http.Handler, error) { if err := services.RegisterProjectServiceHandlerServer(ctx, mux, ps); err != nil { return nil, fmt.Errorf("failed to register project service handler: %w", err) } + us, err := users.NewService(c.IamRepoFn) + if err != nil { + return nil, fmt.Errorf("failed to create user handler service: %w", err) + } + if err := services.RegisterUserServiceHandlerServer(ctx, mux, us); err != nil { + return nil, fmt.Errorf("failed to register user service handler: %w", err) + } return mux, nil } diff --git a/internal/servers/controller/handlers/host_catalogs/host_catalog_service.go b/internal/servers/controller/handlers/host_catalogs/host_catalog_service.go index 7846ae65b..a66f60d9a 100644 --- a/internal/servers/controller/handlers/host_catalogs/host_catalog_service.go +++ b/internal/servers/controller/handlers/host_catalogs/host_catalog_service.go @@ -9,6 +9,7 @@ import ( pb "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/hosts" pbs "github.com/hashicorp/watchtower/internal/gen/controller/api/services" "github.com/hashicorp/watchtower/internal/host/static" + "github.com/hashicorp/watchtower/internal/iam" "github.com/hashicorp/watchtower/internal/servers/controller/common" "github.com/hashicorp/watchtower/internal/servers/controller/handlers" "google.golang.org/grpc/codes" @@ -390,10 +391,10 @@ func validateAncestors(r ancestorProvider) map[string]string { return badFields } - if !validId(r.GetOrgId(), "o_") { + if !validId(r.GetOrgId(), iam.OrganizationScope.Prefix()+"_") { badFields[orgIdFieldName] = "The field is incorrectly formatted." } - if !validId(r.GetProjectId(), "p_") { + if !validId(r.GetProjectId(), iam.ProjectScope.Prefix()+"_") { badFields[projectIdFieldName] = "The field is incorrectly formatted." } return badFields diff --git a/internal/servers/controller/handlers/projects/project_service.go b/internal/servers/controller/handlers/projects/project_service.go index b6ab812af..466f6e583 100644 --- a/internal/servers/controller/handlers/projects/project_service.go +++ b/internal/servers/controller/handlers/projects/project_service.go @@ -16,6 +16,8 @@ import ( "google.golang.org/protobuf/types/known/wrapperspb" ) +const orgIdFieldName = "org_id" + var ( reInvalidID = regexp.MustCompile("[^A-Za-z0-9]") // TODO(ICU-28): Find a way to auto update these names and enforce the mappings between wire and storage. @@ -221,7 +223,7 @@ func toProto(in *iam.Scope) *pb.Project { // * There are no conflicting parameters provided func validateGetRequest(req *pbs.GetProjectRequest) error { badFields := validateAncestors(req) - if !validId(req.GetId(), "p_") { + if !validId(req.GetId(), iam.ProjectScope.Prefix()+"_") { badFields["id"] = "Invalid formatted project id." } if len(badFields) > 0 { @@ -250,7 +252,7 @@ func validateCreateRequest(req *pbs.CreateProjectRequest) error { func validateUpdateRequest(req *pbs.UpdateProjectRequest) error { badFields := validateAncestors(req) - if !validId(req.GetId(), "p_") { + if !validId(req.GetId(), iam.ProjectScope.Prefix()+"_") { badFields["project_id"] = "Improperly formatted path identifier." } if req.GetUpdateMask() == nil { @@ -284,7 +286,7 @@ func validateUpdateRequest(req *pbs.UpdateProjectRequest) error { func validateDeleteRequest(req *pbs.DeleteProjectRequest) error { badFields := validateAncestors(req) - if !validId(req.GetId(), "p_") { + if !validId(req.GetId(), iam.ProjectScope.Prefix()+"_") { badFields["id"] = "Incorrectly formatted project." } if len(badFields) > 0 { @@ -308,10 +310,10 @@ type ancestorProvider interface { // validateAncestors verifies that the ancestors of this call are properly set and provided. func validateAncestors(r ancestorProvider) map[string]string { if r.GetOrgId() == "" { - return map[string]string{"org_id": "Missing organization id."} + return map[string]string{orgIdFieldName: "Missing organization id."} } if !validId(r.GetOrgId(), iam.OrganizationScope.Prefix()+"_") { - return map[string]string{"org_id": "Improperly formatted identifier."} + return map[string]string{orgIdFieldName: "Improperly formatted identifier."} } return map[string]string{} } diff --git a/internal/servers/controller/handlers/users/user_service.go b/internal/servers/controller/handlers/users/user_service.go new file mode 100644 index 000000000..8ab42d744 --- /dev/null +++ b/internal/servers/controller/handlers/users/user_service.go @@ -0,0 +1,323 @@ +package users + +import ( + "context" + "errors" + "fmt" + "regexp" + "strings" + + "github.com/hashicorp/watchtower/internal/db" + pb "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/users" + pbs "github.com/hashicorp/watchtower/internal/gen/controller/api/services" + "github.com/hashicorp/watchtower/internal/iam" + "github.com/hashicorp/watchtower/internal/servers/controller/handlers" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/wrapperspb" +) + +const orgIdFieldName = "org_id" + +var ( + reInvalidID = regexp.MustCompile("[^A-Za-z0-9]") + // TODO(ICU-28): Find a way to auto update these names and enforce the mappings between wire and storage. + wireToStorageMask = map[string]string{ + "name": "Name", + "description": "Description", + } +) + +// Service handles request as described by the pbs.UserServiceServer interface. +type Service struct { + repoFn func() (*iam.Repository, error) +} + +// NewService returns a user service which handles user related requests to watchtower. +func NewService(repo func() (*iam.Repository, error)) (Service, error) { + if repo == nil { + return Service{}, fmt.Errorf("nil iam repostiroy provided") + } + return Service{repoFn: repo}, nil +} + +var _ pbs.UserServiceServer = Service{} + +// CreateUser is not yet implemented but will implement the interface pbs.UserServiceServer. +func (s Service) ListUsers(context.Context, *pbs.ListUsersRequest) (*pbs.ListUsersResponse, error) { + return nil, status.Error(codes.Unimplemented, "List not enabled for this resource.") +} + +// GetUsers implements the interface pbs.UserServiceServer. +func (s Service) GetUser(ctx context.Context, req *pbs.GetUserRequest) (*pbs.GetUserResponse, error) { + if err := validateGetRequest(req); err != nil { + return nil, err + } + u, err := s.getFromRepo(ctx, req.GetId()) + if err != nil { + return nil, err + } + return &pbs.GetUserResponse{Item: u}, nil +} + +// CreateUser implements the interface pbs.UserServiceServer. +func (s Service) CreateUser(ctx context.Context, req *pbs.CreateUserRequest) (*pbs.CreateUserResponse, error) { + if err := validateCreateRequest(req); err != nil { + return nil, err + } + u, err := s.createInRepo(ctx, req.GetOrgId(), req.GetItem()) + if err != nil { + return nil, err + } + return &pbs.CreateUserResponse{Item: u, Uri: fmt.Sprintf("orgs/%s/users/%s", req.GetOrgId(), u.GetId())}, nil +} + +// UpdateUser implements the interface pbs.UserServiceServer. +func (s Service) UpdateUser(ctx context.Context, req *pbs.UpdateUserRequest) (*pbs.UpdateUserResponse, error) { + if err := validateUpdateRequest(req); err != nil { + return nil, err + } + u, err := s.updateInRepo(ctx, req.GetOrgId(), req.GetId(), req.GetUpdateMask().GetPaths(), req.GetItem()) + if err != nil { + return nil, err + } + return &pbs.UpdateUserResponse{Item: u}, nil +} + +// DeleteUser implements the interface pbs.UserServiceServer. +func (s Service) DeleteUser(ctx context.Context, req *pbs.DeleteUserRequest) (*pbs.DeleteUserResponse, error) { + if err := validateDeleteRequest(req); err != nil { + return nil, err + } + existed, err := s.deleteFromRepo(ctx, req.GetId()) + if err != nil { + return nil, err + } + return &pbs.DeleteUserResponse{Existed: existed}, nil +} + +func (s Service) getFromRepo(ctx context.Context, id string) (*pb.User, error) { + repo, err := s.repoFn() + if err != nil { + return nil, err + } + u, err := repo.LookupUser(ctx, id) + if err != nil { + if errors.Is(err, db.ErrRecordNotFound) { + return nil, handlers.NotFoundErrorf("User %q doesn't exist.", id) + } + return nil, err + } + if u == nil { + return nil, handlers.NotFoundErrorf("User %q doesn't exist.", id) + } + return toProto(u), nil +} + +func (s Service) createInRepo(ctx context.Context, orgId string, item *pb.User) (*pb.User, error) { + var opts []iam.Option + if item.GetName() != nil { + opts = append(opts, iam.WithName(item.GetName().GetValue())) + } + if item.GetDescription() != nil { + opts = append(opts, iam.WithDescription(item.GetDescription().GetValue())) + } + u, err := iam.NewUser(orgId, opts...) + if err != nil { + return nil, status.Errorf(codes.Internal, "Unable to build user for creation: %v.", err) + } + repo, err := s.repoFn() + if err != nil { + return nil, err + } + out, err := repo.CreateUser(ctx, u) + if err != nil { + return nil, status.Errorf(codes.Internal, "Unable to create user: %v.", err) + } + if out == nil { + return nil, status.Error(codes.Internal, "Unable to create user but no error returned from repository.") + } + return toProto(out), nil +} + +func (s Service) updateInRepo(ctx context.Context, orgId, id string, mask []string, item *pb.User) (*pb.User, error) { + var opts []iam.Option + if desc := item.GetDescription(); desc != nil { + opts = append(opts, iam.WithDescription(desc.GetValue())) + } + if name := item.GetName(); name != nil { + opts = append(opts, iam.WithName(name.GetValue())) + } + u, err := iam.NewUser(orgId, opts...) + if err != nil { + return nil, status.Errorf(codes.Internal, "Unable to build user for update: %v.", err) + } + u.PublicId = id + dbMask, err := toDbUpdateMask(mask) + if err != nil { + return nil, err + } + if len(dbMask) == 0 { + return nil, handlers.InvalidArgumentErrorf("No valid fields included in the update mask.", map[string]string{"update_mask": "No valid paths provided in the update mask."}) + } + repo, err := s.repoFn() + if err != nil { + return nil, err + } + out, rowsUpdated, err := repo.UpdateUser(ctx, u, dbMask) + if err != nil { + return nil, status.Errorf(codes.Internal, "Unable to update user: %v.", err) + } + if rowsUpdated == 0 { + return nil, handlers.NotFoundErrorf("User %q doesn't exist.", id) + } + return toProto(out), nil +} + +func (s Service) deleteFromRepo(ctx context.Context, id string) (bool, error) { + repo, err := s.repoFn() + if err != nil { + return false, err + } + rows, err := repo.DeleteUser(ctx, id) + if err != nil { + if errors.Is(err, db.ErrRecordNotFound) { + return false, nil + } + return false, status.Errorf(codes.Internal, "Unable to delete user: %v.", err) + } + return rows > 0, nil +} + +// toDbUpdateMask converts the wire format's FieldMask into a list of strings containing FieldMask paths used +func toDbUpdateMask(paths []string) ([]string, error) { + var dbPaths []string + var invalid []string + for _, p := range paths { + for _, f := range strings.Split(p, ",") { + if dbField, ok := wireToStorageMask[strings.TrimSpace(f)]; ok { + dbPaths = append(dbPaths, dbField) + } else { + invalid = append(invalid, f) + } + } + } + if len(invalid) > 0 { + return nil, handlers.InvalidArgumentErrorf(fmt.Sprintf("Invalid fields passed in update_update mask: %v.", invalid), map[string]string{"update_mask": fmt.Sprintf("Unknown paths provided in update mask: %q", strings.Join(invalid, ","))}) + } + return dbPaths, nil +} + +func toProto(in *iam.User) *pb.User { + out := pb.User{ + Id: in.GetPublicId(), + CreatedTime: in.GetCreateTime().GetTimestamp(), + UpdatedTime: in.GetUpdateTime().GetTimestamp(), + } + if in.GetDescription() != "" { + out.Description = &wrapperspb.StringValue{Value: in.GetDescription()} + } + if in.GetName() != "" { + out.Name = &wrapperspb.StringValue{Value: in.GetName()} + } + return &out +} + +// A validateX method should exist for each method above. These methods do not make calls to any backing service but enforce +// requirements on the structure of the request. They verify that: +// * The path passed in is correctly formatted +// * All required parameters are set +// * There are no conflicting parameters provided +func validateGetRequest(req *pbs.GetUserRequest) error { + badFields := validateAncestors(req) + if !validId(req.GetId(), iam.UserPrefix+"_") { + badFields["id"] = "Invalid formatted user id." + } + if len(badFields) > 0 { + return handlers.InvalidArgumentErrorf("Improperly formatted identifier.", badFields) + } + return nil +} + +func validateCreateRequest(req *pbs.CreateUserRequest) error { + badFields := validateAncestors(req) + item := req.GetItem() + if item.GetId() != "" { + badFields["id"] = "This is a read only field." + } + if item.GetCreatedTime() != nil { + badFields["created_time"] = "This is a read only field." + } + if item.GetUpdatedTime() != nil { + badFields["updated_time"] = "This is a read only field." + } + if len(badFields) > 0 { + return handlers.InvalidArgumentErrorf("Argument errors found in the request.", badFields) + } + return nil +} + +func validateUpdateRequest(req *pbs.UpdateUserRequest) error { + badFields := validateAncestors(req) + if !validId(req.GetId(), iam.UserPrefix+"_") { + badFields["user_id"] = "Improperly formatted path identifier." + } + if req.GetUpdateMask() == nil { + badFields["update_mask"] = "UpdateMask not provided but is required to update a user." + } + + item := req.GetItem() + if item == nil { + // It is legitimate for no item to be specified in an update request as it indicates all fields provided in + // the mask will be marked as unset. + return nil + } + if item.GetId() != "" { + badFields["id"] = "This is a read only field and cannot be specified in an update request." + } + if item.GetCreatedTime() != nil { + badFields["created_time"] = "This is a read only field and cannot be specified in an update request." + } + if item.GetUpdatedTime() != nil { + badFields["updated_time"] = "This is a read only field and cannot be specified in an update request." + } + if len(badFields) > 0 { + return handlers.InvalidArgumentErrorf("Errors in provided fields.", badFields) + } + + return nil +} + +func validateDeleteRequest(req *pbs.DeleteUserRequest) error { + badFields := validateAncestors(req) + if !validId(req.GetId(), iam.UserPrefix+"_") { + badFields["id"] = "Incorrectly formatted identifier." + } + 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 + } + id = strings.TrimPrefix(id, prefix) + return !reInvalidID.Match([]byte(id)) +} + +type ancestorProvider interface { + GetOrgId() string +} + +// validateAncestors verifies that the ancestors of this call are properly set and provided. +func validateAncestors(r ancestorProvider) map[string]string { + if r.GetOrgId() == "" { + return map[string]string{orgIdFieldName: "Missing organization id."} + } + if !validId(r.GetOrgId(), iam.OrganizationScope.Prefix()+"_") { + return map[string]string{orgIdFieldName: "Improperly formatted identifier."} + } + return map[string]string{} +} diff --git a/internal/servers/controller/handlers/users/user_service_test.go b/internal/servers/controller/handlers/users/user_service_test.go new file mode 100644 index 000000000..5f1dea87b --- /dev/null +++ b/internal/servers/controller/handlers/users/user_service_test.go @@ -0,0 +1,533 @@ +package users_test + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/golang/protobuf/ptypes" + "github.com/hashicorp/watchtower/internal/db" + pb "github.com/hashicorp/watchtower/internal/gen/controller/api/resources/users" + pbs "github.com/hashicorp/watchtower/internal/gen/controller/api/services" + "github.com/hashicorp/watchtower/internal/iam" + "github.com/hashicorp/watchtower/internal/servers/controller/handlers/users" + "google.golang.org/genproto/protobuf/field_mask" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/wrapperspb" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func createDefaultUserAndRepo(t *testing.T) (*iam.User, func() (*iam.Repository, error)) { + t.Helper() + cleanup, conn, _ := db.TestSetup(t, "postgres") + t.Cleanup(func() { + if err := conn.Close(); err != nil { + t.Errorf("Error when closing gorm DB: %v", err) + } + if err := cleanup(); err != nil { + t.Errorf("Error when cleaning up TestSetup: %v", err) + } + }) + rw := db.New(conn) + wrap := db.TestWrapper(t) + repoFn := func() (*iam.Repository, error) { + return iam.NewRepository(rw, rw, wrap) + } + + o, _ := iam.TestScopes(t, conn) + u := iam.TestUser(t, conn, o.GetPublicId(), iam.WithDescription("default"), iam.WithName("default")) + return u, repoFn +} + +func TestGet(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + u, repo := createDefaultUserAndRepo(t) + toMerge := &pbs.GetUserRequest{ + OrgId: u.GetScopeId(), + Id: u.GetPublicId(), + } + + wantU := &pb.User{ + Id: u.GetPublicId(), + Name: &wrapperspb.StringValue{Value: u.GetName()}, + Description: &wrapperspb.StringValue{Value: u.GetDescription()}, + CreatedTime: u.CreateTime.GetTimestamp(), + UpdatedTime: u.UpdateTime.GetTimestamp(), + } + + cases := []struct { + name string + req *pbs.GetUserRequest + res *pbs.GetUserResponse + errCode codes.Code + }{ + { + name: "Get an Existing User", + req: &pbs.GetUserRequest{Id: u.GetPublicId()}, + res: &pbs.GetUserResponse{Item: wantU}, + errCode: codes.OK, + }, + { + name: "Get a non existant User", + req: &pbs.GetUserRequest{Id: iam.UserPrefix + "_DoesntExis"}, + res: nil, + errCode: codes.NotFound, + }, + { + name: "Wrong id prefix", + req: &pbs.GetUserRequest{Id: "j_1234567890"}, + res: nil, + errCode: codes.InvalidArgument, + }, + { + name: "space in id", + req: &pbs.GetUserRequest{Id: iam.UserPrefix + "_1 23456789"}, + res: nil, + errCode: codes.InvalidArgument, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + req := proto.Clone(toMerge).(*pbs.GetUserRequest) + proto.Merge(req, tc.req) + + s, err := users.NewService(repo) + require.NoError(err, "Couldn't create new user service.") + + got, gErr := s.GetUser(context.Background(), req) + assert.Equal(tc.errCode, status.Code(gErr), "GetUser(%+v) got error %v, wanted %v", req, gErr, tc.errCode) + assert.True(proto.Equal(got, tc.res), "GetUser(%q) got response %q, wanted %q", req, got, tc.res) + }) + } +} + +func TestDelete(t *testing.T) { + require := require.New(t) + u, repo := createDefaultUserAndRepo(t) + + s, err := users.NewService(repo) + require.NoError(err, "Error when getting new user service.") + + cases := []struct { + name string + req *pbs.DeleteUserRequest + res *pbs.DeleteUserResponse + errCode codes.Code + }{ + { + name: "Delete an Existing User", + req: &pbs.DeleteUserRequest{ + OrgId: u.GetScopeId(), + Id: u.GetPublicId(), + }, + res: &pbs.DeleteUserResponse{ + Existed: true, + }, + errCode: codes.OK, + }, + { + name: "Delete bad user id", + req: &pbs.DeleteUserRequest{ + OrgId: u.GetScopeId(), + Id: iam.UserPrefix + "_doesntexis", + }, + res: &pbs.DeleteUserResponse{ + Existed: false, + }, + errCode: codes.OK, + }, + { + name: "Delete bad org id", + req: &pbs.DeleteUserRequest{ + OrgId: "o_doesntexis", + Id: u.GetPublicId(), + }, + res: &pbs.DeleteUserResponse{ + Existed: false, + }, + errCode: codes.OK, + }, + { + name: "Bad org formatting", + req: &pbs.DeleteUserRequest{ + OrgId: "bad_format", + Id: u.GetPublicId(), + }, + res: nil, + errCode: codes.InvalidArgument, + }, + { + name: "Bad User Id formatting", + req: &pbs.DeleteUserRequest{ + OrgId: u.GetScopeId(), + Id: "bad_format", + }, + res: nil, + errCode: codes.InvalidArgument, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + assert := assert.New(t) + got, gErr := s.DeleteUser(context.Background(), tc.req) + assert.Equal(tc.errCode, status.Code(gErr), "DeleteUser(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) + assert.EqualValuesf(tc.res, got, "DeleteUser(%q) got response %q, wanted %q", tc.req, got, tc.res) + }) + } +} + +func TestDelete_twice(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + u, repo := createDefaultUserAndRepo(t) + + s, err := users.NewService(repo) + require.NoError(err, "Error when getting new user service") + req := &pbs.DeleteUserRequest{ + OrgId: u.GetScopeId(), + Id: u.GetPublicId(), + } + got, gErr := s.DeleteUser(context.Background(), req) + assert.NoError(gErr, "First attempt") + assert.True(got.GetExisted(), "Expected existed to be true for the first delete.") + got, gErr = s.DeleteUser(context.Background(), req) + assert.NoError(gErr, "Second attempt") + assert.False(got.GetExisted(), "Expected existed to be false for the second delete.") +} + +func TestCreate(t *testing.T) { + require := require.New(t) + defaultUser, repo := createDefaultUserAndRepo(t) + defaultCreated, err := ptypes.Timestamp(defaultUser.GetCreateTime().GetTimestamp()) + require.NoError(err, "Error converting proto to timestamp.") + toMerge := &pbs.CreateUserRequest{ + OrgId: defaultUser.GetScopeId(), + } + + cases := []struct { + name string + req *pbs.CreateUserRequest + res *pbs.CreateUserResponse + errCode codes.Code + }{ + { + name: "Create a valid User", + req: &pbs.CreateUserRequest{Item: &pb.User{ + Name: &wrapperspb.StringValue{Value: "name"}, + Description: &wrapperspb.StringValue{Value: "desc"}, + }}, + res: &pbs.CreateUserResponse{ + Uri: fmt.Sprintf("orgs/%s/users/u_", defaultUser.GetScopeId()), + Item: &pb.User{ + Name: &wrapperspb.StringValue{Value: "name"}, + Description: &wrapperspb.StringValue{Value: "desc"}, + }, + }, + errCode: codes.OK, + }, + { + name: "Can't specify Id", + req: &pbs.CreateUserRequest{Item: &pb.User{ + Id: iam.UserPrefix + "_notallowed", + }}, + res: nil, + errCode: codes.InvalidArgument, + }, + { + name: "Can't specify Created Time", + req: &pbs.CreateUserRequest{Item: &pb.User{ + CreatedTime: ptypes.TimestampNow(), + }}, + res: nil, + errCode: codes.InvalidArgument, + }, + { + name: "Can't specify Update Time", + req: &pbs.CreateUserRequest{Item: &pb.User{ + UpdatedTime: ptypes.TimestampNow(), + }}, + res: nil, + errCode: codes.InvalidArgument, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + assert := assert.New(t) + req := proto.Clone(toMerge).(*pbs.CreateUserRequest) + proto.Merge(req, tc.req) + + s, err := users.NewService(repo) + require.NoError(err, "Error when getting new user service.") + + got, gErr := s.CreateUser(context.Background(), req) + assert.Equal(tc.errCode, status.Code(gErr), "CreateUser(%+v) got error %v, wanted %v", req, gErr, tc.errCode) + if got != nil { + assert.True(strings.HasPrefix(got.GetUri(), tc.res.Uri)) + assert.True(strings.HasPrefix(got.GetItem().GetId(), iam.UserPrefix+"_")) + gotCreateTime, err := ptypes.Timestamp(got.GetItem().GetCreatedTime()) + require.NoError(err, "Error converting proto to timestamp.") + gotUpdateTime, err := ptypes.Timestamp(got.GetItem().GetUpdatedTime()) + require.NoError(err, "Error converting proto to timestamp.") + // Verify it is a user created after the test setup's default user + assert.True(gotCreateTime.After(defaultCreated), "New user should have been created after default user. Was created %v, which is after %v", gotCreateTime, defaultCreated) + assert.True(gotUpdateTime.After(defaultCreated), "New user should have been updated after default user. Was updated %v, which is after %v", gotUpdateTime, defaultCreated) + + // Clear all values which are hard to compare against. + got.Uri, tc.res.Uri = "", "" + 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), "CreateUser(%q) got response %q, wanted %q", req, got, tc.res) + }) + } +} + +func TestUpdate(t *testing.T) { + require := require.New(t) + u, repoFn := createDefaultUserAndRepo(t) + tested, err := users.NewService(repoFn) + require.NoError(err, "Error when getting new user service.") + + resetUser := func() { + repo, err := repoFn() + require.NoError(err, "Couldn't get a new repo") + u, _, err = repo.UpdateUser(context.Background(), u, []string{"Name", "Description"}) + require.NoError(err, "Failed to reset the user") + } + + created, err := ptypes.Timestamp(u.GetCreateTime().GetTimestamp()) + require.NoError(err, "Error converting proto to timestamp") + toMerge := &pbs.UpdateUserRequest{ + OrgId: u.GetScopeId(), + Id: u.GetPublicId(), + } + + cases := []struct { + name string + req *pbs.UpdateUserRequest + res *pbs.UpdateUserResponse + errCode codes.Code + }{ + { + name: "Update an Existing User", + req: &pbs.UpdateUserRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"name", "description"}, + }, + Item: &pb.User{ + Name: &wrapperspb.StringValue{Value: "new"}, + Description: &wrapperspb.StringValue{Value: "desc"}, + }, + }, + res: &pbs.UpdateUserResponse{ + Item: &pb.User{ + Id: u.GetPublicId(), + Name: &wrapperspb.StringValue{Value: "new"}, + Description: &wrapperspb.StringValue{Value: "desc"}, + CreatedTime: u.GetCreateTime().GetTimestamp(), + }, + }, + errCode: codes.OK, + }, + { + name: "Multiple Paths in single string", + req: &pbs.UpdateUserRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"name,description"}, + }, + Item: &pb.User{ + Name: &wrapperspb.StringValue{Value: "new"}, + Description: &wrapperspb.StringValue{Value: "desc"}, + }, + }, + res: &pbs.UpdateUserResponse{ + Item: &pb.User{ + Id: u.GetPublicId(), + Name: &wrapperspb.StringValue{Value: "new"}, + Description: &wrapperspb.StringValue{Value: "desc"}, + CreatedTime: u.GetCreateTime().GetTimestamp(), + }, + }, + errCode: codes.OK, + }, + { + name: "No Update Mask", + req: &pbs.UpdateUserRequest{ + Item: &pb.User{ + Name: &wrapperspb.StringValue{Value: "updated name"}, + Description: &wrapperspb.StringValue{Value: "updated desc"}, + }, + }, + errCode: codes.InvalidArgument, + }, + { + name: "No Paths in Mask", + req: &pbs.UpdateUserRequest{ + UpdateMask: &field_mask.FieldMask{Paths: []string{}}, + Item: &pb.User{ + Name: &wrapperspb.StringValue{Value: "updated name"}, + Description: &wrapperspb.StringValue{Value: "updated desc"}, + }, + }, + errCode: codes.InvalidArgument, + }, + { + name: "Only non-existant paths in Mask", + req: &pbs.UpdateUserRequest{ + UpdateMask: &field_mask.FieldMask{Paths: []string{"nonexistant_field"}}, + Item: &pb.User{ + Name: &wrapperspb.StringValue{Value: "updated name"}, + Description: &wrapperspb.StringValue{Value: "updated desc"}, + }, + }, + errCode: codes.InvalidArgument, + }, + { + name: "Unset Name", + req: &pbs.UpdateUserRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"name"}, + }, + Item: &pb.User{ + Description: &wrapperspb.StringValue{Value: "ignored"}, + }, + }, + res: &pbs.UpdateUserResponse{ + Item: &pb.User{ + Id: u.GetPublicId(), + Description: &wrapperspb.StringValue{Value: "default"}, + CreatedTime: u.GetCreateTime().GetTimestamp(), + }, + }, + errCode: codes.OK, + }, + { + name: "Update Only Name", + req: &pbs.UpdateUserRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"name"}, + }, + Item: &pb.User{ + Name: &wrapperspb.StringValue{Value: "updated"}, + Description: &wrapperspb.StringValue{Value: "ignored"}, + }, + }, + res: &pbs.UpdateUserResponse{ + Item: &pb.User{ + Id: u.GetPublicId(), + Name: &wrapperspb.StringValue{Value: "updated"}, + Description: &wrapperspb.StringValue{Value: "default"}, + CreatedTime: u.GetCreateTime().GetTimestamp(), + }, + }, + errCode: codes.OK, + }, + { + name: "Update Only Description", + req: &pbs.UpdateUserRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"description"}, + }, + Item: &pb.User{ + Name: &wrapperspb.StringValue{Value: "ignored"}, + Description: &wrapperspb.StringValue{Value: "notignored"}, + }, + }, + res: &pbs.UpdateUserResponse{ + Item: &pb.User{ + Id: u.GetPublicId(), + Name: &wrapperspb.StringValue{Value: "default"}, + Description: &wrapperspb.StringValue{Value: "notignored"}, + CreatedTime: u.GetCreateTime().GetTimestamp(), + }, + }, + errCode: codes.OK, + }, + // TODO: Updating a non existant user should result in a NotFound exception but currently results in + // the repoFn returning an internal error. + { + name: "Update a Non Existing User", + req: &pbs.UpdateUserRequest{ + Id: iam.UserPrefix + "_DoesntExis", + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"description"}, + }, + Item: &pb.User{ + Name: &wrapperspb.StringValue{Value: "new"}, + Description: &wrapperspb.StringValue{Value: "desc"}, + }, + }, + errCode: codes.Internal, + }, + { + name: "Cant change Id", + req: &pbs.UpdateUserRequest{ + Id: u.GetPublicId(), + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"id"}, + }, + Item: &pb.User{ + Id: iam.UserPrefix + "_somethinge", + Name: &wrapperspb.StringValue{Value: "new"}, + Description: &wrapperspb.StringValue{Value: "new desc"}, + }}, + res: nil, + errCode: codes.InvalidArgument, + }, + { + name: "Cant specify Created Time", + req: &pbs.UpdateUserRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"created_time"}, + }, + Item: &pb.User{ + CreatedTime: ptypes.TimestampNow(), + }, + }, + res: nil, + errCode: codes.InvalidArgument, + }, + { + name: "Cant specify Updated Time", + req: &pbs.UpdateUserRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"updated_time"}, + }, + Item: &pb.User{ + UpdatedTime: ptypes.TimestampNow(), + }, + }, + res: nil, + errCode: codes.InvalidArgument, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + defer resetUser() + assert := assert.New(t) + req := proto.Clone(toMerge).(*pbs.UpdateUserRequest) + proto.Merge(req, tc.req) + + got, gErr := tested.UpdateUser(context.Background(), req) + assert.Equal(tc.errCode, status.Code(gErr), "UpdateUser(%+v) got error %v, wanted %v", req, gErr, tc.errCode) + + if got != nil { + assert.NotNilf(tc.res, "Expected UpdateUser response to be nil, but was %v", got) + gotUpdateTime, err := ptypes.Timestamp(got.GetItem().GetUpdatedTime()) + require.NoError(err, "Error converting proto to timestamp") + // Verify it is a user updated after it was created + assert.True(gotUpdateTime.After(created), "Updated user should have been updated after it's creation. Was updated %v, which is after %v", gotUpdateTime, created) + + // Clear all values which are hard to compare against. + got.Item.UpdatedTime, tc.res.Item.UpdatedTime = nil, nil + } + assert.True(proto.Equal(got, tc.res), "UpdateUser(%q) got response %q, wanted %q", req, got, tc.res) + }) + } +} diff --git a/internal/servers/controller/testing.go b/internal/servers/controller/testing.go index b73c0b1d8..f4907d983 100644 --- a/internal/servers/controller/testing.go +++ b/internal/servers/controller/testing.go @@ -73,6 +73,9 @@ func (tc *TestController) buildClient() { if err := client.SetAddr(apiAddrs[0]); err != nil { tc.t.Fatal(fmt.Errorf("error setting client address: %w", err)) } + if tc.b.DefaultOrgId != "" { + client.SetOrg(tc.b.DefaultOrgId) + } tc.client = client }