mirror of
https://github.com/zitadel/zitadel.git
synced 2025-03-01 00:17:24 +00:00
feat: iam members in admin api (#272)
* feat: iam members in admin api * feat: add error id in translate error * fix: resolve merge conflicts
This commit is contained in:
parent
8bfa1a083c
commit
62b654ea18
@ -4,6 +4,12 @@ InternalAuthZ:
|
|||||||
Permissions:
|
Permissions:
|
||||||
- "iam.read"
|
- "iam.read"
|
||||||
- "iam.write"
|
- "iam.write"
|
||||||
|
- "iam.policy.read"
|
||||||
|
- "iam.policy.write"
|
||||||
|
- "iam.policy.delete"
|
||||||
|
- "iam.member.read"
|
||||||
|
- "iam.member.write"
|
||||||
|
- "iam.member.delete"
|
||||||
- "org.read"
|
- "org.read"
|
||||||
- "org.write"
|
- "org.write"
|
||||||
- "org.member.read"
|
- "org.member.read"
|
||||||
@ -36,9 +42,6 @@ InternalAuthZ:
|
|||||||
- "project.grant.member.read"
|
- "project.grant.member.read"
|
||||||
- "project.grant.member.write"
|
- "project.grant.member.write"
|
||||||
- "project.grant.member.delete"
|
- "project.grant.member.delete"
|
||||||
- "iam.policy.read"
|
|
||||||
- "iam.policy.write"
|
|
||||||
- "iam.policy.delete"
|
|
||||||
- Role: 'ORG_OWNER'
|
- Role: 'ORG_OWNER'
|
||||||
Permissions:
|
Permissions:
|
||||||
- "org.read"
|
- "org.read"
|
||||||
|
67
internal/admin/repository/eventsourcing/eventstore/iam.go
Normal file
67
internal/admin/repository/eventsourcing/eventstore/iam.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package eventstore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
||||||
|
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||||
|
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||||
|
iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IamRepository struct {
|
||||||
|
SearchLimit uint64
|
||||||
|
*iam_es.IamEventstore
|
||||||
|
View *admin_view.View
|
||||||
|
SystemDefaults systemdefaults.SystemDefaults
|
||||||
|
Roles []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *IamRepository) IamMemberByID(ctx context.Context, orgID, userID string) (*iam_model.IamMemberView, error) {
|
||||||
|
member, err := repo.View.IamMemberByIDs(orgID, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return iam_es_model.IamMemberToModel(member), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *IamRepository) AddIamMember(ctx context.Context, member *iam_model.IamMember) (*iam_model.IamMember, error) {
|
||||||
|
member.AggregateID = repo.SystemDefaults.IamID
|
||||||
|
return repo.IamEventstore.AddIamMember(ctx, member)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *IamRepository) ChangeIamMember(ctx context.Context, member *iam_model.IamMember) (*iam_model.IamMember, error) {
|
||||||
|
member.AggregateID = repo.SystemDefaults.IamID
|
||||||
|
return repo.IamEventstore.ChangeIamMember(ctx, member)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *IamRepository) RemoveIamMember(ctx context.Context, userID string) error {
|
||||||
|
member := iam_model.NewIamMember(repo.SystemDefaults.IamID, userID)
|
||||||
|
return repo.IamEventstore.RemoveIamMember(ctx, member)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *IamRepository) SearchIamMembers(ctx context.Context, request *iam_model.IamMemberSearchRequest) (*iam_model.IamMemberSearchResponse, error) {
|
||||||
|
request.EnsureLimit(repo.SearchLimit)
|
||||||
|
members, count, err := repo.View.SearchIamMembers(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &iam_model.IamMemberSearchResponse{
|
||||||
|
Offset: request.Offset,
|
||||||
|
Limit: request.Limit,
|
||||||
|
TotalResult: uint64(count),
|
||||||
|
Result: iam_es_model.IamMembersToModel(members),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *IamRepository) GetIamMemberRoles() []string {
|
||||||
|
roles := make([]string, 0)
|
||||||
|
for _, roleMap := range repo.Roles {
|
||||||
|
if strings.HasPrefix(roleMap, "IAM") {
|
||||||
|
roles = append(roles, roleMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return roles
|
||||||
|
}
|
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
||||||
"github.com/caos/zitadel/internal/config/types"
|
"github.com/caos/zitadel/internal/config/types"
|
||||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||||
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
|
||||||
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,13 +23,13 @@ type handler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EventstoreRepos struct {
|
type EventstoreRepos struct {
|
||||||
ProjectEvents *proj_event.ProjectEventstore
|
UserEvents *usr_event.UserEventstore
|
||||||
UserEvents *usr_event.UserEventstore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View) []spooler.Handler {
|
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, repos EventstoreRepos) []spooler.Handler {
|
||||||
return []spooler.Handler{
|
return []spooler.Handler{
|
||||||
&Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}},
|
&Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}},
|
||||||
|
&IamMember{handler: handler{view, bulkLimit, configs.cycleDuration("IamMember"), errorCount}, userEvents: repos.UserEvents},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
127
internal/admin/repository/eventsourcing/handler/iam_member.go
Normal file
127
internal/admin/repository/eventsourcing/handler/iam_member.go
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||||
|
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/logging"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||||
|
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||||
|
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||||
|
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IamMember struct {
|
||||||
|
handler
|
||||||
|
userEvents *usr_event.UserEventstore
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
iamMemberTable = "admin_api.iam_members"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *IamMember) MinimumCycleDuration() time.Duration { return m.cycleDuration }
|
||||||
|
|
||||||
|
func (m *IamMember) ViewModel() string {
|
||||||
|
return iamMemberTable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *IamMember) EventQuery() (*models.SearchQuery, error) {
|
||||||
|
sequence, err := m.view.GetLatestIamMemberSequence()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return es_models.NewSearchQuery().
|
||||||
|
AggregateTypeFilter(model.IamAggregate, usr_es_model.UserAggregate).
|
||||||
|
LatestSequenceFilter(sequence), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *IamMember) Reduce(event *models.Event) (err error) {
|
||||||
|
switch event.AggregateType {
|
||||||
|
case model.IamAggregate:
|
||||||
|
err = m.processIamMember(event)
|
||||||
|
case usr_es_model.UserAggregate:
|
||||||
|
err = m.processUser(event)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *IamMember) processIamMember(event *models.Event) (err error) {
|
||||||
|
member := new(iam_model.IamMemberView)
|
||||||
|
switch event.Type {
|
||||||
|
case model.IamMemberAdded:
|
||||||
|
member.AppendEvent(event)
|
||||||
|
m.fillData(member)
|
||||||
|
case model.IamMemberChanged:
|
||||||
|
err := member.SetData(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
member, err = m.view.IamMemberByIDs(event.AggregateID, member.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
member.AppendEvent(event)
|
||||||
|
case model.IamMemberRemoved:
|
||||||
|
err := member.SetData(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return m.view.DeleteIamMember(event.AggregateID, member.UserID, event.Sequence)
|
||||||
|
default:
|
||||||
|
return m.view.ProcessedIamMemberSequence(event.Sequence)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return m.view.PutIamMember(member, member.Sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *IamMember) processUser(event *models.Event) (err error) {
|
||||||
|
switch event.Type {
|
||||||
|
case usr_es_model.UserProfileChanged,
|
||||||
|
usr_es_model.UserEmailChanged:
|
||||||
|
members, err := m.view.IamMembersByUserID(event.AggregateID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user, err := m.userEvents.UserByID(context.Background(), event.AggregateID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, member := range members {
|
||||||
|
m.fillUserData(member, user)
|
||||||
|
err = m.view.PutIamMember(member, event.Sequence)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return m.view.ProcessedIamMemberSequence(event.Sequence)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *IamMember) fillData(member *iam_model.IamMemberView) (err error) {
|
||||||
|
user, err := m.userEvents.UserByID(context.Background(), member.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.fillUserData(member, user)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *IamMember) fillUserData(member *iam_model.IamMemberView, user *usr_model.User) {
|
||||||
|
member.UserName = user.UserName
|
||||||
|
member.FirstName = user.FirstName
|
||||||
|
member.LastName = user.LastName
|
||||||
|
member.Email = user.EmailAddress
|
||||||
|
}
|
||||||
|
func (m *IamMember) OnError(event *models.Event, err error) error {
|
||||||
|
logging.LogWithFields("SPOOL-Ld9ow", "id", event.AggregateID).WithError(err).Warn("something went wrong in iammember handler")
|
||||||
|
return spooler.HandleError(event, err, m.view.GetLatestIamMemberFailedEvent, m.view.ProcessedIamMemberFailedEvent, m.view.ProcessedIamMemberSequence, m.errorCountUntilSkip)
|
||||||
|
}
|
@ -2,6 +2,7 @@ package eventsourcing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/handler"
|
||||||
es_policy "github.com/caos/zitadel/internal/policy/repository/eventsourcing"
|
es_policy "github.com/caos/zitadel/internal/policy/repository/eventsourcing"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
@ -30,10 +31,11 @@ type Config struct {
|
|||||||
type EsRepository struct {
|
type EsRepository struct {
|
||||||
spooler *es_spol.Spooler
|
spooler *es_spol.Spooler
|
||||||
eventstore.OrgRepo
|
eventstore.OrgRepo
|
||||||
|
eventstore.IamRepository
|
||||||
eventstore.AdministratorRepo
|
eventstore.AdministratorRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) {
|
func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, roles []string) (*EsRepository, error) {
|
||||||
es, err := es_int.Start(conf.Eventstore)
|
es, err := es_int.Start(conf.Eventstore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -84,7 +86,7 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults) (
|
|||||||
err = setup.StartSetup(systemDefaults, eventstoreRepos).Execute(ctx)
|
err = setup.StartSetup(systemDefaults, eventstoreRepos).Execute(ctx)
|
||||||
logging.Log("SERVE-djs3R").OnError(err).Panic("failed to execute setup")
|
logging.Log("SERVE-djs3R").OnError(err).Panic("failed to execute setup")
|
||||||
|
|
||||||
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient)
|
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, handler.EventstoreRepos{UserEvents: user})
|
||||||
|
|
||||||
return &EsRepository{
|
return &EsRepository{
|
||||||
spooler: spool,
|
spooler: spool,
|
||||||
@ -96,6 +98,13 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults) (
|
|||||||
View: view,
|
View: view,
|
||||||
SearchLimit: conf.SearchLimit,
|
SearchLimit: conf.SearchLimit,
|
||||||
},
|
},
|
||||||
|
IamRepository: eventstore.IamRepository{
|
||||||
|
IamEventstore: iam,
|
||||||
|
View: view,
|
||||||
|
SystemDefaults: systemDefaults,
|
||||||
|
SearchLimit: conf.SearchLimit,
|
||||||
|
Roles: roles,
|
||||||
|
},
|
||||||
AdministratorRepo: eventstore.AdministratorRepo{
|
AdministratorRepo: eventstore.AdministratorRepo{
|
||||||
View: view,
|
View: view,
|
||||||
},
|
},
|
||||||
|
@ -16,12 +16,12 @@ type SpoolerConfig struct {
|
|||||||
Handlers handler.Configs
|
Handlers handler.Configs
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB) *spooler.Spooler {
|
func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, repos handler.EventstoreRepos) *spooler.Spooler {
|
||||||
spoolerConfig := spooler.Config{
|
spoolerConfig := spooler.Config{
|
||||||
Eventstore: es,
|
Eventstore: es,
|
||||||
Locker: &locker{dbClient: sql},
|
Locker: &locker{dbClient: sql},
|
||||||
ConcurrentTasks: c.ConcurrentTasks,
|
ConcurrentTasks: c.ConcurrentTasks,
|
||||||
ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view),
|
ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, repos),
|
||||||
}
|
}
|
||||||
spool := spoolerConfig.New()
|
spool := spoolerConfig.New()
|
||||||
spool.Start()
|
spool.Start()
|
||||||
|
56
internal/admin/repository/eventsourcing/view/iam_member.go
Normal file
56
internal/admin/repository/eventsourcing/view/iam_member.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||||
|
"github.com/caos/zitadel/internal/iam/repository/view"
|
||||||
|
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||||
|
global_view "github.com/caos/zitadel/internal/view/repository"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
iamMemberTable = "admin_api.iam_members"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v *View) IamMemberByIDs(orgID, userID string) (*model.IamMemberView, error) {
|
||||||
|
return view.IamMemberByIDs(v.Db, iamMemberTable, orgID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) SearchIamMembers(request *iam_model.IamMemberSearchRequest) ([]*model.IamMemberView, int, error) {
|
||||||
|
return view.SearchIamMembers(v.Db, iamMemberTable, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) IamMembersByUserID(userID string) ([]*model.IamMemberView, error) {
|
||||||
|
return view.IamMembersByUserID(v.Db, iamMemberTable, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) PutIamMember(org *model.IamMemberView, sequence uint64) error {
|
||||||
|
err := view.PutIamMember(v.Db, iamMemberTable, org)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return v.ProcessedIamMemberSequence(sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) DeleteIamMember(orgID, userID string, eventSequence uint64) error {
|
||||||
|
err := view.DeleteIamMember(v.Db, iamMemberTable, orgID, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.ProcessedIamMemberSequence(eventSequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestIamMemberSequence() (uint64, error) {
|
||||||
|
return v.latestSequence(iamMemberTable)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ProcessedIamMemberSequence(eventSequence uint64) error {
|
||||||
|
return v.saveCurrentSequence(iamMemberTable, eventSequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestIamMemberFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
|
||||||
|
return v.latestFailedEvent(iamMemberTable, sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ProcessedIamMemberFailedEvent(failedEvent *global_view.FailedEvent) error {
|
||||||
|
return v.saveFailedEvent(failedEvent)
|
||||||
|
}
|
15
internal/admin/repository/iam.go
Normal file
15
internal/admin/repository/iam.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IamRepository interface {
|
||||||
|
SearchIamMembers(ctx context.Context, request *iam_model.IamMemberSearchRequest) (*iam_model.IamMemberSearchResponse, error)
|
||||||
|
AddIamMember(ctx context.Context, member *iam_model.IamMember) (*iam_model.IamMember, error)
|
||||||
|
ChangeIamMember(ctx context.Context, member *iam_model.IamMember) (*iam_model.IamMember, error)
|
||||||
|
RemoveIamMember(ctx context.Context, userID string) error
|
||||||
|
|
||||||
|
GetIamMemberRoles() []string
|
||||||
|
}
|
@ -5,5 +5,6 @@ import "context"
|
|||||||
type Repository interface {
|
type Repository interface {
|
||||||
Health(ctx context.Context) error
|
Health(ctx context.Context) error
|
||||||
OrgRepository
|
OrgRepository
|
||||||
|
IamRepository
|
||||||
AdministratorRepository
|
AdministratorRepository
|
||||||
}
|
}
|
||||||
|
@ -12,40 +12,41 @@ func CaosToGRPCError(err error, ctx context.Context, translator *i18n.Translator
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
code, msg, ok := Extract(err)
|
code, msg, id, ok := Extract(err)
|
||||||
if !ok {
|
if !ok {
|
||||||
return status.Convert(err).Err()
|
return status.Convert(err).Err()
|
||||||
}
|
}
|
||||||
if translator != nil {
|
if translator != nil {
|
||||||
msg = translator.LocalizeFromCtx(ctx, msg, nil)
|
msg = translator.LocalizeFromCtx(ctx, msg, nil)
|
||||||
|
msg = msg + "(" + id + ")"
|
||||||
}
|
}
|
||||||
return status.Error(code, msg)
|
return status.Error(code, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Extract(err error) (c codes.Code, msg string, ok bool) {
|
func Extract(err error) (c codes.Code, msg, id string, ok bool) {
|
||||||
switch caosErr := err.(type) {
|
switch caosErr := err.(type) {
|
||||||
case *caos_errs.AlreadyExistsError:
|
case *caos_errs.AlreadyExistsError:
|
||||||
return codes.AlreadyExists, caosErr.GetMessage(), true
|
|
||||||
|
return codes.AlreadyExists, caosErr.GetMessage(), caosErr.GetID(), true
|
||||||
case *caos_errs.DeadlineExceededError:
|
case *caos_errs.DeadlineExceededError:
|
||||||
return codes.DeadlineExceeded, caosErr.GetMessage(), true
|
return codes.DeadlineExceeded, caosErr.GetMessage(), caosErr.GetID(), true
|
||||||
case caos_errs.InternalError:
|
case caos_errs.InternalError:
|
||||||
return codes.Internal, caosErr.GetMessage(), true
|
return codes.Internal, caosErr.GetMessage(), caosErr.GetID(), true
|
||||||
case *caos_errs.InvalidArgumentError:
|
case *caos_errs.InvalidArgumentError:
|
||||||
return codes.InvalidArgument, caosErr.GetMessage(), true
|
return codes.InvalidArgument, caosErr.GetMessage(), caosErr.GetID(), true
|
||||||
case *caos_errs.NotFoundError:
|
case *caos_errs.NotFoundError:
|
||||||
return codes.NotFound, caosErr.GetMessage(), true
|
return codes.NotFound, caosErr.GetMessage(), caosErr.GetID(), true
|
||||||
case *caos_errs.PermissionDeniedError:
|
case *caos_errs.PermissionDeniedError:
|
||||||
return codes.PermissionDenied, caosErr.GetMessage(), true
|
return codes.PermissionDenied, caosErr.GetMessage(), caosErr.GetID(), true
|
||||||
case *caos_errs.PreconditionFailedError:
|
case *caos_errs.PreconditionFailedError:
|
||||||
return codes.FailedPrecondition, caosErr.GetMessage(), true
|
return codes.FailedPrecondition, caosErr.GetMessage(), caosErr.GetID(), true
|
||||||
case *caos_errs.UnauthenticatedError:
|
case *caos_errs.UnauthenticatedError:
|
||||||
return codes.Unauthenticated, caosErr.GetMessage(), true
|
return codes.Unauthenticated, caosErr.GetMessage(), caosErr.GetID(), true
|
||||||
case *caos_errs.UnavailableError:
|
case *caos_errs.UnavailableError:
|
||||||
return codes.Unavailable, caosErr.GetMessage(), true
|
return codes.Unavailable, caosErr.GetMessage(), caosErr.GetID(), true
|
||||||
case *caos_errs.UnimplementedError:
|
case *caos_errs.UnimplementedError:
|
||||||
return codes.Unimplemented, caosErr.GetMessage(), true
|
return codes.Unimplemented, caosErr.GetMessage(), caosErr.GetID(), true
|
||||||
default:
|
default:
|
||||||
return codes.Unknown, err.Error(), false
|
return codes.Unknown, err.Error(), "", false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ type IamMember struct {
|
|||||||
Roles []string
|
Roles []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIamMember(projectID, userID string) *IamMember {
|
func NewIamMember(iamID, userID string) *IamMember {
|
||||||
return &IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: projectID}, UserID: userID}
|
return &IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: iamID}, UserID: userID}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *IamMember) IsValid() bool {
|
func (i *IamMember) IsValid() bool {
|
||||||
|
58
internal/iam/model/iam_member_view.go
Normal file
58
internal/iam/model/iam_member_view.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caos/zitadel/internal/model"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IamMemberView struct {
|
||||||
|
UserID string
|
||||||
|
IamID string
|
||||||
|
UserName string
|
||||||
|
Email string
|
||||||
|
FirstName string
|
||||||
|
LastName string
|
||||||
|
Roles []string
|
||||||
|
CreationDate time.Time
|
||||||
|
ChangeDate time.Time
|
||||||
|
Sequence uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type IamMemberSearchRequest struct {
|
||||||
|
Offset uint64
|
||||||
|
Limit uint64
|
||||||
|
SortingColumn IamMemberSearchKey
|
||||||
|
Asc bool
|
||||||
|
Queries []*IamMemberSearchQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
type IamMemberSearchKey int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
IamMemberSearchKeyUnspecified IamMemberSearchKey = iota
|
||||||
|
IamMemberSearchKeyUserName
|
||||||
|
IamMemberSearchKeyEmail
|
||||||
|
IamMemberSearchKeyFirstName
|
||||||
|
IamMemberSearchKeyLastName
|
||||||
|
IamMemberSearchKeyIamID
|
||||||
|
IamMemberSearchKeyUserID
|
||||||
|
)
|
||||||
|
|
||||||
|
type IamMemberSearchQuery struct {
|
||||||
|
Key IamMemberSearchKey
|
||||||
|
Method model.SearchMethod
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type IamMemberSearchResponse struct {
|
||||||
|
Offset uint64
|
||||||
|
Limit uint64
|
||||||
|
TotalResult uint64
|
||||||
|
Result []*IamMemberView
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *IamMemberSearchRequest) EnsureLimit(limit uint64) {
|
||||||
|
if r.Limit == 0 || r.Limit > limit {
|
||||||
|
r.Limit = limit
|
||||||
|
}
|
||||||
|
}
|
59
internal/iam/repository/view/iam_member_view.go
Normal file
59
internal/iam/repository/view/iam_member_view.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||||
|
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||||
|
global_model "github.com/caos/zitadel/internal/model"
|
||||||
|
"github.com/caos/zitadel/internal/view/repository"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IamMemberByIDs(db *gorm.DB, table, orgID, userID string) (*model.IamMemberView, error) {
|
||||||
|
member := new(model.IamMemberView)
|
||||||
|
|
||||||
|
orgIDQuery := &model.IamMemberSearchQuery{Key: iam_model.IamMemberSearchKeyIamID, Value: orgID, Method: global_model.SearchMethodEquals}
|
||||||
|
userIDQuery := &model.IamMemberSearchQuery{Key: iam_model.IamMemberSearchKeyUserID, Value: userID, Method: global_model.SearchMethodEquals}
|
||||||
|
query := repository.PrepareGetByQuery(table, orgIDQuery, userIDQuery)
|
||||||
|
err := query(db, member)
|
||||||
|
return member, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SearchIamMembers(db *gorm.DB, table string, req *iam_model.IamMemberSearchRequest) ([]*model.IamMemberView, int, error) {
|
||||||
|
members := make([]*model.IamMemberView, 0)
|
||||||
|
query := repository.PrepareSearchQuery(table, model.IamMemberSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
||||||
|
count, err := query(db, &members)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return members, count, nil
|
||||||
|
}
|
||||||
|
func IamMembersByUserID(db *gorm.DB, table string, userID string) ([]*model.IamMemberView, error) {
|
||||||
|
members := make([]*model.IamMemberView, 0)
|
||||||
|
queries := []*iam_model.IamMemberSearchQuery{
|
||||||
|
{
|
||||||
|
Key: iam_model.IamMemberSearchKeyUserID,
|
||||||
|
Value: userID,
|
||||||
|
Method: global_model.SearchMethodEquals,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
query := repository.PrepareSearchQuery(table, model.IamMemberSearchRequest{Queries: queries})
|
||||||
|
_, err := query(db, &members)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return members, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutIamMember(db *gorm.DB, table string, role *model.IamMemberView) error {
|
||||||
|
save := repository.PrepareSave(table)
|
||||||
|
return save(db, role)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteIamMember(db *gorm.DB, table, orgID, userID string) error {
|
||||||
|
member, err := IamMemberByIDs(db, table, orgID, userID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
delete := repository.PrepareDeleteByObject(table, member)
|
||||||
|
return delete(db)
|
||||||
|
}
|
100
internal/iam/repository/view/model/iam_member.go
Normal file
100
internal/iam/repository/view/model/iam_member.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/logging"
|
||||||
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
"github.com/caos/zitadel/internal/iam/model"
|
||||||
|
"github.com/lib/pq"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
IamMemberKeyUserID = "user_id"
|
||||||
|
IamMemberKeyIamID = "org_id"
|
||||||
|
IamMemberKeyUserName = "user_name"
|
||||||
|
IamMemberKeyEmail = "email"
|
||||||
|
IamMemberKeyFirstName = "first_name"
|
||||||
|
IamMemberKeyLastName = "last_name"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IamMemberView struct {
|
||||||
|
UserID string `json:"userId" gorm:"column:user_id;primary_key"`
|
||||||
|
IamID string `json:"-" gorm:"column:iam_id"`
|
||||||
|
UserName string `json:"-" gorm:"column:user_name"`
|
||||||
|
Email string `json:"-" gorm:"column:email_address"`
|
||||||
|
FirstName string `json:"-" gorm:"column:first_name"`
|
||||||
|
LastName string `json:"-" gorm:"column:last_name"`
|
||||||
|
Roles pq.StringArray `json:"roles" gorm:"column:roles"`
|
||||||
|
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||||
|
|
||||||
|
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||||
|
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func IamMemberViewFromModel(member *model.IamMemberView) *IamMemberView {
|
||||||
|
return &IamMemberView{
|
||||||
|
UserID: member.UserID,
|
||||||
|
IamID: member.IamID,
|
||||||
|
UserName: member.UserName,
|
||||||
|
Email: member.Email,
|
||||||
|
FirstName: member.FirstName,
|
||||||
|
LastName: member.LastName,
|
||||||
|
Roles: member.Roles,
|
||||||
|
Sequence: member.Sequence,
|
||||||
|
CreationDate: member.CreationDate,
|
||||||
|
ChangeDate: member.ChangeDate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IamMemberToModel(member *IamMemberView) *model.IamMemberView {
|
||||||
|
return &model.IamMemberView{
|
||||||
|
UserID: member.UserID,
|
||||||
|
IamID: member.IamID,
|
||||||
|
UserName: member.UserName,
|
||||||
|
Email: member.Email,
|
||||||
|
FirstName: member.FirstName,
|
||||||
|
LastName: member.LastName,
|
||||||
|
Roles: member.Roles,
|
||||||
|
Sequence: member.Sequence,
|
||||||
|
CreationDate: member.CreationDate,
|
||||||
|
ChangeDate: member.ChangeDate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IamMembersToModel(roles []*IamMemberView) []*model.IamMemberView {
|
||||||
|
result := make([]*model.IamMemberView, len(roles))
|
||||||
|
for i, r := range roles {
|
||||||
|
result[i] = IamMemberToModel(r)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *IamMemberView) AppendEvent(event *models.Event) (err error) {
|
||||||
|
r.Sequence = event.Sequence
|
||||||
|
r.ChangeDate = event.CreationDate
|
||||||
|
switch event.Type {
|
||||||
|
case es_model.IamMemberAdded:
|
||||||
|
r.setRootData(event)
|
||||||
|
r.CreationDate = event.CreationDate
|
||||||
|
err = r.SetData(event)
|
||||||
|
case es_model.IamMemberChanged:
|
||||||
|
err = r.SetData(event)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *IamMemberView) setRootData(event *models.Event) {
|
||||||
|
r.IamID = event.AggregateID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *IamMemberView) SetData(event *models.Event) error {
|
||||||
|
if err := json.Unmarshal(event.Data, r); err != nil {
|
||||||
|
logging.Log("EVEN-Psl89").WithError(err).Error("could not unmarshal event data")
|
||||||
|
return caos_errs.ThrowInternal(err, "MODEL-lub6s", "Could not unmarshal data")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
69
internal/iam/repository/view/model/iam_member_query.go
Normal file
69
internal/iam/repository/view/model/iam_member_query.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||||
|
global_model "github.com/caos/zitadel/internal/model"
|
||||||
|
"github.com/caos/zitadel/internal/view/repository"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IamMemberSearchRequest iam_model.IamMemberSearchRequest
|
||||||
|
type IamMemberSearchQuery iam_model.IamMemberSearchQuery
|
||||||
|
type IamMemberSearchKey iam_model.IamMemberSearchKey
|
||||||
|
|
||||||
|
func (req IamMemberSearchRequest) GetLimit() uint64 {
|
||||||
|
return req.Limit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req IamMemberSearchRequest) GetOffset() uint64 {
|
||||||
|
return req.Offset
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req IamMemberSearchRequest) GetSortingColumn() repository.ColumnKey {
|
||||||
|
if req.SortingColumn == iam_model.IamMemberSearchKeyUnspecified {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return IamMemberSearchKey(req.SortingColumn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req IamMemberSearchRequest) GetAsc() bool {
|
||||||
|
return req.Asc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req IamMemberSearchRequest) GetQueries() []repository.SearchQuery {
|
||||||
|
result := make([]repository.SearchQuery, len(req.Queries))
|
||||||
|
for i, q := range req.Queries {
|
||||||
|
result[i] = IamMemberSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req IamMemberSearchQuery) GetKey() repository.ColumnKey {
|
||||||
|
return IamMemberSearchKey(req.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req IamMemberSearchQuery) GetMethod() global_model.SearchMethod {
|
||||||
|
return req.Method
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req IamMemberSearchQuery) GetValue() interface{} {
|
||||||
|
return req.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (key IamMemberSearchKey) ToColumnName() string {
|
||||||
|
switch iam_model.IamMemberSearchKey(key) {
|
||||||
|
case iam_model.IamMemberSearchKeyEmail:
|
||||||
|
return IamMemberKeyEmail
|
||||||
|
case iam_model.IamMemberSearchKeyFirstName:
|
||||||
|
return IamMemberKeyFirstName
|
||||||
|
case iam_model.IamMemberSearchKeyLastName:
|
||||||
|
return IamMemberKeyLastName
|
||||||
|
case iam_model.IamMemberSearchKeyUserName:
|
||||||
|
return IamMemberKeyUserName
|
||||||
|
case iam_model.IamMemberSearchKeyUserID:
|
||||||
|
return IamMemberKeyUserID
|
||||||
|
case iam_model.IamMemberSearchKeyIamID:
|
||||||
|
return IamMemberKeyIamID
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
@ -2,13 +2,13 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
global_model "github.com/caos/zitadel/internal/model"
|
global_model "github.com/caos/zitadel/internal/model"
|
||||||
proj_model "github.com/caos/zitadel/internal/org/model"
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
"github.com/caos/zitadel/internal/view/repository"
|
"github.com/caos/zitadel/internal/view/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OrgMemberSearchRequest proj_model.OrgMemberSearchRequest
|
type OrgMemberSearchRequest org_model.OrgMemberSearchRequest
|
||||||
type OrgMemberSearchQuery proj_model.OrgMemberSearchQuery
|
type OrgMemberSearchQuery org_model.OrgMemberSearchQuery
|
||||||
type OrgMemberSearchKey proj_model.OrgMemberSearchKey
|
type OrgMemberSearchKey org_model.OrgMemberSearchKey
|
||||||
|
|
||||||
func (req OrgMemberSearchRequest) GetLimit() uint64 {
|
func (req OrgMemberSearchRequest) GetLimit() uint64 {
|
||||||
return req.Limit
|
return req.Limit
|
||||||
@ -19,7 +19,7 @@ func (req OrgMemberSearchRequest) GetOffset() uint64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (req OrgMemberSearchRequest) GetSortingColumn() repository.ColumnKey {
|
func (req OrgMemberSearchRequest) GetSortingColumn() repository.ColumnKey {
|
||||||
if req.SortingColumn == proj_model.OrgMemberSearchKeyUnspecified {
|
if req.SortingColumn == org_model.OrgMemberSearchKeyUnspecified {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return OrgMemberSearchKey(req.SortingColumn)
|
return OrgMemberSearchKey(req.SortingColumn)
|
||||||
@ -50,18 +50,18 @@ func (req OrgMemberSearchQuery) GetValue() interface{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (key OrgMemberSearchKey) ToColumnName() string {
|
func (key OrgMemberSearchKey) ToColumnName() string {
|
||||||
switch proj_model.OrgMemberSearchKey(key) {
|
switch org_model.OrgMemberSearchKey(key) {
|
||||||
case proj_model.OrgMemberSearchKeyEmail:
|
case org_model.OrgMemberSearchKeyEmail:
|
||||||
return OrgMemberKeyEmail
|
return OrgMemberKeyEmail
|
||||||
case proj_model.OrgMemberSearchKeyFirstName:
|
case org_model.OrgMemberSearchKeyFirstName:
|
||||||
return OrgMemberKeyFirstName
|
return OrgMemberKeyFirstName
|
||||||
case proj_model.OrgMemberSearchKeyLastName:
|
case org_model.OrgMemberSearchKeyLastName:
|
||||||
return OrgMemberKeyLastName
|
return OrgMemberKeyLastName
|
||||||
case proj_model.OrgMemberSearchKeyUserName:
|
case org_model.OrgMemberSearchKeyUserName:
|
||||||
return OrgMemberKeyUserName
|
return OrgMemberKeyUserName
|
||||||
case proj_model.OrgMemberSearchKeyUserID:
|
case org_model.OrgMemberSearchKeyUserID:
|
||||||
return OrgMemberKeyUserID
|
return OrgMemberKeyUserID
|
||||||
case proj_model.OrgMemberSearchKeyOrgID:
|
case org_model.OrgMemberSearchKeyOrgID:
|
||||||
return OrgMemberKeyOrgID
|
return OrgMemberKeyOrgID
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
|
@ -40,7 +40,7 @@ func (s *Span) SetStatusByError(err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func statusFromError(err error) trace.Status {
|
func statusFromError(err error) trace.Status {
|
||||||
code, msg, _ := grpc.Extract(err)
|
code, msg, _, _ := grpc.Extract(err)
|
||||||
return trace.Status{Code: int32(code), Message: msg}
|
return trace.Status{Code: int32(code), Message: msg}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
migrations/cockroach/V1.23__admin_iam_members.sql
Normal file
20
migrations/cockroach/V1.23__admin_iam_members.sql
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
CREATE TABLE admin_api.iam_members (
|
||||||
|
user_id TEXT,
|
||||||
|
|
||||||
|
iam_id TEXT,
|
||||||
|
creation_date TIMESTAMPTZ,
|
||||||
|
change_date TIMESTAMPTZ,
|
||||||
|
|
||||||
|
user_name TEXT,
|
||||||
|
email_address TEXT,
|
||||||
|
first_name TEXT,
|
||||||
|
last_name TEXT,
|
||||||
|
roles TEXT ARRAY,
|
||||||
|
sequence BIGINT,
|
||||||
|
|
||||||
|
PRIMARY KEY (user_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMIT;
|
@ -17,7 +17,12 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Start(ctx context.Context, config Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, systemDefaults sd.SystemDefaults) {
|
func Start(ctx context.Context, config Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, systemDefaults sd.SystemDefaults) {
|
||||||
repo, err := eventsourcing.Start(ctx, config.Repository, systemDefaults)
|
roles := make([]string, len(authZ.RolePermissionMappings))
|
||||||
|
for i, role := range authZ.RolePermissionMappings {
|
||||||
|
roles[i] = role.Role
|
||||||
|
}
|
||||||
|
|
||||||
|
repo, err := eventsourcing.Start(ctx, config.Repository, systemDefaults, roles)
|
||||||
logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app")
|
logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app")
|
||||||
|
|
||||||
api.Start(ctx, config.API, authZRepo, authZ, systemDefaults, repo)
|
api.Start(ctx, config.API, authZRepo, authZ, systemDefaults, repo)
|
||||||
|
@ -55,6 +55,31 @@ var AdminService_AuthMethods = utils_auth.MethodMapping{
|
|||||||
CheckParam: "",
|
CheckParam: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"/caos.zitadel.admin.api.v1.AdminService/GetIamMemberRoles": utils_auth.Option{
|
||||||
|
Permission: "iam.member.read",
|
||||||
|
CheckParam: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
"/caos.zitadel.admin.api.v1.AdminService/AddIamMember": utils_auth.Option{
|
||||||
|
Permission: "iam.member.write",
|
||||||
|
CheckParam: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
"/caos.zitadel.admin.api.v1.AdminService/ChangeIamMember": utils_auth.Option{
|
||||||
|
Permission: "iam.member.write",
|
||||||
|
CheckParam: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
"/caos.zitadel.admin.api.v1.AdminService/RemoveIamMember": utils_auth.Option{
|
||||||
|
Permission: "iam.member.delete",
|
||||||
|
CheckParam: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
"/caos.zitadel.admin.api.v1.AdminService/SearchIamMembers": utils_auth.Option{
|
||||||
|
Permission: "iam.member.read",
|
||||||
|
CheckParam: "",
|
||||||
|
},
|
||||||
|
|
||||||
"/caos.zitadel.admin.api.v1.AdminService/GetViews": utils_auth.Option{
|
"/caos.zitadel.admin.api.v1.AdminService/GetViews": utils_auth.Option{
|
||||||
Permission: "iam.read",
|
Permission: "iam.read",
|
||||||
CheckParam: "",
|
CheckParam: "",
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -258,6 +258,111 @@ func request_AdminService_DeleteOrgIamPolicy_0(ctx context.Context, marshaler ru
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func request_AdminService_GetIamMemberRoles_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq empty.Empty
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
msg, err := client.GetIamMemberRoles(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func request_AdminService_AddIamMember_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq AddIamMemberRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||||
|
if berr != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||||
|
}
|
||||||
|
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := client.AddIamMember(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func request_AdminService_ChangeIamMember_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq ChangeIamMemberRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||||
|
if berr != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||||
|
}
|
||||||
|
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
val string
|
||||||
|
ok bool
|
||||||
|
err error
|
||||||
|
_ = err
|
||||||
|
)
|
||||||
|
|
||||||
|
val, ok = pathParams["user_id"]
|
||||||
|
if !ok {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "user_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
protoReq.UserId, err = runtime.String(val)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "user_id", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := client.ChangeIamMember(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func request_AdminService_RemoveIamMember_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq RemoveIamMemberRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
var (
|
||||||
|
val string
|
||||||
|
ok bool
|
||||||
|
err error
|
||||||
|
_ = err
|
||||||
|
)
|
||||||
|
|
||||||
|
val, ok = pathParams["user_id"]
|
||||||
|
if !ok {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "user_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
protoReq.UserId, err = runtime.String(val)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "user_id", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := client.RemoveIamMember(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func request_AdminService_SearchIamMembers_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq IamMemberSearchRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||||
|
if berr != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||||
|
}
|
||||||
|
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := client.SearchIamMembers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func request_AdminService_GetViews_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
func request_AdminService_GetViews_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
var protoReq empty.Empty
|
var protoReq empty.Empty
|
||||||
var metadata runtime.ServerMetadata
|
var metadata runtime.ServerMetadata
|
||||||
@ -621,6 +726,106 @@ func RegisterAdminServiceHandlerClient(ctx context.Context, mux *runtime.ServeMu
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mux.Handle("GET", pattern_AdminService_GetIamMemberRoles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_AdminService_GetIamMemberRoles_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||||
|
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_AdminService_GetIamMemberRoles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
mux.Handle("POST", pattern_AdminService_AddIamMember_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_AdminService_AddIamMember_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||||
|
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_AdminService_AddIamMember_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
mux.Handle("PUT", pattern_AdminService_ChangeIamMember_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_AdminService_ChangeIamMember_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||||
|
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_AdminService_ChangeIamMember_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
mux.Handle("DELETE", pattern_AdminService_RemoveIamMember_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_AdminService_RemoveIamMember_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||||
|
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_AdminService_RemoveIamMember_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
mux.Handle("POST", pattern_AdminService_SearchIamMembers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_AdminService_SearchIamMembers_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||||
|
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_AdminService_SearchIamMembers_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_AdminService_GetViews_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_AdminService_GetViews_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -727,6 +932,16 @@ var (
|
|||||||
|
|
||||||
pattern_AdminService_DeleteOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, ""))
|
pattern_AdminService_DeleteOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, ""))
|
||||||
|
|
||||||
|
pattern_AdminService_GetIamMemberRoles_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"members", "roles"}, ""))
|
||||||
|
|
||||||
|
pattern_AdminService_AddIamMember_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"members"}, ""))
|
||||||
|
|
||||||
|
pattern_AdminService_ChangeIamMember_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"members", "user_id"}, ""))
|
||||||
|
|
||||||
|
pattern_AdminService_RemoveIamMember_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"members", "user_id"}, ""))
|
||||||
|
|
||||||
|
pattern_AdminService_SearchIamMembers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"members", "_search"}, ""))
|
||||||
|
|
||||||
pattern_AdminService_GetViews_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"views"}, ""))
|
pattern_AdminService_GetViews_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"views"}, ""))
|
||||||
|
|
||||||
pattern_AdminService_ClearView_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 1, 0, 4, 1, 5, 2}, []string{"views", "database", "view_name"}, ""))
|
pattern_AdminService_ClearView_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 1, 0, 4, 1, 5, 2}, []string{"views", "database", "view_name"}, ""))
|
||||||
@ -759,6 +974,16 @@ var (
|
|||||||
|
|
||||||
forward_AdminService_DeleteOrgIamPolicy_0 = runtime.ForwardResponseMessage
|
forward_AdminService_DeleteOrgIamPolicy_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_AdminService_GetIamMemberRoles_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_AdminService_AddIamMember_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_AdminService_ChangeIamMember_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_AdminService_RemoveIamMember_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_AdminService_SearchIamMembers_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_AdminService_GetViews_0 = runtime.ForwardResponseMessage
|
forward_AdminService_GetViews_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_AdminService_ClearView_0 = runtime.ForwardResponseMessage
|
forward_AdminService_ClearView_0 = runtime.ForwardResponseMessage
|
||||||
|
@ -89,6 +89,128 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/members": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "AddIamMember",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1IamMember"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1AddIamMemberRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"AdminService"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/members/_search": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "SearchIamMembers",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1IamMemberSearchResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1IamMemberSearchRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"AdminService"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/members/roles": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "GetIamMemberRoles",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1IamMemberRoles"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"AdminService"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/members/{user_id}": {
|
||||||
|
"delete": {
|
||||||
|
"operationId": "RemoveIamMember",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "user_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"AdminService"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"operationId": "ChangeIamMember",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1IamMember"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "user_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/v1ChangeIamMemberRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"AdminService"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/orgs/_isunique": {
|
"/orgs/_isunique": {
|
||||||
"get": {
|
"get": {
|
||||||
"summary": "ORG",
|
"summary": "ORG",
|
||||||
@ -450,6 +572,34 @@
|
|||||||
},
|
},
|
||||||
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
|
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
|
||||||
},
|
},
|
||||||
|
"v1AddIamMemberRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"user_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1ChangeIamMemberRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"user_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"v1CreateOrgRequest": {
|
"v1CreateOrgRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -559,6 +709,148 @@
|
|||||||
],
|
],
|
||||||
"default": "GENDER_UNSPECIFIED"
|
"default": "GENDER_UNSPECIFIED"
|
||||||
},
|
},
|
||||||
|
"v1IamMember": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"user_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"change_date": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
|
"creation_date": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
|
"sequence": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1IamMemberRoles": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"roles": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1IamMemberSearchKey": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"IAMMEMBERSEARCHKEY_UNSPECIFIED",
|
||||||
|
"IAMMEMBERSEARCHKEY_FIRST_NAME",
|
||||||
|
"IAMMEMBERSEARCHKEY_LAST_NAME",
|
||||||
|
"IAMMEMBERSEARCHKEY_EMAIL",
|
||||||
|
"IAMMEMBERSEARCHKEY_USER_ID"
|
||||||
|
],
|
||||||
|
"default": "IAMMEMBERSEARCHKEY_UNSPECIFIED"
|
||||||
|
},
|
||||||
|
"v1IamMemberSearchQuery": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"key": {
|
||||||
|
"$ref": "#/definitions/v1IamMemberSearchKey"
|
||||||
|
},
|
||||||
|
"method": {
|
||||||
|
"$ref": "#/definitions/v1SearchMethod"
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1IamMemberSearchRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"offset": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64"
|
||||||
|
},
|
||||||
|
"limit": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64"
|
||||||
|
},
|
||||||
|
"queries": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/v1IamMemberSearchQuery"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1IamMemberSearchResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"offset": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64"
|
||||||
|
},
|
||||||
|
"limit": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64"
|
||||||
|
},
|
||||||
|
"total_result": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64"
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/v1IamMemberView"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"v1IamMemberView": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"user_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"change_date": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
|
"creation_date": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
|
"sequence": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uint64"
|
||||||
|
},
|
||||||
|
"user_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"first_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"last_name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"v1Org": {
|
"v1Org": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -743,6 +1035,23 @@
|
|||||||
],
|
],
|
||||||
"default": "ORGSTATE_UNSPECIFIED"
|
"default": "ORGSTATE_UNSPECIFIED"
|
||||||
},
|
},
|
||||||
|
"v1SearchMethod": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"SEARCHMETHOD_EQUALS",
|
||||||
|
"SEARCHMETHOD_STARTS_WITH",
|
||||||
|
"SEARCHMETHOD_CONTAINS",
|
||||||
|
"SEARCHMETHOD_EQUALS_IGNORE_CASE",
|
||||||
|
"SEARCHMETHOD_STARTS_WITH_IGNORE_CASE",
|
||||||
|
"SEARCHMETHOD_CONTAINS_IGNORE_CASE",
|
||||||
|
"SEARCHMETHOD_NOT_EQUALS",
|
||||||
|
"SEARCHMETHOD_GREATER_THAN",
|
||||||
|
"SEARCHMETHOD_LESS_THAN",
|
||||||
|
"SEARCHMETHOD_IS_ONE_OF",
|
||||||
|
"SEARCHMETHOD_LIST_CONTAINS"
|
||||||
|
],
|
||||||
|
"default": "SEARCHMETHOD_EQUALS"
|
||||||
|
},
|
||||||
"v1UniqueOrgResponse": {
|
"v1UniqueOrgResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
41
pkg/admin/api/grpc/iam_member.go
Normal file
41
pkg/admin/api/grpc/iam_member.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package grpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/ptypes/empty"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) GetIamMemberRoles(ctx context.Context, _ *empty.Empty) (*IamMemberRoles, error) {
|
||||||
|
return &IamMemberRoles{Roles: s.iam.GetIamMemberRoles()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) SearchIamMembers(ctx context.Context, in *IamMemberSearchRequest) (*IamMemberSearchResponse, error) {
|
||||||
|
members, err := s.iam.SearchIamMembers(ctx, iamMemberSearchRequestToModel(in))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return iamMemberSearchResponseFromModel(members), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) AddIamMember(ctx context.Context, member *AddIamMemberRequest) (*IamMember, error) {
|
||||||
|
addedMember, err := s.iam.AddIamMember(ctx, addIamMemberToModel(member))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return iamMemberFromModel(addedMember), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ChangeIamMember(ctx context.Context, member *ChangeIamMemberRequest) (*IamMember, error) {
|
||||||
|
changedMember, err := s.iam.ChangeIamMember(ctx, changeIamMemberToModel(member))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return iamMemberFromModel(changedMember), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) RemoveIamMember(ctx context.Context, member *RemoveIamMemberRequest) (*empty.Empty, error) {
|
||||||
|
err := s.iam.RemoveIamMember(ctx, member.UserId)
|
||||||
|
return &empty.Empty{}, err
|
||||||
|
}
|
138
pkg/admin/api/grpc/iam_member_converter.go
Normal file
138
pkg/admin/api/grpc/iam_member_converter.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
package grpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caos/logging"
|
||||||
|
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||||
|
"github.com/caos/zitadel/internal/model"
|
||||||
|
"github.com/golang/protobuf/ptypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
func addIamMemberToModel(member *AddIamMemberRequest) *iam_model.IamMember {
|
||||||
|
memberModel := &iam_model.IamMember{
|
||||||
|
UserID: member.UserId,
|
||||||
|
}
|
||||||
|
memberModel.Roles = member.Roles
|
||||||
|
|
||||||
|
return memberModel
|
||||||
|
}
|
||||||
|
|
||||||
|
func changeIamMemberToModel(member *ChangeIamMemberRequest) *iam_model.IamMember {
|
||||||
|
memberModel := &iam_model.IamMember{
|
||||||
|
UserID: member.UserId,
|
||||||
|
}
|
||||||
|
memberModel.Roles = member.Roles
|
||||||
|
|
||||||
|
return memberModel
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamMemberFromModel(member *iam_model.IamMember) *IamMember {
|
||||||
|
creationDate, err := ptypes.TimestampProto(member.CreationDate)
|
||||||
|
logging.Log("GRPC-Lsp76").OnError(err).Debug("date parse failed")
|
||||||
|
|
||||||
|
changeDate, err := ptypes.TimestampProto(member.ChangeDate)
|
||||||
|
logging.Log("GRPC-3fG5s").OnError(err).Debug("date parse failed")
|
||||||
|
|
||||||
|
return &IamMember{
|
||||||
|
UserId: member.UserID,
|
||||||
|
CreationDate: creationDate,
|
||||||
|
ChangeDate: changeDate,
|
||||||
|
Roles: member.Roles,
|
||||||
|
Sequence: member.Sequence,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamMemberSearchRequestToModel(request *IamMemberSearchRequest) *iam_model.IamMemberSearchRequest {
|
||||||
|
return &iam_model.IamMemberSearchRequest{
|
||||||
|
Limit: request.Limit,
|
||||||
|
Offset: request.Offset,
|
||||||
|
Queries: iamMemberSearchQueriesToModel(request.Queries),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamMemberSearchQueriesToModel(queries []*IamMemberSearchQuery) []*iam_model.IamMemberSearchQuery {
|
||||||
|
modelQueries := make([]*iam_model.IamMemberSearchQuery, len(queries))
|
||||||
|
for i, query := range queries {
|
||||||
|
modelQueries[i] = iamMemberSearchQueryToModel(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
return modelQueries
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamMemberSearchQueryToModel(query *IamMemberSearchQuery) *iam_model.IamMemberSearchQuery {
|
||||||
|
return &iam_model.IamMemberSearchQuery{
|
||||||
|
Key: iamMemberSearchKeyToModel(query.Key),
|
||||||
|
Method: iamMemberSearchMethodToModel(query.Method),
|
||||||
|
Value: query.Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamMemberSearchKeyToModel(key IamMemberSearchKey) iam_model.IamMemberSearchKey {
|
||||||
|
switch key {
|
||||||
|
case IamMemberSearchKey_IAMMEMBERSEARCHKEY_EMAIL:
|
||||||
|
return iam_model.IamMemberSearchKeyEmail
|
||||||
|
case IamMemberSearchKey_IAMMEMBERSEARCHKEY_FIRST_NAME:
|
||||||
|
return iam_model.IamMemberSearchKeyFirstName
|
||||||
|
case IamMemberSearchKey_IAMMEMBERSEARCHKEY_LAST_NAME:
|
||||||
|
return iam_model.IamMemberSearchKeyLastName
|
||||||
|
case IamMemberSearchKey_IAMMEMBERSEARCHKEY_USER_ID:
|
||||||
|
return iam_model.IamMemberSearchKeyUserID
|
||||||
|
default:
|
||||||
|
return iam_model.IamMemberSearchKeyUnspecified
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamMemberSearchMethodToModel(key SearchMethod) model.SearchMethod {
|
||||||
|
switch key {
|
||||||
|
case SearchMethod_SEARCHMETHOD_CONTAINS:
|
||||||
|
return model.SearchMethodContains
|
||||||
|
case SearchMethod_SEARCHMETHOD_CONTAINS_IGNORE_CASE:
|
||||||
|
return model.SearchMethodContainsIgnoreCase
|
||||||
|
case SearchMethod_SEARCHMETHOD_EQUALS:
|
||||||
|
return model.SearchMethodEquals
|
||||||
|
case SearchMethod_SEARCHMETHOD_EQUALS_IGNORE_CASE:
|
||||||
|
return model.SearchMethodEqualsIgnoreCase
|
||||||
|
case SearchMethod_SEARCHMETHOD_STARTS_WITH:
|
||||||
|
return model.SearchMethodStartsWith
|
||||||
|
case SearchMethod_SEARCHMETHOD_STARTS_WITH_IGNORE_CASE:
|
||||||
|
return model.SearchMethodStartsWithIgnoreCase
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamMemberSearchResponseFromModel(resp *iam_model.IamMemberSearchResponse) *IamMemberSearchResponse {
|
||||||
|
return &IamMemberSearchResponse{
|
||||||
|
Limit: resp.Limit,
|
||||||
|
Offset: resp.Offset,
|
||||||
|
TotalResult: resp.TotalResult,
|
||||||
|
Result: iamMembersFromView(resp.Result),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func iamMembersFromView(viewMembers []*iam_model.IamMemberView) []*IamMemberView {
|
||||||
|
members := make([]*IamMemberView, len(viewMembers))
|
||||||
|
|
||||||
|
for i, member := range viewMembers {
|
||||||
|
members[i] = iamMemberFromView(member)
|
||||||
|
}
|
||||||
|
|
||||||
|
return members
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamMemberFromView(member *iam_model.IamMemberView) *IamMemberView {
|
||||||
|
changeDate, err := ptypes.TimestampProto(member.ChangeDate)
|
||||||
|
logging.Log("GRPC-Lso9c").OnError(err).Debug("unable to parse changedate")
|
||||||
|
creationDate, err := ptypes.TimestampProto(member.CreationDate)
|
||||||
|
logging.Log("GRPC-6szE").OnError(err).Debug("unable to parse creation date")
|
||||||
|
|
||||||
|
return &IamMemberView{
|
||||||
|
ChangeDate: changeDate,
|
||||||
|
CreationDate: creationDate,
|
||||||
|
Roles: member.Roles,
|
||||||
|
Sequence: member.Sequence,
|
||||||
|
UserId: member.UserID,
|
||||||
|
UserName: member.UserName,
|
||||||
|
Email: member.Email,
|
||||||
|
FirstName: member.FirstName,
|
||||||
|
LastName: member.LastName,
|
||||||
|
}
|
||||||
|
}
|
@ -15,22 +15,24 @@ import (
|
|||||||
var _ AdminServiceServer = (*Server)(nil)
|
var _ AdminServiceServer = (*Server)(nil)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
port string
|
port string
|
||||||
org repository.OrgRepository
|
org repository.OrgRepository
|
||||||
|
iam repository.IamRepository
|
||||||
administrator repository.AdministratorRepository
|
administrator repository.AdministratorRepository
|
||||||
verifier auth.TokenVerifier
|
verifier auth.TokenVerifier
|
||||||
authZ auth.Config
|
authZ auth.Config
|
||||||
repo repository.Repository
|
repo repository.Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartServer(conf grpc_util.ServerConfig, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) *Server {
|
func StartServer(conf grpc_util.ServerConfig, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
port: conf.Port,
|
port: conf.Port,
|
||||||
org: repo,
|
org: repo,
|
||||||
|
iam: repo,
|
||||||
administrator: repo,
|
administrator: repo,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
authZ: authZ,
|
authZ: authZ,
|
||||||
verifier: admin_auth.Start(authZRepo),
|
verifier: admin_auth.Start(authZRepo),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +142,59 @@ service AdminService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpc GetIamMemberRoles(google.protobuf.Empty) returns (IamMemberRoles) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
get: "/members/roles"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (caos.zitadel.utils.v1.auth_option) = {
|
||||||
|
permission: "iam.member.read"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc AddIamMember(AddIamMemberRequest) returns (IamMember) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/members"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (caos.zitadel.utils.v1.auth_option) = {
|
||||||
|
permission: "iam.member.write"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc ChangeIamMember(ChangeIamMemberRequest) returns (IamMember) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
put: "/members/{user_id}"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (caos.zitadel.utils.v1.auth_option) = {
|
||||||
|
permission: "iam.member.write"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc RemoveIamMember(RemoveIamMemberRequest) returns (google.protobuf.Empty) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
delete: "/members/{user_id}"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (caos.zitadel.utils.v1.auth_option) = {
|
||||||
|
permission: "iam.member.delete"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc SearchIamMembers(IamMemberSearchRequest) returns (IamMemberSearchResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/members/_search"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (caos.zitadel.utils.v1.auth_option) = {
|
||||||
|
permission: "iam.member.read"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
rpc GetViews(google.protobuf.Empty) returns (Views) {
|
rpc GetViews(google.protobuf.Empty) returns (Views) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/views"
|
get: "/views"
|
||||||
@ -340,6 +393,85 @@ message OrgIamPolicyID {
|
|||||||
string org_id = 1;
|
string org_id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message IamMemberRoles {
|
||||||
|
repeated string roles = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message IamMember {
|
||||||
|
string user_id = 1;
|
||||||
|
repeated string roles = 2;
|
||||||
|
google.protobuf.Timestamp change_date = 3;
|
||||||
|
google.protobuf.Timestamp creation_date = 4;
|
||||||
|
uint64 sequence = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AddIamMemberRequest {
|
||||||
|
string user_id = 1;
|
||||||
|
repeated string roles = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ChangeIamMemberRequest {
|
||||||
|
string user_id = 1;
|
||||||
|
repeated string roles = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RemoveIamMemberRequest {
|
||||||
|
string user_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message IamMemberSearchResponse {
|
||||||
|
uint64 offset = 1;
|
||||||
|
uint64 limit = 2;
|
||||||
|
uint64 total_result = 3;
|
||||||
|
repeated IamMemberView result = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message IamMemberView {
|
||||||
|
string user_id = 1;
|
||||||
|
repeated string roles = 2;
|
||||||
|
google.protobuf.Timestamp change_date = 3;
|
||||||
|
google.protobuf.Timestamp creation_date = 4;
|
||||||
|
uint64 sequence = 5;
|
||||||
|
string user_name = 6;
|
||||||
|
string email = 7;
|
||||||
|
string first_name = 8;
|
||||||
|
string last_name = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
message IamMemberSearchRequest {
|
||||||
|
uint64 offset = 1;
|
||||||
|
uint64 limit = 2;
|
||||||
|
repeated IamMemberSearchQuery queries = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message IamMemberSearchQuery {
|
||||||
|
IamMemberSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
|
||||||
|
SearchMethod method = 2;
|
||||||
|
string value = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum IamMemberSearchKey {
|
||||||
|
IAMMEMBERSEARCHKEY_UNSPECIFIED = 0;
|
||||||
|
IAMMEMBERSEARCHKEY_FIRST_NAME = 1;
|
||||||
|
IAMMEMBERSEARCHKEY_LAST_NAME = 2;
|
||||||
|
IAMMEMBERSEARCHKEY_EMAIL = 3;
|
||||||
|
IAMMEMBERSEARCHKEY_USER_ID = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SearchMethod {
|
||||||
|
SEARCHMETHOD_EQUALS = 0;
|
||||||
|
SEARCHMETHOD_STARTS_WITH = 1;
|
||||||
|
SEARCHMETHOD_CONTAINS = 2;
|
||||||
|
SEARCHMETHOD_EQUALS_IGNORE_CASE = 3;
|
||||||
|
SEARCHMETHOD_STARTS_WITH_IGNORE_CASE = 4;
|
||||||
|
SEARCHMETHOD_CONTAINS_IGNORE_CASE = 5;
|
||||||
|
SEARCHMETHOD_NOT_EQUALS = 6;
|
||||||
|
SEARCHMETHOD_GREATER_THAN = 7;
|
||||||
|
SEARCHMETHOD_LESS_THAN = 8;
|
||||||
|
SEARCHMETHOD_IS_ONE_OF = 9;
|
||||||
|
SEARCHMETHOD_LIST_CONTAINS = 10;
|
||||||
|
}
|
||||||
|
|
||||||
message FailedEventID {
|
message FailedEventID {
|
||||||
string database = 1;
|
string database = 1;
|
||||||
string view_name = 2;
|
string view_name = 2;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user