Browse Source

Merge branch 'release/6.x'

# Conflicts:
#	CHANGELOG.md
#	backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsCacheGrain.cs
#	backend/src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesCacheGrain.cs
#	backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasCacheGrain.cs
#	backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Indexes/AppsCacheGrainTests.cs
#	backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Indexes/RulesCacheGrainTests.cs
#	backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasCacheGrainTests.cs
pull/899/head
Sebastian 3 years ago
parent
commit
07eccc69ff
  1. 1
      backend/i18n/source/backend_en.json
  2. 1
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs
  3. 8
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/SingletonExtensions.cs
  4. 2
      backend/src/Squidex.Infrastructure/Tasks/Scheduler.cs
  5. 4
      backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs
  6. 2
      backend/src/Squidex/Areas/Api/Controllers/Translations/Models/TranslationDto.cs
  7. 3
      backend/src/Squidex/Config/Domain/BackupsServices.cs
  8. 12
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs
  9. 25
      backend/tests/Squidex.Infrastructure.Tests/Tasks/SchedulerTests.cs
  10. 2
      frontend/src/app/features/content/shared/list/content.component.html
  11. 2
      frontend/src/app/features/content/shared/references/content-creator.component.ts
  12. 7
      frontend/src/app/features/schemas/pages/schema/fields/types/array-validation.component.ts
  13. 2
      frontend/src/app/features/schemas/pages/schema/fields/types/references-validation.component.html
  14. 2
      frontend/src/app/features/schemas/pages/schema/fields/types/string-ui.component.html
  15. 4
      frontend/src/app/features/settings/pages/workflows/workflow.component.html
  16. 2
      frontend/src/app/shared/components/forms/rich-editor.component.ts
  17. 2
      frontend/src/app/shared/components/references/content-selector.component.ts
  18. 11
      frontend/src/app/shared/state/schema-tag-source.ts

1
backend/i18n/source/backend_en.json

@ -142,6 +142,7 @@
"contents.singletonNotChangeable": "Singleton content cannot be updated.",
"contents.singletonNotCreatable": "Singleton content cannot be created.",
"contents.singletonNotDeletable": "Singleton content cannot be deleted.",
"contents.componentNotCreatable": "Component content cannot be created.",
"contents.statusNotValid": "Status is not defined in the workflow.",
"contents.statusTransitionNotAllowed": "Cannot change status from {oldStatus} to {newStatus}.",
"contents.validation.aspectRatio": "Must have aspect ratio {width}:{height}.",

1
backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs

@ -228,6 +228,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
private async Task CreateCore(CreateContent c, ContentOperation operation)
{
operation.MustNotCreateComponent();
operation.MustNotCreateSingleton();
operation.MustNotCreateForUnpublishedSchema();
operation.MustHaveData(c.Data);

8
backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/SingletonExtensions.cs

@ -22,6 +22,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
}
}
public static void MustNotCreateComponent(this ContentOperation operation)
{
if (operation.SchemaDef.Type == SchemaType.Component)
{
throw new DomainException(T.Get("contents.componentNotCreatable"));
}
}
public static void MustNotCreateSingleton(this ContentOperation operation)
{
if (operation.SchemaDef.Type == SchemaType.Singleton && operation.CommandId != operation.Schema.Id)

2
backend/src/Squidex.Infrastructure/Tasks/Scheduler.cs

@ -113,6 +113,8 @@ namespace Squidex.Infrastructure.Tasks
}
finally
{
semaphore.Release();
if (Interlocked.Decrement(ref pendingTasks) <= 1)
{
tcs.TrySetResult(true);

4
backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemaDto.cs

@ -154,12 +154,12 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models
AddSelfLink(resources.Url<SchemasController>(x => nameof(x.GetSchema), values));
if (resources.CanReadContent(Name))
if (resources.CanReadContent(Name) && Type == SchemaType.Default)
{
AddGetLink("contents", resources.Url<ContentsController>(x => nameof(x.GetContents), values));
}
if (resources.CanCreateContent(Name))
if (resources.CanCreateContent(Name) && Type == SchemaType.Default)
{
AddPostLink("contents/create", resources.Url<ContentsController>(x => nameof(x.PostContent), values));
AddPostLink("contents/create/publish", resources.Url<ContentsController>(x => nameof(x.PostContent), values) + "?publish=true");

2
backend/src/Squidex/Areas/Api/Controllers/Translations/Models/TranslationDto.cs

@ -24,7 +24,7 @@ namespace Squidex.Areas.Api.Controllers.Translations.Models
public static TranslationDto FromDomain(TranslationResult translation)
{
return SimpleMapper.Map(translation, new TranslationDto());
return SimpleMapper.Map(translation, new TranslationDto { Result = translation.Code });
}
}
}

3
backend/src/Squidex/Config/Domain/BackupsServices.cs

@ -22,6 +22,9 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<TempFolderBackupArchiveLocation>()
.As<IBackupArchiveLocation>();
services.AddSingletonAs<DefaultBackupHandlerFactory>()
.As<IBackupHandlerFactory>();
services.AddSingletonAs<DefaultBackupArchiveStore>()
.As<IBackupArchiveStore>();

12
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs

@ -34,6 +34,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
private readonly ISchemaEntity normalUnpublishedSchema;
private readonly ISchemaEntity singletonSchema;
private readonly ISchemaEntity singletonUnpublishedSchema;
private readonly ISchemaEntity componentSchema;
private readonly RefToken actor = RefToken.User("123");
public GuardContentTests()
@ -49,6 +50,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
singletonSchema =
Mocks.Schema(appId, schemaId, new Schema(schemaId.Name, type: SchemaType.Singleton).Publish());
componentSchema =
Mocks.Schema(appId, schemaId, new Schema(schemaId.Name, type: SchemaType.Component).Publish());
}
[Fact]
@ -91,6 +95,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
Assert.Throws<DomainException>(() => operation.MustNotCreateSingleton());
}
[Fact]
public void Should_throw_exception_if_creating_component_content()
{
var operation = Operation(CreateContent(Status.Draft), componentSchema);
Assert.Throws<DomainException>(() => operation.MustNotCreateComponent());
}
[Fact]
public void Should_not_throw_exception_if_creating_singleton_content_with_schema_id()
{

25
backend/tests/Squidex.Infrastructure.Tests/Tasks/SchedulerTests.cs

@ -25,6 +25,21 @@ namespace Squidex.Infrastructure.Tasks
Assert.Equal(new[] { 1 }, results.ToArray());
}
[Fact]
public async Task Should_schedule_lot_of_tasks_with_limited_concurrency()
{
var limited = new Scheduler(1);
for (var i = 1; i <= 10; i++)
{
Schedule(i, limited);
}
await limited.CompleteAsync();
Assert.Equal(Enumerable.Range(1, 10).ToArray(), results.OrderBy(x => x).ToArray());
}
[Fact]
public async Task Should_schedule_multiple_tasks()
{
@ -83,5 +98,15 @@ namespace Squidex.Infrastructure.Tasks
results.Add(value);
});
}
private void Schedule(int value, Scheduler target)
{
target.Schedule(async _ =>
{
await Task.Delay(1);
results.Add(value);
});
}
}
}

2
frontend/src/app/features/content/shared/list/content.component.html

@ -43,7 +43,7 @@
<div class="dropdown-divider"></div>
<a class="dropdown-item dropdown-item-delete"
<a class="dropdown-item dropdown-item-delete" [class.disabled]="!content.canDelete"
(sqxConfirmClick)="delete.emit()"
confirmTitle="i18n:contents.deleteConfirmTitle"
confirmText="i18n:contents.deleteConfirmText"

2
frontend/src/app/features/content/shared/references/content-creator.component.ts

@ -56,7 +56,7 @@ export class ContentCreatorComponent extends ResourceOwner implements OnInit {
this.schemas = this.schemasState.snapshot.schemas.filter(x => x.canContentsCreate);
if (this.schemaIds && this.schemaIds.length > 0) {
this.schemas = this.schemas.filter(x => this.schemaIds!.indexOf(x.id) >= 0);
this.schemas = this.schemas.filter(x => x.type === 'Default' && this.schemaIds!.indexOf(x.id) >= 0);
}
const selectedSchema = this.schemas.find(x => x.name === this.schemaName) || this.schemas[0];

7
frontend/src/app/features/schemas/pages/schema/fields/types/array-validation.component.ts

@ -7,7 +7,7 @@
import { Component, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { ArrayFieldPropertiesDto, FieldDto, SchemaTagSource } from '@app/shared';
import { ArrayFieldPropertiesDto, FieldDto } from '@app/shared';
@Component({
selector: 'sqx-array-validation[field][fieldForm][properties]',
@ -23,9 +23,4 @@ export class ArrayValidationComponent {
@Input()
public properties!: ArrayFieldPropertiesDto;
constructor(
public readonly schemasSource: SchemaTagSource,
) {
}
}

2
frontend/src/app/features/schemas/pages/schema/fields/types/references-validation.component.html

@ -4,7 +4,7 @@
<div class="col-9">
<sqx-tag-editor placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" formControlName="schemaIds"
[converter]="(schemasSource.converter | async)!" [suggestions]="(schemasSource.converter | async)?.suggestions">
[converter]="(schemasSource.normalConverter | async)!" [suggestions]="(schemasSource.normalConverter | async)?.suggestions">
</sqx-tag-editor>
</div>
</div>

2
frontend/src/app/features/schemas/pages/schema/fields/types/string-ui.component.html

@ -91,7 +91,7 @@
<div class="col-9">
<sqx-tag-editor placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" formControlName="schemaIds"
[converter]="(schemasSource.converter | async)!" [suggestions]="(schemasSource.converter | async)?.suggestions">
[converter]="(schemasSource.normalConverter | async)!" [suggestions]="(schemasSource.normalConverter | async)?.suggestions">
</sqx-tag-editor>
</div>
</div>

4
frontend/src/app/features/settings/pages/workflows/workflow.component.html

@ -4,7 +4,7 @@
<span class="workflow-name">{{workflow.displayName}}</span>
</div>
<div class="col col-tags">
<sqx-tag-editor [converter]="(schemasSource.converter | async)!" [ngModel]="workflow.schemaIds"
<sqx-tag-editor [converter]="(schemasSource.normalConverter | async)!" [ngModel]="workflow.schemaIds"
[styleBlank]="true"
[singleLine]="true"
[readonly]="true">
@ -81,7 +81,7 @@
[disabled]="!isEditable"
[ngModel]="workflow.schemaIds"
(ngModelChange)="changeSchemaIds($event)"
[suggestions]="(schemasSource.converter | async)?.suggestions">
[suggestions]="(schemasSource.normalConverter | async)?.suggestions">
</sqx-tag-editor>
<sqx-form-hint>

2
frontend/src/app/shared/components/forms/rich-editor.component.ts

@ -119,7 +119,7 @@ export class RichEditorComponent extends StatefulControlComponent<{}, string> im
images_upload_handler: (blob: any, success: (url: string) => void, failure: (message: string) => void) => {
const file = new File([blob.blob()], blob.filename(), { lastModified: new Date().getTime() });
self.assetUploader.uploadFile(file)
self.assetUploader.uploadFile(file, undefined, this.folderId)
.subscribe({
next: asset => {
if (Types.is(asset, AssetDto)) {

2
frontend/src/app/shared/components/references/content-selector.component.ts

@ -81,7 +81,7 @@ export class ContentSelectorComponent extends ResourceOwner implements OnInit {
this.schemas = this.schemasState.snapshot.schemas.filter(x => x.canReadContents);
if (this.schemaIds && this.schemaIds.length > 0) {
this.schemas = this.schemas.filter(x => x.canReadContents && this.schemaIds!.includes(x.id));
this.schemas = this.schemas.filter(x => x.type === 'Default' && x.canReadContents && this.schemaIds!.includes(x.id));
}
this.selectSchema(this.schemas[0]);

11
frontend/src/app/shared/state/schema-tag-source.ts

@ -16,7 +16,12 @@ class SchemaConverter implements TagConverter {
constructor(
private readonly schemas: ReadonlyArray<SchemaDto>,
normalOnly: boolean,
) {
if (normalOnly) {
schemas = schemas.filter(x => x.type === 'Default');
}
this.suggestions = schemas.map(x => new TagValue(x.id, x.name, x.id));
}
@ -45,7 +50,11 @@ class SchemaConverter implements TagConverter {
export class SchemaTagSource {
public converter =
this.schemasState.schemas.pipe(
map(x => new SchemaConverter(x)));
map(x => new SchemaConverter(x, false)));
public normalConverter =
this.schemasState.schemas.pipe(
map(x => new SchemaConverter(x, true)));
constructor(
readonly schemasState: SchemasState,

Loading…
Cancel
Save