Files
zitadel/internal/command/organization_settings_model.go

246 lines
7.2 KiB
Go
Raw Normal View History

package command
import (
"context"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/org"
settings "github.com/zitadel/zitadel/internal/repository/organization_settings"
"github.com/zitadel/zitadel/internal/repository/user"
"github.com/zitadel/zitadel/internal/zerrors"
)
type OrganizationSettingsWriteModel struct {
eventstore.WriteModel
OrganizationScopedUsernames bool
OrganizationState domain.OrgState
State domain.OrganizationSettingsState
checkPermission domain.PermissionCheck
}
func (wm *OrganizationSettingsWriteModel) GetWriteModel() *eventstore.WriteModel {
return &wm.WriteModel
}
func (wm *OrganizationSettingsWriteModel) checkPermissionWrite(
ctx context.Context,
resourceOwner string,
aggregateID string,
) error {
if wm.checkPermission == nil {
return zerrors.ThrowPermissionDenied(nil, "COMMAND-8Dttuyj0B4", "Permission check not defined")
}
return wm.checkPermission(ctx, domain.PermissionIAMPolicyWrite, resourceOwner, aggregateID)
}
func (wm *OrganizationSettingsWriteModel) checkPermissionDelete(
ctx context.Context,
resourceOwner string,
aggregateID string,
) error {
if wm.checkPermission == nil {
return zerrors.ThrowPermissionDenied(nil, "COMMAND-6R54f4vWqv", "Permission check not defined")
}
return wm.checkPermission(ctx, domain.PermissionIAMPolicyDelete, resourceOwner, aggregateID)
}
func NewOrganizationSettingsWriteModel(id string, checkPermission domain.PermissionCheck) *OrganizationSettingsWriteModel {
return &OrganizationSettingsWriteModel{
WriteModel: eventstore.WriteModel{
AggregateID: id,
ResourceOwner: id,
},
checkPermission: checkPermission,
}
}
func (wm *OrganizationSettingsWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *settings.OrganizationSettingsSetEvent:
wm.OrganizationScopedUsernames = e.OrganizationScopedUsernames
wm.State = domain.OrganizationSettingsStateActive
case *settings.OrganizationSettingsRemovedEvent:
wm.OrganizationScopedUsernames = false
wm.State = domain.OrganizationSettingsStateRemoved
case *org.OrgAddedEvent:
wm.OrganizationState = domain.OrgStateActive
wm.OrganizationScopedUsernames = false
case *org.OrgRemovedEvent:
wm.OrganizationState = domain.OrgStateRemoved
wm.OrganizationScopedUsernames = false
}
}
return wm.WriteModel.Reduce()
}
func (wm *OrganizationSettingsWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
ResourceOwner(wm.ResourceOwner).
AddQuery().
AggregateTypes(settings.AggregateType).
AggregateIDs(wm.AggregateID).
EventTypes(settings.OrganizationSettingsSetEventType,
settings.OrganizationSettingsRemovedEventType).
Or().
AggregateTypes(org.AggregateType).
AggregateIDs(wm.AggregateID).
EventTypes(org.OrgAddedEventType,
org.OrgRemovedEventType).
Builder()
}
func (wm *OrganizationSettingsWriteModel) NewSet(
ctx context.Context,
organizationScopedUsernames *bool,
userLoginMustBeDomain bool,
usernamesF func(ctx context.Context, orgID string) ([]string, error),
) (_ []eventstore.Command, err error) {
if err := wm.checkPermissionWrite(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
return nil, err
}
// no changes
if organizationScopedUsernames == nil || *organizationScopedUsernames == wm.OrganizationScopedUsernames {
return nil, nil
}
var usernames []string
if (wm.OrganizationScopedUsernames || userLoginMustBeDomain) != (*organizationScopedUsernames || userLoginMustBeDomain) {
usernames, err = usernamesF(ctx, wm.AggregateID)
if err != nil {
return nil, err
}
}
events := []eventstore.Command{
settings.NewOrganizationSettingsAddedEvent(ctx,
SettingsAggregateFromWriteModel(&wm.WriteModel),
usernames,
*organizationScopedUsernames || userLoginMustBeDomain,
wm.OrganizationScopedUsernames || userLoginMustBeDomain,
),
}
return events, nil
}
func (wm *OrganizationSettingsWriteModel) NewRemoved(
ctx context.Context,
userLoginMustBeDomain bool,
usernamesF func(ctx context.Context, orgID string) ([]string, error),
) (_ []eventstore.Command, err error) {
if err := wm.checkPermissionDelete(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
return nil, err
}
var usernames []string
if userLoginMustBeDomain != wm.OrganizationScopedUsernames {
usernames, err = usernamesF(ctx, wm.AggregateID)
if err != nil {
return nil, err
}
}
events := []eventstore.Command{
settings.NewOrganizationSettingsRemovedEvent(ctx,
SettingsAggregateFromWriteModel(&wm.WriteModel),
usernames,
userLoginMustBeDomain,
wm.OrganizationScopedUsernames || userLoginMustBeDomain,
),
}
return events, nil
}
func SettingsAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregate {
return &eventstore.Aggregate{
ID: wm.AggregateID,
Type: settings.AggregateType,
ResourceOwner: wm.ResourceOwner,
InstanceID: wm.InstanceID,
Version: settings.AggregateVersion,
}
}
type OrganizationScopedUsernamesWriteModel struct {
eventstore.WriteModel
Users []*organizationScopedUser
}
type organizationScopedUser struct {
id string
username string
}
func NewOrganizationScopedUsernamesWriteModel(orgID string) *OrganizationScopedUsernamesWriteModel {
return &OrganizationScopedUsernamesWriteModel{
WriteModel: eventstore.WriteModel{
ResourceOwner: orgID,
},
Users: make([]*organizationScopedUser, 0),
}
}
func (wm *OrganizationScopedUsernamesWriteModel) AppendEvents(events ...eventstore.Event) {
wm.WriteModel.AppendEvents(events...)
}
func (wm *OrganizationScopedUsernamesWriteModel) Reduce() error {
for _, event := range wm.Events {
switch e := event.(type) {
case *user.HumanAddedEvent:
wm.Users = append(wm.Users, &organizationScopedUser{id: e.Aggregate().ID, username: e.UserName})
case *user.HumanRegisteredEvent:
wm.Users = append(wm.Users, &organizationScopedUser{id: e.Aggregate().ID, username: e.UserName})
case *user.MachineAddedEvent:
wm.Users = append(wm.Users, &organizationScopedUser{id: e.Aggregate().ID, username: e.UserName})
case *user.UsernameChangedEvent:
for _, user := range wm.Users {
if user.id == e.Aggregate().ID {
user.username = e.UserName
break
}
}
case *user.DomainClaimedEvent:
for _, user := range wm.Users {
if user.id == e.Aggregate().ID {
user.username = e.UserName
break
}
}
case *user.UserRemovedEvent:
wm.removeUser(e.Aggregate().ID)
}
}
return wm.WriteModel.Reduce()
}
func (wm *OrganizationScopedUsernamesWriteModel) removeUser(userID string) {
for i, user := range wm.Users {
if user.id == userID {
wm.Users[i] = wm.Users[len(wm.Users)-1]
wm.Users[len(wm.Users)-1] = nil
wm.Users = wm.Users[:len(wm.Users)-1]
return
}
}
}
func (wm *OrganizationScopedUsernamesWriteModel) Query() *eventstore.SearchQueryBuilder {
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
ResourceOwner(wm.ResourceOwner).
AddQuery().
AggregateTypes(user.AggregateType).
EventTypes(
user.HumanAddedType,
user.HumanRegisteredType,
user.MachineAddedEventType,
user.UserUserNameChangedType,
user.UserDomainClaimedType,
user.UserRemovedType,
).
Builder()
}