mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:27:42 +00:00
feat: project v2beta resource API (#9742)
# Which Problems Are Solved Resource management of projects and sub-resources was before limited by the context provided by the management API, which would mean you could only manage resources belonging to a specific organization. # How the Problems Are Solved With the addition of a resource-based API, it is now possible to manage projects and sub-resources on the basis of the resources themselves, which means that as long as you have the permission for the resource, you can create, read, update and delete it. - CreateProject to create a project under an organization - UpdateProject to update an existing project - DeleteProject to delete an existing project - DeactivateProject and ActivateProject to change the status of a project - GetProject to query for a specific project with an identifier - ListProject to query for projects and granted projects - CreateProjectGrant to create a project grant with project and granted organization - UpdateProjectGrant to update the roles of a project grant - DeactivateProjectGrant and ActivateProjectGrant to change the status of a project grant - DeleteProjectGrant to delete an existing project grant - ListProjectGrants to query for project grants - AddProjectRole to add a role to an existing project - UpdateProjectRole to change texts of an existing role - RemoveProjectRole to remove an existing role - ListProjectRoles to query for project roles # Additional Changes - Changes to ListProjects, which now contains granted projects as well - Changes to messages as defined in the [API_DESIGN](https://github.com/zitadel/zitadel/blob/main/API_DESIGN.md) - Permission checks for project functionality on query and command side - Added testing to unit tests on command side - Change update endpoints to no error returns if nothing changes in the resource - Changed all integration test utility to the new service - ListProjects now also correctly lists `granted projects` - Permission checks for project grant and project role functionality on query and command side - Change existing pre checks so that they also work resource specific without resourceowner - Added the resourceowner to the grant and role if no resourceowner is provided - Corrected import tests with project grants and roles - Added testing to unit tests on command side - Change update endpoints to no error returns if nothing changes in the resource - Changed all integration test utility to the new service - Corrected some naming in the proto files to adhere to the API_DESIGN # Additional Context Closes #9177 --------- Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
@@ -468,7 +468,7 @@ func (c *Commands) prepareRemoveOrg(a *org.Aggregate) preparation.Validation {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMA-wG9p1", "Errors.Org.DefaultOrgNotDeletable")
|
||||
}
|
||||
|
||||
err := c.checkProjectExists(ctx, instance.ProjectID(), a.ID)
|
||||
_, err := c.checkProjectExists(ctx, instance.ProjectID(), a.ID)
|
||||
// if there is no error, the ZITADEL project was found on the org to be deleted
|
||||
if err == nil {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMA-AF3JW", "Errors.Org.ZitadelOrgNotDeletable")
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
"github.com/zitadel/zitadel/internal/v2/user"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
@@ -58,3 +59,15 @@ func (c *Commands) checkPermissionUpdateUser(ctx context.Context, resourceOwner,
|
||||
func (c *Commands) checkPermissionUpdateUserCredentials(ctx context.Context, resourceOwner, userID string) error {
|
||||
return c.checkPermissionOnUser(ctx, domain.PermissionUserCredentialWrite)(resourceOwner, userID)
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionDeleteProject(ctx context.Context, resourceOwner, projectID string) error {
|
||||
return c.newPermissionCheck(ctx, domain.PermissionProjectDelete, project.AggregateType)(resourceOwner, projectID)
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionUpdateProject(ctx context.Context, resourceOwner, projectID string) error {
|
||||
return c.newPermissionCheck(ctx, domain.PermissionProjectWrite, project.AggregateType)(resourceOwner, projectID)
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionWriteProjectGrant(ctx context.Context, resourceOwner, projectGrantID string) error {
|
||||
return c.newPermissionCheck(ctx, domain.PermissionProjectGrantWrite, project.AggregateType)(resourceOwner, projectGrantID)
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package command
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/feature"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
@@ -17,67 +19,60 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func (c *Commands) AddProjectWithID(ctx context.Context, project *domain.Project, resourceOwner, projectID string) (_ *domain.Project, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
if resourceOwner == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-w8tnSoJxtn", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if projectID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-nDXf5vXoUj", "Errors.IDMissing")
|
||||
}
|
||||
if !project.IsValid() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid")
|
||||
}
|
||||
project, err = c.addProjectWithID(ctx, project, resourceOwner, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return project, nil
|
||||
type AddProject struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Name string
|
||||
ProjectRoleAssertion bool
|
||||
ProjectRoleCheck bool
|
||||
HasProjectCheck bool
|
||||
PrivateLabelingSetting domain.PrivateLabelingSetting
|
||||
}
|
||||
|
||||
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() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid")
|
||||
func (p *AddProject) IsValid() error {
|
||||
if p.ResourceOwner == "" {
|
||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-fmq7bqQX1s", "Errors.ResourceOwnerMissing")
|
||||
}
|
||||
if resourceOwner == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-fmq7bqQX1s", "Errors.ResourceOwnerMissing")
|
||||
if p.Name == "" {
|
||||
return zerrors.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid")
|
||||
}
|
||||
|
||||
projectID, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
project, err = c.addProjectWithID(ctx, project, resourceOwner, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return project, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Commands) addProjectWithID(ctx context.Context, projectAdd *domain.Project, resourceOwner, projectID string) (_ *domain.Project, err error) {
|
||||
projectAdd.AggregateID = projectID
|
||||
projectWriteModel, err := c.getProjectWriteModelByID(ctx, projectAdd.AggregateID, resourceOwner)
|
||||
func (c *Commands) AddProject(ctx context.Context, add *AddProject) (_ *domain.ObjectDetails, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
if err := add.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if add.AggregateID == "" {
|
||||
add.AggregateID, err = c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
wm, err := c.getProjectWriteModelByID(ctx, add.AggregateID, add.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isProjectStateExists(projectWriteModel.State) {
|
||||
if isProjectStateExists(wm.State) {
|
||||
return nil, zerrors.ThrowAlreadyExists(nil, "COMMAND-opamwu", "Errors.Project.AlreadyExisting")
|
||||
}
|
||||
if err := c.checkPermissionUpdateProject(ctx, wm.ResourceOwner, wm.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
events := []eventstore.Command{
|
||||
project.NewProjectAddedEvent(
|
||||
ctx,
|
||||
//nolint: contextcheck
|
||||
ProjectAggregateFromWriteModel(&projectWriteModel.WriteModel),
|
||||
projectAdd.Name,
|
||||
projectAdd.ProjectRoleAssertion,
|
||||
projectAdd.ProjectRoleCheck,
|
||||
projectAdd.HasProjectCheck,
|
||||
projectAdd.PrivateLabelingSetting),
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &wm.WriteModel),
|
||||
add.Name,
|
||||
add.ProjectRoleAssertion,
|
||||
add.ProjectRoleCheck,
|
||||
add.HasProjectCheck,
|
||||
add.PrivateLabelingSetting),
|
||||
}
|
||||
postCommit, err := c.projectCreatedMilestone(ctx, &events)
|
||||
if err != nil {
|
||||
@@ -88,11 +83,11 @@ func (c *Commands) addProjectWithID(ctx context.Context, projectAdd *domain.Proj
|
||||
return nil, err
|
||||
}
|
||||
postCommit(ctx)
|
||||
err = AppendAndReduce(projectWriteModel, pushedEvents...)
|
||||
err = AppendAndReduce(wm, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectWriteModelToProject(projectWriteModel), nil
|
||||
return writeModelToObjectDetails(&wm.WriteModel), nil
|
||||
}
|
||||
|
||||
func AddProjectCommand(
|
||||
@@ -143,14 +138,14 @@ func projectWriteModel(ctx context.Context, filter preparation.FilterToQueryRedu
|
||||
return project, nil
|
||||
}
|
||||
|
||||
func (c *Commands) projectAggregateByID(ctx context.Context, projectID, resourceOwner string) (*eventstore.Aggregate, domain.ProjectState, error) {
|
||||
result, err := c.projectState(ctx, projectID, resourceOwner)
|
||||
func (c *Commands) projectAggregateByID(ctx context.Context, projectID string) (*eventstore.Aggregate, domain.ProjectState, error) {
|
||||
result, err := c.projectState(ctx, projectID)
|
||||
if err != nil {
|
||||
return nil, domain.ProjectStateUnspecified, zerrors.ThrowNotFound(err, "COMMA-NDQoF", "Errors.Project.NotFound")
|
||||
}
|
||||
if len(result) == 0 {
|
||||
_ = projection.ProjectGrantFields.Trigger(ctx)
|
||||
result, err = c.projectState(ctx, projectID, resourceOwner)
|
||||
result, err = c.projectState(ctx, projectID)
|
||||
if err != nil || len(result) == 0 {
|
||||
return nil, domain.ProjectStateUnspecified, zerrors.ThrowNotFound(err, "COMMA-U1nza", "Errors.Project.NotFound")
|
||||
}
|
||||
@@ -164,7 +159,7 @@ func (c *Commands) projectAggregateByID(ctx context.Context, projectID, resource
|
||||
return &result[0].Aggregate, state, nil
|
||||
}
|
||||
|
||||
func (c *Commands) projectState(ctx context.Context, projectID, resourceOwner string) ([]*eventstore.SearchResult, error) {
|
||||
func (c *Commands) projectState(ctx context.Context, projectID string) ([]*eventstore.SearchResult, error) {
|
||||
return c.eventstore.Search(
|
||||
ctx,
|
||||
map[eventstore.FieldType]any{
|
||||
@@ -172,12 +167,11 @@ func (c *Commands) projectState(ctx context.Context, projectID, resourceOwner st
|
||||
eventstore.FieldTypeObjectID: projectID,
|
||||
eventstore.FieldTypeObjectRevision: project.ProjectObjectRevision,
|
||||
eventstore.FieldTypeFieldName: project.ProjectStateSearchField,
|
||||
eventstore.FieldTypeResourceOwner: resourceOwner,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Commands) checkProjectExists(ctx context.Context, projectID, resourceOwner string) (err error) {
|
||||
func (c *Commands) checkProjectExists(ctx context.Context, projectID, resourceOwner string) (_ string, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
@@ -185,50 +179,69 @@ func (c *Commands) checkProjectExists(ctx context.Context, projectID, resourceOw
|
||||
return c.checkProjectExistsOld(ctx, projectID, resourceOwner)
|
||||
}
|
||||
|
||||
_, state, err := c.projectAggregateByID(ctx, projectID, resourceOwner)
|
||||
agg, state, err := c.projectAggregateByID(ctx, projectID)
|
||||
if err != nil || !state.Valid() {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMA-VCnwD", "Errors.Project.NotFound")
|
||||
return "", zerrors.ThrowPreconditionFailed(err, "COMMA-VCnwD", "Errors.Project.NotFound")
|
||||
}
|
||||
return agg.ResourceOwner, nil
|
||||
}
|
||||
|
||||
type ChangeProject struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Name *string
|
||||
ProjectRoleAssertion *bool
|
||||
ProjectRoleCheck *bool
|
||||
HasProjectCheck *bool
|
||||
PrivateLabelingSetting *domain.PrivateLabelingSetting
|
||||
}
|
||||
|
||||
func (p *ChangeProject) IsValid() error {
|
||||
if p.AggregateID == "" {
|
||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.Invalid")
|
||||
}
|
||||
if p.Name != nil && *p.Name == "" {
|
||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.Invalid")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeProject(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")
|
||||
func (c *Commands) ChangeProject(ctx context.Context, change *ChangeProject) (_ *domain.ObjectDetails, err error) {
|
||||
if err := change.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingProject, err := c.getProjectWriteModelByID(ctx, projectChange.AggregateID, resourceOwner)
|
||||
existing, err := c.getProjectWriteModelByID(ctx, change.AggregateID, change.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isProjectStateExists(existingProject.State) {
|
||||
if !isProjectStateExists(existing.State) {
|
||||
return nil, zerrors.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
|
||||
}
|
||||
if err := c.checkPermissionUpdateProject(ctx, existing.ResourceOwner, existing.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
||||
changedEvent, hasChanged, err := existingProject.NewChangedEvent(
|
||||
changedEvent := existing.NewChangedEvent(
|
||||
ctx,
|
||||
projectAgg,
|
||||
projectChange.Name,
|
||||
projectChange.ProjectRoleAssertion,
|
||||
projectChange.ProjectRoleCheck,
|
||||
projectChange.HasProjectCheck,
|
||||
projectChange.PrivateLabelingSetting)
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existing.WriteModel),
|
||||
change.Name,
|
||||
change.ProjectRoleAssertion,
|
||||
change.ProjectRoleCheck,
|
||||
change.HasProjectCheck,
|
||||
change.PrivateLabelingSetting)
|
||||
if changedEvent == nil {
|
||||
return writeModelToObjectDetails(&existing.WriteModel), nil
|
||||
}
|
||||
err = c.pushAppendAndReduce(ctx, existing, changedEvent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !hasChanged {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-2M0fs", "Errors.NoChangesFound")
|
||||
}
|
||||
err = c.pushAppendAndReduce(ctx, existingProject, changedEvent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectWriteModelToProject(existingProject), nil
|
||||
return writeModelToObjectDetails(&existing.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) DeactivateProject(ctx context.Context, projectID string, resourceOwner string) (*domain.ObjectDetails, error) {
|
||||
if projectID == "" || resourceOwner == "" {
|
||||
if projectID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-88iF0", "Errors.Project.ProjectIDMissing")
|
||||
}
|
||||
|
||||
@@ -236,7 +249,7 @@ func (c *Commands) DeactivateProject(ctx context.Context, projectID string, reso
|
||||
return c.deactivateProjectOld(ctx, projectID, resourceOwner)
|
||||
}
|
||||
|
||||
projectAgg, state, err := c.projectAggregateByID(ctx, projectID, resourceOwner)
|
||||
projectAgg, state, err := c.projectAggregateByID(ctx, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -247,6 +260,9 @@ func (c *Commands) DeactivateProject(ctx context.Context, projectID string, reso
|
||||
if state != domain.ProjectStateActive {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-mki55", "Errors.Project.NotActive")
|
||||
}
|
||||
if err := c.checkPermissionUpdateProject(ctx, projectAgg.ResourceOwner, projectAgg.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, project.NewProjectDeactivatedEvent(ctx, projectAgg))
|
||||
if err != nil {
|
||||
@@ -261,7 +277,7 @@ func (c *Commands) DeactivateProject(ctx context.Context, projectID string, reso
|
||||
}
|
||||
|
||||
func (c *Commands) ReactivateProject(ctx context.Context, projectID string, resourceOwner string) (*domain.ObjectDetails, error) {
|
||||
if projectID == "" || resourceOwner == "" {
|
||||
if projectID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-3ihsF", "Errors.Project.ProjectIDMissing")
|
||||
}
|
||||
|
||||
@@ -269,7 +285,7 @@ func (c *Commands) ReactivateProject(ctx context.Context, projectID string, reso
|
||||
return c.reactivateProjectOld(ctx, projectID, resourceOwner)
|
||||
}
|
||||
|
||||
projectAgg, state, err := c.projectAggregateByID(ctx, projectID, resourceOwner)
|
||||
projectAgg, state, err := c.projectAggregateByID(ctx, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -280,6 +296,9 @@ func (c *Commands) ReactivateProject(ctx context.Context, projectID string, reso
|
||||
if state != domain.ProjectStateInactive {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-5M9bs", "Errors.Project.NotInactive")
|
||||
}
|
||||
if err := c.checkPermissionUpdateProject(ctx, projectAgg.ResourceOwner, projectAgg.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, project.NewProjectReactivatedEvent(ctx, projectAgg))
|
||||
if err != nil {
|
||||
@@ -293,6 +312,7 @@ func (c *Commands) ReactivateProject(ctx context.Context, projectID string, reso
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Deprecated: use commands.DeleteProject
|
||||
func (c *Commands) RemoveProject(ctx context.Context, projectID, resourceOwner string, cascadingUserGrantIDs ...string) (*domain.ObjectDetails, error) {
|
||||
if projectID == "" || resourceOwner == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-66hM9", "Errors.Project.ProjectIDMissing")
|
||||
@@ -316,15 +336,18 @@ func (c *Commands) RemoveProject(ctx context.Context, projectID, resourceOwner s
|
||||
uniqueConstraints[i] = project.NewRemoveSAMLConfigEntityIDUniqueConstraint(entityID.EntityID)
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
||||
events := []eventstore.Command{
|
||||
project.NewProjectRemovedEvent(ctx, projectAgg, existingProject.Name, uniqueConstraints),
|
||||
project.NewProjectRemovedEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existingProject.WriteModel),
|
||||
existingProject.Name,
|
||||
uniqueConstraints,
|
||||
),
|
||||
}
|
||||
|
||||
for _, grantID := range cascadingUserGrantIDs {
|
||||
event, _, err := c.removeUserGrant(ctx, grantID, "", true)
|
||||
if err != nil {
|
||||
logging.LogWithFields("COMMAND-b8Djf", "usergrantid", grantID).WithError(err).Warn("could not cascade remove user grant")
|
||||
logging.WithFields("id", "COMMAND-b8Djf", "usergrantid", grantID).WithError(err).Warn("could not cascade remove user grant")
|
||||
continue
|
||||
}
|
||||
events = append(events, event)
|
||||
@@ -341,6 +364,53 @@ func (c *Commands) RemoveProject(ctx context.Context, projectID, resourceOwner s
|
||||
return writeModelToObjectDetails(&existingProject.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) DeleteProject(ctx context.Context, id, resourceOwner string, cascadingUserGrantIDs ...string) (time.Time, error) {
|
||||
if id == "" {
|
||||
return time.Time{}, zerrors.ThrowInvalidArgument(nil, "COMMAND-obqos2l3no", "Errors.IDMissing")
|
||||
}
|
||||
|
||||
existing, err := c.getProjectWriteModelByID(ctx, id, resourceOwner)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
if !isProjectStateExists(existing.State) {
|
||||
return existing.WriteModel.ChangeDate, nil
|
||||
}
|
||||
if err := c.checkPermissionDeleteProject(ctx, existing.ResourceOwner, existing.AggregateID); err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
samlEntityIDsAgg, err := c.getSAMLEntityIdsWriteModelByProjectID(ctx, id, resourceOwner)
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
uniqueConstraints := make([]*eventstore.UniqueConstraint, len(samlEntityIDsAgg.EntityIDs))
|
||||
for i, entityID := range samlEntityIDsAgg.EntityIDs {
|
||||
uniqueConstraints[i] = project.NewRemoveSAMLConfigEntityIDUniqueConstraint(entityID.EntityID)
|
||||
}
|
||||
events := []eventstore.Command{
|
||||
project.NewProjectRemovedEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existing.WriteModel),
|
||||
existing.Name,
|
||||
uniqueConstraints,
|
||||
),
|
||||
}
|
||||
for _, grantID := range cascadingUserGrantIDs {
|
||||
event, _, err := c.removeUserGrant(ctx, grantID, "", true)
|
||||
if err != nil {
|
||||
logging.WithFields("id", "COMMAND-b8Djf", "usergrantid", grantID).WithError(err).Warn("could not cascade remove user grant")
|
||||
continue
|
||||
}
|
||||
events = append(events, event)
|
||||
}
|
||||
|
||||
if err := c.pushAppendAndReduce(ctx, existing, events...); err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
return existing.WriteModel.ChangeDate, nil
|
||||
}
|
||||
|
||||
func (c *Commands) getProjectWriteModelByID(ctx context.Context, projectID, resourceOwner string) (_ *ProjectWriteModel, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
@@ -79,7 +79,7 @@ func (c *Commands) AddAPIApplicationWithID(ctx context.Context, apiApp *domain.A
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-mabu12", "Errors.Project.App.AlreadyExisting")
|
||||
}
|
||||
|
||||
if err := c.checkProjectExists(ctx, apiApp.AggregateID, resourceOwner); err != nil {
|
||||
if _, err := c.checkProjectExists(ctx, apiApp.AggregateID, resourceOwner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.addAPIApplicationWithID(ctx, apiApp, resourceOwner, appID)
|
||||
@@ -90,7 +90,7 @@ func (c *Commands) AddAPIApplication(ctx context.Context, apiApp *domain.APIApp,
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-5m9E", "Errors.Project.App.Invalid")
|
||||
}
|
||||
|
||||
if err := c.checkProjectExists(ctx, apiApp.AggregateID, resourceOwner); err != nil {
|
||||
if _, err := c.checkProjectExists(ctx, apiApp.AggregateID, resourceOwner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !apiApp.IsValid() {
|
||||
|
@@ -132,7 +132,7 @@ func (c *Commands) AddOIDCApplicationWithID(ctx context.Context, oidcApp *domain
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-lxowmp", "Errors.Project.App.AlreadyExisting")
|
||||
}
|
||||
|
||||
if err := c.checkProjectExists(ctx, oidcApp.AggregateID, resourceOwner); err != nil {
|
||||
if _, err := c.checkProjectExists(ctx, oidcApp.AggregateID, resourceOwner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.addOIDCApplicationWithID(ctx, oidcApp, resourceOwner, appID)
|
||||
@@ -142,7 +142,7 @@ func (c *Commands) AddOIDCApplication(ctx context.Context, oidcApp *domain.OIDCA
|
||||
if oidcApp == nil || oidcApp.AggregateID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-34Fm0", "Errors.Project.App.Invalid")
|
||||
}
|
||||
if err := c.checkProjectExists(ctx, oidcApp.AggregateID, resourceOwner); err != nil {
|
||||
if _, err := c.checkProjectExists(ctx, oidcApp.AggregateID, resourceOwner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if oidcApp.AppName == "" || !oidcApp.IsValid() {
|
||||
|
@@ -16,7 +16,7 @@ func (c *Commands) AddSAMLApplication(ctx context.Context, application *domain.S
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-35Fn0", "Errors.Project.App.Invalid")
|
||||
}
|
||||
|
||||
if err := c.checkProjectExists(ctx, application.AggregateID, resourceOwner); err != nil {
|
||||
if _, err := c.checkProjectExists(ctx, application.AggregateID, resourceOwner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addedApplication := NewSAMLApplicationWriteModel(application.AggregateID, resourceOwner)
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/feature"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
@@ -16,69 +17,107 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func (c *Commands) AddProjectGrantWithID(ctx context.Context, grant *domain.ProjectGrant, grantID string, resourceOwner string) (_ *domain.ProjectGrant, err error) {
|
||||
type AddProjectGrant struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
GrantID string
|
||||
GrantedOrgID string
|
||||
RoleKeys []string
|
||||
}
|
||||
|
||||
func (p *AddProjectGrant) IsValid() error {
|
||||
if p.AggregateID == "" {
|
||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-FYRnWEzBzV", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
if p.GrantedOrgID == "" {
|
||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-PPhHpWGRAE", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddProjectGrant(ctx context.Context, grant *AddProjectGrant) (_ *domain.ObjectDetails, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
return c.addProjectGrantWithID(ctx, grant, grantID, resourceOwner)
|
||||
if err := grant.IsValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if grant.GrantID == "" {
|
||||
grant.GrantID, err = c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
projectResourceOwner, err := c.checkProjectGrantPreCondition(ctx, grant.AggregateID, grant.GrantedOrgID, grant.ResourceOwner, grant.RoleKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// if there is no resourceowner provided then use the resourceowner of the project
|
||||
if grant.ResourceOwner == "" {
|
||||
grant.ResourceOwner = projectResourceOwner
|
||||
}
|
||||
if err := c.checkPermissionWriteProjectGrant(ctx, grant.ResourceOwner, grant.GrantID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wm := NewProjectGrantWriteModel(grant.GrantID, grant.AggregateID, grant.ResourceOwner)
|
||||
// error if provided resourceowner is not equal to the resourceowner of the project or the project grant is for the same organization
|
||||
if projectResourceOwner != wm.ResourceOwner || wm.ResourceOwner == grant.GrantedOrgID {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-ckUpbvboAH", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
if err := c.pushAppendAndReduce(ctx,
|
||||
wm,
|
||||
project.NewGrantAddedEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &wm.WriteModel),
|
||||
grant.GrantID,
|
||||
grant.GrantedOrgID,
|
||||
grant.RoleKeys),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&wm.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddProjectGrant(ctx context.Context, grant *domain.ProjectGrant, resourceOwner string) (_ *domain.ProjectGrant, err error) {
|
||||
if !grant.IsValid() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-3b8fs", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
err = c.checkProjectGrantPreCondition(ctx, grant, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
type ChangeProjectGrant struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
grantID, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.addProjectGrantWithID(ctx, grant, grantID, resourceOwner)
|
||||
GrantID string
|
||||
RoleKeys []string
|
||||
}
|
||||
|
||||
func (c *Commands) addProjectGrantWithID(ctx context.Context, grant *domain.ProjectGrant, grantID string, resourceOwner string) (_ *domain.ProjectGrant, err error) {
|
||||
grant.GrantID = grantID
|
||||
|
||||
addedGrant := NewProjectGrantWriteModel(grant.GrantID, grant.AggregateID, resourceOwner)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&addedGrant.WriteModel)
|
||||
pushedEvents, err := c.eventstore.Push(
|
||||
ctx,
|
||||
project.NewGrantAddedEvent(ctx, projectAgg, grant.GrantID, grant.GrantedOrgID, grant.RoleKeys))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(addedGrant, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectGrantWriteModelToProjectGrant(addedGrant), nil
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeProjectGrant(ctx context.Context, grant *domain.ProjectGrant, resourceOwner string, cascadeUserGrantIDs ...string) (_ *domain.ProjectGrant, err error) {
|
||||
func (c *Commands) ChangeProjectGrant(ctx context.Context, grant *ChangeProjectGrant, cascadeUserGrantIDs ...string) (_ *domain.ObjectDetails, err error) {
|
||||
if grant.GrantID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-1j83s", "Errors.IDMissing")
|
||||
}
|
||||
existingGrant, err := c.projectGrantWriteModelByID(ctx, grant.GrantID, grant.AggregateID, resourceOwner)
|
||||
existingGrant, err := c.projectGrantWriteModelByID(ctx, grant.GrantID, grant.AggregateID, grant.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
grant.GrantedOrgID = existingGrant.GrantedOrgID
|
||||
err = c.checkProjectGrantPreCondition(ctx, grant, resourceOwner)
|
||||
if err := c.checkPermissionWriteProjectGrant(ctx, existingGrant.ResourceOwner, existingGrant.GrantID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
projectResourceOwner, err := c.checkProjectGrantPreCondition(ctx, existingGrant.AggregateID, existingGrant.GrantedOrgID, existingGrant.ResourceOwner, grant.RoleKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
|
||||
// error if provided resourceowner is not equal to the resourceowner of the project
|
||||
if existingGrant.ResourceOwner != projectResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-q1BhA68RBC", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
|
||||
// return if there are no changes to the project grant roles
|
||||
if reflect.DeepEqual(existingGrant.RoleKeys, grant.RoleKeys) {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-0o0pL", "Errors.NoChangesFoundc")
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
|
||||
events := []eventstore.Command{
|
||||
project.NewGrantChangedEvent(ctx, projectAgg, grant.GrantID, grant.RoleKeys),
|
||||
project.NewGrantChangedEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existingGrant.WriteModel),
|
||||
existingGrant.GrantID,
|
||||
grant.RoleKeys,
|
||||
),
|
||||
}
|
||||
|
||||
removedRoles := domain.GetRemovedRoles(existingGrant.RoleKeys, grant.RoleKeys)
|
||||
@@ -91,7 +130,7 @@ func (c *Commands) ChangeProjectGrant(ctx context.Context, grant *domain.Project
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectGrantWriteModelToProjectGrant(existingGrant), nil
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
|
||||
for _, userGrantID := range cascadeUserGrantIDs {
|
||||
@@ -109,7 +148,7 @@ func (c *Commands) ChangeProjectGrant(ctx context.Context, grant *domain.Project
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectGrantWriteModelToProjectGrant(existingGrant), nil
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) removeRoleFromProjectGrant(ctx context.Context, projectAgg *eventstore.Aggregate, projectID, projectGrantID, roleKey string, cascade bool) (_ eventstore.Command, _ *ProjectGrantWriteModel, err error) {
|
||||
@@ -147,7 +186,7 @@ func (c *Commands) DeactivateProjectGrant(ctx context.Context, projectID, grantI
|
||||
return details, zerrors.ThrowInvalidArgument(nil, "PROJECT-p0s4V", "Errors.IDMissing")
|
||||
}
|
||||
|
||||
err = c.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
projectResourceOwner, err := c.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -156,12 +195,27 @@ func (c *Commands) DeactivateProjectGrant(ctx context.Context, projectID, grantI
|
||||
if err != nil {
|
||||
return details, err
|
||||
}
|
||||
// error if provided resourceowner is not equal to the resourceowner of the project
|
||||
if projectResourceOwner != existingGrant.ResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-0l10S9OmZV", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
// return if project grant is already inactive
|
||||
if existingGrant.State == domain.ProjectGrantStateInactive {
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
// error if project grant is neither active nor inactive
|
||||
if existingGrant.State != domain.ProjectGrantStateActive {
|
||||
return details, zerrors.ThrowPreconditionFailed(nil, "PROJECT-47fu8", "Errors.Project.Grant.NotActive")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, project.NewGrantDeactivateEvent(ctx, projectAgg, grantID))
|
||||
if err := c.checkPermissionWriteProjectGrant(ctx, existingGrant.ResourceOwner, existingGrant.GrantID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx,
|
||||
project.NewGrantDeactivateEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existingGrant.WriteModel),
|
||||
grantID,
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -177,7 +231,7 @@ func (c *Commands) ReactivateProjectGrant(ctx context.Context, projectID, grantI
|
||||
return details, zerrors.ThrowInvalidArgument(nil, "PROJECT-p0s4V", "Errors.IDMissing")
|
||||
}
|
||||
|
||||
err = c.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
projectResourceOwner, err := c.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -186,11 +240,27 @@ func (c *Commands) ReactivateProjectGrant(ctx context.Context, projectID, grantI
|
||||
if err != nil {
|
||||
return details, err
|
||||
}
|
||||
// error if provided resourceowner is not equal to the resourceowner of the project
|
||||
if projectResourceOwner != existingGrant.ResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-byscAarAST", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
// return if project grant is already active
|
||||
if existingGrant.State == domain.ProjectGrantStateActive {
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
// error if project grant is neither active nor inactive
|
||||
if existingGrant.State != domain.ProjectGrantStateInactive {
|
||||
return details, zerrors.ThrowPreconditionFailed(nil, "PROJECT-47fu8", "Errors.Project.Grant.NotInactive")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
|
||||
pushedEvents, err := c.eventstore.Push(ctx, project.NewGrantReactivatedEvent(ctx, projectAgg, grantID))
|
||||
if err := c.checkPermissionWriteProjectGrant(ctx, existingGrant.ResourceOwner, existingGrant.GrantID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx,
|
||||
project.NewGrantReactivatedEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existingGrant.WriteModel),
|
||||
grantID,
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -209,9 +279,20 @@ func (c *Commands) RemoveProjectGrant(ctx context.Context, projectID, grantID, r
|
||||
if err != nil {
|
||||
return details, err
|
||||
}
|
||||
// return if project grant does not exist, or was removed already
|
||||
if !existingGrant.State.Exists() {
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
if err := c.checkPermissionDeleteProjectGrant(ctx, existingGrant.ResourceOwner, existingGrant.GrantID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events := make([]eventstore.Command, 0)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
|
||||
events = append(events, project.NewGrantRemovedEvent(ctx, projectAgg, grantID, existingGrant.GrantedOrgID))
|
||||
events = append(events, project.NewGrantRemovedEvent(ctx,
|
||||
ProjectAggregateFromWriteModelWithCTX(ctx, &existingGrant.WriteModel),
|
||||
grantID,
|
||||
existingGrant.GrantedOrgID,
|
||||
),
|
||||
)
|
||||
|
||||
for _, userGrantID := range cascadeUserGrantIDs {
|
||||
event, _, err := c.removeUserGrant(ctx, userGrantID, "", true)
|
||||
@@ -232,6 +313,10 @@ func (c *Commands) RemoveProjectGrant(ctx context.Context, projectID, grantID, r
|
||||
return writeModelToObjectDetails(&existingGrant.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionDeleteProjectGrant(ctx context.Context, resourceOwner, projectGrantID string) error {
|
||||
return c.checkPermission(ctx, domain.PermissionProjectGrantDelete, resourceOwner, projectGrantID)
|
||||
}
|
||||
|
||||
func (c *Commands) projectGrantWriteModelByID(ctx context.Context, grantID, projectID, resourceOwner string) (member *ProjectGrantWriteModel, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
@@ -249,55 +334,61 @@ func (c *Commands) projectGrantWriteModelByID(ctx context.Context, grantID, proj
|
||||
return writeModel, nil
|
||||
}
|
||||
|
||||
func (c *Commands) checkProjectGrantPreCondition(ctx context.Context, projectGrant *domain.ProjectGrant, resourceOwner string) error {
|
||||
func (c *Commands) checkProjectGrantPreCondition(ctx context.Context, projectID, grantedOrgID, resourceOwner string, roles []string) (string, error) {
|
||||
if !authz.GetFeatures(ctx).ShouldUseImprovedPerformance(feature.ImprovedPerformanceTypeProjectGrant) {
|
||||
return c.checkProjectGrantPreConditionOld(ctx, projectGrant, resourceOwner)
|
||||
return c.checkProjectGrantPreConditionOld(ctx, projectID, grantedOrgID, resourceOwner, roles)
|
||||
}
|
||||
existingRoleKeys, err := c.searchProjectGrantState(ctx, projectGrant.AggregateID, projectGrant.GrantedOrgID, resourceOwner)
|
||||
projectResourceOwner, existingRoleKeys, err := c.searchProjectGrantState(ctx, projectID, grantedOrgID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
|
||||
if projectGrant.HasInvalidRoles(existingRoleKeys) {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMAND-6m9gd", "Errors.Project.Role.NotFound")
|
||||
if domain.HasInvalidRoles(existingRoleKeys, roles) {
|
||||
return "", zerrors.ThrowPreconditionFailed(err, "COMMAND-6m9gd", "Errors.Project.Role.NotFound")
|
||||
}
|
||||
return nil
|
||||
return projectResourceOwner, nil
|
||||
}
|
||||
|
||||
func (c *Commands) searchProjectGrantState(ctx context.Context, projectID, grantedOrgID, resourceOwner string) (existingRoleKeys []string, err error) {
|
||||
func (c *Commands) searchProjectGrantState(ctx context.Context, projectID, grantedOrgID, resourceOwner string) (_ string, existingRoleKeys []string, err error) {
|
||||
projectStateQuery := map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: projectID,
|
||||
eventstore.FieldTypeFieldName: project.ProjectStateSearchField,
|
||||
eventstore.FieldTypeObjectType: project.ProjectSearchType,
|
||||
}
|
||||
grantedOrgQuery := map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: org.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: grantedOrgID,
|
||||
eventstore.FieldTypeFieldName: org.OrgStateSearchField,
|
||||
eventstore.FieldTypeObjectType: org.OrgSearchType,
|
||||
}
|
||||
roleQuery := map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: projectID,
|
||||
eventstore.FieldTypeFieldName: project.ProjectRoleKeySearchField,
|
||||
eventstore.FieldTypeObjectType: project.ProjectRoleSearchType,
|
||||
}
|
||||
|
||||
// as resourceowner is not always provided, it has to be separately
|
||||
if resourceOwner != "" {
|
||||
projectStateQuery[eventstore.FieldTypeResourceOwner] = resourceOwner
|
||||
roleQuery[eventstore.FieldTypeResourceOwner] = resourceOwner
|
||||
}
|
||||
|
||||
results, err := c.eventstore.Search(
|
||||
ctx,
|
||||
// project state query
|
||||
map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeResourceOwner: resourceOwner,
|
||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: projectID,
|
||||
eventstore.FieldTypeFieldName: project.ProjectStateSearchField,
|
||||
eventstore.FieldTypeObjectType: project.ProjectSearchType,
|
||||
},
|
||||
// granted org query
|
||||
map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: org.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: grantedOrgID,
|
||||
eventstore.FieldTypeFieldName: org.OrgStateSearchField,
|
||||
eventstore.FieldTypeObjectType: org.OrgSearchType,
|
||||
},
|
||||
// role query
|
||||
map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeResourceOwner: resourceOwner,
|
||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: projectID,
|
||||
eventstore.FieldTypeFieldName: project.ProjectRoleKeySearchField,
|
||||
eventstore.FieldTypeObjectType: project.ProjectRoleSearchType,
|
||||
},
|
||||
projectStateQuery,
|
||||
grantedOrgQuery,
|
||||
roleQuery,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
existsProject bool
|
||||
existsGrantedOrg bool
|
||||
existsProject bool
|
||||
existingProjectResourceOwner string
|
||||
existsGrantedOrg bool
|
||||
)
|
||||
|
||||
for _, result := range results {
|
||||
@@ -306,31 +397,32 @@ func (c *Commands) searchProjectGrantState(ctx context.Context, projectID, grant
|
||||
var role string
|
||||
err := result.Value.Unmarshal(&role)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
existingRoleKeys = append(existingRoleKeys, role)
|
||||
case org.OrgSearchType:
|
||||
var state domain.OrgState
|
||||
err := result.Value.Unmarshal(&state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
existsGrantedOrg = state.Valid() && state != domain.OrgStateRemoved
|
||||
case project.ProjectSearchType:
|
||||
var state domain.ProjectState
|
||||
err := result.Value.Unmarshal(&state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", nil, err
|
||||
}
|
||||
existsProject = state.Valid() && state != domain.ProjectStateRemoved
|
||||
existingProjectResourceOwner = result.Aggregate.ResourceOwner
|
||||
}
|
||||
}
|
||||
|
||||
if !existsProject {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-m9gsd", "Errors.Project.NotFound")
|
||||
return "", nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-m9gsd", "Errors.Project.NotFound")
|
||||
}
|
||||
if !existsGrantedOrg {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-3m9gg", "Errors.Org.NotFound")
|
||||
return "", nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-3m9gg", "Errors.Org.NotFound")
|
||||
}
|
||||
return existingRoleKeys, nil
|
||||
return existingProjectResourceOwner, existingRoleKeys, nil
|
||||
}
|
||||
|
@@ -133,14 +133,18 @@ func (wm *ProjectGrantPreConditionReadModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *project.ProjectAddedEvent:
|
||||
if e.Aggregate().ResourceOwner != wm.ResourceOwner {
|
||||
if wm.ResourceOwner == "" {
|
||||
wm.ResourceOwner = e.Aggregate().ResourceOwner
|
||||
}
|
||||
if wm.ResourceOwner != e.Aggregate().ResourceOwner {
|
||||
continue
|
||||
}
|
||||
wm.ProjectExists = true
|
||||
case *project.ProjectRemovedEvent:
|
||||
if e.Aggregate().ResourceOwner != wm.ResourceOwner {
|
||||
if wm.ResourceOwner != e.Aggregate().ResourceOwner {
|
||||
continue
|
||||
}
|
||||
wm.ResourceOwner = ""
|
||||
wm.ProjectExists = false
|
||||
case *project.RoleAddedEvent:
|
||||
if e.Aggregate().ResourceOwner != wm.ResourceOwner {
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -88,40 +88,35 @@ func (wm *ProjectWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
func (wm *ProjectWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
name string,
|
||||
name *string,
|
||||
projectRoleAssertion,
|
||||
projectRoleCheck,
|
||||
hasProjectCheck bool,
|
||||
privateLabelingSetting domain.PrivateLabelingSetting,
|
||||
) (*project.ProjectChangeEvent, bool, error) {
|
||||
hasProjectCheck *bool,
|
||||
privateLabelingSetting *domain.PrivateLabelingSetting,
|
||||
) *project.ProjectChangeEvent {
|
||||
changes := make([]project.ProjectChanges, 0)
|
||||
var err error
|
||||
|
||||
oldName := ""
|
||||
if wm.Name != name {
|
||||
if name != nil && wm.Name != *name {
|
||||
oldName = wm.Name
|
||||
changes = append(changes, project.ChangeName(name))
|
||||
changes = append(changes, project.ChangeName(*name))
|
||||
}
|
||||
if wm.ProjectRoleAssertion != projectRoleAssertion {
|
||||
changes = append(changes, project.ChangeProjectRoleAssertion(projectRoleAssertion))
|
||||
if projectRoleAssertion != nil && wm.ProjectRoleAssertion != *projectRoleAssertion {
|
||||
changes = append(changes, project.ChangeProjectRoleAssertion(*projectRoleAssertion))
|
||||
}
|
||||
if wm.ProjectRoleCheck != projectRoleCheck {
|
||||
changes = append(changes, project.ChangeProjectRoleCheck(projectRoleCheck))
|
||||
if projectRoleCheck != nil && wm.ProjectRoleCheck != *projectRoleCheck {
|
||||
changes = append(changes, project.ChangeProjectRoleCheck(*projectRoleCheck))
|
||||
}
|
||||
if wm.HasProjectCheck != hasProjectCheck {
|
||||
changes = append(changes, project.ChangeHasProjectCheck(hasProjectCheck))
|
||||
if hasProjectCheck != nil && wm.HasProjectCheck != *hasProjectCheck {
|
||||
changes = append(changes, project.ChangeHasProjectCheck(*hasProjectCheck))
|
||||
}
|
||||
if wm.PrivateLabelingSetting != privateLabelingSetting {
|
||||
changes = append(changes, project.ChangePrivateLabelingSetting(privateLabelingSetting))
|
||||
if privateLabelingSetting != nil && wm.PrivateLabelingSetting != *privateLabelingSetting {
|
||||
changes = append(changes, project.ChangePrivateLabelingSetting(*privateLabelingSetting))
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, false, nil
|
||||
return nil
|
||||
}
|
||||
changeEvent, err := project.NewProjectChangeEvent(ctx, aggregate, oldName, changes)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return changeEvent, true, nil
|
||||
return project.NewProjectChangeEvent(ctx, aggregate, oldName, changes)
|
||||
}
|
||||
|
||||
func isProjectStateExists(state domain.ProjectState) bool {
|
||||
@@ -132,6 +127,10 @@ func ProjectAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggre
|
||||
return eventstore.AggregateFromWriteModel(wm, project.AggregateType, project.AggregateVersion)
|
||||
}
|
||||
|
||||
func ProjectAggregateFromWriteModelWithCTX(ctx context.Context, wm *eventstore.WriteModel) *eventstore.Aggregate {
|
||||
return project.AggregateFromWriteModel(ctx, wm)
|
||||
}
|
||||
|
||||
func hasProjectState(check domain.ProjectState, states ...domain.ProjectState) bool {
|
||||
for _, state := range states {
|
||||
if check == state {
|
||||
|
@@ -9,18 +9,18 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func (c *Commands) checkProjectExistsOld(ctx context.Context, projectID, resourceOwner string) (err error) {
|
||||
func (c *Commands) checkProjectExistsOld(ctx context.Context, projectID, resourceOwner string) (_ string, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
projectWriteModel, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
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 projectWriteModel.ResourceOwner, nil
|
||||
}
|
||||
|
||||
func (c *Commands) deactivateProjectOld(ctx context.Context, projectID string, resourceOwner string) (*domain.ObjectDetails, error) {
|
||||
@@ -34,6 +34,9 @@ func (c *Commands) deactivateProjectOld(ctx context.Context, projectID string, r
|
||||
if existingProject.State != domain.ProjectStateActive {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-mki55", "Errors.Project.NotActive")
|
||||
}
|
||||
if err := c.checkPermissionUpdateProject(ctx, existingProject.ResourceOwner, existingProject.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//nolint: contextcheck
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
||||
@@ -59,6 +62,9 @@ func (c *Commands) reactivateProjectOld(ctx context.Context, projectID string, r
|
||||
if existingProject.State != domain.ProjectStateInactive {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-5M9bs", "Errors.Project.NotInactive")
|
||||
}
|
||||
if err := c.checkPermissionUpdateProject(ctx, existingProject.ResourceOwner, existingProject.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//nolint: contextcheck
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
||||
@@ -73,20 +79,20 @@ func (c *Commands) reactivateProjectOld(ctx context.Context, projectID string, r
|
||||
return writeModelToObjectDetails(&existingProject.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) checkProjectGrantPreConditionOld(ctx context.Context, projectGrant *domain.ProjectGrant, resourceOwner string) error {
|
||||
preConditions := NewProjectGrantPreConditionReadModel(projectGrant.AggregateID, projectGrant.GrantedOrgID, resourceOwner)
|
||||
func (c *Commands) checkProjectGrantPreConditionOld(ctx context.Context, projectID, grantedOrgID, resourceOwner string, roles []string) (string, error) {
|
||||
preConditions := NewProjectGrantPreConditionReadModel(projectID, grantedOrgID, resourceOwner)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, preConditions)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
if !preConditions.ProjectExists {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMAND-m9gsd", "Errors.Project.NotFound")
|
||||
return "", zerrors.ThrowPreconditionFailed(err, "COMMAND-m9gsd", "Errors.Project.NotFound")
|
||||
}
|
||||
if !preConditions.GrantedOrgExists {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMAND-3m9gg", "Errors.Org.NotFound")
|
||||
return "", zerrors.ThrowPreconditionFailed(err, "COMMAND-3m9gg", "Errors.Org.NotFound")
|
||||
}
|
||||
if projectGrant.HasInvalidRoles(preConditions.ExistingRoleKeys) {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMAND-6m9gd", "Errors.Project.Role.NotFound")
|
||||
if domain.HasInvalidRoles(preConditions.ExistingRoleKeys, roles) {
|
||||
return "", zerrors.ThrowPreconditionFailed(err, "COMMAND-6m9gd", "Errors.Project.Role.NotFound")
|
||||
}
|
||||
return nil
|
||||
return preConditions.ResourceOwner, nil
|
||||
}
|
||||
|
@@ -7,22 +7,45 @@ import (
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func (c *Commands) AddProjectRole(ctx context.Context, projectRole *domain.ProjectRole, resourceOwner string) (_ *domain.ProjectRole, err error) {
|
||||
type AddProjectRole struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Key string
|
||||
DisplayName string
|
||||
Group string
|
||||
}
|
||||
|
||||
func (p *AddProjectRole) IsValid() bool {
|
||||
return p.AggregateID != "" && p.Key != ""
|
||||
}
|
||||
|
||||
func (c *Commands) AddProjectRole(ctx context.Context, projectRole *AddProjectRole) (_ *domain.ObjectDetails, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
err = c.checkProjectExists(ctx, projectRole.AggregateID, resourceOwner)
|
||||
projectResourceOwner, err := c.checkProjectExists(ctx, projectRole.AggregateID, projectRole.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if projectRole.ResourceOwner == "" {
|
||||
projectRole.ResourceOwner = projectResourceOwner
|
||||
}
|
||||
if err := c.checkPermissionWriteProjectRole(ctx, projectRole.ResourceOwner, projectRole.Key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roleWriteModel := NewProjectRoleWriteModelWithKey(projectRole.Key, projectRole.AggregateID, resourceOwner)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&roleWriteModel.WriteModel)
|
||||
roleWriteModel := NewProjectRoleWriteModelWithKey(projectRole.Key, projectRole.AggregateID, projectRole.ResourceOwner)
|
||||
if roleWriteModel.ResourceOwner != projectResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-RLB4UpqQSd", "Errors.Project.Role.Invalid")
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModelWithCTX(ctx, &roleWriteModel.WriteModel)
|
||||
events, err := c.addProjectRoles(ctx, projectAgg, projectRole)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -35,37 +58,45 @@ func (c *Commands) AddProjectRole(ctx context.Context, projectRole *domain.Proje
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return roleWriteModelToRole(roleWriteModel), nil
|
||||
return writeModelToObjectDetails(&roleWriteModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) BulkAddProjectRole(ctx context.Context, projectID, resourceOwner string, projectRoles []*domain.ProjectRole) (details *domain.ObjectDetails, err error) {
|
||||
err = c.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
func (c *Commands) checkPermissionWriteProjectRole(ctx context.Context, resourceOwner, roleKey string) error {
|
||||
return c.checkPermission(ctx, domain.PermissionProjectRoleWrite, resourceOwner, roleKey)
|
||||
}
|
||||
|
||||
func (c *Commands) BulkAddProjectRole(ctx context.Context, projectID, resourceOwner string, projectRoles []*AddProjectRole) (details *domain.ObjectDetails, err error) {
|
||||
projectResourceOwner, err := c.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, projectRole := range projectRoles {
|
||||
if projectRole.ResourceOwner == "" {
|
||||
projectRole.ResourceOwner = projectResourceOwner
|
||||
}
|
||||
if err := c.checkPermissionWriteProjectRole(ctx, projectRole.ResourceOwner, projectRole.Key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if projectRole.ResourceOwner != projectResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-9ZXtdaJKJJ", "Errors.Project.Role.Invalid")
|
||||
}
|
||||
}
|
||||
|
||||
roleWriteModel := NewProjectRoleWriteModel(projectID, resourceOwner)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&roleWriteModel.WriteModel)
|
||||
projectAgg := ProjectAggregateFromWriteModelWithCTX(ctx, &roleWriteModel.WriteModel)
|
||||
events, err := c.addProjectRoles(ctx, projectAgg, projectRoles...)
|
||||
if err != nil {
|
||||
return details, err
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, events...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(roleWriteModel, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&roleWriteModel.WriteModel), nil
|
||||
return c.pushAppendAndReduceDetails(ctx, roleWriteModel, events...)
|
||||
}
|
||||
|
||||
func (c *Commands) addProjectRoles(ctx context.Context, projectAgg *eventstore.Aggregate, projectRoles ...*domain.ProjectRole) ([]eventstore.Command, error) {
|
||||
func (c *Commands) addProjectRoles(ctx context.Context, projectAgg *eventstore.Aggregate, projectRoles ...*AddProjectRole) ([]eventstore.Command, error) {
|
||||
var events []eventstore.Command
|
||||
for _, projectRole := range projectRoles {
|
||||
projectRole.AggregateID = projectAgg.ID
|
||||
if projectRole.ResourceOwner != projectAgg.ResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-4Q2WjlbHvc", "Errors.Project.Role.Invalid")
|
||||
}
|
||||
if !projectRole.IsValid() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.Role.Invalid")
|
||||
}
|
||||
@@ -81,42 +112,55 @@ func (c *Commands) addProjectRoles(ctx context.Context, projectAgg *eventstore.A
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeProjectRole(ctx context.Context, projectRole *domain.ProjectRole, resourceOwner string) (_ *domain.ProjectRole, err error) {
|
||||
type ChangeProjectRole struct {
|
||||
models.ObjectRoot
|
||||
|
||||
Key string
|
||||
DisplayName string
|
||||
Group string
|
||||
}
|
||||
|
||||
func (p *ChangeProjectRole) IsValid() bool {
|
||||
return p.AggregateID != "" && p.Key != ""
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeProjectRole(ctx context.Context, projectRole *ChangeProjectRole) (_ *domain.ObjectDetails, err error) {
|
||||
if !projectRole.IsValid() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-2ilfW", "Errors.Project.Invalid")
|
||||
}
|
||||
err = c.checkProjectExists(ctx, projectRole.AggregateID, resourceOwner)
|
||||
projectResourceOwner, err := c.checkProjectExists(ctx, projectRole.AggregateID, projectRole.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if projectRole.ResourceOwner == "" {
|
||||
projectRole.ResourceOwner = projectResourceOwner
|
||||
}
|
||||
if err := c.checkPermissionWriteProjectRole(ctx, projectRole.ResourceOwner, projectRole.Key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingRole, err := c.getProjectRoleWriteModelByID(ctx, projectRole.Key, projectRole.AggregateID, resourceOwner)
|
||||
existingRole, err := c.getProjectRoleWriteModelByID(ctx, projectRole.Key, projectRole.AggregateID, projectRole.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingRole.State == domain.ProjectRoleStateUnspecified || existingRole.State == domain.ProjectRoleStateRemoved {
|
||||
if !existingRole.State.Exists() {
|
||||
return nil, zerrors.ThrowNotFound(nil, "COMMAND-vv8M9", "Errors.Project.Role.NotExisting")
|
||||
}
|
||||
if existingRole.ResourceOwner != projectResourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-3MizLWveMf", "Errors.Project.Role.Invalid")
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingRole.WriteModel)
|
||||
projectAgg := ProjectAggregateFromWriteModelWithCTX(ctx, &existingRole.WriteModel)
|
||||
|
||||
changeEvent, changed, err := existingRole.NewProjectRoleChangedEvent(ctx, projectAgg, projectRole.Key, projectRole.DisplayName, projectRole.Group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !changed {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-5M0cs", "Errors.NoChangesFound")
|
||||
return writeModelToObjectDetails(&existingRole.WriteModel), nil
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, changeEvent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingRole, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return roleWriteModelToRole(existingRole), nil
|
||||
return c.pushAppendAndReduceDetails(ctx, existingRole, changeEvent)
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveProjectRole(ctx context.Context, projectID, key, resourceOwner string, cascadingProjectGrantIds []string, cascadeUserGrantIDs ...string) (details *domain.ObjectDetails, err error) {
|
||||
@@ -127,10 +171,14 @@ func (c *Commands) RemoveProjectRole(ctx context.Context, projectID, key, resour
|
||||
if err != nil {
|
||||
return details, err
|
||||
}
|
||||
if existingRole.State == domain.ProjectRoleStateUnspecified || existingRole.State == domain.ProjectRoleStateRemoved {
|
||||
return details, zerrors.ThrowNotFound(nil, "COMMAND-m9vMf", "Errors.Project.Role.NotExisting")
|
||||
// return if project role is not existing
|
||||
if !existingRole.State.Exists() {
|
||||
return writeModelToObjectDetails(&existingRole.WriteModel), nil
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingRole.WriteModel)
|
||||
if err := c.checkPermissionDeleteProjectRole(ctx, existingRole.ResourceOwner, existingRole.Key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModelWithCTX(ctx, &existingRole.WriteModel)
|
||||
events := []eventstore.Command{
|
||||
project.NewRoleRemovedEvent(ctx, projectAgg, key),
|
||||
}
|
||||
@@ -153,15 +201,11 @@ func (c *Commands) RemoveProjectRole(ctx context.Context, projectID, key, resour
|
||||
events = append(events, event)
|
||||
}
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, events...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = AppendAndReduce(existingRole, pushedEvents...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&existingRole.WriteModel), nil
|
||||
return c.pushAppendAndReduceDetails(ctx, existingRole, events...)
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionDeleteProjectRole(ctx context.Context, resourceOwner, roleKey string) error {
|
||||
return c.checkPermission(ctx, domain.PermissionProjectRoleDelete, resourceOwner, roleKey)
|
||||
}
|
||||
|
||||
func (c *Commands) getProjectRoleWriteModelByID(ctx context.Context, key, projectID, resourceOwner string) (*ProjectRoleWriteModel, error) {
|
||||
|
@@ -17,6 +17,10 @@ type ProjectRoleWriteModel struct {
|
||||
State domain.ProjectRoleState
|
||||
}
|
||||
|
||||
func (wm *ProjectRoleWriteModel) GetWriteModel() *eventstore.WriteModel {
|
||||
return &wm.WriteModel
|
||||
}
|
||||
|
||||
func NewProjectRoleWriteModelWithKey(key, projectID, resourceOwner string) *ProjectRoleWriteModel {
|
||||
return &ProjectRoleWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
|
@@ -16,15 +16,15 @@ import (
|
||||
|
||||
func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
role *domain.ProjectRole
|
||||
resourceOwner string
|
||||
ctx context.Context
|
||||
role *AddProjectRole
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ProjectRole
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
@@ -36,8 +36,7 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "project not existing, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -55,16 +54,16 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &AddProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
Key: "key1",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsPreconditionFailed,
|
||||
@@ -73,8 +72,7 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "invalid role, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -85,15 +83,15 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &AddProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsErrorInvalidArgument,
|
||||
@@ -102,8 +100,7 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role key already exists, already exists error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -123,10 +120,11 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &AddProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
@@ -134,7 +132,6 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
DisplayName: "key",
|
||||
Group: "group",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsErrorAlreadyExists,
|
||||
@@ -143,8 +140,7 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "add role,ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -164,10 +160,11 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &AddProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
@@ -175,10 +172,41 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
DisplayName: "key",
|
||||
Group: "group",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ProjectRole{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add role, resourceowner, ok",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
"projectname1", true, true, true,
|
||||
domain.PrivateLabelingSettingUnspecified,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
project.NewRoleAddedEvent(
|
||||
context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
"key1",
|
||||
"key",
|
||||
"group",
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &AddProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
ResourceOwner: "org1",
|
||||
@@ -188,14 +216,20 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
Group: "group",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
}
|
||||
got, err := r.AddProjectRole(tt.args.ctx, tt.args.role, tt.args.resourceOwner)
|
||||
got, err := r.AddProjectRole(tt.args.ctx, tt.args.role)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -203,7 +237,7 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
assertObjectDetails(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -211,11 +245,12 @@ func TestCommandSide_AddProjectRole(t *testing.T) {
|
||||
|
||||
func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
roles []*domain.ProjectRole
|
||||
roles []*AddProjectRole
|
||||
projectID string
|
||||
resourceOwner string
|
||||
}
|
||||
@@ -232,8 +267,7 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "project not existing, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -251,10 +285,11 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
roles: []*domain.ProjectRole{
|
||||
roles: []*AddProjectRole{
|
||||
{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
@@ -271,8 +306,7 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "invalid role, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -283,10 +317,11 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
roles: []*domain.ProjectRole{
|
||||
roles: []*AddProjectRole{
|
||||
{
|
||||
ObjectRoot: models.ObjectRoot{},
|
||||
},
|
||||
@@ -304,8 +339,7 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role key already exists, already exists error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -332,16 +366,23 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
roles: []*domain.ProjectRole{
|
||||
roles: []*AddProjectRole{
|
||||
{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
Key: "key1",
|
||||
DisplayName: "key",
|
||||
Group: "group",
|
||||
},
|
||||
{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
Key: "key2",
|
||||
DisplayName: "key2",
|
||||
Group: "group",
|
||||
@@ -357,8 +398,7 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "add roles,ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -385,16 +425,23 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
roles: []*domain.ProjectRole{
|
||||
roles: []*AddProjectRole{
|
||||
{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
Key: "key1",
|
||||
DisplayName: "key",
|
||||
Group: "group",
|
||||
},
|
||||
{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
Key: "key2",
|
||||
DisplayName: "key2",
|
||||
Group: "group",
|
||||
@@ -413,7 +460,8 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
}
|
||||
got, err := r.BulkAddProjectRole(tt.args.ctx, tt.args.projectID, tt.args.resourceOwner, tt.args.roles)
|
||||
if tt.res.err == nil {
|
||||
@@ -431,15 +479,15 @@ func TestCommandSide_BulkAddProjectRole(t *testing.T) {
|
||||
|
||||
func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
role *domain.ProjectRole
|
||||
resourceOwner string
|
||||
ctx context.Context
|
||||
role *ChangeProjectRole
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ProjectRole
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
@@ -451,18 +499,16 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "invalid role, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &ChangeProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsErrorInvalidArgument,
|
||||
@@ -471,8 +517,7 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "project not existing, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -490,16 +535,16 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &ChangeProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
Key: "key1",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsPreconditionFailed,
|
||||
@@ -508,8 +553,7 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role removed, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -536,10 +580,11 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &ChangeProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
@@ -547,7 +592,6 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
DisplayName: "key",
|
||||
Group: "group",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsNotFound,
|
||||
@@ -556,8 +600,7 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role not changed, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -578,10 +621,11 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &ChangeProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
@@ -589,17 +633,17 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
DisplayName: "key",
|
||||
Group: "group",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsPreconditionFailed,
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "role changed, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
@@ -623,10 +667,11 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
newRoleChangedEvent(context.Background(), "project1", "org1", "key1", "keychanged", "groupchanged"),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
role: &domain.ProjectRole{
|
||||
role: &ChangeProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
@@ -634,17 +679,10 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
DisplayName: "keychanged",
|
||||
Group: "groupchanged",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ProjectRole{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
Key: "key1",
|
||||
DisplayName: "keychanged",
|
||||
Group: "groupchanged",
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -652,9 +690,10 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
}
|
||||
got, err := r.ChangeProjectRole(tt.args.ctx, tt.args.role, tt.args.resourceOwner)
|
||||
got, err := r.ChangeProjectRole(tt.args.ctx, tt.args.role)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -662,7 +701,7 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
assertObjectDetails(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -670,7 +709,8 @@ func TestCommandSide_ChangeProjectRole(t *testing.T) {
|
||||
|
||||
func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -693,9 +733,8 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "invalid projectid, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -709,9 +748,8 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "invalid key, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -726,10 +764,10 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role not existing, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -738,14 +776,15 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsNotFound,
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "role removed, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewRoleAddedEvent(context.Background(),
|
||||
@@ -763,6 +802,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -771,14 +811,15 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsNotFound,
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "role removed, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewRoleAddedEvent(context.Background(),
|
||||
@@ -796,6 +837,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -812,8 +854,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role removed with cascadingProjectGrantids, grant not found, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewRoleAddedEvent(context.Background(),
|
||||
@@ -832,6 +873,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -849,8 +891,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role removed with cascadingProjectGrantids, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewRoleAddedEvent(context.Background(),
|
||||
@@ -883,6 +924,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -900,8 +942,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role removed with cascadingUserGrantIDs, grant not found, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewRoleAddedEvent(context.Background(),
|
||||
@@ -920,6 +961,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -937,8 +979,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
{
|
||||
name: "role removed with cascadingUserGrantIDs, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewRoleAddedEvent(context.Background(),
|
||||
@@ -969,6 +1010,7 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -987,7 +1029,8 @@ func TestCommandSide_RemoveProjectRole(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
}
|
||||
got, err := r.RemoveProjectRole(tt.args.ctx, tt.args.projectID, tt.args.key, tt.args.resourceOwner, tt.args.cascadingProjectGrantIDs, tt.args.cascadingUserGrantIDs...)
|
||||
if tt.res.err == nil {
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user