mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:17:23 +00:00
feat: org queries (#136)
* search orgs * org by domain * member spooler * member * get roles * tests * types duration * use default func for renew * correct database * reorder migrations * delete unused consts * move get roles to internal * use prepared org by domain * implement org in other objects * add eventstores
This commit is contained in:
parent
a6aba86b54
commit
3025ac577b
@ -93,6 +93,7 @@ Admin:
|
|||||||
CustomHeaders:
|
CustomHeaders:
|
||||||
- x-zitadel-
|
- x-zitadel-
|
||||||
Repository:
|
Repository:
|
||||||
|
SearchLimit: 100
|
||||||
Eventstore:
|
Eventstore:
|
||||||
ServiceName: 'Admin'
|
ServiceName: 'Admin'
|
||||||
Repository:
|
Repository:
|
||||||
@ -106,6 +107,16 @@ Admin:
|
|||||||
Type: 'fastcache'
|
Type: 'fastcache'
|
||||||
Config:
|
Config:
|
||||||
MaxCacheSizeInByte: 10485760 #10mb
|
MaxCacheSizeInByte: 10485760 #10mb
|
||||||
|
View:
|
||||||
|
Host: $ZITADEL_EVENTSTORE_HOST
|
||||||
|
Port: $ZITADEL_EVENTSTORE_PORT
|
||||||
|
User: 'admin_api'
|
||||||
|
Database: 'admin_api'
|
||||||
|
SSLmode: disable
|
||||||
|
Spooler:
|
||||||
|
ConcurrentTasks: 1
|
||||||
|
BulkLimit: 100
|
||||||
|
FailureCountUntilSkip: 5
|
||||||
|
|
||||||
Console:
|
Console:
|
||||||
Port: 50050
|
Port: 50050
|
||||||
|
@ -4,11 +4,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
admin_model "github.com/caos/zitadel/internal/admin/model"
|
admin_model "github.com/caos/zitadel/internal/admin/model"
|
||||||
"github.com/caos/zitadel/internal/errors"
|
admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
"github.com/caos/zitadel/internal/eventstore/sdk"
|
"github.com/caos/zitadel/internal/eventstore/sdk"
|
||||||
org_model "github.com/caos/zitadel/internal/org/model"
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||||
|
org_view "github.com/caos/zitadel/internal/org/repository/view"
|
||||||
usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,6 +17,10 @@ type OrgRepo struct {
|
|||||||
Eventstore eventstore.Eventstore
|
Eventstore eventstore.Eventstore
|
||||||
OrgEventstore *org_es.OrgEventstore
|
OrgEventstore *org_es.OrgEventstore
|
||||||
UserEventstore *usr_es.UserEventstore
|
UserEventstore *usr_es.UserEventstore
|
||||||
|
|
||||||
|
View *admin_view.View
|
||||||
|
|
||||||
|
SearchLimit uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *OrgRepo) SetUpOrg(ctx context.Context, setUp *admin_model.SetupOrg) (*admin_model.SetupOrg, error) {
|
func (repo *OrgRepo) SetUpOrg(ctx context.Context, setUp *admin_model.SetupOrg) (*admin_model.SetupOrg, error) {
|
||||||
@ -51,8 +56,18 @@ func (repo *OrgRepo) OrgByID(ctx context.Context, id string) (*org_model.Org, er
|
|||||||
return repo.OrgEventstore.OrgByID(ctx, org_model.NewOrg(id))
|
return repo.OrgEventstore.OrgByID(ctx, org_model.NewOrg(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *OrgRepo) SearchOrgs(ctx context.Context) ([]*org_model.Org, error) {
|
func (repo *OrgRepo) SearchOrgs(ctx context.Context, query *org_model.OrgSearchRequest) (*org_model.OrgSearchResult, error) {
|
||||||
return nil, errors.ThrowUnimplemented(nil, "EVENT-hFIHK", "search not implemented")
|
query.EnsureLimit(repo.SearchLimit)
|
||||||
|
orgs, count, err := repo.View.SearchOrgs(query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &org_model.OrgSearchResult{
|
||||||
|
Offset: query.Offset,
|
||||||
|
Limit: query.Limit,
|
||||||
|
TotalResult: uint64(count),
|
||||||
|
Result: org_view.OrgsToModel(orgs),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *OrgRepo) IsOrgUnique(ctx context.Context, name, domain string) (isUnique bool, err error) {
|
func (repo *OrgRepo) IsOrgUnique(ctx context.Context, name, domain string) (isUnique bool, err error) {
|
||||||
|
43
internal/admin/repository/eventsourcing/handler/handler.go
Normal file
43
internal/admin/repository/eventsourcing/handler/handler.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
||||||
|
"github.com/caos/zitadel/internal/config/types"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Configs map[string]*Config
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
MinimumCycleDuration types.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type handler struct {
|
||||||
|
view *view.View
|
||||||
|
bulkLimit uint64
|
||||||
|
cycleDuration time.Duration
|
||||||
|
errorCountUntilSkip uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type EventstoreRepos struct {
|
||||||
|
ProjectEvents *proj_event.ProjectEventstore
|
||||||
|
UserEvents *usr_event.UserEventstore
|
||||||
|
}
|
||||||
|
|
||||||
|
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View) []spooler.Handler {
|
||||||
|
return []spooler.Handler{
|
||||||
|
&Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (configs Configs) cycleDuration(viewModel string) time.Duration {
|
||||||
|
c, ok := configs[viewModel]
|
||||||
|
if !ok {
|
||||||
|
return 1 * time.Second
|
||||||
|
}
|
||||||
|
return c.MinimumCycleDuration.Duration
|
||||||
|
}
|
65
internal/admin/repository/eventsourcing/handler/org.go
Normal file
65
internal/admin/repository/eventsourcing/handler/org.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/logging"
|
||||||
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||||
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
|
"github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||||
|
"github.com/caos/zitadel/internal/org/repository/view"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Org struct {
|
||||||
|
handler
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
orgTable = "admin_api.orgs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (o *Org) MinimumCycleDuration() time.Duration { return o.cycleDuration }
|
||||||
|
|
||||||
|
func (o *Org) ViewModel() string {
|
||||||
|
return orgTable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) EventQuery() (*es_models.SearchQuery, error) {
|
||||||
|
sequence, err := o.view.GetLatestOrgSequence()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return eventsourcing.OrgQuery(sequence), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) Process(event *es_models.Event) error {
|
||||||
|
org := new(view.OrgView)
|
||||||
|
|
||||||
|
switch event.Type {
|
||||||
|
case org_model.OrgAdded:
|
||||||
|
org.AppendEvent(event)
|
||||||
|
case org_model.OrgChanged:
|
||||||
|
err := org.SetData(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
org, err = o.view.OrgByID(org.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = org.AppendEvent(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return o.view.ProcessedOrgSequence(event.Sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.view.PutOrg(org)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) OnError(event *es_models.Event, spoolerErr error) error {
|
||||||
|
logging.LogWithFields("SPOOL-ls9ew", "id", event.AggregateID).WithError(spoolerErr).Warn("something went wrong in project app handler")
|
||||||
|
return spooler.HandleError(event, spoolerErr, o.view.GetLatestOrgFailedEvent, o.view.ProcessedOrgFailedEvent, o.view.ProcessedOrgSequence, o.errorCountUntilSkip)
|
||||||
|
}
|
@ -6,8 +6,12 @@ import (
|
|||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/eventstore"
|
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/eventstore"
|
||||||
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/setup"
|
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/setup"
|
||||||
|
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/spooler"
|
||||||
|
admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
||||||
sd "github.com/caos/zitadel/internal/config/systemdefaults"
|
sd "github.com/caos/zitadel/internal/config/systemdefaults"
|
||||||
|
"github.com/caos/zitadel/internal/config/types"
|
||||||
es_int "github.com/caos/zitadel/internal/eventstore"
|
es_int "github.com/caos/zitadel/internal/eventstore"
|
||||||
|
es_spol "github.com/caos/zitadel/internal/eventstore/spooler"
|
||||||
es_iam "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
|
es_iam "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
|
||||||
es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||||
es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||||
@ -15,13 +19,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Eventstore es_int.Config
|
SearchLimit uint64
|
||||||
//View view.ViewConfig
|
Eventstore es_int.Config
|
||||||
//Spooler spooler.SpoolerConfig
|
View types.SQL
|
||||||
|
Spooler spooler.SpoolerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type EsRepository struct {
|
type EsRepository struct {
|
||||||
//spooler *es_spooler.Spooler
|
spooler *es_spol.Spooler
|
||||||
eventstore.OrgRepo
|
eventstore.OrgRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,15 +36,6 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
//view, sql, err := mgmt_view.StartView(conf.View)
|
|
||||||
//if err != nil {
|
|
||||||
// return nil, err
|
|
||||||
//}
|
|
||||||
|
|
||||||
//conf.Spooler.View = view
|
|
||||||
//conf.Spooler.EsClient = es.Client
|
|
||||||
//conf.Spooler.SQL = sql
|
|
||||||
//spool := spooler.StartSpooler(conf.Spooler)
|
|
||||||
iam, err := es_iam.StartIam(es_iam.IamConfig{
|
iam, err := es_iam.StartIam(es_iam.IamConfig{
|
||||||
Eventstore: es,
|
Eventstore: es,
|
||||||
Cache: conf.Eventstore.Cache,
|
Cache: conf.Eventstore.Cache,
|
||||||
@ -66,15 +62,29 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sqlClient, err := conf.View.Start()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
view, err := admin_view.StartView(sqlClient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
eventstoreRepos := setup.EventstoreRepos{OrgEvents: org, UserEvents: user, ProjectEvents: project, IamEvents: iam}
|
eventstoreRepos := setup.EventstoreRepos{OrgEvents: org, UserEvents: user, ProjectEvents: project, IamEvents: iam}
|
||||||
err = setup.StartSetup(systemDefaults, eventstoreRepos).Execute(ctx)
|
err = setup.StartSetup(systemDefaults, eventstoreRepos).Execute(ctx)
|
||||||
logging.Log("SERVE-k280HZ").OnError(err).Panic("failed to execute setup")
|
logging.Log("SERVE-k280HZ").OnError(err).Panic("failed to execute setup")
|
||||||
|
|
||||||
|
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient)
|
||||||
|
|
||||||
return &EsRepository{
|
return &EsRepository{
|
||||||
|
spooler: spool,
|
||||||
OrgRepo: eventstore.OrgRepo{
|
OrgRepo: eventstore.OrgRepo{
|
||||||
Eventstore: es,
|
Eventstore: es,
|
||||||
OrgEventstore: org,
|
OrgEventstore: org,
|
||||||
UserEventstore: user,
|
UserEventstore: user,
|
||||||
|
View: view,
|
||||||
|
SearchLimit: conf.SearchLimit,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
29
internal/admin/repository/eventsourcing/spooler/lock.go
Normal file
29
internal/admin/repository/eventsourcing/spooler/lock.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package spooler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
es_locker "github.com/caos/zitadel/internal/eventstore/locker"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
lockTable = "admin_api.locks"
|
||||||
|
lockedUntilKey = "locked_until"
|
||||||
|
lockerIDKey = "locker_id"
|
||||||
|
objectTypeKey = "object_type"
|
||||||
|
)
|
||||||
|
|
||||||
|
type locker struct {
|
||||||
|
dbClient *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
type lock struct {
|
||||||
|
LockerID string `gorm:"column:locker_id;primary_key"`
|
||||||
|
LockedUntil time.Time `gorm:"column:locked_until"`
|
||||||
|
ViewName string `gorm:"column:object_type;primary_key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *locker) Renew(lockerID, viewModel string, waitTime time.Duration) error {
|
||||||
|
return es_locker.Renew(l.dbClient, lockTable, lockerID, viewModel, waitTime)
|
||||||
|
}
|
127
internal/admin/repository/eventsourcing/spooler/lock_test.go
Normal file
127
internal/admin/repository/eventsourcing/spooler/lock_test.go
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
package spooler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dbMock struct {
|
||||||
|
db *sql.DB
|
||||||
|
mock sqlmock.Sqlmock
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockDB(t *testing.T) *dbMock {
|
||||||
|
mockDB := dbMock{}
|
||||||
|
var err error
|
||||||
|
mockDB.db, mockDB.mock, err = sqlmock.New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error occured while creating stub db %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mockDB.mock.MatchExpectationsInOrder(true)
|
||||||
|
|
||||||
|
return &mockDB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *dbMock) expectCommit() *dbMock {
|
||||||
|
db.mock.ExpectCommit()
|
||||||
|
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *dbMock) expectRollback() *dbMock {
|
||||||
|
db.mock.ExpectRollback()
|
||||||
|
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *dbMock) expectBegin() *dbMock {
|
||||||
|
db.mock.ExpectBegin()
|
||||||
|
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *dbMock) expectSavepoint() *dbMock {
|
||||||
|
db.mock.ExpectExec("SAVEPOINT").WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *dbMock) expectReleaseSavepoint() *dbMock {
|
||||||
|
db.mock.ExpectExec("RELEASE SAVEPOINT").WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
|
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *dbMock) expectRenew(lockerID, view string, affectedRows int64) *dbMock {
|
||||||
|
query := db.mock.
|
||||||
|
ExpectExec(`INSERT INTO admin_api\.locks \(object_type, locker_id, locked_until\) VALUES \(\$1, \$2, now\(\)\+\$3\) ON CONFLICT \(object_type\) DO UPDATE SET locked_until = now\(\)\+\$4, locker_id = \$5 WHERE \(locks\.locked_until < now\(\) OR locks\.locker_id = \$6\) AND locks\.object_type = \$7`).
|
||||||
|
WithArgs(view, lockerID, sqlmock.AnyArg(), sqlmock.AnyArg(), lockerID, lockerID, view).
|
||||||
|
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
|
|
||||||
|
if affectedRows == 0 {
|
||||||
|
query.WillReturnResult(sqlmock.NewResult(0, 0))
|
||||||
|
} else {
|
||||||
|
query.WillReturnResult(sqlmock.NewResult(1, affectedRows))
|
||||||
|
}
|
||||||
|
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_locker_Renew(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
db *dbMock
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
lockerID string
|
||||||
|
viewModel string
|
||||||
|
waitTime time.Duration
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "renew succeeded",
|
||||||
|
fields: fields{
|
||||||
|
db: mockDB(t).
|
||||||
|
expectBegin().
|
||||||
|
expectSavepoint().
|
||||||
|
expectRenew("locker", "view", 1).
|
||||||
|
expectReleaseSavepoint().
|
||||||
|
expectCommit(),
|
||||||
|
},
|
||||||
|
args: args{lockerID: "locker", viewModel: "view", waitTime: 1 * time.Second},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "renew now rows updated",
|
||||||
|
fields: fields{
|
||||||
|
db: mockDB(t).
|
||||||
|
expectBegin().
|
||||||
|
expectSavepoint().
|
||||||
|
expectRenew("locker", "view", 0).
|
||||||
|
expectRollback(),
|
||||||
|
},
|
||||||
|
args: args{lockerID: "locker", viewModel: "view", waitTime: 1 * time.Second},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
l := &locker{
|
||||||
|
dbClient: tt.fields.db.db,
|
||||||
|
}
|
||||||
|
if err := l.Renew(tt.args.lockerID, tt.args.viewModel, tt.args.waitTime); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("locker.Renew() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
if err := tt.fields.db.mock.ExpectationsWereMet(); err != nil {
|
||||||
|
t.Errorf("not all database expectations met: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
29
internal/admin/repository/eventsourcing/spooler/spooler.go
Normal file
29
internal/admin/repository/eventsourcing/spooler/spooler.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package spooler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/handler"
|
||||||
|
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SpoolerConfig struct {
|
||||||
|
BulkLimit uint64
|
||||||
|
FailureCountUntilSkip uint64
|
||||||
|
ConcurrentTasks int
|
||||||
|
Handlers handler.Configs
|
||||||
|
}
|
||||||
|
|
||||||
|
func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB) *spooler.Spooler {
|
||||||
|
spoolerConfig := spooler.Config{
|
||||||
|
Eventstore: es,
|
||||||
|
Locker: &locker{dbClient: sql},
|
||||||
|
ConcurrentTasks: c.ConcurrentTasks,
|
||||||
|
ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view),
|
||||||
|
}
|
||||||
|
spool := spoolerConfig.New()
|
||||||
|
spool.Start()
|
||||||
|
return spool
|
||||||
|
}
|
17
internal/admin/repository/eventsourcing/view/error_event.go
Normal file
17
internal/admin/repository/eventsourcing/view/error_event.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caos/zitadel/internal/view"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
errTable = "admin_api.failed_event"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v *View) saveFailedEvent(failedEvent *view.FailedEvent) error {
|
||||||
|
return view.SaveFailedEvent(v.Db, errTable, failedEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) latestFailedEvent(viewName string, sequence uint64) (*view.FailedEvent, error) {
|
||||||
|
return view.LatestFailedEvent(v.Db, errTable, viewName, sequence)
|
||||||
|
}
|
43
internal/admin/repository/eventsourcing/view/org.go
Normal file
43
internal/admin/repository/eventsourcing/view/org.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
|
org_view "github.com/caos/zitadel/internal/org/repository/view"
|
||||||
|
"github.com/caos/zitadel/internal/view"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
orgTable = "admin_api.orgs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v *View) OrgByID(orgID string) (*org_view.OrgView, error) {
|
||||||
|
return org_view.OrgByID(v.Db, orgTable, orgID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) SearchOrgs(query *org_model.OrgSearchRequest) ([]*org_view.OrgView, int, error) {
|
||||||
|
return org_view.SearchOrgs(v.Db, orgTable, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) PutOrg(org *org_view.OrgView) error {
|
||||||
|
err := org_view.PutOrg(v.Db, orgTable, org)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return v.ProcessedOrgSequence(org.Sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*view.FailedEvent, error) {
|
||||||
|
return v.latestFailedEvent(orgTable, sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ProcessedOrgFailedEvent(failedEvent *view.FailedEvent) error {
|
||||||
|
return v.saveFailedEvent(failedEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestOrgSequence() (uint64, error) {
|
||||||
|
return v.latestSequence(orgTable)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ProcessedOrgSequence(eventSequence uint64) error {
|
||||||
|
return v.saveCurrentSequence(orgTable, eventSequence)
|
||||||
|
}
|
17
internal/admin/repository/eventsourcing/view/sequence.go
Normal file
17
internal/admin/repository/eventsourcing/view/sequence.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caos/zitadel/internal/view"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
sequencesTable = "admin_api.current_sequences"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v *View) saveCurrentSequence(viewName string, sequence uint64) error {
|
||||||
|
return view.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) latestSequence(viewName string) (uint64, error) {
|
||||||
|
return view.LatestSequence(v.Db, sequencesTable, viewName)
|
||||||
|
}
|
25
internal/admin/repository/eventsourcing/view/view.go
Normal file
25
internal/admin/repository/eventsourcing/view/view.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type View struct {
|
||||||
|
Db *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func StartView(sqlClient *sql.DB) (*View, error) {
|
||||||
|
gorm, err := gorm.Open("postgres", sqlClient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &View{
|
||||||
|
Db: gorm,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) Health() (err error) {
|
||||||
|
return v.Db.DB().Ping()
|
||||||
|
}
|
@ -11,5 +11,5 @@ type OrgRepository interface {
|
|||||||
SetUpOrg(context.Context, *admin_model.SetupOrg) (*admin_model.SetupOrg, error)
|
SetUpOrg(context.Context, *admin_model.SetupOrg) (*admin_model.SetupOrg, error)
|
||||||
IsOrgUnique(ctx context.Context, name, domain string) (bool, error)
|
IsOrgUnique(ctx context.Context, name, domain string) (bool, error)
|
||||||
OrgByID(ctx context.Context, id string) (*org_model.Org, error)
|
OrgByID(ctx context.Context, id string) (*org_model.Org, error)
|
||||||
SearchOrgs(ctx context.Context) ([]*org_model.Org, error)
|
SearchOrgs(ctx context.Context, query *org_model.OrgSearchRequest) (*org_model.OrgSearchResult, error)
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,20 @@ package eventstore
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
mgmt_view "github.com/caos/zitadel/internal/management/repository/eventsourcing/view"
|
||||||
org_model "github.com/caos/zitadel/internal/org/model"
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||||
|
"github.com/caos/zitadel/internal/org/repository/view"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OrgRepository struct {
|
type OrgRepository struct {
|
||||||
|
SearchLimit uint64
|
||||||
*org_es.OrgEventstore
|
*org_es.OrgEventstore
|
||||||
|
View *mgmt_view.View
|
||||||
|
Roles []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *OrgRepository) OrgByID(ctx context.Context, id string) (*org_model.Org, error) {
|
func (repo *OrgRepository) OrgByID(ctx context.Context, id string) (*org_model.Org, error) {
|
||||||
@ -17,8 +23,12 @@ func (repo *OrgRepository) OrgByID(ctx context.Context, id string) (*org_model.O
|
|||||||
return repo.OrgEventstore.OrgByID(ctx, org)
|
return repo.OrgEventstore.OrgByID(ctx, org)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *OrgRepository) OrgByDomainGlobal(ctx context.Context, domain string) (*org_model.Org, error) {
|
func (repo *OrgRepository) OrgByDomainGlobal(ctx context.Context, domain string) (*org_model.OrgView, error) {
|
||||||
return nil, errors.ThrowUnimplemented(nil, "EVENT-GQoS8", "not implemented")
|
org, err := repo.View.OrgByDomain(domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return view.OrgToModel(org), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *OrgRepository) UpdateOrg(ctx context.Context, org *org_model.Org) (*org_model.Org, error) {
|
func (repo *OrgRepository) UpdateOrg(ctx context.Context, org *org_model.Org) (*org_model.Org, error) {
|
||||||
@ -50,3 +60,27 @@ func (repo *OrgRepository) RemoveOrgMember(ctx context.Context, orgID, userID st
|
|||||||
member := org_model.NewOrgMember(orgID, userID)
|
member := org_model.NewOrgMember(orgID, userID)
|
||||||
return repo.OrgEventstore.RemoveOrgMember(ctx, member)
|
return repo.OrgEventstore.RemoveOrgMember(ctx, member)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (repo *OrgRepository) SearchOrgMembers(ctx context.Context, request *org_model.OrgMemberSearchRequest) (*org_model.OrgMemberSearchResponse, error) {
|
||||||
|
request.EnsureLimit(repo.SearchLimit)
|
||||||
|
members, count, err := repo.View.SearchOrgMembers(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &org_model.OrgMemberSearchResponse{
|
||||||
|
Offset: request.Offset,
|
||||||
|
Limit: request.Limit,
|
||||||
|
TotalResult: uint64(count),
|
||||||
|
Result: view.OrgMembersToModel(members),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *OrgRepository) GetOrgMemberRoles() []string {
|
||||||
|
roles := make([]string, 0)
|
||||||
|
for _, roleMap := range repo.Roles {
|
||||||
|
if strings.HasPrefix(roleMap, "ORG") {
|
||||||
|
roles = append(roles, roleMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
package eventstore
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
org_model "github.com/caos/zitadel/internal/org/model"
|
|
||||||
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type OrgMemberRepository struct {
|
|
||||||
*org_es.OrgEventstore
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *OrgMemberRepository) OrgMemberByID(ctx context.Context, orgID, userID string) (member *org_model.OrgMember, err error) {
|
|
||||||
member = org_model.NewOrgMember(orgID, userID)
|
|
||||||
return repo.OrgEventstore.OrgMemberByIDs(ctx, member)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *OrgMemberRepository) AddOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) {
|
|
||||||
return repo.OrgEventstore.AddOrgMember(ctx, member)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *OrgMemberRepository) ChangeOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) {
|
|
||||||
return repo.OrgEventstore.ChangeOrgMember(ctx, member)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *OrgMemberRepository) RemoveOrgMember(ctx context.Context, orgID, userID string) error {
|
|
||||||
member := org_model.NewOrgMember(orgID, userID)
|
|
||||||
return repo.OrgEventstore.RemoveOrgMember(ctx, member)
|
|
||||||
}
|
|
@ -2,6 +2,8 @@ package eventstore
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/management/repository/eventsourcing/view"
|
"github.com/caos/zitadel/internal/management/repository/eventsourcing/view"
|
||||||
"github.com/caos/zitadel/internal/project/repository/view/model"
|
"github.com/caos/zitadel/internal/project/repository/view/model"
|
||||||
|
|
||||||
@ -13,6 +15,7 @@ type ProjectRepo struct {
|
|||||||
SearchLimit uint64
|
SearchLimit uint64
|
||||||
ProjectEvents *proj_event.ProjectEventstore
|
ProjectEvents *proj_event.ProjectEventstore
|
||||||
View *view.View
|
View *view.View
|
||||||
|
Roles []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ProjectRepo) ProjectByID(ctx context.Context, id string) (project *proj_model.Project, err error) {
|
func (repo *ProjectRepo) ProjectByID(ctx context.Context, id string) (project *proj_model.Project, err error) {
|
||||||
@ -212,3 +215,23 @@ func (repo *ProjectRepo) SearchProjectGrantMembers(ctx context.Context, request
|
|||||||
Result: model.ProjectGrantMembersToModel(members),
|
Result: model.ProjectGrantMembersToModel(members),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (repo *ProjectRepo) GetProjectMemberRoles() []string {
|
||||||
|
roles := make([]string, 0)
|
||||||
|
for _, roleMap := range repo.Roles {
|
||||||
|
if strings.HasPrefix(roleMap, "PROJECT") && !strings.HasPrefix(roleMap, "PROJECT_GRANT") {
|
||||||
|
roles = append(roles, roleMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *ProjectRepo) GetProjectGrantMemberRoles() []string {
|
||||||
|
roles := make([]string, 0)
|
||||||
|
for _, roleMap := range repo.Roles {
|
||||||
|
if strings.HasPrefix(roleMap, "PROJECT_GRANT") {
|
||||||
|
roles = append(roles, roleMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
@ -9,8 +9,9 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
"github.com/caos/zitadel/internal/eventstore/models"
|
"github.com/caos/zitadel/internal/eventstore/models"
|
||||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||||
"github.com/caos/zitadel/internal/project/model"
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
"github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||||
|
proj_model "github.com/caos/zitadel/internal/project/model"
|
||||||
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||||
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||||
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
||||||
@ -20,6 +21,7 @@ type GrantedProject struct {
|
|||||||
handler
|
handler
|
||||||
eventstore eventstore.Eventstore
|
eventstore eventstore.Eventstore
|
||||||
projectEvents *proj_event.ProjectEventstore
|
projectEvents *proj_event.ProjectEventstore
|
||||||
|
orgEvents *org_event.OrgEventstore
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -37,7 +39,7 @@ func (p *GrantedProject) EventQuery() (*models.SearchQuery, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return eventsourcing.ProjectQuery(sequence), nil
|
return proj_event.ProjectQuery(sequence), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *GrantedProject) Process(event *models.Event) (err error) {
|
func (p *GrantedProject) Process(event *models.Event) (err error) {
|
||||||
@ -71,7 +73,12 @@ func (p *GrantedProject) Process(event *models.Event) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
grantedProject.Name = project.Name
|
grantedProject.Name = project.Name
|
||||||
//TODO: read org
|
|
||||||
|
org, err := p.orgEvents.OrgByID(context.TODO(), org_model.NewOrg(grantedProject.OrgID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.fillOrgData(grantedProject, org)
|
||||||
case es_model.ProjectGrantChanged:
|
case es_model.ProjectGrantChanged:
|
||||||
grant := new(view_model.ProjectGrant)
|
grant := new(view_model.ProjectGrant)
|
||||||
err := grant.SetData(event)
|
err := grant.SetData(event)
|
||||||
@ -99,11 +106,12 @@ func (p *GrantedProject) Process(event *models.Event) (err error) {
|
|||||||
return p.view.PutGrantedProject(grantedProject)
|
return p.view.PutGrantedProject(grantedProject)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *GrantedProject) getOrg(orgID string) {
|
func (p *GrantedProject) fillOrgData(grantedProject *view_model.GrantedProjectView, org *org_model.Org) {
|
||||||
//TODO: Get Org
|
grantedProject.OrgDomain = org.Domain
|
||||||
|
grantedProject.OrgName = org.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *GrantedProject) getProject(projectID string) (*model.Project, error) {
|
func (p *GrantedProject) getProject(projectID string) (*proj_model.Project, error) {
|
||||||
return p.projectEvents.ProjectByID(context.Background(), projectID)
|
return p.projectEvents.ProjectByID(context.Background(), projectID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/config/types"
|
"github.com/caos/zitadel/internal/config/types"
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||||
"github.com/caos/zitadel/internal/management/repository/eventsourcing/view"
|
"github.com/caos/zitadel/internal/management/repository/eventsourcing/view"
|
||||||
|
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||||
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
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"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Configs map[string]*Config
|
type Configs map[string]*Config
|
||||||
@ -26,17 +28,20 @@ type handler struct {
|
|||||||
type EventstoreRepos struct {
|
type EventstoreRepos struct {
|
||||||
ProjectEvents *proj_event.ProjectEventstore
|
ProjectEvents *proj_event.ProjectEventstore
|
||||||
UserEvents *usr_event.UserEventstore
|
UserEvents *usr_event.UserEventstore
|
||||||
|
OrgEvents *org_event.OrgEventstore
|
||||||
}
|
}
|
||||||
|
|
||||||
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, eventstore eventstore.Eventstore, repos EventstoreRepos) []spooler.Handler {
|
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, eventstore eventstore.Eventstore, repos EventstoreRepos) []spooler.Handler {
|
||||||
return []spooler.Handler{
|
return []spooler.Handler{
|
||||||
&GrantedProject{handler: handler{view, bulkLimit, configs.cycleDuration("GrantedProject"), errorCount}, eventstore: eventstore, projectEvents: repos.ProjectEvents},
|
&GrantedProject{handler: handler{view, bulkLimit, configs.cycleDuration("GrantedProject"), errorCount}, eventstore: eventstore, projectEvents: repos.ProjectEvents, orgEvents: repos.OrgEvents},
|
||||||
&ProjectRole{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount}, projectEvents: repos.ProjectEvents},
|
&ProjectRole{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount}, projectEvents: repos.ProjectEvents},
|
||||||
&ProjectMember{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectMember"), errorCount}, userEvents: repos.UserEvents},
|
&ProjectMember{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectMember"), errorCount}, userEvents: repos.UserEvents},
|
||||||
&ProjectGrantMember{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectGrantMember"), errorCount}, userEvents: repos.UserEvents},
|
&ProjectGrantMember{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectGrantMember"), errorCount}, userEvents: repos.UserEvents},
|
||||||
&Application{handler: handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount}},
|
&Application{handler: handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount}, projectEvents: repos.ProjectEvents},
|
||||||
&User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount}},
|
&User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount}, eventstore: eventstore},
|
||||||
&UserGrant{handler: handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount}, projectEvents: repos.ProjectEvents, userEvents: repos.UserEvents},
|
&UserGrant{handler: handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount}, projectEvents: repos.ProjectEvents, userEvents: repos.UserEvents, orgEvents: repos.OrgEvents},
|
||||||
|
&Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}},
|
||||||
|
&OrgMember{handler: handler{view, bulkLimit, configs.cycleDuration("OrgMember"), errorCount}, userEvents: repos.UserEvents},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
65
internal/management/repository/eventsourcing/handler/org.go
Normal file
65
internal/management/repository/eventsourcing/handler/org.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/logging"
|
||||||
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||||
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
|
"github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||||
|
"github.com/caos/zitadel/internal/org/repository/view"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Org struct {
|
||||||
|
handler
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
orgTable = "management.orgs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (o *Org) MinimumCycleDuration() time.Duration { return o.cycleDuration }
|
||||||
|
|
||||||
|
func (o *Org) ViewModel() string {
|
||||||
|
return orgTable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) EventQuery() (*es_models.SearchQuery, error) {
|
||||||
|
sequence, err := o.view.GetLatestOrgSequence()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return eventsourcing.OrgQuery(sequence), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) Process(event *es_models.Event) error {
|
||||||
|
org := new(view.OrgView)
|
||||||
|
|
||||||
|
switch event.Type {
|
||||||
|
case org_model.OrgAdded:
|
||||||
|
org.AppendEvent(event)
|
||||||
|
case org_model.OrgChanged:
|
||||||
|
err := org.SetData(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
org, err = o.view.OrgByID(org.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = org.AppendEvent(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return o.view.ProcessedOrgSequence(event.Sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.view.PutOrg(org)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Org) OnError(event *es_models.Event, spoolerErr error) error {
|
||||||
|
logging.LogWithFields("SPOOL-ls9ew", "id", event.AggregateID).WithError(spoolerErr).Warn("something went wrong in project app handler")
|
||||||
|
return spooler.HandleError(event, spoolerErr, o.view.GetLatestOrgFailedEvent, o.view.ProcessedOrgFailedEvent, o.view.ProcessedOrgSequence, o.errorCountUntilSkip)
|
||||||
|
}
|
@ -0,0 +1,127 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"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"
|
||||||
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
|
view_model "github.com/caos/zitadel/internal/org/repository/view"
|
||||||
|
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 OrgMember struct {
|
||||||
|
handler
|
||||||
|
userEvents *usr_event.UserEventstore
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
orgMemberTable = "management.org_members"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *OrgMember) MinimumCycleDuration() time.Duration { return m.cycleDuration }
|
||||||
|
|
||||||
|
func (m *OrgMember) ViewModel() string {
|
||||||
|
return orgMemberTable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *OrgMember) EventQuery() (*models.SearchQuery, error) {
|
||||||
|
sequence, err := m.view.GetLatestOrgMemberSequence()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return es_models.NewSearchQuery().
|
||||||
|
AggregateTypeFilter(org_model.OrgAggregate, usr_es_model.UserAggregate).
|
||||||
|
LatestSequenceFilter(sequence), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *OrgMember) Process(event *models.Event) (err error) {
|
||||||
|
switch event.AggregateType {
|
||||||
|
case org_model.OrgAggregate:
|
||||||
|
err = m.processOrgMember(event)
|
||||||
|
case usr_es_model.UserAggregate:
|
||||||
|
err = m.processUser(event)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *OrgMember) processOrgMember(event *models.Event) (err error) {
|
||||||
|
member := new(view_model.OrgMemberView)
|
||||||
|
switch event.Type {
|
||||||
|
case org_model.OrgMemberAdded:
|
||||||
|
member.AppendEvent(event)
|
||||||
|
m.fillData(member)
|
||||||
|
case org_model.OrgMemberChanged:
|
||||||
|
err := member.SetData(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
member, err = m.view.OrgMemberByIDs(event.AggregateID, member.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
member.AppendEvent(event)
|
||||||
|
case org_model.OrgMemberRemoved:
|
||||||
|
err := member.SetData(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return m.view.DeleteOrgMember(event.AggregateID, member.UserID, event.Sequence)
|
||||||
|
default:
|
||||||
|
return m.view.ProcessedOrgMemberSequence(event.Sequence)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return m.view.PutOrgMember(member, member.Sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *OrgMember) processUser(event *models.Event) (err error) {
|
||||||
|
switch event.Type {
|
||||||
|
case usr_es_model.UserProfileChanged,
|
||||||
|
usr_es_model.UserEmailChanged:
|
||||||
|
members, err := m.view.OrgMembersByUserID(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.PutOrgMember(member, event.Sequence)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return m.view.ProcessedOrgMemberSequence(event.Sequence)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *OrgMember) fillData(member *view_model.OrgMemberView) (err error) {
|
||||||
|
user, err := m.userEvents.UserByID(context.Background(), member.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.fillUserData(member, user)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *OrgMember) fillUserData(member *view_model.OrgMemberView, user *usr_model.User) {
|
||||||
|
member.UserName = user.UserName
|
||||||
|
member.FirstName = user.FirstName
|
||||||
|
member.LastName = user.LastName
|
||||||
|
member.Email = user.EmailAddress
|
||||||
|
}
|
||||||
|
func (m *OrgMember) OnError(event *models.Event, err error) error {
|
||||||
|
logging.LogWithFields("SPOOL-u73es", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgmember handler")
|
||||||
|
return spooler.HandleError(event, err, m.view.GetLatestOrgMemberFailedEvent, m.view.ProcessedOrgMemberFailedEvent, m.view.ProcessedOrgMemberSequence, m.errorCountUntilSkip)
|
||||||
|
}
|
@ -2,7 +2,11 @@ package handler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
|
org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||||
proj_model "github.com/caos/zitadel/internal/project/model"
|
proj_model "github.com/caos/zitadel/internal/project/model"
|
||||||
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||||
proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||||
@ -10,7 +14,6 @@ import (
|
|||||||
usr_events "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
usr_events "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||||
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||||
grant_es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
|
grant_es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
|
||||||
@ -25,6 +28,7 @@ type UserGrant struct {
|
|||||||
eventstore eventstore.Eventstore
|
eventstore eventstore.Eventstore
|
||||||
projectEvents *proj_event.ProjectEventstore
|
projectEvents *proj_event.ProjectEventstore
|
||||||
userEvents *usr_events.UserEventstore
|
userEvents *usr_events.UserEventstore
|
||||||
|
orgEvents *org_events.OrgEventstore
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -67,7 +71,7 @@ func (u *UserGrant) processUserGrant(event *models.Event) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = u.fillData(grant)
|
err = u.fillData(grant, event.ResourceOwner)
|
||||||
case grant_es_model.UserGrantChanged,
|
case grant_es_model.UserGrantChanged,
|
||||||
grant_es_model.UserGrantDeactivated,
|
grant_es_model.UserGrantDeactivated,
|
||||||
grant_es_model.UserGrantReactivated:
|
grant_es_model.UserGrantReactivated:
|
||||||
@ -133,7 +137,7 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserGrant) fillData(grant *view_model.UserGrantView) (err error) {
|
func (u *UserGrant) fillData(grant *view_model.UserGrantView, resourceOwner string) (err error) {
|
||||||
user, err := u.userEvents.UserByID(context.Background(), grant.UserID)
|
user, err := u.userEvents.UserByID(context.Background(), grant.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -144,7 +148,12 @@ func (u *UserGrant) fillData(grant *view_model.UserGrantView) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
u.fillProjectData(grant, project)
|
u.fillProjectData(grant, project)
|
||||||
u.fillOrgData(grant)
|
|
||||||
|
org, err := u.orgEvents.OrgByID(context.TODO(), org_model.NewOrg(resourceOwner))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
u.fillOrgData(grant, org)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,8 +168,9 @@ func (u *UserGrant) fillProjectData(grant *view_model.UserGrantView, project *pr
|
|||||||
grant.ProjectName = project.Name
|
grant.ProjectName = project.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView) {
|
func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView, org *org_model.Org) {
|
||||||
//TODO: get ORG
|
grant.OrgDomain = org.Domain
|
||||||
|
grant.OrgName = org.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserGrant) OnError(event *models.Event, err error) error {
|
func (u *UserGrant) OnError(event *models.Event, err error) error {
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
package eventsourcing
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/errors"
|
|
||||||
org_model "github.com/caos/zitadel/internal/org/model"
|
|
||||||
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type OrgRepository struct {
|
|
||||||
*org_es.OrgEventstore
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *OrgRepository) OrgByID(ctx context.Context, id string) (*org_model.Org, error) {
|
|
||||||
org := org_model.NewOrg(id)
|
|
||||||
return repo.OrgEventstore.OrgByID(ctx, org)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *OrgRepository) OrgByDomainGlobal(ctx context.Context, domain string) (*org_model.Org, error) {
|
|
||||||
return nil, errors.ThrowUnimplemented(nil, "EVENT-GQoS8", "not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *OrgRepository) UpdateOrg(ctx context.Context, org *org_model.Org) (*org_model.Org, error) {
|
|
||||||
return nil, errors.ThrowUnimplemented(nil, "EVENT-RkurR", "not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *OrgRepository) DeactivateOrg(ctx context.Context, id string) (*org_model.Org, error) {
|
|
||||||
return repo.OrgEventstore.DeactivateOrg(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *OrgRepository) ReactivateOrg(ctx context.Context, id string) (*org_model.Org, error) {
|
|
||||||
return repo.OrgEventstore.ReactivateOrg(ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *OrgRepository) OrgMemberByID(ctx context.Context, orgID, userID string) (member *org_model.OrgMember, err error) {
|
|
||||||
member = org_model.NewOrgMember(orgID, userID)
|
|
||||||
return repo.OrgEventstore.OrgMemberByIDs(ctx, member)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *OrgRepository) AddOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) {
|
|
||||||
return repo.OrgEventstore.AddOrgMember(ctx, member)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *OrgRepository) ChangeOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) {
|
|
||||||
return repo.OrgEventstore.ChangeOrgMember(ctx, member)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *OrgRepository) RemoveOrgMember(ctx context.Context, orgID, userID string) error {
|
|
||||||
member := org_model.NewOrgMember(orgID, userID)
|
|
||||||
return repo.OrgEventstore.RemoveOrgMember(ctx, member)
|
|
||||||
}
|
|
@ -34,7 +34,7 @@ type EsRepository struct {
|
|||||||
eventstore.PolicyRepo
|
eventstore.PolicyRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) {
|
func Start(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
|
||||||
@ -79,13 +79,13 @@ func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error)
|
|||||||
}
|
}
|
||||||
org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es})
|
org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es})
|
||||||
|
|
||||||
eventstoreRepos := handler.EventstoreRepos{ProjectEvents: project, UserEvents: user}
|
eventstoreRepos := handler.EventstoreRepos{ProjectEvents: project, UserEvents: user, OrgEvents: org}
|
||||||
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, eventstoreRepos)
|
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, eventstoreRepos)
|
||||||
|
|
||||||
return &EsRepository{
|
return &EsRepository{
|
||||||
spooler: spool,
|
spooler: spool,
|
||||||
OrgRepository: eventstore.OrgRepository{org},
|
OrgRepository: eventstore.OrgRepository{conf.SearchLimit, org, view, roles},
|
||||||
ProjectRepo: eventstore.ProjectRepo{conf.SearchLimit, project, view},
|
ProjectRepo: eventstore.ProjectRepo{conf.SearchLimit, project, view, roles},
|
||||||
UserRepo: eventstore.UserRepo{conf.SearchLimit, user, view},
|
UserRepo: eventstore.UserRepo{conf.SearchLimit, user, view},
|
||||||
UserGrantRepo: eventstore.UserGrantRepo{conf.SearchLimit, usergrant, view},
|
UserGrantRepo: eventstore.UserGrantRepo{conf.SearchLimit, usergrant, view},
|
||||||
PolicyRepo: eventstore.PolicyRepo{policy},
|
PolicyRepo: eventstore.PolicyRepo{policy},
|
||||||
|
42
internal/management/repository/eventsourcing/view/org.go
Normal file
42
internal/management/repository/eventsourcing/view/org.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
org_view "github.com/caos/zitadel/internal/org/repository/view"
|
||||||
|
"github.com/caos/zitadel/internal/view"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
orgTable = "management.orgs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v *View) OrgByID(orgID string) (*org_view.OrgView, error) {
|
||||||
|
return org_view.OrgByID(v.Db, orgTable, orgID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) OrgByDomain(domain string) (*org_view.OrgView, error) {
|
||||||
|
return org_view.GetGlobalOrgByDomain(v.Db, orgTable, domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) PutOrg(org *org_view.OrgView) error {
|
||||||
|
err := org_view.PutOrg(v.Db, orgTable, org)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return v.ProcessedOrgSequence(org.Sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*view.FailedEvent, error) {
|
||||||
|
return v.latestFailedEvent(orgTable, sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ProcessedOrgFailedEvent(failedEvent *view.FailedEvent) error {
|
||||||
|
return v.saveFailedEvent(failedEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestOrgSequence() (uint64, error) {
|
||||||
|
return v.latestSequence(orgTable)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ProcessedOrgSequence(eventSequence uint64) error {
|
||||||
|
return v.saveCurrentSequence(orgTable, eventSequence)
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
|
"github.com/caos/zitadel/internal/org/repository/view"
|
||||||
|
global_view "github.com/caos/zitadel/internal/view"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
orgMemberTable = "management.org_members"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v *View) OrgMemberByIDs(orgID, userID string) (*view.OrgMemberView, error) {
|
||||||
|
return view.OrgMemberByIDs(v.Db, orgMemberTable, orgID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) SearchOrgMembers(request *org_model.OrgMemberSearchRequest) ([]*view.OrgMemberView, int, error) {
|
||||||
|
return view.SearchOrgMembers(v.Db, orgMemberTable, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) OrgMembersByUserID(userID string) ([]*view.OrgMemberView, error) {
|
||||||
|
return view.OrgMembersByUserID(v.Db, orgMemberTable, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) PutOrgMember(org *view.OrgMemberView, sequence uint64) error {
|
||||||
|
err := view.PutOrgMember(v.Db, orgMemberTable, org)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return v.ProcessedOrgMemberSequence(sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) DeleteOrgMember(orgID, userID string, eventSequence uint64) error {
|
||||||
|
err := view.DeleteOrgMember(v.Db, orgMemberTable, orgID, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.ProcessedOrgMemberSequence(eventSequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestOrgMemberSequence() (uint64, error) {
|
||||||
|
return v.latestSequence(orgMemberTable)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ProcessedOrgMemberSequence(eventSequence uint64) error {
|
||||||
|
return v.saveCurrentSequence(orgMemberTable, eventSequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestOrgMemberFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
|
||||||
|
return v.latestFailedEvent(orgMemberTable, sequence)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) ProcessedOrgMemberFailedEvent(failedEvent *global_view.FailedEvent) error {
|
||||||
|
return v.saveFailedEvent(failedEvent)
|
||||||
|
}
|
@ -8,14 +8,15 @@ import (
|
|||||||
|
|
||||||
type OrgRepository interface {
|
type OrgRepository interface {
|
||||||
OrgByID(ctx context.Context, id string) (*org_model.Org, error)
|
OrgByID(ctx context.Context, id string) (*org_model.Org, error)
|
||||||
OrgByDomainGlobal(ctx context.Context, domain string) (*org_model.Org, error)
|
OrgByDomainGlobal(ctx context.Context, domain string) (*org_model.OrgView, error)
|
||||||
UpdateOrg(ctx context.Context, org *org_model.Org) (*org_model.Org, error)
|
UpdateOrg(ctx context.Context, org *org_model.Org) (*org_model.Org, error)
|
||||||
DeactivateOrg(ctx context.Context, id string) (*org_model.Org, error)
|
DeactivateOrg(ctx context.Context, id string) (*org_model.Org, error)
|
||||||
ReactivateOrg(ctx context.Context, id string) (*org_model.Org, error)
|
ReactivateOrg(ctx context.Context, id string) (*org_model.Org, error)
|
||||||
}
|
|
||||||
|
|
||||||
type OrgMemberRepository interface {
|
SearchOrgMembers(ctx context.Context, request *org_model.OrgMemberSearchRequest) (*org_model.OrgMemberSearchResponse, error)
|
||||||
AddOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error)
|
AddOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error)
|
||||||
ChangeOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error)
|
ChangeOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error)
|
||||||
RemoveOrgMember(ctx context.Context, orgID, userID string) error
|
RemoveOrgMember(ctx context.Context, orgID, userID string) error
|
||||||
|
|
||||||
|
GetOrgMemberRoles() []string
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package repository
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/project/model"
|
"github.com/caos/zitadel/internal/project/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,6 +19,7 @@ type ProjectRepository interface {
|
|||||||
ChangeProjectMember(ctx context.Context, member *model.ProjectMember) (*model.ProjectMember, error)
|
ChangeProjectMember(ctx context.Context, member *model.ProjectMember) (*model.ProjectMember, error)
|
||||||
RemoveProjectMember(ctx context.Context, projectID, userID string) error
|
RemoveProjectMember(ctx context.Context, projectID, userID string) error
|
||||||
SearchProjectMembers(ctx context.Context, request *model.ProjectMemberSearchRequest) (*model.ProjectMemberSearchResponse, error)
|
SearchProjectMembers(ctx context.Context, request *model.ProjectMemberSearchRequest) (*model.ProjectMemberSearchResponse, error)
|
||||||
|
GetProjectMemberRoles() []string
|
||||||
|
|
||||||
AddProjectRole(ctx context.Context, role *model.ProjectRole) (*model.ProjectRole, error)
|
AddProjectRole(ctx context.Context, role *model.ProjectRole) (*model.ProjectRole, error)
|
||||||
ChangeProjectRole(ctx context.Context, role *model.ProjectRole) (*model.ProjectRole, error)
|
ChangeProjectRole(ctx context.Context, role *model.ProjectRole) (*model.ProjectRole, error)
|
||||||
@ -46,4 +48,5 @@ type ProjectRepository interface {
|
|||||||
AddProjectGrantMember(ctx context.Context, member *model.ProjectGrantMember) (*model.ProjectGrantMember, error)
|
AddProjectGrantMember(ctx context.Context, member *model.ProjectGrantMember) (*model.ProjectGrantMember, error)
|
||||||
ChangeProjectGrantMember(ctx context.Context, member *model.ProjectGrantMember) (*model.ProjectGrantMember, error)
|
ChangeProjectGrantMember(ctx context.Context, member *model.ProjectGrantMember) (*model.ProjectGrantMember, error)
|
||||||
RemoveProjectGrantMember(ctx context.Context, projectID, grantID, userID string) error
|
RemoveProjectGrantMember(ctx context.Context, projectID, grantID, userID string) error
|
||||||
|
GetProjectGrantMemberRoles() []string
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ type Repository interface {
|
|||||||
ProjectRepository
|
ProjectRepository
|
||||||
PolicyRepository
|
PolicyRepository
|
||||||
OrgRepository
|
OrgRepository
|
||||||
OrgMemberRepository
|
|
||||||
UserRepository
|
UserRepository
|
||||||
UserGrantRepository
|
UserGrantRepository
|
||||||
}
|
}
|
||||||
|
59
internal/org/model/org_member_view.go
Normal file
59
internal/org/model/org_member_view.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrgMemberView struct {
|
||||||
|
UserID string
|
||||||
|
OrgID string
|
||||||
|
UserName string
|
||||||
|
Email string
|
||||||
|
FirstName string
|
||||||
|
LastName string
|
||||||
|
Roles []string
|
||||||
|
CreationDate time.Time
|
||||||
|
ChangeDate time.Time
|
||||||
|
Sequence uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgMemberSearchRequest struct {
|
||||||
|
Offset uint64
|
||||||
|
Limit uint64
|
||||||
|
SortingColumn OrgMemberSearchKey
|
||||||
|
Asc bool
|
||||||
|
Queries []*OrgMemberSearchQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgMemberSearchKey int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
ORGMEMBERSEARCHKEY_UNSPECIFIED OrgMemberSearchKey = iota
|
||||||
|
ORGMEMBERSEARCHKEY_USER_NAME
|
||||||
|
ORGMEMBERSEARCHKEY_EMAIL
|
||||||
|
ORGMEMBERSEARCHKEY_FIRST_NAME
|
||||||
|
ORGMEMBERSEARCHKEY_LAST_NAME
|
||||||
|
ORGMEMBERSEARCHKEY_ORG_ID
|
||||||
|
ORGMEMBERSEARCHKEY_USER_ID
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrgMemberSearchQuery struct {
|
||||||
|
Key OrgMemberSearchKey
|
||||||
|
Method model.SearchMethod
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgMemberSearchResponse struct {
|
||||||
|
Offset uint64
|
||||||
|
Limit uint64
|
||||||
|
TotalResult uint64
|
||||||
|
Result []*OrgMemberView
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *OrgMemberSearchRequest) EnsureLimit(limit uint64) {
|
||||||
|
if r.Limit == 0 || r.Limit > limit {
|
||||||
|
r.Limit = limit
|
||||||
|
}
|
||||||
|
}
|
73
internal/org/model/org_view.go
Normal file
73
internal/org/model/org_view.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
"github.com/caos/zitadel/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrgView struct {
|
||||||
|
ID string
|
||||||
|
CreationDate time.Time
|
||||||
|
ChangeDate time.Time
|
||||||
|
State OrgState
|
||||||
|
ResourceOwner string
|
||||||
|
Sequence uint64
|
||||||
|
|
||||||
|
Name string
|
||||||
|
Domain string
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgSearchRequest struct {
|
||||||
|
Offset uint64
|
||||||
|
Limit uint64
|
||||||
|
SortingColumn OrgSearchKey
|
||||||
|
Asc bool
|
||||||
|
Queries []*OrgSearchQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgSearchKey int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
ORGSEARCHKEY_UNSPECIFIED OrgSearchKey = iota
|
||||||
|
ORGSEARCHKEY_ORG_ID
|
||||||
|
ORGSEARCHKEY_ORG_NAME
|
||||||
|
ORGSEARCHKEY_ORG_DOMAIN
|
||||||
|
ORGSEARCHKEY_STATE
|
||||||
|
ORGSEARCHKEY_RESOURCEOWNER
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrgSearchQuery struct {
|
||||||
|
Key OrgSearchKey
|
||||||
|
Method model.SearchMethod
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgSearchResult struct {
|
||||||
|
Offset uint64
|
||||||
|
Limit uint64
|
||||||
|
TotalResult uint64
|
||||||
|
Result []*OrgView
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *OrgSearchRequest) EnsureLimit(limit uint64) {
|
||||||
|
if r.Limit == 0 || r.Limit > limit {
|
||||||
|
r.Limit = limit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func OrgViewToOrg(o *OrgView) *Org {
|
||||||
|
return &Org{
|
||||||
|
ObjectRoot: models.ObjectRoot{
|
||||||
|
AggregateID: o.ID,
|
||||||
|
ChangeDate: o.ChangeDate,
|
||||||
|
CreationDate: o.CreationDate,
|
||||||
|
ResourceOwner: o.ResourceOwner,
|
||||||
|
Sequence: o.Sequence,
|
||||||
|
},
|
||||||
|
Domain: o.Domain,
|
||||||
|
Name: o.Name,
|
||||||
|
State: o.State,
|
||||||
|
}
|
||||||
|
}
|
101
internal/org/repository/view/org.go
Normal file
101
internal/org/repository/view/org.go
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/logging"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
org_es_model "github.com/caos/zitadel/internal/org/model"
|
||||||
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
OrgKeyOrgDomain = "domain"
|
||||||
|
OrgKeyOrgID = "id"
|
||||||
|
OrgKeyOrgName = "name"
|
||||||
|
OrgKeyResourceOwner = "resource_owner"
|
||||||
|
OrgKeyState = "org_state"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrgView struct {
|
||||||
|
ID string `json:"-" gorm:"column:id;primary_key"`
|
||||||
|
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||||
|
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||||
|
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
|
||||||
|
State int32 `json:"-" gorm:"column:org_state"`
|
||||||
|
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||||
|
|
||||||
|
Name string `json:"name" gorm:"column:name"`
|
||||||
|
Domain string `json:"domain" gorm:"column:domain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func OrgFromModel(org *org_model.OrgView) *OrgView {
|
||||||
|
return &OrgView{
|
||||||
|
Domain: org.Domain,
|
||||||
|
ChangeDate: org.ChangeDate,
|
||||||
|
CreationDate: org.CreationDate,
|
||||||
|
ID: org.ID,
|
||||||
|
Name: org.Name,
|
||||||
|
ResourceOwner: org.ResourceOwner,
|
||||||
|
Sequence: org.Sequence,
|
||||||
|
State: int32(org.State),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func OrgToModel(org *OrgView) *org_model.OrgView {
|
||||||
|
return &org_model.OrgView{
|
||||||
|
Domain: org.Domain,
|
||||||
|
ChangeDate: org.ChangeDate,
|
||||||
|
CreationDate: org.CreationDate,
|
||||||
|
ID: org.ID,
|
||||||
|
Name: org.Name,
|
||||||
|
ResourceOwner: org.ResourceOwner,
|
||||||
|
Sequence: org.Sequence,
|
||||||
|
State: org_model.OrgState(org.State),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func OrgsToModel(orgs []*OrgView) []*org_model.OrgView {
|
||||||
|
modelOrgs := make([]*org_model.OrgView, len(orgs))
|
||||||
|
|
||||||
|
for i, org := range orgs {
|
||||||
|
modelOrgs[i] = OrgToModel(org)
|
||||||
|
}
|
||||||
|
|
||||||
|
return modelOrgs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrgView) AppendEvent(event *es_models.Event) (err error) {
|
||||||
|
switch event.Type {
|
||||||
|
case org_es_model.OrgAdded:
|
||||||
|
o.CreationDate = event.CreationDate
|
||||||
|
o.State = int32(org_model.ORGSTATE_ACTIVE)
|
||||||
|
o.setRootData(event)
|
||||||
|
err = o.SetData(event)
|
||||||
|
case org_es_model.OrgChanged:
|
||||||
|
o.setRootData(event)
|
||||||
|
err = o.SetData(event)
|
||||||
|
case org_es_model.OrgDeactivated:
|
||||||
|
o.State = int32(org_model.ORGSTATE_INACTIVE)
|
||||||
|
case org_es_model.OrgReactivated:
|
||||||
|
o.State = int32(org_model.ORGSTATE_ACTIVE)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrgView) setRootData(event *es_models.Event) {
|
||||||
|
o.ChangeDate = event.CreationDate
|
||||||
|
o.Sequence = event.Sequence
|
||||||
|
o.ID = event.AggregateID
|
||||||
|
o.ResourceOwner = event.ResourceOwner
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrgView) SetData(event *es_models.Event) error {
|
||||||
|
if err := json.Unmarshal(event.Data, o); err != nil {
|
||||||
|
logging.Log("VIEW-5W7Op").WithError(err).Error("could not unmarshal event data")
|
||||||
|
return errors.ThrowInternal(err, "VIEW-HZKME", "Could not unmarshal data")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
99
internal/org/repository/view/org_member.go
Normal file
99
internal/org/repository/view/org_member.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"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/org/model"
|
||||||
|
"github.com/lib/pq"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
OrgMemberKeyUserID = "user_id"
|
||||||
|
OrgMemberKeyOrgID = "org_id"
|
||||||
|
OrgMemberKeyUserName = "user_name"
|
||||||
|
OrgMemberKeyEmail = "email"
|
||||||
|
OrgMemberKeyFirstName = "first_name"
|
||||||
|
OrgMemberKeyLastName = "last_name"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrgMemberView struct {
|
||||||
|
UserID string `json:"userId" gorm:"column:user_id;primary_key"`
|
||||||
|
OrgID string `json:"-" gorm:"column:org_id;primary_key"`
|
||||||
|
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 OrgMemberViewFromModel(member *model.OrgMemberView) *OrgMemberView {
|
||||||
|
return &OrgMemberView{
|
||||||
|
UserID: member.UserID,
|
||||||
|
OrgID: member.OrgID,
|
||||||
|
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 OrgMemberToModel(member *OrgMemberView) *model.OrgMemberView {
|
||||||
|
return &model.OrgMemberView{
|
||||||
|
UserID: member.UserID,
|
||||||
|
OrgID: member.OrgID,
|
||||||
|
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 OrgMembersToModel(roles []*OrgMemberView) []*model.OrgMemberView {
|
||||||
|
result := make([]*model.OrgMemberView, len(roles))
|
||||||
|
for i, r := range roles {
|
||||||
|
result[i] = OrgMemberToModel(r)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *OrgMemberView) AppendEvent(event *models.Event) (err error) {
|
||||||
|
r.Sequence = event.Sequence
|
||||||
|
r.ChangeDate = event.CreationDate
|
||||||
|
switch event.Type {
|
||||||
|
case model.OrgMemberAdded:
|
||||||
|
r.setRootData(event)
|
||||||
|
r.CreationDate = event.CreationDate
|
||||||
|
err = r.SetData(event)
|
||||||
|
case model.OrgMemberChanged:
|
||||||
|
err = r.SetData(event)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *OrgMemberView) setRootData(event *models.Event) {
|
||||||
|
r.OrgID = event.AggregateID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *OrgMemberView) SetData(event *models.Event) error {
|
||||||
|
if err := json.Unmarshal(event.Data, r); err != nil {
|
||||||
|
logging.Log("EVEN-slo9s").WithError(err).Error("could not unmarshal event data")
|
||||||
|
return caos_errs.ThrowInternal(err, "MODEL-lub6s", "Could not unmarshal data")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
69
internal/org/repository/view/org_member_query.go
Normal file
69
internal/org/repository/view/org_member_query.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
global_model "github.com/caos/zitadel/internal/model"
|
||||||
|
proj_model "github.com/caos/zitadel/internal/org/model"
|
||||||
|
"github.com/caos/zitadel/internal/view"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrgMemberSearchRequest proj_model.OrgMemberSearchRequest
|
||||||
|
type OrgMemberSearchQuery proj_model.OrgMemberSearchQuery
|
||||||
|
type OrgMemberSearchKey proj_model.OrgMemberSearchKey
|
||||||
|
|
||||||
|
func (req OrgMemberSearchRequest) GetLimit() uint64 {
|
||||||
|
return req.Limit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgMemberSearchRequest) GetOffset() uint64 {
|
||||||
|
return req.Offset
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgMemberSearchRequest) GetSortingColumn() view.ColumnKey {
|
||||||
|
if req.SortingColumn == proj_model.ORGMEMBERSEARCHKEY_UNSPECIFIED {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return OrgMemberSearchKey(req.SortingColumn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgMemberSearchRequest) GetAsc() bool {
|
||||||
|
return req.Asc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgMemberSearchRequest) GetQueries() []view.SearchQuery {
|
||||||
|
result := make([]view.SearchQuery, len(req.Queries))
|
||||||
|
for i, q := range req.Queries {
|
||||||
|
result[i] = OrgMemberSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgMemberSearchQuery) GetKey() view.ColumnKey {
|
||||||
|
return OrgMemberSearchKey(req.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgMemberSearchQuery) GetMethod() global_model.SearchMethod {
|
||||||
|
return req.Method
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgMemberSearchQuery) GetValue() interface{} {
|
||||||
|
return req.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (key OrgMemberSearchKey) ToColumnName() string {
|
||||||
|
switch proj_model.OrgMemberSearchKey(key) {
|
||||||
|
case proj_model.ORGMEMBERSEARCHKEY_EMAIL:
|
||||||
|
return OrgMemberKeyEmail
|
||||||
|
case proj_model.ORGMEMBERSEARCHKEY_FIRST_NAME:
|
||||||
|
return OrgMemberKeyFirstName
|
||||||
|
case proj_model.ORGMEMBERSEARCHKEY_LAST_NAME:
|
||||||
|
return OrgMemberKeyLastName
|
||||||
|
case proj_model.ORGMEMBERSEARCHKEY_USER_NAME:
|
||||||
|
return OrgMemberKeyUserName
|
||||||
|
case proj_model.ORGMEMBERSEARCHKEY_USER_ID:
|
||||||
|
return OrgMemberKeyUserID
|
||||||
|
case proj_model.ORGMEMBERSEARCHKEY_ORG_ID:
|
||||||
|
return OrgMemberKeyOrgID
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
58
internal/org/repository/view/org_member_view.go
Normal file
58
internal/org/repository/view/org_member_view.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
global_model "github.com/caos/zitadel/internal/model"
|
||||||
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
|
"github.com/caos/zitadel/internal/view"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func OrgMemberByIDs(db *gorm.DB, table, orgID, userID string) (*OrgMemberView, error) {
|
||||||
|
member := new(OrgMemberView)
|
||||||
|
|
||||||
|
orgIDQuery := &OrgMemberSearchQuery{Key: org_model.ORGMEMBERSEARCHKEY_ORG_ID, Value: orgID, Method: global_model.SEARCHMETHOD_EQUALS}
|
||||||
|
userIDQuery := &OrgMemberSearchQuery{Key: org_model.ORGMEMBERSEARCHKEY_USER_ID, Value: userID, Method: global_model.SEARCHMETHOD_EQUALS}
|
||||||
|
query := view.PrepareGetByQuery(table, orgIDQuery, userIDQuery)
|
||||||
|
err := query(db, member)
|
||||||
|
return member, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SearchOrgMembers(db *gorm.DB, table string, req *org_model.OrgMemberSearchRequest) ([]*OrgMemberView, int, error) {
|
||||||
|
members := make([]*OrgMemberView, 0)
|
||||||
|
query := view.PrepareSearchQuery(table, OrgMemberSearchRequest{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 OrgMembersByUserID(db *gorm.DB, table string, userID string) ([]*OrgMemberView, error) {
|
||||||
|
members := make([]*OrgMemberView, 0)
|
||||||
|
queries := []*org_model.OrgMemberSearchQuery{
|
||||||
|
{
|
||||||
|
Key: org_model.ORGMEMBERSEARCHKEY_USER_ID,
|
||||||
|
Value: userID,
|
||||||
|
Method: global_model.SEARCHMETHOD_EQUALS,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
query := view.PrepareSearchQuery(table, OrgMemberSearchRequest{Queries: queries})
|
||||||
|
_, err := query(db, &members)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return members, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutOrgMember(db *gorm.DB, table string, role *OrgMemberView) error {
|
||||||
|
save := view.PrepareSave(table)
|
||||||
|
return save(db, role)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteOrgMember(db *gorm.DB, table, orgID, userID string) error {
|
||||||
|
member, err := OrgMemberByIDs(db, table, orgID, userID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
delete := view.PrepareDeleteByObject(table, member)
|
||||||
|
return delete(db)
|
||||||
|
}
|
67
internal/org/repository/view/org_query.go
Normal file
67
internal/org/repository/view/org_query.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
global_model "github.com/caos/zitadel/internal/model"
|
||||||
|
usr_model "github.com/caos/zitadel/internal/org/model"
|
||||||
|
"github.com/caos/zitadel/internal/view"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrgSearchRequest usr_model.OrgSearchRequest
|
||||||
|
type OrgSearchQuery usr_model.OrgSearchQuery
|
||||||
|
type OrgSearchKey usr_model.OrgSearchKey
|
||||||
|
|
||||||
|
func (req OrgSearchRequest) GetLimit() uint64 {
|
||||||
|
return req.Limit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgSearchRequest) GetOffset() uint64 {
|
||||||
|
return req.Offset
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgSearchRequest) GetSortingColumn() view.ColumnKey {
|
||||||
|
if req.SortingColumn == usr_model.ORGSEARCHKEY_UNSPECIFIED {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return OrgSearchKey(req.SortingColumn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgSearchRequest) GetAsc() bool {
|
||||||
|
return req.Asc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgSearchRequest) GetQueries() []view.SearchQuery {
|
||||||
|
result := make([]view.SearchQuery, len(req.Queries))
|
||||||
|
for i, q := range req.Queries {
|
||||||
|
result[i] = OrgSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgSearchQuery) GetKey() view.ColumnKey {
|
||||||
|
return OrgSearchKey(req.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgSearchQuery) GetMethod() global_model.SearchMethod {
|
||||||
|
return req.Method
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req OrgSearchQuery) GetValue() interface{} {
|
||||||
|
return req.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (key OrgSearchKey) ToColumnName() string {
|
||||||
|
switch usr_model.OrgSearchKey(key) {
|
||||||
|
case usr_model.ORGSEARCHKEY_ORG_DOMAIN:
|
||||||
|
return OrgKeyOrgDomain
|
||||||
|
case usr_model.ORGSEARCHKEY_ORG_ID:
|
||||||
|
return OrgKeyOrgID
|
||||||
|
case usr_model.ORGSEARCHKEY_ORG_NAME:
|
||||||
|
return OrgKeyOrgName
|
||||||
|
case usr_model.ORGSEARCHKEY_RESOURCEOWNER:
|
||||||
|
return OrgKeyResourceOwner
|
||||||
|
case usr_model.ORGSEARCHKEY_STATE:
|
||||||
|
return OrgKeyState
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
41
internal/org/repository/view/org_view.go
Normal file
41
internal/org/repository/view/org_view.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
|
"github.com/caos/zitadel/internal/view"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func OrgByID(db *gorm.DB, table, orgID string) (*OrgView, error) {
|
||||||
|
org := new(OrgView)
|
||||||
|
query := view.PrepareGetByKey(table, OrgSearchKey(org_model.ORGSEARCHKEY_ORG_ID), orgID)
|
||||||
|
err := query(db, org)
|
||||||
|
return org, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SearchOrgs(db *gorm.DB, table string, req *org_model.OrgSearchRequest) ([]*OrgView, int, error) {
|
||||||
|
orgs := make([]*OrgView, 0)
|
||||||
|
query := view.PrepareSearchQuery(table, OrgSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
||||||
|
count, err := query(db, &orgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return orgs, count, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGlobalOrgByDomain(db *gorm.DB, table, domain string) (*OrgView, error) {
|
||||||
|
org := new(OrgView)
|
||||||
|
query := view.PrepareGetByKey(table, OrgSearchKey(org_model.ORGSEARCHKEY_ORG_DOMAIN), domain)
|
||||||
|
err := query(db, org)
|
||||||
|
return org, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutOrg(db *gorm.DB, table string, org *OrgView) error {
|
||||||
|
save := view.PrepareSave(table)
|
||||||
|
return save(db, org)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteOrg(db *gorm.DB, table, orgID string) error {
|
||||||
|
delete := view.PrepareDeleteByKey(table, OrgSearchKey(org_model.ORGSEARCHKEY_ORG_ID), orgID)
|
||||||
|
return delete(db)
|
||||||
|
}
|
@ -55,15 +55,7 @@ func StartUser(conf UserConfig, systemDefaults sd.SystemDefaults) (*UserEventsto
|
|||||||
passwordVerificationCode := crypto.NewEncryptionGenerator(systemDefaults.SecretGenerators.PasswordVerificationCode, aesCrypto)
|
passwordVerificationCode := crypto.NewEncryptionGenerator(systemDefaults.SecretGenerators.PasswordVerificationCode, aesCrypto)
|
||||||
aesOtpCrypto, err := crypto.NewAESCrypto(systemDefaults.Multifactors.OTP.VerificationKey)
|
aesOtpCrypto, err := crypto.NewAESCrypto(systemDefaults.Multifactors.OTP.VerificationKey)
|
||||||
passwordAlg := crypto.NewBCrypt(systemDefaults.SecretGenerators.PasswordSaltCost)
|
passwordAlg := crypto.NewBCrypt(systemDefaults.SecretGenerators.PasswordSaltCost)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mfa := global_model.Multifactors{
|
|
||||||
OTP: global_model.OTP{
|
|
||||||
CryptoMFA: aesOtpCrypto,
|
|
||||||
Issuer: systemDefaults.Multifactors.OTP.Issuer,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return &UserEventstore{
|
return &UserEventstore{
|
||||||
Eventstore: conf.Eventstore,
|
Eventstore: conf.Eventstore,
|
||||||
userCache: userCache,
|
userCache: userCache,
|
||||||
@ -72,9 +64,14 @@ func StartUser(conf UserConfig, systemDefaults sd.SystemDefaults) (*UserEventsto
|
|||||||
EmailVerificationCode: emailVerificationCode,
|
EmailVerificationCode: emailVerificationCode,
|
||||||
PhoneVerificationCode: phoneVerificationCode,
|
PhoneVerificationCode: phoneVerificationCode,
|
||||||
PasswordVerificationCode: passwordVerificationCode,
|
PasswordVerificationCode: passwordVerificationCode,
|
||||||
Multifactors: mfa,
|
Multifactors: global_model.Multifactors{
|
||||||
PasswordAlg: passwordAlg,
|
OTP: global_model.OTP{
|
||||||
validateTOTP: totp.Validate,
|
CryptoMFA: aesOtpCrypto,
|
||||||
|
Issuer: systemDefaults.Multifactors.OTP.Issuer,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PasswordAlg: passwordAlg,
|
||||||
|
validateTOTP: totp.Validate,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,13 +2,14 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/eventstore/models"
|
"github.com/caos/zitadel/internal/eventstore/models"
|
||||||
"github.com/caos/zitadel/internal/usergrant/model"
|
"github.com/caos/zitadel/internal/usergrant/model"
|
||||||
es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
|
es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
|
||||||
"github.com/lib/pq"
|
"github.com/lib/pq"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
34
migrations/cockroach/V1.10__mgmt_orgs.sql
Normal file
34
migrations/cockroach/V1.10__mgmt_orgs.sql
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
CREATE TABLE management.orgs (
|
||||||
|
id TEXT,
|
||||||
|
creation_date TIMESTAMPTZ,
|
||||||
|
change_date TIMESTAMPTZ,
|
||||||
|
resource_owner TEXT,
|
||||||
|
org_state SMALLINT,
|
||||||
|
sequence BIGINT,
|
||||||
|
|
||||||
|
domain TEXT,
|
||||||
|
name TEXT,
|
||||||
|
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE management.org_members (
|
||||||
|
user_id TEXT,
|
||||||
|
org_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 (org_id, user_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMIT;
|
49
migrations/cockroach/V1.8__admin.sql
Normal file
49
migrations/cockroach/V1.8__admin.sql
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
CREATE DATABASE admin_api;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
CREATE TABLE admin_api.orgs (
|
||||||
|
id TEXT,
|
||||||
|
creation_date TIMESTAMPTZ,
|
||||||
|
change_date TIMESTAMPTZ,
|
||||||
|
resource_owner TEXT,
|
||||||
|
org_state SMALLINT,
|
||||||
|
sequence BIGINT,
|
||||||
|
|
||||||
|
domain TEXT,
|
||||||
|
name TEXT,
|
||||||
|
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE admin_api.failed_event (
|
||||||
|
view_name TEXT,
|
||||||
|
failed_sequence BIGINT,
|
||||||
|
failure_count SMALLINT,
|
||||||
|
err_msg TEXT,
|
||||||
|
|
||||||
|
PRIMARY KEY (view_name, failed_sequence)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE admin_api.locks (
|
||||||
|
locker_id TEXT,
|
||||||
|
locked_until TIMESTAMPTZ,
|
||||||
|
object_type TEXT,
|
||||||
|
|
||||||
|
PRIMARY KEY (object_type)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE admin_api.current_sequences (
|
||||||
|
view_name TEXT,
|
||||||
|
|
||||||
|
current_sequence BIGINT,
|
||||||
|
|
||||||
|
PRIMARY KEY (view_name)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
COMMIT;
|
6
migrations/cockroach/V1.9__admin_grant.sql
Normal file
6
migrations/cockroach/V1.9__admin_grant.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
GRANT SELECT, INSERT, UPDATE, DELETE ON DATABASE admin_api TO admin_api;
|
||||||
|
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE admin_api.* TO admin_api;
|
||||||
|
|
||||||
|
COMMIT;
|
@ -2,6 +2,10 @@ package grpc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/model"
|
||||||
|
|
||||||
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) GetOrgByID(ctx context.Context, orgID *OrgID) (_ *Org, err error) {
|
func (s *Server) GetOrgByID(ctx context.Context, orgID *OrgID) (_ *Org, err error) {
|
||||||
@ -13,14 +17,15 @@ func (s *Server) GetOrgByID(ctx context.Context, orgID *OrgID) (_ *Org, err erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SearchOrgs(ctx context.Context, request *OrgSearchRequest) (_ *OrgSearchResponse, err error) {
|
func (s *Server) SearchOrgs(ctx context.Context, request *OrgSearchRequest) (_ *OrgSearchResponse, err error) {
|
||||||
orgs, err := s.org.SearchOrgs(ctx)
|
result, err := s.org.SearchOrgs(ctx, orgSearchRequestToModel(request))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &OrgSearchResponse{Result: orgsFromModel(orgs),
|
return &OrgSearchResponse{
|
||||||
Limit: request.Limit,
|
Result: orgViewsFromModel(result.Result),
|
||||||
Offset: request.Offset,
|
Limit: request.Limit,
|
||||||
// TotalResult: , TODO: total result from search
|
Offset: request.Offset,
|
||||||
|
TotalResult: result.TotalResult,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,3 +42,57 @@ func (s *Server) SetUpOrg(ctx context.Context, orgSetUp *OrgSetUpRequest) (_ *Or
|
|||||||
}
|
}
|
||||||
return setUpOrgResponseFromModel(setUp), err
|
return setUpOrgResponseFromModel(setUp), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func orgSearchRequestToModel(req *OrgSearchRequest) *org_model.OrgSearchRequest {
|
||||||
|
return &org_model.OrgSearchRequest{
|
||||||
|
Limit: req.Limit,
|
||||||
|
Asc: req.Asc,
|
||||||
|
Offset: req.Offset,
|
||||||
|
Queries: orgQueriesToModel(req.Queries),
|
||||||
|
SortingColumn: orgQueryKeyToModel(req.SortingColumn),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func orgQueriesToModel(queries []*OrgSearchQuery) []*org_model.OrgSearchQuery {
|
||||||
|
modelQueries := make([]*org_model.OrgSearchQuery, len(queries))
|
||||||
|
|
||||||
|
for i, query := range queries {
|
||||||
|
modelQueries[i] = orgQueryToModel(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
return modelQueries
|
||||||
|
}
|
||||||
|
|
||||||
|
func orgQueryToModel(query *OrgSearchQuery) *org_model.OrgSearchQuery {
|
||||||
|
return &org_model.OrgSearchQuery{
|
||||||
|
Key: orgQueryKeyToModel(query.Key),
|
||||||
|
Value: query.Value,
|
||||||
|
Method: orgQueryMethodToModel(query.Method),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func orgQueryKeyToModel(key OrgSearchKey) org_model.OrgSearchKey {
|
||||||
|
switch key {
|
||||||
|
case OrgSearchKey_ORGSEARCHKEY_DOMAIN:
|
||||||
|
return org_model.ORGSEARCHKEY_ORG_DOMAIN
|
||||||
|
case OrgSearchKey_ORGSEARCHKEY_ORG_NAME:
|
||||||
|
return org_model.ORGSEARCHKEY_ORG_NAME
|
||||||
|
case OrgSearchKey_ORGSEARCHKEY_STATE:
|
||||||
|
return org_model.ORGSEARCHKEY_STATE
|
||||||
|
default:
|
||||||
|
return org_model.ORGSEARCHKEY_UNSPECIFIED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func orgQueryMethodToModel(method OrgSearchMethod) model.SearchMethod {
|
||||||
|
switch method {
|
||||||
|
case OrgSearchMethod_ORGSEARCHMETHOD_CONTAINS:
|
||||||
|
return model.SEARCHMETHOD_CONTAINS
|
||||||
|
case OrgSearchMethod_ORGSEARCHMETHOD_EQUALS:
|
||||||
|
return model.SEARCHMETHOD_EQUALS
|
||||||
|
case OrgSearchMethod_ORGSEARCHMETHOD_STARTS_WITH:
|
||||||
|
return model.SEARCHMETHOD_STARTS_WITH
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -65,10 +65,10 @@ func setUpOrgResponseFromModel(setUp *admin_model.SetupOrg) *OrgSetUpResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func orgsFromModel(orgs []*org_model.Org) []*Org {
|
func orgViewsFromModel(orgs []*org_model.OrgView) []*Org {
|
||||||
result := make([]*Org, len(orgs))
|
result := make([]*Org, len(orgs))
|
||||||
for i, org := range orgs {
|
for i, org := range orgs {
|
||||||
result[i] = orgFromModel(org)
|
result[i] = orgViewFromModel(org)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@ -91,6 +91,23 @@ func orgFromModel(org *org_model.Org) *Org {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func orgViewFromModel(org *org_model.OrgView) *Org {
|
||||||
|
creationDate, err := ptypes.TimestampProto(org.CreationDate)
|
||||||
|
logging.Log("GRPC-GTHsZ").OnError(err).Debug("unable to get timestamp from time")
|
||||||
|
|
||||||
|
changeDate, err := ptypes.TimestampProto(org.ChangeDate)
|
||||||
|
logging.Log("GRPC-dVnoj").OnError(err).Debug("unable to get timestamp from time")
|
||||||
|
|
||||||
|
return &Org{
|
||||||
|
Domain: org.Domain,
|
||||||
|
ChangeDate: changeDate,
|
||||||
|
CreationDate: creationDate,
|
||||||
|
Id: org.ID,
|
||||||
|
Name: org.Name,
|
||||||
|
State: orgStateFromModel(org.State),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func userFromModel(user *usr_model.User) *User {
|
func userFromModel(user *usr_model.User) *User {
|
||||||
creationDate, err := ptypes.TimestampProto(user.CreationDate)
|
creationDate, err := ptypes.TimestampProto(user.CreationDate)
|
||||||
logging.Log("GRPC-8duwe").OnError(err).Debug("unable to parse timestamp")
|
logging.Log("GRPC-8duwe").OnError(err).Debug("unable to parse timestamp")
|
||||||
|
@ -19,7 +19,7 @@ func (s *Server) GetOrgByDomainGlobal(ctx context.Context, in *OrgDomain) (*Org,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return orgFromModel(org), nil
|
return orgFromView(org), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) DeactivateOrg(ctx context.Context, in *OrgID) (*Org, error) {
|
func (s *Server) DeactivateOrg(ctx context.Context, in *OrgID) (*Org, error) {
|
||||||
|
@ -31,6 +31,23 @@ func orgFromModel(org *org_model.Org) *Org {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func orgFromView(org *org_model.OrgView) *Org {
|
||||||
|
creationDate, err := ptypes.TimestampProto(org.CreationDate)
|
||||||
|
logging.Log("GRPC-GTHsZ").OnError(err).Debug("unable to get timestamp from time")
|
||||||
|
|
||||||
|
changeDate, err := ptypes.TimestampProto(org.ChangeDate)
|
||||||
|
logging.Log("GRPC-dVnoj").OnError(err).Debug("unable to get timestamp from time")
|
||||||
|
|
||||||
|
return &Org{
|
||||||
|
Domain: org.Domain,
|
||||||
|
ChangeDate: changeDate,
|
||||||
|
CreationDate: creationDate,
|
||||||
|
Id: org.ID,
|
||||||
|
Name: org.Name,
|
||||||
|
State: orgStateFromModel(org.State),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func orgStateFromModel(state org_model.OrgState) OrgState {
|
func orgStateFromModel(state org_model.OrgState) OrgState {
|
||||||
switch state {
|
switch state {
|
||||||
case org_model.ORGSTATE_ACTIVE:
|
case org_model.ORGSTATE_ACTIVE:
|
||||||
|
@ -3,22 +3,25 @@ package grpc
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/errors"
|
|
||||||
"github.com/golang/protobuf/ptypes/empty"
|
"github.com/golang/protobuf/ptypes/empty"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) GetOrgMemberRoles(ctx context.Context, _ *empty.Empty) (*OrgMemberRoles, error) {
|
func (s *Server) GetOrgMemberRoles(ctx context.Context, _ *empty.Empty) (*OrgMemberRoles, error) {
|
||||||
return nil, errors.ThrowUnimplemented(nil, "GRPC-wz4vc", "Not implemented")
|
return &OrgMemberRoles{Roles: s.org.GetOrgMemberRoles()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SearchOrgMembers(ctx context.Context, in *OrgMemberSearchRequest) (*OrgMemberSearchResponse, error) {
|
func (s *Server) SearchOrgMembers(ctx context.Context, in *OrgMemberSearchRequest) (*OrgMemberSearchResponse, error) {
|
||||||
return nil, errors.ThrowUnimplemented(nil, "GRPC-wkdl3", "Not implemented")
|
members, err := s.org.SearchOrgMembers(ctx, orgMemberSearchRequestToModel(in))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return orgMemberSearchResponseFromModel(members), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) AddOrgMember(ctx context.Context, member *AddOrgMemberRequest) (*OrgMember, error) {
|
func (s *Server) AddOrgMember(ctx context.Context, member *AddOrgMemberRequest) (*OrgMember, error) {
|
||||||
repositoryMember := addOrgMemberToModel(member)
|
repositoryMember := addOrgMemberToModel(member)
|
||||||
|
|
||||||
addedMember, err := s.orgMember.AddOrgMember(ctx, repositoryMember)
|
addedMember, err := s.org.AddOrgMember(ctx, repositoryMember)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -28,7 +31,7 @@ func (s *Server) AddOrgMember(ctx context.Context, member *AddOrgMemberRequest)
|
|||||||
|
|
||||||
func (s *Server) ChangeOrgMember(ctx context.Context, member *ChangeOrgMemberRequest) (*OrgMember, error) {
|
func (s *Server) ChangeOrgMember(ctx context.Context, member *ChangeOrgMemberRequest) (*OrgMember, error) {
|
||||||
repositoryMember := changeOrgMemberToModel(member)
|
repositoryMember := changeOrgMemberToModel(member)
|
||||||
changedMember, err := s.orgMember.ChangeOrgMember(ctx, repositoryMember)
|
changedMember, err := s.org.ChangeOrgMember(ctx, repositoryMember)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -36,6 +39,6 @@ func (s *Server) ChangeOrgMember(ctx context.Context, member *ChangeOrgMemberReq
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) RemoveOrgMember(ctx context.Context, member *RemoveOrgMemberRequest) (*empty.Empty, error) {
|
func (s *Server) RemoveOrgMember(ctx context.Context, member *RemoveOrgMemberRequest) (*empty.Empty, error) {
|
||||||
err := s.orgMember.RemoveOrgMember(ctx, member.OrgId, member.UserId)
|
err := s.org.RemoveOrgMember(ctx, member.OrgId, member.UserId)
|
||||||
return &empty.Empty{}, err
|
return &empty.Empty{}, err
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package grpc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
"github.com/caos/zitadel/internal/model"
|
||||||
org_model "github.com/caos/zitadel/internal/org/model"
|
org_model "github.com/caos/zitadel/internal/org/model"
|
||||||
"github.com/golang/protobuf/ptypes"
|
"github.com/golang/protobuf/ptypes"
|
||||||
)
|
)
|
||||||
@ -35,3 +36,96 @@ func orgMemberFromModel(member *org_model.OrgMember) *OrgMember {
|
|||||||
Sequence: member.Sequence,
|
Sequence: member.Sequence,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func orgMemberSearchRequestToModel(request *OrgMemberSearchRequest) *org_model.OrgMemberSearchRequest {
|
||||||
|
return &org_model.OrgMemberSearchRequest{
|
||||||
|
Limit: request.Limit,
|
||||||
|
Offset: request.Offset,
|
||||||
|
Queries: orgMemberSearchQueriesToModel(request.Queries),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func orgMemberSearchQueriesToModel(queries []*OrgMemberSearchQuery) []*org_model.OrgMemberSearchQuery {
|
||||||
|
modelQueries := make([]*org_model.OrgMemberSearchQuery, len(queries))
|
||||||
|
|
||||||
|
for i, query := range queries {
|
||||||
|
modelQueries[i] = orgMemberSearchQueryToModel(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
return modelQueries
|
||||||
|
}
|
||||||
|
|
||||||
|
func orgMemberSearchQueryToModel(query *OrgMemberSearchQuery) *org_model.OrgMemberSearchQuery {
|
||||||
|
return &org_model.OrgMemberSearchQuery{
|
||||||
|
Key: orgMemberSearchKeyToModel(query.Key),
|
||||||
|
Method: orgMemberSearchMethodToModel(query.Method),
|
||||||
|
Value: query.Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func orgMemberSearchKeyToModel(key OrgMemberSearchKey) org_model.OrgMemberSearchKey {
|
||||||
|
switch key {
|
||||||
|
case OrgMemberSearchKey_ORGMEMBERSEARCHKEY_EMAIL:
|
||||||
|
return org_model.ORGMEMBERSEARCHKEY_EMAIL
|
||||||
|
case OrgMemberSearchKey_ORGMEMBERSEARCHKEY_FIRST_NAME:
|
||||||
|
return org_model.ORGMEMBERSEARCHKEY_FIRST_NAME
|
||||||
|
case OrgMemberSearchKey_ORGMEMBERSEARCHKEY_LAST_NAME:
|
||||||
|
return org_model.ORGMEMBERSEARCHKEY_LAST_NAME
|
||||||
|
case OrgMemberSearchKey_ORGMEMBERSEARCHKEY_USER_ID:
|
||||||
|
return org_model.ORGMEMBERSEARCHKEY_USER_ID
|
||||||
|
default:
|
||||||
|
return org_model.ORGMEMBERSEARCHKEY_UNSPECIFIED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func orgMemberSearchMethodToModel(key SearchMethod) model.SearchMethod {
|
||||||
|
switch key {
|
||||||
|
case SearchMethod_SEARCHMETHOD_CONTAINS:
|
||||||
|
return model.SEARCHMETHOD_CONTAINS
|
||||||
|
case SearchMethod_SEARCHMETHOD_CONTAINS_IGNORE_CASE:
|
||||||
|
return model.SEARCHMETHOD_CONTAINS_IGNORE_CASE
|
||||||
|
case SearchMethod_SEARCHMETHOD_EQUALS:
|
||||||
|
return model.SEARCHMETHOD_EQUALS
|
||||||
|
case SearchMethod_SEARCHMETHOD_EQUALS_IGNORE_CASE:
|
||||||
|
return model.SEARCHMETHOD_EQUALS_IGNORE_CASE
|
||||||
|
case SearchMethod_SEARCHMETHOD_STARTS_WITH:
|
||||||
|
return model.SEARCHMETHOD_STARTS_WITH
|
||||||
|
case SearchMethod_SEARCHMETHOD_STARTS_WITH_IGNORE_CASE:
|
||||||
|
return model.SEARCHMETHOD_STARTS_WITH_IGNORE_CASE
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func orgMemberSearchResponseFromModel(resp *org_model.OrgMemberSearchResponse) *OrgMemberSearchResponse {
|
||||||
|
return &OrgMemberSearchResponse{
|
||||||
|
Limit: resp.Limit,
|
||||||
|
Offset: resp.Offset,
|
||||||
|
TotalResult: resp.TotalResult,
|
||||||
|
Result: orgMembersFromView(resp.Result),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func orgMembersFromView(viewMembers []*org_model.OrgMemberView) []*OrgMember {
|
||||||
|
members := make([]*OrgMember, len(viewMembers))
|
||||||
|
|
||||||
|
for i, member := range viewMembers {
|
||||||
|
members[i] = orgMemberFromView(member)
|
||||||
|
}
|
||||||
|
|
||||||
|
return members
|
||||||
|
}
|
||||||
|
|
||||||
|
func orgMemberFromView(member *org_model.OrgMemberView) *OrgMember {
|
||||||
|
changeDate, err := ptypes.TimestampProto(member.ChangeDate)
|
||||||
|
logging.Log("GRPC-S9LAZ").OnError(err).Debug("unable to parse changedate")
|
||||||
|
creationDate, err := ptypes.TimestampProto(member.CreationDate)
|
||||||
|
logging.Log("GRPC-oJN56").OnError(err).Debug("unable to parse creation date")
|
||||||
|
|
||||||
|
return &OrgMember{
|
||||||
|
ChangeDate: changeDate,
|
||||||
|
CreationDate: creationDate,
|
||||||
|
Roles: member.Roles,
|
||||||
|
Sequence: member.Sequence,
|
||||||
|
UserId: member.UserID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,16 +2,12 @@ package grpc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/api"
|
"github.com/caos/zitadel/internal/api"
|
||||||
grpc_util "github.com/caos/zitadel/internal/api/grpc"
|
grpc_util "github.com/caos/zitadel/internal/api/grpc"
|
||||||
"github.com/caos/zitadel/internal/errors"
|
|
||||||
"github.com/golang/protobuf/ptypes/empty"
|
"github.com/golang/protobuf/ptypes/empty"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) GetProjectGrantMemberRoles(ctx context.Context, _ *empty.Empty) (*ProjectGrantMemberRoles, error) {
|
|
||||||
return nil, errors.ThrowUnimplemented(nil, "GRPC-mGo89", "Not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) SearchProjectGrants(ctx context.Context, in *ProjectGrantSearchRequest) (*ProjectGrantSearchResponse, error) {
|
func (s *Server) SearchProjectGrants(ctx context.Context, in *ProjectGrantSearchRequest) (*ProjectGrantSearchResponse, error) {
|
||||||
request := projectGrantSearchRequestsToModel(in)
|
request := projectGrantSearchRequestsToModel(in)
|
||||||
orgID := grpc_util.GetHeader(ctx, api.ZitadelOrgID)
|
orgID := grpc_util.GetHeader(ctx, api.ZitadelOrgID)
|
||||||
|
@ -2,9 +2,14 @@ package grpc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/golang/protobuf/ptypes/empty"
|
"github.com/golang/protobuf/ptypes/empty"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (s *Server) GetProjectGrantMemberRoles(ctx context.Context, _ *empty.Empty) (*ProjectGrantMemberRoles, error) {
|
||||||
|
return &ProjectGrantMemberRoles{Roles: s.project.GetProjectGrantMemberRoles()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) SearchProjectGrantMembers(ctx context.Context, in *ProjectGrantMemberSearchRequest) (*ProjectGrantMemberSearchResponse, error) {
|
func (s *Server) SearchProjectGrantMembers(ctx context.Context, in *ProjectGrantMemberSearchRequest) (*ProjectGrantMemberSearchResponse, error) {
|
||||||
response, err := s.project.SearchProjectGrantMembers(ctx, projectGrantMemberSearchRequestsToModel(in))
|
response, err := s.project.SearchProjectGrantMembers(ctx, projectGrantMemberSearchRequestsToModel(in))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2,12 +2,12 @@ package grpc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/caos/zitadel/internal/errors"
|
|
||||||
"github.com/golang/protobuf/ptypes/empty"
|
"github.com/golang/protobuf/ptypes/empty"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) GetProjectMemberRoles(ctx context.Context, _ *empty.Empty) (*ProjectMemberRoles, error) {
|
func (s *Server) GetProjectMemberRoles(ctx context.Context, _ *empty.Empty) (*ProjectMemberRoles, error) {
|
||||||
return nil, errors.ThrowUnimplemented(nil, "GRPC-qw34d", "Not implemented")
|
return &ProjectMemberRoles{Roles: s.project.GetProjectMemberRoles()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SearchProjectMembers(ctx context.Context, in *ProjectMemberSearchRequest) (*ProjectMemberSearchResponse, error) {
|
func (s *Server) SearchProjectMembers(ctx context.Context, in *ProjectMemberSearchRequest) (*ProjectMemberSearchResponse, error) {
|
||||||
|
@ -17,7 +17,6 @@ type Server struct {
|
|||||||
project repository.ProjectRepository
|
project repository.ProjectRepository
|
||||||
policy repository.PolicyRepository
|
policy repository.PolicyRepository
|
||||||
org repository.OrgRepository
|
org repository.OrgRepository
|
||||||
orgMember repository.OrgMemberRepository
|
|
||||||
user repository.UserRepository
|
user repository.UserRepository
|
||||||
usergrant repository.UserGrantRepository
|
usergrant repository.UserGrantRepository
|
||||||
verifier *mgmt_auth.TokenVerifier
|
verifier *mgmt_auth.TokenVerifier
|
||||||
@ -30,7 +29,6 @@ func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository
|
|||||||
project: repo,
|
project: repo,
|
||||||
policy: repo,
|
policy: repo,
|
||||||
org: repo,
|
org: repo,
|
||||||
orgMember: repo,
|
|
||||||
user: repo,
|
user: repo,
|
||||||
usergrant: repo,
|
usergrant: repo,
|
||||||
authZ: authZ,
|
authZ: authZ,
|
||||||
|
@ -16,7 +16,11 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) {
|
func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) {
|
||||||
repo, err := eventsourcing.Start(config.Repository, systemDefaults)
|
roles := make([]string, len(authZ.RolePermissionMappings))
|
||||||
|
for i, role := range authZ.RolePermissionMappings {
|
||||||
|
roles[i] = role.Role
|
||||||
|
}
|
||||||
|
repo, err := eventsourcing.Start(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, authZ, repo)
|
api.Start(ctx, config.API, authZ, repo)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user