diff --git a/Nuget.config b/NuGet.Config similarity index 59% rename from Nuget.config rename to NuGet.Config index 8c24b91a1..3f0e00340 100644 --- a/Nuget.config +++ b/NuGet.Config @@ -1,7 +1,6 @@  - \ No newline at end of file diff --git a/extensions/Squidex.Extensions/Squidex.Extensions.csproj b/extensions/Squidex.Extensions/Squidex.Extensions.csproj index 5e0af3773..3edb1180c 100644 --- a/extensions/Squidex.Extensions/Squidex.Extensions.csproj +++ b/extensions/Squidex.Extensions/Squidex.Extensions.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj b/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj index bd47258f1..fda492bdf 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj +++ b/src/Squidex.Domain.Apps.Core.Model/Squidex.Domain.Apps.Core.Model.csproj @@ -8,11 +8,11 @@ True - + all runtime; build; native; contentfiles; analyzers - + diff --git a/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj b/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj index f366ea646..4a1d40b7e 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj +++ b/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj @@ -17,7 +17,7 @@ - + diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs index 6c42283c8..ed6e85b39 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; using Squidex.Domain.Apps.Entities.Assets; @@ -32,7 +33,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets return "States_Assets"; } - protected override Task SetupCollectionAsync(IMongoCollection collection) + protected override Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default(CancellationToken)) { return collection.Indexes.CreateOneAsync( new CreateIndexModel( @@ -41,7 +42,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets .Ascending(x => x.IsDeleted) .Ascending(x => x.FileName) .Ascending(x => x.Tags) - .Descending(x => x.LastModified))); + .Descending(x => x.LastModified)), + cancellationToken: ct); } public async Task> QueryAsync(Guid appId, Query query) diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetStatsRepository.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetStatsRepository.cs index dd53f4313..a78ad5987 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetStatsRepository.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetStatsRepository.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; using Squidex.Domain.Apps.Entities.Assets; @@ -30,12 +31,14 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets return "Projections_AssetStats"; } - protected override async Task SetupCollectionAsync(IMongoCollection collection) + protected override Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default(CancellationToken)) { - await collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.AssetId).Ascending(x => x.Date))); - await collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.AssetId).Descending(x => x.Date))); + return collection.Indexes.CreateManyAsync( + new[] + { + new CreateIndexModel(Index.Ascending(x => x.AssetId).Ascending(x => x.Date)), + new CreateIndexModel(Index.Ascending(x => x.AssetId).Descending(x => x.Date)) + }, ct); } public async Task> QueryAsync(Guid appId, DateTime fromDate, DateTime toDate) diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs index f9a7b2d25..c9eec5756 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; using Squidex.Domain.Apps.Core.Contents; @@ -31,10 +32,10 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents this.collectionName = collectionName; } - protected override async Task SetupCollectionAsync(IMongoCollection collection) + protected override async Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default(CancellationToken)) { await collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.ReferencedIds))); + new CreateIndexModel(Index.Ascending(x => x.ReferencedIds)), cancellationToken: ct); } protected override string CollectionName() diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentDraftCollection.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentDraftCollection.cs index 15cdb7f32..6ad2c7651 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentDraftCollection.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentDraftCollection.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; using NodaTime; @@ -29,24 +30,25 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents { } - protected override async Task SetupCollectionAsync(IMongoCollection collection) + protected override async Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default(CancellationToken)) { - await collection.Indexes.CreateOneAsync( - new CreateIndexModel( - Index - .Ascending(x => x.IndexedSchemaId) - .Ascending(x => x.Id) - .Ascending(x => x.IsDeleted))); - - await collection.Indexes.CreateOneAsync( - new CreateIndexModel( - Index - .Text(x => x.DataText) - .Ascending(x => x.IndexedSchemaId) - .Ascending(x => x.IsDeleted) - .Ascending(x => x.Status))); - - await base.SetupCollectionAsync(collection); + await collection.Indexes.CreateManyAsync( + new[] + { + new CreateIndexModel( + Index + .Ascending(x => x.IndexedSchemaId) + .Ascending(x => x.Id) + .Ascending(x => x.IsDeleted)), + new CreateIndexModel( + Index + .Text(x => x.DataText) + .Ascending(x => x.IndexedSchemaId) + .Ascending(x => x.IsDeleted) + .Ascending(x => x.Status)), + }, ct); + + await base.SetupCollectionAsync(collection, ct); } public async Task> QueryNotFoundAsync(Guid appId, Guid schemaId, IList ids) diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentPublishedCollection.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentPublishedCollection.cs index ec1d2da7c..8f2c424e9 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentPublishedCollection.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentPublishedCollection.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; using Squidex.Domain.Apps.Entities.Apps; @@ -22,18 +23,16 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents { } - protected override async Task SetupCollectionAsync(IMongoCollection collection) + protected override async Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default(CancellationToken)) { - await collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Text(x => x.DataText).Ascending(x => x.IndexedSchemaId))); - - await collection.Indexes.CreateOneAsync( - new CreateIndexModel( - Index - .Ascending(x => x.IndexedSchemaId) - .Ascending(x => x.Id))); - - await base.SetupCollectionAsync(collection); + await collection.Indexes.CreateManyAsync( + new[] + { + new CreateIndexModel(Index.Text(x => x.DataText).Ascending(x => x.IndexedSchemaId)), + new CreateIndexModel(Index.Ascending(x => x.IndexedSchemaId).Ascending(x => x.Id)) + }, ct); + + await base.SetupCollectionAsync(collection, ct); } public async Task FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id) diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs index 796026d71..71c81e3aa 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; using NodaTime; @@ -40,10 +41,9 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents this.database = database; } - public void Initialize() + public Task InitializeAsync(CancellationToken ct = default(CancellationToken)) { - contentsDraft.Initialize(); - contentsPublished.Initialize(); + return Task.WhenAll(contentsDraft.InitializeAsync(ct), contentsPublished.InitializeAsync(ct)); } public async Task> QueryAsync(IAppEntity app, ISchemaEntity schema, Status[] status, Query query) diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/History/MongoHistoryEventRepository.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/History/MongoHistoryEventRepository.cs index fb40a3062..95e9c6e74 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/History/MongoHistoryEventRepository.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/History/MongoHistoryEventRepository.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; using Squidex.Domain.Apps.Entities.History; @@ -52,18 +53,20 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.History return "Projections_History"; } - protected override async Task SetupCollectionAsync(IMongoCollection collection) + protected override Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default(CancellationToken)) { - await collection.Indexes.CreateOneAsync( - new CreateIndexModel( - Index - .Ascending(x => x.AppId) - .Ascending(x => x.Channel) - .Descending(x => x.Created) - .Descending(x => x.Version))); - - await collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.Created), new CreateIndexOptions { ExpireAfter = TimeSpan.FromDays(365) })); + return collection.Indexes.CreateManyAsync( + new[] + { + new CreateIndexModel( + Index + .Ascending(x => x.AppId) + .Ascending(x => x.Channel) + .Descending(x => x.Created) + .Descending(x => x.Version)), + new CreateIndexModel(Index.Ascending(x => x.Created), + new CreateIndexOptions { ExpireAfter = TimeSpan.FromDays(365) }) + }, ct); } public async Task> QueryByChannelAsync(Guid appId, string channelPrefix, int count) diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs index b775e9aba..352dfc479 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs @@ -32,14 +32,15 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules return "RuleEvents"; } - protected override async Task SetupCollectionAsync(IMongoCollection collection) + protected override async Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default(CancellationToken)) { - await collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.NextAttempt))); - await collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.AppId).Descending(x => x.Created))); - await collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.Expires), new CreateIndexOptions { ExpireAfter = TimeSpan.Zero })); + await collection.Indexes.CreateManyAsync( + new[] + { + new CreateIndexModel(Index.Ascending(x => x.NextAttempt)), + new CreateIndexModel(Index.Ascending(x => x.AppId).Descending(x => x.Created)), + new CreateIndexModel(Index.Ascending(x => x.Expires), new CreateIndexOptions { ExpireAfter = TimeSpan.Zero }) + }, ct); } public Task QueryPendingAsync(Instant now, Func callback, CancellationToken ct = default(CancellationToken)) diff --git a/src/Squidex.Infrastructure/IRunnable.cs b/src/Squidex.Domain.Apps.Entities/Assets/AssetOptions.cs similarity index 64% rename from src/Squidex.Infrastructure/IRunnable.cs rename to src/Squidex.Domain.Apps.Entities/Assets/AssetOptions.cs index 790fa1c59..1326eaa4f 100644 --- a/src/Squidex.Infrastructure/IRunnable.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/AssetOptions.cs @@ -1,14 +1,14 @@ // ========================================================================== // Squidex Headless CMS // ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) +// Copyright (c) Squidex UG (haftungsbeschraenkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== -namespace Squidex.Infrastructure +namespace Squidex.Domain.Apps.Entities.Assets { - public interface IRunnable + public sealed class AssetOptions { - void Run(); + public int MaxResults { get; set; } = 200; } } diff --git a/src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs b/src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs index e706b3dcd..763603162 100644 --- a/src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs @@ -22,18 +22,19 @@ namespace Squidex.Domain.Apps.Entities.Assets { public sealed class AssetQueryService : IAssetQueryService { - private const int MaxResults = 200; private readonly ITagService tagService; private readonly IAssetRepository assetRepository; + private readonly AssetOptions options; - public AssetQueryService(ITagService tagService, IAssetRepository assetRepository) + public AssetQueryService(ITagService tagService, IAssetRepository assetRepository, AssetOptions options) { Guard.NotNull(tagService, nameof(tagService)); + Guard.NotNull(options, nameof(options)); Guard.NotNull(assetRepository, nameof(assetRepository)); - this.tagService = tagService; - this.assetRepository = assetRepository; + this.options = options; + this.tagService = tagService; } public async Task FindAssetAsync(QueryContext context, Guid id) @@ -97,9 +98,9 @@ namespace Squidex.Domain.Apps.Entities.Assets result.Sort.Add(new SortNode(new List { "lastModified" }, SortOrder.Descending)); } - if (result.Take > MaxResults) + if (result.Take > options.MaxResults) { - result.Take = MaxResults; + result.Take = options.MaxResults; } return result; diff --git a/src/Squidex.Domain.Apps.Entities/Contents/Commands/CreateContent.cs b/src/Squidex.Domain.Apps.Entities/Contents/Commands/CreateContent.cs index 2eec65f73..c382d28c3 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/Commands/CreateContent.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/Commands/CreateContent.cs @@ -18,6 +18,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Commands public bool Publish { get; set; } + public bool DoNotValidate { get; set; } + public CreateContent() { ContentId = Guid.NewGuid(); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs index e01f16486..85d847e62 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs @@ -68,7 +68,11 @@ namespace Squidex.Domain.Apps.Entities.Contents await ctx.ExecuteScriptAndTransformAsync(x => x.ScriptCreate, "Create", c, c.Data); await ctx.EnrichAsync(c.Data); - await ctx.ValidateAsync(c.Data); + + if (!c.DoNotValidate) + { + await ctx.ValidateAsync(c.Data); + } if (c.Publish) { diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentOptions.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentOptions.cs new file mode 100644 index 000000000..4b58d7312 --- /dev/null +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentOptions.cs @@ -0,0 +1,14 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Domain.Apps.Entities.Contents +{ + public sealed class ContentOptions + { + public int MaxResults { get; set; } = 200; + } +} diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs index 62ec24a95..f3c6fa07b 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs @@ -28,7 +28,6 @@ namespace Squidex.Domain.Apps.Entities.Contents { public sealed class ContentQueryService : IContentQueryService { - private const int MaxResults = 200; private static readonly Status[] StatusAll = { Status.Archived, Status.Draft, Status.Published }; private static readonly Status[] StatusArchived = { Status.Archived }; private static readonly Status[] StatusPublished = { Status.Published }; @@ -37,6 +36,7 @@ namespace Squidex.Domain.Apps.Entities.Contents private readonly IContentVersionLoader contentVersionLoader; private readonly IAppProvider appProvider; private readonly IScriptEngine scriptEngine; + private readonly ContentOptions options; private readonly EdmModelBuilder modelBuilder; public ContentQueryService( @@ -44,18 +44,21 @@ namespace Squidex.Domain.Apps.Entities.Contents IContentRepository contentRepository, IContentVersionLoader contentVersionLoader, IScriptEngine scriptEngine, + ContentOptions options, EdmModelBuilder modelBuilder) { Guard.NotNull(appProvider, nameof(appProvider)); Guard.NotNull(contentRepository, nameof(contentRepository)); Guard.NotNull(contentVersionLoader, nameof(contentVersionLoader)); Guard.NotNull(modelBuilder, nameof(modelBuilder)); + Guard.NotNull(options, nameof(options)); Guard.NotNull(scriptEngine, nameof(scriptEngine)); this.appProvider = appProvider; this.contentRepository = contentRepository; this.contentVersionLoader = contentVersionLoader; this.modelBuilder = modelBuilder; + this.options = options; this.scriptEngine = scriptEngine; } @@ -120,12 +123,12 @@ namespace Squidex.Domain.Apps.Entities.Contents private IContentEntity Transform(QueryContext context, ISchemaEntity schema, bool checkType, IContentEntity content) { - return TansformCore(context, schema, checkType, Enumerable.Repeat(content, 1)).FirstOrDefault(); + return TransformCore(context, schema, checkType, Enumerable.Repeat(content, 1)).FirstOrDefault(); } private IResultList Transform(QueryContext context, ISchemaEntity schema, bool checkType, IResultList contents) { - var transformed = TansformCore(context, schema, checkType, contents); + var transformed = TransformCore(context, schema, checkType, contents); return ResultList.Create(contents.Total, transformed); } @@ -137,7 +140,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return ResultList.Create(contents.Total, sorted); } - private IEnumerable TansformCore(QueryContext context, ISchemaEntity schema, bool checkType, IEnumerable contents) + private IEnumerable TransformCore(QueryContext context, ISchemaEntity schema, bool checkType, IEnumerable contents) { using (Profiler.TraceMethod()) { @@ -214,9 +217,9 @@ namespace Squidex.Domain.Apps.Entities.Contents result.Sort.Add(new SortNode(new List { "lastModified" }, SortOrder.Descending)); } - if (result.Take > MaxResults) + if (result.Take > options.MaxResults) { - result.Take = MaxResults; + result.Take = options.MaxResults; } return result; diff --git a/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs b/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs index 71fa52761..401a0a67b 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/SingletonCommandMiddleware.cs @@ -31,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Contents var data = new NamedContentData(); var contentId = schemaId.Id; - var content = new CreateContent { Data = data, ContentId = contentId, SchemaId = schemaId }; + var content = new CreateContent { Data = data, ContentId = contentId, SchemaId = schemaId, DoNotValidate = true }; SimpleMapper.Map(createSchema, content); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs b/src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs index fd5b9a343..15f2fc357 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs @@ -86,13 +86,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.State protected void On(ContentStatusChanged @event) { ScheduleJob = null; - Status = @event.Status; if (@event.Status == Status.Published) { Data = DataDraft; } + + IsPending = false; } protected void On(ContentSchedulingCancelled @event) diff --git a/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj b/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj index a3d6da666..f3c64022d 100644 --- a/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj +++ b/src/Squidex.Domain.Apps.Entities/Squidex.Domain.Apps.Entities.csproj @@ -14,12 +14,12 @@ - - + + all runtime; build; native; contentfiles; analyzers - + diff --git a/src/Squidex.Domain.Users.MongoDb/Infrastructure/MongoPersistedGrantStore.cs b/src/Squidex.Domain.Users.MongoDb/Infrastructure/MongoPersistedGrantStore.cs index 0f839a848..abf05e1ac 100644 --- a/src/Squidex.Domain.Users.MongoDb/Infrastructure/MongoPersistedGrantStore.cs +++ b/src/Squidex.Domain.Users.MongoDb/Infrastructure/MongoPersistedGrantStore.cs @@ -6,6 +6,7 @@ // ========================================================================== using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using IdentityServer4.Models; using IdentityServer4.Stores; @@ -36,13 +37,14 @@ namespace Squidex.Domain.Users.MongoDb.Infrastructure return "Identity_PersistedGrants"; } - protected override Task SetupCollectionAsync(IMongoCollection collection) + protected override Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default(CancellationToken)) { - return Task.WhenAll( - collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.ClientId))), - collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.SubjectId)))); + return collection.Indexes.CreateManyAsync( + new[] + { + new CreateIndexModel(Index.Ascending(x => x.ClientId)), + new CreateIndexModel(Index.Ascending(x => x.SubjectId)) + }, ct); } public Task StoreAsync(PersistedGrant grant) diff --git a/src/Squidex.Domain.Users.MongoDb/MongoRoleStore.cs b/src/Squidex.Domain.Users.MongoDb/MongoRoleStore.cs index 745414c35..8043b89e2 100644 --- a/src/Squidex.Domain.Users.MongoDb/MongoRoleStore.cs +++ b/src/Squidex.Domain.Users.MongoDb/MongoRoleStore.cs @@ -26,10 +26,10 @@ namespace Squidex.Domain.Users.MongoDb return "Identity_Roles"; } - protected override Task SetupCollectionAsync(IMongoCollection collection) + protected override Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default(CancellationToken)) { return collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.NormalizedName), new CreateIndexOptions { Unique = true })); + new CreateIndexModel(Index.Ascending(x => x.NormalizedName), new CreateIndexOptions { Unique = true }), cancellationToken: ct); } protected override MongoCollectionSettings CollectionSettings() diff --git a/src/Squidex.Domain.Users.MongoDb/MongoUserStore.cs b/src/Squidex.Domain.Users.MongoDb/MongoUserStore.cs index 686acd84d..ec3cbde8d 100644 --- a/src/Squidex.Domain.Users.MongoDb/MongoUserStore.cs +++ b/src/Squidex.Domain.Users.MongoDb/MongoUserStore.cs @@ -46,15 +46,15 @@ namespace Squidex.Domain.Users.MongoDb return "Identity_Users"; } - protected override Task SetupCollectionAsync(IMongoCollection collection) - { - return Task.WhenAll( - collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending("Logins.LoginProvider").Ascending("Logins.ProviderKey"))), - collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.NormalizedUserName), new CreateIndexOptions { Unique = true })), - collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.NormalizedEmail), new CreateIndexOptions { Unique = true }))); + protected override Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default(CancellationToken)) + { + return collection.Indexes.CreateManyAsync( + new[] + { + new CreateIndexModel(Index.Ascending("Logins.LoginProvider").Ascending("Logins.ProviderKey")), + new CreateIndexModel(Index.Ascending(x => x.NormalizedUserName), new CreateIndexOptions { Unique = true }), + new CreateIndexModel(Index.Ascending(x => x.NormalizedEmail), new CreateIndexOptions { Unique = true }) + }, ct); } protected override MongoCollectionSettings CollectionSettings() diff --git a/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj b/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj index 8753ca0ef..56fc1237c 100644 --- a/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj +++ b/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj @@ -19,7 +19,7 @@ - + ..\..\Squidex.ruleset diff --git a/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj b/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj index 8a4d33405..539128d44 100644 --- a/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj +++ b/src/Squidex.Domain.Users/Squidex.Domain.Users.csproj @@ -17,7 +17,7 @@ - + ..\..\Squidex.ruleset diff --git a/src/Squidex.Infrastructure.Azure/Assets/AzureBlobAssetStore.cs b/src/Squidex.Infrastructure.Azure/Assets/AzureBlobAssetStore.cs index 4239d2c4b..969f00ef3 100644 --- a/src/Squidex.Infrastructure.Azure/Assets/AzureBlobAssetStore.cs +++ b/src/Squidex.Infrastructure.Azure/Assets/AzureBlobAssetStore.cs @@ -29,7 +29,7 @@ namespace Squidex.Infrastructure.Assets this.containerName = containerName; } - public void Initialize() + public async Task InitializeAsync(CancellationToken ct = default(CancellationToken)) { try { @@ -38,7 +38,7 @@ namespace Squidex.Infrastructure.Assets var blobClient = storageAccount.CreateCloudBlobClient(); var blobReference = blobClient.GetContainerReference(containerName); - blobReference.CreateIfNotExistsAsync().Wait(); + await blobReference.CreateIfNotExistsAsync(); blobContainer = blobReference; } @@ -130,7 +130,7 @@ namespace Squidex.Infrastructure.Assets return blob.DeleteIfExistsAsync(); } - private async Task UploadCoreAsync(string blobName, Stream stream, CancellationToken ct) + private async Task UploadCoreAsync(string blobName, Stream stream, CancellationToken ct = default(CancellationToken)) { try { diff --git a/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStore.cs b/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStore.cs index d948039e2..9ea5bc45c 100644 --- a/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStore.cs +++ b/src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStore.cs @@ -34,18 +34,18 @@ namespace Squidex.Infrastructure.EventSourcing projectionClient = new ProjectionClient(connection, prefix, projectionHost); } - public void Initialize() + public async Task InitializeAsync(CancellationToken ct = default(CancellationToken)) { try { - connection.ConnectAsync().Wait(); + await connection.ConnectAsync(); } catch (Exception ex) { throw new ConfigurationException("Cannot connect to event store.", ex); } - projectionClient.ConnectAsync().Wait(); + await projectionClient.ConnectAsync(); } public IEventSubscription CreateSubscription(IEventSubscriber subscriber, string streamFilter, string position = null) @@ -82,7 +82,7 @@ namespace Squidex.Infrastructure.EventSourcing } } - private async Task QueryAsync(Func callback, string streamName, long sliceStart, CancellationToken ct) + private async Task QueryAsync(Func callback, string streamName, long sliceStart, CancellationToken ct = default(CancellationToken)) { StreamEventsSlice currentSlice; do diff --git a/src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionClient.cs b/src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionClient.cs index 6c4ef3f75..cb6051f52 100644 --- a/src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionClient.cs +++ b/src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionClient.cs @@ -10,6 +10,7 @@ using System.Collections.Concurrent; using System.Linq; using System.Net; using System.Net.Sockets; +using System.Threading; using System.Threading.Tasks; using EventStore.ClientAPI; using EventStore.ClientAPI.Exceptions; @@ -103,7 +104,7 @@ namespace Squidex.Infrastructure.EventSourcing } } - public async Task ConnectAsync() + public async Task ConnectAsync(CancellationToken ct = default(CancellationToken)) { var addressParts = projectionHost.Split(':'); diff --git a/src/Squidex.Infrastructure.GoogleCloud/Assets/GoogleCloudAssetStore.cs b/src/Squidex.Infrastructure.GoogleCloud/Assets/GoogleCloudAssetStore.cs index 9a8a31e7c..3ef01b8d2 100644 --- a/src/Squidex.Infrastructure.GoogleCloud/Assets/GoogleCloudAssetStore.cs +++ b/src/Squidex.Infrastructure.GoogleCloud/Assets/GoogleCloudAssetStore.cs @@ -30,13 +30,13 @@ namespace Squidex.Infrastructure.Assets this.bucketName = bucketName; } - public void Initialize() + public async Task InitializeAsync(CancellationToken ct = default(CancellationToken)) { try { storageClient = StorageClient.Create(); - storageClient.GetBucket(bucketName); + await storageClient.GetBucketAsync(bucketName, cancellationToken: ct); } catch (Exception ex) { @@ -103,7 +103,7 @@ namespace Squidex.Infrastructure.Assets return DeleteCoreAsync(fileName); } - private async Task UploadCoreAsync(string objectName, Stream stream, CancellationToken ct) + private async Task UploadCoreAsync(string objectName, Stream stream, CancellationToken ct = default(CancellationToken)) { try { diff --git a/src/Squidex.Infrastructure.MongoDb/Assets/MongoGridFsAssetStore.cs b/src/Squidex.Infrastructure.MongoDb/Assets/MongoGridFsAssetStore.cs index 15dc5619b..7f4ac0fd5 100644 --- a/src/Squidex.Infrastructure.MongoDb/Assets/MongoGridFsAssetStore.cs +++ b/src/Squidex.Infrastructure.MongoDb/Assets/MongoGridFsAssetStore.cs @@ -27,11 +27,11 @@ namespace Squidex.Infrastructure.Assets this.bucket = bucket; } - public void Initialize() + public async Task InitializeAsync(CancellationToken ct = default(CancellationToken)) { try { - bucket.Database.ListCollections(); + await bucket.Database.ListCollectionsAsync(cancellationToken: ct); } catch (MongoException ex) { diff --git a/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore.cs b/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore.cs index 9438d62d6..be564d763 100644 --- a/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore.cs +++ b/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System.Threading; using System.Threading.Tasks; using MongoDB.Bson; using MongoDB.Driver; @@ -43,13 +44,14 @@ namespace Squidex.Infrastructure.EventSourcing return new MongoCollectionSettings { ReadPreference = ReadPreference.Primary, WriteConcern = WriteConcern.WMajority }; } - protected override Task SetupCollectionAsync(IMongoCollection collection) + protected override Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default(CancellationToken)) { - return Task.WhenAll( - collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.Timestamp).Ascending(x => x.EventStream))), - collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.EventStream).Descending(x => x.EventStreamOffset), new CreateIndexOptions { Unique = true }))); + return collection.Indexes.CreateManyAsync( + new[] + { + new CreateIndexModel(Index.Ascending(x => x.Timestamp).Ascending(x => x.EventStream)), + new CreateIndexModel(Index.Ascending(x => x.EventStream).Descending(x => x.EventStreamOffset), new CreateIndexOptions { Unique = true }) + }, ct); } } } \ No newline at end of file diff --git a/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs b/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs index a9e31eb43..d11bc804a 100644 --- a/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs +++ b/src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs @@ -91,7 +91,7 @@ namespace Squidex.Infrastructure.EventSourcing return QueryAsync(callback, lastPosition, filter, ct); } - private async Task QueryAsync(Func callback, StreamPosition lastPosition, FilterDefinition filter, CancellationToken ct) + private async Task QueryAsync(Func callback, StreamPosition lastPosition, FilterDefinition filter, CancellationToken ct = default(CancellationToken)) { using (Profiler.TraceMethod()) { diff --git a/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs b/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs index d8c35ef2d..0a11b956e 100644 --- a/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs +++ b/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs @@ -7,6 +7,7 @@ using System; using System.Globalization; +using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; using Squidex.Infrastructure.Tasks; @@ -67,21 +68,12 @@ namespace Squidex.Infrastructure.MongoDb private Lazy> CreateCollection() { return new Lazy>(() => - { - return Task.Run(async () => - { - var databaseCollection = mongoDatabase.GetCollection( - CollectionName(), - CollectionSettings() ?? new MongoCollectionSettings()); - - await SetupCollectionAsync(databaseCollection).ConfigureAwait(false); - - return databaseCollection; - }).Result; - }); + mongoDatabase.GetCollection( + CollectionName(), + CollectionSettings() ?? new MongoCollectionSettings())); } - protected virtual Task SetupCollectionAsync(IMongoCollection collection) + protected virtual Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default(CancellationToken)) { return TaskHelper.Done; } @@ -93,7 +85,7 @@ namespace Squidex.Infrastructure.MongoDb await SetupCollectionAsync(Collection); } - public async Task DropCollectionIfExistsAsync() + public async Task DropCollectionIfExistsAsync(CancellationToken ct = default(CancellationToken)) { try { @@ -101,6 +93,8 @@ namespace Squidex.Infrastructure.MongoDb mongoCollection = CreateCollection(); + await SetupCollectionAsync(Collection, ct); + return true; } catch @@ -109,11 +103,11 @@ namespace Squidex.Infrastructure.MongoDb } } - public void Initialize() + public async Task InitializeAsync(CancellationToken ct = default(CancellationToken)) { try { - Database.ListCollections(); + await SetupCollectionAsync(Collection, ct); } catch (Exception ex) { diff --git a/src/Squidex.Infrastructure.MongoDb/UsageTracking/MongoUsageStore.cs b/src/Squidex.Infrastructure.MongoDb/UsageTracking/MongoUsageStore.cs index dc77f5677..63d6d32bc 100644 --- a/src/Squidex.Infrastructure.MongoDb/UsageTracking/MongoUsageStore.cs +++ b/src/Squidex.Infrastructure.MongoDb/UsageTracking/MongoUsageStore.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; using Squidex.Infrastructure.MongoDb; @@ -26,10 +27,10 @@ namespace Squidex.Infrastructure.UsageTracking return "Usages"; } - protected override Task SetupCollectionAsync(IMongoCollection collection) + protected override Task SetupCollectionAsync(IMongoCollection collection, CancellationToken ct = default(CancellationToken)) { return collection.Indexes.CreateOneAsync( - new CreateIndexModel(Index.Ascending(x => x.Key).Ascending(x => x.Category).Ascending(x => x.Date))); + new CreateIndexModel(Index.Ascending(x => x.Key).Ascending(x => x.Category).Ascending(x => x.Date)), cancellationToken: ct); } public Task TrackUsagesAsync(DateTime date, string key, string category, double count, double elapsedMs) diff --git a/src/Squidex.Infrastructure.RabbitMq/CQRS/Events/RabbitMqEventConsumer.cs b/src/Squidex.Infrastructure.RabbitMq/CQRS/Events/RabbitMqEventConsumer.cs index 979a66208..238698bda 100644 --- a/src/Squidex.Infrastructure.RabbitMq/CQRS/Events/RabbitMqEventConsumer.cs +++ b/src/Squidex.Infrastructure.RabbitMq/CQRS/Events/RabbitMqEventConsumer.cs @@ -7,6 +7,7 @@ using System; using System.Text; +using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using RabbitMQ.Client; @@ -61,7 +62,7 @@ namespace Squidex.Infrastructure.CQRS.Events } } - public void Initialize() + public Task InitializeAsync(CancellationToken ct = default(CancellationToken)) { try { @@ -71,6 +72,8 @@ namespace Squidex.Infrastructure.CQRS.Events { throw new ConfigurationException($"RabbitMq event bus failed to connect to {connectionFactory.Endpoint}"); } + + return TaskHelper.Done; } catch (Exception e) { diff --git a/src/Squidex.Infrastructure.Redis/RedisPubSub.cs b/src/Squidex.Infrastructure.Redis/RedisPubSub.cs index ce14d18fb..ce5e9f1f0 100644 --- a/src/Squidex.Infrastructure.Redis/RedisPubSub.cs +++ b/src/Squidex.Infrastructure.Redis/RedisPubSub.cs @@ -7,7 +7,10 @@ using System; using System.Collections.Concurrent; +using System.Threading; +using System.Threading.Tasks; using Squidex.Infrastructure.Log; +using Squidex.Infrastructure.Tasks; using StackExchange.Redis; namespace Squidex.Infrastructure @@ -30,11 +33,13 @@ namespace Squidex.Infrastructure redisSubscriber = new Lazy(() => redis.Value.GetSubscriber()); } - public void Initialize() + public Task InitializeAsync(CancellationToken ct = default(CancellationToken)) { try { redisClient.Value.GetStatus(); + + return TaskHelper.Done; } catch (Exception ex) { diff --git a/src/Squidex.Infrastructure/Assets/FolderAssetStore.cs b/src/Squidex.Infrastructure/Assets/FolderAssetStore.cs index e86c5dd84..435e41433 100644 --- a/src/Squidex.Infrastructure/Assets/FolderAssetStore.cs +++ b/src/Squidex.Infrastructure/Assets/FolderAssetStore.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System; using System.IO; using System.Linq; using System.Threading; @@ -30,7 +31,7 @@ namespace Squidex.Infrastructure.Assets directory = new DirectoryInfo(path); } - public void Initialize() + public Task InitializeAsync(CancellationToken ct = default(CancellationToken)) { try { @@ -42,13 +43,12 @@ namespace Squidex.Infrastructure.Assets log.LogInformation(w => w .WriteProperty("action", "FolderAssetStoreConfigured") .WriteProperty("path", directory.FullName)); + + return TaskHelper.Done; } - catch + catch (Exception ex) { - if (!directory.Exists) - { - throw new ConfigurationException($"Cannot access directory {directory.FullName}"); - } + throw new ConfigurationException($"Cannot access directory {directory.FullName}", ex); } } @@ -125,7 +125,7 @@ namespace Squidex.Infrastructure.Assets return TaskHelper.Done; } - private static async Task UploadCoreAsync(FileInfo file, Stream stream, CancellationToken ct) + private static async Task UploadCoreAsync(FileInfo file, Stream stream, CancellationToken ct = default(CancellationToken)) { try { diff --git a/src/Squidex.Infrastructure/IInitializable.cs b/src/Squidex.Infrastructure/IInitializable.cs index 85011ae58..21f2afc8e 100644 --- a/src/Squidex.Infrastructure/IInitializable.cs +++ b/src/Squidex.Infrastructure/IInitializable.cs @@ -5,10 +5,13 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System.Threading; +using System.Threading.Tasks; + namespace Squidex.Infrastructure { public interface IInitializable { - void Initialize(); + Task InitializeAsync(CancellationToken ct = default(CancellationToken)); } } diff --git a/src/Squidex.Infrastructure/Language.cs b/src/Squidex.Infrastructure/Language.cs index 5534be463..e18268e7b 100644 --- a/src/Squidex.Infrastructure/Language.cs +++ b/src/Squidex.Infrastructure/Language.cs @@ -20,11 +20,7 @@ namespace Squidex.Infrastructure private static Language AddLanguage(string iso2Code, string englishName) { - var language = new Language(iso2Code, englishName); - - AllLanguagesField[iso2Code] = language; - - return language; + return AllLanguagesField.GetOrAdd(iso2Code, code => new Language(code, englishName)); } public static Language GetLanguage(string iso2Code) diff --git a/src/Squidex.Infrastructure/Languages.cs b/src/Squidex.Infrastructure/Languages.cs index f788c86e2..403b79996 100644 --- a/src/Squidex.Infrastructure/Languages.cs +++ b/src/Squidex.Infrastructure/Languages.cs @@ -1,4 +1,5 @@ // ========================================================================== +// Languages.cs // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex UG (haftungsbeschränkt) @@ -190,5 +191,325 @@ namespace Squidex.Infrastructure public static readonly Language ZA = AddLanguage("za", "Zhuang"); public static readonly Language ZH = AddLanguage("zh", "Chinese"); public static readonly Language ZU = AddLanguage("zu", "Zulu"); + + public static readonly Language AfarDjibouti = AddLanguage("aa-DJ", "Afar (Djibouti)"); + public static readonly Language AfarEritrea = AddLanguage("aa-ER", "Afar (Eritrea)"); + public static readonly Language AfarEthiopia = AddLanguage("aa-ET", "Afar (Ethiopia)"); + public static readonly Language AfrikaansNamibia = AddLanguage("af-NA", "Afrikaans (Namibia)"); + public static readonly Language AfrikaansSouthAfrica = AddLanguage("af-ZA", "Afrikaans (South Africa)"); + public static readonly Language ArabicUnitedArabEmirates = AddLanguage("ar-AE", "Arabic (United Arab Emirates)"); + public static readonly Language ArabicBahrain = AddLanguage("ar-BH", "Arabic (Bahrain)"); + public static readonly Language ArabicDjibouti = AddLanguage("ar-DJ", "Arabic (Djibouti)"); + public static readonly Language ArabicAlgeria = AddLanguage("ar-DZ", "Arabic (Algeria)"); + public static readonly Language ArabicEgypt = AddLanguage("ar-EG", "Arabic (Egypt)"); + public static readonly Language ArabicEritrea = AddLanguage("ar-ER", "Arabic (Eritrea)"); + public static readonly Language ArabicIsrael = AddLanguage("ar-IL", "Arabic (Israel)"); + public static readonly Language ArabicIraq = AddLanguage("ar-IQ", "Arabic (Iraq)"); + public static readonly Language ArabicJordan = AddLanguage("ar-JO", "Arabic (Jordan)"); + public static readonly Language ArabicComoros = AddLanguage("ar-KM", "Arabic (Comoros)"); + public static readonly Language ArabicKuwait = AddLanguage("ar-KW", "Arabic (Kuwait)"); + public static readonly Language ArabicLebanon = AddLanguage("ar-LB", "Arabic (Lebanon)"); + public static readonly Language ArabicLibya = AddLanguage("ar-LY", "Arabic (Libya)"); + public static readonly Language ArabicMorocco = AddLanguage("ar-MA", "Arabic (Morocco)"); + public static readonly Language ArabicMauritania = AddLanguage("ar-MR", "Arabic (Mauritania)"); + public static readonly Language ArabicOman = AddLanguage("ar-OM", "Arabic (Oman)"); + public static readonly Language ArabicPalestinianAuthority = AddLanguage("ar-PS", "Arabic (Palestinian Authority)"); + public static readonly Language ArabicQatar = AddLanguage("ar-QA", "Arabic (Qatar)"); + public static readonly Language ArabicSaudiArabia = AddLanguage("ar-SA", "Arabic (Saudi Arabia)"); + public static readonly Language ArabicSudan = AddLanguage("ar-SD", "Arabic (Sudan)"); + public static readonly Language ArabicSomalia = AddLanguage("ar-SO", "Arabic (Somalia)"); + public static readonly Language ArabicSouthSudan = AddLanguage("ar-SS", "Arabic (South Sudan)"); + public static readonly Language ArabicSyria = AddLanguage("ar-SY", "Arabic (Syria)"); + public static readonly Language ArabicChad = AddLanguage("ar-TD", "Arabic (Chad)"); + public static readonly Language ArabicTunisia = AddLanguage("ar-TN", "Arabic (Tunisia)"); + public static readonly Language ArabicYemen = AddLanguage("ar-YE", "Arabic (Yemen)"); + public static readonly Language BanglaBangladesh = AddLanguage("bn-BD", "Bangla (Bangladesh)"); + public static readonly Language BanglaIndia = AddLanguage("bn-IN", "Bangla (India)"); + public static readonly Language TibetanChina = AddLanguage("bo-CN", "Tibetan (China)"); + public static readonly Language TibetanIndia = AddLanguage("bo-IN", "Tibetan (India)"); + public static readonly Language CatalanAndorra = AddLanguage("ca-AD", "Catalan (Andorra)"); + public static readonly Language CatalanCatalan = AddLanguage("ca-ES", "Catalan (Catalan)"); + public static readonly Language CatalanFrance = AddLanguage("ca-FR", "Catalan (France)"); + public static readonly Language CatalanItaly = AddLanguage("ca-IT", "Catalan (Italy)"); + public static readonly Language DanishDenmark = AddLanguage("da-DK", "Danish (Denmark)"); + public static readonly Language DanishGreenland = AddLanguage("da-GL", "Danish (Greenland)"); + public static readonly Language GermanAustria = AddLanguage("de-AT", "German (Austria)"); + public static readonly Language GermanBelgium = AddLanguage("de-BE", "German (Belgium)"); + public static readonly Language GermanSwitzerland = AddLanguage("de-CH", "German (Switzerland)"); + public static readonly Language GermanGermany = AddLanguage("de-DE", "German (Germany)"); + public static readonly Language GermanItaly = AddLanguage("de-IT", "German (Italy)"); + public static readonly Language GermanLiechtenstein = AddLanguage("de-LI", "German (Liechtenstein)"); + public static readonly Language GermanLuxembourg = AddLanguage("de-LU", "German (Luxembourg)"); + public static readonly Language EweGhana = AddLanguage("ee-GH", "Ewe (Ghana)"); + public static readonly Language EweTogo = AddLanguage("ee-TG", "Ewe (Togo)"); + public static readonly Language GreekCyprus = AddLanguage("el-CY", "Greek (Cyprus)"); + public static readonly Language GreekGreece = AddLanguage("el-GR", "Greek (Greece)"); + public static readonly Language EnglishAntiguaandBarbuda = AddLanguage("en-AG", "English (Antigua and Barbuda)"); + public static readonly Language EnglishAnguilla = AddLanguage("en-AI", "English (Anguilla)"); + public static readonly Language EnglishAmericanSamoa = AddLanguage("en-AS", "English (American Samoa)"); + public static readonly Language EnglishAustria = AddLanguage("en-AT", "English (Austria)"); + public static readonly Language EnglishAustralia = AddLanguage("en-AU", "English (Australia)"); + public static readonly Language EnglishBarbados = AddLanguage("en-BB", "English (Barbados)"); + public static readonly Language EnglishBelgium = AddLanguage("en-BE", "English (Belgium)"); + public static readonly Language EnglishBurundi = AddLanguage("en-BI", "English (Burundi)"); + public static readonly Language EnglishBermuda = AddLanguage("en-BM", "English (Bermuda)"); + public static readonly Language EnglishBahamas = AddLanguage("en-BS", "English (Bahamas)"); + public static readonly Language EnglishBotswana = AddLanguage("en-BW", "English (Botswana)"); + public static readonly Language EnglishBelize = AddLanguage("en-BZ", "English (Belize)"); + public static readonly Language EnglishCanada = AddLanguage("en-CA", "English (Canada)"); + public static readonly Language EnglishCocosKeelingIslands = AddLanguage("en-CC", "English (Cocos (Keeling) Islands)"); + public static readonly Language EnglishSwitzerland = AddLanguage("en-CH", "English (Switzerland)"); + public static readonly Language EnglishCookIslands = AddLanguage("en-CK", "English (Cook Islands)"); + public static readonly Language EnglishCameroon = AddLanguage("en-CM", "English (Cameroon)"); + public static readonly Language EnglishChristmasIsland = AddLanguage("en-CX", "English (Christmas Island)"); + public static readonly Language EnglishCyprus = AddLanguage("en-CY", "English (Cyprus)"); + public static readonly Language EnglishGermany = AddLanguage("en-DE", "English (Germany)"); + public static readonly Language EnglishDenmark = AddLanguage("en-DK", "English (Denmark)"); + public static readonly Language EnglishDominica = AddLanguage("en-DM", "English (Dominica)"); + public static readonly Language EnglishEritrea = AddLanguage("en-ER", "English (Eritrea)"); + public static readonly Language EnglishFinland = AddLanguage("en-FI", "English (Finland)"); + public static readonly Language EnglishFiji = AddLanguage("en-FJ", "English (Fiji)"); + public static readonly Language EnglishFalklandIslands = AddLanguage("en-FK", "English (Falkland Islands)"); + public static readonly Language EnglishMicronesia = AddLanguage("en-FM", "English (Micronesia)"); + public static readonly Language EnglishUnitedKingdom = AddLanguage("en-GB", "English (United Kingdom)"); + public static readonly Language EnglishGrenada = AddLanguage("en-GD", "English (Grenada)"); + public static readonly Language EnglishGuernsey = AddLanguage("en-GG", "English (Guernsey)"); + public static readonly Language EnglishGhana = AddLanguage("en-GH", "English (Ghana)"); + public static readonly Language EnglishGibraltar = AddLanguage("en-GI", "English (Gibraltar)"); + public static readonly Language EnglishGambia = AddLanguage("en-GM", "English (Gambia)"); + public static readonly Language EnglishGuam = AddLanguage("en-GU", "English (Guam)"); + public static readonly Language EnglishGuyana = AddLanguage("en-GY", "English (Guyana)"); + public static readonly Language EnglishHongKongSAR = AddLanguage("en-HK", "English (Hong Kong SAR)"); + public static readonly Language EnglishIndonesia = AddLanguage("en-ID", "English (Indonesia)"); + public static readonly Language EnglishIreland = AddLanguage("en-IE", "English (Ireland)"); + public static readonly Language EnglishIsrael = AddLanguage("en-IL", "English (Israel)"); + public static readonly Language EnglishIsleofMan = AddLanguage("en-IM", "English (Isle of Man)"); + public static readonly Language EnglishIndia = AddLanguage("en-IN", "English (India)"); + public static readonly Language EnglishBritishIndianOceanTerritory = AddLanguage("en-IO", "English (British Indian Ocean Territory)"); + public static readonly Language EnglishJersey = AddLanguage("en-JE", "English (Jersey)"); + public static readonly Language EnglishJamaica = AddLanguage("en-JM", "English (Jamaica)"); + public static readonly Language EnglishKenya = AddLanguage("en-KE", "English (Kenya)"); + public static readonly Language EnglishKiribati = AddLanguage("en-KI", "English (Kiribati)"); + public static readonly Language EnglishSaintKittsandNevis = AddLanguage("en-KN", "English (Saint Kitts and Nevis)"); + public static readonly Language EnglishCaymanIslands = AddLanguage("en-KY", "English (Cayman Islands)"); + public static readonly Language EnglishSaintLucia = AddLanguage("en-LC", "English (Saint Lucia)"); + public static readonly Language EnglishLiberia = AddLanguage("en-LR", "English (Liberia)"); + public static readonly Language EnglishLesotho = AddLanguage("en-LS", "English (Lesotho)"); + public static readonly Language EnglishMadagascar = AddLanguage("en-MG", "English (Madagascar)"); + public static readonly Language EnglishMarshallIslands = AddLanguage("en-MH", "English (Marshall Islands)"); + public static readonly Language EnglishMacaoSAR = AddLanguage("en-MO", "English (Macao SAR)"); + public static readonly Language EnglishNorthernMarianaIslands = AddLanguage("en-MP", "English (Northern Mariana Islands)"); + public static readonly Language EnglishMontserrat = AddLanguage("en-MS", "English (Montserrat)"); + public static readonly Language EnglishMalta = AddLanguage("en-MT", "English (Malta)"); + public static readonly Language EnglishMauritius = AddLanguage("en-MU", "English (Mauritius)"); + public static readonly Language EnglishMalawi = AddLanguage("en-MW", "English (Malawi)"); + public static readonly Language EnglishMalaysia = AddLanguage("en-MY", "English (Malaysia)"); + public static readonly Language EnglishNamibia = AddLanguage("en-NA", "English (Namibia)"); + public static readonly Language EnglishNorfolkIsland = AddLanguage("en-NF", "English (Norfolk Island)"); + public static readonly Language EnglishNigeria = AddLanguage("en-NG", "English (Nigeria)"); + public static readonly Language EnglishNetherlands = AddLanguage("en-NL", "English (Netherlands)"); + public static readonly Language EnglishNauru = AddLanguage("en-NR", "English (Nauru)"); + public static readonly Language EnglishNiue = AddLanguage("en-NU", "English (Niue)"); + public static readonly Language EnglishNewZealand = AddLanguage("en-NZ", "English (New Zealand)"); + public static readonly Language EnglishPapuaNewGuinea = AddLanguage("en-PG", "English (Papua New Guinea)"); + public static readonly Language EnglishPhilippines = AddLanguage("en-PH", "English (Philippines)"); + public static readonly Language EnglishPakistan = AddLanguage("en-PK", "English (Pakistan)"); + public static readonly Language EnglishPitcairnIslands = AddLanguage("en-PN", "English (Pitcairn Islands)"); + public static readonly Language EnglishPuertoRico = AddLanguage("en-PR", "English (Puerto Rico)"); + public static readonly Language EnglishPalau = AddLanguage("en-PW", "English (Palau)"); + public static readonly Language EnglishRwanda = AddLanguage("en-RW", "English (Rwanda)"); + public static readonly Language EnglishSolomonIslands = AddLanguage("en-SB", "English (Solomon Islands)"); + public static readonly Language EnglishSeychelles = AddLanguage("en-SC", "English (Seychelles)"); + public static readonly Language EnglishSudan = AddLanguage("en-SD", "English (Sudan)"); + public static readonly Language EnglishSweden = AddLanguage("en-SE", "English (Sweden)"); + public static readonly Language EnglishSingapore = AddLanguage("en-SG", "English (Singapore)"); + public static readonly Language EnglishStHelenaAscensionTristandaCunha = AddLanguage("en-SH", "English (St Helena, Ascension, Tristan da Cunha)"); + public static readonly Language EnglishSlovenia = AddLanguage("en-SI", "English (Slovenia)"); + public static readonly Language EnglishSierraLeone = AddLanguage("en-SL", "English (Sierra Leone)"); + public static readonly Language EnglishSouthSudan = AddLanguage("en-SS", "English (South Sudan)"); + public static readonly Language EnglishSintMaarten = AddLanguage("en-SX", "English (Sint Maarten)"); + public static readonly Language EnglishSwaziland = AddLanguage("en-SZ", "English (Swaziland)"); + public static readonly Language EnglishTurksandCaicosIslands = AddLanguage("en-TC", "English (Turks and Caicos Islands)"); + public static readonly Language EnglishTokelau = AddLanguage("en-TK", "English (Tokelau)"); + public static readonly Language EnglishTonga = AddLanguage("en-TO", "English (Tonga)"); + public static readonly Language EnglishTrinidadandTobago = AddLanguage("en-TT", "English (Trinidad and Tobago)"); + public static readonly Language EnglishTuvalu = AddLanguage("en-TV", "English (Tuvalu)"); + public static readonly Language EnglishTanzania = AddLanguage("en-TZ", "English (Tanzania)"); + public static readonly Language EnglishUganda = AddLanguage("en-UG", "English (Uganda)"); + public static readonly Language EnglishUSOutlyingIslands = AddLanguage("en-UM", "English (U.S. Outlying Islands)"); + public static readonly Language EnglishUnitedStates = AddLanguage("en-US", "English (United States)"); + public static readonly Language EnglishSaintVincentandtheGrenadines = AddLanguage("en-VC", "English (Saint Vincent and the Grenadines)"); + public static readonly Language EnglishBritishVirginIslands = AddLanguage("en-VG", "English (British Virgin Islands)"); + public static readonly Language EnglishUSVirginIslands = AddLanguage("en-VI", "English (U.S. Virgin Islands)"); + public static readonly Language EnglishVanuatu = AddLanguage("en-VU", "English (Vanuatu)"); + public static readonly Language EnglishSamoa = AddLanguage("en-WS", "English (Samoa)"); + public static readonly Language EnglishSouthAfrica = AddLanguage("en-ZA", "English (South Africa)"); + public static readonly Language EnglishZambia = AddLanguage("en-ZM", "English (Zambia)"); + public static readonly Language EnglishZimbabwe = AddLanguage("en-ZW", "English (Zimbabwe)"); + public static readonly Language SpanishArgentina = AddLanguage("es-AR", "Spanish (Argentina)"); + public static readonly Language SpanishBolivia = AddLanguage("es-BO", "Spanish (Bolivia)"); + public static readonly Language SpanishBrazil = AddLanguage("es-BR", "Spanish (Brazil)"); + public static readonly Language SpanishBelize = AddLanguage("es-BZ", "Spanish (Belize)"); + public static readonly Language SpanishChile = AddLanguage("es-CL", "Spanish (Chile)"); + public static readonly Language SpanishColombia = AddLanguage("es-CO", "Spanish (Colombia)"); + public static readonly Language SpanishCostaRica = AddLanguage("es-CR", "Spanish (Costa Rica)"); + public static readonly Language SpanishCuba = AddLanguage("es-CU", "Spanish (Cuba)"); + public static readonly Language SpanishDominicanRepublic = AddLanguage("es-DO", "Spanish (Dominican Republic)"); + public static readonly Language SpanishEcuador = AddLanguage("es-EC", "Spanish (Ecuador)"); + public static readonly Language SpanishSpainInternationalSort = AddLanguage("es-ES", "Spanish (Spain, International Sort)"); + public static readonly Language SpanishEquatorialGuinea = AddLanguage("es-GQ", "Spanish (Equatorial Guinea)"); + public static readonly Language SpanishGuatemala = AddLanguage("es-GT", "Spanish (Guatemala)"); + public static readonly Language SpanishHonduras = AddLanguage("es-HN", "Spanish (Honduras)"); + public static readonly Language SpanishMexico = AddLanguage("es-MX", "Spanish (Mexico)"); + public static readonly Language SpanishNicaragua = AddLanguage("es-NI", "Spanish (Nicaragua)"); + public static readonly Language SpanishPanama = AddLanguage("es-PA", "Spanish (Panama)"); + public static readonly Language SpanishPeru = AddLanguage("es-PE", "Spanish (Peru)"); + public static readonly Language SpanishPhilippines = AddLanguage("es-PH", "Spanish (Philippines)"); + public static readonly Language SpanishPuertoRico = AddLanguage("es-PR", "Spanish (Puerto Rico)"); + public static readonly Language SpanishParaguay = AddLanguage("es-PY", "Spanish (Paraguay)"); + public static readonly Language SpanishElSalvador = AddLanguage("es-SV", "Spanish (El Salvador)"); + public static readonly Language SpanishUnitedStates = AddLanguage("es-US", "Spanish (United States)"); + public static readonly Language SpanishUruguay = AddLanguage("es-UY", "Spanish (Uruguay)"); + public static readonly Language SpanishVenezuela = AddLanguage("es-VE", "Spanish (Venezuela)"); + public static readonly Language FulahCameroon = AddLanguage("ff-CM", "Fulah (Cameroon)"); + public static readonly Language FulahGuinea = AddLanguage("ff-GN", "Fulah (Guinea)"); + public static readonly Language FulahMauritania = AddLanguage("ff-MR", "Fulah (Mauritania)"); + public static readonly Language FulahNigeria = AddLanguage("ff-NG", "Fulah (Nigeria)"); + public static readonly Language FaroeseDenmark = AddLanguage("fo-DK", "Faroese (Denmark)"); + public static readonly Language FaroeseFaroeIslands = AddLanguage("fo-FO", "Faroese (Faroe Islands)"); + public static readonly Language FrenchBelgium = AddLanguage("fr-BE", "French (Belgium)"); + public static readonly Language FrenchBurkinaFaso = AddLanguage("fr-BF", "French (Burkina Faso)"); + public static readonly Language FrenchBurundi = AddLanguage("fr-BI", "French (Burundi)"); + public static readonly Language FrenchBenin = AddLanguage("fr-BJ", "French (Benin)"); + public static readonly Language FrenchSaintBarthélemy = AddLanguage("fr-BL", "French (Saint Barthélemy)"); + public static readonly Language FrenchCanada = AddLanguage("fr-CA", "French (Canada)"); + public static readonly Language FrenchCongoDRC = AddLanguage("fr-CD", "French Congo (DRC)"); + public static readonly Language FrenchCentralAfricanRepublic = AddLanguage("fr-CF", "French (Central African Republic)"); + public static readonly Language FrenchCongo = AddLanguage("fr-CG", "French (Congo)"); + public static readonly Language FrenchSwitzerland = AddLanguage("fr-CH", "French (Switzerland)"); + public static readonly Language FrenchCôtedIvoire = AddLanguage("fr-CI", "French (Côte d’Ivoire)"); + public static readonly Language FrenchCameroon = AddLanguage("fr-CM", "French (Cameroon)"); + public static readonly Language FrenchDjibouti = AddLanguage("fr-DJ", "French (Djibouti)"); + public static readonly Language FrenchAlgeria = AddLanguage("fr-DZ", "French (Algeria)"); + public static readonly Language FrenchFrance = AddLanguage("fr-FR", "French (France)"); + public static readonly Language FrenchGabon = AddLanguage("fr-GA", "French (Gabon)"); + public static readonly Language FrenchFrenchGuiana = AddLanguage("fr-GF", "French (French Guiana)"); + public static readonly Language FrenchGuinea = AddLanguage("fr-GN", "French (Guinea)"); + public static readonly Language FrenchGuadeloupe = AddLanguage("fr-GP", "French (Guadeloupe)"); + public static readonly Language FrenchEquatorialGuinea = AddLanguage("fr-GQ", "French (Equatorial Guinea)"); + public static readonly Language FrenchHaiti = AddLanguage("fr-HT", "French (Haiti)"); + public static readonly Language FrenchComoros = AddLanguage("fr-KM", "French (Comoros)"); + public static readonly Language FrenchLuxembourg = AddLanguage("fr-LU", "French (Luxembourg)"); + public static readonly Language FrenchMorocco = AddLanguage("fr-MA", "French (Morocco)"); + public static readonly Language FrenchMonaco = AddLanguage("fr-MC", "French (Monaco)"); + public static readonly Language FrenchSaintMartin = AddLanguage("fr-MF", "French (Saint Martin)"); + public static readonly Language FrenchMadagascar = AddLanguage("fr-MG", "French (Madagascar)"); + public static readonly Language FrenchMali = AddLanguage("fr-ML", "French (Mali)"); + public static readonly Language FrenchMartinique = AddLanguage("fr-MQ", "French (Martinique)"); + public static readonly Language FrenchMauritania = AddLanguage("fr-MR", "French (Mauritania)"); + public static readonly Language FrenchMauritius = AddLanguage("fr-MU", "French (Mauritius)"); + public static readonly Language FrenchNewCaledonia = AddLanguage("fr-NC", "French (New Caledonia)"); + public static readonly Language FrenchNiger = AddLanguage("fr-NE", "French (Niger)"); + public static readonly Language FrenchFrenchPolynesia = AddLanguage("fr-PF", "French (French Polynesia)"); + public static readonly Language FrenchSaintPierreandMiquelon = AddLanguage("fr-PM", "French (Saint Pierre and Miquelon)"); + public static readonly Language FrenchRéunion = AddLanguage("fr-RE", "French (Réunion)"); + public static readonly Language FrenchRwanda = AddLanguage("fr-RW", "French (Rwanda)"); + public static readonly Language FrenchSeychelles = AddLanguage("fr-SC", "French (Seychelles)"); + public static readonly Language FrenchSenegal = AddLanguage("fr-SN", "French (Senegal)"); + public static readonly Language FrenchSyria = AddLanguage("fr-SY", "French (Syria)"); + public static readonly Language FrenchChad = AddLanguage("fr-TD", "French (Chad)"); + public static readonly Language FrenchTogo = AddLanguage("fr-TG", "French (Togo)"); + public static readonly Language FrenchTunisia = AddLanguage("fr-TN", "French (Tunisia)"); + public static readonly Language FrenchVanuatu = AddLanguage("fr-VU", "French (Vanuatu)"); + public static readonly Language FrenchWallisandFutuna = AddLanguage("fr-WF", "French (Wallis and Futuna)"); + public static readonly Language FrenchMayotte = AddLanguage("fr-YT", "French (Mayotte)"); + public static readonly Language CroatianBosniaandHerzegovina = AddLanguage("hr-BA", "Croatian (Bosnia and Herzegovina)"); + public static readonly Language CroatianCroatia = AddLanguage("hr-HR", "Croatian (Croatia)"); + public static readonly Language ItalianSwitzerland = AddLanguage("it-CH", "Italian (Switzerland)"); + public static readonly Language ItalianItaly = AddLanguage("it-IT", "Italian (Italy)"); + public static readonly Language ItalianSanMarino = AddLanguage("it-SM", "Italian (San Marino)"); + public static readonly Language ItalianVaticanCity = AddLanguage("it-VA", "Italian (Vatican City)"); + public static readonly Language KoreanNorthKorea = AddLanguage("ko-KP", "Korean (North Korea)"); + public static readonly Language KoreanKorea = AddLanguage("ko-KR", "Korean (Korea)"); + public static readonly Language LingalaAngola = AddLanguage("ln-AO", "Lingala (Angola)"); + public static readonly Language LingalaCongoDRC = AddLanguage("ln-CD", "Lingala (Congo DRC)"); + public static readonly Language LingalaCentralAfricanRepublic = AddLanguage("ln-CF", "Lingala (Central African Republic)"); + public static readonly Language LingalaCongo = AddLanguage("ln-CG", "Lingala (Congo)"); + public static readonly Language MalayBrunei = AddLanguage("ms-BN", "Malay (Brunei)"); + public static readonly Language MalayMalaysia = AddLanguage("ms-MY", "Malay (Malaysia)"); + public static readonly Language MalaySingapore = AddLanguage("ms-SG", "Malay (Singapore)"); + public static readonly Language NorwegianBokmålNorway = AddLanguage("nb-NO", "Norwegian Bokmål (Norway)"); + public static readonly Language NorwegianBokmålSvalbardandJanMayen = AddLanguage("nb-SJ", "Norwegian Bokmål (Svalbard and Jan Mayen)"); + public static readonly Language NepaliIndia = AddLanguage("ne-IN", "Nepali (India)"); + public static readonly Language NepaliNepal = AddLanguage("ne-NP", "Nepali (Nepal)"); + public static readonly Language DutchAruba = AddLanguage("nl-AW", "Dutch (Aruba)"); + public static readonly Language DutchBelgium = AddLanguage("nl-BE", "Dutch (Belgium)"); + public static readonly Language DutchBonaireSintEustatiusandSaba = AddLanguage("nl-BQ", "Dutch (Bonaire, Sint Eustatius and Saba)"); + public static readonly Language DutchCuraçao = AddLanguage("nl-CW", "Dutch (Curaçao)"); + public static readonly Language DutchNetherlands = AddLanguage("nl-NL", "Dutch (Netherlands)"); + public static readonly Language DutchSuriname = AddLanguage("nl-SR", "Dutch (Suriname)"); + public static readonly Language DutchSintMaarten = AddLanguage("nl-SX", "Dutch (Sint Maarten)"); + public static readonly Language OromoEthiopia = AddLanguage("om-ET", "Oromo (Ethiopia)"); + public static readonly Language OromoKenya = AddLanguage("om-KE", "Oromo (Kenya)"); + public static readonly Language PortugueseAngola = AddLanguage("pt-AO", "Portuguese (Angola)"); + public static readonly Language PortugueseBrazil = AddLanguage("pt-BR", "Portuguese (Brazil)"); + public static readonly Language PortugueseSwitzerland = AddLanguage("pt-CH", "Portuguese (Switzerland)"); + public static readonly Language PortugueseCaboVerde = AddLanguage("pt-CV", "Portuguese (Cabo Verde)"); + public static readonly Language PortugueseEquatorialGuinea = AddLanguage("pt-GQ", "Portuguese (Equatorial Guinea)"); + public static readonly Language PortugueseGuineaBissau = AddLanguage("pt-GW", "Portuguese (Guinea-Bissau)"); + public static readonly Language PortugueseLuxembourg = AddLanguage("pt-LU", "Portuguese (Luxembourg)"); + public static readonly Language PortugueseMacaoSAR = AddLanguage("pt-MO", "Portuguese (Macao SAR)"); + public static readonly Language PortugueseMozambique = AddLanguage("pt-MZ", "Portuguese (Mozambique)"); + public static readonly Language PortuguesePortugal = AddLanguage("pt-PT", "Portuguese (Portugal)"); + public static readonly Language PortugueseSãoToméandPríncipe = AddLanguage("pt-ST", "Portuguese (São Tomé and Príncipe)"); + public static readonly Language PortugueseTimorLeste = AddLanguage("pt-TL", "Portuguese (Timor-Leste)"); + public static readonly Language RomanianMoldova = AddLanguage("ro-MD", "Romanian (Moldova)"); + public static readonly Language RomanianRomania = AddLanguage("ro-RO", "Romanian (Romania)"); + public static readonly Language RussianBelarus = AddLanguage("ru-BY", "Russian (Belarus)"); + public static readonly Language RussianKyrgyzstan = AddLanguage("ru-KG", "Russian (Kyrgyzstan)"); + public static readonly Language RussianKazakhstan = AddLanguage("ru-KZ", "Russian (Kazakhstan)"); + public static readonly Language RussianMoldova = AddLanguage("ru-MD", "Russian (Moldova)"); + public static readonly Language RussianRussia = AddLanguage("ru-RU", "Russian (Russia)"); + public static readonly Language RussianUkraine = AddLanguage("ru-UA", "Russian (Ukraine)"); + public static readonly Language SamiNorthernFinland = AddLanguage("se-FI", "Sami, Northern (Finland)"); + public static readonly Language SamiNorthernNorway = AddLanguage("se-NO", "Sami, Northern (Norway)"); + public static readonly Language SamiNorthernSweden = AddLanguage("se-SE", "Sami, Northern (Sweden)"); + public static readonly Language SomaliDjibouti = AddLanguage("so-DJ", "Somali (Djibouti)"); + public static readonly Language SomaliEthiopia = AddLanguage("so-ET", "Somali (Ethiopia)"); + public static readonly Language SomaliKenya = AddLanguage("so-KE", "Somali (Kenya)"); + public static readonly Language SomaliSomalia = AddLanguage("so-SO", "Somali (Somalia)"); + public static readonly Language AlbanianAlbania = AddLanguage("sq-AL", "Albanian (Albania)"); + public static readonly Language AlbanianMacedoniaFYRO = AddLanguage("sq-MK", "Albanian (Macedonia, FYRO)"); + public static readonly Language AlbanianKosovo = AddLanguage("sq-XK", "Albanian (Kosovo)"); + public static readonly Language siSwatiSwaziland = AddLanguage("ss-SZ", "siSwati (Swaziland)"); + public static readonly Language siSwatiSouthAfrica = AddLanguage("ss-ZA", "siSwati (South Africa)"); + public static readonly Language SesothoLesotho = AddLanguage("st-LS", "Sesotho (Lesotho)"); + public static readonly Language SesothoSouthAfrica = AddLanguage("st-ZA", "Sesotho (South Africa)"); + public static readonly Language SwedishÅlandIslands = AddLanguage("sv-AX", "Swedish (Åland Islands)"); + public static readonly Language SwedishFinland = AddLanguage("sv-FI", "Swedish (Finland)"); + public static readonly Language SwedishSweden = AddLanguage("sv-SE", "Swedish (Sweden)"); + public static readonly Language KiswahiliCongoDRC = AddLanguage("sw-CD", "Kiswahili (Congo DRC)"); + public static readonly Language KiswahiliKenya = AddLanguage("sw-KE", "Kiswahili (Kenya)"); + public static readonly Language KiswahiliTanzania = AddLanguage("sw-TZ", "Kiswahili (Tanzania)"); + public static readonly Language KiswahiliUganda = AddLanguage("sw-UG", "Kiswahili (Uganda)"); + public static readonly Language TamilIndia = AddLanguage("ta-IN", "Tamil (India)"); + public static readonly Language TamilSriLanka = AddLanguage("ta-LK", "Tamil (Sri Lanka)"); + public static readonly Language TamilMalaysia = AddLanguage("ta-MY", "Tamil (Malaysia)"); + public static readonly Language TamilSingapore = AddLanguage("ta-SG", "Tamil (Singapore)"); + public static readonly Language TigrinyaEritrea = AddLanguage("ti-ER", "Tigrinya (Eritrea)"); + public static readonly Language TigrinyaEthiopia = AddLanguage("ti-ET", "Tigrinya (Ethiopia)"); + public static readonly Language SetswanaBotswana = AddLanguage("tn-BW", "Setswana (Botswana)"); + public static readonly Language SetswanaSouthAfrica = AddLanguage("tn-ZA", "Setswana (South Africa)"); + public static readonly Language TurkishCyprus = AddLanguage("tr-CY", "Turkish (Cyprus)"); + public static readonly Language TurkishTurkey = AddLanguage("tr-TR", "Turkish (Turkey)"); + public static readonly Language UrduIndia = AddLanguage("ur-IN", "Urdu (India)"); + public static readonly Language UrduPakistan = AddLanguage("ur-PK", "Urdu (Pakistan)"); + public static readonly Language YorubaBenin = AddLanguage("yo-BJ", "Yoruba (Benin)"); + public static readonly Language YorubaNigeria = AddLanguage("yo-NG", "Yoruba (Nigeria)"); + public static readonly Language ChineseSimplifiedChina = AddLanguage("zh-CN", "Chinese (Simplified, China)"); + public static readonly Language ChineseTraditionalHongKongSAR = AddLanguage("zh-HK", "Chinese (Traditional, Hong Kong SAR)"); + public static readonly Language ChineseTraditionalMacaoSAR = AddLanguage("zh-MO", "Chinese (Traditional, Macao SAR)"); + public static readonly Language ChineseSimplifiedSingapore = AddLanguage("zh-SG", "Chinese (Simplified, Singapore)"); + public static readonly Language ChineseTraditionalTaiwan = AddLanguage("zh-TW", "Chinese (Traditional, Taiwan)"); } } diff --git a/src/Squidex.Infrastructure/Log/FileChannel.cs b/src/Squidex.Infrastructure/Log/FileChannel.cs index 51ec006ab..c5d8d37f1 100644 --- a/src/Squidex.Infrastructure/Log/FileChannel.cs +++ b/src/Squidex.Infrastructure/Log/FileChannel.cs @@ -9,9 +9,11 @@ using Squidex.Infrastructure.Log.Internal; namespace Squidex.Infrastructure.Log { - public sealed class FileChannel : DisposableObjectBase, ILogChannel, IInitializable + public sealed class FileChannel : DisposableObjectBase, ILogChannel { private readonly FileLogProcessor processor; + private readonly object lockObject = new object(); + private bool isInitialized; public FileChannel(string path) { @@ -30,12 +32,20 @@ namespace Squidex.Infrastructure.Log public void Log(SemanticLogLevel logLevel, string message) { - processor.EnqueueMessage(new LogMessageEntry { Message = message }); - } + if (!isInitialized) + { + lock (lockObject) + { + if (!isInitialized) + { + processor.Initialize(); - public void Initialize() - { - processor.Connect(); + isInitialized = true; + } + } + } + + processor.EnqueueMessage(new LogMessageEntry { Message = message }); } } } diff --git a/src/Squidex.Infrastructure/Log/Internal/FileLogProcessor.cs b/src/Squidex.Infrastructure/Log/Internal/FileLogProcessor.cs index fa60d61f8..42495544d 100644 --- a/src/Squidex.Infrastructure/Log/Internal/FileLogProcessor.cs +++ b/src/Squidex.Infrastructure/Log/Internal/FileLogProcessor.cs @@ -20,6 +20,7 @@ namespace Squidex.Infrastructure.Log.Internal private readonly BlockingCollection messageQueue = new BlockingCollection(MaxQueuedMessages); private readonly Task outputTask; private readonly string path; + private StreamWriter writer; public FileLogProcessor(string path) { @@ -45,16 +46,33 @@ namespace Squidex.Infrastructure.Log.Internal throw; } } + finally + { + writer.Dispose(); + } } } - public void Connect() + public void Initialize() { var fileInfo = new FileInfo(path); + try + { + if (!fileInfo.Directory.Exists) + { + fileInfo.Directory.Create(); + } - if (!fileInfo.Directory.Exists) + var fs = new FileStream(fileInfo.FullName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite); + + writer = new StreamWriter(fs, Encoding.UTF8); + writer.AutoFlush = true; + + writer.WriteLine($"--- Started Logging {DateTime.UtcNow} ---", 1); + } + catch (Exception ex) { - throw new ConfigurationException($"Log directory '{fileInfo.Directory.FullName}' does not exist."); + throw new ConfigurationException($"Log directory '{fileInfo.Directory.FullName}' does not exist or cannot be created.", ex); } } @@ -71,8 +89,7 @@ namespace Squidex.Infrastructure.Log.Internal { try { - File.AppendAllText(path, entry.Message + Environment.NewLine, Encoding.UTF8); - + writer.WriteLine(entry.Message); break; } catch (Exception ex) diff --git a/src/Squidex.Infrastructure/Orleans/InitializerStartup.cs b/src/Squidex.Infrastructure/Orleans/InitializerStartup.cs new file mode 100644 index 000000000..848afcadf --- /dev/null +++ b/src/Squidex.Infrastructure/Orleans/InitializerStartup.cs @@ -0,0 +1,40 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orleans.Runtime; +using Squidex.Infrastructure.Log; + +namespace Squidex.Infrastructure.Orleans +{ + public sealed class InitializerStartup : IStartupTask + { + private readonly IEnumerable targets; + private readonly ISemanticLog log; + + public InitializerStartup(IEnumerable targets, ISemanticLog log) + { + Guard.NotNull(targets, nameof(targets)); + + this.targets = targets; + + this.log = log; + } + + public async Task Execute(CancellationToken cancellationToken) + { + foreach (var target in targets) + { + await target.InitializeAsync(cancellationToken); + + log?.LogInformation(w => w.WriteProperty("siloInitializedSystem", target.GetType().Name)); + } + } + } +} diff --git a/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj b/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj index e39741428..11d4cf7ba 100644 --- a/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj +++ b/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj @@ -11,12 +11,12 @@ - + all runtime; build; native; contentfiles; analyzers - - + + @@ -25,7 +25,7 @@ - + diff --git a/src/Squidex/AppServices.cs b/src/Squidex/AppServices.cs index 99d77a706..3e5cc0f53 100644 --- a/src/Squidex/AppServices.cs +++ b/src/Squidex/AppServices.cs @@ -14,6 +14,8 @@ using Squidex.Config; using Squidex.Config.Authentication; using Squidex.Config.Domain; using Squidex.Config.Web; +using Squidex.Domain.Apps.Entities.Assets; +using Squidex.Domain.Apps.Entities.Contents; using Squidex.Extensions.Actions.Twitter; using Squidex.Infrastructure.Commands; @@ -44,9 +46,12 @@ namespace Squidex services.AddMySwaggerSettings(); services.AddMySubscriptionServices(config); + services.Configure( + config.GetSection("contents")); + services.Configure( + config.GetSection("assets")); services.Configure( config.GetSection("mode")); - services.Configure( config.GetSection("twitter")); diff --git a/src/Squidex/Areas/Api/Config/Swagger/SwaggerExtensions.cs b/src/Squidex/Areas/Api/Config/Swagger/SwaggerExtensions.cs index 1cdea31b5..07e0f2c6f 100644 --- a/src/Squidex/Areas/Api/Config/Swagger/SwaggerExtensions.cs +++ b/src/Squidex/Areas/Api/Config/Swagger/SwaggerExtensions.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Reflection; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -20,7 +19,7 @@ namespace Squidex.Areas.Api.Config.Swagger { var urlOptions = app.ApplicationServices.GetService>().Value; - app.UseSwagger(typeof(SwaggerExtensions).GetTypeInfo().Assembly, settings => + app.UseSwaggerWithApiExplorer(settings => { settings.AddAssetODataParams(); settings.ConfigureNames(); diff --git a/src/Squidex/Areas/Api/Config/Swagger/SwaggerServices.cs b/src/Squidex/Areas/Api/Config/Swagger/SwaggerServices.cs index e4367b418..44e95ba0d 100644 --- a/src/Squidex/Areas/Api/Config/Swagger/SwaggerServices.cs +++ b/src/Squidex/Areas/Api/Config/Swagger/SwaggerServices.cs @@ -106,7 +106,6 @@ namespace Squidex.Areas.Api.Config.Swagger settings.GeneratorSettings.DocumentProcessors.Add(new RuleActionProcessor()); settings.GeneratorSettings.DocumentProcessors.Add(new XmlTagProcessor()); - settings.GeneratorSettings.OperationProcessors.Add(new XmlTagProcessor()); settings.GeneratorSettings.OperationProcessors.Add(new XmlResponseTypesProcessor()); return settings; diff --git a/src/Squidex/Areas/Api/Config/Swagger/XmlResponseTypesProcessor.cs b/src/Squidex/Areas/Api/Config/Swagger/XmlResponseTypesProcessor.cs index aa3598de7..ebab2b885 100644 --- a/src/Squidex/Areas/Api/Config/Swagger/XmlResponseTypesProcessor.cs +++ b/src/Squidex/Areas/Api/Config/Swagger/XmlResponseTypesProcessor.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Text.RegularExpressions; using System.Threading.Tasks; using NJsonSchema.Infrastructure; @@ -43,7 +42,7 @@ namespace Squidex.Areas.Api.Config.Swagger response.Description = match.Groups["Description"].Value; - if (string.Equals(statusCode, "200", StringComparison.OrdinalIgnoreCase)) + if (statusCode == "200" || statusCode == "204") { hasOkResponse = true; } @@ -72,8 +71,7 @@ namespace Squidex.Areas.Api.Config.Swagger private static void RemoveOkResponse(SwaggerOperation operation) { if (operation.Responses.TryGetValue("200", out var response) && - response.Description != null && - response.Description.Contains("=>")) + response.Description?.Contains("=>") == true) { operation.Responses.Remove("200"); } diff --git a/src/Squidex/Areas/Api/Config/Swagger/XmlTagProcessor.cs b/src/Squidex/Areas/Api/Config/Swagger/XmlTagProcessor.cs index 6e63a03fb..42da7bfe4 100644 --- a/src/Squidex/Areas/Api/Config/Swagger/XmlTagProcessor.cs +++ b/src/Squidex/Areas/Api/Config/Swagger/XmlTagProcessor.cs @@ -16,7 +16,7 @@ using Squidex.Infrastructure.Tasks; namespace Squidex.Areas.Api.Config.Swagger { - public sealed class XmlTagProcessor : IOperationProcessor, IDocumentProcessor + public sealed class XmlTagProcessor : IDocumentProcessor { public Task ProcessAsync(DocumentProcessorContext context) { @@ -47,18 +47,5 @@ namespace Squidex.Areas.Api.Config.Swagger return TaskHelper.Done; } - - public Task ProcessAsync(OperationProcessorContext context) - { - var tagAttribute = context.MethodInfo.DeclaringType.GetTypeInfo().GetCustomAttribute(); - - if (tagAttribute != null) - { - context.OperationDescription.Operation.Tags.Clear(); - context.OperationDescription.Operation.Tags.Add(tagAttribute.Name); - } - - return TaskHelper.True; - } } } diff --git a/src/Squidex/Areas/Api/Controllers/Apps/AppClientsController.cs b/src/Squidex/Areas/Api/Controllers/Apps/AppClientsController.cs index dff6510a1..1257d0e43 100644 --- a/src/Squidex/Areas/Api/Controllers/Apps/AppClientsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Apps/AppClientsController.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Areas.Api.Controllers.Apps.Models; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Infrastructure.Commands; @@ -23,7 +22,7 @@ namespace Squidex.Areas.Api.Controllers.Apps [ApiExceptionFilter] [AppApi] [MustBeAppEditor] - [SwaggerTag(nameof(Apps))] + [ApiExplorerSettings(GroupName = nameof(Apps))] public sealed class AppClientsController : ApiController { public AppClientsController(ICommandBus commandBus) diff --git a/src/Squidex/Areas/Api/Controllers/Apps/AppContributorsController.cs b/src/Squidex/Areas/Api/Controllers/Apps/AppContributorsController.cs index edd1a33f1..4fcaa1a4c 100644 --- a/src/Squidex/Areas/Api/Controllers/Apps/AppContributorsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Apps/AppContributorsController.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Areas.Api.Controllers.Apps.Models; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Services; @@ -23,7 +22,7 @@ namespace Squidex.Areas.Api.Controllers.Apps [ApiExceptionFilter] [AppApi] [MustBeAppOwner] - [SwaggerTag(nameof(Apps))] + [ApiExplorerSettings(GroupName = nameof(Apps))] public sealed class AppContributorsController : ApiController { private readonly IAppPlansProvider appPlansProvider; diff --git a/src/Squidex/Areas/Api/Controllers/Apps/AppLanguagesController.cs b/src/Squidex/Areas/Api/Controllers/Apps/AppLanguagesController.cs index a2bcfdab4..b075f9968 100644 --- a/src/Squidex/Areas/Api/Controllers/Apps/AppLanguagesController.cs +++ b/src/Squidex/Areas/Api/Controllers/Apps/AppLanguagesController.cs @@ -8,7 +8,6 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Areas.Api.Controllers.Apps.Models; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Infrastructure; @@ -23,7 +22,7 @@ namespace Squidex.Areas.Api.Controllers.Apps [ApiAuthorize] [ApiExceptionFilter] [AppApi] - [SwaggerTag(nameof(Apps))] + [ApiExplorerSettings(GroupName = nameof(Apps))] public sealed class AppLanguagesController : ApiController { public AppLanguagesController(ICommandBus commandBus) diff --git a/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs b/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs index c1cb2c82a..a57c8bff2 100644 --- a/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Apps/AppPatternsController.cs @@ -9,7 +9,6 @@ using System; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Areas.Api.Controllers.Apps.Models; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Infrastructure.Commands; @@ -24,7 +23,7 @@ namespace Squidex.Areas.Api.Controllers.Apps [MustBeAppDeveloper] [ApiExceptionFilter] [AppApi] - [SwaggerTag(nameof(Apps))] + [ApiExplorerSettings(GroupName = nameof(Apps))] public sealed class AppPatternsController : ApiController { public AppPatternsController(ICommandBus commandBus) @@ -104,7 +103,7 @@ namespace Squidex.Areas.Api.Controllers.Apps } /// - /// Revoke an app client. + /// Delete an existing app pattern. /// /// The name of the app. /// The id of the pattern to be deleted. diff --git a/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs b/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs index 21ec8ad64..9030c316a 100644 --- a/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs @@ -9,7 +9,6 @@ using System; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Areas.Api.Controllers.Apps.Models; using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps.Commands; @@ -25,7 +24,7 @@ namespace Squidex.Areas.Api.Controllers.Apps /// [ApiAuthorize] [ApiExceptionFilter] - [SwaggerTag(nameof(Apps))] + [ApiExplorerSettings(GroupName = nameof(Apps))] public sealed class AppsController : ApiController { private readonly IAppProvider appProvider; diff --git a/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs b/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs index d443cc17a..bd91cfa81 100644 --- a/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs +++ b/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs @@ -9,7 +9,6 @@ using System; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Infrastructure.Assets; using Squidex.Infrastructure.Commands; @@ -24,7 +23,7 @@ namespace Squidex.Areas.Api.Controllers.Assets /// [ApiExceptionFilter] [AppApi] - [SwaggerTag(nameof(Assets))] + [ApiExplorerSettings(GroupName = nameof(Assets))] public sealed class AssetContentController : ApiController { private readonly IAssetStore assetStore; diff --git a/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs b/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs index ece13037b..8008cb779 100644 --- a/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs @@ -33,7 +33,7 @@ namespace Squidex.Areas.Api.Controllers.Assets [ApiAuthorize] [ApiExceptionFilter] [AppApi] - [SwaggerTag(nameof(Assets))] + [ApiExplorerSettings(GroupName = nameof(Assets))] public sealed class AssetsController : ApiController { private readonly IAssetQueryService assetQuery; diff --git a/src/Squidex/Areas/Api/Controllers/Backups/BackupContentController.cs b/src/Squidex/Areas/Api/Controllers/Backups/BackupContentController.cs index 0db366eef..09ddfe0ed 100644 --- a/src/Squidex/Areas/Api/Controllers/Backups/BackupContentController.cs +++ b/src/Squidex/Areas/Api/Controllers/Backups/BackupContentController.cs @@ -7,7 +7,6 @@ using System; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Infrastructure.Assets; using Squidex.Infrastructure.Commands; using Squidex.Pipeline; @@ -19,7 +18,7 @@ namespace Squidex.Areas.Api.Controllers.Backups /// [ApiExceptionFilter] [AppApi] - [SwaggerTag(nameof(Backups))] + [ApiExplorerSettings(GroupName = nameof(Backups))] public class BackupContentController : ApiController { private readonly IAssetStore assetStore; diff --git a/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs b/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs index dc05949d1..2b8fa73e9 100644 --- a/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs @@ -10,7 +10,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Orleans; using Squidex.Areas.Api.Controllers.Backups.Models; using Squidex.Domain.Apps.Entities.Backup; @@ -27,7 +26,7 @@ namespace Squidex.Areas.Api.Controllers.Backups [ApiExceptionFilter] [AppApi] [MustBeAppOwner] - [SwaggerTag(nameof(Backups))] + [ApiExplorerSettings(GroupName = nameof(Backups))] public class BackupsController : ApiController { private readonly IGrainFactory grainFactory; diff --git a/src/Squidex/Areas/Api/Controllers/History/HistoryController.cs b/src/Squidex/Areas/Api/Controllers/History/HistoryController.cs index c908e8888..75a55c06e 100644 --- a/src/Squidex/Areas/Api/Controllers/History/HistoryController.cs +++ b/src/Squidex/Areas/Api/Controllers/History/HistoryController.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Areas.Api.Controllers.History.Models; using Squidex.Domain.Apps.Entities.History.Repositories; using Squidex.Infrastructure.Commands; @@ -23,7 +22,7 @@ namespace Squidex.Areas.Api.Controllers.History [ApiExceptionFilter] [AppApi] [MustBeAppEditor] - [SwaggerTag(nameof(History))] + [ApiExplorerSettings(GroupName = nameof(History))] public sealed class HistoryController : ApiController { private readonly IHistoryEventRepository historyEventRepository; diff --git a/src/Squidex/Areas/Api/Controllers/Languages/LanguagesController.cs b/src/Squidex/Areas/Api/Controllers/Languages/LanguagesController.cs index e36ef7dc0..7e8fea639 100644 --- a/src/Squidex/Areas/Api/Controllers/Languages/LanguagesController.cs +++ b/src/Squidex/Areas/Api/Controllers/Languages/LanguagesController.cs @@ -7,7 +7,6 @@ using System.Linq; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Pipeline; @@ -19,7 +18,7 @@ namespace Squidex.Areas.Api.Controllers.Languages /// [ApiAuthorize] [ApiExceptionFilter] - [SwaggerTag(nameof(Languages))] + [ApiExplorerSettings(GroupName = nameof(Languages))] public sealed class LanguagesController : ApiController { public LanguagesController(ICommandBus commandBus) diff --git a/src/Squidex/Areas/Api/Controllers/Ping/PingController.cs b/src/Squidex/Areas/Api/Controllers/Ping/PingController.cs index 9b9014a8b..8df454a9f 100644 --- a/src/Squidex/Areas/Api/Controllers/Ping/PingController.cs +++ b/src/Squidex/Areas/Api/Controllers/Ping/PingController.cs @@ -6,7 +6,6 @@ // ========================================================================== using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Infrastructure.Commands; using Squidex.Pipeline; @@ -15,11 +14,8 @@ namespace Squidex.Areas.Api.Controllers.Ping /// /// Makes a ping request. /// - [ApiAuthorize] [ApiExceptionFilter] - [AppApi] - [MustBeAppReader] - [SwaggerTag(nameof(Ping))] + [ApiExplorerSettings(GroupName = nameof(Ping))] public sealed class PingController : ApiController { public PingController(ICommandBus commandBus) @@ -27,6 +23,22 @@ namespace Squidex.Areas.Api.Controllers.Ping { } + /// + /// Get ping status of the API. + /// + /// + /// 204 => Service ping successful. + /// + /// + /// Can be used to test, if the Squidex API is alive and responding. + /// + [HttpGet] + [Route("ping/")] + public IActionResult GetPing() + { + return NoContent(); + } + /// /// Get ping status. /// @@ -37,9 +49,12 @@ namespace Squidex.Areas.Api.Controllers.Ping /// /// Can be used to test, if the Squidex API is alive and responding. /// + [ApiAuthorize] + [ApiCosts(0)] + [AppApi] + [MustBeAppReader] [HttpGet] [Route("ping/{app}/")] - [ApiCosts(0)] public IActionResult GetPing(string app) { return NoContent(); diff --git a/src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs b/src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs index 2fc575f5e..5998e0b12 100644 --- a/src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs +++ b/src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Areas.Api.Controllers.Plans.Models; using Squidex.Domain.Apps.Entities.Apps.Services; using Squidex.Infrastructure.Commands; @@ -21,7 +20,7 @@ namespace Squidex.Areas.Api.Controllers.Plans [ApiAuthorize] [ApiExceptionFilter] [AppApi] - [SwaggerTag(nameof(Plans))] + [ApiExplorerSettings(GroupName = nameof(Plans))] public sealed class AppPlansController : ApiController { private readonly IAppPlansProvider appPlansProvider; @@ -66,8 +65,7 @@ namespace Squidex.Areas.Api.Controllers.Plans /// The name of the app. /// Plan object that needs to be changed. /// - /// 201 => Redirected to checkout page. - /// 204 => Plan changed. + /// 200 => Plan changed or redirect url returned. /// 400 => Plan not owned by user. /// 404 => App not found. /// diff --git a/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs b/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs index 1170416ce..28ee52be9 100644 --- a/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs +++ b/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs @@ -11,7 +11,6 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using NodaTime; -using NSwag.Annotations; using Squidex.Areas.Api.Controllers.Rules.Models; using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Rules.Commands; @@ -29,7 +28,7 @@ namespace Squidex.Areas.Api.Controllers.Rules [ApiAuthorize] [ApiExceptionFilter] [AppApi] - [SwaggerTag(nameof(Rules))] + [ApiExplorerSettings(GroupName = nameof(Rules))] [MustBeAppDeveloper] public sealed class RulesController : ApiController { diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs b/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs index 0299cee87..a57e6a5a8 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Areas.Api.Controllers.Schemas.Models; using Squidex.Domain.Apps.Entities.Schemas.Commands; using Squidex.Infrastructure.Commands; @@ -22,7 +21,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas [ApiExceptionFilter] [AppApi] [MustBeAppDeveloper] - [SwaggerTag(nameof(Schemas))] + [ApiExplorerSettings(GroupName = nameof(Schemas))] public sealed class SchemaFieldsController : ApiController { public SchemaFieldsController(ICommandBus commandBus) diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs b/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs index 16ad59a2d..ed2490360 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/SchemasController.cs @@ -9,7 +9,6 @@ using System; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Areas.Api.Controllers.Schemas.Models; using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Schemas; @@ -25,7 +24,7 @@ namespace Squidex.Areas.Api.Controllers.Schemas [ApiAuthorize] [ApiExceptionFilter] [AppApi] - [SwaggerTag(nameof(Schemas))] + [ApiExplorerSettings(GroupName = nameof(Schemas))] public sealed class SchemasController : ApiController { private readonly IAppProvider appProvider; diff --git a/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs b/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs index 30eff2da8..0f8f3b6a3 100644 --- a/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs +++ b/src/Squidex/Areas/Api/Controllers/Statistics/UsagesController.cs @@ -10,7 +10,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Areas.Api.Controllers.Statistics.Models; using Squidex.Domain.Apps.Entities.Apps.Services; using Squidex.Domain.Apps.Entities.Assets.Repositories; @@ -27,7 +26,7 @@ namespace Squidex.Areas.Api.Controllers.Statistics [ApiExceptionFilter] [AppApi] [MustBeAppEditor] - [SwaggerTag(nameof(Statistics))] + [ApiExplorerSettings(GroupName = nameof(Statistics))] public sealed class UsagesController : ApiController { private readonly IUsageTracker usageTracker; diff --git a/src/Squidex/Areas/Api/Controllers/UI/UIController.cs b/src/Squidex/Areas/Api/Controllers/UI/UIController.cs index b15859cfc..ef6e2d51d 100644 --- a/src/Squidex/Areas/Api/Controllers/UI/UIController.cs +++ b/src/Squidex/Areas/Api/Controllers/UI/UIController.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; -using NSwag.Annotations; using Orleans; using Squidex.Areas.Api.Controllers.UI.Models; using Squidex.Config; @@ -25,7 +24,7 @@ namespace Squidex.Areas.Api.Controllers.UI [ApiAuthorize] [ApiExceptionFilter] [AppApi] - [SwaggerTag(nameof(UI))] + [ApiExplorerSettings(GroupName = nameof(UI))] public sealed class UIController : ApiController { private readonly MyUIOptions uiOptions; diff --git a/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs b/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs index 607f2047c..48660c06d 100644 --- a/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs +++ b/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs @@ -12,7 +12,6 @@ using System.Net.Http; using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Squidex.Areas.Api.Controllers.Users.Models; using Squidex.Domain.Users; using Squidex.Infrastructure.Commands; @@ -26,7 +25,7 @@ namespace Squidex.Areas.Api.Controllers.Users /// Readonly API to retrieve information about squidex users. /// [ApiExceptionFilter] - [SwaggerTag(nameof(Users))] + [ApiExplorerSettings(GroupName = nameof(Users))] public sealed class UsersController : ApiController { private static readonly byte[] AvatarBytes; diff --git a/src/Squidex/Config/Domain/EntitiesServices.cs b/src/Squidex/Config/Domain/EntitiesServices.cs index 739b068f9..b3f72de7c 100644 --- a/src/Squidex/Config/Domain/EntitiesServices.cs +++ b/src/Squidex/Config/Domain/EntitiesServices.cs @@ -65,9 +65,15 @@ namespace Squidex.Config.Domain services.AddSingletonAs() .As(); + services.AddSingletonAs(c => c.GetRequiredService>().Value) + .AsSelf(); + services.AddSingletonAs() .As(); + services.AddSingletonAs(c => c.GetRequiredService>().Value) + .AsSelf(); + services.AddSingletonAs() .As(); diff --git a/src/Squidex/Config/Domain/LoggingExtensions.cs b/src/Squidex/Config/Domain/LoggingExtensions.cs index 65dbfe410..0ee6c0844 100644 --- a/src/Squidex/Config/Domain/LoggingExtensions.cs +++ b/src/Squidex/Config/Domain/LoggingExtensions.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -19,15 +20,20 @@ namespace Squidex.Config.Domain { var log = services.GetRequiredService(); - var config = services.GetRequiredService(); - log.LogInformation(w => w .WriteProperty("message", "Application started") .WriteObject("environment", c => { - foreach (var kvp in config.AsEnumerable().Where(kvp => kvp.Value != null)) + var config = services.GetRequiredService(); + + var logged = new HashSet(StringComparer.OrdinalIgnoreCase); + + foreach (var kvp in config.AsEnumerable().Where(kvp => kvp.Value != null).Select(x => new { Key = x.Key.ToLowerInvariant(), x.Value }).OrderBy(x => x.Key)) { - c.WriteProperty(kvp.Key, kvp.Value); + if (logged.Add(kvp.Key)) + { + c.WriteProperty(kvp.Key, kvp.Value); + } } })); } diff --git a/src/Squidex/Config/Domain/LoggingServices.cs b/src/Squidex/Config/Domain/LoggingServices.cs index 486c29dff..a00ad2db2 100644 --- a/src/Squidex/Config/Domain/LoggingServices.cs +++ b/src/Squidex/Config/Domain/LoggingServices.cs @@ -9,7 +9,6 @@ using System; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; -using Squidex.Infrastructure; using Squidex.Infrastructure.Log; using Squidex.Pipeline; @@ -38,8 +37,7 @@ namespace Squidex.Config.Domain if (!string.IsNullOrWhiteSpace(loggingFile)) { services.AddSingletonAs(file ?? (file = new FileChannel(loggingFile))) - .As() - .As(); + .As(); } var useColors = config.GetValue("logging:colors"); diff --git a/src/Squidex/Config/Domain/SystemExtensions.cs b/src/Squidex/Config/Domain/SystemExtensions.cs index 29e985d3e..87cb4654e 100644 --- a/src/Squidex/Config/Domain/SystemExtensions.cs +++ b/src/Squidex/Config/Domain/SystemExtensions.cs @@ -5,41 +5,64 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; -using Microsoft.Extensions.DependencyInjection; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; using Squidex.Infrastructure; +using Squidex.Infrastructure.Log; using Squidex.Infrastructure.Migrations; namespace Squidex.Config.Domain { public static class SystemExtensions { - public static void RunInitialization(this IServiceProvider services) + public sealed class InitializeHostedService : IHostedService { - var systems = services.GetRequiredService>(); + private readonly IEnumerable targets; + private readonly ISemanticLog log; - foreach (var system in systems) + public InitializeHostedService(IEnumerable targets, ISemanticLog log) { - system.Initialize(); + this.targets = targets; + + this.log = log; } - } - public static void RunRunnables(this IServiceProvider services) - { - var systems = services.GetRequiredService>(); + public async Task StartAsync(CancellationToken cancellationToken) + { + foreach (var target in targets) + { + await target.InitializeAsync(cancellationToken); - foreach (var system in systems) + log.LogInformation(w => w.WriteProperty("initializedSystem", target.GetType().Name)); + } + } + + public Task StopAsync(CancellationToken cancellationToken) { - system.Run(); + return Task.CompletedTask; } } - public static void RunMigrate(this IServiceProvider services) + public sealed class MigratorHostedService : IHostedService { - var migrator = services.GetRequiredService(); + private readonly Migrator migrator; + + public MigratorHostedService(Migrator migrator) + { + this.migrator = migrator; + } - migrator.MigrateAsync().Wait(); + public Task StartAsync(CancellationToken cancellationToken) + { + return migrator.MigrateAsync(); + } + + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } } } } diff --git a/src/Squidex/Config/Logging.cs b/src/Squidex/Config/Logging.cs index ecd1c0859..bea1bbd60 100644 --- a/src/Squidex/Config/Logging.cs +++ b/src/Squidex/Config/Logging.cs @@ -16,6 +16,16 @@ namespace Squidex.Config { builder.AddFilter((category, level) => { + if (category.StartsWith("Orleans.Runtime.NoOpHostEnvironmentStatistics", StringComparison.OrdinalIgnoreCase)) + { + return level >= LogLevel.Error; + } + + if (category.StartsWith("Orleans.Runtime.Scheduler", StringComparison.OrdinalIgnoreCase)) + { + return level >= LogLevel.Error; + } + if (category.StartsWith("Orleans.", StringComparison.OrdinalIgnoreCase)) { return level >= LogLevel.Warning; diff --git a/src/Squidex/Config/Orleans/OrleansServices.cs b/src/Squidex/Config/Orleans/OrleansServices.cs index a75936ad8..cb32bced3 100644 --- a/src/Squidex/Config/Orleans/OrleansServices.cs +++ b/src/Squidex/Config/Orleans/OrleansServices.cs @@ -6,8 +6,8 @@ // ========================================================================== using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Orleans; -using Squidex.Infrastructure; namespace Squidex.Config.Orleans { @@ -16,7 +16,7 @@ namespace Squidex.Config.Orleans public static void AddOrleansSilo(this IServiceCollection services) { services.AddSingletonAs() - .As() + .As() .AsSelf(); services.AddServicesForSelfHostedDashboard(null, options => @@ -24,7 +24,7 @@ namespace Squidex.Config.Orleans options.HideTrace = true; }); - services.AddSingletonAs(c => c.GetRequiredService().Client) + services.AddSingletonAs(c => c.GetRequiredService()) .As(); services.AddSingletonAs(c => c.GetRequiredService().Client) diff --git a/src/Squidex/Config/Orleans/SiloWrapper.cs b/src/Squidex/Config/Orleans/SiloWrapper.cs index 62139bb06..4a1150289 100644 --- a/src/Squidex/Config/Orleans/SiloWrapper.cs +++ b/src/Squidex/Config/Orleans/SiloWrapper.cs @@ -7,14 +7,15 @@ using System; using System.Net; +using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Orleans; using Orleans.Configuration; using Orleans.Hosting; -using Squidex.Config.Domain; using Squidex.Domain.Apps.Entities.Contents; using Squidex.Domain.Apps.Entities.Rules; using Squidex.Infrastructure; @@ -22,14 +23,14 @@ using Squidex.Infrastructure.EventSourcing.Grains; using Squidex.Infrastructure.Log; using Squidex.Infrastructure.Log.Adapter; using Squidex.Infrastructure.Orleans; -using Squidex.Infrastructure.Tasks; namespace Squidex.Config.Orleans { - public sealed class SiloWrapper : DisposableObjectBase, IInitializable, IDisposable + public sealed class SiloWrapper : IHostedService { - private readonly Lazy silo; + private readonly Lazy lazySilo; private readonly ISemanticLog log; + private bool isStopping; internal sealed class Source : IConfigurationSource { @@ -48,28 +49,23 @@ namespace Squidex.Config.Orleans public IClusterClient Client { - get { return silo.Value.Services.GetRequiredService(); } + get { return lazySilo.Value.Services.GetRequiredService(); } } - public SiloWrapper(IConfiguration config, ISemanticLog log) + public SiloWrapper(IConfiguration config, ISemanticLog log, IApplicationLifetime lifetime) { this.log = log; - silo = new Lazy(() => + lazySilo = new Lazy(() => { var hostBuilder = new SiloHostBuilder() .UseDashboard(options => options.HostSelf = false) .EnableDirectClient() .AddIncomingGrainCallFilter() + .AddStartupTask() .AddStartupTask>() .AddStartupTask>() .AddStartupTask>() - .AddStartupTask((services, ct) => - { - services.RunInitialization(); - - return TaskHelper.Done; - }) .Configure(options => { options.Configure(); @@ -141,16 +137,26 @@ namespace Squidex.Config.Orleans } }); - return hostBuilder.Build(); + var silo = hostBuilder.Build(); + + silo.Stopped.ContinueWith(x => + { + if (!isStopping) + { + lifetime.StopApplication(); + } + }); + + return silo; }); } - public void Initialize() + public async Task StartAsync(CancellationToken cancellationToken) { var watch = ValueStopwatch.StartNew(); try { - silo.Value.StartAsync().Wait(); + await lazySilo.Value.StartAsync(cancellationToken); } finally { @@ -162,14 +168,13 @@ namespace Squidex.Config.Orleans } } - protected override void DisposeObject(bool disposing) + public async Task StopAsync(CancellationToken cancellationToken) { - if (disposing) + if (lazySilo.IsValueCreated) { - if (silo.IsValueCreated) - { - Task.Run(() => silo.Value.StopAsync()).Wait(); - } + isStopping = true; + + await lazySilo.Value.StopAsync(cancellationToken); } } } diff --git a/src/Squidex/Squidex.csproj b/src/Squidex/Squidex.csproj index c6c9c710c..536d85ab3 100644 --- a/src/Squidex/Squidex.csproj +++ b/src/Squidex/Squidex.csproj @@ -54,36 +54,36 @@ - + - + - + - - - - + + + + - + - + - + diff --git a/src/Squidex/WebStartup.cs b/src/Squidex/WebStartup.cs index 815d183fd..119a69928 100644 --- a/src/Squidex/WebStartup.cs +++ b/src/Squidex/WebStartup.cs @@ -32,14 +32,14 @@ namespace Squidex { services.AddOrleansSilo(); services.AddAppServices(configuration); + + services.AddHostedService(); + services.AddHostedService(); } public void Configure(IApplicationBuilder app) { app.ApplicationServices.LogConfiguration(); - app.ApplicationServices.RunInitialization(); - app.ApplicationServices.RunMigrate(); - app.ApplicationServices.RunRunnables(); app.UseMyLocalCache(); app.UseMyCors(); diff --git a/src/Squidex/app/features/administration/guards/user-must-exist.guard.ts b/src/Squidex/app/features/administration/guards/user-must-exist.guard.ts index db67514f9..63fc2bba1 100644 --- a/src/Squidex/app/features/administration/guards/user-must-exist.guard.ts +++ b/src/Squidex/app/features/administration/guards/user-must-exist.guard.ts @@ -32,7 +32,7 @@ export class UserMustExistGuard implements CanActivate { this.router.navigate(['/404']); } }), - map(u => u !== null)); + map(u => !!u)); return result; } diff --git a/src/Squidex/app/features/administration/pages/event-consumers/event-consumers-page.component.ts b/src/Squidex/app/features/administration/pages/event-consumers/event-consumers-page.component.ts index 30161a18b..a8df38179 100644 --- a/src/Squidex/app/features/administration/pages/event-consumers/event-consumers-page.component.ts +++ b/src/Squidex/app/features/administration/pages/event-consumers/event-consumers-page.component.ts @@ -38,8 +38,7 @@ export class EventConsumersPageComponent implements OnDestroy, OnInit { this.eventConsumersState.load(false, true).pipe(onErrorResumeNext()).subscribe(); this.timerSubscription = - timer(2000, 2000).pipe( - switchMap(x => this.eventConsumersState.load(true, true)), onErrorResumeNext()) + timer(2000, 2000).pipe(switchMap(x => this.eventConsumersState.load(true, true)), onErrorResumeNext()) .subscribe(); } diff --git a/src/Squidex/app/features/administration/pages/restore/restore-page.component.ts b/src/Squidex/app/features/administration/pages/restore/restore-page.component.ts index fa8977ccf..32884a7d2 100644 --- a/src/Squidex/app/features/administration/pages/restore/restore-page.component.ts +++ b/src/Squidex/app/features/administration/pages/restore/restore-page.component.ts @@ -8,7 +8,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { FormBuilder } from '@angular/forms'; import { Subscription, timer } from 'rxjs'; -import { switchMap } from 'rxjs/operators'; +import { filter, switchMap } from 'rxjs/operators'; import { AuthService, @@ -43,11 +43,9 @@ export class RestorePageComponent implements OnDestroy, OnInit { public ngOnInit() { this.timerSubscription = - timer(0, 2000).pipe(switchMap(() => this.backupsService.getRestore())) + timer(0, 2000).pipe(switchMap(() => this.backupsService.getRestore()), filter(x => !!x)) .subscribe(dto => { - if (dto !== null) { - this.restoreJob = dto; - } + this.restoreJob = dto!; }); } diff --git a/src/Squidex/app/features/assets/pages/assets-page.component.html b/src/Squidex/app/features/assets/pages/assets-page.component.html index 594f6220c..4a6d7cc55 100644 --- a/src/Squidex/app/features/assets/pages/assets-page.component.html +++ b/src/Squidex/app/features/assets/pages/assets-page.component.html @@ -34,18 +34,30 @@ +
+
+ + +
+
- +