Browse Source

Merge branch 'master' into feature/separators

pull/359/head
Sebastian Stehle 8 years ago
parent
commit
c671745a3d
  1. 25
      src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppContributors.cs
  2. 2
      src/Squidex.Domain.Apps.Entities/Apps/Services/Implementations/ConfigAppPlansProvider.cs
  3. 25
      src/Squidex.Domain.Apps.Entities/Backup/RestoreGrain.cs
  4. 38
      src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs
  5. 38
      src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs
  6. 2
      src/Squidex/app/features/settings/pages/plans/plans-page.component.html
  7. 4
      src/Squidex/app/framework/state.ts
  8. 1
      src/Squidex/app/shared/state/assets.forms.ts
  9. 4
      src/Squidex/appsettings.json
  10. 4
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppGrainTests.cs
  11. 8
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsGrainTests.cs
  12. 2
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/Billing/ConfigAppLimitsProviderTests.cs
  13. 64
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppContributorsTests.cs
  14. 4
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs
  15. 4
      tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs
  16. 52
      tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaTests.cs
  17. 8
      tests/Squidex.Infrastructure.Tests/Assets/AssetStoreTests.cs
  18. 12
      tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs

25
src/Squidex.Domain.Apps.Entities/Apps/Guards/GuardAppContributors.cs

@ -44,21 +44,24 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
command.ContributorId = user.Id; 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 (contributors.TryGetValue(command.ContributorId, out var existing))
{
if (existing == command.Role)
{ {
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 (plan.MaxContributors == contributors.Count)
{
e("You have reached the maximum number of contributors for your plan.");
} }
}); });
} }

2
src/Squidex.Domain.Apps.Entities/Apps/Services/Implementations/ConfigAppPlansProvider.cs

@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Services.Implementations
Name = "Infinite", Name = "Infinite",
MaxApiCalls = -1, MaxApiCalls = -1,
MaxAssetSize = -1, MaxAssetSize = -1,
MaxContributors = -1 MaxContributors = int.MaxValue
}; };
private readonly Dictionary<string, ConfigAppLimitsPlan> plansById = new Dictionary<string, ConfigAppLimitsPlan>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<string, ConfigAppLimitsPlan> plansById = new Dictionary<string, ConfigAppLimitsPlan>(StringComparer.OrdinalIgnoreCase);

25
src/Squidex.Domain.Apps.Entities/Backup/RestoreGrain.cs

@ -246,16 +246,23 @@ namespace Squidex.Domain.Apps.Entities.Backup
if (actor?.IsSubject == true) if (actor?.IsSubject == true)
{ {
await commandBus.PublishAsync(new AssignContributor try
{ {
Actor = actor, await commandBus.PublishAsync(new AssignContributor
AppId = CurrentJob.AppId, {
ContributorId = actor.Identifier, Actor = actor,
IsRestore = true, AppId = CurrentJob.AppId,
Role = Role.Owner ContributorId = actor.Identifier,
}); IsRestore = true,
Role = Role.Owner
Log("Assigned current user."); });
Log("Assigned current user.");
}
catch (DomainException ex)
{
Log($"Failed to assign contributor: {ex.Message}");
}
} }
else else
{ {

38
src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs

@ -8,6 +8,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Assets;
@ -47,7 +48,8 @@ namespace Squidex.Areas.Api.Controllers.Assets
/// <summary> /// <summary>
/// Get the asset content. /// Get the asset content.
/// </summary> /// </summary>
/// <param name="id">The id of the asset.</param> /// <param name="app">The name of the app.</param>
/// <param name="idOrSlug">The id or slug of the asset.</param>
/// <param name="more">Optional suffix that can be used to seo-optimize the link to the image Has not effect.</param> /// <param name="more">Optional suffix that can be used to seo-optimize the link to the image Has not effect.</param>
/// <param name="version">The optional version of the asset.</param> /// <param name="version">The optional version of the asset.</param>
/// <param name="width">The target width of the asset, if it is an image.</param> /// <param name="width">The target width of the asset, if it is an image.</param>
@ -59,17 +61,27 @@ namespace Squidex.Areas.Api.Controllers.Assets
/// 404 => Asset or app not found. /// 404 => Asset or app not found.
/// </returns> /// </returns>
[HttpGet] [HttpGet]
[Route("assets/{id}/{*more}")] [Route("assets/{app}/{idOrSlug}/{*more}")]
[ProducesResponseType(typeof(FileResult), 200)] [ProducesResponseType(typeof(FileResult), 200)]
[ApiCosts(0.5)] [ApiCosts(0.5)]
public async Task<IActionResult> GetAssetContent(Guid id, string more, [AllowAnonymous]
public async Task<IActionResult> GetAssetContentBySlug(string app, string idOrSlug, string more,
[FromQuery] long version = EtagVersion.Any, [FromQuery] long version = EtagVersion.Any,
[FromQuery] int? width = null, [FromQuery] int? width = null,
[FromQuery] int? height = null, [FromQuery] int? height = null,
[FromQuery] int? quality = null, [FromQuery] int? quality = null,
[FromQuery] string mode = null) [FromQuery] string mode = null)
{ {
var entity = await assetRepository.FindAssetAsync(id); IAssetEntity entity;
if (Guid.TryParse(idOrSlug, out var guid))
{
entity = await assetRepository.FindAssetAsync(guid);
}
else
{
entity = await assetRepository.FindAssetBySlugAsync(App.Id, idOrSlug);
}
return DeliverAsset(entity, version, width, height, quality, mode); return DeliverAsset(entity, version, width, height, quality, mode);
} }
@ -77,8 +89,7 @@ namespace Squidex.Areas.Api.Controllers.Assets
/// <summary> /// <summary>
/// Get the asset content. /// Get the asset content.
/// </summary> /// </summary>
/// <param name="app">The name of the app.</param> /// <param name="id">The id of the asset.</param>
/// <param name="idOrSlug">The id or slug of the asset.</param>
/// <param name="more">Optional suffix that can be used to seo-optimize the link to the image Has not effect.</param> /// <param name="more">Optional suffix that can be used to seo-optimize the link to the image Has not effect.</param>
/// <param name="version">The optional version of the asset.</param> /// <param name="version">The optional version of the asset.</param>
/// <param name="width">The target width of the asset, if it is an image.</param> /// <param name="width">The target width of the asset, if it is an image.</param>
@ -90,26 +101,17 @@ namespace Squidex.Areas.Api.Controllers.Assets
/// 404 => Asset or app not found. /// 404 => Asset or app not found.
/// </returns> /// </returns>
[HttpGet] [HttpGet]
[Route("assets/{app}/{idOrSlug}/{*more}")] [Route("assets/{id}/{*more}")]
[ProducesResponseType(typeof(FileResult), 200)] [ProducesResponseType(typeof(FileResult), 200)]
[ApiCosts(0.5)] [ApiCosts(0.5)]
public async Task<IActionResult> GetAssetContent(string app, string idOrSlug, string more, public async Task<IActionResult> GetAssetContent(Guid id, string more,
[FromQuery] long version = EtagVersion.Any, [FromQuery] long version = EtagVersion.Any,
[FromQuery] int? width = null, [FromQuery] int? width = null,
[FromQuery] int? height = null, [FromQuery] int? height = null,
[FromQuery] int? quality = null, [FromQuery] int? quality = null,
[FromQuery] string mode = null) [FromQuery] string mode = null)
{ {
IAssetEntity entity; var entity = await assetRepository.FindAssetAsync(id);
if (Guid.TryParse(idOrSlug, out var guid))
{
entity = await assetRepository.FindAssetAsync(guid);
}
else
{
entity = await assetRepository.FindAssetBySlugAsync(App.Id, idOrSlug);
}
return DeliverAsset(entity, version, width, height, quality, mode); return DeliverAsset(entity, version, width, height, quality, mode);
} }

38
src/Squidex/Areas/Frontend/Middlewares/WebpackMiddleware.cs

@ -25,28 +25,25 @@ namespace Squidex.Areas.Frontend.Middlewares
public async Task Invoke(HttpContext context) public async Task Invoke(HttpContext context)
{ {
if (context.IsIndex()) if (context.IsIndex() && context.Response.StatusCode != 304)
{ {
if (context.Response.StatusCode != 304) using (var client = new HttpClient())
{ {
using (var client = new HttpClient()) var result = await client.GetAsync(WebpackUrl);
{
var result = await client.GetAsync(WebpackUrl);
context.Response.StatusCode = (int)result.StatusCode; context.Response.StatusCode = (int)result.StatusCode;
if (result.IsSuccessStatusCode) if (result.IsSuccessStatusCode)
{ {
var html = await result.Content.ReadAsStringAsync(); var html = await result.Content.ReadAsStringAsync();
html = AdjustBase(html, context.Request.PathBase); html = AdjustBase(html, context.Request.PathBase);
await context.Response.WriteHtmlAsync(html); await context.Response.WriteHtmlAsync(html);
}
} }
} }
} }
else if (context.IsHtmlPath()) else if (context.IsHtmlPath() && context.Response.StatusCode != 304)
{ {
var responseBuffer = new MemoryStream(); var responseBuffer = new MemoryStream();
var responseBody = context.Response.Body; var responseBody = context.Response.Body;
@ -55,16 +52,19 @@ namespace Squidex.Areas.Frontend.Middlewares
await next(context); await next(context);
context.Response.Body = responseBody; if (context.Response.StatusCode != 304)
{
context.Response.Body = responseBody;
var html = Encoding.UTF8.GetString(responseBuffer.ToArray()); var html = Encoding.UTF8.GetString(responseBuffer.ToArray());
html = AdjustBase(html, context.Request.PathBase); html = AdjustBase(html, context.Request.PathBase);
context.Response.ContentLength = Encoding.UTF8.GetByteCount(html); context.Response.ContentLength = Encoding.UTF8.GetByteCount(html);
context.Response.Body = responseBody; context.Response.Body = responseBody;
await context.Response.WriteAsync(html); await context.Response.WriteAsync(html);
}
} }
else else
{ {

2
src/Squidex/app/features/settings/pages/plans/plans-page.component.html

@ -1,6 +1,6 @@
<sqx-title message="{app} | Plans | Settings" parameter1="app" [value1]="appsState.appName"></sqx-title> <sqx-title message="{app} | Plans | Settings" parameter1="app" [value1]="appsState.appName"></sqx-title>
<sqx-panel desiredWidth="63rem" [showSidebar]="true"> <sqx-panel desiredWidth="64rem" [showSidebar]="true">
<ng-container title> <ng-container title>
Update Plan Update Plan
</ng-container> </ng-container>

4
src/Squidex/app/framework/state.ts

@ -71,7 +71,9 @@ export class Form<T extends AbstractControl, V> {
if (this.form.valid) { if (this.form.valid) {
const value = this.transformSubmit(fullValue(this.form)); const value = this.transformSubmit(fullValue(this.form));
this.disable(); if (value) {
this.disable();
}
return value; return value;
} else { } else {

1
src/Squidex/app/shared/state/assets.forms.ts

@ -57,6 +57,7 @@ export class AnnotateAssetForm extends Form<FormGroup, { fileName?: string, slug
} }
if (Object.keys(result).length === 0) { if (Object.keys(result).length === 0) {
this.enable();
return null; return null;
} }
} }

4
src/Squidex/appsettings.json

@ -104,7 +104,7 @@
/* /*
* The email body when a new user is added as contributor. * The email body when a new user is added as contributor.
*/ */
"newUserBody": "Welcome to Squidex\r\nDear User,\r\n\r\n{{$ASSIGNER_NAME}} ($ASSIGNER_EMAIL) has invited you to join Project (also called an App) {{var:app_name}} at Squidex Headless CMS. Login with your Github, Google or Microsoft credentials to create a new user account and start editing content now.\r\n\r\nThank you very much,\r\nThe Squidex Team\r\n\r\n<<Start now!>> [$UI_URL]", "newUserBody": "Welcome to Squidex\r\nDear User,\r\n\r\n$ASSIGNER_NAME ($ASSIGNER_EMAIL) has invited you to join Project (also called an App) $APP_NAME at Squidex Headless CMS. Login with your Github, Google or Microsoft credentials to create a new user account and start editing content now.\r\n\r\nThank you very much,\r\nThe Squidex Team\r\n\r\n<<Start now!>> [$UI_URL]",
/* /*
* The email subject when an existing user is added as contributor. * The email subject when an existing user is added as contributor.
*/ */
@ -112,7 +112,7 @@
/* /*
* The email body when an existing user is added as contributor. * The email body when an existing user is added as contributor.
*/ */
"existingUserBody": "Dear User,\r\n\r\n{{$ASSIGNER_NAME}} ($ASSIGNER_EMAIL) has invited you to join App {{var:app_name}} at Squidex Headless CMS.\r\n\r\nLogin or reload the Management UI to see the App.\r\n\r\nThank you very much,\r\nThe Squidex Team\r\n\r\n<<Start now!>> [$UI_URL]" "existingUserBody": "Dear User,\r\n\r\n$ASSIGNER_NAME ($ASSIGNER_EMAIL) has invited you to join App $APP_NAME at Squidex Headless CMS.\r\n\r\nLogin or reload the Management UI to see the App.\r\n\r\nThank you very much,\r\nThe Squidex Team\r\n\r\n<<Start now!>> [$UI_URL]"
} }
}, },

4
tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppGrainTests.cs

@ -12,6 +12,7 @@ using FakeItEasy;
using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.Apps.Services; using Squidex.Domain.Apps.Entities.Apps.Services;
using Squidex.Domain.Apps.Entities.Apps.Services.Implementations;
using Squidex.Domain.Apps.Entities.Apps.State; using Squidex.Domain.Apps.Entities.Apps.State;
using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Domain.Apps.Events.Apps; using Squidex.Domain.Apps.Events.Apps;
@ -54,6 +55,9 @@ namespace Squidex.Domain.Apps.Entities.Apps
A.CallTo(() => userResolver.FindByIdOrEmailAsync(contributorId)) A.CallTo(() => userResolver.FindByIdOrEmailAsync(contributorId))
.Returns(user); .Returns(user);
A.CallTo(() => appPlansProvider.GetPlan(A<string>.Ignored))
.Returns(new ConfigAppLimitsPlan { MaxContributors = 10 });
initialPatterns = new InitialPatterns initialPatterns = new InitialPatterns
{ {
{ patternId1, new AppPattern("Number", "[0-9]") }, { patternId1, new AppPattern("Number", "[0-9]") },

8
tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsGrainTests.cs

@ -107,15 +107,15 @@ namespace Squidex.Domain.Apps.Entities.Apps
} }
[Fact] [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] [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");
} }
} }
} }

2
tests/Squidex.Domain.Apps.Entities.Tests/Apps/Billing/ConfigAppLimitsProviderTests.cs

@ -23,7 +23,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Billing
Name = "Infinite", Name = "Infinite",
MaxApiCalls = -1, MaxApiCalls = -1,
MaxAssetSize = -1, MaxAssetSize = -1,
MaxContributors = -1 MaxContributors = int.MaxValue
}; };
private static readonly ConfigAppLimitsPlan FreePlan = new ConfigAppLimitsPlan private static readonly ConfigAppLimitsPlan FreePlan = new ConfigAppLimitsPlan

64
tests/Squidex.Domain.Apps.Entities.Tests/Apps/Guards/GuardAppContributorsTests.cs

@ -51,52 +51,62 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
} }
[Fact] [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(); 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")); new ValidationError("Contributor id is required.", "ContributorId"));
} }
[Fact] [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" }; 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")); new ValidationError("Role is not a valid value.", "Role"));
} }
[Fact] [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 command = new AssignContributor { ContributorId = "1", Role = Role.Owner };
var contributors_1 = contributors_0.Assign("1", 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")); new ValidationError("Contributor has already this role.", "Role"));
} }
[Fact] [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 }; var command = new AssignContributor { ContributorId = "notfound", Role = Role.Owner };
return Assert.ThrowsAsync<DomainObjectNotFoundException>(() => GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan)); await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan));
} }
[Fact] [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") }; var command = new AssignContributor { ContributorId = "3", Role = Role.Editor, Actor = new RefToken("user", "3") };
return Assert.ThrowsAsync<DomainForbiddenException>(() => GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan)); await Assert.ThrowsAsync<DomainForbiddenException>(() => GuardAppContributors.CanAssign(contributors_0, roles, command, users, appPlan));
} }
[Fact] [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) A.CallTo(() => appPlan.MaxContributors)
.Returns(2); .Returns(2);
@ -106,7 +116,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Guards
var contributors_1 = contributors_0.Assign("1", Role.Owner); var contributors_1 = contributors_0.Assign("1", Role.Owner);
var contributors_2 = contributors_1.Assign("2", Role.Editor); 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.")); 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] [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" }; 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] [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); 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] [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) A.CallTo(() => appPlan.MaxContributors)
.Returns(2); .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_1 = contributors_0.Assign("1", Role.Editor);
var contributors_2 = contributors_1.Assign("2", 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] [Fact]

4
tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs

@ -328,14 +328,14 @@ namespace Squidex.Domain.Apps.Entities.Contents
} }
[Fact] [Fact]
public Task Should_throw_if_query_is_invalid() public async Task Should_throw_if_query_is_invalid()
{ {
SetupClaims(isFrontend: false); SetupClaims(isFrontend: false);
SetupSchemaFound(); SetupSchemaFound();
var query = Q.Empty.WithODataQuery("$filter=invalid"); var query = Q.Empty.WithODataQuery("$filter=invalid");
return Assert.ThrowsAsync<ValidationException>(() => sut.QueryAsync(context, schemaId.Name, query)); await Assert.ThrowsAsync<ValidationException>(() => sut.QueryAsync(context, schemaId.Name, query));
} }
public static IEnumerable<object[]> ManyDataFrontend = new[] public static IEnumerable<object[]> ManyDataFrontend = new[]

4
tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs

@ -60,9 +60,9 @@ namespace Squidex.Domain.Apps.Entities.Rules
} }
[Fact] [Fact]
public Task Should_do_nothing_on_clear() public async Task Should_do_nothing_on_clear()
{ {
return sut.ClearAsync(); await sut.ClearAsync();
} }
[Fact] [Fact]

52
tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Guards/GuardSchemaTests.cs

@ -41,25 +41,25 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
} }
[Fact] [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" }; 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")); new ValidationError("Name is not a valid slug.", "Name"));
} }
[Fact] [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" }; 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.")); new ValidationError("A schema with the same name already exists."));
} }
[Fact] [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 var command = new CreateSchema
{ {
@ -76,13 +76,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
Name = "new-schema" 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.", new ValidationError("Field name must be a valid javascript property name.",
"Fields[1].Name")); "Fields[1].Name"));
} }
[Fact] [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 var command = new CreateSchema
{ {
@ -99,13 +99,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
Name = "new-schema" Name = "new-schema"
}; };
return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider),
new ValidationError("Field properties is required.", new ValidationError("Field properties is required.",
"Fields[1].Properties")); "Fields[1].Properties"));
} }
[Fact] [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 var command = new CreateSchema
{ {
@ -122,14 +122,14 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
Name = "new-schema" 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.", new ValidationError("Max length must be greater or equal to min length.",
"Fields[1].Properties.MinLength", "Fields[1].Properties.MinLength",
"Fields[1].Properties.MaxLength")); "Fields[1].Properties.MaxLength"));
} }
[Fact] [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 var command = new CreateSchema
{ {
@ -146,13 +146,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
Name = "new-schema" 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.", new ValidationError("Partitioning is not a valid value.",
"Fields[1].Partitioning")); "Fields[1].Partitioning"));
} }
[Fact] [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 var command = new CreateSchema
{ {
@ -175,13 +175,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
Name = "new-schema" Name = "new-schema"
}; };
return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider),
new ValidationError("Fields cannot have duplicate names.", new ValidationError("Fields cannot have duplicate names.",
"Fields")); "Fields"));
} }
[Fact] [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 var command = new CreateSchema
{ {
@ -206,13 +206,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
Name = "new-schema" 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.", new ValidationError("Field name must be a valid javascript property name.",
"Fields[1].Nested[1].Name")); "Fields[1].Nested[1].Name"));
} }
[Fact] [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 var command = new CreateSchema
{ {
@ -237,13 +237,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
Name = "new-schema" Name = "new-schema"
}; };
return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider),
new ValidationError("Field properties is required.", new ValidationError("Field properties is required.",
"Fields[1].Nested[1].Properties")); "Fields[1].Nested[1].Properties"));
} }
[Fact] [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 var command = new CreateSchema
{ {
@ -268,13 +268,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
Name = "new-schema" 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.", new ValidationError("Nested field cannot be array fields.",
"Fields[1].Nested[1].Properties")); "Fields[1].Nested[1].Properties"));
} }
[Fact] [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 var command = new CreateSchema
{ {
@ -299,14 +299,14 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
Name = "new-schema" 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.", new ValidationError("Max length must be greater or equal to min length.",
"Fields[1].Nested[1].Properties.MinLength", "Fields[1].Nested[1].Properties.MinLength",
"Fields[1].Nested[1].Properties.MaxLength")); "Fields[1].Nested[1].Properties.MaxLength"));
} }
[Fact] [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 var command = new CreateSchema
{ {
@ -336,13 +336,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
Name = "new-schema" Name = "new-schema"
}; };
return ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider), await ValidationAssert.ThrowsAsync(() => GuardSchema.CanCreate(command, appProvider),
new ValidationError("Fields cannot have duplicate names.", new ValidationError("Fields cannot have duplicate names.",
"Fields[1].Nested")); "Fields[1].Nested"));
} }
[Fact] [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 var command = new CreateSchema
{ {
@ -384,7 +384,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Guards
Name = "new-schema" Name = "new-schema"
}; };
return GuardSchema.CanCreate(command, appProvider); await GuardSchema.CanCreate(command, appProvider);
} }
[Fact] [Fact]

8
tests/Squidex.Infrastructure.Tests/Assets/AssetStoreTests.cs

@ -37,15 +37,15 @@ namespace Squidex.Infrastructure.Assets
public abstract T CreateStore(); public abstract T CreateStore();
[Fact] [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<AssetNotFoundException>(() => Sut.DownloadAsync(fileName, new MemoryStream())); await Assert.ThrowsAsync<AssetNotFoundException>(() => Sut.DownloadAsync(fileName, new MemoryStream()));
} }
[Fact] [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<AssetNotFoundException>(() => Sut.CopyAsync(fileName, sourceFile)); await Assert.ThrowsAsync<AssetNotFoundException>(() => Sut.CopyAsync(fileName, sourceFile));
} }
[Fact] [Fact]

12
tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs

@ -28,27 +28,27 @@ namespace Squidex.Infrastructure.UsageTracking
} }
[Fact] [Fact]
public Task Should_throw_exception_if_tracking_on_disposed_object() public async Task Should_throw_exception_if_tracking_on_disposed_object()
{ {
sut.Dispose(); sut.Dispose();
return Assert.ThrowsAsync<ObjectDisposedException>(() => sut.TrackAsync(key, "category1", 1, 1000)); await Assert.ThrowsAsync<ObjectDisposedException>(() => sut.TrackAsync(key, "category1", 1, 1000));
} }
[Fact] [Fact]
public Task Should_throw_exception_if_querying_on_disposed_object() public async Task Should_throw_exception_if_querying_on_disposed_object()
{ {
sut.Dispose(); sut.Dispose();
return Assert.ThrowsAsync<ObjectDisposedException>(() => sut.QueryAsync(key, DateTime.Today, DateTime.Today.AddDays(1))); await Assert.ThrowsAsync<ObjectDisposedException>(() => sut.QueryAsync(key, DateTime.Today, DateTime.Today.AddDays(1)));
} }
[Fact] [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(); sut.Dispose();
return Assert.ThrowsAsync<ObjectDisposedException>(() => sut.GetMonthlyCallsAsync(key, DateTime.Today)); await Assert.ThrowsAsync<ObjectDisposedException>(() => sut.GetMonthlyCallsAsync(key, DateTime.Today));
} }
[Fact] [Fact]

Loading…
Cancel
Save