fix: no project owner at project creation and cleanup (#9317)

# Which Problems Are Solved

Project creation always requires a user as project owner, in case of a
system user creating the project, there is no valid user existing at
that moment.

# How the Problems Are Solved

Remove the initially created project owner membership, as this is
something which was necessary in old versions, and all should work
perfectly without.
The call to add a project automatically designates the calling user as
the project owner, which is irrelevant currently, as this user always
already has higher permissions to be able to even create the project.

# Additional Changes

Cleanup of the existing checks for the project, which can be improved
through the usage of the fields table.

# Additional Context

Closes #9182
This commit is contained in:
Stefan Benz 2025-02-12 12:48:28 +01:00 committed by GitHub
parent bcc6a689fa
commit 0ea42f1ddf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 87 additions and 273 deletions

View File

@ -177,8 +177,7 @@ func (s *Server) ListProjectChanges(ctx context.Context, req *mgmt_pb.ListProjec
} }
func (s *Server) AddProject(ctx context.Context, req *mgmt_pb.AddProjectRequest) (*mgmt_pb.AddProjectResponse, error) { func (s *Server) AddProject(ctx context.Context, req *mgmt_pb.AddProjectRequest) (*mgmt_pb.AddProjectResponse, error) {
ctxData := authz.GetCtxData(ctx) project, err := s.command.AddProject(ctx, ProjectCreateToDomain(req), authz.GetCtxData(ctx).OrgID)
project, err := s.command.AddProject(ctx, ProjectCreateToDomain(req), ctxData.OrgID, ctxData.UserID)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -50,11 +50,6 @@ func projectAddedEvents(ctx context.Context, instanceID, orgID, id, owner string
false, false,
domain.PrivateLabelingSettingUnspecified, domain.PrivateLabelingSettingUnspecified,
), ),
project.NewProjectMemberAddedEvent(ctx,
&project.NewAggregate(id, orgID).Aggregate,
owner,
domain.RoleProjectOwner,
),
instance.NewIAMProjectSetEvent(ctx, instance.NewIAMProjectSetEvent(ctx,
&instance.NewAggregate(instanceID).Aggregate, &instance.NewAggregate(instanceID).Aggregate,
id, id,

View File

@ -26,13 +26,8 @@ func (c *Commands) AddProjectWithID(ctx context.Context, project *domain.Project
if projectID == "" { if projectID == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-nDXf5vXoUj", "Errors.IDMissing") return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-nDXf5vXoUj", "Errors.IDMissing")
} }
if !project.IsValid() {
existingProject, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner) return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid")
if err != nil {
return nil, err
}
if existingProject.State != domain.ProjectStateUnspecified {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-opamwu", "Errors.Project.AlreadyExisting")
} }
project, err = c.addProjectWithID(ctx, project, resourceOwner, projectID) project, err = c.addProjectWithID(ctx, project, resourceOwner, projectID)
if err != nil { if err != nil {
@ -41,23 +36,22 @@ func (c *Commands) AddProjectWithID(ctx context.Context, project *domain.Project
return project, nil return project, nil
} }
func (c *Commands) AddProject(ctx context.Context, project *domain.Project, resourceOwner, ownerUserID string) (_ *domain.Project, err error) { func (c *Commands) AddProject(ctx context.Context, project *domain.Project, resourceOwner string) (_ *domain.Project, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
if !project.IsValid() { if !project.IsValid() {
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid") return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid")
} }
if resourceOwner == "" { if resourceOwner == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-fmq7bqQX1s", "Errors.ResourceOwnerMissing") return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-fmq7bqQX1s", "Errors.ResourceOwnerMissing")
} }
if ownerUserID == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-xe95Gl3Dro", "Errors.IDMissing")
}
projectID, err := c.idGenerator.Next() projectID, err := c.idGenerator.Next()
if err != nil { if err != nil {
return nil, err return nil, err
} }
project, err = c.addProjectWithIDWithOwner(ctx, project, resourceOwner, ownerUserID, projectID) project, err = c.addProjectWithID(ctx, project, resourceOwner, projectID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -66,13 +60,19 @@ func (c *Commands) AddProject(ctx context.Context, project *domain.Project, reso
func (c *Commands) addProjectWithID(ctx context.Context, projectAdd *domain.Project, resourceOwner, projectID string) (_ *domain.Project, err error) { func (c *Commands) addProjectWithID(ctx context.Context, projectAdd *domain.Project, resourceOwner, projectID string) (_ *domain.Project, err error) {
projectAdd.AggregateID = projectID projectAdd.AggregateID = projectID
addedProject := NewProjectWriteModel(projectAdd.AggregateID, resourceOwner) projectWriteModel, err := c.getProjectWriteModelByID(ctx, projectAdd.AggregateID, resourceOwner)
projectAgg := ProjectAggregateFromWriteModel(&addedProject.WriteModel) if err != nil {
return nil, err
}
if isProjectStateExists(projectWriteModel.State) {
return nil, zerrors.ThrowAlreadyExists(nil, "COMMAND-opamwu", "Errors.Project.AlreadyExisting")
}
events := []eventstore.Command{ events := []eventstore.Command{
project.NewProjectAddedEvent( project.NewProjectAddedEvent(
ctx, ctx,
projectAgg, //nolint: contextcheck
ProjectAggregateFromWriteModel(&projectWriteModel.WriteModel),
projectAdd.Name, projectAdd.Name,
projectAdd.ProjectRoleAssertion, projectAdd.ProjectRoleAssertion,
projectAdd.ProjectRoleCheck, projectAdd.ProjectRoleCheck,
@ -88,47 +88,11 @@ func (c *Commands) addProjectWithID(ctx context.Context, projectAdd *domain.Proj
return nil, err return nil, err
} }
postCommit(ctx) postCommit(ctx)
err = AppendAndReduce(addedProject, pushedEvents...) err = AppendAndReduce(projectWriteModel, pushedEvents...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return projectWriteModelToProject(addedProject), nil return projectWriteModelToProject(projectWriteModel), nil
}
func (c *Commands) addProjectWithIDWithOwner(ctx context.Context, projectAdd *domain.Project, resourceOwner, ownerUserID, projectID string) (_ *domain.Project, err error) {
if !projectAdd.IsValid() {
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid")
}
projectAdd.AggregateID = projectID
addedProject := NewProjectWriteModel(projectAdd.AggregateID, resourceOwner)
projectAgg := ProjectAggregateFromWriteModel(&addedProject.WriteModel)
projectRole := domain.RoleProjectOwner
events := []eventstore.Command{
project.NewProjectAddedEvent(
ctx,
projectAgg,
projectAdd.Name,
projectAdd.ProjectRoleAssertion,
projectAdd.ProjectRoleCheck,
projectAdd.HasProjectCheck,
projectAdd.PrivateLabelingSetting),
project.NewProjectMemberAddedEvent(ctx, projectAgg, ownerUserID, projectRole),
}
postCommit, err := c.projectCreatedMilestone(ctx, &events)
if err != nil {
return nil, err
}
pushedEvents, err := c.eventstore.Push(ctx, events...)
if err != nil {
return nil, err
}
postCommit(ctx)
err = AppendAndReduce(addedProject, pushedEvents...)
if err != nil {
return nil, err
}
return projectWriteModelToProject(addedProject), nil
} }
func AddProjectCommand( func AddProjectCommand(
@ -159,9 +123,6 @@ func AddProjectCommand(
hasProjectCheck, hasProjectCheck,
privateLabelingSetting, privateLabelingSetting,
), ),
project.NewProjectMemberAddedEvent(ctx, &a.Aggregate,
owner,
domain.RoleProjectOwner),
}, nil }, nil
}, nil }, nil
} }
@ -182,20 +143,6 @@ func projectWriteModel(ctx context.Context, filter preparation.FilterToQueryRedu
return project, nil return project, nil
} }
func (c *Commands) getProjectByID(ctx context.Context, projectID, resourceOwner string) (_ *domain.Project, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
projectWriteModel, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner)
if err != nil {
return nil, err
}
if projectWriteModel.State == domain.ProjectStateUnspecified || projectWriteModel.State == domain.ProjectStateRemoved {
return nil, zerrors.ThrowNotFound(nil, "PROJECT-Gd2hh", "Errors.Project.NotFound")
}
return projectWriteModelToProject(projectWriteModel), nil
}
func (c *Commands) projectAggregateByID(ctx context.Context, projectID, resourceOwner string) (*eventstore.Aggregate, domain.ProjectState, error) { func (c *Commands) projectAggregateByID(ctx context.Context, projectID, resourceOwner string) (*eventstore.Aggregate, domain.ProjectState, error) {
result, err := c.projectState(ctx, projectID, resourceOwner) result, err := c.projectState(ctx, projectID, resourceOwner)
if err != nil { if err != nil {
@ -250,15 +197,11 @@ func (c *Commands) ChangeProject(ctx context.Context, projectChange *domain.Proj
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.Invalid") return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.Invalid")
} }
if !authz.GetFeatures(ctx).ShouldUseImprovedPerformance(feature.ImprovedPerformanceTypeProject) {
return c.changeProjectOld(ctx, projectChange, resourceOwner)
}
existingProject, err := c.getProjectWriteModelByID(ctx, projectChange.AggregateID, resourceOwner) existingProject, err := c.getProjectWriteModelByID(ctx, projectChange.AggregateID, resourceOwner)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved { if !isProjectStateExists(existingProject.State) {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound") return nil, zerrors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
} }
@ -277,11 +220,7 @@ func (c *Commands) ChangeProject(ctx context.Context, projectChange *domain.Proj
if !hasChanged { if !hasChanged {
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-2M0fs", "Errors.NoChangesFound") return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-2M0fs", "Errors.NoChangesFound")
} }
pushedEvents, err := c.eventstore.Push(ctx, changedEvent) err = c.pushAppendAndReduce(ctx, existingProject, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingProject, pushedEvents...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -302,7 +241,7 @@ func (c *Commands) DeactivateProject(ctx context.Context, projectID string, reso
return nil, err return nil, err
} }
if state == domain.ProjectStateUnspecified || state == domain.ProjectStateRemoved { if !isProjectStateExists(state) {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-112M9", "Errors.Project.NotFound") return nil, zerrors.ThrowNotFound(nil, "COMMAND-112M9", "Errors.Project.NotFound")
} }
if state != domain.ProjectStateActive { if state != domain.ProjectStateActive {
@ -314,17 +253,6 @@ func (c *Commands) DeactivateProject(ctx context.Context, projectID string, reso
return nil, err return nil, err
} }
existingProject, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner)
if err != nil {
return nil, err
}
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-112M9", "Errors.Project.NotFound")
}
if existingProject.State != domain.ProjectStateActive {
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-mki55", "Errors.Project.NotActive")
}
return &domain.ObjectDetails{ return &domain.ObjectDetails{
ResourceOwner: pushedEvents[0].Aggregate().ResourceOwner, ResourceOwner: pushedEvents[0].Aggregate().ResourceOwner,
Sequence: pushedEvents[0].Sequence(), Sequence: pushedEvents[0].Sequence(),
@ -346,25 +274,13 @@ func (c *Commands) ReactivateProject(ctx context.Context, projectID string, reso
return nil, err return nil, err
} }
if state == domain.ProjectStateUnspecified || state == domain.ProjectStateRemoved { if !isProjectStateExists(state) {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound") return nil, zerrors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
} }
if state != domain.ProjectStateInactive { if state != domain.ProjectStateInactive {
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-5M9bs", "Errors.Project.NotInactive") return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-5M9bs", "Errors.Project.NotInactive")
} }
existingProject, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner)
if err != nil {
return nil, err
}
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
}
if existingProject.State != domain.ProjectStateInactive {
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-5M9bs", "Errors.Project.NotInactive")
}
pushedEvents, err := c.eventstore.Push(ctx, project.NewProjectReactivatedEvent(ctx, projectAgg)) pushedEvents, err := c.eventstore.Push(ctx, project.NewProjectReactivatedEvent(ctx, projectAgg))
if err != nil { if err != nil {
return nil, err return nil, err
@ -382,15 +298,11 @@ func (c *Commands) RemoveProject(ctx context.Context, projectID, resourceOwner s
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-66hM9", "Errors.Project.ProjectIDMissing") return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-66hM9", "Errors.Project.ProjectIDMissing")
} }
if !authz.GetFeatures(ctx).ShouldUseImprovedPerformance(feature.ImprovedPerformanceTypeProject) {
return c.removeProjectOld(ctx, projectID, resourceOwner)
}
existingProject, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner) existingProject, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved { if !isProjectStateExists(existingProject.State) {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound") return nil, zerrors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
} }

View File

@ -78,11 +78,10 @@ func (c *Commands) AddAPIApplicationWithID(ctx context.Context, apiApp *domain.A
if existingAPI.State != domain.AppStateUnspecified { if existingAPI.State != domain.AppStateUnspecified {
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-mabu12", "Errors.Project.App.AlreadyExisting") return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-mabu12", "Errors.Project.App.AlreadyExisting")
} }
_, err = c.getProjectByID(ctx, apiApp.AggregateID, resourceOwner)
if err != nil {
return nil, zerrors.ThrowPreconditionFailed(err, "PROJECT-9fnsa", "Errors.Project.NotFound")
}
if err := c.checkProjectExists(ctx, apiApp.AggregateID, resourceOwner); err != nil {
return nil, err
}
return c.addAPIApplicationWithID(ctx, apiApp, resourceOwner, appID) return c.addAPIApplicationWithID(ctx, apiApp, resourceOwner, appID)
} }
@ -90,11 +89,10 @@ func (c *Commands) AddAPIApplication(ctx context.Context, apiApp *domain.APIApp,
if apiApp == nil || apiApp.AggregateID == "" { if apiApp == nil || apiApp.AggregateID == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-5m9E", "Errors.Project.App.Invalid") return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-5m9E", "Errors.Project.App.Invalid")
} }
_, err = c.getProjectByID(ctx, apiApp.AggregateID, resourceOwner)
if err != nil {
return nil, zerrors.ThrowPreconditionFailed(err, "PROJECT-9fnsf", "Errors.Project.NotFound")
}
if err := c.checkProjectExists(ctx, apiApp.AggregateID, resourceOwner); err != nil {
return nil, err
}
if !apiApp.IsValid() { if !apiApp.IsValid() {
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-Bff2g", "Errors.Project.App.Invalid") return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-Bff2g", "Errors.Project.App.Invalid")
} }

View File

@ -132,11 +132,9 @@ func (c *Commands) AddOIDCApplicationWithID(ctx context.Context, oidcApp *domain
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-lxowmp", "Errors.Project.App.AlreadyExisting") return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-lxowmp", "Errors.Project.App.AlreadyExisting")
} }
_, err = c.getProjectByID(ctx, oidcApp.AggregateID, resourceOwner) if err := c.checkProjectExists(ctx, oidcApp.AggregateID, resourceOwner); err != nil {
if err != nil { return nil, err
return nil, zerrors.ThrowPreconditionFailed(err, "PROJECT-3m9s2", "Errors.Project.NotFound")
} }
return c.addOIDCApplicationWithID(ctx, oidcApp, resourceOwner, appID) return c.addOIDCApplicationWithID(ctx, oidcApp, resourceOwner, appID)
} }
@ -144,11 +142,9 @@ func (c *Commands) AddOIDCApplication(ctx context.Context, oidcApp *domain.OIDCA
if oidcApp == nil || oidcApp.AggregateID == "" { if oidcApp == nil || oidcApp.AggregateID == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-34Fm0", "Errors.Project.App.Invalid") return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-34Fm0", "Errors.Project.App.Invalid")
} }
_, err = c.getProjectByID(ctx, oidcApp.AggregateID, resourceOwner) if err := c.checkProjectExists(ctx, oidcApp.AggregateID, resourceOwner); err != nil {
if err != nil { return nil, err
return nil, zerrors.ThrowPreconditionFailed(err, "PROJECT-3m9ss", "Errors.Project.NotFound")
} }
if oidcApp.AppName == "" || !oidcApp.IsValid() { if oidcApp.AppName == "" || !oidcApp.IsValid() {
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-1n8df", "Errors.Project.App.Invalid") return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-1n8df", "Errors.Project.App.Invalid")
} }

View File

@ -16,11 +16,9 @@ func (c *Commands) AddSAMLApplication(ctx context.Context, application *domain.S
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-35Fn0", "Errors.Project.App.Invalid") return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-35Fn0", "Errors.Project.App.Invalid")
} }
_, err = c.getProjectByID(ctx, application.AggregateID, resourceOwner) if err := c.checkProjectExists(ctx, application.AggregateID, resourceOwner); err != nil {
if err != nil { return nil, err
return nil, zerrors.ThrowPreconditionFailed(err, "PROJECT-3p9ss", "Errors.Project.NotFound")
} }
addedApplication := NewSAMLApplicationWriteModel(application.AggregateID, resourceOwner) addedApplication := NewSAMLApplicationWriteModel(application.AggregateID, resourceOwner)
projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel) projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel)
events, err := c.addSAMLApplication(ctx, projectAgg, application) events, err := c.addSAMLApplication(ctx, projectAgg, application)

View File

@ -124,6 +124,19 @@ func (wm *ProjectWriteModel) NewChangedEvent(
return changeEvent, true, nil return changeEvent, true, nil
} }
func isProjectStateExists(state domain.ProjectState) bool {
return !hasProjectState(state, domain.ProjectStateRemoved, domain.ProjectStateUnspecified)
}
func ProjectAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregate { func ProjectAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregate {
return eventstore.AggregateFromWriteModel(wm, project.AggregateType, project.AggregateVersion) return eventstore.AggregateFromWriteModel(wm, project.AggregateType, project.AggregateVersion)
} }
func hasProjectState(check domain.ProjectState, states ...domain.ProjectState) bool {
for _, state := range states {
if check == state {
return true
}
}
return false
}

View File

@ -3,10 +3,7 @@ package command
import ( import (
"context" "context"
"github.com/zitadel/logging"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/project"
"github.com/zitadel/zitadel/internal/telemetry/tracing" "github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors" "github.com/zitadel/zitadel/internal/zerrors"
@ -20,58 +17,18 @@ func (c *Commands) checkProjectExistsOld(ctx context.Context, projectID, resourc
if err != nil { if err != nil {
return err return err
} }
if projectWriteModel.State == domain.ProjectStateUnspecified || projectWriteModel.State == domain.ProjectStateRemoved { if !isProjectStateExists(projectWriteModel.State) {
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-EbFMN", "Errors.Project.NotFound") return zerrors.ThrowPreconditionFailed(nil, "COMMAND-EbFMN", "Errors.Project.NotFound")
} }
return nil return nil
} }
func (c *Commands) changeProjectOld(ctx context.Context, projectChange *domain.Project, resourceOwner string) (*domain.Project, error) {
if !projectChange.IsValid() || projectChange.AggregateID == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.Invalid")
}
existingProject, err := c.getProjectWriteModelByID(ctx, projectChange.AggregateID, resourceOwner)
if err != nil {
return nil, err
}
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
}
//nolint: contextcheck
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
changedEvent, hasChanged, err := existingProject.NewChangedEvent(
ctx,
projectAgg,
projectChange.Name,
projectChange.ProjectRoleAssertion,
projectChange.ProjectRoleCheck,
projectChange.HasProjectCheck,
projectChange.PrivateLabelingSetting)
if err != nil {
return nil, err
}
if !hasChanged {
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-2M0fs", "Errors.NoChangesFound")
}
pushedEvents, err := c.eventstore.Push(ctx, changedEvent)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingProject, pushedEvents...)
if err != nil {
return nil, err
}
return projectWriteModelToProject(existingProject), nil
}
func (c *Commands) deactivateProjectOld(ctx context.Context, projectID string, resourceOwner string) (*domain.ObjectDetails, error) { func (c *Commands) deactivateProjectOld(ctx context.Context, projectID string, resourceOwner string) (*domain.ObjectDetails, error) {
existingProject, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner) existingProject, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved { if !isProjectStateExists(existingProject.State) {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-112M9", "Errors.Project.NotFound") return nil, zerrors.ThrowNotFound(nil, "COMMAND-112M9", "Errors.Project.NotFound")
} }
if existingProject.State != domain.ProjectStateActive { if existingProject.State != domain.ProjectStateActive {
@ -96,7 +53,7 @@ func (c *Commands) reactivateProjectOld(ctx context.Context, projectID string, r
if err != nil { if err != nil {
return nil, err return nil, err
} }
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved { if !isProjectStateExists(existingProject.State) {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound") return nil, zerrors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
} }
if existingProject.State != domain.ProjectStateInactive { if existingProject.State != domain.ProjectStateInactive {
@ -116,51 +73,6 @@ func (c *Commands) reactivateProjectOld(ctx context.Context, projectID string, r
return writeModelToObjectDetails(&existingProject.WriteModel), nil return writeModelToObjectDetails(&existingProject.WriteModel), nil
} }
func (c *Commands) removeProjectOld(ctx context.Context, projectID, resourceOwner string, cascadingUserGrantIDs ...string) (*domain.ObjectDetails, error) {
existingProject, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner)
if err != nil {
return nil, err
}
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved {
return nil, zerrors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
}
samlEntityIDsAgg, err := c.getSAMLEntityIdsWriteModelByProjectID(ctx, projectID, resourceOwner)
if err != nil {
return nil, err
}
uniqueConstraints := make([]*eventstore.UniqueConstraint, len(samlEntityIDsAgg.EntityIDs))
for i, entityID := range samlEntityIDsAgg.EntityIDs {
uniqueConstraints[i] = project.NewRemoveSAMLConfigEntityIDUniqueConstraint(entityID.EntityID)
}
//nolint: contextcheck
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
events := []eventstore.Command{
project.NewProjectRemovedEvent(ctx, projectAgg, existingProject.Name, uniqueConstraints),
}
for _, grantID := range cascadingUserGrantIDs {
event, _, err := c.removeUserGrant(ctx, grantID, "", true)
if err != nil {
logging.WithFields("usergrantid", grantID).WithError(err).Warn("could not cascade remove user grant")
continue
}
events = append(events, event)
}
pushedEvents, err := c.eventstore.Push(ctx, events...)
if err != nil {
return nil, err
}
err = AppendAndReduce(existingProject, pushedEvents...)
if err != nil {
return nil, err
}
return writeModelToObjectDetails(&existingProject.WriteModel), nil
}
func (c *Commands) checkProjectGrantPreConditionOld(ctx context.Context, projectGrant *domain.ProjectGrant, resourceOwner string) error { func (c *Commands) checkProjectGrantPreConditionOld(ctx context.Context, projectGrant *domain.ProjectGrant, resourceOwner string) error {
preConditions := NewProjectGrantPreConditionReadModel(projectGrant.AggregateID, projectGrant.GrantedOrgID, resourceOwner) preConditions := NewProjectGrantPreConditionReadModel(projectGrant.AggregateID, projectGrant.GrantedOrgID, resourceOwner)
err := c.eventstore.FilterToQueryReducer(ctx, preConditions) err := c.eventstore.FilterToQueryReducer(ctx, preConditions)

View File

@ -25,7 +25,6 @@ func TestCommandSide_AddProject(t *testing.T) {
ctx context.Context ctx context.Context
project *domain.Project project *domain.Project
resourceOwner string resourceOwner string
ownerID string
} }
type res struct { type res struct {
want *domain.Project want *domain.Project
@ -54,7 +53,7 @@ func TestCommandSide_AddProject(t *testing.T) {
}, },
}, },
{ {
name: "org with project owner, resourceowner empty", name: "project, resourceowner empty",
fields: fields{ fields: fields{
eventstore: eventstoreExpect( eventstore: eventstoreExpect(
t, t,
@ -70,40 +69,17 @@ func TestCommandSide_AddProject(t *testing.T) {
PrivateLabelingSetting: domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy, PrivateLabelingSetting: domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy,
}, },
resourceOwner: "", resourceOwner: "",
ownerID: "user1",
}, },
res: res{ res: res{
err: zerrors.IsErrorInvalidArgument, err: zerrors.IsErrorInvalidArgument,
}, },
}, },
{ {
name: "org with project owner, ownerID empty", name: "project, error already exists",
fields: fields{
eventstore: eventstoreExpect(
t,
),
},
args: args{
ctx: context.Background(),
project: &domain.Project{
Name: "project",
ProjectRoleAssertion: true,
ProjectRoleCheck: true,
HasProjectCheck: true,
PrivateLabelingSetting: domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy,
},
resourceOwner: "org1",
ownerID: "",
},
res: res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
name: "org with project owner, error already exists",
fields: fields{ fields: fields{
eventstore: eventstoreExpect( eventstore: eventstoreExpect(
t, t,
expectFilter(),
expectPushFailed(zerrors.ThrowAlreadyExists(nil, "ERROR", "internl"), expectPushFailed(zerrors.ThrowAlreadyExists(nil, "ERROR", "internl"),
project.NewProjectAddedEvent( project.NewProjectAddedEvent(
context.Background(), context.Background(),
@ -111,11 +87,36 @@ func TestCommandSide_AddProject(t *testing.T) {
"project", true, true, true, "project", true, true, true,
domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy, domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy,
), ),
project.NewProjectMemberAddedEvent( ),
context.Background(), ),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "project1"),
},
args: args{
ctx: authz.WithInstanceID(context.Background(), "instanceID"),
project: &domain.Project{
Name: "project",
ProjectRoleAssertion: true,
ProjectRoleCheck: true,
HasProjectCheck: true,
PrivateLabelingSetting: domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy,
},
resourceOwner: "org1",
},
res: res{
err: zerrors.IsErrorAlreadyExists,
},
},
{
name: "project, already exists",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
project.NewProjectAddedEvent(context.Background(),
&project.NewAggregate("project1", "org1").Aggregate, &project.NewAggregate("project1", "org1").Aggregate,
"user1", "project", true, true, true,
[]string{domain.RoleProjectOwner}..., domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy),
), ),
), ),
), ),
@ -131,17 +132,17 @@ func TestCommandSide_AddProject(t *testing.T) {
PrivateLabelingSetting: domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy, PrivateLabelingSetting: domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy,
}, },
resourceOwner: "org1", resourceOwner: "org1",
ownerID: "user1",
}, },
res: res{ res: res{
err: zerrors.IsErrorAlreadyExists, err: zerrors.IsErrorAlreadyExists,
}, },
}, },
{ {
name: "org with project owner, ok", name: "project, ok",
fields: fields{ fields: fields{
eventstore: eventstoreExpect( eventstore: eventstoreExpect(
t, t,
expectFilter(),
expectPush( expectPush(
project.NewProjectAddedEvent( project.NewProjectAddedEvent(
context.Background(), context.Background(),
@ -149,12 +150,6 @@ func TestCommandSide_AddProject(t *testing.T) {
"project", true, true, true, "project", true, true, true,
domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy, domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy,
), ),
project.NewProjectMemberAddedEvent(
context.Background(),
&project.NewAggregate("project1", "org1").Aggregate,
"user1",
[]string{domain.RoleProjectOwner}...,
),
), ),
), ),
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "project1"), idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "project1"),
@ -169,7 +164,6 @@ func TestCommandSide_AddProject(t *testing.T) {
PrivateLabelingSetting: domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy, PrivateLabelingSetting: domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy,
}, },
resourceOwner: "org1", resourceOwner: "org1",
ownerID: "user1",
}, },
res: res{ res: res{
want: &domain.Project{ want: &domain.Project{
@ -193,7 +187,7 @@ func TestCommandSide_AddProject(t *testing.T) {
idGenerator: tt.fields.idGenerator, idGenerator: tt.fields.idGenerator,
} }
c.setMilestonesCompletedForTest("instanceID") c.setMilestonesCompletedForTest("instanceID")
got, err := c.AddProject(tt.args.ctx, tt.args.project, tt.args.resourceOwner, tt.args.ownerID) got, err := c.AddProject(tt.args.ctx, tt.args.project, tt.args.resourceOwner)
if tt.res.err == nil { if tt.res.err == nil {
assert.NoError(t, err) assert.NoError(t, err)
} }
@ -1207,9 +1201,6 @@ func TestAddProject(t *testing.T) {
false, false,
domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy, domain.PrivateLabelingSettingAllowLoginUserResourceOwnerPolicy,
), ),
project.NewProjectMemberAddedEvent(ctx, &agg.Aggregate,
"CAOS AG",
domain.RoleProjectOwner),
}, },
}, },
}, },