mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 08:37:32 +00:00
feat: multiple domains (#188)
* check uniqueness on create and register user * change user email, reserve release unique email * usergrant unique aggregate * usergrant uniqueness * validate UserGrant * fix tests * domain is set on username in all orgs * domain in admin * org domain sql * zitadel domain org name * org domains * org iam policy * default org iam policy * SETUP * load login names * login by login name * login name * fix: merge master * fix: merge master * Update internal/user/repository/eventsourcing/user.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * fix: fix unique domains * fix: rename env variable Co-authored-by: adlerhurst <silvan.reusser@gmail.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
@@ -3,11 +3,11 @@ package eventsourcing
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"log"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
|
||||
@@ -19,17 +19,24 @@ import (
|
||||
|
||||
type OrgEventstore struct {
|
||||
eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
IAMDomain string
|
||||
idGenerator id.Generator
|
||||
defaultOrgIamPolicy *org_model.OrgIamPolicy
|
||||
}
|
||||
|
||||
type OrgConfig struct {
|
||||
eventstore.Eventstore
|
||||
IAMDomain string
|
||||
}
|
||||
|
||||
func StartOrg(conf OrgConfig) *OrgEventstore {
|
||||
func StartOrg(conf OrgConfig, defaults systemdefaults.SystemDefaults) *OrgEventstore {
|
||||
policy := defaults.DefaultPolicies.OrgIam
|
||||
policy.Default = true
|
||||
return &OrgEventstore{
|
||||
Eventstore: conf.Eventstore,
|
||||
idGenerator: id.SonyFlakeGenerator,
|
||||
Eventstore: conf.Eventstore,
|
||||
idGenerator: id.SonyFlakeGenerator,
|
||||
IAMDomain: conf.IAMDomain,
|
||||
defaultOrgIamPolicy: &policy,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +44,8 @@ func (es *OrgEventstore) PrepareCreateOrg(ctx context.Context, orgModel *org_mod
|
||||
if orgModel == nil || !orgModel.IsValid() {
|
||||
return nil, nil, errors.ThrowInvalidArgument(nil, "EVENT-OeLSk", "org not valid")
|
||||
}
|
||||
orgModel.AddIAMDomain(es.IAMDomain)
|
||||
|
||||
id, err := es.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, nil, errors.ThrowInternal(err, "EVENT-OwciI", "id gen failed")
|
||||
@@ -138,6 +147,53 @@ func (es *OrgEventstore) ReactivateOrg(ctx context.Context, orgID string) (*org_
|
||||
return model.OrgToModel(org), nil
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) AddOrgDomain(ctx context.Context, domain *org_model.OrgDomain) (*org_model.OrgDomain, error) {
|
||||
if !domain.IsValid() {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-8sFJW", "domain is invalid")
|
||||
}
|
||||
existing, err := es.OrgByID(ctx, org_model.NewOrg(domain.AggregateID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repoOrg := model.OrgFromModel(existing)
|
||||
repoDomain := model.OrgDomainFromModel(domain)
|
||||
aggregate := OrgDomainAddedAggregate(es.Eventstore.AggregateCreator(), repoOrg, repoDomain)
|
||||
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoOrg.AppendEvents, aggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, d := model.GetDomain(repoOrg.Domains, domain.Domain); d != nil {
|
||||
return model.OrgDomainToModel(d), nil
|
||||
}
|
||||
return nil, errors.ThrowInternal(nil, "EVENT-ISOP0", "Could not find org in list")
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) RemoveOrgDomain(ctx context.Context, domain *org_model.OrgDomain) error {
|
||||
if domain.Domain == "" {
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-SJsK3", "Domain is required")
|
||||
}
|
||||
existing, err := es.OrgByID(ctx, org_model.NewOrg(domain.AggregateID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !existing.ContainsDomain(domain) {
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-Sjdi3", "Domain doesn't exist on project")
|
||||
}
|
||||
repoOrg := model.OrgFromModel(existing)
|
||||
repoDomain := model.OrgDomainFromModel(domain)
|
||||
orgAggregates, err := OrgDomainRemovedAggregate(ctx, es.Eventstore.AggregateCreator(), repoOrg, repoDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = es_sdk.PushAggregates(ctx, es.PushAggregates, repoOrg.AppendEvents, orgAggregates...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) OrgChanges(ctx context.Context, id string, lastSequence uint64, limit uint64) (*org_model.OrgChanges, error) {
|
||||
query := ChangesQuery(id, lastSequence)
|
||||
|
||||
@@ -147,7 +203,7 @@ func (es *OrgEventstore) OrgChanges(ctx context.Context, id string, lastSequence
|
||||
return nil, errors.ThrowInternal(err, "EVENT-328b1", "unable to get current user")
|
||||
}
|
||||
if len(events) == 0 {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "EVENT-FpQqK", "no objects found")
|
||||
return nil, errors.ThrowNotFound(nil, "EVENT-FpQqK", "no objects found")
|
||||
}
|
||||
|
||||
result := make([]*org_model.OrgChange, 0)
|
||||
@@ -277,3 +333,74 @@ func (es *OrgEventstore) RemoveOrgMember(ctx context.Context, member *org_model.
|
||||
orgAggregate := orgMemberRemovedAggregate(es.Eventstore.AggregateCreator(), repoMember)
|
||||
return es_sdk.Push(ctx, es.PushAggregates, repoMember.AppendEvents, orgAggregate)
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) GetOrgIamPolicy(ctx context.Context, orgID string) (*org_model.OrgIamPolicy, error) {
|
||||
existing, err := es.OrgByID(ctx, org_model.NewOrg(orgID))
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
return nil, err
|
||||
}
|
||||
if existing != nil && existing.OrgIamPolicy != nil {
|
||||
return existing.OrgIamPolicy, nil
|
||||
}
|
||||
return es.defaultOrgIamPolicy, nil
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) AddOrgIamPolicy(ctx context.Context, policy *org_model.OrgIamPolicy) (*org_model.OrgIamPolicy, error) {
|
||||
existing, err := es.OrgByID(ctx, org_model.NewOrg(policy.AggregateID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existing.OrgIamPolicy != nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-7Usj3", "Policy already exists")
|
||||
}
|
||||
repoOrg := model.OrgFromModel(existing)
|
||||
repoPolicy := model.OrgIamPolicyFromModel(policy)
|
||||
orgAggregate := OrgIamPolicyAddedAggregate(es.Eventstore.AggregateCreator(), repoOrg, repoPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoOrg.AppendEvents, orgAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return model.OrgIamPolicyToModel(repoOrg.OrgIamPolicy), nil
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) ChangeOrgIamPolicy(ctx context.Context, policy *org_model.OrgIamPolicy) (*org_model.OrgIamPolicy, error) {
|
||||
existing, err := es.OrgByID(ctx, org_model.NewOrg(policy.AggregateID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existing.OrgIamPolicy == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-8juSd", "Policy doesnt exist")
|
||||
}
|
||||
repoOrg := model.OrgFromModel(existing)
|
||||
repoPolicy := model.OrgIamPolicyFromModel(policy)
|
||||
orgAggregate := OrgIamPolicyChangedAggregate(es.Eventstore.AggregateCreator(), repoOrg, repoPolicy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoOrg.AppendEvents, orgAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return model.OrgIamPolicyToModel(repoOrg.OrgIamPolicy), nil
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) RemoveOrgIamPolicy(ctx context.Context, orgID string) error {
|
||||
existing, err := es.OrgByID(ctx, org_model.NewOrg(orgID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existing.OrgIamPolicy == nil {
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-z6Dse", "Policy doesnt exist")
|
||||
}
|
||||
repoOrg := model.OrgFromModel(existing)
|
||||
orgAggregate := OrgIamPolicyRemovedAggregate(es.Eventstore.AggregateCreator(), repoOrg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return es_sdk.Push(ctx, es.PushAggregates, repoOrg.AppendEvents, orgAggregate)
|
||||
}
|
||||
|
@@ -18,8 +18,7 @@ func GetMockedEventstoreComplexity(ctrl *gomock.Controller, mockEs *mock.MockEve
|
||||
|
||||
func GetMockChangesOrgOK(ctrl *gomock.Controller) *OrgEventstore {
|
||||
org := model.Org{
|
||||
Name: "MusterOrg",
|
||||
Domain: "myDomain",
|
||||
Name: "MusterOrg",
|
||||
}
|
||||
data, err := json.Marshal(org)
|
||||
if err != nil {
|
||||
|
@@ -1058,7 +1058,7 @@ func TestChangesOrg(t *testing.T) {
|
||||
},
|
||||
res: res{
|
||||
changes: &org_model.OrgChanges{Changes: []*org_model.OrgChange{&org_model.OrgChange{EventType: "", Sequence: 1, Modifier: ""}}, LastSequence: 1},
|
||||
org: &model.Org{Name: "MusterOrg", Domain: "myDomain"},
|
||||
org: &model.Org{Name: "MusterOrg"},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
120
internal/org/repository/eventsourcing/model/domain.go
Normal file
120
internal/org/repository/eventsourcing/model/domain.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/org/model"
|
||||
)
|
||||
|
||||
type OrgDomain struct {
|
||||
es_models.ObjectRoot `json:"-"`
|
||||
|
||||
Domain string `json:"domain"`
|
||||
Verified bool `json:"-"`
|
||||
Primary bool `json:"-"`
|
||||
}
|
||||
|
||||
func GetDomain(domains []*OrgDomain, domain string) (int, *OrgDomain) {
|
||||
for i, d := range domains {
|
||||
if d.Domain == domain {
|
||||
return i, d
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func (o *Org) appendAddDomainEvent(event *es_models.Event) error {
|
||||
domain := new(OrgDomain)
|
||||
err := domain.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domain.ObjectRoot.CreationDate = event.CreationDate
|
||||
o.Domains = append(o.Domains, domain)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Org) appendRemoveDomainEvent(event *es_models.Event) error {
|
||||
domain := new(OrgDomain)
|
||||
err := domain.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i, r := GetDomain(o.Domains, domain.Domain); r != nil {
|
||||
o.Domains[i] = o.Domains[len(o.Domains)-1]
|
||||
o.Domains[len(o.Domains)-1] = nil
|
||||
o.Domains = o.Domains[:len(o.Domains)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Org) appendVerifyDomainEvent(event *es_models.Event) error {
|
||||
domain := new(OrgDomain)
|
||||
err := domain.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i, d := GetDomain(o.Domains, domain.Domain); d != nil {
|
||||
d.Verified = true
|
||||
o.Domains[i] = d
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Org) appendPrimaryDomainEvent(event *es_models.Event) error {
|
||||
domain := new(OrgDomain)
|
||||
err := domain.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, d := range o.Domains {
|
||||
d.Primary = false
|
||||
if d.Domain == domain.Domain {
|
||||
d.Primary = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *OrgDomain) SetData(event *es_models.Event) error {
|
||||
err := json.Unmarshal(event.Data, m)
|
||||
if err != nil {
|
||||
return errors.ThrowInternal(err, "EVENT-Hz7Mb", "unable to unmarshal data")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func OrgDomainsFromModel(domains []*model.OrgDomain) []*OrgDomain {
|
||||
convertedDomainss := make([]*OrgDomain, len(domains))
|
||||
for i, m := range domains {
|
||||
convertedDomainss[i] = OrgDomainFromModel(m)
|
||||
}
|
||||
return convertedDomainss
|
||||
}
|
||||
|
||||
func OrgDomainFromModel(domain *model.OrgDomain) *OrgDomain {
|
||||
return &OrgDomain{
|
||||
ObjectRoot: domain.ObjectRoot,
|
||||
Domain: domain.Domain,
|
||||
Verified: domain.Verified,
|
||||
Primary: domain.Primary,
|
||||
}
|
||||
}
|
||||
|
||||
func OrgDomainsToModel(domains []*OrgDomain) []*model.OrgDomain {
|
||||
convertedDomains := make([]*model.OrgDomain, len(domains))
|
||||
for i, m := range domains {
|
||||
convertedDomains[i] = OrgDomainToModel(m)
|
||||
}
|
||||
return convertedDomains
|
||||
}
|
||||
|
||||
func OrgDomainToModel(domain *OrgDomain) *model.OrgDomain {
|
||||
return &model.OrgDomain{
|
||||
ObjectRoot: domain.ObjectRoot,
|
||||
Domain: domain.Domain,
|
||||
Verified: domain.Verified,
|
||||
Primary: domain.Primary,
|
||||
}
|
||||
}
|
@@ -14,33 +14,42 @@ const (
|
||||
type Org struct {
|
||||
es_models.ObjectRoot `json:"-"`
|
||||
|
||||
Name string `json:"name,omitempty"`
|
||||
Domain string `json:"domain,omitempty"`
|
||||
State int32 `json:"-"`
|
||||
Name string `json:"name,omitempty"`
|
||||
State int32 `json:"-"`
|
||||
|
||||
Members []*OrgMember `json:"-"`
|
||||
Domains []*OrgDomain `json:"-"`
|
||||
Members []*OrgMember `json:"-"`
|
||||
OrgIamPolicy *OrgIamPolicy `json:"-"`
|
||||
}
|
||||
|
||||
func OrgFromModel(org *org_model.Org) *Org {
|
||||
members := OrgMembersFromModel(org.Members)
|
||||
|
||||
return &Org{
|
||||
domains := OrgDomainsFromModel(org.Domains)
|
||||
converted := &Org{
|
||||
ObjectRoot: org.ObjectRoot,
|
||||
Domain: org.Domain,
|
||||
Name: org.Name,
|
||||
State: int32(org.State),
|
||||
Domains: domains,
|
||||
Members: members,
|
||||
}
|
||||
if org.OrgIamPolicy != nil {
|
||||
converted.OrgIamPolicy = OrgIamPolicyFromModel(org.OrgIamPolicy)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func OrgToModel(org *Org) *org_model.Org {
|
||||
return &org_model.Org{
|
||||
converted := &org_model.Org{
|
||||
ObjectRoot: org.ObjectRoot,
|
||||
Domain: org.Domain,
|
||||
Name: org.Name,
|
||||
State: org_model.OrgState(org.State),
|
||||
Domains: OrgDomainsToModel(org.Domains),
|
||||
Members: OrgMembersToModel(org.Members),
|
||||
}
|
||||
if org.OrgIamPolicy != nil {
|
||||
converted.OrgIamPolicy = OrgIamPolicyToModel(org.OrgIamPolicy)
|
||||
}
|
||||
return converted
|
||||
}
|
||||
|
||||
func OrgFromEvents(org *Org, events ...*es_models.Event) (*Org, error) {
|
||||
@@ -101,6 +110,20 @@ func (o *Org) AppendEvent(event *es_models.Event) error {
|
||||
return err
|
||||
}
|
||||
o.removeMember(member.UserID)
|
||||
case OrgDomainAdded:
|
||||
o.appendAddDomainEvent(event)
|
||||
case OrgDomainVerified:
|
||||
o.appendVerifyDomainEvent(event)
|
||||
case OrgDomainPrimarySet:
|
||||
o.appendPrimaryDomainEvent(event)
|
||||
case OrgDomainRemoved:
|
||||
o.appendRemoveDomainEvent(event)
|
||||
case OrgIamPolicyAdded:
|
||||
o.appendAddOrgIamPolicyEvent(event)
|
||||
case OrgIamPolicyChanged:
|
||||
o.appendChangeOrgIamPolicyEvent(event)
|
||||
case OrgIamPolicyRemoved:
|
||||
o.appendRemoveOrgIamPolicyEvent()
|
||||
}
|
||||
|
||||
o.ObjectRoot.AppendEvent(event)
|
||||
@@ -151,9 +174,6 @@ func (o *Org) Changes(changed *Org) map[string]interface{} {
|
||||
if changed.Name != "" && changed.Name != o.Name {
|
||||
changes["name"] = changed.Name
|
||||
}
|
||||
if changed.Domain != "" && changed.Domain != o.Domain {
|
||||
changes["domain"] = changed.Domain
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
@@ -0,0 +1,72 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"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"
|
||||
)
|
||||
|
||||
type OrgIamPolicy struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Description string `json:"description,omitempty"`
|
||||
State int32 `json:"-"`
|
||||
UserLoginMustBeDomain bool `json:"userLoginMustBeDomain"`
|
||||
}
|
||||
|
||||
func OrgIamPolicyToModel(policy *OrgIamPolicy) *org_model.OrgIamPolicy {
|
||||
return &org_model.OrgIamPolicy{
|
||||
ObjectRoot: policy.ObjectRoot,
|
||||
State: org_model.PolicyState(policy.State),
|
||||
UserLoginMustBeDomain: policy.UserLoginMustBeDomain,
|
||||
}
|
||||
}
|
||||
|
||||
func OrgIamPolicyFromModel(policy *org_model.OrgIamPolicy) *OrgIamPolicy {
|
||||
return &OrgIamPolicy{
|
||||
ObjectRoot: policy.ObjectRoot,
|
||||
State: int32(policy.State),
|
||||
UserLoginMustBeDomain: policy.UserLoginMustBeDomain,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Org) appendAddOrgIamPolicyEvent(event *es_models.Event) error {
|
||||
o.OrgIamPolicy = new(OrgIamPolicy)
|
||||
err := o.OrgIamPolicy.SetData(event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.OrgIamPolicy.ObjectRoot.CreationDate = event.CreationDate
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Org) appendChangeOrgIamPolicyEvent(event *es_models.Event) error {
|
||||
return o.OrgIamPolicy.SetData(event)
|
||||
}
|
||||
|
||||
func (o *Org) appendRemoveOrgIamPolicyEvent() {
|
||||
o.OrgIamPolicy = nil
|
||||
}
|
||||
|
||||
func (p *OrgIamPolicy) Changes(changed *OrgIamPolicy) map[string]interface{} {
|
||||
changes := make(map[string]interface{}, 2)
|
||||
|
||||
if changed.Description != p.Description {
|
||||
changes["description"] = changed.Description
|
||||
}
|
||||
if changed.UserLoginMustBeDomain != p.UserLoginMustBeDomain {
|
||||
changes["userLoginMustBeDomain"] = changed.UserLoginMustBeDomain
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
||||
|
||||
func (p *OrgIamPolicy) SetData(event *es_models.Event) error {
|
||||
err := json.Unmarshal(event.Data, p)
|
||||
if err != nil {
|
||||
return errors.ThrowInternal(err, "EVENT-7JS9d", "unable to unmarshal data")
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -74,10 +74,10 @@ func TestAppendEvent(t *testing.T) {
|
||||
{
|
||||
name: "append change event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgChanged, Data: []byte(`{"domain": "OrgDomain"}`)},
|
||||
org: &Org{Name: "OrgName", Domain: "asdf"},
|
||||
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgChanged, Data: []byte(`{"name": "OrgName}`)},
|
||||
org: &Org{Name: "OrgNameChanged"},
|
||||
},
|
||||
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE), Name: "OrgName", Domain: "OrgDomain"},
|
||||
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE), Name: "OrgNameChanged"},
|
||||
},
|
||||
{
|
||||
name: "append deactivate event",
|
||||
@@ -93,6 +93,13 @@ func TestAppendEvent(t *testing.T) {
|
||||
},
|
||||
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE)},
|
||||
},
|
||||
{
|
||||
name: "append added domain event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgDomainAdded},
|
||||
},
|
||||
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE)},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -138,16 +145,6 @@ func TestChanges(t *testing.T) {
|
||||
changesLen: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org domain changes",
|
||||
args: args{
|
||||
existing: &Org{Name: "Name", Domain: "old domain"},
|
||||
new: &Org{Name: "Name", Domain: "new domain"},
|
||||
},
|
||||
res: res{
|
||||
changesLen: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes",
|
||||
args: args{
|
@@ -7,11 +7,15 @@ const (
|
||||
OrgDomainAggregate models.AggregateType = "org.domain"
|
||||
OrgNameAggregate models.AggregateType = "org.name"
|
||||
|
||||
OrgAdded models.EventType = "org.added"
|
||||
OrgChanged models.EventType = "org.changed"
|
||||
OrgDeactivated models.EventType = "org.deactivated"
|
||||
OrgReactivated models.EventType = "org.reactivated"
|
||||
OrgRemoved models.EventType = "org.removed"
|
||||
OrgAdded models.EventType = "org.added"
|
||||
OrgChanged models.EventType = "org.changed"
|
||||
OrgDeactivated models.EventType = "org.deactivated"
|
||||
OrgReactivated models.EventType = "org.reactivated"
|
||||
OrgRemoved models.EventType = "org.removed"
|
||||
OrgDomainAdded models.EventType = "org.domain.added"
|
||||
OrgDomainVerified models.EventType = "org.domain.verified"
|
||||
OrgDomainRemoved models.EventType = "org.domain.removed"
|
||||
OrgDomainPrimarySet models.EventType = "org.domain.primary.set"
|
||||
|
||||
OrgNameReserved models.EventType = "org.name.reserved"
|
||||
OrgNameReleased models.EventType = "org.name.released"
|
||||
@@ -22,4 +26,8 @@ const (
|
||||
OrgMemberAdded models.EventType = "org.member.added"
|
||||
OrgMemberChanged models.EventType = "org.member.changed"
|
||||
OrgMemberRemoved models.EventType = "org.member.removed"
|
||||
|
||||
OrgIamPolicyAdded models.EventType = "org.iam.policy.added"
|
||||
OrgIamPolicyChanged models.EventType = "org.iam.policy.changed"
|
||||
OrgIamPolicyRemoved models.EventType = "org.iam.policy.removed"
|
||||
)
|
||||
|
@@ -47,16 +47,6 @@ func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCr
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-kdie7", "org should not be nil")
|
||||
}
|
||||
|
||||
domainAgrregate, err := uniqueDomainAggregate(ctx, aggCreator, org.AggregateID, org.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nameAggregate, err := uniqueNameAggregate(ctx, aggCreator, org.AggregateID, org.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
agg, err := aggCreator.NewAggregate(ctx, org.AggregateID, model.OrgAggregate, model.OrgVersion, org.Sequence, es_models.OverwriteResourceOwner(org.AggregateID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -65,12 +55,44 @@ func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCr
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates := make([]*es_models.Aggregate, 0)
|
||||
aggregates, err = addDomainAggregateAndEvents(ctx, aggCreator, agg, aggregates, org)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nameAggregate, err := reservedUniqueNameAggregate(ctx, aggCreator, org.AggregateID, org.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, nameAggregate)
|
||||
return append(aggregates, agg), nil
|
||||
}
|
||||
|
||||
return []*es_models.Aggregate{
|
||||
agg,
|
||||
domainAgrregate,
|
||||
nameAggregate,
|
||||
}, nil
|
||||
func addDomainAggregateAndEvents(ctx context.Context, aggCreator *es_models.AggregateCreator, orgAggregate *es_models.Aggregate, aggregates []*es_models.Aggregate, org *model.Org) ([]*es_models.Aggregate, error) {
|
||||
for _, domain := range org.Domains {
|
||||
orgAggregate, err := orgAggregate.AppendEvent(model.OrgDomainAdded, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if domain.Verified {
|
||||
domainAggregate, err := reservedUniqueDomainAggregate(ctx, aggCreator, org.AggregateID, domain.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, domainAggregate)
|
||||
orgAggregate, err = orgAggregate.AppendEvent(model.OrgDomainVerified, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if domain.Primary {
|
||||
orgAggregate, err = orgAggregate.AppendEvent(model.OrgDomainPrimarySet, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return aggregates, nil
|
||||
}
|
||||
|
||||
func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.Org, updated *model.Org) ([]*es_models.Aggregate, error) {
|
||||
@@ -88,19 +110,16 @@ func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCre
|
||||
aggregates := make([]*es_models.Aggregate, 0, 3)
|
||||
|
||||
if name, ok := changes["name"]; ok {
|
||||
nameAggregate, err := uniqueNameAggregate(ctx, aggCreator, "", name.(string))
|
||||
nameAggregate, err := reservedUniqueNameAggregate(ctx, aggCreator, "", name.(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, nameAggregate)
|
||||
}
|
||||
|
||||
if name, ok := changes["domain"]; ok {
|
||||
domainAggregate, err := uniqueDomainAggregate(ctx, aggCreator, "", name.(string))
|
||||
nameReleasedAggregate, err := releasedUniqueNameAggregate(ctx, aggCreator, "", existing.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, domainAggregate)
|
||||
aggregates = append(aggregates, nameReleasedAggregate)
|
||||
}
|
||||
|
||||
orgAggregate, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
@@ -151,7 +170,7 @@ func orgReactivateAggregate(aggCreator *es_models.AggregateCreator, org *model.O
|
||||
}
|
||||
}
|
||||
|
||||
func uniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, domain string) (*es_models.Aggregate, error) {
|
||||
func reservedUniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, domain string) (*es_models.Aggregate, error) {
|
||||
aggregate, err := aggCreator.NewAggregate(ctx, domain, model.OrgDomainAggregate, model.OrgVersion, 0)
|
||||
if resourceOwner != "" {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, domain, model.OrgDomainAggregate, model.OrgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
|
||||
@@ -164,10 +183,26 @@ func uniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateC
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return aggregate.SetPrecondition(OrgDomainUniqueQuery(domain), isReservedValidation(aggregate, model.OrgDomainReserved)), nil
|
||||
return aggregate.SetPrecondition(OrgDomainUniqueQuery(domain), isEventValidation(aggregate, model.OrgDomainReserved)), nil
|
||||
}
|
||||
|
||||
func uniqueNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, name string) (aggregate *es_models.Aggregate, err error) {
|
||||
func releasedUniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, domain string) (*es_models.Aggregate, error) {
|
||||
aggregate, err := aggCreator.NewAggregate(ctx, domain, model.OrgDomainAggregate, model.OrgVersion, 0)
|
||||
if resourceOwner != "" {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, domain, model.OrgDomainAggregate, model.OrgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregate, err = aggregate.AppendEvent(model.OrgDomainReleased, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return aggregate.SetPrecondition(OrgDomainUniqueQuery(domain), isEventValidation(aggregate, model.OrgDomainReleased)), nil
|
||||
}
|
||||
|
||||
func reservedUniqueNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, name string) (aggregate *es_models.Aggregate, err error) {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, name, model.OrgNameAggregate, model.OrgVersion, 0)
|
||||
if resourceOwner != "" {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, name, model.OrgNameAggregate, model.OrgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
|
||||
@@ -180,17 +215,103 @@ func uniqueNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCre
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return aggregate.SetPrecondition(OrgNameUniqueQuery(name), isReservedValidation(aggregate, model.OrgNameReserved)), nil
|
||||
return aggregate.SetPrecondition(OrgNameUniqueQuery(name), isEventValidation(aggregate, model.OrgNameReserved)), nil
|
||||
}
|
||||
|
||||
func isReservedValidation(aggregate *es_models.Aggregate, resevedEventType es_models.EventType) func(...*es_models.Event) error {
|
||||
func releasedUniqueNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, name string) (aggregate *es_models.Aggregate, err error) {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, name, model.OrgNameAggregate, model.OrgVersion, 0)
|
||||
if resourceOwner != "" {
|
||||
aggregate, err = aggCreator.NewAggregate(ctx, name, model.OrgNameAggregate, model.OrgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregate, err = aggregate.AppendEvent(model.OrgNameReleased, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return aggregate.SetPrecondition(OrgNameUniqueQuery(name), isEventValidation(aggregate, model.OrgNameReleased)), nil
|
||||
}
|
||||
|
||||
func OrgDomainAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org, domain *model.OrgDomain) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if domain == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-OSid3", "domain should not be nil")
|
||||
}
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.OrgDomainAdded, domain)
|
||||
}
|
||||
}
|
||||
|
||||
func OrgDomainVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org, domain *model.OrgDomain) func(ctx context.Context) ([]*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) ([]*es_models.Aggregate, error) {
|
||||
if domain == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-DHs7s", "domain should not be nil")
|
||||
}
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates := make([]*es_models.Aggregate, 0, 2)
|
||||
agg, err = agg.AppendEvent(model.OrgDomainVerified, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainAgregate, err := reservedUniqueDomainAggregate(ctx, aggCreator, existing.AggregateID, domain.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, domainAgregate)
|
||||
return append(aggregates, agg), nil
|
||||
}
|
||||
}
|
||||
|
||||
func OrgDomainSetPrimaryAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org, domain *model.OrgDomain) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if domain == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-PSw3j", "domain should not be nil")
|
||||
}
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.OrgDomainPrimarySet, domain)
|
||||
}
|
||||
}
|
||||
|
||||
func OrgDomainRemovedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.Org, domain *model.OrgDomain) ([]*es_models.Aggregate, error) {
|
||||
if domain == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-si8dW", "domain should not be nil")
|
||||
}
|
||||
aggregates := make([]*es_models.Aggregate, 0, 2)
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
agg, err = agg.AppendEvent(model.OrgDomainRemoved, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, agg)
|
||||
domainAgregate, err := releasedUniqueDomainAggregate(ctx, aggCreator, existing.AggregateID, domain.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(aggregates, domainAgregate), nil
|
||||
}
|
||||
|
||||
func isEventValidation(aggregate *es_models.Aggregate, eventType es_models.EventType) func(...*es_models.Event) error {
|
||||
return func(events ...*es_models.Event) error {
|
||||
if len(events) == 0 {
|
||||
aggregate.PreviousSequence = 0
|
||||
return nil
|
||||
}
|
||||
if events[0].Type == resevedEventType {
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-eJQqe", "org already reseved")
|
||||
if events[0].Type == eventType {
|
||||
return errors.ThrowPreconditionFailedf(nil, "EVENT-eJQqe", "user is already %v", eventType)
|
||||
}
|
||||
aggregate.PreviousSequence = events[0].Sequence
|
||||
return nil
|
||||
|
48
internal/org/repository/eventsourcing/org_iam_policy.go
Normal file
48
internal/org/repository/eventsourcing/org_iam_policy.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package eventsourcing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
)
|
||||
|
||||
func OrgIamPolicyAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org, policy *model.OrgIamPolicy) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if policy == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-i9sJS", "policy should not be nil")
|
||||
}
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.OrgIamPolicyAdded, policy)
|
||||
}
|
||||
}
|
||||
|
||||
func OrgIamPolicyChangedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org, policy *model.OrgIamPolicy) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if policy == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-9Ksie", "policy should not be nil")
|
||||
}
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes := existing.OrgIamPolicy.Changes(policy)
|
||||
if len(changes) == 0 {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Js6Vs", "no changes")
|
||||
}
|
||||
return agg.AppendEvent(model.OrgIamPolicyChanged, changes)
|
||||
}
|
||||
}
|
||||
|
||||
func OrgIamPolicyRemovedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Org) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.OrgIamPolicyRemoved, nil)
|
||||
}
|
||||
}
|
237
internal/org/repository/eventsourcing/org_iam_policy_test.go
Normal file
237
internal/org/repository/eventsourcing/org_iam_policy_test.go
Normal file
@@ -0,0 +1,237 @@
|
||||
package eventsourcing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOrgIamPolicyAddedAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
eventsCount int
|
||||
eventType es_models.EventType
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
policy *model.OrgIamPolicy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no policy error",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "policy successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
},
|
||||
policy: &model.OrgIamPolicy{
|
||||
Description: "description",
|
||||
UserLoginMustBeDomain: true,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
eventsCount: 1,
|
||||
eventType: model.OrgIamPolicyAdded,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg := OrgIamPolicyAddedAggregate(tt.args.aggCreator, tt.args.org, tt.args.policy)
|
||||
got, err := agg(tt.args.ctx)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr == nil && got.Events[0].Type != tt.res.eventType {
|
||||
t.Errorf("OrgIamPolicyAddedAggregate() event type = %v, wanted count %v", got.Events[0].Type, tt.res.eventType)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got.Events) != tt.res.eventsCount {
|
||||
t.Errorf("OrgIamPolicyAddedAggregate() event count = %d, wanted count %d", len(got.Events), tt.res.eventsCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrgIamPolicyChangedAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
eventsCount int
|
||||
eventType es_models.EventType
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
policy *model.OrgIamPolicy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no policy error",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "policy successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
OrgIamPolicy: &model.OrgIamPolicy{
|
||||
Description: "description",
|
||||
UserLoginMustBeDomain: true,
|
||||
},
|
||||
},
|
||||
policy: &model.OrgIamPolicy{
|
||||
Description: "description",
|
||||
UserLoginMustBeDomain: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
eventsCount: 1,
|
||||
eventType: model.OrgIamPolicyChanged,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "policy no changes",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
OrgIamPolicy: &model.OrgIamPolicy{
|
||||
Description: "description",
|
||||
UserLoginMustBeDomain: true,
|
||||
},
|
||||
},
|
||||
policy: &model.OrgIamPolicy{
|
||||
Description: "description",
|
||||
UserLoginMustBeDomain: true,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg := OrgIamPolicyChangedAggregate(tt.args.aggCreator, tt.args.org, tt.args.policy)
|
||||
got, err := agg(tt.args.ctx)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr == nil && got.Events[0].Type != tt.res.eventType {
|
||||
t.Errorf("OrgIamPolicyChangedAggregate() event type = %v, wanted count %v", got.Events[0].Type, tt.res.eventType)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got.Events) != tt.res.eventsCount {
|
||||
t.Errorf("OrgIamPolicyChangedAggregate() event count = %d, wanted count %d", len(got.Events), tt.res.eventsCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrgIamPolicyRemovedAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
eventsCount int
|
||||
eventType es_models.EventType
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "policy successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
OrgIamPolicy: &model.OrgIamPolicy{
|
||||
Description: "description",
|
||||
UserLoginMustBeDomain: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
eventsCount: 1,
|
||||
eventType: model.OrgIamPolicyRemoved,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg := OrgIamPolicyRemovedAggregate(tt.args.aggCreator, tt.args.org)
|
||||
got, err := agg(tt.args.ctx)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr == nil && got.Events[0].Type != tt.res.eventType {
|
||||
t.Errorf("OrgIamPolicyChangedAggregate() event type = %v, wanted count %v", got.Events[0].Type, tt.res.eventType)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got.Events) != tt.res.eventsCount {
|
||||
t.Errorf("OrgIamPolicyChangedAggregate() event count = %d, wanted count %d", len(got.Events), tt.res.eventsCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -79,7 +79,7 @@ func Test_isReservedValidation(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
validate := isReservedValidation(tt.args.aggregate, tt.args.eventType)
|
||||
validate := isEventValidation(tt.args.aggregate, tt.args.eventType)
|
||||
|
||||
err := validate(tt.args.Events...)
|
||||
|
||||
@@ -142,7 +142,7 @@ func Test_uniqueNameAggregate(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := uniqueNameAggregate(tt.args.ctx, tt.args.aggCreator, "", tt.args.orgName)
|
||||
got, err := reservedUniqueNameAggregate(tt.args.ctx, tt.args.aggCreator, "", tt.args.orgName)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got: %v", err)
|
||||
}
|
||||
@@ -198,7 +198,7 @@ func Test_uniqueDomainAggregate(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := uniqueDomainAggregate(tt.args.ctx, tt.args.aggCreator, "", tt.args.orgDomain)
|
||||
got, err := reservedUniqueDomainAggregate(tt.args.ctx, tt.args.aggCreator, "", tt.args.orgDomain)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got: %v", err)
|
||||
}
|
||||
@@ -425,47 +425,18 @@ func TestOrgUpdateAggregates(t *testing.T) {
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
Domain: "caos.ch",
|
||||
Name: "coas",
|
||||
Name: "coas",
|
||||
},
|
||||
updated: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
Domain: "caos.ch",
|
||||
Name: "caos",
|
||||
Name: "caos",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 2,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "domain changed",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
existing: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
Domain: "caos.swiss",
|
||||
Name: "caos",
|
||||
},
|
||||
updated: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
Domain: "caos.ch",
|
||||
Name: "caos",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 2,
|
||||
aggregateCount: 3,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
@@ -523,17 +494,16 @@ func TestOrgCreatedAggregates(t *testing.T) {
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
Domain: "caos.ch",
|
||||
Name: "caos",
|
||||
Name: "caos",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 3,
|
||||
aggregateCount: 2,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no domain error",
|
||||
name: "org with domain successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
@@ -543,11 +513,14 @@ func TestOrgCreatedAggregates(t *testing.T) {
|
||||
Sequence: 5,
|
||||
},
|
||||
Name: "caos",
|
||||
Domains: []*model.OrgDomain{&model.OrgDomain{
|
||||
Domain: "caos.ch",
|
||||
}},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 2,
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -560,7 +533,6 @@ func TestOrgCreatedAggregates(t *testing.T) {
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
Domain: "caos.ch",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@@ -584,3 +556,270 @@ func TestOrgCreatedAggregates(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrgDomainAddedAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
eventCount int
|
||||
eventType es_models.EventType
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
domain *model.OrgDomain
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no domain error",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "domain successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
},
|
||||
domain: &model.OrgDomain{
|
||||
Domain: "caos.ch",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
eventCount: 1,
|
||||
eventType: model.OrgDomainAdded,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg := OrgDomainAddedAggregate(tt.args.aggCreator, tt.args.org, tt.args.domain)
|
||||
got, err := agg(tt.args.ctx)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
|
||||
if tt.res.isErr == nil && got.Events[0].Type != tt.res.eventType {
|
||||
t.Errorf("OrgDomainAddedAggregate() event type = %v, wanted count %v", got.Events[0].Type, tt.res.eventType)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got.Events) != tt.res.eventCount {
|
||||
t.Errorf("OrgDomainAddedAggregate() event count = %v, wanted count %v", len(got.Events), tt.res.eventCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrgDomainVerifiedAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
aggregateCount int
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
domain *model.OrgDomain
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no domain error",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "domain successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
},
|
||||
domain: &model.OrgDomain{
|
||||
Domain: "caos.ch",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 2,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg := OrgDomainVerifiedAggregate(tt.args.aggCreator, tt.args.org, tt.args.domain)
|
||||
got, err := agg(tt.args.ctx)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got) != tt.res.aggregateCount {
|
||||
t.Errorf("OrgDomainVerifiedAggregate() aggregate count = %d, wanted count %d", len(got), tt.res.aggregateCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrgDomainSetPrimaryAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
eventsCount int
|
||||
eventType es_models.EventType
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
domain *model.OrgDomain
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no domain error",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "domain successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
},
|
||||
domain: &model.OrgDomain{
|
||||
Domain: "caos.ch",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
eventsCount: 1,
|
||||
eventType: model.OrgDomainPrimarySet,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg := OrgDomainSetPrimaryAggregate(tt.args.aggCreator, tt.args.org, tt.args.domain)
|
||||
got, err := agg(tt.args.ctx)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr == nil && got.Events[0].Type != tt.res.eventType {
|
||||
t.Errorf("OrgDomainSetPrimaryAggregate() event type = %v, wanted count %v", got.Events[0].Type, tt.res.eventType)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got.Events) != tt.res.eventsCount {
|
||||
t.Errorf("OrgDomainSetPrimaryAggregate() event count = %d, wanted count %d", len(got.Events), tt.res.eventsCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrgDomainRemovedAggregates(t *testing.T) {
|
||||
type res struct {
|
||||
aggregateCount int
|
||||
isErr func(error) bool
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
domain *model.OrgDomain
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "no domain error",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 0,
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "domain successful",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
},
|
||||
domain: &model.OrgDomain{
|
||||
Domain: "caos.ch",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
aggregateCount: 2,
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := OrgDomainRemovedAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.org, tt.args.domain)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr != nil && !tt.res.isErr(err) {
|
||||
t.Errorf("wrong error got %T: %v", err, err)
|
||||
}
|
||||
if tt.res.isErr == nil && len(got) != tt.res.aggregateCount {
|
||||
t.Errorf("OrgDomainRemovedAggregate() aggregate count = %d, wanted count %d", len(got), tt.res.aggregateCount)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user