diff --git a/api/admin/v1/admin.proto b/api/admin/v1/admin.proto new file mode 100644 index 0000000..7c546ff --- /dev/null +++ b/api/admin/v1/admin.proto @@ -0,0 +1,77 @@ +syntax = "proto3"; + +package admin.v1; + +option go_package = "github.com/ozontech/seq-ui/pkg/admin/v1;admin"; + +service AdminService { + rpc CreateRole(CreateRoleRequest) returns (CreateRoleResponse); + + rpc AddUsersToRole(AddUsersToRoleRequest) returns (AddUsersToRoleResponse); + + rpc GetRoles(GetRolesRequest) returns (GetRolesResponse); + + rpc GetRole(GetRoleRequest) returns (GetRoleResponse); + + rpc UpdateRole(UpdateRoleRequest) returns (UpdateRoleResponse); + + rpc DeleteRole(DeleteRoleRequest) returns (DeleteRoleResponse); +} + +message Role { + int32 id = 1; + string name = 2; + repeated uint64 permissions = 3; +} + +message CreateRoleRequest { + string name = 1; + repeated uint64 permissions = 2; +} + +message CreateRoleResponse { + int32 role_id = 1; +} + +message AddUsersToRoleRequest { + int32 role_id = 1; + repeated string usernames = 2; +} + +message AddUsersToRoleResponse {} + +message GetRolesRequest {} + +message GetRolesResponse { + message Permission { + uint64 value = 1; + string name = 2; + optional string description = 3; + } + + repeated Role roles = 1; + repeated Permission available_permissions = 2; +} + +message GetRoleRequest { + int32 id = 1; +} + +message GetRoleResponse { + repeated string usernames = 1; +} + +message UpdateRoleRequest { + int32 id = 1; + optional string name = 2; + repeated uint64 permissions = 3; +} + +message UpdateRoleResponse {} + +message DeleteRoleRequest { + int32 id = 1; + optional int32 replacement_role_id = 2; +} + +message DeleteRoleResponse {} diff --git a/api/userprofile/v1/userprofile.proto b/api/userprofile/v1/userprofile.proto index 4391901..eb4c767 100644 --- a/api/userprofile/v1/userprofile.proto +++ b/api/userprofile/v1/userprofile.proto @@ -26,6 +26,7 @@ message GetUserProfileResponse { string timezone = 1; string onboarding_version = 2; LogColumns log_columns = 3; + optional int32 role_id = 4; } message UpdateUserProfileRequest { @@ -36,7 +37,6 @@ message UpdateUserProfileRequest { message UpdateUserProfileResponse {} - message GetFavoriteQueriesRequest {} message GetFavoriteQueriesResponse { @@ -66,7 +66,6 @@ message DeleteFavoriteQueryRequest { message DeleteFavoriteQueryResponse {} - message GetDashboardsRequest {} message GetDashboardsResponse { @@ -109,4 +108,4 @@ message DeleteDashboardRequest { string uuid = 1; } -message DeleteDashboardResponse {} \ No newline at end of file +message DeleteDashboardResponse {} diff --git a/cmd/seq-ui/main.go b/cmd/seq-ui/main.go index d661fcd..139a64d 100644 --- a/cmd/seq-ui/main.go +++ b/cmd/seq-ui/main.go @@ -16,6 +16,7 @@ import ( "github.com/jackc/pgx/v5/pgxpool" "github.com/joho/godotenv" "github.com/ozontech/seq-ui/internal/api" + admin_v1 "github.com/ozontech/seq-ui/internal/api/admin/v1" dashboards_v1 "github.com/ozontech/seq-ui/internal/api/dashboards/v1" errorgroups_v1 "github.com/ozontech/seq-ui/internal/api/errorgroups/v1" massexport_v1 "github.com/ozontech/seq-ui/internal/api/massexport/v1" @@ -152,6 +153,7 @@ func initApp(ctx context.Context, cfg config.Config) *api.Registrar { var ( asyncSearchesService *asyncsearches.Service p *profiles.Profiles + adminV1 *admin_v1.Admin userProfileV1 *userprofile_v1.UserProfile dashboardsV1 *dashboards_v1.Dashboards ) @@ -164,6 +166,10 @@ func initApp(ctx context.Context, cfg config.Config) *api.Registrar { dashboardsV1 = dashboards_v1.New(svc, p) asyncSearchesService = asyncsearches.New(ctx, repo, defaultClient, cfg.Handlers.AsyncSearch) + + if cfg.Handlers.Admin != nil { + adminV1 = admin_v1.New(svc, cfg.Handlers.Admin) + } } seqApiV1 := seqapi_v1.New(cfg.Handlers.SeqAPI, seqDBClients, inmemWithRedisCache, redisCache, asyncSearchesService, p) @@ -182,7 +188,7 @@ func initApp(ctx context.Context, cfg config.Config) *api.Registrar { errorGroupsV1 = errorgroups_v1.New(svc) } - return api.NewRegistrar(seqApiV1, userProfileV1, dashboardsV1, massExportV1, errorGroupsV1) + return api.NewRegistrar(adminV1, seqApiV1, userProfileV1, dashboardsV1, massExportV1, errorGroupsV1) } func initSeqDBClients(ctx context.Context, cfg config.Config) (map[string]seqdb.Client, error) { diff --git a/docs/en/02-configuration.md b/docs/en/02-configuration.md index 48b30f6..25a878c 100644 --- a/docs/en/02-configuration.md +++ b/docs/en/02-configuration.md @@ -507,6 +507,7 @@ handlers: error_groups: mass_export: async_search: + admin: ``` ### SeqAPI @@ -829,6 +830,18 @@ Configuration for async search request. Maximum length of `request.query` in async searches list responses. Requests exceeding the limit will be truncated to it +### Admin + +**`admin`** *`Admin`* *`optional`* + +Configuration for `/admin` API. + +`Admin` fields: + ++ **`super_users`** *`[]string`* *`required`* + + List of users with full access to admin features. + ## Tracing The tracing configuration is set through environment variables. diff --git a/docs/ru/02-configuration.md b/docs/ru/02-configuration.md index 65ecfee..2ed1087 100644 --- a/docs/ru/02-configuration.md +++ b/docs/ru/02-configuration.md @@ -507,6 +507,7 @@ handlers: error_groups: mass_export: async_search: + admin: ``` ### SeqAPI @@ -515,7 +516,7 @@ handlers: Конфигурация `/seqapi` API. -`SeqAPI` fields: +Поля `SeqAPI`: + **`max_search_limit`** *`int`* *`default=0`* @@ -829,6 +830,18 @@ handlers: Максимальная длина `request.query` в ответе списка отложенных запросов. Запросы, превышающие лимит, будут обрезаны до этого значения. +### Admin + +**`admin`** *`Admin`* *`optional`* + +Конфигурация `/admin` API. + +Поля `Admin`: + ++ **`super_users`** *`[]string`* *`required`* + + Список пользователей с полным доступом к административным функциям. + ## Tracing Конфигурация трейсинга задается переменными окружения. diff --git a/internal/api/admin/v1/admin.go b/internal/api/admin/v1/admin.go new file mode 100644 index 0000000..397ae13 --- /dev/null +++ b/internal/api/admin/v1/admin.go @@ -0,0 +1,29 @@ +package admin_v1 + +import ( + "github.com/go-chi/chi/v5" + grpc_api "github.com/ozontech/seq-ui/internal/api/admin/v1/grpc" + http_api "github.com/ozontech/seq-ui/internal/api/admin/v1/http" + "github.com/ozontech/seq-ui/internal/app/config" + "github.com/ozontech/seq-ui/internal/pkg/service" +) + +type Admin struct { + grpcAPI *grpc_api.API + httpAPI *http_api.API +} + +func New(svc service.Service, cfg *config.Admin) *Admin { + return &Admin{ + grpcAPI: grpc_api.New(svc, cfg), + httpAPI: http_api.New(svc, cfg), + } +} + +func (a *Admin) GRPCServer() *grpc_api.API { + return a.grpcAPI +} + +func (a *Admin) HTTPRouter() chi.Router { + return a.httpAPI.Router() +} diff --git a/internal/api/admin/v1/grpc/api.go b/internal/api/admin/v1/grpc/api.go new file mode 100644 index 0000000..4bb2277 --- /dev/null +++ b/internal/api/admin/v1/grpc/api.go @@ -0,0 +1,71 @@ +package grpc + +import ( + "context" + "strings" + + "github.com/ozontech/seq-ui/internal/app/config" + "github.com/ozontech/seq-ui/internal/app/types" + "github.com/ozontech/seq-ui/internal/pkg/service" + "github.com/ozontech/seq-ui/pkg/admin/v1" +) + +var grpcRoutePermissions = map[string]uint64{ + "Role": service.PermissionManageRoles, +} + +type API struct { + admin.UnimplementedAdminServiceServer + + service service.Service + availablePermissions []*admin.GetRolesResponse_Permission + superUsers map[string]struct{} +} + +func New(svc service.Service, cfg *config.Admin) *API { + su := make(map[string]struct{}, len(cfg.SuperUsers)) + for _, user := range cfg.SuperUsers { + su[user] = struct{}{} + } + return &API{ + service: svc, + availablePermissions: availablePermissionsToProto(svc.GetAvailablePermissions()), + superUsers: su, + } +} + +func (a *API) authorize(ctx context.Context, method string) error { + username, err := types.GetUserKey(ctx) + if err != nil { + return types.ErrUnauthenticated + } + + if _, ok := a.superUsers[username]; ok { + return nil + } + + requiredPermission, ok := matchGRPCRoutePermissions(method) + if !ok { + return types.ErrPermissionDenied + } + + resp, err := a.service.GetUserPermissions(ctx, types.GetUserPermissionsRequest{Username: username}) + if err != nil { + return types.ErrPermissionDenied + } + + if resp.Permissions&requiredPermission == 0 { + return types.ErrPermissionDenied + } + + return nil +} + +func matchGRPCRoutePermissions(method string) (uint64, bool) { + for keyword, permission := range grpcRoutePermissions { + if strings.Contains(method, keyword) { + return permission, true + } + } + return 0, false +} diff --git a/internal/api/admin/v1/grpc/roles.go b/internal/api/admin/v1/grpc/roles.go new file mode 100644 index 0000000..c8cb113 --- /dev/null +++ b/internal/api/admin/v1/grpc/roles.go @@ -0,0 +1,210 @@ +package grpc + +import ( + "context" + + "github.com/ozontech/seq-ui/internal/api/grpcutil" + "github.com/ozontech/seq-ui/internal/app/types" + "github.com/ozontech/seq-ui/pkg/admin/v1" + "github.com/ozontech/seq-ui/tracing" + "go.opentelemetry.io/otel/attribute" +) + +func (a *API) CreateRole(ctx context.Context, req *admin.CreateRoleRequest) (*admin.CreateRoleResponse, error) { + if err := a.authorize(ctx, "CreateRole"); err != nil { + return nil, grpcutil.ProcessError(err) + } + + ctx, span := tracing.StartSpan(ctx, "admin_v1_create_role") + defer span.End() + + span.SetAttributes( + attribute.KeyValue{ + Key: "role_name", + Value: attribute.StringValue(req.GetName()), + }, + attribute.KeyValue{ + Key: "permissions_count", + Value: attribute.IntValue(len(req.GetPermissions())), + }, + ) + + request := types.CreateRoleRequest{ + Name: req.Name, + Permissions: req.Permissions, + } + + roleID, err := a.service.CreateRole(ctx, request) + if err != nil { + return nil, grpcutil.ProcessError(err) + } + + return &admin.CreateRoleResponse{ + RoleId: roleID.RoleID, + }, nil +} + +func (a *API) AddUsersToRole(ctx context.Context, req *admin.AddUsersToRoleRequest) (*admin.AddUsersToRoleResponse, error) { + if err := a.authorize(ctx, "AddUsersToRole"); err != nil { + return nil, grpcutil.ProcessError(err) + } + + ctx, span := tracing.StartSpan(ctx, "admin_v1_add_users_to_role") + defer span.End() + + span.SetAttributes( + attribute.KeyValue{ + Key: "role_id", + Value: attribute.IntValue(int(req.GetRoleId())), + }, + attribute.KeyValue{ + Key: "users_count", + Value: attribute.IntValue(len(req.GetUsernames())), + }, + ) + + if err := a.service.AddUsersToRole(ctx, types.AddUsersToRoleRequest{ + RoleID: req.RoleId, + Usernames: req.Usernames, + }); err != nil { + return nil, grpcutil.ProcessError(err) + } + + return &admin.AddUsersToRoleResponse{}, nil +} + +func (a *API) GetRoles(ctx context.Context, _ *admin.GetRolesRequest) (*admin.GetRolesResponse, error) { + if err := a.authorize(ctx, "GetRoles"); err != nil { + return nil, grpcutil.ProcessError(err) + } + + resp, err := a.service.GetRoles(ctx) + if err != nil { + return nil, grpcutil.ProcessError(err) + } + + return &admin.GetRolesResponse{ + Roles: rolesToProto(resp.Roles), + AvailablePermissions: a.availablePermissions, + }, nil +} + +func (a *API) GetRole(ctx context.Context, req *admin.GetRoleRequest) (*admin.GetRoleResponse, error) { + if err := a.authorize(ctx, "GetRole"); err != nil { + return nil, grpcutil.ProcessError(err) + } + + ctx, span := tracing.StartSpan(ctx, "admin_v1_get_role") + defer span.End() + + span.SetAttributes( + attribute.KeyValue{ + Key: "role_id", + Value: attribute.IntValue(int(req.GetId())), + }, + ) + + resp, err := a.service.GetRole(ctx, types.GetRoleRequest{ + RoleID: req.Id, + }) + if err != nil { + return nil, grpcutil.ProcessError(err) + } + + return &admin.GetRoleResponse{ + Usernames: resp.Usernames, + }, nil +} + +func (a *API) UpdateRole(ctx context.Context, req *admin.UpdateRoleRequest) (*admin.UpdateRoleResponse, error) { + if err := a.authorize(ctx, "UpdateRole"); err != nil { + return nil, grpcutil.ProcessError(err) + } + + ctx, span := tracing.StartSpan(ctx, "admin_v1_update_role") + defer span.End() + + spanAttributes := []attribute.KeyValue{ + { + Key: "role_id", + Value: attribute.IntValue(int(req.GetId())), + }, + { + Key: "permissions_count", + Value: attribute.IntValue(len(req.GetPermissions())), + }, + } + if req.Name != nil { + spanAttributes = append(spanAttributes, attribute.KeyValue{ + Key: "role_name", + Value: attribute.StringValue(req.GetName()), + }) + } + span.SetAttributes(spanAttributes...) + + if err := a.service.UpdateRole(ctx, types.UpdateRoleRequest{ + RoleID: req.Id, + Name: req.Name, + Permissions: req.Permissions, + }); err != nil { + return nil, grpcutil.ProcessError(err) + } + + return &admin.UpdateRoleResponse{}, nil +} + +func (a *API) DeleteRole(ctx context.Context, req *admin.DeleteRoleRequest) (*admin.DeleteRoleResponse, error) { + if err := a.authorize(ctx, "DeleteRole"); err != nil { + return nil, grpcutil.ProcessError(err) + } + + ctx, span := tracing.StartSpan(ctx, "admin_v1_delete_role") + defer span.End() + + spanAttributes := []attribute.KeyValue{ + { + Key: "role_id", + Value: attribute.IntValue(int(req.GetId())), + }, + } + if req.ReplacementRoleId != nil { + spanAttributes = append(spanAttributes, attribute.KeyValue{ + Key: "replacement_role_id", + Value: attribute.IntValue(int(req.GetReplacementRoleId())), + }) + } + span.SetAttributes(spanAttributes...) + + if err := a.service.DeleteRole(ctx, types.DeleteRoleRequest{ + RoleID: req.Id, + ReplacementRoleID: req.ReplacementRoleId, + }); err != nil { + return nil, grpcutil.ProcessError(err) + } + + return &admin.DeleteRoleResponse{}, nil +} + +func rolesToProto(source []types.Role) []*admin.Role { + roles := make([]*admin.Role, 0, len(source)) + for _, role := range source { + roles = append(roles, &admin.Role{ + Id: role.ID, + Name: role.Name, + Permissions: role.Permissions, + }) + } + return roles +} + +func availablePermissionsToProto(source []types.Permission) []*admin.GetRolesResponse_Permission { + availablePermissions := make([]*admin.GetRolesResponse_Permission, 0, len(source)) + for _, aPermission := range source { + availablePermissions = append(availablePermissions, &admin.GetRolesResponse_Permission{ + Value: aPermission.Value, + Name: aPermission.Name, + Description: aPermission.Description, + }) + } + return availablePermissions +} diff --git a/internal/api/admin/v1/http/api.go b/internal/api/admin/v1/http/api.go new file mode 100644 index 0000000..5cde169 --- /dev/null +++ b/internal/api/admin/v1/http/api.go @@ -0,0 +1,45 @@ +package http + +import ( + "github.com/go-chi/chi/v5" + "github.com/ozontech/seq-ui/internal/app/config" + "github.com/ozontech/seq-ui/internal/pkg/service" +) + +type API struct { + service service.Service + availablePermissions []permission + superUsers map[string]struct{} +} + +func New(svc service.Service, cfg *config.Admin) *API { + su := make(map[string]struct{}, len(cfg.SuperUsers)) + for _, user := range cfg.SuperUsers { + su[user] = struct{}{} + } + + return &API{ + service: svc, + availablePermissions: parsePermissions(svc.GetAvailablePermissions()), + superUsers: su, + } +} + +func (a *API) Router() chi.Router { + mux := chi.NewMux() + + mux.Use(a.adminAuthInterceptor) + mux.Route("/roles", func(r chi.Router) { + r.Post("/", a.serveCreateRole) + r.Get("/", a.serveGetRoles) + + r.Route("/{id}", func(r chi.Router) { + r.Post("/users", a.serveAddUsersToRole) + r.Get("/", a.serveGetRole) + r.Patch("/", a.serveUpdateRole) + r.Delete("/", a.serveDeleteRole) + }) + }) + + return mux +} diff --git a/internal/api/admin/v1/http/mw.go b/internal/api/admin/v1/http/mw.go new file mode 100644 index 0000000..3d861ef --- /dev/null +++ b/internal/api/admin/v1/http/mw.go @@ -0,0 +1,61 @@ +package http + +import ( + "net/http" + "strings" + + "github.com/ozontech/seq-ui/internal/app/types" + "github.com/ozontech/seq-ui/internal/pkg/service" +) + +var RoutePermissions = map[string]uint64{ + "/roles": service.PermissionManageRoles, +} + +func (a *API) adminAuthInterceptor(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + username, err := types.GetUserKey(ctx) + if err != nil { + http.Error(w, "Unauthenticated", http.StatusUnauthorized) + return + } + + if _, ok := a.superUsers[username]; ok { + next.ServeHTTP(w, r) + return + } + + requiredPermission, ok := matchRoutePermissions(r.URL.Path) + if !ok { + http.Error(w, "Forbidden", http.StatusForbidden) + return + } + + resp, err := a.service.GetUserPermissions(ctx, types.GetUserPermissionsRequest{Username: username}) + if err != nil { + http.Error(w, "Forbidden", http.StatusForbidden) + return + } + + if resp.Permissions&requiredPermission == 0 { + http.Error(w, "Forbidden", http.StatusForbidden) + return + } + + next.ServeHTTP(w, r) + }) +} + +func matchRoutePermissions(path string) (uint64, bool) { + path = strings.TrimPrefix(path, "/admin/v1") + prefix := path + + if idx := strings.Index(path[1:], "/"); idx != -1 { + prefix = path[:idx+1] + } + + permission, ok := RoutePermissions[prefix] + return permission, ok +} diff --git a/internal/api/admin/v1/http/roles.go b/internal/api/admin/v1/http/roles.go new file mode 100644 index 0000000..eb19047 --- /dev/null +++ b/internal/api/admin/v1/http/roles.go @@ -0,0 +1,310 @@ +package http + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "strconv" + + "github.com/go-chi/chi/v5" + "github.com/ozontech/seq-ui/internal/api/httputil" + "github.com/ozontech/seq-ui/internal/app/types" + "github.com/ozontech/seq-ui/tracing" + "go.opentelemetry.io/otel/attribute" +) + +func (a *API) serveCreateRole(w http.ResponseWriter, r *http.Request) { + ctx, span := tracing.StartSpan(r.Context(), "admin_v1_create_role") + defer span.End() + + wr := httputil.NewWriter(w) + + var httpReq createRoleRequest + if err := json.NewDecoder(r.Body).Decode(&httpReq); err != nil { + wr.Error(fmt.Errorf("failed to parse request: %w", err), http.StatusBadRequest) + return + } + + span.SetAttributes( + attribute.KeyValue{ + Key: "role_name", + Value: attribute.StringValue(httpReq.Name), + }, + attribute.KeyValue{ + Key: "permissions_count", + Value: attribute.IntValue(len(httpReq.Permissions)), + }, + ) + + resp, err := a.service.CreateRole(ctx, types.CreateRoleRequest{ + Name: httpReq.Name, + Permissions: httpReq.Permissions, + }) + if err != nil { + httputil.ProcessError(wr, err) + return + } + + wr.WriteJson(createRoleResponse{RoleID: resp.RoleID}) +} + +func (a *API) serveAddUsersToRole(w http.ResponseWriter, r *http.Request) { + ctx, span := tracing.StartSpan(r.Context(), "admin_v1_add_users_to_role") + defer span.End() + + wr := httputil.NewWriter(w) + + roleID, err := getRoleID(r) + if err != nil { + httputil.ProcessError(wr, err) + return + } + + var httpReq addUsersToRoleRequest + if err := json.NewDecoder(r.Body).Decode(&httpReq); err != nil { + wr.Error(fmt.Errorf("failed to parse request: %w", err), http.StatusBadRequest) + return + } + + span.SetAttributes( + attribute.KeyValue{ + Key: "role_id", + Value: attribute.IntValue(int(roleID)), + }, + attribute.KeyValue{ + Key: "users_count", + Value: attribute.IntValue(len(httpReq.Usernames)), + }, + ) + + if err := a.service.AddUsersToRole(ctx, types.AddUsersToRoleRequest{ + RoleID: roleID, + Usernames: httpReq.Usernames, + }); err != nil { + httputil.ProcessError(wr, err) + return + } + + w.WriteHeader(http.StatusOK) +} + +func (a *API) serveGetRoles(w http.ResponseWriter, r *http.Request) { + ctx, span := tracing.StartSpan(r.Context(), "admin_v1_get_roles") + defer span.End() + + wr := httputil.NewWriter(w) + + resp, err := a.service.GetRoles(ctx) + if err != nil { + httputil.ProcessError(wr, err) + return + } + + wr.WriteJson(getRolesResponse{ + Roles: parseRoles(resp.Roles), + AvailablePermissions: a.availablePermissions, + }) +} + +func (a *API) serveGetRole(w http.ResponseWriter, r *http.Request) { + ctx, span := tracing.StartSpan(r.Context(), "admin_v1_get_role") + defer span.End() + + wr := httputil.NewWriter(w) + + roleID, err := getRoleID(r) + if err != nil { + httputil.ProcessError(wr, err) + return + } + + span.SetAttributes( + attribute.KeyValue{ + Key: "role_id", + Value: attribute.IntValue(int(roleID)), + }, + ) + + resp, err := a.service.GetRole(ctx, types.GetRoleRequest{ + RoleID: roleID, + }) + if err != nil { + httputil.ProcessError(wr, err) + return + } + + wr.WriteJson(getRoleResponse{ + Usernames: resp.Usernames, + }) +} + +func (a *API) serveUpdateRole(w http.ResponseWriter, r *http.Request) { + ctx, span := tracing.StartSpan(r.Context(), "admin_v1_update_role") + defer span.End() + + wr := httputil.NewWriter(w) + + roleID, err := getRoleID(r) + if err != nil { + httputil.ProcessError(wr, err) + return + } + + var httpReq updateRoleRequest + if err := json.NewDecoder(r.Body).Decode(&httpReq); err != nil { + wr.Error(fmt.Errorf("failed to parse request: %w", err), http.StatusBadRequest) + return + } + + spanAttributes := []attribute.KeyValue{ + { + Key: "role_id", + Value: attribute.IntValue(int(roleID)), + }, + { + Key: "permissions_count", + Value: attribute.IntValue(len(httpReq.Permissions)), + }, + } + if httpReq.Name != nil { + spanAttributes = append(spanAttributes, attribute.KeyValue{ + Key: "role_name", + Value: attribute.StringValue(*httpReq.Name), + }) + } + span.SetAttributes(spanAttributes...) + + if err := a.service.UpdateRole(ctx, types.UpdateRoleRequest{ + RoleID: roleID, + Name: httpReq.Name, + Permissions: httpReq.Permissions, + }); err != nil { + httputil.ProcessError(wr, err) + return + } + + w.WriteHeader(http.StatusOK) +} + +func (a *API) serveDeleteRole(w http.ResponseWriter, r *http.Request) { + ctx, span := tracing.StartSpan(r.Context(), "admin_v1_delete_role") + defer span.End() + + wr := httputil.NewWriter(w) + + roleID, err := getRoleID(r) + if err != nil { + httputil.ProcessError(wr, err) + return + } + + var httpReq deleteRoleRequest + if err := json.NewDecoder(r.Body).Decode(&httpReq); err != nil && !errors.Is(err, io.EOF) { + wr.Error(fmt.Errorf("failed to parse request: %w", err), http.StatusBadRequest) + return + } + + spanAttributes := []attribute.KeyValue{ + { + Key: "role_id", + Value: attribute.IntValue(int(roleID)), + }, + } + if httpReq.ReplacementRoleID != nil { + spanAttributes = append(spanAttributes, attribute.KeyValue{ + Key: "replacement_role_id", + Value: attribute.IntValue(int(*httpReq.ReplacementRoleID)), + }) + } + span.SetAttributes(spanAttributes...) + + if err := a.service.DeleteRole(ctx, types.DeleteRoleRequest{ + RoleID: roleID, + ReplacementRoleID: httpReq.ReplacementRoleID, + }); err != nil { + httputil.ProcessError(wr, err) + return + } + + w.WriteHeader(http.StatusOK) +} + +func getRoleID(r *http.Request) (int32, error) { + idString := chi.URLParam(r, "id") + + id, err := strconv.ParseInt(idString, 10, 32) + if err != nil { + return 0, types.NewErrInvalidRequestField("invalid role_id") + } + + return int32(id), nil +} + +func parseRoles(source []types.Role) []role { + roles := make([]role, 0, len(source)) + for _, s := range source { + roles = append(roles, role{ + ID: s.ID, + Name: s.Name, + Permissions: s.Permissions, + }) + } + return roles +} + +func parsePermissions(source []types.Permission) []permission { + permissions := make([]permission, 0, len(source)) + for _, s := range source { + permissions = append(permissions, permission{ + Value: s.Value, + Name: s.Name, + Description: s.Description, + }) + } + return permissions +} + +type role struct { + ID int32 `json:"id"` + Name string `json:"name"` + Permissions []uint64 `json:"permissions"` +} + +type permission struct { + Value uint64 `json:"value"` + Name string `json:"name"` + Description *string `json:"description"` +} + +type createRoleRequest struct { + Name string `json:"name"` + Permissions []uint64 `json:"permissions"` +} + +type createRoleResponse struct { + RoleID int32 `json:"role_id"` +} + +type addUsersToRoleRequest struct { + Usernames []string `json:"usernames"` +} + +type getRolesResponse struct { + Roles []role `json:"roles"` + AvailablePermissions []permission `json:"available_permissions"` +} + +type getRoleResponse struct { + Usernames []string `json:"usernames"` +} + +type updateRoleRequest struct { + Name *string `json:"name"` + Permissions []uint64 `json:"permissions"` +} + +type deleteRoleRequest struct { + ReplacementRoleID *int32 `json:"replacement_role_id"` +} diff --git a/internal/api/dashboards/v1/grpc/create_test.go b/internal/api/dashboards/v1/grpc/create_test.go index c22ef3a..b1690a5 100644 --- a/internal/api/dashboards/v1/grpc/create_test.go +++ b/internal/api/dashboards/v1/grpc/create_test.go @@ -105,7 +105,7 @@ func TestCreate(t *testing.T) { ctx := context.Background() if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + ctx = types.SetUserKey(ctx, userName) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/dashboards/v1/grpc/delete_test.go b/internal/api/dashboards/v1/grpc/delete_test.go index 6d9885b..b985397 100644 --- a/internal/api/dashboards/v1/grpc/delete_test.go +++ b/internal/api/dashboards/v1/grpc/delete_test.go @@ -102,7 +102,7 @@ func TestDelete(t *testing.T) { ctx := context.Background() if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + ctx = types.SetUserKey(ctx, userName) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/dashboards/v1/grpc/get_all_test.go b/internal/api/dashboards/v1/grpc/get_all_test.go index 1a87bab..6c26b49 100644 --- a/internal/api/dashboards/v1/grpc/get_all_test.go +++ b/internal/api/dashboards/v1/grpc/get_all_test.go @@ -120,7 +120,7 @@ func TestGetAll(t *testing.T) { ctx := context.Background() if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + ctx = types.SetUserKey(ctx, userName) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/dashboards/v1/grpc/get_by_uuid_test.go b/internal/api/dashboards/v1/grpc/get_by_uuid_test.go index c2a459e..5593430 100644 --- a/internal/api/dashboards/v1/grpc/get_by_uuid_test.go +++ b/internal/api/dashboards/v1/grpc/get_by_uuid_test.go @@ -106,7 +106,7 @@ func TestGetByUUID(t *testing.T) { ctx := context.Background() if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + ctx = types.SetUserKey(ctx, userName) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/dashboards/v1/grpc/get_my_test.go b/internal/api/dashboards/v1/grpc/get_my_test.go index 27b2c34..6a2d637 100644 --- a/internal/api/dashboards/v1/grpc/get_my_test.go +++ b/internal/api/dashboards/v1/grpc/get_my_test.go @@ -110,7 +110,7 @@ func TestGetMy(t *testing.T) { ctx := context.Background() if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + ctx = types.SetUserKey(ctx, userName) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/dashboards/v1/grpc/search_test.go b/internal/api/dashboards/v1/grpc/search_test.go index 04f66d2..f0d7299 100644 --- a/internal/api/dashboards/v1/grpc/search_test.go +++ b/internal/api/dashboards/v1/grpc/search_test.go @@ -160,7 +160,7 @@ func TestSearch(t *testing.T) { ctx := context.Background() if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + ctx = types.SetUserKey(ctx, userName) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/dashboards/v1/grpc/update_test.go b/internal/api/dashboards/v1/grpc/update_test.go index b3c784f..a8eb74f 100644 --- a/internal/api/dashboards/v1/grpc/update_test.go +++ b/internal/api/dashboards/v1/grpc/update_test.go @@ -175,7 +175,7 @@ func TestUpdate(t *testing.T) { ctx := context.Background() if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + ctx = types.SetUserKey(ctx, userName) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/dashboards/v1/http/create_test.go b/internal/api/dashboards/v1/http/create_test.go index 9bd86d5..a20cc3a 100644 --- a/internal/api/dashboards/v1/http/create_test.go +++ b/internal/api/dashboards/v1/http/create_test.go @@ -1,7 +1,6 @@ package http import ( - "context" "errors" "fmt" "net/http" @@ -104,7 +103,7 @@ func TestServeCreate(t *testing.T) { Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) } if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + req = req.WithContext(types.SetUserKey(req.Context(), userName)) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/dashboards/v1/http/delete_test.go b/internal/api/dashboards/v1/http/delete_test.go index fc50e03..d33ed07 100644 --- a/internal/api/dashboards/v1/http/delete_test.go +++ b/internal/api/dashboards/v1/http/delete_test.go @@ -95,7 +95,7 @@ func TestServeDelete(t *testing.T) { Return(tt.mockArgs.err).Times(1) } if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + req = req.WithContext(types.SetUserKey(req.Context(), userName)) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/dashboards/v1/http/get_all_test.go b/internal/api/dashboards/v1/http/get_all_test.go index 927bb52..ccffcdb 100644 --- a/internal/api/dashboards/v1/http/get_all_test.go +++ b/internal/api/dashboards/v1/http/get_all_test.go @@ -1,7 +1,6 @@ package http import ( - "context" "errors" "fmt" "net/http" @@ -116,7 +115,7 @@ func TestServeGetAll(t *testing.T) { Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) } if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + req = req.WithContext(types.SetUserKey(req.Context(), userName)) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/dashboards/v1/http/get_by_uuid_test.go b/internal/api/dashboards/v1/http/get_by_uuid_test.go index cde63ce..1e33868 100644 --- a/internal/api/dashboards/v1/http/get_by_uuid_test.go +++ b/internal/api/dashboards/v1/http/get_by_uuid_test.go @@ -94,7 +94,7 @@ func TestServeGetByUUID(t *testing.T) { Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) } if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + req = req.WithContext(types.SetUserKey(req.Context(), userName)) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/dashboards/v1/http/get_my_test.go b/internal/api/dashboards/v1/http/get_my_test.go index 30f7dcf..7db0d21 100644 --- a/internal/api/dashboards/v1/http/get_my_test.go +++ b/internal/api/dashboards/v1/http/get_my_test.go @@ -1,7 +1,6 @@ package http import ( - "context" "errors" "fmt" "net/http" @@ -106,7 +105,7 @@ func TestServeGetMy(t *testing.T) { Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) } if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + req = req.WithContext(types.SetUserKey(req.Context(), userName)) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/dashboards/v1/http/search_test.go b/internal/api/dashboards/v1/http/search_test.go index c825936..ec89bbf 100644 --- a/internal/api/dashboards/v1/http/search_test.go +++ b/internal/api/dashboards/v1/http/search_test.go @@ -1,7 +1,6 @@ package http import ( - "context" "errors" "fmt" "net/http" @@ -155,7 +154,7 @@ func TestServeSearch(t *testing.T) { Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) } if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + req = req.WithContext(types.SetUserKey(req.Context(), userName)) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/dashboards/v1/http/update_test.go b/internal/api/dashboards/v1/http/update_test.go index bf0d29f..187db25 100644 --- a/internal/api/dashboards/v1/http/update_test.go +++ b/internal/api/dashboards/v1/http/update_test.go @@ -179,7 +179,7 @@ func TestServeUpdate(t *testing.T) { Return(tt.mockArgs.err).Times(1) } if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + req = req.WithContext(types.SetUserKey(req.Context(), userName)) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/httputil/error.go b/internal/api/httputil/error.go index ce5d5b4..0070478 100644 --- a/internal/api/httputil/error.go +++ b/internal/api/httputil/error.go @@ -15,7 +15,7 @@ func ProcessError(w *Writer, err error) { switch { case err == nil: return - case errors.Is(err, types.ErrUnauthenticated) || errors.Is(err, types.ErrBadUserKeyValueType): + case errors.Is(err, types.ErrUnauthenticated): w.Error(err, http.StatusUnauthorized) case errors.Is(err, types.ErrEmptyUpdateRequest) || errors.Is(err, types.ErrInvalidRequestField): w.Error(err, http.StatusBadRequest) diff --git a/internal/api/registrar.go b/internal/api/registrar.go index 70d4f67..ecc8ca8 100644 --- a/internal/api/registrar.go +++ b/internal/api/registrar.go @@ -14,11 +14,13 @@ package api import ( "github.com/go-chi/chi/v5" + admin_v1_api "github.com/ozontech/seq-ui/internal/api/admin/v1" dashboards_v1_api "github.com/ozontech/seq-ui/internal/api/dashboards/v1" errorgroups_v1_api "github.com/ozontech/seq-ui/internal/api/errorgroups/v1" massexport_v1_api "github.com/ozontech/seq-ui/internal/api/massexport/v1" seqapi_v1_api "github.com/ozontech/seq-ui/internal/api/seqapi/v1" userprofile_v1_api "github.com/ozontech/seq-ui/internal/api/userprofile/v1" + admin_v1 "github.com/ozontech/seq-ui/pkg/admin/v1" dashboards_v1 "github.com/ozontech/seq-ui/pkg/dashboards/v1" errorgroups_v1 "github.com/ozontech/seq-ui/pkg/errorgroups/v1" massexport_v1 "github.com/ozontech/seq-ui/pkg/massexport/v1" @@ -29,6 +31,7 @@ import ( // Registrar is registrar of gRPC and gRPC-Gateway handlers. type Registrar struct { + adminV1 *admin_v1_api.Admin seqApiV1 *seqapi_v1_api.SeqAPI userProfileV1 *userprofile_v1_api.UserProfile dashboardsV1 *dashboards_v1_api.Dashboards @@ -38,6 +41,7 @@ type Registrar struct { // NewRegistrar returns new registrar instance. func NewRegistrar( + adminV1 *admin_v1_api.Admin, seqApiV1 *seqapi_v1_api.SeqAPI, userProfileV1 *userprofile_v1_api.UserProfile, dashboardsV1 *dashboards_v1_api.Dashboards, @@ -45,6 +49,7 @@ func NewRegistrar( errorGroupsV1 *errorgroups_v1_api.ErrorGroups, ) *Registrar { return &Registrar{ + adminV1: adminV1, seqApiV1: seqApiV1, userProfileV1: userProfileV1, dashboardsV1: dashboardsV1, @@ -70,6 +75,9 @@ func (r *Registrar) RegisterGRPCHandlers(grpcServer *grpc.Server) { if r.errorGroupsV1 != nil { errorgroups_v1.RegisterErrorGroupsServiceServer(grpcServer, r.errorGroupsV1.GRPCServer()) } + if r.adminV1 != nil { + admin_v1.RegisterAdminServiceServer(grpcServer, r.adminV1.GRPCServer()) + } } // RegisterHTTPHandlers registers all handlers for mux. @@ -89,4 +97,7 @@ func (r *Registrar) RegisterHTTPHandlers(mux *chi.Mux) { if r.errorGroupsV1 != nil { mux.Mount("/errorgroups/v1", r.errorGroupsV1.HTTPRouter()) } + if r.adminV1 != nil { + mux.Mount("/admin/v1", r.adminV1.HTTPRouter()) + } } diff --git a/internal/api/seqapi/v1/grpc/cancel_async_search_test.go b/internal/api/seqapi/v1/grpc/cancel_async_search_test.go index 610cd92..bf4ec7f 100644 --- a/internal/api/seqapi/v1/grpc/cancel_async_search_test.go +++ b/internal/api/seqapi/v1/grpc/cancel_async_search_test.go @@ -135,7 +135,7 @@ func TestServeCancelAsyncSearch(t *testing.T) { api := initTestAPIWithAsyncSearches(seqData) ctx := context.Background() - ctx = context.WithValue(ctx, types.UserKey{}, tt.mockArgs.userName) + ctx = types.SetUserKey(ctx, tt.mockArgs.userName) resp, err := api.CancelAsyncSearch(ctx, tt.req) if tt.err == nil { diff --git a/internal/api/seqapi/v1/grpc/delete_async_search_test.go b/internal/api/seqapi/v1/grpc/delete_async_search_test.go index f785ad4..3141f50 100644 --- a/internal/api/seqapi/v1/grpc/delete_async_search_test.go +++ b/internal/api/seqapi/v1/grpc/delete_async_search_test.go @@ -146,7 +146,7 @@ func TestServeDeleteAsyncSearch(t *testing.T) { api := initTestAPIWithAsyncSearches(seqData) ctx := context.Background() - ctx = context.WithValue(ctx, types.UserKey{}, tt.mockArgs.userName) + ctx = types.SetUserKey(ctx, tt.mockArgs.userName) resp, err := api.DeleteAsyncSearch(ctx, tt.req) if tt.err == nil { diff --git a/internal/api/seqapi/v1/grpc/start_async_search_test.go b/internal/api/seqapi/v1/grpc/start_async_search_test.go index 14c0dd9..70e9456 100644 --- a/internal/api/seqapi/v1/grpc/start_async_search_test.go +++ b/internal/api/seqapi/v1/grpc/start_async_search_test.go @@ -118,7 +118,7 @@ func TestServeStartAsyncSearch(t *testing.T) { api := initTestAPIWithAsyncSearches(seqData) ctx := context.Background() - ctx = context.WithValue(ctx, types.UserKey{}, mockUserName) + ctx = types.SetUserKey(ctx, mockUserName) resp, err := api.StartAsyncSearch(ctx, tt.req) require.NoError(t, err) diff --git a/internal/api/seqapi/v1/http/cancel_async_search_test.go b/internal/api/seqapi/v1/http/cancel_async_search_test.go index 053df8b..3ea0168 100644 --- a/internal/api/seqapi/v1/http/cancel_async_search_test.go +++ b/internal/api/seqapi/v1/http/cancel_async_search_test.go @@ -147,7 +147,7 @@ func TestServeCancelAsyncSearch(t *testing.T) { fmt.Sprintf("/seqapi/v1/async_search/%s/cancel", tt.mockArgs.proxyReq.SearchId), http.NoBody, ) - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, tt.mockArgs.userName)) + req = req.WithContext(types.SetUserKey(req.Context(), tt.mockArgs.userName)) rCtx := chi.NewRouteContext() rCtx.URLParams.Add("id", tt.mockArgs.proxyReq.SearchId) req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rCtx)) diff --git a/internal/api/seqapi/v1/http/delete_async_search_test.go b/internal/api/seqapi/v1/http/delete_async_search_test.go index 878adf6..e739ce2 100644 --- a/internal/api/seqapi/v1/http/delete_async_search_test.go +++ b/internal/api/seqapi/v1/http/delete_async_search_test.go @@ -157,7 +157,7 @@ func TestServeDeleteAsyncSearch(t *testing.T) { fmt.Sprintf("/seqapi/v1/async_search/%s", tt.mockArgs.proxyReq.SearchId), http.NoBody, ) - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, tt.mockArgs.userName)) + req = req.WithContext(types.SetUserKey(req.Context(), tt.mockArgs.userName)) rCtx := chi.NewRouteContext() rCtx.URLParams.Add("id", tt.mockArgs.proxyReq.SearchId) req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rCtx)) diff --git a/internal/api/seqapi/v1/http/start_async_search_test.go b/internal/api/seqapi/v1/http/start_async_search_test.go index d1ac82d..c705221 100644 --- a/internal/api/seqapi/v1/http/start_async_search_test.go +++ b/internal/api/seqapi/v1/http/start_async_search_test.go @@ -1,7 +1,6 @@ package http import ( - "context" "fmt" "net/http" "net/http/httptest" @@ -137,7 +136,7 @@ func TestServeStartAsyncSearch(t *testing.T) { api := initTestAPIWithAsyncSearches(seqData) req := httptest.NewRequest(http.MethodPost, "/seqapi/v1/async_search/start", strings.NewReader(tt.reqBody)) - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, mockUserName)) + req = req.WithContext(types.SetUserKey(req.Context(), mockUserName)) httputil.DoTestHTTP(t, httputil.TestDataHTTP{ Req: req, diff --git a/internal/api/userprofile/v1/grpc/favorite_queries_test.go b/internal/api/userprofile/v1/grpc/favorite_queries_test.go index c82ce3a..516d90b 100644 --- a/internal/api/userprofile/v1/grpc/favorite_queries_test.go +++ b/internal/api/userprofile/v1/grpc/favorite_queries_test.go @@ -123,7 +123,7 @@ func TestGetFavoriteQueries(t *testing.T) { ctx := context.Background() if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + ctx = types.SetUserKey(ctx, userName) api.profiles.SetID(userName, profileID) } @@ -240,7 +240,7 @@ func TestCreateFavoriteQuery(t *testing.T) { ctx := context.Background() if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + ctx = types.SetUserKey(ctx, userName) api.profiles.SetID(userName, profileID) } @@ -331,7 +331,7 @@ func TestDeleteFavoriteQuery(t *testing.T) { ctx := context.Background() if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + ctx = types.SetUserKey(ctx, userName) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/userprofile/v1/grpc/user_profiles_test.go b/internal/api/userprofile/v1/grpc/user_profiles_test.go index d5feeb2..da26b11 100644 --- a/internal/api/userprofile/v1/grpc/user_profiles_test.go +++ b/internal/api/userprofile/v1/grpc/user_profiles_test.go @@ -85,7 +85,7 @@ func TestGetUserProfile(t *testing.T) { ctx := context.Background() if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + ctx = types.SetUserKey(ctx, userName) } got, err := api.GetUserProfile(ctx, &userprofile.GetUserProfileRequest{}) @@ -256,7 +256,7 @@ func TestUpdateUserProfile(t *testing.T) { ctx := context.Background() if !tt.noUser { - ctx = context.WithValue(ctx, types.UserKey{}, userName) + ctx = types.SetUserKey(ctx, userName) } got, err := api.UpdateUserProfile(ctx, tt.req) diff --git a/internal/api/userprofile/v1/http/favorite_queries_test.go b/internal/api/userprofile/v1/http/favorite_queries_test.go index b07c7ca..bb657a1 100644 --- a/internal/api/userprofile/v1/http/favorite_queries_test.go +++ b/internal/api/userprofile/v1/http/favorite_queries_test.go @@ -95,7 +95,7 @@ func TestServeGetFavoriteQueries(t *testing.T) { Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) } if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + req = req.WithContext(types.SetUserKey(req.Context(), userName)) api.profiles.SetID(userName, profileID) } @@ -220,7 +220,7 @@ func TestServeCreateFavoriteQuery(t *testing.T) { Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) } if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + req = req.WithContext(types.SetUserKey(req.Context(), userName)) api.profiles.SetID(userName, profileID) } @@ -309,7 +309,7 @@ func TestServeDeleteFavoriteQuery(t *testing.T) { Return(tt.mockArgs.err).Times(1) } if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + req = req.WithContext(types.SetUserKey(req.Context(), userName)) api.profiles.SetID(userName, profileID) } diff --git a/internal/api/userprofile/v1/http/user_profiles_test.go b/internal/api/userprofile/v1/http/user_profiles_test.go index 57da0f2..7e8bb54 100644 --- a/internal/api/userprofile/v1/http/user_profiles_test.go +++ b/internal/api/userprofile/v1/http/user_profiles_test.go @@ -1,7 +1,6 @@ package http import ( - "context" "encoding/json" "errors" "fmt" @@ -82,7 +81,7 @@ func TestServeGetUserProfile(t *testing.T) { Return(tt.mockArgs.resp, tt.mockArgs.err).Times(1) } if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + req = req.WithContext(types.SetUserKey(req.Context(), userName)) } httputil.DoTestHTTP(t, httputil.TestDataHTTP{ @@ -256,7 +255,7 @@ func TestServeUpdateUserProfile(t *testing.T) { Return(tt.mockArgs.err).Times(1) } if !tt.noUser { - req = req.WithContext(context.WithValue(req.Context(), types.UserKey{}, userName)) + req = req.WithContext(types.SetUserKey(req.Context(), userName)) } httputil.DoTestHTTP(t, httputil.TestDataHTTP{ diff --git a/internal/app/config/config.go b/internal/app/config/config.go index 62a4184..2a25a9c 100644 --- a/internal/app/config/config.go +++ b/internal/app/config/config.go @@ -239,6 +239,7 @@ type Handlers struct { ErrorGroups ErrorGroups `yaml:"error_groups"` MassExport *MassExport `yaml:"mass_export"` AsyncSearch AsyncSearch `yaml:"async_search"` + Admin *Admin `yaml:"admin"` } type PinnedField struct { @@ -318,6 +319,10 @@ type AsyncSearch struct { ListQueryLengthLimit int `yaml:"list_query_length_limit"` } +type Admin struct { + SuperUsers []string `yaml:"super_users"` +} + // FromFile parse config from config path. func FromFile(cfgPath string) (Config, error) { cfgBytes, err := os.ReadFile(cfgPath) //nolint:gosec diff --git a/internal/app/mw/grpc_mw.go b/internal/app/mw/grpc_mw.go index fa9b644..9df993b 100644 --- a/internal/app/mw/grpc_mw.go +++ b/internal/app/mw/grpc_mw.go @@ -163,7 +163,7 @@ func GRPCAuthInterceptor(providers *AuthProviders) grpc.UnaryServerInterceptor { logger.Error("token auth failed", zap.Error(err)) return nil, errUnauth } - ctx = context.WithValue(ctx, types.UserKey{}, userName) + ctx = types.SetUserKey(ctx, userName) return h(ctx, req) } diff --git a/internal/app/mw/http_mw.go b/internal/app/mw/http_mw.go index 10aedcd..ef22b0e 100644 --- a/internal/app/mw/http_mw.go +++ b/internal/app/mw/http_mw.go @@ -177,7 +177,7 @@ func HTTPAuthInterceptor(providers *AuthProviders) func(next http.Handler) http. http.Error(w, "Unauthenticated", http.StatusUnauthorized) return } - r = r.WithContext(context.WithValue(ctx, types.UserKey{}, username)) + r = r.WithContext(types.SetUserKey(ctx, username)) next.ServeHTTP(w, r) } diff --git a/internal/app/types/admin.go b/internal/app/types/admin.go new file mode 100644 index 0000000..81c9c4c --- /dev/null +++ b/internal/app/types/admin.go @@ -0,0 +1,80 @@ +package types + +type Role struct { + ID int32 + Name string + Permissions []uint64 +} + +type RoleRepo struct { + ID int32 + Name string + Permissions uint64 +} + +type Permission struct { + Value uint64 + Name string + Description *string +} + +type CreateRoleRequest struct { + Name string + Permissions []uint64 +} + +type CreateRoleRepoRequest struct { + Name string + Permissions uint64 +} + +type CreateRoleResponse struct { + RoleID int32 +} + +type AddUsersToRoleRequest struct { + RoleID int32 + Usernames []string +} + +type GetRolesResponse struct { + Roles []Role + AvailablePermissions []Permission +} + +type GetRolesRepoResponse struct { + Roles []RoleRepo +} + +type GetRoleRequest struct { + RoleID int32 +} + +type GetRoleResponse struct { + Usernames []string +} + +type UpdateRoleRequest struct { + RoleID int32 + Name *string + Permissions []uint64 +} + +type UpdateRoleRepoRequest struct { + RoleID int32 + Name *string + Permissions *uint64 +} + +type DeleteRoleRequest struct { + RoleID int32 + ReplacementRoleID *int32 +} + +type GetUserPermissionsRequest struct { + Username string +} + +type GetUserPermissionsResponse struct { + Permissions uint64 +} diff --git a/internal/app/types/ctx.go b/internal/app/types/ctx.go index b03cea1..b833054 100644 --- a/internal/app/types/ctx.go +++ b/internal/app/types/ctx.go @@ -5,13 +5,15 @@ import ( "errors" ) -var ( - ErrUnauthenticated = errors.New("unauthenticated") - ErrBadUserKeyValueType = errors.New("invalid JWT token") -) +var ErrUnauthenticated = errors.New("unauthenticated") type UserKey struct{} +// SetUserKey returns a new context with the username. +func SetUserKey(ctx context.Context, username string) context.Context { + return context.WithValue(ctx, UserKey{}, username) +} + // GetUserKey returns username from context. func GetUserKey(ctx context.Context) (string, error) { userStr := "" @@ -21,11 +23,7 @@ func GetUserKey(ctx context.Context) (string, error) { return "", ErrUnauthenticated } - userStr, ok := userVal.(string) - // foolproof. - if !ok { - return "", ErrBadUserKeyValueType - } + userStr = userVal.(string) return userStr, nil } diff --git a/internal/app/types/ctx_test.go b/internal/app/types/ctx_test.go index cbaec49..df0f311 100644 --- a/internal/app/types/ctx_test.go +++ b/internal/app/types/ctx_test.go @@ -16,7 +16,7 @@ func TestGetUserKey(t *testing.T) { }{ { name: "success", - ctx: context.WithValue(context.Background(), UserKey{}, "unnamed"), + ctx: SetUserKey(context.Background(), "unnamed"), wantUserName: "unnamed", }, { @@ -24,11 +24,6 @@ func TestGetUserKey(t *testing.T) { ctx: context.Background(), wantErr: ErrUnauthenticated, }, - { - name: "err_bad_value_type", - ctx: context.WithValue(context.Background(), UserKey{}, 99999), - wantErr: ErrBadUserKeyValueType, - }, } for _, tCase := range tCases { diff --git a/internal/pkg/client/seqdb/seqproxyapi/v1/seq_proxy_api.pb.go b/internal/pkg/client/seqdb/seqproxyapi/v1/seq_proxy_api.pb.go index e0e67c8..3cfd476 100644 --- a/internal/pkg/client/seqdb/seqproxyapi/v1/seq_proxy_api.pb.go +++ b/internal/pkg/client/seqdb/seqproxyapi/v1/seq_proxy_api.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc v6.33.4 +// protoc v7.34.1 // source: v1/seq_proxy_api.proto package seqproxyapi diff --git a/internal/pkg/client/seqdb/seqproxyapi/v1/seq_proxy_api_grpc.pb.go b/internal/pkg/client/seqdb/seqproxyapi/v1/seq_proxy_api_grpc.pb.go index 6b7825b..ee491b3 100644 --- a/internal/pkg/client/seqdb/seqproxyapi/v1/seq_proxy_api_grpc.pb.go +++ b/internal/pkg/client/seqdb/seqproxyapi/v1/seq_proxy_api_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 -// - protoc v6.33.4 +// - protoc v7.34.1 // source: v1/seq_proxy_api.proto package seqproxyapi diff --git a/internal/pkg/repository/admin_repo.go b/internal/pkg/repository/admin_repo.go new file mode 100644 index 0000000..8e3dd94 --- /dev/null +++ b/internal/pkg/repository/admin_repo.go @@ -0,0 +1,246 @@ +package repository + +import ( + "context" + "fmt" + + "github.com/jackc/pgx/v5" + "github.com/ozontech/seq-ui/internal/app/types" +) + +type adminRepository struct { + *pool +} + +func newAdminRepository(pool *pool) *adminRepository { + return &adminRepository{pool} +} + +func (r *adminRepository) CreateRole(ctx context.Context, req types.CreateRoleRepoRequest) (types.CreateRoleResponse, error) { + query, args := "INSERT INTO roles (name, permissions) VALUES ($1, $2) RETURNING id", []any{req.Name, req.Permissions} + + var roleID int32 + metricLabels := []string{"admin", "CREATE"} + resp := types.CreateRoleResponse{} + + if err := r.pool.queryRow(ctx, metricLabels, query, args...).Scan(&roleID); err != nil { + incErrorMetric(err, metricLabels) + return resp, fmt.Errorf("failed to create role: %w", err) + } + + resp.RoleID = roleID + + return resp, nil +} + +func (r *adminRepository) AddUsersToRole(ctx context.Context, req types.AddUsersToRoleRequest) error { + query, args := "UPDATE user_profiles SET role_id=$1 WHERE user_name=ANY($2)", []any{req.RoleID, req.Usernames} + + metricLabels := []string{"admin", "UPDATE"} + if _, err := r.pool.exec(ctx, metricLabels, query, args...); err != nil { + incErrorMetric(err, metricLabels) + return fmt.Errorf("failed to add users to role: %w", err) + } + + return nil +} + +func (r *adminRepository) GetRoles(ctx context.Context) (types.GetRolesRepoResponse, error) { + query := "SELECT id, name, permissions FROM roles ORDER BY id" + + metricLabels := []string{"admin", "SELECT"} + resp := types.GetRolesRepoResponse{} + + rows, err := r.pool.query(ctx, metricLabels, query) + if err != nil { + incErrorMetric(err, metricLabels) + return resp, fmt.Errorf("failed to get roles: %w", err) + } + defer rows.Close() + + for rows.Next() { + var role types.RoleRepo + if err := rows.Scan(&role.ID, &role.Name, &role.Permissions); err != nil { + incErrorMetric(err, metricLabels) + return resp, fmt.Errorf("failed to scan role: %w", err) + } + + resp.Roles = append(resp.Roles, role) + } + + return resp, nil +} + +func (r *adminRepository) GetRole(ctx context.Context, req types.GetRoleRequest) (types.GetRoleResponse, error) { + metricLabels := []string{"admin", "SELECT"} + + roleExists, err := r.roleExists(ctx, req.RoleID) + if err != nil { + return types.GetRoleResponse{}, err + } + if !roleExists { + incErrorMetric(err, metricLabels) + return types.GetRoleResponse{}, types.NewErrNotFound("role") + } + + query, args := "SELECT user_name FROM user_profiles WHERE role_id=$1 ORDER BY user_name", []any{req.RoleID} + resp := types.GetRoleResponse{} + + rows, err := r.pool.query(ctx, metricLabels, query, args...) + if err != nil { + incErrorMetric(err, metricLabels) + return resp, fmt.Errorf("failed to get role users: %w", err) + } + defer rows.Close() + + for rows.Next() { + var username string + if err := rows.Scan(&username); err != nil { + incErrorMetric(err, metricLabels) + return resp, fmt.Errorf("failed to scan role user: %w", err) + } + + resp.Usernames = append(resp.Usernames, username) + } + + return resp, nil +} + +func (r *adminRepository) UpdateRole(ctx context.Context, req types.UpdateRoleRepoRequest) error { + metricLabels := []string{"admin", "UPDATE"} + var ( + query string + args []any + ) + + switch { + case req.Name != nil && req.Permissions != nil: + query = "UPDATE roles SET name=$1, permissions=$2 WHERE id=$3" + args = []any{*req.Name, *req.Permissions, req.RoleID} + case req.Name != nil: + query = "UPDATE roles SET name=$1 WHERE id=$2" + args = []any{*req.Name, req.RoleID} + default: + query = "UPDATE roles SET permissions=$1 WHERE id=$2" + args = []any{*req.Permissions, req.RoleID} + } + + tag, err := r.pool.exec(ctx, metricLabels, query, args...) + if err != nil { + incErrorMetric(err, metricLabels) + return fmt.Errorf("failed to update role: %w", err) + } + + if tag.RowsAffected() == 0 { + incErrorMetric(err, metricLabels) + return types.NewErrNotFound("role") + } + + return nil +} + +func (r *adminRepository) DeleteRole(ctx context.Context, req types.DeleteRoleRequest) error { + metricLabels := []string{"admin", "DELETE"} + var ( + query string + args []any + ) + + ctx, cancel := context.WithTimeout(ctx, r.pool.requestTimeout) + defer cancel() + + tx, err := r.pool.pool.Begin(ctx) + if err != nil { + incErrorMetric(err, metricLabels) + return fmt.Errorf("failed to begin delete role transaction: %w", err) + } + + defer func() { + _ = tx.Rollback(ctx) + }() + + if req.ReplacementRoleID != nil { + replacementRoleExists, err := r.roleExistsTx(ctx, tx, *req.ReplacementRoleID) + if err != nil { + return err + } + if !replacementRoleExists { + incErrorMetric(err, metricLabels) + return types.NewErrNotFound("replacement role") + } + } + + switch { + case req.ReplacementRoleID != nil: + query = "UPDATE user_profiles SET role_id=$1 WHERE role_id=$2" + args = []any{*req.ReplacementRoleID, req.RoleID} + default: + query = "UPDATE user_profiles SET role_id=NULL WHERE role_id=$1" + args = []any{req.RoleID} + } + + if _, err := r.pool.execTx(ctx, tx, metricLabels, query, args...); err != nil { + incErrorMetric(err, metricLabels) + return fmt.Errorf("failed to update user_profiles when delete role: %w", err) + } + + query, args = "DELETE FROM roles WHERE id=$1", []any{req.RoleID} + tag, err := r.pool.execTx(ctx, tx, metricLabels, query, args...) + if err != nil { + incErrorMetric(err, metricLabels) + return fmt.Errorf("failed to delete role: %w", err) + } + + if tag.RowsAffected() == 0 { + incErrorMetric(err, metricLabels) + return types.NewErrNotFound("role") + } + + if err := tx.Commit(ctx); err != nil { + incErrorMetric(err, metricLabels) + return fmt.Errorf("failed to commit delete role transaction: %w", err) + } + + return nil +} + +func (r *adminRepository) GetUserPermissions(ctx context.Context, req types.GetUserPermissionsRequest) (types.GetUserPermissionsResponse, error) { + metricLabels := []string{"admin", "SELECT"} + query, args := "SELECT COALESCE(r.permissions, 0) FROM user_profiles up LEFT JOIN roles r ON r.id=up.role_id WHERE up.user_name=$1", []any{req.Username} + + var permissions uint64 + if err := r.pool.queryRow(ctx, metricLabels, query, args...).Scan(&permissions); err != nil { + incErrorMetric(err, metricLabels) + return types.GetUserPermissionsResponse{}, fmt.Errorf("failed to get user permissions: %w", err) + } + + return types.GetUserPermissionsResponse{Permissions: permissions}, nil +} + +// Transactional check +func (r *adminRepository) roleExistsTx(ctx context.Context, tx pgx.Tx, roleID int32) (bool, error) { + metricLabels := []string{"admin", "SELECT"} + query, args := "SELECT EXISTS(SELECT 1 FROM roles WHERE id=$1)", []any{roleID} + + var exists bool + if err := r.pool.queryRowTx(ctx, tx, metricLabels, query, args...).Scan(&exists); err != nil { + incErrorMetric(err, metricLabels) + return false, fmt.Errorf("failed to check role existence: %w", err) + } + + return exists, nil +} + +// Non-transactional check +func (r *adminRepository) roleExists(ctx context.Context, roleID int32) (bool, error) { + metricLabels := []string{"admin", "SELECT"} + query, args := "SELECT EXISTS(SELECT 1 FROM roles WHERE id=$1)", []any{roleID} + + var exists bool + if err := r.pool.queryRow(ctx, metricLabels, query, args...).Scan(&exists); err != nil { + incErrorMetric(err, metricLabels) + return false, fmt.Errorf("failed to check role existence: %w", err) + } + + return exists, nil +} diff --git a/internal/pkg/repository/mock/repository.go b/internal/pkg/repository/mock/repository.go index 221f703..79312c7 100644 --- a/internal/pkg/repository/mock/repository.go +++ b/internal/pkg/repository/mock/repository.go @@ -360,3 +360,129 @@ func (mr *MockAsyncSearchesMockRecorder) SaveAsyncSearch(arg0, arg1 any) *gomock mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveAsyncSearch", reflect.TypeOf((*MockAsyncSearches)(nil).SaveAsyncSearch), arg0, arg1) } + +// MockAdmin is a mock of Admin interface. +type MockAdmin struct { + ctrl *gomock.Controller + recorder *MockAdminMockRecorder + isgomock struct{} +} + +// MockAdminMockRecorder is the mock recorder for MockAdmin. +type MockAdminMockRecorder struct { + mock *MockAdmin +} + +// NewMockAdmin creates a new mock instance. +func NewMockAdmin(ctrl *gomock.Controller) *MockAdmin { + mock := &MockAdmin{ctrl: ctrl} + mock.recorder = &MockAdminMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAdmin) EXPECT() *MockAdminMockRecorder { + return m.recorder +} + +// AddUsersToRole mocks base method. +func (m *MockAdmin) AddUsersToRole(arg0 context.Context, arg1 types.AddUsersToRoleRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddUsersToRole", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// AddUsersToRole indicates an expected call of AddUsersToRole. +func (mr *MockAdminMockRecorder) AddUsersToRole(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddUsersToRole", reflect.TypeOf((*MockAdmin)(nil).AddUsersToRole), arg0, arg1) +} + +// CreateRole mocks base method. +func (m *MockAdmin) CreateRole(arg0 context.Context, arg1 types.CreateRoleRepoRequest) (types.CreateRoleResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateRole", arg0, arg1) + ret0, _ := ret[0].(types.CreateRoleResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateRole indicates an expected call of CreateRole. +func (mr *MockAdminMockRecorder) CreateRole(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRole", reflect.TypeOf((*MockAdmin)(nil).CreateRole), arg0, arg1) +} + +// DeleteRole mocks base method. +func (m *MockAdmin) DeleteRole(arg0 context.Context, arg1 types.DeleteRoleRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteRole", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteRole indicates an expected call of DeleteRole. +func (mr *MockAdminMockRecorder) DeleteRole(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRole", reflect.TypeOf((*MockAdmin)(nil).DeleteRole), arg0, arg1) +} + +// GetRole mocks base method. +func (m *MockAdmin) GetRole(arg0 context.Context, arg1 types.GetRoleRequest) (types.GetRoleResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRole", arg0, arg1) + ret0, _ := ret[0].(types.GetRoleResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetRole indicates an expected call of GetRole. +func (mr *MockAdminMockRecorder) GetRole(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRole", reflect.TypeOf((*MockAdmin)(nil).GetRole), arg0, arg1) +} + +// GetRoles mocks base method. +func (m *MockAdmin) GetRoles(arg0 context.Context) (types.GetRolesRepoResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRoles", arg0) + ret0, _ := ret[0].(types.GetRolesRepoResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetRoles indicates an expected call of GetRoles. +func (mr *MockAdminMockRecorder) GetRoles(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRoles", reflect.TypeOf((*MockAdmin)(nil).GetRoles), arg0) +} + +// GetUserPermissions mocks base method. +func (m *MockAdmin) GetUserPermissions(arg0 context.Context, arg1 types.GetUserPermissionsRequest) (types.GetUserPermissionsResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserPermissions", arg0, arg1) + ret0, _ := ret[0].(types.GetUserPermissionsResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserPermissions indicates an expected call of GetUserPermissions. +func (mr *MockAdminMockRecorder) GetUserPermissions(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserPermissions", reflect.TypeOf((*MockAdmin)(nil).GetUserPermissions), arg0, arg1) +} + +// UpdateRole mocks base method. +func (m *MockAdmin) UpdateRole(arg0 context.Context, arg1 types.UpdateRoleRepoRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateRole", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateRole indicates an expected call of UpdateRole. +func (mr *MockAdminMockRecorder) UpdateRole(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateRole", reflect.TypeOf((*MockAdmin)(nil).UpdateRole), arg0, arg1) +} diff --git a/internal/pkg/repository/pool.go b/internal/pkg/repository/pool.go index 3df1379..a160720 100644 --- a/internal/pkg/repository/pool.go +++ b/internal/pkg/repository/pool.go @@ -60,3 +60,23 @@ func (p *pool) exec(ctx context.Context, metricLabels []string, query string, ar return tag, err } + +func (p *pool) execTx(ctx context.Context, tx pgx.Tx, metricLabels []string, query string, args ...any) (pgconn.CommandTag, error) { + metric.RepositoryRequestSent.WithLabelValues(metricLabels...).Inc() + start := time.Now() + tag, err := tx.Exec(ctx, query, args...) + took := time.Since(start) + metric.RepositoryRequestDuration.WithLabelValues(metricLabels...).Observe(took.Seconds()) + + return tag, err +} + +func (p *pool) queryRowTx(ctx context.Context, tx pgx.Tx, metricLabels []string, query string, args ...any) pgx.Row { + metric.RepositoryRequestSent.WithLabelValues(metricLabels...).Inc() + start := time.Now() + row := tx.QueryRow(ctx, query, args...) + took := time.Since(start) + metric.RepositoryRequestDuration.WithLabelValues(metricLabels...).Observe(took.Seconds()) + + return row +} diff --git a/internal/pkg/repository/repository.go b/internal/pkg/repository/repository.go index 78044dc..243e852 100644 --- a/internal/pkg/repository/repository.go +++ b/internal/pkg/repository/repository.go @@ -37,6 +37,16 @@ type ( DeleteExpiredAsyncSearches(context.Context) error GetAsyncSearchesList(context.Context, types.GetAsyncSearchesListRequest) ([]types.AsyncSearchInfo, error) } + + Admin interface { + CreateRole(context.Context, types.CreateRoleRepoRequest) (types.CreateRoleResponse, error) + AddUsersToRole(context.Context, types.AddUsersToRoleRequest) error + GetRoles(context.Context) (types.GetRolesRepoResponse, error) + GetRole(context.Context, types.GetRoleRequest) (types.GetRoleResponse, error) + UpdateRole(context.Context, types.UpdateRoleRepoRequest) error + DeleteRole(context.Context, types.DeleteRoleRequest) error + GetUserPermissions(context.Context, types.GetUserPermissionsRequest) (types.GetUserPermissionsResponse, error) + } ) type Repository struct { @@ -44,6 +54,7 @@ type Repository struct { FavoriteQueries Dashboards AsyncSearches + Admin } func New(pool *pgxpool.Pool, requestTimeout time.Duration) *Repository { @@ -53,5 +64,6 @@ func New(pool *pgxpool.Pool, requestTimeout time.Duration) *Repository { FavoriteQueries: newFavoriteQueriesRepository(p), Dashboards: newDashboardsRepository(p), AsyncSearches: newAsyncSearchesRepository(p), + Admin: newAdminRepository(p), } } diff --git a/internal/pkg/service/admin.go b/internal/pkg/service/admin.go new file mode 100644 index 0000000..25ccb7f --- /dev/null +++ b/internal/pkg/service/admin.go @@ -0,0 +1,124 @@ +package service + +import ( + "context" + + "github.com/ozontech/seq-ui/internal/app/types" +) + +func (s *service) CreateRole(ctx context.Context, req types.CreateRoleRequest) (types.CreateRoleResponse, error) { + if req.Name == "" { + return types.CreateRoleResponse{}, types.NewErrInvalidRequestField("empty role name") + } + + if err := validatePermissions(req.Permissions); err != nil { + return types.CreateRoleResponse{}, err + } + + return s.repo.CreateRole(ctx, types.CreateRoleRepoRequest{ + Name: req.Name, + Permissions: permissionsToValue(req.Permissions), + }) +} + +func (s *service) AddUsersToRole(ctx context.Context, req types.AddUsersToRoleRequest) error { + if req.RoleID <= 0 { + return types.NewErrInvalidRequestField("value role_id must be greater than 0") + } + + if len(req.Usernames) == 0 { + return types.NewErrInvalidRequestField("empty usernames") + } + + for _, username := range req.Usernames { + if username == "" { + return types.NewErrInvalidRequestField("empty username") + } + } + + return s.repo.AddUsersToRole(ctx, req) +} + +func (s *service) GetRoles(ctx context.Context) (types.GetRolesResponse, error) { + resp, err := s.repo.GetRoles(ctx) + if err != nil { + return types.GetRolesResponse{}, err + } + + roles := make([]types.Role, 0, len(resp.Roles)) + for _, role := range resp.Roles { + roles = append(roles, types.Role{ + ID: role.ID, + Name: role.Name, + Permissions: valueToPermissions(role.Permissions), + }) + } + + return types.GetRolesResponse{ + Roles: roles, + AvailablePermissions: availablePermissions, + }, nil +} + +func (s *service) GetRole(ctx context.Context, req types.GetRoleRequest) (types.GetRoleResponse, error) { + if req.RoleID <= 0 { + return types.GetRoleResponse{}, types.NewErrInvalidRequestField("value role_id must be greater than 0") + } + + return s.repo.GetRole(ctx, req) +} + +func (s *service) UpdateRole(ctx context.Context, req types.UpdateRoleRequest) error { + if req.RoleID <= 0 { + return types.NewErrInvalidRequestField("value role_id must be greater than 0") + } + + if req.Name == nil && len(req.Permissions) == 0 { + return types.ErrEmptyUpdateRequest + } + + if req.Name != nil && *req.Name == "" { + return types.NewErrInvalidRequestField("empty role name") + } + + var permissions *uint64 + if len(req.Permissions) > 0 { + if err := validatePermissions(req.Permissions); err != nil { + return err + } + + value := permissionsToValue(req.Permissions) + permissions = &value + } + + return s.repo.UpdateRole(ctx, types.UpdateRoleRepoRequest{ + RoleID: req.RoleID, + Name: req.Name, + Permissions: permissions, + }) +} + +func (s *service) DeleteRole(ctx context.Context, req types.DeleteRoleRequest) error { + if req.RoleID <= 0 { + return types.NewErrInvalidRequestField("value role_id must be greater than 0") + } + + if req.ReplacementRoleID != nil { + if *req.ReplacementRoleID <= 0 { + return types.NewErrInvalidRequestField("value replacement_role_id must be greater than 0") + } + if *req.ReplacementRoleID == req.RoleID { + return types.NewErrInvalidRequestField("replacement_role_id must be not equal to role_id") + } + } + + return s.repo.DeleteRole(ctx, req) +} + +func (s *service) GetUserPermissions(ctx context.Context, req types.GetUserPermissionsRequest) (types.GetUserPermissionsResponse, error) { + return s.repo.GetUserPermissions(ctx, req) +} + +func (s *service) GetAvailablePermissions() []types.Permission { + return availablePermissions +} diff --git a/internal/pkg/service/admin_permissions.go b/internal/pkg/service/admin_permissions.go new file mode 100644 index 0000000..25db55c --- /dev/null +++ b/internal/pkg/service/admin_permissions.go @@ -0,0 +1,68 @@ +package service + +import ( + "fmt" + + "github.com/ozontech/seq-ui/internal/app/types" +) + +const ( + PermissionAdminAccess uint64 = 1 << iota + PermissionManageRoles +) + +var availablePermissions = []types.Permission{ + { + Value: PermissionAdminAccess, + Name: "admin_access", + Description: ptr("Access to admin page"), + }, + { + Value: PermissionManageRoles, + Name: "manage_roles_access", + Description: ptr("Manage roles"), + }, +} + +var availablePermissionsMap = map[uint64]struct{}{ + PermissionAdminAccess: {}, + PermissionManageRoles: {}, +} + +func valueToPermissions(value uint64) []uint64 { + permissions := make([]uint64, 0) + + for _, permission := range availablePermissions { + if value&permission.Value != 0 { + permissions = append(permissions, permission.Value) + } + } + + return permissions +} + +func validatePermissions(permissions []uint64) error { + if len(permissions) == 0 { + return types.NewErrInvalidRequestField("empty permissions") + } + + for _, permission := range permissions { + if _, ok := availablePermissionsMap[permission]; !ok { + return fmt.Errorf("unknown permission: %d", permission) + } + } + + return nil +} + +func permissionsToValue(permissions []uint64) uint64 { + var value uint64 + for _, permission := range permissions { + value |= permission + } + return value +} + +func ptr(desc string) *string { + return &desc +} diff --git a/internal/pkg/service/service.go b/internal/pkg/service/service.go index 4a34733..faeda94 100644 --- a/internal/pkg/service/service.go +++ b/internal/pkg/service/service.go @@ -22,6 +22,15 @@ type Service interface { UpdateDashboard(context.Context, types.UpdateDashboardRequest) error DeleteDashboard(context.Context, types.DeleteDashboardRequest) error SearchDashboards(context.Context, types.SearchDashboardsRequest) (types.DashboardInfosWithOwner, error) + + CreateRole(context.Context, types.CreateRoleRequest) (types.CreateRoleResponse, error) + AddUsersToRole(context.Context, types.AddUsersToRoleRequest) error + GetRoles(context.Context) (types.GetRolesResponse, error) + GetRole(context.Context, types.GetRoleRequest) (types.GetRoleResponse, error) + UpdateRole(context.Context, types.UpdateRoleRequest) error + DeleteRole(context.Context, types.DeleteRoleRequest) error + GetUserPermissions(context.Context, types.GetUserPermissionsRequest) (types.GetUserPermissionsResponse, error) + GetAvailablePermissions() []types.Permission } type service struct { diff --git a/migration/12_admin_initial.sql b/migration/12_admin_initial.sql new file mode 100644 index 0000000..d8dca9f --- /dev/null +++ b/migration/12_admin_initial.sql @@ -0,0 +1,21 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE IF NOT EXISTS roles( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL UNIQUE, + permissions BIGINT NOT NULL DEFAULT 0 +); + +ALTER TABLE IF EXISTS user_profiles ADD COLUMN IF NOT EXISTS role_id INTEGER; + +CREATE INDEX IF NOT EXISTS idx_user_profiles_role_id ON user_profiles USING HASH (role_id); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP INDEX IF EXISTS idx_user_profiles_role_id; + +ALTER TABLE IF EXISTS user_profiles DROP COLUMN IF EXISTS role_id; + +DROP TABLE IF EXISTS roles; +-- +goose StatementEnd diff --git a/pkg/admin/v1/admin.pb.go b/pkg/admin/v1/admin.pb.go new file mode 100644 index 0000000..7661db5 --- /dev/null +++ b/pkg/admin/v1/admin.pb.go @@ -0,0 +1,1070 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.2 +// protoc v7.34.1 +// source: admin/v1/admin.proto + +package admin + +import ( + 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) +) + +type Role struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Permissions []uint64 `protobuf:"varint,3,rep,packed,name=permissions,proto3" json:"permissions,omitempty"` +} + +func (x *Role) Reset() { + *x = Role{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Role) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Role) ProtoMessage() {} + +func (x *Role) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_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 Role.ProtoReflect.Descriptor instead. +func (*Role) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{0} +} + +func (x *Role) GetId() int32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Role) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Role) GetPermissions() []uint64 { + if x != nil { + return x.Permissions + } + return nil +} + +type CreateRoleRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Permissions []uint64 `protobuf:"varint,2,rep,packed,name=permissions,proto3" json:"permissions,omitempty"` +} + +func (x *CreateRoleRequest) Reset() { + *x = CreateRoleRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateRoleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateRoleRequest) ProtoMessage() {} + +func (x *CreateRoleRequest) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_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 CreateRoleRequest.ProtoReflect.Descriptor instead. +func (*CreateRoleRequest) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{1} +} + +func (x *CreateRoleRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CreateRoleRequest) GetPermissions() []uint64 { + if x != nil { + return x.Permissions + } + return nil +} + +type CreateRoleResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RoleId int32 `protobuf:"varint,1,opt,name=role_id,json=roleId,proto3" json:"role_id,omitempty"` +} + +func (x *CreateRoleResponse) Reset() { + *x = CreateRoleResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateRoleResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateRoleResponse) ProtoMessage() {} + +func (x *CreateRoleResponse) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_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 CreateRoleResponse.ProtoReflect.Descriptor instead. +func (*CreateRoleResponse) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{2} +} + +func (x *CreateRoleResponse) GetRoleId() int32 { + if x != nil { + return x.RoleId + } + return 0 +} + +type AddUsersToRoleRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RoleId int32 `protobuf:"varint,1,opt,name=role_id,json=roleId,proto3" json:"role_id,omitempty"` + Usernames []string `protobuf:"bytes,2,rep,name=usernames,proto3" json:"usernames,omitempty"` +} + +func (x *AddUsersToRoleRequest) Reset() { + *x = AddUsersToRoleRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddUsersToRoleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddUsersToRoleRequest) ProtoMessage() {} + +func (x *AddUsersToRoleRequest) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_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 AddUsersToRoleRequest.ProtoReflect.Descriptor instead. +func (*AddUsersToRoleRequest) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{3} +} + +func (x *AddUsersToRoleRequest) GetRoleId() int32 { + if x != nil { + return x.RoleId + } + return 0 +} + +func (x *AddUsersToRoleRequest) GetUsernames() []string { + if x != nil { + return x.Usernames + } + return nil +} + +type AddUsersToRoleResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AddUsersToRoleResponse) Reset() { + *x = AddUsersToRoleResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddUsersToRoleResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddUsersToRoleResponse) ProtoMessage() {} + +func (x *AddUsersToRoleResponse) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_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 AddUsersToRoleResponse.ProtoReflect.Descriptor instead. +func (*AddUsersToRoleResponse) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{4} +} + +type GetRolesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetRolesRequest) Reset() { + *x = GetRolesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetRolesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRolesRequest) ProtoMessage() {} + +func (x *GetRolesRequest) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_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 GetRolesRequest.ProtoReflect.Descriptor instead. +func (*GetRolesRequest) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{5} +} + +type GetRolesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Roles []*Role `protobuf:"bytes,1,rep,name=roles,proto3" json:"roles,omitempty"` + AvailablePermissions []*GetRolesResponse_Permission `protobuf:"bytes,2,rep,name=available_permissions,json=availablePermissions,proto3" json:"available_permissions,omitempty"` +} + +func (x *GetRolesResponse) Reset() { + *x = GetRolesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetRolesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRolesResponse) ProtoMessage() {} + +func (x *GetRolesResponse) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_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 GetRolesResponse.ProtoReflect.Descriptor instead. +func (*GetRolesResponse) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{6} +} + +func (x *GetRolesResponse) GetRoles() []*Role { + if x != nil { + return x.Roles + } + return nil +} + +func (x *GetRolesResponse) GetAvailablePermissions() []*GetRolesResponse_Permission { + if x != nil { + return x.AvailablePermissions + } + return nil +} + +type GetRoleRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *GetRoleRequest) Reset() { + *x = GetRoleRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetRoleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRoleRequest) ProtoMessage() {} + +func (x *GetRoleRequest) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_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 GetRoleRequest.ProtoReflect.Descriptor instead. +func (*GetRoleRequest) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{7} +} + +func (x *GetRoleRequest) GetId() int32 { + if x != nil { + return x.Id + } + return 0 +} + +type GetRoleResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Usernames []string `protobuf:"bytes,1,rep,name=usernames,proto3" json:"usernames,omitempty"` +} + +func (x *GetRoleResponse) Reset() { + *x = GetRoleResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetRoleResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRoleResponse) ProtoMessage() {} + +func (x *GetRoleResponse) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_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 GetRoleResponse.ProtoReflect.Descriptor instead. +func (*GetRoleResponse) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{8} +} + +func (x *GetRoleResponse) GetUsernames() []string { + if x != nil { + return x.Usernames + } + return nil +} + +type UpdateRoleRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Name *string `protobuf:"bytes,2,opt,name=name,proto3,oneof" json:"name,omitempty"` + Permissions []uint64 `protobuf:"varint,3,rep,packed,name=permissions,proto3" json:"permissions,omitempty"` +} + +func (x *UpdateRoleRequest) Reset() { + *x = UpdateRoleRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateRoleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateRoleRequest) ProtoMessage() {} + +func (x *UpdateRoleRequest) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_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 UpdateRoleRequest.ProtoReflect.Descriptor instead. +func (*UpdateRoleRequest) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{9} +} + +func (x *UpdateRoleRequest) GetId() int32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *UpdateRoleRequest) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *UpdateRoleRequest) GetPermissions() []uint64 { + if x != nil { + return x.Permissions + } + return nil +} + +type UpdateRoleResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateRoleResponse) Reset() { + *x = UpdateRoleResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateRoleResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateRoleResponse) ProtoMessage() {} + +func (x *UpdateRoleResponse) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateRoleResponse.ProtoReflect.Descriptor instead. +func (*UpdateRoleResponse) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{10} +} + +type DeleteRoleRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + ReplacementRoleId *int32 `protobuf:"varint,2,opt,name=replacement_role_id,json=replacementRoleId,proto3,oneof" json:"replacement_role_id,omitempty"` +} + +func (x *DeleteRoleRequest) Reset() { + *x = DeleteRoleRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteRoleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteRoleRequest) ProtoMessage() {} + +func (x *DeleteRoleRequest) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteRoleRequest.ProtoReflect.Descriptor instead. +func (*DeleteRoleRequest) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{11} +} + +func (x *DeleteRoleRequest) GetId() int32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *DeleteRoleRequest) GetReplacementRoleId() int32 { + if x != nil && x.ReplacementRoleId != nil { + return *x.ReplacementRoleId + } + return 0 +} + +type DeleteRoleResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteRoleResponse) Reset() { + *x = DeleteRoleResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteRoleResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteRoleResponse) ProtoMessage() {} + +func (x *DeleteRoleResponse) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteRoleResponse.ProtoReflect.Descriptor instead. +func (*DeleteRoleResponse) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{12} +} + +type GetRolesResponse_Permission struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Description *string `protobuf:"bytes,3,opt,name=description,proto3,oneof" json:"description,omitempty"` +} + +func (x *GetRolesResponse_Permission) Reset() { + *x = GetRolesResponse_Permission{} + if protoimpl.UnsafeEnabled { + mi := &file_admin_v1_admin_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetRolesResponse_Permission) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRolesResponse_Permission) ProtoMessage() {} + +func (x *GetRolesResponse_Permission) ProtoReflect() protoreflect.Message { + mi := &file_admin_v1_admin_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRolesResponse_Permission.ProtoReflect.Descriptor instead. +func (*GetRolesResponse_Permission) Descriptor() ([]byte, []int) { + return file_admin_v1_admin_proto_rawDescGZIP(), []int{6, 0} +} + +func (x *GetRolesResponse_Permission) GetValue() uint64 { + if x != nil { + return x.Value + } + return 0 +} + +func (x *GetRolesResponse_Permission) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *GetRolesResponse_Permission) GetDescription() string { + if x != nil && x.Description != nil { + return *x.Description + } + return "" +} + +var File_admin_v1_admin_proto protoreflect.FileDescriptor + +var file_admin_v1_admin_proto_rawDesc = []byte{ + 0x0a, 0x14, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, + 0x22, 0x4c, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, + 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x04, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x49, + 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0b, 0x70, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x2d, 0x0a, 0x12, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x06, 0x72, 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x22, 0x4e, 0x0a, 0x15, 0x41, 0x64, 0x64, 0x55, + 0x73, 0x65, 0x72, 0x73, 0x54, 0x6f, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x06, 0x72, 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x41, 0x64, 0x64, 0x55, + 0x73, 0x65, 0x72, 0x73, 0x54, 0x6f, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x11, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x83, 0x02, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x05, 0x72, 0x6f, + 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, + 0x12, 0x5a, 0x0a, 0x15, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x70, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x25, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, + 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x65, 0x72, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x14, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, + 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x6d, 0x0a, 0x0a, + 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x20, 0x0a, 0x0e, 0x47, + 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x22, 0x2f, 0x0a, + 0x0f, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x67, + 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x0b, + 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x04, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x07, + 0x0a, 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x70, 0x0a, + 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x33, 0x0a, 0x13, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x48, + 0x00, 0x52, 0x11, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x6f, + 0x6c, 0x65, 0x49, 0x64, 0x88, 0x01, 0x01, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x72, 0x65, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x22, + 0x14, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc1, 0x03, 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x47, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x1b, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x53, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x54, 0x6f, 0x52, 0x6f, 0x6c, + 0x65, 0x12, 0x1f, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, + 0x55, 0x73, 0x65, 0x72, 0x73, 0x54, 0x6f, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, + 0x64, 0x55, 0x73, 0x65, 0x72, 0x73, 0x54, 0x6f, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x73, + 0x12, 0x19, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, + 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x52, 0x6f, + 0x6c, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, + 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x1b, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x47, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x1b, + 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6c, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x7a, 0x6f, 0x6e, 0x74, 0x65, 0x63, 0x68, + 0x2f, 0x73, 0x65, 0x71, 0x2d, 0x75, 0x69, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_admin_v1_admin_proto_rawDescOnce sync.Once + file_admin_v1_admin_proto_rawDescData = file_admin_v1_admin_proto_rawDesc +) + +func file_admin_v1_admin_proto_rawDescGZIP() []byte { + file_admin_v1_admin_proto_rawDescOnce.Do(func() { + file_admin_v1_admin_proto_rawDescData = protoimpl.X.CompressGZIP(file_admin_v1_admin_proto_rawDescData) + }) + return file_admin_v1_admin_proto_rawDescData +} + +var file_admin_v1_admin_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_admin_v1_admin_proto_goTypes = []any{ + (*Role)(nil), // 0: admin.v1.Role + (*CreateRoleRequest)(nil), // 1: admin.v1.CreateRoleRequest + (*CreateRoleResponse)(nil), // 2: admin.v1.CreateRoleResponse + (*AddUsersToRoleRequest)(nil), // 3: admin.v1.AddUsersToRoleRequest + (*AddUsersToRoleResponse)(nil), // 4: admin.v1.AddUsersToRoleResponse + (*GetRolesRequest)(nil), // 5: admin.v1.GetRolesRequest + (*GetRolesResponse)(nil), // 6: admin.v1.GetRolesResponse + (*GetRoleRequest)(nil), // 7: admin.v1.GetRoleRequest + (*GetRoleResponse)(nil), // 8: admin.v1.GetRoleResponse + (*UpdateRoleRequest)(nil), // 9: admin.v1.UpdateRoleRequest + (*UpdateRoleResponse)(nil), // 10: admin.v1.UpdateRoleResponse + (*DeleteRoleRequest)(nil), // 11: admin.v1.DeleteRoleRequest + (*DeleteRoleResponse)(nil), // 12: admin.v1.DeleteRoleResponse + (*GetRolesResponse_Permission)(nil), // 13: admin.v1.GetRolesResponse.Permission +} +var file_admin_v1_admin_proto_depIdxs = []int32{ + 0, // 0: admin.v1.GetRolesResponse.roles:type_name -> admin.v1.Role + 13, // 1: admin.v1.GetRolesResponse.available_permissions:type_name -> admin.v1.GetRolesResponse.Permission + 1, // 2: admin.v1.AdminService.CreateRole:input_type -> admin.v1.CreateRoleRequest + 3, // 3: admin.v1.AdminService.AddUsersToRole:input_type -> admin.v1.AddUsersToRoleRequest + 5, // 4: admin.v1.AdminService.GetRoles:input_type -> admin.v1.GetRolesRequest + 7, // 5: admin.v1.AdminService.GetRole:input_type -> admin.v1.GetRoleRequest + 9, // 6: admin.v1.AdminService.UpdateRole:input_type -> admin.v1.UpdateRoleRequest + 11, // 7: admin.v1.AdminService.DeleteRole:input_type -> admin.v1.DeleteRoleRequest + 2, // 8: admin.v1.AdminService.CreateRole:output_type -> admin.v1.CreateRoleResponse + 4, // 9: admin.v1.AdminService.AddUsersToRole:output_type -> admin.v1.AddUsersToRoleResponse + 6, // 10: admin.v1.AdminService.GetRoles:output_type -> admin.v1.GetRolesResponse + 8, // 11: admin.v1.AdminService.GetRole:output_type -> admin.v1.GetRoleResponse + 10, // 12: admin.v1.AdminService.UpdateRole:output_type -> admin.v1.UpdateRoleResponse + 12, // 13: admin.v1.AdminService.DeleteRole:output_type -> admin.v1.DeleteRoleResponse + 8, // [8:14] is the sub-list for method output_type + 2, // [2:8] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_admin_v1_admin_proto_init() } +func file_admin_v1_admin_proto_init() { + if File_admin_v1_admin_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_admin_v1_admin_proto_msgTypes[0].Exporter = func(v any, i int) any { + switch v := v.(*Role); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_v1_admin_proto_msgTypes[1].Exporter = func(v any, i int) any { + switch v := v.(*CreateRoleRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_v1_admin_proto_msgTypes[2].Exporter = func(v any, i int) any { + switch v := v.(*CreateRoleResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_v1_admin_proto_msgTypes[3].Exporter = func(v any, i int) any { + switch v := v.(*AddUsersToRoleRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_v1_admin_proto_msgTypes[4].Exporter = func(v any, i int) any { + switch v := v.(*AddUsersToRoleResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_v1_admin_proto_msgTypes[5].Exporter = func(v any, i int) any { + switch v := v.(*GetRolesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_v1_admin_proto_msgTypes[6].Exporter = func(v any, i int) any { + switch v := v.(*GetRolesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_v1_admin_proto_msgTypes[7].Exporter = func(v any, i int) any { + switch v := v.(*GetRoleRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_v1_admin_proto_msgTypes[8].Exporter = func(v any, i int) any { + switch v := v.(*GetRoleResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_v1_admin_proto_msgTypes[9].Exporter = func(v any, i int) any { + switch v := v.(*UpdateRoleRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_v1_admin_proto_msgTypes[10].Exporter = func(v any, i int) any { + switch v := v.(*UpdateRoleResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_v1_admin_proto_msgTypes[11].Exporter = func(v any, i int) any { + switch v := v.(*DeleteRoleRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_v1_admin_proto_msgTypes[12].Exporter = func(v any, i int) any { + switch v := v.(*DeleteRoleResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_admin_v1_admin_proto_msgTypes[13].Exporter = func(v any, i int) any { + switch v := v.(*GetRolesResponse_Permission); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_admin_v1_admin_proto_msgTypes[9].OneofWrappers = []any{} + file_admin_v1_admin_proto_msgTypes[11].OneofWrappers = []any{} + file_admin_v1_admin_proto_msgTypes[13].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_admin_v1_admin_proto_rawDesc, + NumEnums: 0, + NumMessages: 14, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_admin_v1_admin_proto_goTypes, + DependencyIndexes: file_admin_v1_admin_proto_depIdxs, + MessageInfos: file_admin_v1_admin_proto_msgTypes, + }.Build() + File_admin_v1_admin_proto = out.File + file_admin_v1_admin_proto_rawDesc = nil + file_admin_v1_admin_proto_goTypes = nil + file_admin_v1_admin_proto_depIdxs = nil +} diff --git a/pkg/admin/v1/admin_grpc.pb.go b/pkg/admin/v1/admin_grpc.pb.go new file mode 100644 index 0000000..afc56ff --- /dev/null +++ b/pkg/admin/v1/admin_grpc.pb.go @@ -0,0 +1,298 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.4.0 +// - protoc v7.34.1 +// source: admin/v1/admin.proto + +package admin + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.62.0 or later. +const _ = grpc.SupportPackageIsVersion8 + +const ( + AdminService_CreateRole_FullMethodName = "/admin.v1.AdminService/CreateRole" + AdminService_AddUsersToRole_FullMethodName = "/admin.v1.AdminService/AddUsersToRole" + AdminService_GetRoles_FullMethodName = "/admin.v1.AdminService/GetRoles" + AdminService_GetRole_FullMethodName = "/admin.v1.AdminService/GetRole" + AdminService_UpdateRole_FullMethodName = "/admin.v1.AdminService/UpdateRole" + AdminService_DeleteRole_FullMethodName = "/admin.v1.AdminService/DeleteRole" +) + +// AdminServiceClient is the client API for AdminService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type AdminServiceClient interface { + CreateRole(ctx context.Context, in *CreateRoleRequest, opts ...grpc.CallOption) (*CreateRoleResponse, error) + AddUsersToRole(ctx context.Context, in *AddUsersToRoleRequest, opts ...grpc.CallOption) (*AddUsersToRoleResponse, error) + GetRoles(ctx context.Context, in *GetRolesRequest, opts ...grpc.CallOption) (*GetRolesResponse, error) + GetRole(ctx context.Context, in *GetRoleRequest, opts ...grpc.CallOption) (*GetRoleResponse, error) + UpdateRole(ctx context.Context, in *UpdateRoleRequest, opts ...grpc.CallOption) (*UpdateRoleResponse, error) + DeleteRole(ctx context.Context, in *DeleteRoleRequest, opts ...grpc.CallOption) (*DeleteRoleResponse, error) +} + +type adminServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewAdminServiceClient(cc grpc.ClientConnInterface) AdminServiceClient { + return &adminServiceClient{cc} +} + +func (c *adminServiceClient) CreateRole(ctx context.Context, in *CreateRoleRequest, opts ...grpc.CallOption) (*CreateRoleResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateRoleResponse) + err := c.cc.Invoke(ctx, AdminService_CreateRole_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) AddUsersToRole(ctx context.Context, in *AddUsersToRoleRequest, opts ...grpc.CallOption) (*AddUsersToRoleResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddUsersToRoleResponse) + err := c.cc.Invoke(ctx, AdminService_AddUsersToRole_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) GetRoles(ctx context.Context, in *GetRolesRequest, opts ...grpc.CallOption) (*GetRolesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetRolesResponse) + err := c.cc.Invoke(ctx, AdminService_GetRoles_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) GetRole(ctx context.Context, in *GetRoleRequest, opts ...grpc.CallOption) (*GetRoleResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetRoleResponse) + err := c.cc.Invoke(ctx, AdminService_GetRole_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) UpdateRole(ctx context.Context, in *UpdateRoleRequest, opts ...grpc.CallOption) (*UpdateRoleResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateRoleResponse) + err := c.cc.Invoke(ctx, AdminService_UpdateRole_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adminServiceClient) DeleteRole(ctx context.Context, in *DeleteRoleRequest, opts ...grpc.CallOption) (*DeleteRoleResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteRoleResponse) + err := c.cc.Invoke(ctx, AdminService_DeleteRole_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AdminServiceServer is the server API for AdminService service. +// All implementations should embed UnimplementedAdminServiceServer +// for forward compatibility +type AdminServiceServer interface { + CreateRole(context.Context, *CreateRoleRequest) (*CreateRoleResponse, error) + AddUsersToRole(context.Context, *AddUsersToRoleRequest) (*AddUsersToRoleResponse, error) + GetRoles(context.Context, *GetRolesRequest) (*GetRolesResponse, error) + GetRole(context.Context, *GetRoleRequest) (*GetRoleResponse, error) + UpdateRole(context.Context, *UpdateRoleRequest) (*UpdateRoleResponse, error) + DeleteRole(context.Context, *DeleteRoleRequest) (*DeleteRoleResponse, error) +} + +// UnimplementedAdminServiceServer should be embedded to have forward compatible implementations. +type UnimplementedAdminServiceServer struct { +} + +func (UnimplementedAdminServiceServer) CreateRole(context.Context, *CreateRoleRequest) (*CreateRoleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateRole not implemented") +} +func (UnimplementedAdminServiceServer) AddUsersToRole(context.Context, *AddUsersToRoleRequest) (*AddUsersToRoleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddUsersToRole not implemented") +} +func (UnimplementedAdminServiceServer) GetRoles(context.Context, *GetRolesRequest) (*GetRolesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetRoles not implemented") +} +func (UnimplementedAdminServiceServer) GetRole(context.Context, *GetRoleRequest) (*GetRoleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetRole not implemented") +} +func (UnimplementedAdminServiceServer) UpdateRole(context.Context, *UpdateRoleRequest) (*UpdateRoleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateRole not implemented") +} +func (UnimplementedAdminServiceServer) DeleteRole(context.Context, *DeleteRoleRequest) (*DeleteRoleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteRole not implemented") +} + +// UnsafeAdminServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to AdminServiceServer will +// result in compilation errors. +type UnsafeAdminServiceServer interface { + mustEmbedUnimplementedAdminServiceServer() +} + +func RegisterAdminServiceServer(s grpc.ServiceRegistrar, srv AdminServiceServer) { + s.RegisterService(&AdminService_ServiceDesc, srv) +} + +func _AdminService_CreateRole_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateRoleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).CreateRole(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_CreateRole_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).CreateRole(ctx, req.(*CreateRoleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_AddUsersToRole_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddUsersToRoleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).AddUsersToRole(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_AddUsersToRole_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).AddUsersToRole(ctx, req.(*AddUsersToRoleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_GetRoles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetRolesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).GetRoles(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_GetRoles_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).GetRoles(ctx, req.(*GetRolesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_GetRole_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetRoleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).GetRole(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_GetRole_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).GetRole(ctx, req.(*GetRoleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_UpdateRole_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateRoleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).UpdateRole(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_UpdateRole_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).UpdateRole(ctx, req.(*UpdateRoleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdminService_DeleteRole_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteRoleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdminServiceServer).DeleteRole(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdminService_DeleteRole_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdminServiceServer).DeleteRole(ctx, req.(*DeleteRoleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// AdminService_ServiceDesc is the grpc.ServiceDesc for AdminService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var AdminService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "admin.v1.AdminService", + HandlerType: (*AdminServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateRole", + Handler: _AdminService_CreateRole_Handler, + }, + { + MethodName: "AddUsersToRole", + Handler: _AdminService_AddUsersToRole_Handler, + }, + { + MethodName: "GetRoles", + Handler: _AdminService_GetRoles_Handler, + }, + { + MethodName: "GetRole", + Handler: _AdminService_GetRole_Handler, + }, + { + MethodName: "UpdateRole", + Handler: _AdminService_UpdateRole_Handler, + }, + { + MethodName: "DeleteRole", + Handler: _AdminService_DeleteRole_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "admin/v1/admin.proto", +} diff --git a/pkg/dashboards/v1/dashboards.pb.go b/pkg/dashboards/v1/dashboards.pb.go index 2a0ad02..7f74181 100644 --- a/pkg/dashboards/v1/dashboards.pb.go +++ b/pkg/dashboards/v1/dashboards.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc v6.33.4 +// protoc v7.34.1 // source: dashboards/v1/dashboards.proto package dashboards diff --git a/pkg/dashboards/v1/dashboards_grpc.pb.go b/pkg/dashboards/v1/dashboards_grpc.pb.go index d8b1ca7..8217c47 100644 --- a/pkg/dashboards/v1/dashboards_grpc.pb.go +++ b/pkg/dashboards/v1/dashboards_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 -// - protoc v6.33.4 +// - protoc v7.34.1 // source: dashboards/v1/dashboards.proto package dashboards diff --git a/pkg/errorgroups/v1/errorgroups.pb.go b/pkg/errorgroups/v1/errorgroups.pb.go index 220df28..b21fb5e 100644 --- a/pkg/errorgroups/v1/errorgroups.pb.go +++ b/pkg/errorgroups/v1/errorgroups.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc v6.33.4 +// protoc v7.34.1 // source: errorgroups/v1/errorgroups.proto package errorgroups diff --git a/pkg/errorgroups/v1/errorgroups_grpc.pb.go b/pkg/errorgroups/v1/errorgroups_grpc.pb.go index ba752fa..1828b07 100644 --- a/pkg/errorgroups/v1/errorgroups_grpc.pb.go +++ b/pkg/errorgroups/v1/errorgroups_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 -// - protoc v6.33.4 +// - protoc v7.34.1 // source: errorgroups/v1/errorgroups.proto package errorgroups diff --git a/pkg/massexport/v1/massexport.pb.go b/pkg/massexport/v1/massexport.pb.go index b04ba0a..f624bfe 100644 --- a/pkg/massexport/v1/massexport.pb.go +++ b/pkg/massexport/v1/massexport.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc v6.33.4 +// protoc v7.34.1 // source: massexport/v1/massexport.proto package massexport diff --git a/pkg/massexport/v1/massexport_grpc.pb.go b/pkg/massexport/v1/massexport_grpc.pb.go index 99316dc..eaaea70 100644 --- a/pkg/massexport/v1/massexport_grpc.pb.go +++ b/pkg/massexport/v1/massexport_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 -// - protoc v6.33.4 +// - protoc v7.34.1 // source: massexport/v1/massexport.proto package massexport diff --git a/pkg/seqapi/v1/seq_api.pb.go b/pkg/seqapi/v1/seq_api.pb.go index 2269ecf..16361db 100644 --- a/pkg/seqapi/v1/seq_api.pb.go +++ b/pkg/seqapi/v1/seq_api.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc v6.33.4 +// protoc v7.34.1 // source: seqapi/v1/seq_api.proto package seqapi diff --git a/pkg/seqapi/v1/seq_api_grpc.pb.go b/pkg/seqapi/v1/seq_api_grpc.pb.go index 452d051..83a451d 100644 --- a/pkg/seqapi/v1/seq_api_grpc.pb.go +++ b/pkg/seqapi/v1/seq_api_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 -// - protoc v6.33.4 +// - protoc v7.34.1 // source: seqapi/v1/seq_api.proto package seqapi diff --git a/pkg/userprofile/v1/userprofile.pb.go b/pkg/userprofile/v1/userprofile.pb.go index d415d67..aa5b672 100644 --- a/pkg/userprofile/v1/userprofile.pb.go +++ b/pkg/userprofile/v1/userprofile.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc v6.33.4 +// protoc v7.34.1 // source: userprofile/v1/userprofile.proto package userprofile @@ -113,6 +113,7 @@ type GetUserProfileResponse struct { Timezone string `protobuf:"bytes,1,opt,name=timezone,proto3" json:"timezone,omitempty"` OnboardingVersion string `protobuf:"bytes,2,opt,name=onboarding_version,json=onboardingVersion,proto3" json:"onboarding_version,omitempty"` LogColumns *LogColumns `protobuf:"bytes,3,opt,name=log_columns,json=logColumns,proto3" json:"log_columns,omitempty"` + RoleId *int32 `protobuf:"varint,4,opt,name=role_id,json=roleId,proto3,oneof" json:"role_id,omitempty"` } func (x *GetUserProfileResponse) Reset() { @@ -168,6 +169,13 @@ func (x *GetUserProfileResponse) GetLogColumns() *LogColumns { return nil } +func (x *GetUserProfileResponse) GetRoleId() int32 { + if x != nil && x.RoleId != nil { + return *x.RoleId + } + return 0 +} + type UpdateUserProfileRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1168,7 +1176,7 @@ var file_userprofile_v1_userprofile_proto_rawDesc = []byte{ 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x6f, 0x67, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x6f, 0x67, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xa0, 0x01, 0x0a, 0x16, 0x47, + 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xca, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, @@ -1178,138 +1186,141 @@ var file_userprofile_v1_userprofile_proto_rawDesc = []byte{ 0x12, 0x3b, 0x0a, 0x0b, 0x6c, 0x6f, 0x67, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, - 0x73, 0x52, 0x0a, 0x6c, 0x6f, 0x67, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x22, 0xe5, 0x01, - 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x08, 0x74, 0x69, - 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, - 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x88, 0x01, 0x01, 0x12, 0x32, 0x0a, 0x12, 0x6f, - 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x11, 0x6f, 0x6e, 0x62, 0x6f, 0x61, - 0x72, 0x64, 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, - 0x40, 0x0a, 0x0b, 0x6c, 0x6f, 0x67, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, - 0x48, 0x02, 0x52, 0x0a, 0x6c, 0x6f, 0x67, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x88, 0x01, - 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x42, 0x15, - 0x0a, 0x13, 0x5f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x63, 0x6f, - 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x22, 0x1b, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, - 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x1b, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, - 0x65, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0xf6, 0x01, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, - 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, - 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x30, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, - 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x1a, 0x8b, 0x01, 0x0a, 0x05, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x88, 0x01, 0x01, 0x12, 0x28, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, - 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x48, 0x01, 0x52, 0x0c, 0x72, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, - 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, - 0x69, 0x76, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x22, 0x90, 0x01, 0x0a, 0x1a, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x17, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x28, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, - 0x76, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x48, 0x01, 0x52, - 0x0c, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x88, 0x01, 0x01, - 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x72, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x22, 0x2d, 0x0a, 0x1b, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x22, 0x2c, 0x0a, 0x1a, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1d, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x44, 0x61, - 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0x9d, 0x01, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x0a, 0x64, 0x61, 0x73, - 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, - 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, - 0x65, 0x74, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x0a, - 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x73, 0x1a, 0x33, 0x0a, 0x09, 0x44, 0x61, - 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, - 0x29, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0x5d, 0x0a, 0x14, 0x47, 0x65, - 0x74, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x77, - 0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x40, 0x0a, 0x16, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x2d, 0x0a, 0x17, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0x70, 0x0a, 0x16, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, - 0x01, 0x12, 0x17, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, - 0x01, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x19, 0x0a, 0x17, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0x19, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, + 0x73, 0x52, 0x0a, 0x6c, 0x6f, 0x67, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x1c, 0x0a, + 0x07, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, + 0x52, 0x06, 0x72, 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, + 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x22, 0xe5, 0x01, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, + 0x6e, 0x65, 0x88, 0x01, 0x01, 0x12, 0x32, 0x0a, 0x12, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, + 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x01, 0x52, 0x11, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x40, 0x0a, 0x0b, 0x6c, 0x6f, 0x67, + 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x48, 0x02, 0x52, 0x0a, 0x6c, 0x6f, + 0x67, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x6f, 0x6e, 0x62, + 0x6f, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, + 0x0e, 0x0a, 0x0c, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x22, + 0x1b, 0x0a, 0x19, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x0a, 0x19, + 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x69, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xf6, 0x01, 0x0a, 0x1a, 0x47, 0x65, + 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, + 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x61, + 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x07, 0x71, 0x75, 0x65, + 0x72, 0x69, 0x65, 0x73, 0x1a, 0x8b, 0x01, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, + 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x28, 0x0a, + 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x04, 0x48, 0x01, 0x52, 0x0c, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x46, 0x72, 0x6f, 0x6d, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x66, 0x72, + 0x6f, 0x6d, 0x22, 0x90, 0x01, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, + 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, + 0x12, 0x28, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x66, 0x72, 0x6f, + 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x48, 0x01, 0x52, 0x0c, 0x72, 0x65, 0x6c, 0x61, 0x74, + 0x69, 0x76, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x22, 0x2d, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, + 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x02, 0x69, 0x64, 0x22, 0x2c, 0x0a, 0x1a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x61, + 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, + 0x69, 0x64, 0x22, 0x1d, 0x0a, 0x1b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, + 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x16, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x9d, 0x01, 0x0a, 0x15, 0x47, 0x65, + 0x74, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x0a, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, + 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x61, 0x73, 0x68, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, + 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x0a, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x73, 0x1a, 0x33, 0x0a, 0x09, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x29, 0x0a, 0x13, 0x47, 0x65, 0x74, + 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x75, 0x75, 0x69, 0x64, 0x22, 0x5d, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x44, 0x61, 0x73, 0x68, 0x62, + 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6d, 0x65, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x4e, + 0x61, 0x6d, 0x65, 0x22, 0x40, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x61, 0x73, + 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x2d, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x32, 0xb6, 0x04, 0x0a, 0x12, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x61, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x73, - 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x25, 0x2e, 0x75, 0x73, 0x65, 0x72, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, - 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x26, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6a, 0x0a, 0x11, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, - 0x28, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, - 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x75, 0x73, 0x65, 0x72, + 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x75, 0x75, 0x69, 0x64, 0x22, 0x70, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x61, + 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, + 0x69, 0x64, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x6d, + 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x04, 0x6d, 0x65, 0x74, + 0x61, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x07, 0x0a, + 0x05, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x19, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x2c, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x61, 0x73, 0x68, 0x62, + 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, + 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, + 0x19, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xb6, 0x04, 0x0a, 0x12, 0x55, + 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x61, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x12, 0x25, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x6a, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x28, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6d, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, - 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x29, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, - 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, - 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, - 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x70, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, - 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x2a, 0x2e, 0x75, - 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x70, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x2a, - 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x75, 0x73, 0x65, - 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x7a, 0x6f, 0x6e, 0x74, 0x65, 0x63, 0x68, - 0x2f, 0x73, 0x65, 0x71, 0x2d, 0x75, 0x69, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x75, 0x73, 0x65, 0x72, - 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x70, - 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, + 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x6d, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, + 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x29, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, + 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2a, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, + 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x70, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, + 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x2a, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, + 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, + 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x70, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, 0x72, + 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x2a, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, + 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, + 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x61, 0x76, 0x6f, + 0x72, 0x69, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x6f, 0x7a, 0x6f, 0x6e, 0x74, 0x65, 0x63, 0x68, 0x2f, 0x73, 0x65, 0x71, 0x2d, 0x75, + 0x69, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, + 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1655,6 +1666,7 @@ func file_userprofile_v1_userprofile_proto_init() { } } } + file_userprofile_v1_userprofile_proto_msgTypes[2].OneofWrappers = []any{} file_userprofile_v1_userprofile_proto_msgTypes[3].OneofWrappers = []any{} file_userprofile_v1_userprofile_proto_msgTypes[7].OneofWrappers = []any{} file_userprofile_v1_userprofile_proto_msgTypes[17].OneofWrappers = []any{} diff --git a/pkg/userprofile/v1/userprofile_grpc.pb.go b/pkg/userprofile/v1/userprofile_grpc.pb.go index 2641965..a2c1330 100644 --- a/pkg/userprofile/v1/userprofile_grpc.pb.go +++ b/pkg/userprofile/v1/userprofile_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.4.0 -// - protoc v6.33.4 +// - protoc v7.34.1 // source: userprofile/v1/userprofile.proto package userprofile