mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 04:07:31 +00:00
feat: project grant commands (#68)
* feat: eventstore repository * fix: remove gorm * version * feat: pkg * feat: add some files for project * feat: eventstore without eventstore-lib * rename files * gnueg * fix: key json * fix: add object * fix: change imports * fix: internal models * fix: some imports * fix: global model * feat: add global view functions * fix: add some functions on repo * feat(eventstore): sdk * fix(eventstore): search query * fix(eventstore): rename app to eventstore * delete empty test * remove unused func * merge master * fix(eventstore): tests * fix(models): delete unused struct * fix: some funcitons * feat(eventstore): implemented push events * fix: move project eventstore to project package * fix: change project eventstore funcs * feat(eventstore): overwrite context data * fix: change project eventstore * fix: add project repo to mgmt server * feat(types): SQL-config * fix: commented code * feat(eventstore): options to overwrite editor * feat: auth interceptor and cockroach migrations * fix: migrations * fix: fix filter * fix: not found on getbyid * fix: use global sql config * fix: add sequence * fix: add some tests * fix(eventstore): nullable sequence * fix: add some tests * merge * fix: add some tests * fix(migrations): correct statements for sequence * fix: add some tests * fix: add some tests * fix: changes from mr * fix: changes from mr * fix: add some tests * Update internal/eventstore/models/field.go Co-Authored-By: livio-a <livio.a@gmail.com> * fix(eventstore): code quality * fix: add types to aggregate/Event-types * fix: try tests * fix(eventstore): rename modifier* to editor* * fix(eventstore): delete editor_org * fix(migrations): remove editor_org field, rename modifier_* to editor_* * fix: query tests * fix: use prepare funcs * fix: go mod * fix: generate files * fix(eventstore): tests * fix(eventstore): rename modifier to editor * fix(migrations): add cluster migration, fix(migrations): fix typo of host in clean clsuter * fix(eventstore): move health * fix(eventstore): AggregateTypeFilter aggregateType as param * code quality * fix: go tests * feat: add member funcs * feat: add member model * feat: add member events * feat: add member repo model * fix: better error func testing * fix: project member funcs * fix: add tests * fix: add tests * feat: implement member requests * fix: merge master * fix: merge master * fix: read existing in project repo * fix: fix tests * feat: add internal cache * feat: add cache mock * fix: return values of cache mock * feat: add project role * fix: add cache config * fix: add role to eventstore * fix: use eventstore sdk * fix: use eventstore sdk * fix: add project role grpc requests * fix: fix getby id * fix: changes for mr * fix: change value to interface * feat: add app event creations * fix: searchmethods * Update internal/project/model/project_member.go Co-Authored-By: Silvan <silvan.reusser@gmail.com> * fix: use get project func * fix: append events * fix: check if value is string on equal ignore case * fix: add changes test * fix: add go mod * fix: add some tests * fix: return err not nil * fix: return err not nil * fix: add aggregate funcs and tests * fix: add oidc aggregate funcs and tests * fix: add oidc * fix: add some tests * fix: tests * fix: oidc validation * fix: generate client secret * fix: generate client id * fix: test change app * fix: deactivate/reactivate application * fix: change oidc config * fix: change oidc config secret * fix: implement grpc app funcs * fix: add application requests * fix: converter * fix: converter * fix: converter and generate clientid * fix: tests * feat: project grant aggregate * feat: project grant * fix: project grant check if role existing * fix: project grant requests * fix: project grant fixes * fix: project grant member model * fix: project grant member aggregate * fix: project grant member eventstore * fix: project grant member requests * fix: problems after merger * fix: new commit * fix: remove enum converter * Update internal/project/model/project_grant.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/project/model/project_grant.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/project/model/project.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * fix: better sub object handling * fix: imports Co-authored-by: adlerhurst <silvan.reusser@gmail.com> Co-authored-by: livio-a <livio.a@gmail.com>
This commit is contained in:
154
internal/project/repository/eventsourcing/model/application.go
Normal file
154
internal/project/repository/eventsourcing/model/application.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/caos/logging"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
)
|
||||
|
||||
type Application struct {
|
||||
es_models.ObjectRoot
|
||||
AppID string `json:"appId"`
|
||||
State int32 `json:"-"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Type int32 `json:"appType,omitempty"`
|
||||
OIDCConfig *OIDCConfig `json:"-"`
|
||||
}
|
||||
|
||||
type ApplicationID struct {
|
||||
es_models.ObjectRoot
|
||||
AppID string `json:"appId"`
|
||||
}
|
||||
|
||||
func GetApplication(apps []*Application, id string) (int, *Application) {
|
||||
for i, a := range apps {
|
||||
if a.AppID == id {
|
||||
return i, a
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func (a *Application) Changes(changed *Application) map[string]interface{} {
|
||||
changes := make(map[string]interface{}, 1)
|
||||
changes["appId"] = a.AppID
|
||||
if changed.Name != "" && a.Name != changed.Name {
|
||||
changes["name"] = changed.Name
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
func AppsToModel(apps []*Application) []*model.Application {
|
||||
convertedApps := make([]*model.Application, len(apps))
|
||||
for i, a := range apps {
|
||||
convertedApps[i] = AppToModel(a)
|
||||
}
|
||||
return convertedApps
|
||||
}
|
||||
|
||||
func AppsFromModel(apps []*model.Application) []*Application {
|
||||
convertedApps := make([]*Application, len(apps))
|
||||
for i, a := range apps {
|
||||
convertedApps[i] = AppFromModel(a)
|
||||
}
|
||||
return convertedApps
|
||||
}
|
||||
|
||||
func AppFromModel(app *model.Application) *Application {
|
||||
converted := &Application{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: app.ObjectRoot.AggregateID,
|
||||
Sequence: app.Sequence,
|
||||
ChangeDate: app.ChangeDate,
|
||||
CreationDate: app.CreationDate,
|
||||
},
|
||||
AppID: app.AppID,
|
||||
Name: app.Name,
|
||||
State: int32(app.State),
|
||||
Type: int32(app.Type),
|
||||
}
|
||||
if app.OIDCConfig != nil {
|
||||
converted.OIDCConfig = OIDCConfigFromModel(app.OIDCConfig)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func AppToModel(app *Application) *model.Application {
|
||||
converted := &model.Application{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: app.AggregateID,
|
||||
ChangeDate: app.ChangeDate,
|
||||
CreationDate: app.CreationDate,
|
||||
Sequence: app.Sequence,
|
||||
},
|
||||
AppID: app.AppID,
|
||||
Name: app.Name,
|
||||
State: model.AppState(app.State),
|
||||
Type: model.AppType(app.Type),
|
||||
}
|
||||
if app.OIDCConfig != nil {
|
||||
converted.OIDCConfig = OIDCConfigToModel(app.OIDCConfig)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func (p *Project) appendAddAppEvent(event *es_models.Event) error {
|
||||
app := new(Application)
|
||||
err := app.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app.ObjectRoot.CreationDate = event.CreationDate
|
||||
p.Applications = append(p.Applications, app)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendChangeAppEvent(event *es_models.Event) error {
|
||||
app := new(Application)
|
||||
err := app.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i, a := GetApplication(p.Applications, app.AppID); a != nil {
|
||||
p.Applications[i].setData(event)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendRemoveAppEvent(event *es_models.Event) error {
|
||||
app := new(Application)
|
||||
err := app.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i, a := GetApplication(p.Applications, app.AppID); a != nil {
|
||||
p.Applications[i] = p.Applications[len(p.Applications)-1]
|
||||
p.Applications[len(p.Applications)-1] = nil
|
||||
p.Applications = p.Applications[:len(p.Applications)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendAppStateEvent(event *es_models.Event, state model.AppState) error {
|
||||
app := new(Application)
|
||||
err := app.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i, a := GetApplication(p.Applications, app.AppID); a != nil {
|
||||
a.State = int32(state)
|
||||
p.Applications[i] = a
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Application) setData(event *es_models.Event) error {
|
||||
a.ObjectRoot.AppendEvent(event)
|
||||
if err := json.Unmarshal(event.Data, a); err != nil {
|
||||
logging.Log("EVEN-8die3").WithError(err).Error("could not unmarshal event data")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -0,0 +1,213 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestApplicationChanges(t *testing.T) {
|
||||
type args struct {
|
||||
existing *Application
|
||||
new *Application
|
||||
}
|
||||
type res struct {
|
||||
changesLen int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "application name changes",
|
||||
args: args{
|
||||
existing: &Application{AppID: "AppID", Name: "Name"},
|
||||
new: &Application{AppID: "AppID", Name: "NameChanged"},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes",
|
||||
args: args{
|
||||
existing: &Application{AppID: "AppID", Name: "Name"},
|
||||
new: &Application{AppID: "AppID", Name: "Name"},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
changes := tt.args.existing.Changes(tt.args.new)
|
||||
if len(changes) != tt.res.changesLen {
|
||||
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendAddAppEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
app *Application
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append add application event",
|
||||
args: args{
|
||||
project: &Project{},
|
||||
app: &Application{Name: "Application"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Applications: []*Application{&Application{Name: "Application"}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.app != nil {
|
||||
data, _ := json.Marshal(tt.args.app)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendAddAppEvent(tt.args.event)
|
||||
if len(tt.args.project.Applications) != 1 {
|
||||
t.Errorf("got wrong result should have one app actual: %v ", len(tt.args.project.Applications))
|
||||
}
|
||||
if tt.args.project.Applications[0] == tt.result.Applications[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Applications[0], tt.args.project.Applications[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendChangeAppEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
app *Application
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append change application event",
|
||||
args: args{
|
||||
project: &Project{Applications: []*Application{&Application{Name: "Application"}}},
|
||||
app: &Application{Name: "Application Change"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Applications: []*Application{&Application{Name: "Application Change"}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.app != nil {
|
||||
data, _ := json.Marshal(tt.args.app)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendChangeAppEvent(tt.args.event)
|
||||
if len(tt.args.project.Applications) != 1 {
|
||||
t.Errorf("got wrong result should have one app actual: %v ", len(tt.args.project.Applications))
|
||||
}
|
||||
if tt.args.project.Applications[0] == tt.result.Applications[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Applications[0], tt.args.project.Applications[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendRemoveAppEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
app *Application
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append remove application event",
|
||||
args: args{
|
||||
project: &Project{Applications: []*Application{&Application{AppID: "AppID", Name: "Application"}}},
|
||||
app: &Application{AppID: "AppID", Name: "Application"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Applications: []*Application{}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.app != nil {
|
||||
data, _ := json.Marshal(tt.args.app)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendRemoveAppEvent(tt.args.event)
|
||||
if len(tt.args.project.Applications) != 0 {
|
||||
t.Errorf("got wrong result should have no apps actual: %v ", len(tt.args.project.Applications))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendAppStateEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
app *ApplicationID
|
||||
event *es_models.Event
|
||||
state model.AppState
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append deactivate application event",
|
||||
args: args{
|
||||
project: &Project{Applications: []*Application{&Application{AppID: "AppID", Name: "Application", State: int32(model.APPSTATE_ACTIVE)}}},
|
||||
app: &ApplicationID{AppID: "AppID"},
|
||||
event: &es_models.Event{},
|
||||
state: model.APPSTATE_INACTIVE,
|
||||
},
|
||||
result: &Project{Applications: []*Application{&Application{AppID: "AppID", Name: "Application", State: int32(model.APPSTATE_INACTIVE)}}},
|
||||
},
|
||||
{
|
||||
name: "append reactivate application event",
|
||||
args: args{
|
||||
project: &Project{Applications: []*Application{&Application{AppID: "AppID", Name: "Application", State: int32(model.APPSTATE_INACTIVE)}}},
|
||||
app: &ApplicationID{AppID: "AppID"},
|
||||
event: &es_models.Event{},
|
||||
state: model.APPSTATE_ACTIVE,
|
||||
},
|
||||
result: &Project{Applications: []*Application{&Application{AppID: "AppID", Name: "Application", State: int32(model.APPSTATE_ACTIVE)}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.app != nil {
|
||||
data, _ := json.Marshal(tt.args.app)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendAppStateEvent(tt.args.event, tt.args.state)
|
||||
if len(tt.args.project.Applications) != 1 {
|
||||
t.Errorf("got wrong result should have one app actual: %v ", len(tt.args.project.Applications))
|
||||
}
|
||||
if tt.args.project.Applications[0] == tt.result.Applications[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Applications[0], tt.args.project.Applications[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
139
internal/project/repository/eventsourcing/model/oidc_config.go
Normal file
139
internal/project/repository/eventsourcing/model/oidc_config.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type OIDCConfig struct {
|
||||
es_models.ObjectRoot
|
||||
AppID string `json:"appId"`
|
||||
ClientID string `json:"clientId,omitempty"`
|
||||
ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
|
||||
RedirectUris []string `json:"redirectUris,omitempty"`
|
||||
ResponseTypes []int32 `json:"responseTypes,omitempty"`
|
||||
GrantTypes []int32 `json:"grantTypes,omitempty"`
|
||||
ApplicationType int32 `json:"applicationType,omitempty"`
|
||||
AuthMethodType int32 `json:"authMethodType,omitempty"`
|
||||
PostLogoutRedirectUris []string `json:"postLogoutRedirectUris,omitempty"`
|
||||
}
|
||||
|
||||
func (c *OIDCConfig) Changes(changed *OIDCConfig) map[string]interface{} {
|
||||
changes := make(map[string]interface{}, 1)
|
||||
changes["appId"] = c.AppID
|
||||
if !reflect.DeepEqual(c.RedirectUris, changed.RedirectUris) {
|
||||
changes["redirectUris"] = changed.RedirectUris
|
||||
}
|
||||
if !reflect.DeepEqual(c.ResponseTypes, changed.ResponseTypes) {
|
||||
changes["responseTypes"] = changed.ResponseTypes
|
||||
}
|
||||
if !reflect.DeepEqual(c.GrantTypes, changed.GrantTypes) {
|
||||
changes["grantTypes"] = changed.GrantTypes
|
||||
}
|
||||
if c.ApplicationType != changed.ApplicationType {
|
||||
changes["applicationType"] = changed.ApplicationType
|
||||
}
|
||||
if c.AuthMethodType != changed.AuthMethodType {
|
||||
changes["authMethodType"] = changed.AuthMethodType
|
||||
}
|
||||
if !reflect.DeepEqual(c.PostLogoutRedirectUris, changed.PostLogoutRedirectUris) {
|
||||
changes["postLogoutRedirectUris"] = changed.PostLogoutRedirectUris
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
func OIDCConfigFromModel(config *model.OIDCConfig) *OIDCConfig {
|
||||
responseTypes := make([]int32, len(config.ResponseTypes))
|
||||
for i, rt := range config.ResponseTypes {
|
||||
responseTypes[i] = int32(rt)
|
||||
}
|
||||
grantTypes := make([]int32, len(config.GrantTypes))
|
||||
for i, rt := range config.GrantTypes {
|
||||
grantTypes[i] = int32(rt)
|
||||
}
|
||||
return &OIDCConfig{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: config.ObjectRoot.AggregateID,
|
||||
Sequence: config.Sequence,
|
||||
ChangeDate: config.ChangeDate,
|
||||
CreationDate: config.CreationDate,
|
||||
},
|
||||
AppID: config.AppID,
|
||||
ClientID: config.ClientID,
|
||||
ClientSecret: config.ClientSecret,
|
||||
RedirectUris: config.RedirectUris,
|
||||
ResponseTypes: responseTypes,
|
||||
GrantTypes: grantTypes,
|
||||
ApplicationType: int32(config.ApplicationType),
|
||||
AuthMethodType: int32(config.AuthMethodType),
|
||||
PostLogoutRedirectUris: config.PostLogoutRedirectUris,
|
||||
}
|
||||
}
|
||||
|
||||
func OIDCConfigToModel(config *OIDCConfig) *model.OIDCConfig {
|
||||
responseTypes := make([]model.OIDCResponseType, len(config.ResponseTypes))
|
||||
for i, rt := range config.ResponseTypes {
|
||||
responseTypes[i] = model.OIDCResponseType(rt)
|
||||
}
|
||||
grantTypes := make([]model.OIDCGrantType, len(config.GrantTypes))
|
||||
for i, rt := range config.GrantTypes {
|
||||
grantTypes[i] = model.OIDCGrantType(rt)
|
||||
}
|
||||
return &model.OIDCConfig{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: config.ObjectRoot.AggregateID,
|
||||
Sequence: config.Sequence,
|
||||
ChangeDate: config.ChangeDate,
|
||||
CreationDate: config.CreationDate,
|
||||
},
|
||||
AppID: config.AppID,
|
||||
ClientID: config.ClientID,
|
||||
ClientSecret: config.ClientSecret,
|
||||
RedirectUris: config.RedirectUris,
|
||||
ResponseTypes: responseTypes,
|
||||
GrantTypes: grantTypes,
|
||||
ApplicationType: model.OIDCApplicationType(config.ApplicationType),
|
||||
AuthMethodType: model.OIDCAuthMethodType(config.AuthMethodType),
|
||||
PostLogoutRedirectUris: config.PostLogoutRedirectUris,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Project) appendAddOIDCConfigEvent(event *es_models.Event) error {
|
||||
config := new(OIDCConfig)
|
||||
err := config.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.ObjectRoot.CreationDate = event.CreationDate
|
||||
if i, a := GetApplication(p.Applications, config.AppID); a != nil {
|
||||
p.Applications[i].Type = int32(model.APPTYPE_OIDC)
|
||||
p.Applications[i].OIDCConfig = config
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendChangeOIDCConfigEvent(event *es_models.Event) error {
|
||||
config := new(OIDCConfig)
|
||||
err := config.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i, a := GetApplication(p.Applications, config.AppID); a != nil {
|
||||
p.Applications[i].OIDCConfig.setData(event)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OIDCConfig) setData(event *es_models.Event) error {
|
||||
o.ObjectRoot.AppendEvent(event)
|
||||
if err := json.Unmarshal(event.Data, o); err != nil {
|
||||
logging.Log("EVEN-d8e3s").WithError(err).Error("could not unmarshal event data")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -0,0 +1,181 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOIDCConfigChanges(t *testing.T) {
|
||||
type args struct {
|
||||
existing *OIDCConfig
|
||||
new *OIDCConfig
|
||||
}
|
||||
type res struct {
|
||||
changesLen int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "all possible values change",
|
||||
args: args{
|
||||
existing: &OIDCConfig{
|
||||
AppID: "AppID",
|
||||
RedirectUris: []string{"RedirectUris"},
|
||||
ResponseTypes: []int32{1},
|
||||
GrantTypes: []int32{1},
|
||||
ApplicationType: 1,
|
||||
AuthMethodType: 1,
|
||||
PostLogoutRedirectUris: []string{"PostLogoutRedirectUris"},
|
||||
},
|
||||
new: &OIDCConfig{
|
||||
AppID: "AppID",
|
||||
RedirectUris: []string{"RedirectUrisChanged"},
|
||||
ResponseTypes: []int32{2},
|
||||
GrantTypes: []int32{2},
|
||||
ApplicationType: 2,
|
||||
AuthMethodType: 2,
|
||||
PostLogoutRedirectUris: []string{"PostLogoutRedirectUrisChanged"},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 7,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes",
|
||||
args: args{
|
||||
existing: &OIDCConfig{
|
||||
AppID: "AppID",
|
||||
RedirectUris: []string{"RedirectUris"},
|
||||
ResponseTypes: []int32{1},
|
||||
GrantTypes: []int32{1},
|
||||
ApplicationType: 1,
|
||||
AuthMethodType: 1,
|
||||
PostLogoutRedirectUris: []string{"PostLogoutRedirectUris"},
|
||||
},
|
||||
new: &OIDCConfig{
|
||||
AppID: "AppID",
|
||||
RedirectUris: []string{"RedirectUris"},
|
||||
ResponseTypes: []int32{1},
|
||||
GrantTypes: []int32{1},
|
||||
ApplicationType: 1,
|
||||
AuthMethodType: 1,
|
||||
PostLogoutRedirectUris: []string{"PostLogoutRedirectUris"},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change not changeable attributes",
|
||||
args: args{
|
||||
existing: &OIDCConfig{
|
||||
AppID: "AppID",
|
||||
ClientID: "ClientID",
|
||||
},
|
||||
new: &OIDCConfig{
|
||||
AppID: "AppIDChange",
|
||||
ClientID: "ClientIDChange",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
changes := tt.args.existing.Changes(tt.args.new)
|
||||
if len(changes) != tt.res.changesLen {
|
||||
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendAddOIDCConfigEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
config *OIDCConfig
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append add application event",
|
||||
args: args{
|
||||
project: &Project{Applications: []*Application{&Application{AppID: "AppID"}}},
|
||||
config: &OIDCConfig{AppID: "AppID", ClientID: "ClientID"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Applications: []*Application{&Application{AppID: "AppID", OIDCConfig: &OIDCConfig{AppID: "AppID", ClientID: "ClientID"}}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.config != nil {
|
||||
data, _ := json.Marshal(tt.args.config)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendAddOIDCConfigEvent(tt.args.event)
|
||||
if len(tt.args.project.Applications) != 1 {
|
||||
t.Errorf("got wrong result should have one app actual: %v ", len(tt.args.project.Applications))
|
||||
}
|
||||
if tt.args.project.Applications[0].OIDCConfig == nil {
|
||||
t.Errorf("got wrong result should have oidc config actual: %v ", tt.args.project.Applications[0].OIDCConfig)
|
||||
}
|
||||
if tt.args.project.Applications[0] == tt.result.Applications[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Applications[0], tt.args.project.Applications[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendChangeOIDCConfigEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
config *OIDCConfig
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append change application event",
|
||||
args: args{
|
||||
project: &Project{Applications: []*Application{&Application{AppID: "AppID", OIDCConfig: &OIDCConfig{AppID: "AppID", ClientID: "ClientID"}}}},
|
||||
config: &OIDCConfig{AppID: "AppID", ClientID: "ClientID Changed"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Applications: []*Application{&Application{AppID: "AppID", OIDCConfig: &OIDCConfig{AppID: "AppID", ClientID: "ClientID Changed"}}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.config != nil {
|
||||
data, _ := json.Marshal(tt.args.config)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendChangeOIDCConfigEvent(tt.args.event)
|
||||
if len(tt.args.project.Applications) != 1 {
|
||||
t.Errorf("got wrong result should have one app actual: %v ", len(tt.args.project.Applications))
|
||||
}
|
||||
if tt.args.project.Applications[0].OIDCConfig == nil {
|
||||
t.Errorf("got wrong result should have oidc config actual: %v ", tt.args.project.Applications[0].OIDCConfig)
|
||||
}
|
||||
if tt.args.project.Applications[0] == tt.result.Applications[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Applications[0], tt.args.project.Applications[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
160
internal/project/repository/eventsourcing/model/project.go
Normal file
160
internal/project/repository/eventsourcing/model/project.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/caos/logging"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
)
|
||||
|
||||
const (
|
||||
ProjectVersion = "v1"
|
||||
)
|
||||
|
||||
type Project struct {
|
||||
es_models.ObjectRoot
|
||||
Name string `json:"name,omitempty"`
|
||||
State int32 `json:"-"`
|
||||
Members []*ProjectMember `json:"-"`
|
||||
Roles []*ProjectRole `json:"-"`
|
||||
Applications []*Application `json:"-"`
|
||||
Grants []*ProjectGrant `json:"-"`
|
||||
}
|
||||
|
||||
func (p *Project) Changes(changed *Project) map[string]interface{} {
|
||||
changes := make(map[string]interface{}, 1)
|
||||
if changed.Name != "" && p.Name != changed.Name {
|
||||
changes["name"] = changed.Name
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
func ProjectFromModel(project *model.Project) *Project {
|
||||
members := ProjectMembersFromModel(project.Members)
|
||||
roles := ProjectRolesFromModel(project.Roles)
|
||||
apps := AppsFromModel(project.Applications)
|
||||
grants := GrantsFromModel(project.Grants)
|
||||
return &Project{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: project.ObjectRoot.AggregateID,
|
||||
Sequence: project.Sequence,
|
||||
ChangeDate: project.ChangeDate,
|
||||
CreationDate: project.CreationDate,
|
||||
},
|
||||
Name: project.Name,
|
||||
State: int32(project.State),
|
||||
Members: members,
|
||||
Roles: roles,
|
||||
Applications: apps,
|
||||
Grants: grants,
|
||||
}
|
||||
}
|
||||
|
||||
func ProjectToModel(project *Project) *model.Project {
|
||||
members := ProjectMembersToModel(project.Members)
|
||||
roles := ProjectRolesToModel(project.Roles)
|
||||
apps := AppsToModel(project.Applications)
|
||||
grants := GrantsToModel(project.Grants)
|
||||
return &model.Project{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: project.AggregateID,
|
||||
ChangeDate: project.ChangeDate,
|
||||
CreationDate: project.CreationDate,
|
||||
Sequence: project.Sequence,
|
||||
},
|
||||
Name: project.Name,
|
||||
State: model.ProjectState(project.State),
|
||||
Members: members,
|
||||
Roles: roles,
|
||||
Applications: apps,
|
||||
Grants: grants,
|
||||
}
|
||||
}
|
||||
|
||||
func ProjectFromEvents(project *Project, events ...*es_models.Event) (*Project, error) {
|
||||
if project == nil {
|
||||
project = &Project{}
|
||||
}
|
||||
|
||||
return project, project.AppendEvents(events...)
|
||||
}
|
||||
|
||||
func (p *Project) AppendEvents(events ...*es_models.Event) error {
|
||||
for _, event := range events {
|
||||
if err := p.AppendEvent(event); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) AppendEvent(event *es_models.Event) error {
|
||||
p.ObjectRoot.AppendEvent(event)
|
||||
|
||||
switch event.Type {
|
||||
case model.ProjectAdded, model.ProjectChanged:
|
||||
if err := json.Unmarshal(event.Data, p); err != nil {
|
||||
logging.Log("EVEN-idl93").WithError(err).Error("could not unmarshal event data")
|
||||
return err
|
||||
}
|
||||
p.State = int32(model.PROJECTSTATE_ACTIVE)
|
||||
return nil
|
||||
case model.ProjectDeactivated:
|
||||
return p.appendDeactivatedEvent()
|
||||
case model.ProjectReactivated:
|
||||
return p.appendReactivatedEvent()
|
||||
case model.ProjectMemberAdded:
|
||||
return p.appendAddMemberEvent(event)
|
||||
case model.ProjectMemberChanged:
|
||||
return p.appendChangeMemberEvent(event)
|
||||
case model.ProjectMemberRemoved:
|
||||
return p.appendRemoveMemberEvent(event)
|
||||
case model.ProjectRoleAdded:
|
||||
return p.appendAddRoleEvent(event)
|
||||
case model.ProjectRoleChanged:
|
||||
return p.appendChangeRoleEvent(event)
|
||||
case model.ProjectRoleRemoved:
|
||||
return p.appendRemoveRoleEvent(event)
|
||||
case model.ApplicationAdded:
|
||||
return p.appendAddAppEvent(event)
|
||||
case model.ApplicationChanged:
|
||||
return p.appendChangeAppEvent(event)
|
||||
case model.ApplicationRemoved:
|
||||
return p.appendRemoveAppEvent(event)
|
||||
case model.ApplicationDeactivated:
|
||||
return p.appendAppStateEvent(event, model.APPSTATE_INACTIVE)
|
||||
case model.ApplicationReactivated:
|
||||
return p.appendAppStateEvent(event, model.APPSTATE_ACTIVE)
|
||||
case model.OIDCConfigAdded:
|
||||
return p.appendAddOIDCConfigEvent(event)
|
||||
case model.OIDCConfigChanged, model.OIDCConfigSecretChanged:
|
||||
return p.appendChangeOIDCConfigEvent(event)
|
||||
case model.ProjectGrantAdded:
|
||||
return p.appendAddGrantEvent(event)
|
||||
case model.ProjectGrantChanged:
|
||||
return p.appendChangeGrantEvent(event)
|
||||
case model.ProjectGrantDeactivated:
|
||||
return p.appendGrantStateEvent(event, model.PROJECTGRANTSTATE_INACTIVE)
|
||||
case model.ProjectGrantReactivated:
|
||||
return p.appendGrantStateEvent(event, model.PROJECTGRANTSTATE_ACTIVE)
|
||||
case model.ProjectGrantRemoved:
|
||||
return p.appendRemoveGrantEvent(event)
|
||||
case model.ProjectGrantMemberAdded:
|
||||
return p.appendAddGrantMemberEvent(event)
|
||||
case model.ProjectGrantMemberChanged:
|
||||
return p.appendChangeGrantMemberEvent(event)
|
||||
case model.ProjectGrantMemberRemoved:
|
||||
return p.appendRemoveGrantMemberEvent(event)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendDeactivatedEvent() error {
|
||||
p.State = int32(model.PROJECTSTATE_INACTIVE)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendReactivatedEvent() error {
|
||||
p.State = int32(model.PROJECTSTATE_ACTIVE)
|
||||
return nil
|
||||
}
|
151
internal/project/repository/eventsourcing/model/project_grant.go
Normal file
151
internal/project/repository/eventsourcing/model/project_grant.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/caos/logging"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type ProjectGrant struct {
|
||||
es_models.ObjectRoot
|
||||
State int32 `json:"-"`
|
||||
GrantID string `json:"grantId,omitempty"`
|
||||
GrantedOrgID string `json:"grantedOrgId,omitempty"`
|
||||
RoleKeys []string `json:"roleKeys,omitempty"`
|
||||
Members []*ProjectGrantMember `json:"-"`
|
||||
}
|
||||
|
||||
type ProjectGrantID struct {
|
||||
es_models.ObjectRoot
|
||||
GrantID string `json:"grantId"`
|
||||
}
|
||||
|
||||
func GetProjectGrant(grants []*ProjectGrant, id string) (int, *ProjectGrant) {
|
||||
for i, g := range grants {
|
||||
if g.GrantID == id {
|
||||
return i, g
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func (g *ProjectGrant) Changes(changed *ProjectGrant) map[string]interface{} {
|
||||
changes := make(map[string]interface{}, 1)
|
||||
changes["grantId"] = g.GrantID
|
||||
if !reflect.DeepEqual(g.RoleKeys, changed.RoleKeys) {
|
||||
changes["roleKeys"] = changed.RoleKeys
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
func GrantsToModel(grants []*ProjectGrant) []*model.ProjectGrant {
|
||||
convertedGrants := make([]*model.ProjectGrant, len(grants))
|
||||
for i, g := range grants {
|
||||
convertedGrants[i] = GrantToModel(g)
|
||||
}
|
||||
return convertedGrants
|
||||
}
|
||||
|
||||
func GrantsFromModel(grants []*model.ProjectGrant) []*ProjectGrant {
|
||||
convertedGrants := make([]*ProjectGrant, len(grants))
|
||||
for i, g := range grants {
|
||||
convertedGrants[i] = GrantFromModel(g)
|
||||
}
|
||||
return convertedGrants
|
||||
}
|
||||
|
||||
func GrantFromModel(grant *model.ProjectGrant) *ProjectGrant {
|
||||
members := GrantMembersFromModel(grant.Members)
|
||||
return &ProjectGrant{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: grant.ObjectRoot.AggregateID,
|
||||
Sequence: grant.Sequence,
|
||||
ChangeDate: grant.ChangeDate,
|
||||
CreationDate: grant.CreationDate,
|
||||
},
|
||||
GrantID: grant.GrantID,
|
||||
GrantedOrgID: grant.GrantedOrgID,
|
||||
State: int32(grant.State),
|
||||
RoleKeys: grant.RoleKeys,
|
||||
Members: members,
|
||||
}
|
||||
}
|
||||
|
||||
func GrantToModel(grant *ProjectGrant) *model.ProjectGrant {
|
||||
members := GrantMembersToModel(grant.Members)
|
||||
return &model.ProjectGrant{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: grant.AggregateID,
|
||||
ChangeDate: grant.ChangeDate,
|
||||
CreationDate: grant.CreationDate,
|
||||
Sequence: grant.Sequence,
|
||||
},
|
||||
GrantID: grant.GrantID,
|
||||
GrantedOrgID: grant.GrantedOrgID,
|
||||
State: model.ProjectGrantState(grant.State),
|
||||
RoleKeys: grant.RoleKeys,
|
||||
Members: members,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Project) appendAddGrantEvent(event *es_models.Event) error {
|
||||
grant := new(ProjectGrant)
|
||||
err := grant.getData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
grant.ObjectRoot.CreationDate = event.CreationDate
|
||||
p.Grants = append(p.Grants, grant)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendChangeGrantEvent(event *es_models.Event) error {
|
||||
grant := new(ProjectGrant)
|
||||
err := grant.getData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i, g := GetProjectGrant(p.Grants, grant.GrantID); g != nil {
|
||||
p.Grants[i].getData(event)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendGrantStateEvent(event *es_models.Event, state model.ProjectGrantState) error {
|
||||
grant := new(ProjectGrant)
|
||||
err := grant.getData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i, g := GetProjectGrant(p.Grants, grant.GrantID); g != nil {
|
||||
g.State = int32(state)
|
||||
p.Grants[i] = g
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendRemoveGrantEvent(event *es_models.Event) error {
|
||||
grant := new(ProjectGrant)
|
||||
err := grant.getData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i, g := GetProjectGrant(p.Grants, grant.GrantID); g != nil {
|
||||
p.Grants[i] = p.Grants[len(p.Grants)-1]
|
||||
p.Grants[len(p.Grants)-1] = nil
|
||||
p.Grants = p.Grants[:len(p.Grants)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *ProjectGrant) getData(event *es_models.Event) error {
|
||||
g.ObjectRoot.AppendEvent(event)
|
||||
if err := json.Unmarshal(event.Data, g); err != nil {
|
||||
logging.Log("EVEN-4h6gd").WithError(err).Error("could not unmarshal event data")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -0,0 +1,122 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/caos/logging"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
)
|
||||
|
||||
type ProjectGrantMember struct {
|
||||
es_models.ObjectRoot
|
||||
GrantID string `json:"grantId,omitempty"`
|
||||
UserID string `json:"userId,omitempty"`
|
||||
Roles []string `json:"roles,omitempty"`
|
||||
}
|
||||
|
||||
func GetProjectGrantMember(members []*ProjectGrantMember, id string) (int, *ProjectGrantMember) {
|
||||
for i, m := range members {
|
||||
if m.UserID == id {
|
||||
return i, m
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func GrantMembersToModel(members []*ProjectGrantMember) []*model.ProjectGrantMember {
|
||||
convertedMembers := make([]*model.ProjectGrantMember, len(members))
|
||||
for i, g := range members {
|
||||
convertedMembers[i] = GrantMemberToModel(g)
|
||||
}
|
||||
return convertedMembers
|
||||
}
|
||||
|
||||
func GrantMembersFromModel(members []*model.ProjectGrantMember) []*ProjectGrantMember {
|
||||
convertedMembers := make([]*ProjectGrantMember, len(members))
|
||||
for i, g := range members {
|
||||
convertedMembers[i] = GrantMemberFromModel(g)
|
||||
}
|
||||
return convertedMembers
|
||||
}
|
||||
|
||||
func GrantMemberFromModel(member *model.ProjectGrantMember) *ProjectGrantMember {
|
||||
return &ProjectGrantMember{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: member.ObjectRoot.AggregateID,
|
||||
Sequence: member.Sequence,
|
||||
ChangeDate: member.ChangeDate,
|
||||
CreationDate: member.CreationDate,
|
||||
},
|
||||
GrantID: member.GrantID,
|
||||
UserID: member.UserID,
|
||||
Roles: member.Roles,
|
||||
}
|
||||
}
|
||||
|
||||
func GrantMemberToModel(member *ProjectGrantMember) *model.ProjectGrantMember {
|
||||
return &model.ProjectGrantMember{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: member.AggregateID,
|
||||
ChangeDate: member.ChangeDate,
|
||||
CreationDate: member.CreationDate,
|
||||
Sequence: member.Sequence,
|
||||
},
|
||||
GrantID: member.GrantID,
|
||||
UserID: member.UserID,
|
||||
Roles: member.Roles,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Project) appendAddGrantMemberEvent(event *es_models.Event) error {
|
||||
member := &ProjectGrantMember{}
|
||||
err := member.getData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
member.ObjectRoot.CreationDate = event.CreationDate
|
||||
|
||||
if _, g := GetProjectGrant(p.Grants, member.GrantID); g != nil {
|
||||
g.Members = append(g.Members, member)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendChangeGrantMemberEvent(event *es_models.Event) error {
|
||||
member := &ProjectGrantMember{}
|
||||
err := member.getData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, g := GetProjectGrant(p.Grants, member.GrantID); g != nil {
|
||||
if i, m := GetProjectGrantMember(g.Members, member.UserID); m != nil {
|
||||
g.Members[i].getData(event)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendRemoveGrantMemberEvent(event *es_models.Event) error {
|
||||
member := &ProjectGrantMember{}
|
||||
err := member.getData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, g := GetProjectGrant(p.Grants, member.GrantID); g != nil {
|
||||
if i, member := GetProjectGrantMember(g.Members, member.UserID); member != nil {
|
||||
g.Members[i] = g.Members[len(g.Members)-1]
|
||||
g.Members[len(g.Members)-1] = nil
|
||||
g.Members = g.Members[:len(g.Members)-1]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ProjectGrantMember) getData(event *es_models.Event) error {
|
||||
m.ObjectRoot.AppendEvent(event)
|
||||
if err := json.Unmarshal(event.Data, m); err != nil {
|
||||
logging.Log("EVEN-8die2").WithError(err).Error("could not unmarshal event data")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -0,0 +1,145 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAppendAddGrantMemberEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
member *ProjectGrantMember
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append add grant member",
|
||||
args: args{
|
||||
project: &Project{Grants: []*ProjectGrant{
|
||||
&ProjectGrant{GrantID: "GrantID", GrantedOrgID: "OrgID", RoleKeys: []string{"Key"}}}},
|
||||
member: &ProjectGrantMember{GrantID: "GrantID", UserID: "UserID", Roles: []string{"Role"}},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{
|
||||
Grants: []*ProjectGrant{
|
||||
&ProjectGrant{
|
||||
GrantID: "GrantID",
|
||||
GrantedOrgID: "OrgID",
|
||||
RoleKeys: []string{"Key"},
|
||||
Members: []*ProjectGrantMember{&ProjectGrantMember{GrantID: "GrantID", UserID: "UserID", Roles: []string{"Role"}}}}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.member != nil {
|
||||
data, _ := json.Marshal(tt.args.member)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendAddGrantMemberEvent(tt.args.event)
|
||||
if len(tt.args.project.Grants[0].Members) != 1 {
|
||||
t.Errorf("got wrong result should have one grant actual: %v ", len(tt.args.project.Grants[0].Members))
|
||||
}
|
||||
if tt.args.project.Grants[0].Members[0] == tt.result.Grants[0].Members[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Grants[0].Members[0], tt.args.project.Grants[0].Members[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendChangeGrantMemberEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
member *ProjectGrantMember
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append change grant member",
|
||||
args: args{
|
||||
project: &Project{
|
||||
Grants: []*ProjectGrant{
|
||||
&ProjectGrant{
|
||||
GrantID: "GrantID",
|
||||
GrantedOrgID: "OrgID",
|
||||
RoleKeys: []string{"Key"},
|
||||
Members: []*ProjectGrantMember{&ProjectGrantMember{GrantID: "GrantID", UserID: "UserID", Roles: []string{"Role"}}}}},
|
||||
},
|
||||
member: &ProjectGrantMember{GrantID: "GrantID", UserID: "UserID", Roles: []string{"RoleChanged"}},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{
|
||||
Grants: []*ProjectGrant{
|
||||
&ProjectGrant{
|
||||
GrantID: "GrantID",
|
||||
GrantedOrgID: "OrgID",
|
||||
RoleKeys: []string{"Key"},
|
||||
Members: []*ProjectGrantMember{&ProjectGrantMember{GrantID: "GrantID", UserID: "UserID", Roles: []string{"RoleChanged"}}}}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.member != nil {
|
||||
data, _ := json.Marshal(tt.args.member)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendChangeGrantMemberEvent(tt.args.event)
|
||||
if len(tt.args.project.Grants[0].Members) != 1 {
|
||||
t.Errorf("got wrong result should have one grant actual: %v ", len(tt.args.project.Grants[0].Members))
|
||||
}
|
||||
if tt.args.project.Grants[0].Members[0] == tt.result.Grants[0].Members[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Grants[0].Members[0], tt.args.project.Grants[0].Members[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendRemoveGrantMemberEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
member *ProjectGrantMember
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
{
|
||||
name: "append remove grant member",
|
||||
args: args{
|
||||
project: &Project{
|
||||
Grants: []*ProjectGrant{
|
||||
&ProjectGrant{
|
||||
GrantID: "GrantID",
|
||||
GrantedOrgID: "OrgID",
|
||||
RoleKeys: []string{"Key"},
|
||||
Members: []*ProjectGrantMember{&ProjectGrantMember{GrantID: "GrantID", UserID: "UserID", Roles: []string{"Role"}}}}},
|
||||
},
|
||||
member: &ProjectGrantMember{GrantID: "GrantID", UserID: "UserID", Roles: []string{"RoleChanged"}},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.member != nil {
|
||||
data, _ := json.Marshal(tt.args.member)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendRemoveGrantMemberEvent(tt.args.event)
|
||||
if len(tt.args.project.Grants[0].Members) != 0 {
|
||||
t.Errorf("got wrong result should have no members actual: %v ", len(tt.args.project.Grants[0].Members))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -0,0 +1,169 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAppendAddGrantEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
role *ProjectGrant
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append add grant event",
|
||||
args: args{
|
||||
project: &Project{},
|
||||
role: &ProjectGrant{GrantID: "GrantID", GrantedOrgID: "OrgID", RoleKeys: []string{"Key"}},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Grants: []*ProjectGrant{&ProjectGrant{GrantID: "GrantID", GrantedOrgID: "OrgID", RoleKeys: []string{"Key"}}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.role != nil {
|
||||
data, _ := json.Marshal(tt.args.role)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendAddGrantEvent(tt.args.event)
|
||||
if len(tt.args.project.Grants) != 1 {
|
||||
t.Errorf("got wrong result should have one grant actual: %v ", len(tt.args.project.Grants))
|
||||
}
|
||||
if tt.args.project.Grants[0] == tt.result.Grants[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Grants[0], tt.args.project.Grants[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendChangeGrantEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
grant *ProjectGrant
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append change grant event",
|
||||
args: args{
|
||||
project: &Project{Grants: []*ProjectGrant{&ProjectGrant{GrantID: "GrantID", GrantedOrgID: "OrgID", RoleKeys: []string{"Key"}}}},
|
||||
grant: &ProjectGrant{GrantID: "GrantID", GrantedOrgID: "OrgID", RoleKeys: []string{"KeyChanged"}},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Grants: []*ProjectGrant{&ProjectGrant{GrantID: "GrantID", GrantedOrgID: "OrgID", RoleKeys: []string{"KeyChanged"}}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.grant != nil {
|
||||
data, _ := json.Marshal(tt.args.grant)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendChangeGrantEvent(tt.args.event)
|
||||
if len(tt.args.project.Grants) != 1 {
|
||||
t.Errorf("got wrong result should have one grant actual: %v ", len(tt.args.project.Grants))
|
||||
}
|
||||
if tt.args.project.Grants[0] == tt.result.Grants[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Grants[0], tt.args.project.Grants[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendRemoveGrantEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
grant *ProjectGrant
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append remove role event",
|
||||
args: args{
|
||||
project: &Project{Grants: []*ProjectGrant{&ProjectGrant{GrantID: "GrantID", GrantedOrgID: "OrgID", RoleKeys: []string{"Key"}}}},
|
||||
grant: &ProjectGrant{GrantID: "GrantID"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Grants: []*ProjectGrant{}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.grant != nil {
|
||||
data, _ := json.Marshal(tt.args.grant)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendRemoveGrantEvent(tt.args.event)
|
||||
if len(tt.args.project.Grants) != 0 {
|
||||
t.Errorf("got wrong result should have no grant actual: %v ", len(tt.args.project.Grants))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendGrantStateEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
grant *ProjectGrantID
|
||||
event *es_models.Event
|
||||
state model.ProjectGrantState
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append deactivate grant event",
|
||||
args: args{
|
||||
project: &Project{Grants: []*ProjectGrant{&ProjectGrant{GrantID: "GrantID", GrantedOrgID: "OrgID", RoleKeys: []string{"Key"}}}},
|
||||
grant: &ProjectGrantID{GrantID: "GrantID"},
|
||||
event: &es_models.Event{},
|
||||
state: model.PROJECTGRANTSTATE_INACTIVE,
|
||||
},
|
||||
result: &Project{Grants: []*ProjectGrant{&ProjectGrant{GrantID: "GrantID", GrantedOrgID: "OrgID", RoleKeys: []string{"Key"}, State: int32(model.PROJECTGRANTSTATE_INACTIVE)}}},
|
||||
},
|
||||
{
|
||||
name: "append reactivate grant event",
|
||||
args: args{
|
||||
project: &Project{Grants: []*ProjectGrant{&ProjectGrant{GrantID: "GrantID", GrantedOrgID: "OrgID", RoleKeys: []string{"Key"}}}},
|
||||
grant: &ProjectGrantID{GrantID: "GrantID"},
|
||||
event: &es_models.Event{},
|
||||
state: model.PROJECTGRANTSTATE_ACTIVE,
|
||||
},
|
||||
result: &Project{Grants: []*ProjectGrant{&ProjectGrant{GrantID: "GrantID", GrantedOrgID: "OrgID", RoleKeys: []string{"Key"}, State: int32(model.PROJECTGRANTSTATE_ACTIVE)}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.grant != nil {
|
||||
data, _ := json.Marshal(tt.args.grant)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendGrantStateEvent(tt.args.event, tt.args.state)
|
||||
if len(tt.args.project.Grants) != 1 {
|
||||
t.Errorf("got wrong result should have one grant actual: %v ", len(tt.args.project.Grants))
|
||||
}
|
||||
if tt.args.project.Grants[0] == tt.result.Grants[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Grants[0], tt.args.project.Grants[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/caos/logging"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
)
|
||||
|
||||
type ProjectMember struct {
|
||||
es_models.ObjectRoot
|
||||
UserID string `json:"userId,omitempty"`
|
||||
Roles []string `json:"roles,omitempty"`
|
||||
}
|
||||
|
||||
func GetProjectMember(members []*ProjectMember, id string) (int, *ProjectMember) {
|
||||
for i, m := range members {
|
||||
if m.UserID == id {
|
||||
return i, m
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func ProjectMembersToModel(members []*ProjectMember) []*model.ProjectMember {
|
||||
convertedMembers := make([]*model.ProjectMember, len(members))
|
||||
for i, m := range members {
|
||||
convertedMembers[i] = ProjectMemberToModel(m)
|
||||
}
|
||||
return convertedMembers
|
||||
}
|
||||
|
||||
func ProjectMembersFromModel(members []*model.ProjectMember) []*ProjectMember {
|
||||
convertedMembers := make([]*ProjectMember, len(members))
|
||||
for i, m := range members {
|
||||
convertedMembers[i] = ProjectMemberFromModel(m)
|
||||
}
|
||||
return convertedMembers
|
||||
}
|
||||
|
||||
func ProjectMemberFromModel(member *model.ProjectMember) *ProjectMember {
|
||||
return &ProjectMember{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: member.ObjectRoot.AggregateID,
|
||||
Sequence: member.Sequence,
|
||||
ChangeDate: member.ChangeDate,
|
||||
CreationDate: member.CreationDate,
|
||||
},
|
||||
UserID: member.UserID,
|
||||
Roles: member.Roles,
|
||||
}
|
||||
}
|
||||
|
||||
func ProjectMemberToModel(member *ProjectMember) *model.ProjectMember {
|
||||
return &model.ProjectMember{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: member.AggregateID,
|
||||
ChangeDate: member.ChangeDate,
|
||||
CreationDate: member.CreationDate,
|
||||
Sequence: member.Sequence,
|
||||
},
|
||||
UserID: member.UserID,
|
||||
Roles: member.Roles,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Project) appendAddMemberEvent(event *es_models.Event) error {
|
||||
member := &ProjectMember{}
|
||||
err := member.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
member.ObjectRoot.CreationDate = event.CreationDate
|
||||
p.Members = append(p.Members, member)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendChangeMemberEvent(event *es_models.Event) error {
|
||||
member := &ProjectMember{}
|
||||
err := member.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i, m := GetProjectMember(p.Members, member.UserID); m != nil {
|
||||
p.Members[i] = member
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendRemoveMemberEvent(event *es_models.Event) error {
|
||||
member := &ProjectMember{}
|
||||
err := member.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i, m := GetProjectMember(p.Members, member.UserID); m != nil {
|
||||
p.Members[i] = p.Members[len(p.Members)-1]
|
||||
p.Members[len(p.Members)-1] = nil
|
||||
p.Members = p.Members[:len(p.Members)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ProjectMember) setData(event *es_models.Event) error {
|
||||
m.ObjectRoot.AppendEvent(event)
|
||||
if err := json.Unmarshal(event.Data, m); err != nil {
|
||||
logging.Log("EVEN-e4dkp").WithError(err).Error("could not unmarshal event data")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -0,0 +1,118 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAppendAddMemberEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
member *ProjectMember
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append add member event",
|
||||
args: args{
|
||||
project: &Project{},
|
||||
member: &ProjectMember{UserID: "UserID", Roles: []string{"Role"}},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Members: []*ProjectMember{&ProjectMember{UserID: "UserID", Roles: []string{"Role"}}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.member != nil {
|
||||
data, _ := json.Marshal(tt.args.member)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendAddMemberEvent(tt.args.event)
|
||||
if len(tt.args.project.Members) != 1 {
|
||||
t.Errorf("got wrong result should have one member actual: %v ", len(tt.args.project.Members))
|
||||
}
|
||||
if tt.args.project.Members[0] == tt.result.Members[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Members[0], tt.args.project.Members[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendChangeMemberEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
member *ProjectMember
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append change member event",
|
||||
args: args{
|
||||
project: &Project{Members: []*ProjectMember{&ProjectMember{UserID: "UserID", Roles: []string{"Role"}}}},
|
||||
member: &ProjectMember{UserID: "UserID", Roles: []string{"ChangedRole"}},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Members: []*ProjectMember{&ProjectMember{UserID: "UserID", Roles: []string{"ChangedRole"}}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.member != nil {
|
||||
data, _ := json.Marshal(tt.args.member)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendChangeMemberEvent(tt.args.event)
|
||||
if len(tt.args.project.Members) != 1 {
|
||||
t.Errorf("got wrong result should have one member actual: %v ", len(tt.args.project.Members))
|
||||
}
|
||||
if tt.args.project.Members[0] == tt.result.Members[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Members[0], tt.args.project.Members[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendRemoveMemberEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
member *ProjectMember
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append remove member event",
|
||||
args: args{
|
||||
project: &Project{Members: []*ProjectMember{&ProjectMember{UserID: "UserID", Roles: []string{"Role"}}}},
|
||||
member: &ProjectMember{UserID: "UserID"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Members: []*ProjectMember{}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.member != nil {
|
||||
data, _ := json.Marshal(tt.args.member)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendRemoveMemberEvent(tt.args.event)
|
||||
if len(tt.args.project.Members) != 0 {
|
||||
t.Errorf("got wrong result should have no member actual: %v ", len(tt.args.project.Members))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
114
internal/project/repository/eventsourcing/model/project_role.go
Normal file
114
internal/project/repository/eventsourcing/model/project_role.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/caos/logging"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
)
|
||||
|
||||
type ProjectRole struct {
|
||||
es_models.ObjectRoot
|
||||
Key string `json:"key,omitempty"`
|
||||
DisplayName string `json:"displayName,omitempty"`
|
||||
Group string `json:"group,omitempty"`
|
||||
}
|
||||
|
||||
func GetProjectRole(roles []*ProjectRole, key string) (int, *ProjectRole) {
|
||||
for i, r := range roles {
|
||||
if r.Key == key {
|
||||
return i, r
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func ProjectRolesToModel(roles []*ProjectRole) []*model.ProjectRole {
|
||||
convertedRoles := make([]*model.ProjectRole, len(roles))
|
||||
for i, r := range roles {
|
||||
convertedRoles[i] = ProjectRoleToModel(r)
|
||||
}
|
||||
return convertedRoles
|
||||
}
|
||||
|
||||
func ProjectRolesFromModel(roles []*model.ProjectRole) []*ProjectRole {
|
||||
convertedRoles := make([]*ProjectRole, len(roles))
|
||||
for i, r := range roles {
|
||||
convertedRoles[i] = ProjectRoleFromModel(r)
|
||||
}
|
||||
return convertedRoles
|
||||
}
|
||||
|
||||
func ProjectRoleFromModel(role *model.ProjectRole) *ProjectRole {
|
||||
return &ProjectRole{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: role.ObjectRoot.AggregateID,
|
||||
Sequence: role.Sequence,
|
||||
ChangeDate: role.ChangeDate,
|
||||
CreationDate: role.CreationDate,
|
||||
},
|
||||
Key: role.Key,
|
||||
DisplayName: role.DisplayName,
|
||||
Group: role.Group,
|
||||
}
|
||||
}
|
||||
|
||||
func ProjectRoleToModel(role *ProjectRole) *model.ProjectRole {
|
||||
return &model.ProjectRole{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: role.AggregateID,
|
||||
ChangeDate: role.ChangeDate,
|
||||
CreationDate: role.CreationDate,
|
||||
Sequence: role.Sequence,
|
||||
},
|
||||
Key: role.Key,
|
||||
DisplayName: role.DisplayName,
|
||||
Group: role.Group,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Project) appendAddRoleEvent(event *es_models.Event) error {
|
||||
role := new(ProjectRole)
|
||||
err := role.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
role.ObjectRoot.CreationDate = event.CreationDate
|
||||
p.Roles = append(p.Roles, role)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendChangeRoleEvent(event *es_models.Event) error {
|
||||
role := new(ProjectRole)
|
||||
err := role.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i, r := GetProjectRole(p.Roles, role.Key); r != nil {
|
||||
p.Roles[i] = role
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Project) appendRemoveRoleEvent(event *es_models.Event) error {
|
||||
role := new(ProjectRole)
|
||||
err := role.setData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i, r := GetProjectRole(p.Roles, role.Key); r != nil {
|
||||
p.Roles[i] = p.Roles[len(p.Roles)-1]
|
||||
p.Roles[len(p.Roles)-1] = nil
|
||||
p.Roles = p.Roles[:len(p.Roles)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ProjectRole) setData(event *es_models.Event) error {
|
||||
r.ObjectRoot.AppendEvent(event)
|
||||
if err := json.Unmarshal(event.Data, r); err != nil {
|
||||
logging.Log("EVEN-d9euw").WithError(err).Error("could not unmarshal event data")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -0,0 +1,118 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAppendAddRoleEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
role *ProjectRole
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append add role event",
|
||||
args: args{
|
||||
project: &Project{},
|
||||
role: &ProjectRole{Key: "Key", DisplayName: "DisplayName", Group: "Group"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Roles: []*ProjectRole{&ProjectRole{Key: "Key", DisplayName: "DisplayName", Group: "Group"}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.role != nil {
|
||||
data, _ := json.Marshal(tt.args.role)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendAddRoleEvent(tt.args.event)
|
||||
if len(tt.args.project.Roles) != 1 {
|
||||
t.Errorf("got wrong result should have one role actual: %v ", len(tt.args.project.Roles))
|
||||
}
|
||||
if tt.args.project.Roles[0] == tt.result.Roles[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Roles[0], tt.args.project.Roles[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendChangeRoleEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
role *ProjectRole
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append change role event",
|
||||
args: args{
|
||||
project: &Project{Roles: []*ProjectRole{&ProjectRole{Key: "Key", DisplayName: "DisplayName", Group: "Group"}}},
|
||||
role: &ProjectRole{Key: "Key", DisplayName: "DisplayNameChanged", Group: "Group"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Roles: []*ProjectRole{&ProjectRole{Key: "Key", DisplayName: "DisplayNameChanged", Group: "Group"}}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.role != nil {
|
||||
data, _ := json.Marshal(tt.args.role)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendChangeRoleEvent(tt.args.event)
|
||||
if len(tt.args.project.Roles) != 1 {
|
||||
t.Errorf("got wrong result should have one role actual: %v ", len(tt.args.project.Roles))
|
||||
}
|
||||
if tt.args.project.Roles[0] == tt.result.Roles[0] {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Roles[0], tt.args.project.Roles[0])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendRemoveRoleEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
role *ProjectRole
|
||||
event *es_models.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append remove role event",
|
||||
args: args{
|
||||
project: &Project{Roles: []*ProjectRole{&ProjectRole{Key: "Key", DisplayName: "DisplayName", Group: "Group"}}},
|
||||
role: &ProjectRole{Key: "Key"},
|
||||
event: &es_models.Event{},
|
||||
},
|
||||
result: &Project{Roles: []*ProjectRole{}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.role != nil {
|
||||
data, _ := json.Marshal(tt.args.role)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
tt.args.project.appendRemoveRoleEvent(tt.args.event)
|
||||
if len(tt.args.project.Roles) != 0 {
|
||||
t.Errorf("got wrong result should have no role actual: %v ", len(tt.args.project.Roles))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
213
internal/project/repository/eventsourcing/model/project_test.go
Normal file
213
internal/project/repository/eventsourcing/model/project_test.go
Normal file
@@ -0,0 +1,213 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestProjectChanges(t *testing.T) {
|
||||
type args struct {
|
||||
existing *Project
|
||||
new *Project
|
||||
}
|
||||
type res struct {
|
||||
changesLen int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "project name changes",
|
||||
args: args{
|
||||
existing: &Project{Name: "Name"},
|
||||
new: &Project{Name: "NameChanged"},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes",
|
||||
args: args{
|
||||
existing: &Project{Name: "Name"},
|
||||
new: &Project{Name: "Name"},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
changes := tt.args.existing.Changes(tt.args.new)
|
||||
if len(changes) != tt.res.changesLen {
|
||||
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectFromEvents(t *testing.T) {
|
||||
type args struct {
|
||||
event []*es_models.Event
|
||||
project *Project
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "project from events, ok",
|
||||
args: args{
|
||||
event: []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded},
|
||||
},
|
||||
project: &Project{Name: "ProjectName"},
|
||||
},
|
||||
result: &Project{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, State: int32(model.PROJECTSTATE_ACTIVE), Name: "ProjectName"},
|
||||
},
|
||||
{
|
||||
name: "project from events, nil project",
|
||||
args: args{
|
||||
event: []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded},
|
||||
},
|
||||
project: nil,
|
||||
},
|
||||
result: &Project{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, State: int32(model.PROJECTSTATE_ACTIVE)},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.project != nil {
|
||||
data, _ := json.Marshal(tt.args.project)
|
||||
tt.args.event[0].Data = data
|
||||
}
|
||||
result, _ := ProjectFromEvents(tt.args.project, tt.args.event...)
|
||||
if result.Name != tt.result.Name {
|
||||
t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.result.Name, result.Name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendEvent(t *testing.T) {
|
||||
type args struct {
|
||||
event *es_models.Event
|
||||
project *Project
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append added event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded},
|
||||
project: &Project{Name: "ProjectName"},
|
||||
},
|
||||
result: &Project{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, State: int32(model.PROJECTSTATE_ACTIVE), Name: "ProjectName"},
|
||||
},
|
||||
{
|
||||
name: "append change event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectChanged},
|
||||
project: &Project{Name: "ProjectName"},
|
||||
},
|
||||
result: &Project{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, State: int32(model.PROJECTSTATE_ACTIVE), Name: "ProjectName"},
|
||||
},
|
||||
{
|
||||
name: "append deactivate event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectDeactivated},
|
||||
},
|
||||
result: &Project{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, State: int32(model.PROJECTSTATE_INACTIVE)},
|
||||
},
|
||||
{
|
||||
name: "append reactivate event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectReactivated},
|
||||
},
|
||||
result: &Project{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, State: int32(model.PROJECTSTATE_ACTIVE)},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.args.project != nil {
|
||||
data, _ := json.Marshal(tt.args.project)
|
||||
tt.args.event.Data = data
|
||||
}
|
||||
result := new(Project)
|
||||
result.AppendEvent(tt.args.event)
|
||||
if result.State != tt.result.State {
|
||||
t.Errorf("got wrong result state: expected: %v, actual: %v ", tt.result.State, result.State)
|
||||
}
|
||||
if result.Name != tt.result.Name {
|
||||
t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.result.Name, result.Name)
|
||||
}
|
||||
if result.ObjectRoot.AggregateID != tt.result.ObjectRoot.AggregateID {
|
||||
t.Errorf("got wrong result id: expected: %v, actual: %v ", tt.result.ObjectRoot.AggregateID, result.ObjectRoot.AggregateID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendDeactivatedEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append reactivate event",
|
||||
args: args{
|
||||
project: &Project{},
|
||||
},
|
||||
result: &Project{State: int32(model.PROJECTSTATE_INACTIVE)},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.args.project.appendDeactivatedEvent()
|
||||
if tt.args.project.State != tt.result.State {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.project)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendReactivatedEvent(t *testing.T) {
|
||||
type args struct {
|
||||
project *Project
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *Project
|
||||
}{
|
||||
{
|
||||
name: "append reactivate event",
|
||||
args: args{
|
||||
project: &Project{},
|
||||
},
|
||||
result: &Project{State: int32(model.PROJECTSTATE_ACTIVE)},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.args.project.appendReactivatedEvent()
|
||||
if tt.args.project.State != tt.result.State {
|
||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.project)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user