mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 01:37:31 +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:
@@ -4,11 +4,12 @@ import (
|
||||
"context"
|
||||
|
||||
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/sdk"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
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"
|
||||
)
|
||||
|
||||
@@ -16,6 +17,10 @@ type OrgRepo struct {
|
||||
Eventstore eventstore.Eventstore
|
||||
OrgEventstore *org_es.OrgEventstore
|
||||
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) {
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
func (repo *OrgRepo) SearchOrgs(ctx context.Context) ([]*org_model.Org, error) {
|
||||
return nil, errors.ThrowUnimplemented(nil, "EVENT-hFIHK", "search not implemented")
|
||||
func (repo *OrgRepo) SearchOrgs(ctx context.Context, query *org_model.OrgSearchRequest) (*org_model.OrgSearchResult, error) {
|
||||
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) {
|
||||
|
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/zitadel/internal/admin/repository/eventsourcing/eventstore"
|
||||
"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"
|
||||
"github.com/caos/zitadel/internal/config/types"
|
||||
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_org "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||
es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||
@@ -15,13 +19,14 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Eventstore es_int.Config
|
||||
//View view.ViewConfig
|
||||
//Spooler spooler.SpoolerConfig
|
||||
SearchLimit uint64
|
||||
Eventstore es_int.Config
|
||||
View types.SQL
|
||||
Spooler spooler.SpoolerConfig
|
||||
}
|
||||
|
||||
type EsRepository struct {
|
||||
//spooler *es_spooler.Spooler
|
||||
spooler *es_spol.Spooler
|
||||
eventstore.OrgRepo
|
||||
}
|
||||
|
||||
@@ -31,15 +36,6 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults) (
|
||||
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{
|
||||
Eventstore: es,
|
||||
Cache: conf.Eventstore.Cache,
|
||||
@@ -66,15 +62,29 @@ func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults) (
|
||||
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}
|
||||
err = setup.StartSetup(systemDefaults, eventstoreRepos).Execute(ctx)
|
||||
logging.Log("SERVE-k280HZ").OnError(err).Panic("failed to execute setup")
|
||||
|
||||
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient)
|
||||
|
||||
return &EsRepository{
|
||||
spooler: spool,
|
||||
OrgRepo: eventstore.OrgRepo{
|
||||
Eventstore: es,
|
||||
OrgEventstore: org,
|
||||
UserEventstore: user,
|
||||
View: view,
|
||||
SearchLimit: conf.SearchLimit,
|
||||
},
|
||||
}, 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)
|
||||
IsOrgUnique(ctx context.Context, name, domain string) (bool, 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 (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"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_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
|
||||
"github.com/caos/zitadel/internal/org/repository/view"
|
||||
)
|
||||
|
||||
type OrgRepository struct {
|
||||
SearchLimit uint64
|
||||
*org_es.OrgEventstore
|
||||
View *mgmt_view.View
|
||||
Roles []string
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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) OrgByDomainGlobal(ctx context.Context, domain string) (*org_model.OrgView, error) {
|
||||
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) {
|
||||
@@ -50,3 +60,27 @@ func (repo *OrgRepository) RemoveOrgMember(ctx context.Context, orgID, userID st
|
||||
member := org_model.NewOrgMember(orgID, userID)
|
||||
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 (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/caos/zitadel/internal/management/repository/eventsourcing/view"
|
||||
"github.com/caos/zitadel/internal/project/repository/view/model"
|
||||
|
||||
@@ -13,6 +15,7 @@ type ProjectRepo struct {
|
||||
SearchLimit uint64
|
||||
ProjectEvents *proj_event.ProjectEventstore
|
||||
View *view.View
|
||||
Roles []string
|
||||
}
|
||||
|
||||
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),
|
||||
}, 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/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
"github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
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"
|
||||
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
||||
@@ -20,6 +21,7 @@ type GrantedProject struct {
|
||||
handler
|
||||
eventstore eventstore.Eventstore
|
||||
projectEvents *proj_event.ProjectEventstore
|
||||
orgEvents *org_event.OrgEventstore
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -37,7 +39,7 @@ func (p *GrantedProject) EventQuery() (*models.SearchQuery, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eventsourcing.ProjectQuery(sequence), nil
|
||||
return proj_event.ProjectQuery(sequence), nil
|
||||
}
|
||||
|
||||
func (p *GrantedProject) Process(event *models.Event) (err error) {
|
||||
@@ -71,7 +73,12 @@ func (p *GrantedProject) Process(event *models.Event) (err error) {
|
||||
return err
|
||||
}
|
||||
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:
|
||||
grant := new(view_model.ProjectGrant)
|
||||
err := grant.SetData(event)
|
||||
@@ -99,11 +106,12 @@ func (p *GrantedProject) Process(event *models.Event) (err error) {
|
||||
return p.view.PutGrantedProject(grantedProject)
|
||||
}
|
||||
|
||||
func (p *GrantedProject) getOrg(orgID string) {
|
||||
//TODO: Get Org
|
||||
func (p *GrantedProject) fillOrgData(grantedProject *view_model.GrantedProjectView, org *org_model.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)
|
||||
}
|
||||
|
||||
|
@@ -1,13 +1,15 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/config/types"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/spooler"
|
||||
"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"
|
||||
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Configs map[string]*Config
|
||||
@@ -26,17 +28,20 @@ type handler struct {
|
||||
type EventstoreRepos struct {
|
||||
ProjectEvents *proj_event.ProjectEventstore
|
||||
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 {
|
||||
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},
|
||||
&ProjectMember{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectMember"), 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}},
|
||||
&User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount}},
|
||||
&UserGrant{handler: handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount}, projectEvents: repos.ProjectEvents, userEvents: repos.UserEvents},
|
||||
&Application{handler: handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount}, projectEvents: repos.ProjectEvents},
|
||||
&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, 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 (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
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_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
|
||||
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_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
grant_es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
@@ -25,6 +28,7 @@ type UserGrant struct {
|
||||
eventstore eventstore.Eventstore
|
||||
projectEvents *proj_event.ProjectEventstore
|
||||
userEvents *usr_events.UserEventstore
|
||||
orgEvents *org_events.OrgEventstore
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -67,7 +71,7 @@ func (u *UserGrant) processUserGrant(event *models.Event) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = u.fillData(grant)
|
||||
err = u.fillData(grant, event.ResourceOwner)
|
||||
case grant_es_model.UserGrantChanged,
|
||||
grant_es_model.UserGrantDeactivated,
|
||||
grant_es_model.UserGrantReactivated:
|
||||
@@ -133,7 +137,7 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -144,7 +148,12 @@ func (u *UserGrant) fillData(grant *view_model.UserGrantView) (err error) {
|
||||
return err
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -159,8 +168,9 @@ func (u *UserGrant) fillProjectData(grant *view_model.UserGrantView, project *pr
|
||||
grant.ProjectName = project.Name
|
||||
}
|
||||
|
||||
func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView) {
|
||||
//TODO: get ORG
|
||||
func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView, org *org_model.Org) {
|
||||
grant.OrgDomain = org.Domain
|
||||
grant.OrgName = org.Name
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
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})
|
||||
|
||||
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)
|
||||
|
||||
return &EsRepository{
|
||||
spooler: spool,
|
||||
OrgRepository: eventstore.OrgRepository{org},
|
||||
ProjectRepo: eventstore.ProjectRepo{conf.SearchLimit, project, view},
|
||||
OrgRepository: eventstore.OrgRepository{conf.SearchLimit, org, view, roles},
|
||||
ProjectRepo: eventstore.ProjectRepo{conf.SearchLimit, project, view, roles},
|
||||
UserRepo: eventstore.UserRepo{conf.SearchLimit, user, view},
|
||||
UserGrantRepo: eventstore.UserGrantRepo{conf.SearchLimit, usergrant, view},
|
||||
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 {
|
||||
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)
|
||||
DeactivateOrg(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)
|
||||
ChangeOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error)
|
||||
RemoveOrgMember(ctx context.Context, orgID, userID string) error
|
||||
|
||||
GetOrgMemberRoles() []string
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
)
|
||||
|
||||
@@ -18,6 +19,7 @@ type ProjectRepository interface {
|
||||
ChangeProjectMember(ctx context.Context, member *model.ProjectMember) (*model.ProjectMember, error)
|
||||
RemoveProjectMember(ctx context.Context, projectID, userID string) error
|
||||
SearchProjectMembers(ctx context.Context, request *model.ProjectMemberSearchRequest) (*model.ProjectMemberSearchResponse, error)
|
||||
GetProjectMemberRoles() []string
|
||||
|
||||
AddProjectRole(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)
|
||||
ChangeProjectGrantMember(ctx context.Context, member *model.ProjectGrantMember) (*model.ProjectGrantMember, error)
|
||||
RemoveProjectGrantMember(ctx context.Context, projectID, grantID, userID string) error
|
||||
GetProjectGrantMemberRoles() []string
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ type Repository interface {
|
||||
ProjectRepository
|
||||
PolicyRepository
|
||||
OrgRepository
|
||||
OrgMemberRepository
|
||||
UserRepository
|
||||
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)
|
||||
aesOtpCrypto, err := crypto.NewAESCrypto(systemDefaults.Multifactors.OTP.VerificationKey)
|
||||
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{
|
||||
Eventstore: conf.Eventstore,
|
||||
userCache: userCache,
|
||||
@@ -72,9 +64,14 @@ func StartUser(conf UserConfig, systemDefaults sd.SystemDefaults) (*UserEventsto
|
||||
EmailVerificationCode: emailVerificationCode,
|
||||
PhoneVerificationCode: phoneVerificationCode,
|
||||
PasswordVerificationCode: passwordVerificationCode,
|
||||
Multifactors: mfa,
|
||||
PasswordAlg: passwordAlg,
|
||||
validateTOTP: totp.Validate,
|
||||
Multifactors: global_model.Multifactors{
|
||||
OTP: global_model.OTP{
|
||||
CryptoMFA: aesOtpCrypto,
|
||||
Issuer: systemDefaults.Multifactors.OTP.Issuer,
|
||||
},
|
||||
},
|
||||
PasswordAlg: passwordAlg,
|
||||
validateTOTP: totp.Validate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@@ -2,13 +2,14 @@ package model
|
||||
|
||||
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/usergrant/model"
|
||||
es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
|
||||
"github.com/lib/pq"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
|
Reference in New Issue
Block a user