diff --git a/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppContributors.cs b/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppContributors.cs index 74f0bb850..67e80ac37 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppContributors.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppContributors.cs @@ -44,21 +44,24 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards command.ContributorId = user.Id; - if (string.Equals(command.ContributorId, command.Actor?.Identifier, StringComparison.OrdinalIgnoreCase) && !command.IsRestore) + if (!command.IsRestore) { - throw new DomainForbiddenException("You cannot change your own role."); - } + if (string.Equals(command.ContributorId, command.Actor?.Identifier, StringComparison.OrdinalIgnoreCase)) + { + throw new DomainForbiddenException("You cannot change your own role."); + } - if (contributors.TryGetValue(command.ContributorId, out var existing)) - { - if (existing == command.Role) + if (contributors.TryGetValue(command.ContributorId, out var existing)) { - e(Not.New("Contributor", "role"), nameof(command.Role)); + if (existing == command.Role) + { + e(Not.New("Contributor", "role"), nameof(command.Role)); + } + } + else if (contributors.Count >= plan.MaxContributors) + { + e("You have reached the maximum number of contributors for your plan."); } - } - else if (contributors.Count >= plan.MaxContributors && !command.IsRestore) - { - e("You have reached the maximum number of contributors for your plan."); } }); } diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsGrainTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsGrainTests.cs index 7859d6107..1eed86347 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsGrainTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsGrainTests.cs @@ -107,15 +107,15 @@ namespace Squidex.Domain.Apps.Entities.Apps } [Fact] - public Task Should_do_nothing_if_deleting_and_nested_not_found() + public async Task Should_do_nothing_if_deleting_and_nested_not_found() { - return sut.RemoveAsync("root.nested"); + await sut.RemoveAsync("root.nested"); } [Fact] - public Task Should_do_nothing_if_deleting_and_key_not_found() + public async Task Should_do_nothing_if_deleting_and_key_not_found() { - return sut.RemoveAsync("root"); + await sut.RemoveAsync("root"); } } } diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppContributorsTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppContributorsTests.cs index 71f9bb239..92ceef6ab 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppContributorsTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppContributorsTests.cs @@ -51,52 +51,62 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards } [Fact] - public Task CanAssign_should_throw_exception_if_contributor_id_is_null() + public async Task CanAssign_should_throw_exception_if_contributor_id_is_null() { var command = new AssignContributor(); - return ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan), + await ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan), new ValidationError("Contributor id is required.", "ContributorId")); } [Fact] - public Task CanAssign_should_throw_exception_if_role_not_valid() + public async Task CanAssign_should_throw_exception_if_role_not_valid() { var command = new AssignContributor { ContributorId = "1", Role = "Invalid" }; - return ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan), + await ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan), new ValidationError("Role is not a valid value.", "Role")); } [Fact] - public Task CanAssign_should_throw_exception_if_user_already_exists_with_same_role() + public async Task CanAssign_should_throw_exception_if_user_already_exists_with_same_role() { var command = new AssignContributor { ContributorId = "1", Role = Role.Owner }; var contributors_1 = contributors_0.Assign("1", Role.Owner); - return ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_1, roles, command, users, appPlan), + await ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_1, roles, command, users, appPlan), new ValidationError("Contributor has already this role.", "Role")); } [Fact] - public Task CanAssign_should_throw_exception_if_user_not_found() + public async Task CanAssign_should_not_throw_exception_if_user_already_exists_with_some_role_but_is_from_restore() + { + var command = new AssignContributor { ContributorId = "1", Role = Role.Owner, IsRestore = true }; + + var contributors_1 = contributors_0.Assign("1", Role.Owner); + + await GuardAppContributors.CanAssign(contributors_1, roles, command, users, appPlan); + } + + [Fact] + public async Task CanAssign_should_throw_exception_if_user_not_found() { var command = new AssignContributor { ContributorId = "notfound", Role = Role.Owner }; - return Assert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan)); + await Assert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan)); } [Fact] - public Task CanAssign_should_throw_exception_if_user_is_actor() + public async Task CanAssign_should_throw_exception_if_user_is_actor() { var command = new AssignContributor { ContributorId = "3", Role = Role.Editor, Actor = new RefToken("user", "3") }; - return Assert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan)); + await Assert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan)); } [Fact] - public Task CanAssign_should_throw_exception_if_contributor_max_reached() + public async Task CanAssign_should_throw_exception_if_contributor_max_reached() { A.CallTo(() => appPlan.MaxContributors) .Returns(2); @@ -106,7 +116,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards var contributors_1 = contributors_0.Assign("1", Role.Owner); var contributors_2 = contributors_1.Assign("2", Role.Editor); - return ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_2, roles, command, users, appPlan), + await ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(contributors_2, roles, command, users, appPlan), new ValidationError("You have reached the maximum number of contributors for your plan.")); } @@ -121,35 +131,49 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards } [Fact] - public Task CanAssign_should_not_throw_exception_if_user_found() + public async Task CanAssign_should_not_throw_exception_if_user_found() { var command = new AssignContributor { ContributorId = "1" }; - return GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan); + await GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan); } [Fact] - public Task CanAssign_should_not_throw_exception_if_contributor_has_another_role() + public async Task CanAssign_should_not_throw_exception_if_contributor_has_another_role() { - var command = new AssignContributor { ContributorId = "1", Role = Role.Developer }; + var command = new AssignContributor { ContributorId = "1" }; var contributors_1 = contributors_0.Assign("1", Role.Editor); - return GuardAppContributors.CanAssign(contributors_1, roles, command, users, appPlan); + await GuardAppContributors.CanAssign(contributors_1, roles, command, users, appPlan); + } + + [Fact] + public async Task CanAssign_should_not_throw_exception_if_contributor_max_reached_but_role_changed() + { + A.CallTo(() => appPlan.MaxContributors) + .Returns(2); + + var command = new AssignContributor { ContributorId = "1" }; + + var contributors_1 = contributors_0.Assign("1", Role.Editor); + var contributors_2 = contributors_1.Assign("2", Role.Editor); + + await GuardAppContributors.CanAssign(contributors_2, roles, command, users, appPlan); } [Fact] - public Task CanAssign_should_not_throw_exception_if_contributor_max_reached_but_role_changed() + public async Task CanAssign_should_not_throw_exception_if_contributor_max_reached_but_from_restore() { A.CallTo(() => appPlan.MaxContributors) .Returns(2); - var command = new AssignContributor { ContributorId = "1", Role = Role.Developer }; + var command = new AssignContributor { ContributorId = "3", IsRestore = true }; var contributors_1 = contributors_0.Assign("1", Role.Editor); var contributors_2 = contributors_1.Assign("2", Role.Editor); - return GuardAppContributors.CanAssign(contributors_2, roles, command, users, appPlan); + await GuardAppContributors.CanAssign(contributors_2, roles, command, users, appPlan); } [Fact] diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs index ad1899ede..b0e29dabd 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs @@ -328,14 +328,14 @@ namespace Squidex.Domain.Apps.Entities.Contents } [Fact] - public Task Should_throw_if_query_is_invalid() + public async Task Should_throw_if_query_is_invalid() { SetupClaims(isFrontend: false); SetupSchemaFound(); var query = Q.Empty.WithODataQuery("$filter=invalid"); - return Assert.ThrowsAsync(() => sut.QueryAsync(context, schemaId.Name, query)); + await Assert.ThrowsAsync(() => sut.QueryAsync(context, schemaId.Name, query)); } public static IEnumerable ManyDataFrontend = new[] diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs index b8fcb0d48..363b8f1ef 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs @@ -60,9 +60,9 @@ namespace Squidex.Domain.Apps.Entities.Rules } [Fact] - public Task Should_do_nothing_on_clear() + public async Task Should_do_nothing_on_clear() { - return sut.ClearAsync(); + await sut.ClearAsync(); } [Fact] diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaTests.cs index 2d257f179..adac83401 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaTests.cs @@ -41,25 +41,25 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards } [Fact] - public Task CanCreate_should_throw_exception_if_name_not_valid() + public async Task CanCreate_should_throw_exception_if_name_not_valid() { var command = new CreateSchema { AppId = appId, Name = "INVALID NAME" }; - return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), new ValidationError("Name is not a valid slug.", "Name")); } [Fact] - public Task CanCreate_should_throw_exception_if_name_already_in_use() + public async Task CanCreate_should_throw_exception_if_name_already_in_use() { var command = new CreateSchema { AppId = appId, Name = "existing" }; - return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), new ValidationError("A schema with the same name already exists.")); } [Fact] - public Task CanCreate_should_throw_exception_if_field_name_invalid() + public async Task CanCreate_should_throw_exception_if_field_name_invalid() { var command = new CreateSchema { @@ -76,13 +76,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards Name = "new-schema" }; - return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), new ValidationError("Field name must be a valid javascript property name.", "Fields[1].Name")); } [Fact] - public Task CanCreate_should_throw_exception_if_field_properties_null() + public async Task CanCreate_should_throw_exception_if_field_properties_null() { var command = new CreateSchema { @@ -99,13 +99,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards Name = "new-schema" }; - return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), new ValidationError("Field properties is required.", "Fields[1].Properties")); } [Fact] - public Task CanCreate_should_throw_exception_if_field_properties_not_valid() + public async Task CanCreate_should_throw_exception_if_field_properties_not_valid() { var command = new CreateSchema { @@ -122,14 +122,14 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards Name = "new-schema" }; - return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), new ValidationError("Max length must be greater or equal to min length.", "Fields[1].Properties.MinLength", "Fields[1].Properties.MaxLength")); } [Fact] - public Task CanCreate_should_throw_exception_if_field_partitioning_not_valid() + public async Task CanCreate_should_throw_exception_if_field_partitioning_not_valid() { var command = new CreateSchema { @@ -146,13 +146,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards Name = "new-schema" }; - return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), new ValidationError("Partitioning is not a valid value.", "Fields[1].Partitioning")); } [Fact] - public Task CanCreate_should_throw_exception_if_fields_contains_duplicate_name() + public async Task CanCreate_should_throw_exception_if_fields_contains_duplicate_name() { var command = new CreateSchema { @@ -175,13 +175,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards Name = "new-schema" }; - return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), new ValidationError("Fields cannot have duplicate names.", "Fields")); } [Fact] - public Task CanCreate_should_throw_exception_if_nested_field_name_invalid() + public async Task CanCreate_should_throw_exception_if_nested_field_name_invalid() { var command = new CreateSchema { @@ -206,13 +206,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards Name = "new-schema" }; - return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), new ValidationError("Field name must be a valid javascript property name.", "Fields[1].Nested[1].Name")); } [Fact] - public Task CanCreate_should_throw_exception_if_nested_field_properties_null() + public async Task CanCreate_should_throw_exception_if_nested_field_properties_null() { var command = new CreateSchema { @@ -237,13 +237,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards Name = "new-schema" }; - return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), new ValidationError("Field properties is required.", "Fields[1].Nested[1].Properties")); } [Fact] - public Task CanCreate_should_throw_exception_if_nested_field_is_array() + public async Task CanCreate_should_throw_exception_if_nested_field_is_array() { var command = new CreateSchema { @@ -268,13 +268,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards Name = "new-schema" }; - return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), new ValidationError("Nested field cannot be array fields.", "Fields[1].Nested[1].Properties")); } [Fact] - public Task CanCreate_should_throw_exception_if_nested_field_properties_not_valid() + public async Task CanCreate_should_throw_exception_if_nested_field_properties_not_valid() { var command = new CreateSchema { @@ -299,14 +299,14 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards Name = "new-schema" }; - return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), new ValidationError("Max length must be greater or equal to min length.", "Fields[1].Nested[1].Properties.MinLength", "Fields[1].Nested[1].Properties.MaxLength")); } [Fact] - public Task CanCreate_should_throw_exception_if_nested_field_have_duplicate_names() + public async Task CanCreate_should_throw_exception_if_nested_field_have_duplicate_names() { var command = new CreateSchema { @@ -336,13 +336,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards Name = "new-schema" }; - return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), new ValidationError("Fields cannot have duplicate names.", "Fields[1].Nested")); } [Fact] - public Task CanCreate_should_not_throw_exception_if_command_is_valid() + public async Task CanCreate_should_not_throw_exception_if_command_is_valid() { var command = new CreateSchema { @@ -384,7 +384,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards Name = "new-schema" }; - return GuardSchema.CanCreate(command, appProvider); + await GuardSchema.CanCreate(command, appProvider); } [Fact] diff --git a/tests/Squidex.Infrastructure.Tests/Assets/AssetStoreTests.cs b/tests/Squidex.Infrastructure.Tests/Assets/AssetStoreTests.cs index 26dc836cb..e066217e5 100644 --- a/tests/Squidex.Infrastructure.Tests/Assets/AssetStoreTests.cs +++ b/tests/Squidex.Infrastructure.Tests/Assets/AssetStoreTests.cs @@ -37,15 +37,15 @@ namespace Squidex.Infrastructure.Assets public abstract T CreateStore(); [Fact] - public virtual Task Should_throw_exception_if_asset_to_download_is_not_found() + public virtual async Task Should_throw_exception_if_asset_to_download_is_not_found() { - return Assert.ThrowsAsync(() => Sut.DownloadAsync(fileName, new MemoryStream())); + await Assert.ThrowsAsync(() => Sut.DownloadAsync(fileName, new MemoryStream())); } [Fact] - public Task Should_throw_exception_if_asset_to_copy_is_not_found() + public async Task Should_throw_exception_if_asset_to_copy_is_not_found() { - return Assert.ThrowsAsync(() => Sut.CopyAsync(fileName, sourceFile)); + await Assert.ThrowsAsync(() => Sut.CopyAsync(fileName, sourceFile)); } [Fact] diff --git a/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs b/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs index cf9692bcb..82b7bced7 100644 --- a/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs +++ b/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs @@ -28,27 +28,27 @@ namespace Squidex.Infrastructure.UsageTracking } [Fact] - public Task Should_throw_exception_if_tracking_on_disposed_object() + public async Task Should_throw_exception_if_tracking_on_disposed_object() { sut.Dispose(); - return Assert.ThrowsAsync(() => sut.TrackAsync(key, "category1", 1, 1000)); + await Assert.ThrowsAsync(() => sut.TrackAsync(key, "category1", 1, 1000)); } [Fact] - public Task Should_throw_exception_if_querying_on_disposed_object() + public async Task Should_throw_exception_if_querying_on_disposed_object() { sut.Dispose(); - return Assert.ThrowsAsync(() => sut.QueryAsync(key, DateTime.Today, DateTime.Today.AddDays(1))); + await Assert.ThrowsAsync(() => sut.QueryAsync(key, DateTime.Today, DateTime.Today.AddDays(1))); } [Fact] - public Task Should_throw_exception_if_querying_montly_usage_on_disposed_object() + public async Task Should_throw_exception_if_querying_montly_usage_on_disposed_object() { sut.Dispose(); - return Assert.ThrowsAsync(() => sut.GetMonthlyCallsAsync(key, DateTime.Today)); + await Assert.ThrowsAsync(() => sut.GetMonthlyCallsAsync(key, DateTime.Today)); } [Fact]