Browse Source

Merge pull request #282 from Squidex/feature-no-archive

Feature no archive
pull/283/head
Sebastian Stehle 8 years ago
committed by GitHub
parent
commit
8cd369451f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 29
      src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs
  2. 2
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs
  3. 34
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs
  4. 2
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs
  5. 109
      src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs
  6. 55
      src/Squidex.Domain.Apps.Entities/Contents/ContentVersionLoader.cs
  7. 9
      src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs
  8. 17
      src/Squidex.Domain.Apps.Entities/Contents/IContentVersionLoader.cs
  9. 8
      src/Squidex.Domain.Apps.Entities/Contents/QueryContext.cs
  10. 2
      src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs
  11. 2
      src/Squidex.Domain.Apps.Entities/DomainObjectState.cs
  12. 2
      src/Squidex.Infrastructure/EventSourcing/Grains/EventConsumerGrain.cs
  13. 58
      src/Squidex/Areas/Api/Controllers/Content/ContentsController.cs
  14. 2
      src/Squidex/Areas/Api/Controllers/Schemas/Models/AddFieldDto.cs
  15. 8
      src/Squidex/Config/Domain/EntitiesServices.cs
  16. 2
      src/Squidex/Config/ServiceExtensions.cs
  17. 2
      src/Squidex/app/features/content/pages/content/content-page.component.ts
  18. 2
      src/Squidex/app/shared/state/contents.state.ts
  19. 2
      src/Squidex/app/theme/_bootstrap.scss
  20. 4
      src/Squidex/app/theme/_panels.scss
  21. 2
      tests/RunCoverage.ps1
  22. 23
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionTests.cs
  23. 92
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs
  24. 14
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs
  25. 2
      tests/Squidex.Infrastructure.Tests/Caching/HttpRequestCacheTests.cs
  26. 2
      tests/Squidex.Infrastructure.Tests/Commands/DomainObjectGrainTests.cs
  27. 2
      tests/Squidex.Infrastructure.Tests/Orleans/BootstrapTests.cs
  28. 2
      tests/Squidex.Infrastructure.Tests/Tasks/AsyncLockPoolTests.cs
  29. 2
      tests/Squidex.Infrastructure.Tests/Tasks/AsyncLockTests.cs
  30. 2
      tests/Squidex.Infrastructure.Tests/UsageTracking/ThreadingUsageTrackerTests.cs
  31. 1
      tools/Migrate_01/Migrate_01.csproj
  32. 4
      tools/Migrate_01/MigrationPath.cs
  33. 32
      tools/Migrate_01/Migrations/DeleteArchiveCollection.cs
  34. 2
      tools/Migrate_01/Migrations/RebuildAssets.cs
  35. 2
      tools/Migrate_01/Migrations/RebuildContents.cs

29
src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs

@ -13,6 +13,7 @@ using Newtonsoft.Json.Linq;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.ValidateContent;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json;
@ -106,7 +107,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent
return result;
}
public static NamedContentData ToApiModel(this NamedContentData content, Schema schema, LanguagesConfig languagesConfig, bool excludeHidden = true)
public static NamedContentData ToApiModel(this NamedContentData content, Schema schema, LanguagesConfig languagesConfig, bool excludeHidden = true, bool checkTypeCompatibility = false)
{
Guard.NotNull(schema, nameof(schema));
Guard.NotNull(languagesConfig, nameof(languagesConfig));
@ -123,6 +124,32 @@ namespace Squidex.Domain.Apps.Core.ConvertContent
continue;
}
if (checkTypeCompatibility)
{
var isValid = true;
foreach (var value in fieldValue.Value.Values)
{
try
{
if (!value.IsNull())
{
JsonValueConverter.ConvertValue(field, value);
}
}
catch
{
isValid = false;
break;
}
}
if (!isValid)
{
continue;
}
}
var fieldResult = new ContentFieldData();
var fieldValues = fieldValue.Value;

2
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs

@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
private JsonValueConverter(JToken value)
{
this.Value = value;
Value = value;
}
public static object ConvertValue(Field field, JToken json)

34
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs

@ -26,12 +26,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public partial class MongoContentRepository : MongoRepositoryBase<MongoContentEntity>, IContentRepository
{
private readonly IAppProvider appProvider;
private readonly IMongoCollection<MongoContentEntity> archiveCollection;
protected IMongoCollection<MongoContentEntity> ArchiveCollection
{
get { return archiveCollection; }
}
public MongoContentRepository(IMongoDatabase database, IAppProvider appProvider)
: base(database)
@ -39,8 +33,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
Guard.NotNull(appProvider, nameof(appProvider));
this.appProvider = appProvider;
archiveCollection = database.GetCollection<MongoContentEntity>("States_Contents_Archive");
}
protected override string CollectionName()
@ -52,15 +44,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
{
await collection.Indexes.TryDropOneAsync("si_1_st_1_dl_1_dt_text");
await archiveCollection.Indexes.CreateOneAsync(
Index
.Ascending(x => x.ScheduledTo));
await archiveCollection.Indexes.CreateOneAsync(
Index
.Ascending(x => x.Id)
.Ascending(x => x.Version));
await collection.Indexes.CreateOneAsync(
Index
.Text(x => x.DataText)
@ -150,17 +133,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
return ids.Except(contentEntities.Select(x => Guid.Parse(x["id"].AsString))).ToList();
}
public async Task<IContentEntity> FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id, long version)
{
var contentEntity =
await ArchiveCollection.Find(x => x.Id == id && x.Version >= version).SortBy(x => x.Version)
.FirstOrDefaultAsync();
contentEntity?.ParseData(schema.SchemaDef);
return contentEntity;
}
public async Task<IContentEntity> FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id)
{
var contentEntity =
@ -181,11 +153,9 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
});
}
public override async Task ClearAsync()
public Task DeleteArchiveAsync()
{
await Database.DropCollectionAsync("States_Contents_Archive");
await base.ClearAsync();
return Database.DropCollectionAsync("States_Contents_Archive");
}
}
}

2
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs

@ -88,8 +88,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
}
document.DocumentId = $"{key}_{newVersion}";
await ArchiveCollection.ReplaceOneAsync(x => x.DocumentId == document.DocumentId, document, Upsert);
}
private async Task<ISchemaEntity> GetSchemaAsync(Guid appId, Guid schemaId)

109
src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs

@ -13,6 +13,7 @@ using System.Threading.Tasks;
using Microsoft.OData;
using Microsoft.OData.UriParser;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.ConvertContent;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Contents.Edm;
@ -27,113 +28,130 @@ namespace Squidex.Domain.Apps.Entities.Contents
public sealed class ContentQueryService : IContentQueryService
{
private readonly IContentRepository contentRepository;
private readonly IContentVersionLoader contentVersionLoader;
private readonly IAppProvider appProvider;
private readonly IScriptEngine scriptEngine;
private readonly EdmModelBuilder modelBuilder;
public ContentQueryService(
IContentRepository contentRepository,
IContentVersionLoader contentVersionLoader,
IAppProvider appProvider,
IScriptEngine scriptEngine,
EdmModelBuilder modelBuilder)
{
Guard.NotNull(contentRepository, nameof(contentRepository));
Guard.NotNull(contentVersionLoader, nameof(contentVersionLoader));
Guard.NotNull(scriptEngine, nameof(scriptEngine));
Guard.NotNull(modelBuilder, nameof(modelBuilder));
Guard.NotNull(appProvider, nameof(appProvider));
this.contentRepository = contentRepository;
this.contentVersionLoader = contentVersionLoader;
this.appProvider = appProvider;
this.scriptEngine = scriptEngine;
this.modelBuilder = modelBuilder;
}
public async Task<(ISchemaEntity Schema, IContentEntity Content)> FindContentAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, Guid id, long version = -1)
public Task ThrowIfSchemaNotExistsAsync(IAppEntity app, string schemaIdOrName)
{
return GetSchemaAsync(app, schemaIdOrName);
}
public async Task<IContentEntity> FindContentAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, Guid id, long version = -1)
{
Guard.NotNull(app, nameof(app));
Guard.NotNull(user, nameof(user));
Guard.NotEmpty(id, nameof(id));
Guard.NotNullOrEmpty(schemaIdOrName, nameof(schemaIdOrName));
var isFrontendClient = user.IsInClient("squidex-frontend");
var schema = await GetSchemaAsync(app, schemaIdOrName);
var schema = await FindSchemaAsync(app, schemaIdOrName);
var isFrontendClient = IsFrontendClient(user);
var isVersioned = version > EtagVersion.Empty;
var content =
version > EtagVersion.Empty ?
await contentRepository.FindContentAsync(app, schema, id, version) :
await contentRepository.FindContentAsync(app, schema, id);
isVersioned ?
await FindContentByVersionAsync(id, version) :
await FindContentAsync(app, id, schema);
if (content == null || (content.Status != Status.Published && !isFrontendClient))
if (content == null || (content.Status != Status.Published && !isFrontendClient) || content.SchemaId.Id != schema.Id)
{
throw new DomainObjectNotFoundException(id.ToString(), typeof(ISchemaEntity));
}
content = TransformContent(user, schema, Enumerable.Repeat(content, 1)).FirstOrDefault();
content = TransformContent(app, schema, user, Enumerable.Repeat(content, 1), isVersioned, isFrontendClient).FirstOrDefault();
return (schema, content);
return content;
}
public async Task<(ISchemaEntity Schema, IResultList<IContentEntity> Contents)> QueryAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, bool archived, string query)
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, bool archived, string query)
{
Guard.NotNull(app, nameof(app));
Guard.NotNull(user, nameof(user));
Guard.NotNullOrEmpty(schemaIdOrName, nameof(schemaIdOrName));
var schema = await FindSchemaAsync(app, schemaIdOrName);
var schema = await GetSchemaAsync(app, schemaIdOrName);
var isFrontendClient = IsFrontendClient(user);
var parsedQuery = ParseQuery(app, query, schema);
var parsedStatus = ParseStatus(user, archived);
var parsedStatus = ParseStatus(isFrontendClient, archived);
var contents = await contentRepository.QueryAsync(app, schema, parsedStatus.ToArray(), parsedQuery);
return TransformContents(user, schema, contents);
return TransformContents(app, schema, user, contents, false, isFrontendClient);
}
public async Task<(ISchemaEntity Schema, IResultList<IContentEntity> Contents)> QueryAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, bool archived, HashSet<Guid> ids)
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, bool archived, HashSet<Guid> ids)
{
Guard.NotNull(ids, nameof(ids));
Guard.NotNull(app, nameof(app));
Guard.NotNull(user, nameof(user));
Guard.NotNullOrEmpty(schemaIdOrName, nameof(schemaIdOrName));
var schema = await FindSchemaAsync(app, schemaIdOrName);
var schema = await GetSchemaAsync(app, schemaIdOrName);
var isFrontendClient = IsFrontendClient(user);
var parsedStatus = ParseStatus(user, archived);
var parsedStatus = ParseStatus(isFrontendClient, archived);
var contents = await contentRepository.QueryAsync(app, schema, parsedStatus.ToArray(), ids);
return TransformContents(user, schema, contents);
return TransformContents(app, schema, user, contents, false, isFrontendClient);
}
private (ISchemaEntity Schema, IResultList<IContentEntity> Contents) TransformContents(ClaimsPrincipal user, ISchemaEntity schema, IResultList<IContentEntity> contents)
private IResultList<IContentEntity> TransformContents(IAppEntity app, ISchemaEntity schema, ClaimsPrincipal user,
IResultList<IContentEntity> contents,
bool isTypeChecking,
bool isFrontendClient)
{
var transformed = TransformContent(user, schema, contents);
var transformed = TransformContent(app, schema, user, contents, isTypeChecking, isFrontendClient);
return (schema, ResultList.Create(transformed, contents.Total));
return ResultList.Create(transformed, contents.Total);
}
private IEnumerable<IContentEntity> TransformContent(ClaimsPrincipal user, ISchemaEntity schema, IEnumerable<IContentEntity> contents)
private IEnumerable<IContentEntity> TransformContent(IAppEntity app, ISchemaEntity schema, ClaimsPrincipal user,
IEnumerable<IContentEntity> contents,
bool isTypeChecking,
bool isFrontendClient)
{
var scriptText = schema.ScriptQuery;
if (!string.IsNullOrWhiteSpace(scriptText))
{
foreach (var content in contents)
{
var contentData = scriptEngine.Transform(new ScriptContext { User = user, Data = content.Data, ContentId = content.Id }, scriptText);
var contentResult = SimpleMapper.Map(content, new ContentEntity());
contentResult.Data = contentData;
var isScripting = !string.IsNullOrWhiteSpace(scriptText);
yield return contentResult;
}
}
else
foreach (var content in contents)
{
foreach (var content in contents)
var result = SimpleMapper.Map(content, new ContentEntity());
if (!isFrontendClient && isScripting)
{
yield return content;
result.Data = scriptEngine.Transform(new ScriptContext { User = user, Data = content.Data, ContentId = content.Id }, scriptText);
}
result.Data = result.Data.ToApiModel(schema.SchemaDef, app.LanguagesConfig, isFrontendClient, isTypeChecking);
yield return result;
}
}
@ -151,7 +169,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
}
}
public async Task<ISchemaEntity> FindSchemaAsync(IAppEntity app, string schemaIdOrName)
public async Task<ISchemaEntity> GetSchemaAsync(IAppEntity app, string schemaIdOrName)
{
Guard.NotNull(app, nameof(app));
@ -175,11 +193,11 @@ namespace Squidex.Domain.Apps.Entities.Contents
return schema;
}
private static List<Status> ParseStatus(ClaimsPrincipal user, bool archived)
private static List<Status> ParseStatus(bool isFrontendClient, bool archived)
{
var status = new List<Status>();
if (user.IsInClient("squidex-frontend"))
if (isFrontendClient)
{
if (archived)
{
@ -198,5 +216,20 @@ namespace Squidex.Domain.Apps.Entities.Contents
return status;
}
private Task<IContentEntity> FindContentByVersionAsync(Guid id, long version)
{
return contentVersionLoader.LoadAsync(id, version);
}
private Task<IContentEntity> FindContentAsync(IAppEntity app, Guid id, ISchemaEntity schema)
{
return contentRepository.FindContentAsync(app, schema, id);
}
private static bool IsFrontendClient(ClaimsPrincipal user)
{
return user.IsInClient("squidex-frontend");
}
}
}

55
src/Squidex.Domain.Apps.Entities/Contents/ContentVersionLoader.cs

@ -0,0 +1,55 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Contents.State;
using Squidex.Infrastructure;
using Squidex.Infrastructure.States;
namespace Squidex.Domain.Apps.Entities.Contents
{
public sealed class ContentVersionLoader : IContentVersionLoader
{
private readonly IStore<Guid> store;
private readonly FieldRegistry registry;
public ContentVersionLoader(IStore<Guid> store, FieldRegistry registry)
{
Guard.NotNull(store, nameof(store));
Guard.NotNull(registry, nameof(registry));
this.store = store;
this.registry = registry;
}
public async Task<IContentEntity> LoadAsync(Guid id, long version)
{
var content = new ContentState();
var persistence = store.WithEventSourcing<ContentGrain, Guid>(id, e =>
{
if (content.Version < version)
{
content = content.Apply(e);
content.Version++;
}
});
await persistence.ReadAsync();
if (content.Version != version)
{
throw new DomainObjectNotFoundException(id.ToString(), typeof(IContentEntity));
}
return content;
}
}
}

9
src/Squidex.Domain.Apps.Entities/Contents/IContentQueryService.cs

@ -10,19 +10,18 @@ using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Entities.Contents
{
public interface IContentQueryService
{
Task<(ISchemaEntity Schema, IResultList<IContentEntity> Contents)> QueryAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, bool archived, HashSet<Guid> ids);
Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, bool archived, HashSet<Guid> ids);
Task<(ISchemaEntity Schema, IResultList<IContentEntity> Contents)> QueryAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, bool archived, string query);
Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, bool archived, string query);
Task<(ISchemaEntity Schema, IContentEntity Content)> FindContentAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, Guid id, long version = EtagVersion.Any);
Task<IContentEntity> FindContentAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, Guid id, long version = EtagVersion.Any);
Task<ISchemaEntity> FindSchemaAsync(IAppEntity app, string schemaIdOrName);
Task ThrowIfSchemaNotExistsAsync(IAppEntity app, string schemaIdOrName);
}
}

17
src/Squidex.Domain.Apps.Entities/Contents/IContentVersionLoader.cs

@ -0,0 +1,17 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
namespace Squidex.Domain.Apps.Entities.Contents
{
public interface IContentVersionLoader
{
Task<IContentEntity> LoadAsync(Guid id, long version);
}
}

8
src/Squidex.Domain.Apps.Entities/Contents/QueryContext.cs

@ -69,7 +69,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
if (content == null)
{
content = (await contentQuery.FindContentAsync(app, schemaId.ToString(), user, id)).Content;
content = await contentQuery.FindContentAsync(app, schemaId.ToString(), user, id);
if (content != null)
{
@ -96,12 +96,12 @@ namespace Squidex.Domain.Apps.Entities.Contents
{
var result = await contentQuery.QueryAsync(app, schemaIdOrName, user, false, query);
foreach (var content in result.Contents)
foreach (var content in result)
{
cachedContents[content.Id] = content;
}
return result.Contents;
return result;
}
public async Task<IReadOnlyList<IAssetEntity>> GetReferencedAssetsAsync(ICollection<Guid> ids)
@ -133,7 +133,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
{
var result = await contentQuery.QueryAsync(app, schemaId.ToString(), user, false, notLoadedContents);
foreach (var content in result.Contents)
foreach (var content in result)
{
cachedContents[content.Id] = content;
}

2
src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs

@ -27,8 +27,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.Repositories
Task<IContentEntity> FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id);
Task<IContentEntity> FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id, long version);
Task QueryScheduledWithoutDataAsync(Instant now, Func<IContentEntity, Task> callback);
}
}

2
src/Squidex.Domain.Apps.Entities/DomainObjectState.cs

@ -40,7 +40,7 @@ namespace Squidex.Domain.Apps.Entities
public Instant LastModified { get; set; }
[JsonProperty]
public long Version { get; set; }
public long Version { get; set; } = EtagVersion.Empty;
public T Clone()
{

2
src/Squidex.Infrastructure/EventSourcing/Grains/EventConsumerGrain.cs

@ -63,7 +63,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
public Task<Immutable<EventConsumerInfo>> GetStateAsync()
{
return Task.FromResult(state.ToInfo(this.eventConsumer.Name).AsImmutable());
return Task.FromResult(state.ToInfo(eventConsumer.Name).AsImmutable());
}
public Task OnEventAsync(Immutable<IEventSubscription> subscription, Immutable<StoredEvent> storedEvent)

58
src/Squidex/Areas/Api/Controllers/Content/ContentsController.cs

@ -15,7 +15,6 @@ using NodaTime.Text;
using NSwag.Annotations;
using Squidex.Areas.Api.Controllers.Contents.Models;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.ConvertContent;
using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Domain.Apps.Entities.Contents.GraphQL;
@ -119,18 +118,8 @@ namespace Squidex.Areas.Api.Controllers.Contents
var response = new ContentsDto
{
Total = result.Contents.Total,
Items = result.Contents.Take(200).Select(item =>
{
var itemModel = SimpleMapper.Map(item, new ContentDto());
if (item.Data != null)
{
itemModel.Data = item.Data.ToApiModel(result.Schema.SchemaDef, App.LanguagesConfig, !isFrontendClient);
}
return itemModel;
}).ToArray()
Total = result.Total,
Items = result.Take(200).Select(item => SimpleMapper.Map(item, new ContentDto { Data = item.Data })).ToArray()
};
Response.Headers["Surrogate-Key"] = string.Join(" ", response.Items.Select(x => x.Id));
@ -157,19 +146,12 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)]
public async Task<IActionResult> GetContent(string app, string name, Guid id)
{
var (schema, entity) = await contentQuery.FindContentAsync(App, name, User, id);
var content = await contentQuery.FindContentAsync(App, name, User, id);
var response = SimpleMapper.Map(entity, new ContentDto());
var response = SimpleMapper.Map(content, new ContentDto { Data = content.Data });
if (entity.Data != null)
{
var isFrontendClient = User.IsFrontendClient();
response.Data = entity.Data.ToApiModel(schema.SchemaDef, App.LanguagesConfig, !isFrontendClient);
}
Response.Headers["ETag"] = entity.Version.ToString();
Response.Headers["Surrogate-Key"] = entity.Id.ToString();
Response.Headers["ETag"] = content.Version.ToString();
Response.Headers["Surrogate-Key"] = content.Id.ToString();
return Ok(response);
}
@ -197,16 +179,10 @@ namespace Squidex.Areas.Api.Controllers.Contents
{
var content = await contentQuery.FindContentAsync(App, name, User, id, version);
var response = SimpleMapper.Map(content.Content, new ContentDto());
if (content.Content.Data != null)
{
var isFrontendClient = User.IsFrontendClient();
response.Data = content.Content.Data.ToApiModel(content.Schema.SchemaDef, App.LanguagesConfig, !isFrontendClient);
}
var response = SimpleMapper.Map(content, new ContentDto { Data = content.Data });
Response.Headers["ETag"] = version.ToString();
Response.Headers["ETag"] = content.Version.ToString();
Response.Headers["Surrogate-Key"] = content.Id.ToString();
return Ok(response.Data);
}
@ -232,7 +208,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)]
public async Task<IActionResult> PostContent(string app, string name, [FromBody] NamedContentData request, [FromQuery] bool publish = false)
{
await contentQuery.FindSchemaAsync(App, name);
await contentQuery.ThrowIfSchemaNotExistsAsync(App, name);
var command = new CreateContent { ContentId = Guid.NewGuid(), Data = request.ToCleaned(), Publish = publish };
@ -265,7 +241,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)]
public async Task<IActionResult> PutContent(string app, string name, Guid id, [FromBody] NamedContentData request)
{
await contentQuery.FindSchemaAsync(App, name);
await contentQuery.ThrowIfSchemaNotExistsAsync(App, name);
var command = new UpdateContent { ContentId = id, Data = request.ToCleaned() };
var context = await CommandBus.PublishAsync(command);
@ -297,7 +273,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)]
public async Task<IActionResult> PatchContent(string app, string name, Guid id, [FromBody] NamedContentData request)
{
await contentQuery.FindSchemaAsync(App, name);
await contentQuery.ThrowIfSchemaNotExistsAsync(App, name);
var command = new PatchContent { ContentId = id, Data = request.ToCleaned() };
var context = await CommandBus.PublishAsync(command);
@ -329,7 +305,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)]
public async Task<IActionResult> PublishContent(string app, string name, Guid id, string dueTime = null)
{
await contentQuery.FindSchemaAsync(App, name);
await contentQuery.ThrowIfSchemaNotExistsAsync(App, name);
var command = CreateCommand(id, Status.Published, dueTime);
@ -359,7 +335,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)]
public async Task<IActionResult> UnpublishContent(string app, string name, Guid id, string dueTime = null)
{
await contentQuery.FindSchemaAsync(App, name);
await contentQuery.ThrowIfSchemaNotExistsAsync(App, name);
var command = CreateCommand(id, Status.Draft, dueTime);
@ -389,7 +365,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)]
public async Task<IActionResult> ArchiveContent(string app, string name, Guid id, string dueTime = null)
{
await contentQuery.FindSchemaAsync(App, name);
await contentQuery.ThrowIfSchemaNotExistsAsync(App, name);
var command = CreateCommand(id, Status.Archived, dueTime);
@ -419,7 +395,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)]
public async Task<IActionResult> RestoreContent(string app, string name, Guid id, string dueTime = null)
{
await contentQuery.FindSchemaAsync(App, name);
await contentQuery.ThrowIfSchemaNotExistsAsync(App, name);
var command = CreateCommand(id, Status.Draft, dueTime);
@ -447,7 +423,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
[ApiCosts(1)]
public async Task<IActionResult> DeleteContent(string app, string name, Guid id)
{
await contentQuery.FindSchemaAsync(App, name);
await contentQuery.ThrowIfSchemaNotExistsAsync(App, name);
var command = new DeleteContent { ContentId = id };

2
src/Squidex/Areas/Api/Controllers/Schemas/Models/AddFieldDto.cs

@ -33,7 +33,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas.Models
public AddField ToCommand()
{
return SimpleMapper.Map(this, new AddField { Properties = this.Properties.ToProperties() });
return SimpleMapper.Map(this, new AddField { Properties = Properties.ToProperties() });
}
}
}

8
src/Squidex/Config/Domain/EntitiesServices.cs

@ -60,6 +60,9 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<ContentQueryService>()
.As<IContentQueryService>();
services.AddSingletonAs<ContentVersionLoader>()
.As<IContentVersionLoader>();
services.AddSingletonAs<AppHistoryEventsCreator>()
.As<IHistoryEventsCreator>();
@ -158,13 +161,16 @@ namespace Squidex.Config.Domain
services.AddTransientAs<MigrationPath>()
.As<IMigrationPath>();
services.AddTransientAs<AddPatterns>()
.As<IMigration>();
services.AddTransientAs<ConvertEventStore>()
.As<IMigration>();
services.AddTransientAs<ConvertEventStoreAppId>()
.As<IMigration>();
services.AddTransientAs<AddPatterns>()
services.AddTransientAs<DeleteArchiveCollection>()
.As<IMigration>();
services.AddTransientAs<RebuildContents>()

2
src/Squidex/Config/ServiceExtensions.cs

@ -33,7 +33,7 @@ namespace Squidex.Config
{
if (typeof(TInterface) != typeof(T))
{
this.services.AddSingleton(typeof(TInterface), c =>
services.AddSingleton(typeof(TInterface), c =>
{
return c.GetRequiredService<T>();
});

2
src/Squidex/app/features/content/pages/content/content-page.component.ts

@ -153,7 +153,7 @@ export class ContentPageComponent implements CanComponentDeactivate, OnDestroy,
if (this.content) {
this.contentsState.loadVersion(this.content, version)
.subscribe(dto => {
if (this.content.version.value !== version.toString()) {
if (this.content.version.value !== version.value) {
this.contentVersion = version;
} else {
this.contentVersion = null;

2
src/Squidex/app/shared/state/contents.state.ts

@ -348,7 +348,7 @@ export abstract class ContentsStateBase extends State<Snapshot> {
}
public loadVersion(content: ContentDto, version: Version): Observable<Versioned<any>> {
return this.contentsService.getVersionData(this.appName, this.schemaName, content.id, new Version(version.toString()))
return this.contentsService.getVersionData(this.appName, this.schemaName, content.id, version)
.notify(this.dialogs);
}

2
src/Squidex/app/theme/_bootstrap.scss

@ -56,7 +56,7 @@
}
.alert-link {
color: $color-dark-foreground;
color: $color-dark-foreground !important;
font-size: inherit;
font-weight: normal;
text-decoration: underline;

4
src/Squidex/app/theme/_panels.scss

@ -124,7 +124,9 @@
}
a {
color: $color-dark-foreground;
& {
color: $color-dark-foreground !important;
}
&,
&:hover {

2
tests/RunCoverage.ps1

@ -76,6 +76,6 @@ if ($all -Or $web) {
-oldStyle
}
&"$folderHome\.nuget\packages\ReportGenerator\3.1.1\tools\ReportGenerator.exe" `
&"$folderHome\.nuget\packages\ReportGenerator\3.1.2\tools\ReportGenerator.exe" `
-reports:"$folderWorking\$folderReports\*.xml" `
-targetdir:"$folderWorking\$folderReports\Output"

23
tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ContentConversionTests.cs

@ -315,6 +315,29 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent
Assert.Equal(expected, actual);
}
[Fact]
public void Should_not_include_invalid_field_types()
{
var input =
new NamedContentData()
.AddField("field1",
new ContentFieldData()
.AddValue("iv", "INVALID"))
.AddField("field2",
new ContentFieldData()
.AddValue("iv", 2));
var actual = input.ToApiModel(schema, languagesConfig, checkTypeCompatibility: true);
var expected =
new NamedContentData()
.AddField("field2",
new ContentFieldData()
.AddValue("iv", 2));
Assert.Equal(expected, actual);
}
[Fact]
public void Should_return_original_when_no_language_preferences_defined()
{

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

@ -12,7 +12,9 @@ using System.Security.Claims;
using System.Threading.Tasks;
using FakeItEasy;
using Microsoft.OData.UriParser;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Contents.Edm;
@ -27,6 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
public class ContentQueryServiceTests
{
private readonly IContentRepository contentRepository = A.Fake<IContentRepository>();
private readonly IContentVersionLoader contentVersionLoader = A.Fake<IContentVersionLoader>();
private readonly IScriptEngine scriptEngine = A.Fake<IScriptEngine>();
private readonly ISchemaEntity schema = A.Fake<ISchemaEntity>();
private readonly IContentEntity content = A.Fake<IContentEntity>();
@ -49,12 +52,15 @@ namespace Squidex.Domain.Apps.Entities.Contents
A.CallTo(() => app.Id).Returns(appId);
A.CallTo(() => app.Name).Returns(appName);
A.CallTo(() => app.LanguagesConfig).Returns(LanguagesConfig.English);
A.CallTo(() => content.Id).Returns(contentId);
A.CallTo(() => content.Data).Returns(contentData);
A.CallTo(() => content.Status).Returns(Status.Published);
sut = new ContentQueryService(contentRepository, appProvider, scriptEngine, modelBuilder);
A.CallTo(() => schema.SchemaDef).Returns(new Schema("my-schema"));
sut = new ContentQueryService(contentRepository, contentVersionLoader, appProvider, scriptEngine, modelBuilder);
}
[Fact]
@ -63,7 +69,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
A.CallTo(() => appProvider.GetSchemaAsync(appId, schemaId, false))
.Returns(schema);
var result = await sut.FindSchemaAsync(app, schemaId.ToString());
var result = await sut.GetSchemaAsync(app, schemaId.ToString());
Assert.Equal(schema, result);
}
@ -74,7 +80,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
A.CallTo(() => appProvider.GetSchemaAsync(appId, "my-schema"))
.Returns(schema);
var result = await sut.FindSchemaAsync(app, "my-schema");
var result = await sut.GetSchemaAsync(app, "my-schema");
Assert.Equal(schema, result);
}
@ -85,7 +91,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
A.CallTo(() => appProvider.GetSchemaAsync(appId, "my-schema"))
.Returns((ISchemaEntity)null);
await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => sut.FindSchemaAsync(app, "my-schema"));
await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => sut.GetSchemaAsync(app, "my-schema"));
}
[Fact]
@ -104,10 +110,28 @@ namespace Squidex.Domain.Apps.Entities.Contents
var result = await sut.FindContentAsync(app, schemaId.ToString(), user, contentId);
Assert.Equal(schema, result.Schema);
Assert.Equal(contentTransformed, result.Data);
Assert.Equal(content.Id, result.Id);
}
[Fact]
public async Task Should_return_versioned_content_from_repository_and_transform()
{
A.CallTo(() => appProvider.GetSchemaAsync(appId, schemaId, false))
.Returns(schema);
A.CallTo(() => contentVersionLoader.LoadAsync(contentId, 10))
.Returns(content);
A.CallTo(() => schema.ScriptQuery)
.Returns("<script-query>");
A.CallTo(() => scriptEngine.Transform(A<ScriptContext>.That.Matches(x => x.User == user && x.ContentId == contentId && ReferenceEquals(x.Data, contentData)), "<query-script>"))
.Returns(contentTransformed);
Assert.Equal(contentTransformed, result.Content.Data);
Assert.Equal(content.Id, result.Content.Id);
var result = await sut.FindContentAsync(app, schemaId.ToString(), user, contentId, 10);
Assert.Equal(contentTransformed, result.Data);
Assert.Equal(content.Id, result.Id);
}
[Fact]
@ -123,25 +147,37 @@ namespace Squidex.Domain.Apps.Entities.Contents
}
[Fact]
public async Task Should_return_contents_with_ids_from_repository_and_transform()
public async Task Should_return_contents_with_ids_from_repository()
{
await TestManyIdRequest(true, false, new HashSet<Guid> { Guid.NewGuid() }, Status.Draft, Status.Published);
}
[Fact]
public async Task Should_return_non_archived_contents_from_repository_and_transform()
public async Task Should_return_contents_with_ids_from_repository_and_transform_as_non_frontend()
{
await TestManyIdRequest(false, false, new HashSet<Guid> { Guid.NewGuid() }, Status.Published);
}
[Fact]
public async Task Should_return_non_archived_contents_from_repository()
{
await TestManyRequest(true, false, Status.Draft, Status.Published);
}
[Fact]
public async Task Should_return_archived_contents_from_repository_and_transform()
public async Task Should_return_non_archived_contents_from_repository_and_transform_as_non_frontend()
{
await TestManyRequest(false, false, Status.Published);
}
[Fact]
public async Task Should_return_archived_contents_from_repository()
{
await TestManyRequest(true, true, Status.Archived);
}
[Fact]
public async Task Should_return_draft_contents_from_repository_and_transform()
public async Task Should_return_draft_contents_from_repository()
{
await TestManyRequest(false, false, Status.Published);
}
@ -161,12 +197,21 @@ namespace Squidex.Domain.Apps.Entities.Contents
var result = await sut.QueryAsync(app, schemaId.ToString(), user, archive, string.Empty);
Assert.Equal(schema, result.Schema);
Assert.Equal(contentData, result[0].Data);
Assert.Equal(content.Id, result[0].Id);
Assert.Equal(contentData, result.Contents[0].Data);
Assert.Equal(content.Id, result.Contents[0].Id);
Assert.Equal(123, result.Total);
Assert.Equal(123, result.Contents.Total);
if (!isFrontend)
{
A.CallTo(() => scriptEngine.Transform(A<ScriptContext>.Ignored, A<string>.Ignored))
.MustHaveHappened(Repeated.Exactly.Times(result.Count));
}
else
{
A.CallTo(() => scriptEngine.Transform(A<ScriptContext>.Ignored, A<string>.Ignored))
.MustNotHaveHappened();
}
}
private async Task TestManyIdRequest(bool isFrontend, bool archive, HashSet<Guid> ids, params Status[] status)
@ -178,12 +223,21 @@ namespace Squidex.Domain.Apps.Entities.Contents
var result = await sut.QueryAsync(app, schemaId.ToString(), user, archive, ids);
Assert.Equal(schema, result.Schema);
Assert.Equal(contentData, result[0].Data);
Assert.Equal(content.Id, result[0].Id);
Assert.Equal(contentData, result.Contents[0].Data);
Assert.Equal(content.Id, result.Contents[0].Id);
Assert.Equal(123, result.Total);
Assert.Equal(123, result.Contents.Total);
if (!isFrontend)
{
A.CallTo(() => scriptEngine.Transform(A<ScriptContext>.Ignored, A<string>.Ignored))
.MustHaveHappened(Repeated.Exactly.Times(result.Count));
}
else
{
A.CallTo(() => scriptEngine.Transform(A<ScriptContext>.Ignored, A<string>.Ignored))
.MustNotHaveHappened();
}
}
private void SetupClaims(bool isFrontend)

14
tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs

@ -282,7 +282,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
var contents = new List<IContentEntity> { content };
A.CallTo(() => contentQuery.QueryAsync(app, schema.Id.ToString(), user, false, "?$top=30&$skip=5"))
.Returns((schema, ResultList.Create(contents, 0)));
.Returns(ResultList.Create(contents, 0));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
@ -400,7 +400,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
var contents = new List<IContentEntity> { content };
A.CallTo(() => contentQuery.QueryAsync(app, schema.Id.ToString(), user, false, "?$top=30&$skip=5"))
.Returns((schema, ResultList.Create(contents, 10)));
.Returns(ResultList.Create(contents, 10));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
@ -518,7 +518,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
}}";
A.CallTo(() => contentQuery.FindContentAsync(app, schema.Id.ToString(), user, contentId, EtagVersion.Any))
.Returns((schema, content));
.Returns(content);
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
@ -611,10 +611,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
var refContents = new List<IContentEntity> { contentRef };
A.CallTo(() => contentQuery.FindContentAsync(app, schema.Id.ToString(), user, contentId, EtagVersion.Any))
.Returns((schema, content));
.Returns(content);
A.CallTo(() => contentQuery.QueryAsync(app, schema.Id.ToString(), user, false, A<HashSet<Guid>>.That.Matches(x => x.Contains(contentRefId))))
.Returns((schema, ResultList.Create(refContents, 0)));
.Returns(ResultList.Create(refContents, 0));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
@ -671,7 +671,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
var refAssets = new List<IAssetEntity> { assetRef };
A.CallTo(() => contentQuery.FindContentAsync(app, schema.Id.ToString(), user, contentId, EtagVersion.Any))
.Returns((schema, content));
.Returns(content);
A.CallTo(() => assetRepository.QueryAsync(app.Id, A<HashSet<Guid>>.That.Matches(x => x.Contains(assetRefId))))
.Returns(ResultList.Create(refAssets, 0));
@ -730,7 +730,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
}}";
A.CallTo(() => contentQuery.FindContentAsync(app, schema.Id.ToString(), user, contentId, EtagVersion.Any))
.Returns((schema, content));
.Returns(content);
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });

2
tests/Squidex.Infrastructure.Tests/Caching/HttpRequestCacheTests.cs

@ -13,7 +13,7 @@ using Xunit;
namespace Squidex.Infrastructure.Caching
{
public sealed class HttpRequestCacheTests
public class HttpRequestCacheTests
{
private readonly IHttpContextAccessor httpContextAccessor = A.Fake<IHttpContextAccessor>();
private readonly IRequestCache sut;

2
tests/Squidex.Infrastructure.Tests/Commands/DomainObjectGrainTests.cs

@ -19,7 +19,7 @@ using Xunit;
namespace Squidex.Infrastructure.Commands
{
public sealed class DomainObjectGrainTests
public class DomainObjectGrainTests
{
private readonly IStore<Guid> store = A.Fake<IStore<Guid>>();
private readonly IPersistence<MyDomainState> persistence = A.Fake<IPersistence<MyDomainState>>();

2
tests/Squidex.Infrastructure.Tests/Orleans/BootstrapTests.cs

@ -17,7 +17,7 @@ using Xunit;
namespace Squidex.Infrastructure.Orleans
{
public sealed class BootstrapTests
public class BootstrapTests
{
private readonly IBackgroundGrain grain = A.Fake<IBackgroundGrain>();
private readonly Bootstrap<IBackgroundGrain> sut;

2
tests/Squidex.Infrastructure.Tests/Tasks/AsyncLockPoolTests.cs

@ -12,7 +12,7 @@ using Xunit;
namespace Squidex.Infrastructure.Tasks
{
public sealed class AsyncLockPoolTests
public class AsyncLockPoolTests
{
[Fact]
public async Task Should_lock()

2
tests/Squidex.Infrastructure.Tests/Tasks/AsyncLockTests.cs

@ -12,7 +12,7 @@ using Xunit;
namespace Squidex.Infrastructure.Tasks
{
public sealed class AsyncLockTests
public class AsyncLockTests
{
[Fact]
public async Task Should_lock()

2
tests/Squidex.Infrastructure.Tests/UsageTracking/ThreadingUsageTrackerTests.cs

@ -14,7 +14,7 @@ using Xunit;
namespace Squidex.Infrastructure.UsageTracking
{
public sealed class ThreadingUsageTrackerTests
public class ThreadingUsageTrackerTests
{
private readonly MemoryCache cache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
private readonly IUsageTracker inner = A.Fake<IUsageTracker>();

1
tools/Migrate_01/Migrate_01.csproj

@ -4,6 +4,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Core.Model\Squidex.Domain.Apps.Core.Model.csproj" />
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Entities.MongoDb\Squidex.Domain.Apps.Entities.MongoDb.csproj" />
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Entities\Squidex.Domain.Apps.Entities.csproj" />
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Events\Squidex.Domain.Apps.Events.csproj" />
<ProjectReference Include="..\..\src\Squidex.Infrastructure.MongoDb\Squidex.Infrastructure.MongoDb.csproj" />

4
tools/Migrate_01/MigrationPath.cs

@ -15,7 +15,7 @@ namespace Migrate_01
{
public sealed class MigrationPath : IMigrationPath
{
private const int CurrentVersion = 7;
private const int CurrentVersion = 8;
private readonly IServiceProvider serviceProvider;
public MigrationPath(IServiceProvider serviceProvider)
@ -56,6 +56,8 @@ namespace Migrate_01
migrations.Add(serviceProvider.GetRequiredService<AddPatterns>());
}
migrations.Add(serviceProvider.GetRequiredService<DeleteArchiveCollection>());
return (CurrentVersion, migrations);
}
}

32
tools/Migrate_01/Migrations/DeleteArchiveCollection.cs

@ -0,0 +1,32 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Threading.Tasks;
using Squidex.Domain.Apps.Entities.Contents.Repositories;
using Squidex.Domain.Apps.Entities.MongoDb.Contents;
using Squidex.Infrastructure.Migrations;
namespace Migrate_01.Migrations
{
public sealed class DeleteArchiveCollection : IMigration
{
private readonly IContentRepository contentRepository;
public DeleteArchiveCollection(IContentRepository contentRepository)
{
this.contentRepository = contentRepository;
}
public async Task UpdateAsync()
{
if (contentRepository is MongoContentRepository mongoContentRepository)
{
await mongoContentRepository.DeleteArchiveAsync();
}
}
}
}

2
tools/Migrate_01/Migrations/RebuildAssets.cs

@ -10,7 +10,7 @@ using Squidex.Infrastructure.Migrations;
namespace Migrate_01
{
public class RebuildAssets : IMigration
public sealed class RebuildAssets : IMigration
{
private readonly Rebuilder rebuilder;

2
tools/Migrate_01/Migrations/RebuildContents.cs

@ -10,7 +10,7 @@ using Squidex.Infrastructure.Migrations;
namespace Migrate_01.Migrations
{
public class RebuildContents : IMigration
public sealed class RebuildContents : IMigration
{
private readonly Rebuilder rebuilder;

Loading…
Cancel
Save