mirror of
https://github.com/zitadel/zitadel.git
synced 2025-04-30 20:10:48 +00:00
fix: Project checks (#141)
* project validations * unique project on resourceowner
This commit is contained in:
parent
d447f68d78
commit
2758bf30b1
@ -126,7 +126,7 @@ func prepareWhere(searchQuery *es_models.SearchQuery) (clause string, values []i
|
||||
for i, filter := range searchQuery.Filters {
|
||||
value := filter.GetValue()
|
||||
switch value.(type) {
|
||||
case []bool, []float64, []int64, []string, []models.AggregateType, *[]bool, *[]float64, *[]int64, *[]string, *[]models.AggregateType:
|
||||
case []bool, []float64, []int64, []string, []models.AggregateType, []models.EventType, *[]bool, *[]float64, *[]int64, *[]string, *[]models.AggregateType, *[]models.EventType:
|
||||
value = pq.Array(value)
|
||||
}
|
||||
|
||||
@ -165,6 +165,8 @@ func getField(field es_models.Field) string {
|
||||
return "editor_service"
|
||||
case es_models.Field_EditorUser:
|
||||
return "editor_user"
|
||||
case es_models.Field_EventType:
|
||||
return "event_type"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -9,4 +9,5 @@ const (
|
||||
Field_ResourceOwner
|
||||
Field_EditorService
|
||||
Field_EditorUser
|
||||
Field_EventType
|
||||
)
|
||||
|
@ -43,6 +43,10 @@ func (q *SearchQuery) AggregateTypeFilter(types ...AggregateType) *SearchQuery {
|
||||
return q.setFilter(NewFilter(Field_AggregateType, types, Operation_In))
|
||||
}
|
||||
|
||||
func (q *SearchQuery) EventTypesFilter(types ...EventType) *SearchQuery {
|
||||
return q.setFilter(NewFilter(Field_EventType, types, Operation_In))
|
||||
}
|
||||
|
||||
func (q *SearchQuery) LatestSequenceFilter(sequence uint64) *SearchQuery {
|
||||
sortOrder := Operation_Greater
|
||||
if q.Desc {
|
||||
|
@ -113,8 +113,10 @@ func (es *ProjectEventstore) DeactivateProject(ctx context.Context, id string) (
|
||||
|
||||
repoExisting := model.ProjectFromModel(existing)
|
||||
aggregate := ProjectDeactivateAggregate(es.AggregateCreator(), repoExisting)
|
||||
es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, aggregate)
|
||||
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, aggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoExisting)
|
||||
return model.ProjectToModel(repoExisting), nil
|
||||
}
|
||||
@ -130,8 +132,10 @@ func (es *ProjectEventstore) ReactivateProject(ctx context.Context, id string) (
|
||||
|
||||
repoExisting := model.ProjectFromModel(existing)
|
||||
aggregate := ProjectReactivateAggregate(es.AggregateCreator(), repoExisting)
|
||||
es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, aggregate)
|
||||
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, aggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoExisting)
|
||||
return model.ProjectToModel(repoExisting), nil
|
||||
}
|
||||
@ -194,6 +198,9 @@ func (es *ProjectEventstore) ChangeProjectMember(ctx context.Context, member *pr
|
||||
|
||||
projectAggregate := ProjectMemberChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoMember)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
|
||||
if _, m := model.GetProjectMember(repoProject.Members, member.UserID); m != nil {
|
||||
@ -218,6 +225,9 @@ func (es *ProjectEventstore) RemoveProjectMember(ctx context.Context, member *pr
|
||||
|
||||
projectAggregate := ProjectMemberRemovedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoMember)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
return err
|
||||
}
|
||||
@ -347,6 +357,9 @@ func (es *ProjectEventstore) AddApplication(ctx context.Context, app *proj_model
|
||||
|
||||
addAggregate := ApplicationAddedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoApp)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, addAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil {
|
||||
converted := model.AppToModel(a)
|
||||
@ -372,6 +385,9 @@ func (es *ProjectEventstore) ChangeApplication(ctx context.Context, app *proj_mo
|
||||
|
||||
projectAggregate := ApplicationChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoApp)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil {
|
||||
return model.AppToModel(a), nil
|
||||
@ -418,6 +434,9 @@ func (es *ProjectEventstore) DeactivateApplication(ctx context.Context, projectI
|
||||
|
||||
projectAggregate := ApplicationDeactivatedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoApp)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil {
|
||||
return model.AppToModel(a), nil
|
||||
@ -442,6 +461,9 @@ func (es *ProjectEventstore) ReactivateApplication(ctx context.Context, projectI
|
||||
|
||||
projectAggregate := ApplicationReactivatedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoApp)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil {
|
||||
return model.AppToModel(a), nil
|
||||
@ -469,6 +491,9 @@ func (es *ProjectEventstore) ChangeOIDCConfig(ctx context.Context, config *proj_
|
||||
|
||||
projectAggregate := OIDCConfigChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoConfig)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil {
|
||||
return model.OIDCConfigToModel(a.OIDCConfig), nil
|
||||
@ -500,6 +525,9 @@ func (es *ProjectEventstore) ChangeOIDCConfigSecret(ctx context.Context, project
|
||||
|
||||
projectAggregate := OIDCConfigSecretChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, appID, crypto)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
|
||||
if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil {
|
||||
@ -550,7 +578,9 @@ func (es *ProjectEventstore) AddProjectGrant(ctx context.Context, grant *proj_mo
|
||||
|
||||
addAggregate := ProjectGrantAddedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoGrant)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, addAggregate)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, g := model.GetProjectGrant(repoProject.Grants, grant.GrantID); g != nil {
|
||||
return model.GrantToModel(g), nil
|
||||
}
|
||||
@ -576,6 +606,9 @@ func (es *ProjectEventstore) ChangeProjectGrant(ctx context.Context, grant *proj
|
||||
|
||||
projectAggregate := ProjectGrantChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoGrant)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
|
||||
if _, g := model.GetProjectGrant(repoProject.Grants, grant.GrantID); g != nil {
|
||||
@ -623,6 +656,9 @@ func (es *ProjectEventstore) DeactivateProjectGrant(ctx context.Context, project
|
||||
|
||||
projectAggregate := ProjectGrantDeactivatedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoGrant)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
if _, g := model.GetProjectGrant(repoProject.Grants, grant.GrantID); g != nil {
|
||||
return model.GrantToModel(g), nil
|
||||
@ -647,6 +683,9 @@ func (es *ProjectEventstore) ReactivateProjectGrant(ctx context.Context, project
|
||||
|
||||
projectAggregate := ProjectGrantReactivatedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoGrant)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
|
||||
if _, g := model.GetProjectGrant(repoProject.Grants, grant.GrantID); g != nil {
|
||||
@ -687,6 +726,9 @@ func (es *ProjectEventstore) AddProjectGrantMember(ctx context.Context, member *
|
||||
|
||||
addAggregate := ProjectGrantMemberAddedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoMember)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, addAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
if _, g := model.GetProjectGrant(repoProject.Grants, member.GrantID); g != nil {
|
||||
if _, m := model.GetProjectGrantMember(g.Members, member.UserID); m != nil {
|
||||
@ -712,6 +754,9 @@ func (es *ProjectEventstore) ChangeProjectGrantMember(ctx context.Context, membe
|
||||
|
||||
projectAggregate := ProjectGrantMemberChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoMember)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
if _, g := model.GetProjectGrant(repoProject.Grants, member.GrantID); g != nil {
|
||||
if _, m := model.GetProjectGrantMember(g.Members, member.UserID); m != nil {
|
||||
@ -737,6 +782,9 @@ func (es *ProjectEventstore) RemoveProjectGrantMember(ctx context.Context, membe
|
||||
|
||||
projectAggregate := ProjectGrantMemberRemovedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoMember)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
es.projectCache.cacheProject(repoProject)
|
||||
return err
|
||||
}
|
||||
|
@ -21,6 +21,15 @@ type Project struct {
|
||||
Grants []*ProjectGrant `json:"-"`
|
||||
}
|
||||
|
||||
func GetProject(projects []*Project, id string) (int, *Project) {
|
||||
for i, p := range projects {
|
||||
if p.AggregateID == id {
|
||||
return i, p
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func (p *Project) Changes(changed *Project) map[string]interface{} {
|
||||
changes := make(map[string]interface{}, 1)
|
||||
if changed.Name != "" && p.Name != changed.Name {
|
||||
|
@ -6,7 +6,9 @@ import (
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
"github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
|
||||
usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
)
|
||||
|
||||
func ProjectByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) {
|
||||
@ -40,8 +42,12 @@ func ProjectCreateAggregate(aggCreator *es_models.AggregateCreator, project *mod
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
validationQuery := es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(model.ProjectAggregate).
|
||||
EventTypesFilter(model.ProjectAdded, model.ProjectChanged, model.ProjectRemoved)
|
||||
|
||||
return agg.AppendEvent(model.ProjectAdded, project)
|
||||
validation := addProjectValidation(project.Name)
|
||||
return agg.SetPrecondition(validationQuery, validation).AppendEvent(model.ProjectAdded, project)
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,6 +61,17 @@ func ProjectUpdateAggregate(aggCreator *es_models.AggregateCreator, existing *mo
|
||||
return nil, err
|
||||
}
|
||||
changes := existing.Changes(new)
|
||||
if len(changes) == 0 {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-9soPE", "no changes found")
|
||||
}
|
||||
if existing.Name != new.Name {
|
||||
validationQuery := es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(model.ProjectAggregate).
|
||||
EventTypesFilter(model.ProjectAdded, model.ProjectChanged, model.ProjectRemoved)
|
||||
|
||||
validation := addProjectValidation(new.Name)
|
||||
agg.SetPrecondition(validationQuery, validation)
|
||||
}
|
||||
return agg.AppendEvent(model.ProjectChanged, changes)
|
||||
}
|
||||
}
|
||||
@ -86,7 +103,12 @@ func ProjectMemberAddedAggregate(aggCreator *es_models.AggregateCreator, existin
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.ProjectMemberAdded, member)
|
||||
validationQuery := es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(usr_model.UserAggregate).
|
||||
AggregateIDFilter(member.UserID)
|
||||
|
||||
validation := addProjectMemberValidation()
|
||||
return agg.SetPrecondition(validationQuery, validation).AppendEvent(model.ProjectMemberAdded, member)
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,7 +309,12 @@ func ProjectGrantAddedAggregate(aggCreator *es_models.AggregateCreator, existing
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
agg.AppendEvent(model.ProjectGrantAdded, grant)
|
||||
validationQuery := es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(org_model.OrgAggregate).
|
||||
AggregateIDFilter(grant.GrantedOrgID)
|
||||
|
||||
validation := addProjectGrantValidation()
|
||||
agg.SetPrecondition(validationQuery, validation).AppendEvent(model.ProjectGrantAdded, grant)
|
||||
return agg, nil
|
||||
}
|
||||
}
|
||||
@ -352,9 +379,7 @@ func ProjectGrantReactivatedAggregate(aggCreator *es_models.AggregateCreator, ex
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
agg.AppendEvent(model.ProjectGrantReactivated, &model.ProjectGrantID{GrantID: grant.GrantID})
|
||||
|
||||
return agg, nil
|
||||
return agg.AppendEvent(model.ProjectGrantReactivated, &model.ProjectGrantID{GrantID: grant.GrantID})
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,8 +392,12 @@ func ProjectGrantMemberAddedAggregate(aggCreator *es_models.AggregateCreator, ex
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
agg.AppendEvent(model.ProjectGrantMemberAdded, member)
|
||||
return agg, nil
|
||||
validationQuery := es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(usr_model.UserAggregate).
|
||||
AggregateIDFilter(member.UserID)
|
||||
|
||||
validation := addProjectGrantMemberValidation()
|
||||
return agg.SetPrecondition(validationQuery, validation).AppendEvent(model.ProjectGrantMemberAdded, member)
|
||||
}
|
||||
}
|
||||
|
||||
@ -403,3 +432,86 @@ func ProjectGrantMemberRemovedAggregate(aggCreator *es_models.AggregateCreator,
|
||||
return agg.AppendEvent(model.ProjectGrantMemberRemoved, member)
|
||||
}
|
||||
}
|
||||
|
||||
func addProjectValidation(projectName string) func(...*es_models.Event) error {
|
||||
return func(events ...*es_models.Event) error {
|
||||
projects := make([]*model.Project, 0)
|
||||
for _, event := range events {
|
||||
switch event.Type {
|
||||
case model.ProjectAdded:
|
||||
project := &model.Project{ObjectRoot: es_models.ObjectRoot{AggregateID: event.AggregateID}}
|
||||
project.AppendAddProjectEvent(event)
|
||||
projects = append(projects, project)
|
||||
case model.ProjectChanged:
|
||||
_, project := model.GetProject(projects, event.AggregateID)
|
||||
project.AppendAddProjectEvent(event)
|
||||
case model.ProjectRoleRemoved:
|
||||
for i, project := range projects {
|
||||
if project.AggregateID == event.AggregateID {
|
||||
projects[i] = projects[len(projects)-1]
|
||||
projects[len(projects)-1] = nil
|
||||
projects = projects[:len(projects)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, p := range projects {
|
||||
if p.Name == projectName {
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-s9oPw", "conditions not met")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func addProjectMemberValidation() func(...*es_models.Event) error {
|
||||
return func(events ...*es_models.Event) error {
|
||||
return checkExistsUser(events...)
|
||||
}
|
||||
}
|
||||
|
||||
func addProjectGrantValidation() func(...*es_models.Event) error {
|
||||
return func(events ...*es_models.Event) error {
|
||||
existsOrg := false
|
||||
for _, event := range events {
|
||||
switch event.AggregateType {
|
||||
case org_model.OrgAggregate:
|
||||
switch event.Type {
|
||||
case org_model.OrgAdded:
|
||||
existsOrg = true
|
||||
case org_model.OrgRemoved:
|
||||
existsOrg = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if existsOrg {
|
||||
return nil
|
||||
}
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-3OfIm", "conditions not met")
|
||||
}
|
||||
}
|
||||
|
||||
func addProjectGrantMemberValidation() func(...*es_models.Event) error {
|
||||
return func(events ...*es_models.Event) error {
|
||||
return checkExistsUser(events...)
|
||||
}
|
||||
}
|
||||
|
||||
func checkExistsUser(events ...*es_models.Event) error {
|
||||
existsUser := false
|
||||
for _, event := range events {
|
||||
switch event.AggregateType {
|
||||
case usr_model.UserAggregate:
|
||||
switch event.Type {
|
||||
case usr_model.UserAdded, usr_model.UserRegistered:
|
||||
existsUser = true
|
||||
case usr_model.UserRemoved:
|
||||
existsUser = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if existsUser {
|
||||
return nil
|
||||
}
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-3OfIm", "conditions not met")
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ const (
|
||||
UserRegistered models.EventType = "user.selfregistered"
|
||||
InitializedUserCodeAdded models.EventType = "user.initialization.code.added"
|
||||
InitializedUserCodeSent models.EventType = "user.initialization.code.sent"
|
||||
UserRemoved models.EventType = "user.removed"
|
||||
|
||||
UserUserNameReserved models.EventType = "user.username.reserved"
|
||||
UserUserNameReleased models.EventType = "user.username.released"
|
||||
|
Loading…
x
Reference in New Issue
Block a user