Browse Source

Fix localizations.

pull/967/head
Sebastian 3 years ago
parent
commit
307df27667
  1. 1
      backend/i18n/frontend_en.json
  2. 1
      backend/i18n/frontend_it.json
  3. 1
      backend/i18n/frontend_nl.json
  4. 1
      backend/i18n/frontend_pt.json
  5. 1
      backend/i18n/frontend_zh.json
  6. 1
      backend/i18n/source/frontend_en.json
  7. 23
      backend/src/Squidex.Domain.Apps.Entities/Apps/DomainObject/Guards/GuardApp.cs
  8. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/SecurityExtensions.cs
  9. 3
      backend/src/Squidex.Shared/PermissionIds.cs
  10. 1
      backend/src/Squidex/Squidex.csproj
  11. 4
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs
  12. 21
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppTests.cs
  13. 39
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DynamicContentWorkflowTests.cs
  14. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/Indexes/TeamsIndexTests.cs
  15. 34
      backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/GivenContext.cs
  16. 33
      backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs
  17. 2
      frontend/src/app/features/teams/pages/contributors/contributor-add-form.component.html
  18. 2
      frontend/src/environments/environment.ts
  19. 36
      tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.cs

1
backend/i18n/frontend_en.json

@ -99,6 +99,7 @@
"assets.metadata": "Metadata",
"assets.metadataAdd": "Add Metadata",
"assets.move": "Move",
"assets.moved": "Asset has been moved.",
"assets.moveFailed": "Failed to move asset. Please reload.",
"assets.protected": "Protected",
"assets.protectedHint": "Assets are public by default. Everybody with the link can download the file. If you make an asset protected, only authenticated users (usually a client) can download the asset.",

1
backend/i18n/frontend_it.json

@ -99,6 +99,7 @@
"assets.metadata": "Metadati",
"assets.metadataAdd": "Aggiungi un metadato",
"assets.move": "Move",
"assets.moved": "Asset has been moved.",
"assets.moveFailed": "Non è stato possibile spostare la risorsa. Per favore ricarica.",
"assets.protected": "Protetto",
"assets.protectedHint": "Assets are public by default. Everybody with the link can download the file. If you make an asset protected, only authenticated users (usually a client) can download the asset.",

1
backend/i18n/frontend_nl.json

@ -99,6 +99,7 @@
"assets.metadata": "Metadata",
"assets.metadataAdd": "Metadata toevoegen",
"assets.move": "Move",
"assets.moved": "Asset has been moved.",
"assets.moveFailed": "Verplaatsen van item is mislukt. Laad opnieuw.",
"assets.protected": "Beschermd",
"assets.protectedHint": "Assets are public by default. Everybody with the link can download the file. If you make an asset protected, only authenticated users (usually a client) can download the asset.",

1
backend/i18n/frontend_pt.json

@ -99,6 +99,7 @@
"assets.metadata": "Metadados",
"assets.metadataAdd": "Adicionar metadados",
"assets.move": "Move",
"assets.moved": "Asset has been moved.",
"assets.moveFailed": "Falha ao mover ficheiro. Por favor, recarregue.",
"assets.protected": "Protegido",
"assets.protectedHint": "Os ativos são públicos por defeito. Todos com o link podem descarregar o ficheiro. Se fizer um ficheiro protegido, apenas utilizadores autenticados (normalmente um cliente) podem descarregar o ficheiro.",

1
backend/i18n/frontend_zh.json

@ -99,6 +99,7 @@
"assets.metadata": "元数据",
"assets.metadataAdd": "添加元数据",
"assets.move": "Move",
"assets.moved": "Asset has been moved.",
"assets.moveFailed": "资源移动失败。请重新加载。",
"assets.protected": "受保护",
"assets.protectedHint": "Assets are public by default. Everybody with the link can download the file. If you make an asset protected, only authenticated users (usually a client) can download the asset.",

1
backend/i18n/source/frontend_en.json

@ -99,6 +99,7 @@
"assets.metadata": "Metadata",
"assets.metadataAdd": "Add Metadata",
"assets.move": "Move",
"assets.moved": "Asset has been moved.",
"assets.moveFailed": "Failed to move asset. Please reload.",
"assets.protected": "Protected",
"assets.protectedHint": "Assets are public by default. Everybody with the link can download the file. If you make an asset protected, only authenticated users (usually a client) can download the asset.",

23
backend/src/Squidex.Domain.Apps.Entities/Apps/DomainObject/Guards/GuardApp.cs

@ -7,10 +7,14 @@
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.Billing;
using Squidex.Domain.Apps.Entities.Teams;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation;
using Squidex.Shared;
using Squidex.Shared.Identity;
using Squidex.Text;
using System.Security.Claims;
namespace Squidex.Domain.Apps.Entities.Apps.DomainObject.Guards;
@ -136,7 +140,7 @@ public static class GuardApp
var team = await appProvider.GetTeamAsync(command.TeamId.Value, ct);
if (team == null || !team.Contributors.ContainsKey(command.Actor.Identifier))
if (team == null || (!IsContributor(team, command.Actor) && !HasTransferPermission(command.User)))
{
e(T.Get("apps.transfer.teamNotFound"));
}
@ -146,6 +150,23 @@ public static class GuardApp
e(T.Get("apps.transfer.planAssigned"));
}
});
static bool IsContributor(ITeamEntity team, RefToken actor)
{
return team.Contributors.ContainsKey(actor.Identifier);
}
static bool HasTransferPermission(ClaimsPrincipal? user)
{
var permissions = user?.Claims.Permissions();
if (permissions == null)
{
return false;
}
return permissions.Allows(PermissionIds.Transfer);
}
}
public static void CanChangePlan(ChangePlan command, IAppEntity app, IBillingPlans billingPlans)

4
backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/SecurityExtensions.cs

@ -30,9 +30,7 @@ public static class SecurityExtensions
throw new DomainForbiddenException(T.Get("common.errorNoPermission"));
}
var permission = PermissionIds.ForApp(permissionId, context.App.Name, context.Schema.SchemaDef.Name);
if (!permissions.Allows(permission))
if (!permissions.Allows(permissionId, context.App.Name, context.Schema.SchemaDef.Name))
{
throw new DomainForbiddenException(T.Get("common.errorNoPermission"));
}

3
backend/src/Squidex.Shared/PermissionIds.cs

@ -42,6 +42,9 @@ namespace Squidex.Shared
// Team
public const string Team = "squidex.teams.{team}";
// Team Transfer
public const string Transfer = "squidex.transfer";
// Team General
public const string TeamAdmin = "squidex.teams.{team}.*";
public const string TeamUpdate = "squidex.teams.{team}.update";

1
backend/src/Squidex/Squidex.csproj

@ -129,6 +129,7 @@
<EmbeddedResource Include="..\..\i18n\frontend_en.json" Link="Areas\Frontend\Resources\frontend_en.json" />
<EmbeddedResource Include="..\..\i18n\frontend_it.json" Link="Areas\Frontend\Resources\frontend_it.json" />
<EmbeddedResource Include="..\..\i18n\frontend_nl.json" Link="Areas\Frontend\Resources\frontend_nl.json" />
<EmbeddedResource Include="..\..\i18n\frontend_pt.json" Link="Areas\Frontend\Resources\frontend_pt.json" />
<EmbeddedResource Include="..\..\i18n\frontend_zh.json" Link="Areas\Frontend\Resources\frontend_zh.json" />
</ItemGroup>

4
backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs

@ -7,6 +7,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.TestHelpers;
@ -47,6 +48,9 @@ public class AppDomainObjectTests : HandlerTestBase<AppDomainObject.State>
{
user = UserMocks.User(contributorId);
A.CallTo(() => Team.Contributors)
.Returns(Contributors.Empty.Assign(User.Identifier, Role.Owner));
A.CallTo(() => userResolver.FindByIdOrEmailAsync(contributorId, CancellationToken))
.Returns(user);

21
backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppTests.cs

@ -14,6 +14,7 @@ using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Collections;
using Squidex.Infrastructure.Validation;
using Squidex.Shared;
using Squidex.Shared.Users;
namespace Squidex.Domain.Apps.Entities.Apps.DomainObject.Guards;
@ -22,7 +23,6 @@ public class GuardAppTests : GivenContext, IClassFixture<TranslationsFixture>
{
private readonly IUserResolver users = A.Fake<IUserResolver>();
private readonly IBillingPlans billingPlans = A.Fake<IBillingPlans>();
private readonly RefToken actor = RefToken.User("42");
public GuardAppTests()
{
@ -34,6 +34,9 @@ public class GuardAppTests : GivenContext, IClassFixture<TranslationsFixture>
A.CallTo(() => billingPlans.GetPlan("basic"))
.Returns(new Plan());
A.CallTo(() => Team.Contributors)
.Returns(Contributors.Empty.Assign(User.Identifier, Role.Owner));
}
[Fact]
@ -142,12 +145,22 @@ public class GuardAppTests : GivenContext, IClassFixture<TranslationsFixture>
await GuardApp.CanTransfer(command, App, AppProvider, default);
}
[Fact]
public async Task CanTransfer_should_not_throw_exception_if_user_has_transfer_permission()
{
var admin = Mocks.ApiUser(permission: PermissionIds.Transfer);
var command = new TransferToTeam { TeamId = TeamId, Actor = User, User = admin };
await GuardApp.CanTransfer(command, App, AppProvider, default);
}
[Fact]
public async Task CanTransfer_should_throw_exception_if_team_does_not_exist()
{
Team = null!;
var command = new TransferToTeam { TeamId = TeamId, Actor = actor };
var command = new TransferToTeam { TeamId = TeamId, Actor = User };
await ValidationAssert.ThrowsAsync(() => GuardApp.CanTransfer(command, App, AppProvider, default),
new ValidationError("The team does not exist."));
@ -156,7 +169,9 @@ public class GuardAppTests : GivenContext, IClassFixture<TranslationsFixture>
[Fact]
public async Task CanTransfer_should_throw_exception_if_actor_is_not_part_of_team()
{
var command = new TransferToTeam { TeamId = TeamId, Actor = actor };
var nonContributor = RefToken.User("Other");
var command = new TransferToTeam { TeamId = TeamId, Actor = nonContributor };
await ValidationAssert.ThrowsAsync(() => GuardApp.CanTransfer(command, App, AppProvider, default),
new ValidationError("The team does not exist."));

39
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DynamicContentWorkflowTests.cs

@ -7,6 +7,7 @@
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Scripting;
@ -38,7 +39,7 @@ public class DynamicContentWorkflowTests : GivenContext
new Dictionary<Status, WorkflowTransition>
{
[Status.Archived] = WorkflowTransition.Always,
[Status.Published] = WorkflowTransition.When("data.field.iv === 2", "Editor")
[Status.Published] = WorkflowTransition.When("data.field.iv === 2", Role.Editor)
}.ToReadonlyDictionary(),
StatusColors.Draft),
[Status.Published] =
@ -48,7 +49,7 @@ public class DynamicContentWorkflowTests : GivenContext
[Status.Archived] = WorkflowTransition.Always,
[Status.Draft] = WorkflowTransition.Always
}.ToReadonlyDictionary(),
StatusColors.Published, NoUpdate.When("data.field.iv === 2", "Owner", "Editor"))
StatusColors.Published, NoUpdate.When("data.field.iv === 2", Role.Owner, Role.Editor))
}.ToReadonlyDictionary());
public DynamicContentWorkflowTests()
@ -120,7 +121,7 @@ public class DynamicContentWorkflowTests : GivenContext
[Fact]
public async Task Should_allow_publish_on_create()
{
var actual = await sut.CanPublishInitialAsync(Schema, Mocks.FrontendUser("Editor"));
var actual = await sut.CanPublishInitialAsync(Schema, Mocks.FrontendUser(Role.Editor));
Assert.True(actual);
}
@ -128,7 +129,7 @@ public class DynamicContentWorkflowTests : GivenContext
[Fact]
public async Task Should_not_allow_publish_on_create_if_role_not_allowed()
{
var actual = await sut.CanPublishInitialAsync(Schema, Mocks.FrontendUser("Developer"));
var actual = await sut.CanPublishInitialAsync(Schema, Mocks.FrontendUser(Role.Developer));
Assert.False(actual);
}
@ -138,7 +139,7 @@ public class DynamicContentWorkflowTests : GivenContext
{
var content = CreateContent(Status.Draft, 2);
var actual = await sut.CanMoveToAsync(Schema, content.Status, Status.Published, content.Data, Mocks.FrontendUser("Editor"));
var actual = await sut.CanMoveToAsync(Schema, content.Status, Status.Published, content.Data, Mocks.FrontendUser(Role.Editor));
Assert.True(actual);
}
@ -148,7 +149,7 @@ public class DynamicContentWorkflowTests : GivenContext
{
var content = CreateContent(Status.Draft, 2);
var actual = await sut.CanMoveToAsync(content, content.Status, Status.Published, Mocks.FrontendUser("Editor"));
var actual = await sut.CanMoveToAsync(content, content.Status, Status.Published, Mocks.FrontendUser(Role.Editor));
Assert.True(actual);
}
@ -158,7 +159,7 @@ public class DynamicContentWorkflowTests : GivenContext
{
var content = CreateContent(Status.Draft, 2);
var actual = await sut.CanMoveToAsync(content, content.Status, Status.Published, Mocks.FrontendUser("Developer"));
var actual = await sut.CanMoveToAsync(content, content.Status, Status.Published, Mocks.FrontendUser(Role.Developer));
Assert.False(actual);
}
@ -168,7 +169,7 @@ public class DynamicContentWorkflowTests : GivenContext
{
var content = CreateContent(Status.Draft, 2);
var actual = await sut.CanMoveToAsync(content, content.Status, Status.Published, Mocks.FrontendUser("Editor"));
var actual = await sut.CanMoveToAsync(content, content.Status, Status.Published, Mocks.FrontendUser(Role.Editor));
Assert.True(actual);
}
@ -178,7 +179,7 @@ public class DynamicContentWorkflowTests : GivenContext
{
var content = CreateContent(Status.Draft, 4);
var actual = await sut.CanMoveToAsync(content, content.Status, Status.Published, Mocks.FrontendUser("Editor"));
var actual = await sut.CanMoveToAsync(content, content.Status, Status.Published, Mocks.FrontendUser(Role.Editor));
Assert.False(actual);
}
@ -188,7 +189,7 @@ public class DynamicContentWorkflowTests : GivenContext
{
var content = CreateContent(Status.Published, 2);
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser("Developer"));
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser(Role.Developer));
Assert.True(actual);
}
@ -198,7 +199,7 @@ public class DynamicContentWorkflowTests : GivenContext
{
var content = CreateContent(Status.Published, 2);
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser("Developer"));
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser(Role.Developer));
Assert.True(actual);
}
@ -208,7 +209,7 @@ public class DynamicContentWorkflowTests : GivenContext
{
var content = CreateContent(Status.Archived, 2);
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser("Developer"));
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser(Role.Developer));
Assert.False(actual);
}
@ -218,7 +219,7 @@ public class DynamicContentWorkflowTests : GivenContext
{
var content = CreateContent(Status.Published, 2);
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser("Owner"));
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser(Role.Owner));
Assert.False(actual);
}
@ -228,7 +229,7 @@ public class DynamicContentWorkflowTests : GivenContext
{
var content = CreateContent(Status.Published, 1);
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser("Owner"));
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser(Role.Owner));
Assert.True(actual);
}
@ -238,7 +239,7 @@ public class DynamicContentWorkflowTests : GivenContext
{
var content = CreateContent(Status.Published, 2);
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser("Editor"));
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser(Role.Editor));
Assert.False(actual);
}
@ -248,7 +249,7 @@ public class DynamicContentWorkflowTests : GivenContext
{
var content = CreateContent(Status.Published, 1);
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser("Owner"));
var actual = await sut.CanUpdateAsync(content, content.Status, Mocks.FrontendUser(Role.Owner));
Assert.True(actual);
}
@ -263,7 +264,7 @@ public class DynamicContentWorkflowTests : GivenContext
new StatusInfo(Status.Archived, StatusColors.Archived)
};
var actual = await sut.GetNextAsync(content, content.Status, Mocks.FrontendUser("Developer"));
var actual = await sut.GetNextAsync(content, content.Status, Mocks.FrontendUser(Role.Developer));
actual.Should().BeEquivalentTo(expected);
}
@ -278,7 +279,7 @@ public class DynamicContentWorkflowTests : GivenContext
new StatusInfo(Status.Archived, StatusColors.Archived)
};
var actual = await sut.GetNextAsync(content, content.Status, Mocks.FrontendUser("Editor"));
var actual = await sut.GetNextAsync(content, content.Status, Mocks.FrontendUser(Role.Editor));
actual.Should().BeEquivalentTo(expected);
}
@ -294,7 +295,7 @@ public class DynamicContentWorkflowTests : GivenContext
new StatusInfo(Status.Published, StatusColors.Published)
};
var actual = await sut.GetNextAsync(content, content.Status, Mocks.FrontendUser("Editor"));
var actual = await sut.GetNextAsync(content, content.Status, Mocks.FrontendUser(Role.Editor));
actual.Should().BeEquivalentTo(expected);
}

2
backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/Indexes/TeamsIndexTests.cs

@ -75,7 +75,7 @@ public class TeamsIndexTests : GivenContext
private static ITeamEntity SetupTeam(long version)
{
var team = Mocks.Team(DomainId.NewGuid());
var team = Mocks.Team(DomainId.NewGuid(), "my-team");
A.CallTo(() => team.Version)
.Returns(version);

34
backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/GivenContext.cs

@ -5,14 +5,10 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Security.Claims;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Domain.Apps.Entities.Teams;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Security;
using Squidex.Shared;
using Squidex.Shared.Identity;
namespace Squidex.Domain.Apps.Entities.TestHelpers;
@ -27,6 +23,8 @@ public abstract class GivenContext
public DomainId TeamId { get; } = DomainId.NewGuid();
public string TeamName { get; } = "my-team";
public NamedId<DomainId> AppId { get; } = NamedId.Of(DomainId.NewGuid(), "my-app");
public NamedId<DomainId> SchemaId { get; } = NamedId.Of(DomainId.NewGuid(), "my-schema");
@ -70,31 +68,27 @@ public abstract class GivenContext
protected GivenContext()
{
App = Mocks.App(AppId, Language.EN, Language.DE);
Team = Mocks.Team(TeamId, TeamName);
Team = Mocks.Team(TeamId, "my-team", User.Identifier);
App = Mocks.App(AppId,
Language.EN,
Language.DE);
Schema = Mocks.Schema(AppId, SchemaId);
}
public Context CreateContext(bool isFrontend, params string[] permissions)
public Context CreateContext(params string[] permissions)
{
var claimsIdentity = new ClaimsIdentity();
var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
claimsIdentity.AddClaim(new Claim(OpenIdClaims.Subject, User.Identifier));
var principal = Mocks.CreateUser(false, null, permissions);
if (isFrontend)
{
claimsIdentity.AddClaim(new Claim(OpenIdClaims.ClientId, DefaultClients.Frontend));
}
return new Context(principal, App);
}
foreach (var permission in permissions)
{
claimsIdentity.AddClaim(new Claim(SquidexClaimTypes.Permissions, permission));
}
public Context CreateContext(bool isFrontend, params string[] permissions)
{
var principal = Mocks.CreateUser(isFrontend, null, permissions);
return new Context(claimsPrincipal, App);
return new Context(principal, App);
}
private static IContextProvider CreateContextProvider(Context context)

33
backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs

@ -54,43 +54,58 @@ public static class Mocks
return schema;
}
public static ITeamEntity Team(DomainId teamId, string teamName = "my-team", string contributor = "user")
public static ITeamEntity Team(DomainId teamId, string teamName)
{
var team = A.Fake<ITeamEntity>();
A.CallTo(() => team.Id).Returns(teamId);
A.CallTo(() => team.UniqueId).Returns(teamId);
A.CallTo(() => team.Name).Returns(teamName);
A.CallTo(() => team.Contributors).Returns(Contributors.Empty.Assign(contributor, Role.Owner));
return team;
}
public static ClaimsPrincipal ApiUser(string? role = null)
public static ClaimsPrincipal ApiUser(string? role = null, params string[] permissions)
{
return CreateUser(role, "api");
return CreateUser(false, role, permissions);
}
public static ClaimsPrincipal ApiUser(string? role = null, string? permission = null)
{
return CreateUser(false, role, permission);
}
public static ClaimsPrincipal FrontendUser(string? role = null, params string[] permissions)
{
return CreateUser(true, role, permissions);
}
public static ClaimsPrincipal FrontendUser(string? role = null, string? permission = null)
{
return CreateUser(role, DefaultClients.Frontend, permission);
return CreateUser(true, role, permission);
}
private static ClaimsPrincipal CreateUser(string? role, string client, string? permission = null)
public static ClaimsPrincipal CreateUser(bool isFrontend, string? role, params string?[] permissions)
{
var claimsIdentity = new ClaimsIdentity();
var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
claimsIdentity.AddClaim(new Claim(OpenIdClaims.ClientId, client));
if (isFrontend)
{
claimsIdentity.AddClaim(new Claim(OpenIdClaims.ClientId, DefaultClients.Frontend));
}
if (role != null)
{
claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, role));
}
if (permission != null)
foreach (var permission in permissions)
{
claimsIdentity.AddClaim(new Claim(SquidexClaimTypes.Permissions, permission));
if (permission != null)
{
claimsIdentity.AddClaim(new Claim(SquidexClaimTypes.Permissions, permission));
}
}
return claimsPrincipal;

2
frontend/src/app/features/teams/pages/contributors/contributor-add-form.component.html

@ -24,7 +24,7 @@
<div class="import-hint">
<sqx-form-hint>
{{ 'contributors.importHintg' | sqxTranslate }} <a class="force" (click)="importDialog.show()">{{ 'contributors.importButton' | sqxTranslate }}</a>
{{ 'contributors.importHint' | sqxTranslate }} <a class="force" (click)="importDialog.show()">{{ 'contributors.importButton' | sqxTranslate }}</a>
</sqx-form-hint>
</div>
</div>

2
frontend/src/environments/environment.ts

@ -7,7 +7,7 @@ export const environment = {
production: false,
textLogger: true,
textResolver: () => {
const culture = window['options']?.more?.culture || 'en';
const culture = window['options']?.culture || 'en';
return require(`./../../../backend/i18n/frontend_${culture}.json`);
},

36
tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.cs

@ -1225,4 +1225,40 @@ public class ContentUpdateTests : IClassFixture<ContentFixture>
}
}
}
[Fact]
public async Task Should_create_content_with_custom_id_and_delete_it()
{
var id = "author-12345–fragment-text";
// STEP 1: Create a new item with a custom id.
var options = new ContentCreateOptions { Id = id, Publish = true };
var content = await _.Contents.CreateAsync(new TestEntityData
{
Number = 1
}, options);
Assert.Equal(id, content.Id);
// STEP 2: Delete with bulk update.
await _.Contents.BulkUpdateAsync(new BulkUpdate
{
Jobs = new List<BulkUpdateJob>
{
new BulkUpdateJob
{
Type = BulkUpdateType.Delete,
Id = id
}
}
});
// STEP 3: Retrieve all items and ensure that the deleted item does not exist.
var updated = await _.Contents.GetAsync();
Assert.DoesNotContain(updated.Items, x => x.Id == id);
}
}

Loading…
Cancel
Save