mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:47:22 +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:
|
||||
- x-zitadel-
|
||||
Repository:
|
||||
SearchLimit: 100
|
||||
Eventstore:
|
||||
ServiceName: 'Admin'
|
||||
Repository:
|
||||
@ -106,6 +107,16 @@ Admin:
|
||||
Type: 'fastcache'
|
||||
Config:
|
||||
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:
|
||||
Port: 50050
|
||||
|
@ -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 {
|
||||
SearchLimit uint64
|
||||
Eventstore es_int.Config
|
||||
//View view.ViewConfig
|
||||
//Spooler spooler.SpoolerConfig
|
||||
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,7 +64,12 @@ func StartUser(conf UserConfig, systemDefaults sd.SystemDefaults) (*UserEventsto
|
||||
EmailVerificationCode: emailVerificationCode,
|
||||
PhoneVerificationCode: phoneVerificationCode,
|
||||
PasswordVerificationCode: passwordVerificationCode,
|
||||
Multifactors: mfa,
|
||||
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 (
|
||||
|
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 (
|
||||
"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) {
|
||||
@ -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) {
|
||||
orgs, err := s.org.SearchOrgs(ctx)
|
||||
result, err := s.org.SearchOrgs(ctx, orgSearchRequestToModel(request))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &OrgSearchResponse{Result: orgsFromModel(orgs),
|
||||
return &OrgSearchResponse{
|
||||
Result: orgViewsFromModel(result.Result),
|
||||
Limit: request.Limit,
|
||||
Offset: request.Offset,
|
||||
// TotalResult: , TODO: total result from search
|
||||
TotalResult: result.TotalResult,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -37,3 +42,57 @@ func (s *Server) SetUpOrg(ctx context.Context, orgSetUp *OrgSetUpRequest) (_ *Or
|
||||
}
|
||||
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))
|
||||
for i, org := range orgs {
|
||||
result[i] = orgFromModel(org)
|
||||
result[i] = orgViewFromModel(org)
|
||||
}
|
||||
|
||||
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 {
|
||||
creationDate, err := ptypes.TimestampProto(user.CreationDate)
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
return orgFromModel(org), nil
|
||||
return orgFromView(org), nil
|
||||
}
|
||||
|
||||
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 {
|
||||
switch state {
|
||||
case org_model.ORGSTATE_ACTIVE:
|
||||
|
@ -3,22 +3,25 @@ package grpc
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
)
|
||||
|
||||
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) {
|
||||
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) {
|
||||
repositoryMember := addOrgMemberToModel(member)
|
||||
|
||||
addedMember, err := s.orgMember.AddOrgMember(ctx, repositoryMember)
|
||||
addedMember, err := s.org.AddOrgMember(ctx, repositoryMember)
|
||||
if err != nil {
|
||||
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) {
|
||||
repositoryMember := changeOrgMemberToModel(member)
|
||||
changedMember, err := s.orgMember.ChangeOrgMember(ctx, repositoryMember)
|
||||
changedMember, err := s.org.ChangeOrgMember(ctx, repositoryMember)
|
||||
if err != nil {
|
||||
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) {
|
||||
err := s.orgMember.RemoveOrgMember(ctx, member.OrgId, member.UserId)
|
||||
err := s.org.RemoveOrgMember(ctx, member.OrgId, member.UserId)
|
||||
return &empty.Empty{}, err
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package grpc
|
||||
|
||||
import (
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/model"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
)
|
||||
@ -35,3 +36,96 @@ func orgMemberFromModel(member *org_model.OrgMember) *OrgMember {
|
||||
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 (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/api"
|
||||
grpc_util "github.com/caos/zitadel/internal/api/grpc"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"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) {
|
||||
request := projectGrantSearchRequestsToModel(in)
|
||||
orgID := grpc_util.GetHeader(ctx, api.ZitadelOrgID)
|
||||
|
@ -2,9 +2,14 @@ package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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) {
|
||||
response, err := s.project.SearchProjectGrantMembers(ctx, projectGrantMemberSearchRequestsToModel(in))
|
||||
if err != nil {
|
||||
|
@ -2,12 +2,12 @@ package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
)
|
||||
|
||||
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) {
|
||||
|
@ -17,7 +17,6 @@ type Server struct {
|
||||
project repository.ProjectRepository
|
||||
policy repository.PolicyRepository
|
||||
org repository.OrgRepository
|
||||
orgMember repository.OrgMemberRepository
|
||||
user repository.UserRepository
|
||||
usergrant repository.UserGrantRepository
|
||||
verifier *mgmt_auth.TokenVerifier
|
||||
@ -30,7 +29,6 @@ func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository
|
||||
project: repo,
|
||||
policy: repo,
|
||||
org: repo,
|
||||
orgMember: repo,
|
||||
user: repo,
|
||||
usergrant: repo,
|
||||
authZ: authZ,
|
||||
|
@ -16,7 +16,11 @@ type Config struct {
|
||||
}
|
||||
|
||||
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")
|
||||
|
||||
api.Start(ctx, config.API, authZ, repo)
|
||||
|
Loading…
x
Reference in New Issue
Block a user