diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs index c58263cb1..99d62bd4e 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs @@ -37,12 +37,12 @@ namespace Squidex.Domain.Apps.Core.Schemas } public ArrayField(long id, string name, Partitioning partitioning, ArrayFieldProperties properties = null, IFieldSettings settings = null) - : base(id, name, partitioning, properties) + : base(id, name, partitioning, properties, settings) { } public ArrayField(long id, string name, Partitioning partitioning, NestedField[] fields, ArrayFieldProperties properties = null, IFieldSettings settings = null) - : this(id, name, partitioning, properties) + : this(id, name, partitioning, properties, settings) { Guard.NotNull(fields, nameof(fields)); diff --git a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs index 3e865aeea..d09841b55 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Schemas/FieldCollection.cs @@ -61,7 +61,7 @@ namespace Squidex.Domain.Apps.Core.Schemas } else { - fieldsByName = fieldsOrdered.ToDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase); + fieldsByName = fieldsOrdered.ToDictionary(x => x.Name); } } diff --git a/src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SchemaSynchronizer.cs b/src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SchemaSynchronizer.cs index cebdfbf99..dc889f26b 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SchemaSynchronizer.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/EventSynchronization/SchemaSynchronizer.cs @@ -95,7 +95,7 @@ namespace Squidex.Domain.Apps.Core.EventSynchronization { foreach (var sourceField in source.Ordered) { - if (!target.ByName.TryGetValue(sourceField.Name, out var targetField)) + if (!target.ByName.TryGetValue(sourceField.Name, out _)) { var id = sourceField.NamedId(); @@ -184,7 +184,7 @@ namespace Squidex.Domain.Apps.Core.EventSynchronization if ((sourceField == null || sourceField is IArrayField) && targetField is IArrayField targetArrayField) { - var fields = (sourceField as IArrayField)?.FieldCollection ?? FieldCollection.Empty; + var fields = ((IArrayField)sourceField)?.FieldCollection ?? FieldCollection.Empty; var events = SyncFields(fields, targetArrayField.FieldCollection, serializer, idGenerator, id, options); diff --git a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs index a1f5e3b7b..835e3125a 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs @@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules return null; } - if (!(@event.Payload is AppEvent appEvent)) + if (!(@event.Payload is AppEvent)) { return null; } diff --git a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleTriggerHandler.cs b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleTriggerHandler.cs index d5f8d47df..c369497ac 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleTriggerHandler.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleTriggerHandler.cs @@ -33,9 +33,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules bool IRuleTriggerHandler.Trigger(EnrichedEvent @event, RuleTrigger trigger) { - var typed = @event as TEnrichedEvent; - - if (typed != null) + if (@event is TEnrichedEvent typed) { return Trigger(typed, (TTrigger)trigger); } @@ -45,9 +43,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules bool IRuleTriggerHandler.Trigger(AppEvent @event, RuleTrigger trigger, Guid ruleId) { - var typed = @event as TEvent; - - if (typed != null) + if (@event is TEvent typed) { return Trigger(typed, (TTrigger)trigger, ruleId); } diff --git a/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/JsonMapper.cs b/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/JsonMapper.cs index 33e5fd891..4720ddfce 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/JsonMapper.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/JsonMapper.cs @@ -24,7 +24,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper switch (value) { - case JsonNull n: + case JsonNull _: return JsValue.Null; case JsonScalar s: return new JsString(s.Value); diff --git a/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs b/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs index ab089b5d7..11b072b8c 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs @@ -69,7 +69,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent private IValidator CreateSchemaValidator(bool isPartial) { - var fieldsValidators = new Dictionary(); + var fieldsValidators = new Dictionary(schema.Fields.Count); foreach (var field in schema.FieldsByName) { diff --git a/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidatorsFactory.cs b/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidatorsFactory.cs index afd76321d..464ad7748 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidatorsFactory.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidatorsFactory.cs @@ -38,7 +38,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent yield return new CollectionValidator(field.Properties.IsRequired, field.Properties.MinItems, field.Properties.MaxItems); } - var nestedSchema = new Dictionary(); + var nestedSchema = new Dictionary(field.Fields.Count); foreach (var nestedField in field.Fields) { diff --git a/src/Squidex.Domain.Apps.Entities/Apps/BackupApps.cs b/src/Squidex.Domain.Apps.Entities/Apps/BackupApps.cs index 330014cb8..bf73299e7 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/BackupApps.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/BackupApps.cs @@ -29,8 +29,8 @@ namespace Squidex.Domain.Apps.Entities.Apps private readonly IUserResolver userResolver; private readonly IAppsByNameIndex appsByNameIndex; private readonly HashSet contributors = new HashSet(); + private readonly Dictionary userMapping = new Dictionary(); private Dictionary usersWithEmail = new Dictionary(); - private Dictionary userMapping = new Dictionary(); private bool isReserved; private string appName; diff --git a/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByNameIndexGrain.cs b/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByNameIndexGrain.cs index a76be1ae3..ffd7d333a 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByNameIndexGrain.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByNameIndexGrain.cs @@ -23,7 +23,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes [CollectionName("Index_AppsByName")] public sealed class GrainState { - public Dictionary Apps { get; set; } = new Dictionary(); + public Dictionary Apps { get; set; } = new Dictionary(StringComparer.Ordinal); } public AppsByNameIndexGrain(IStore store) diff --git a/src/Squidex.Domain.Apps.Entities/EntityMapper.cs b/src/Squidex.Domain.Apps.Entities/EntityMapper.cs index f990ae781..1e5c1084c 100644 --- a/src/Squidex.Domain.Apps.Entities/EntityMapper.cs +++ b/src/Squidex.Domain.Apps.Entities/EntityMapper.cs @@ -46,7 +46,7 @@ namespace Squidex.Domain.Apps.Entities private static void SetCreated(IEntity entity, EnvelopeHeaders headers) { - if (entity is IUpdateableEntity updateable && updateable.Created == default(Instant)) + if (entity is IUpdateableEntity updateable && updateable.Created == default) { updateable.Created = headers.Timestamp(); } diff --git a/src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/UsageTrackerGrain.cs b/src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/UsageTrackerGrain.cs index a0cb3b57b..ba7773c68 100644 --- a/src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/UsageTrackerGrain.cs +++ b/src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/UsageTrackerGrain.cs @@ -79,7 +79,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.UsageTracking { var target = kvp.Value; - var (from, to) = GetDateRange(today, target.NumDays); + var (from, _) = GetDateRange(today, target.NumDays); if (!target.Triggered.HasValue || target.Triggered < from) { @@ -107,7 +107,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.UsageTracking await WriteStateAsync(); } - private (DateTime, DateTime) GetDateRange(DateTime today, int? numDays) + private static (DateTime, DateTime) GetDateRange(DateTime today, int? numDays) { if (numDays.HasValue) { diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/SchemaGrain.cs b/src/Squidex.Domain.Apps.Entities/Schemas/SchemaGrain.cs index 70ec38ddc..167971a34 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/SchemaGrain.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/SchemaGrain.cs @@ -220,9 +220,9 @@ namespace Squidex.Domain.Apps.Entities.Schemas var schemaSource = Snapshot.SchemaDef; var schemaTarget = command.ToSchema(schemaSource.Name, schemaSource.IsSingleton); - var @events = schemaSource.Synchronize(schemaTarget, serializer, () => Snapshot.SchemaFieldsTotal + 1, options); + var events = schemaSource.Synchronize(schemaTarget, serializer, () => Snapshot.SchemaFieldsTotal + 1, options); - foreach (var @event in @events) + foreach (var @event in events) { RaiseEvent(SimpleMapper.Map(command, (SchemaEvent)@event)); } diff --git a/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs b/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs index d4c7a0b8c..3f0a356b1 100644 --- a/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs +++ b/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs @@ -43,7 +43,7 @@ namespace Squidex.Infrastructure.States return (existing.Doc, existing.Version); } - return (default(T), EtagVersion.NotFound); + return (default, EtagVersion.NotFound); } } diff --git a/src/Squidex.Infrastructure/EventSourcing/RetrySubscription.cs b/src/Squidex.Infrastructure/EventSourcing/RetrySubscription.cs index 60a9f5679..58bfb6125 100644 --- a/src/Squidex.Infrastructure/EventSourcing/RetrySubscription.cs +++ b/src/Squidex.Infrastructure/EventSourcing/RetrySubscription.cs @@ -82,7 +82,7 @@ namespace Squidex.Infrastructure.EventSourcing { Task.Delay(ReconnectWaitMs, timerCts.Token).ContinueWith(t => { - dispatcher.DispatchAsync(() => Subscribe()); + dispatcher.DispatchAsync(Subscribe); }).Forget(); } else @@ -104,7 +104,7 @@ namespace Squidex.Infrastructure.EventSourcing public async Task StopAsync() { - await dispatcher.DispatchAsync(() => Unsubscribe()); + await dispatcher.DispatchAsync(Unsubscribe); await dispatcher.StopAndWaitAsync(); timerCts.Cancel(); diff --git a/src/Squidex.Infrastructure/Log/LockingLogStore.cs b/src/Squidex.Infrastructure/Log/LockingLogStore.cs index e6b931ebf..7b7ae2968 100644 --- a/src/Squidex.Infrastructure/Log/LockingLogStore.cs +++ b/src/Squidex.Infrastructure/Log/LockingLogStore.cs @@ -52,7 +52,7 @@ namespace Squidex.Infrastructure.Log break; } - await Task.Delay(2000); + await Task.Delay(2000, cts.Token); } if (!cts.IsCancellationRequested) @@ -68,7 +68,7 @@ namespace Squidex.Infrastructure.Log } else { - await stream.WriteAsync(LockedText, 0, LockedText.Length); + await stream.WriteAsync(LockedText, 0, LockedText.Length, cts.Token); } } } diff --git a/src/Squidex.Infrastructure/Security/Extensions.cs b/src/Squidex.Infrastructure/Security/Extensions.cs index 25b9a8b88..2f28f2fb2 100644 --- a/src/Squidex.Infrastructure/Security/Extensions.cs +++ b/src/Squidex.Infrastructure/Security/Extensions.cs @@ -23,6 +23,11 @@ namespace Squidex.Infrastructure.Security return principal.Claims.FirstOrDefault(x => x.Type == OpenIdClaims.ClientId)?.Value; } + public static string UserOrClientId(this ClaimsPrincipal principal) + { + return principal.OpenIdSubject() ?? principal.OpenIdClientId(); + } + public static string OpenIdPreferredUserName(this ClaimsPrincipal principal) { return principal.Claims.FirstOrDefault(x => x.Type == OpenIdClaims.PreferredUserName)?.Value; diff --git a/src/Squidex.Infrastructure/States/IStore.cs b/src/Squidex.Infrastructure/States/IStore.cs index e94d94558..390e555de 100644 --- a/src/Squidex.Infrastructure/States/IStore.cs +++ b/src/Squidex.Infrastructure/States/IStore.cs @@ -12,7 +12,7 @@ namespace Squidex.Infrastructure.States { public delegate void HandleEvent(Envelope @event); - public delegate void HandleSnapshot(T state); + public delegate void HandleSnapshot(T state); public interface IStore { diff --git a/src/Squidex.Shared/Identity/ClaimsPrincipalExtensions.cs b/src/Squidex.Shared/Identity/ClaimsPrincipalExtensions.cs index cb4511d41..0995e9a2e 100644 --- a/src/Squidex.Shared/Identity/ClaimsPrincipalExtensions.cs +++ b/src/Squidex.Shared/Identity/ClaimsPrincipalExtensions.cs @@ -27,12 +27,19 @@ namespace Squidex.Shared.Identity public static PermissionSet Permissions(this ClaimsPrincipal principal) { - return new PermissionSet(principal.Claims.Where(x => x.Type == SquidexClaimTypes.Permissions).Select(x => new Permission(x.Value))); + return new PermissionSet(principal.Claims + .Where(x => + x.Type == SquidexClaimTypes.Permissions || + x.Type == SquidexClaimTypes.PermissionsClient) + .Select(x => new Permission(x.Value))); } public static IEnumerable GetSquidexClaims(this ClaimsPrincipal principal) { - return principal.Claims.Where(c => c.Type.StartsWith(SquidexClaimTypes.Prefix, StringComparison.Ordinal)); + return principal.Claims + .Where(x => + x.Type.StartsWith(SquidexClaimTypes.Prefix, StringComparison.Ordinal) || + x.Type.StartsWith(SquidexClaimTypes.PrefixClient, StringComparison.Ordinal)); } } } diff --git a/src/Squidex.Shared/Identity/SquidexClaimTypes.cs b/src/Squidex.Shared/Identity/SquidexClaimTypes.cs index bd32adb0d..32ba4f90c 100644 --- a/src/Squidex.Shared/Identity/SquidexClaimTypes.cs +++ b/src/Squidex.Shared/Identity/SquidexClaimTypes.cs @@ -21,8 +21,12 @@ namespace Squidex.Shared.Identity public static readonly string Permissions = "urn:squidex:permissions"; + public static readonly string PermissionsClient = "client_urn:squidex:permissions"; + public static readonly string Prefix = "urn:squidex:"; + public static readonly string PrefixClient = "client_urn:squidex:"; + public static readonly string PictureUrlStore = "store"; } } diff --git a/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs b/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs index 5deacb593..fb765658c 100644 --- a/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs @@ -57,12 +57,12 @@ namespace Squidex.Areas.Api.Controllers.Apps [ApiCosts(0)] public async Task GetApps() { - var userId = HttpContext.User.OpenIdSubject(); + var userOrClientId = HttpContext.User.UserOrClientId(); var userPermissions = HttpContext.User.Permissions(); - var entities = await appProvider.GetUserApps(userId, userPermissions); + var entities = await appProvider.GetUserApps(userOrClientId, userPermissions); - var response = entities.ToArray(a => AppDto.FromApp(a, userId, userPermissions, appPlansProvider)); + var response = entities.ToArray(a => AppDto.FromApp(a, userOrClientId, userPermissions, appPlansProvider)); Response.Headers[HeaderNames.ETag] = response.ToManyEtag(); diff --git a/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs b/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs index f0cfeccbf..6f243f8bf 100644 --- a/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs +++ b/src/Squidex/Areas/Api/Controllers/Assets/AssetContentController.cs @@ -57,7 +57,7 @@ namespace Squidex.Areas.Api.Controllers.Assets /// [HttpGet] [Route("assets/{id}/")] - [ProducesResponseType(200)] + [ProducesResponseType(typeof(FileResult), 200)] [ApiCosts(0.5)] public async Task GetAssetContent(Guid id, [FromQuery] long version = EtagVersion.Any, [FromQuery] int? width = null, [FromQuery] int? height = null, [FromQuery] string mode = null) { diff --git a/src/Squidex/Areas/Api/Controllers/Backups/BackupContentController.cs b/src/Squidex/Areas/Api/Controllers/Backups/BackupContentController.cs index f94233fad..ba2dbe410 100644 --- a/src/Squidex/Areas/Api/Controllers/Backups/BackupContentController.cs +++ b/src/Squidex/Areas/Api/Controllers/Backups/BackupContentController.cs @@ -40,7 +40,7 @@ namespace Squidex.Areas.Api.Controllers.Backups [HttpGet] [Route("apps/{app}/backups/{id}")] [ResponseCache(Duration = 3600 * 24 * 30)] - [ProducesResponseType(200)] + [ProducesResponseType(typeof(FileResult), 200)] [ApiCosts(0)] [AllowAnonymous] public IActionResult GetBackupContent(string app, Guid id) diff --git a/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs b/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs index 5819a1a16..3c433fbdb 100644 --- a/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Backups/BackupsController.cs @@ -21,7 +21,7 @@ using Squidex.Shared; namespace Squidex.Areas.Api.Controllers.Backups { /// - /// Manages backups for app. + /// Manages backups for apps. /// [ApiExplorerSettings(GroupName = nameof(Backups))] public class BackupsController : ApiController diff --git a/src/Squidex/Areas/Api/Controllers/Backups/RestoreController.cs b/src/Squidex/Areas/Api/Controllers/Backups/RestoreController.cs index 273bacc90..b9eafaac4 100644 --- a/src/Squidex/Areas/Api/Controllers/Backups/RestoreController.cs +++ b/src/Squidex/Areas/Api/Controllers/Backups/RestoreController.cs @@ -11,12 +11,16 @@ using Orleans; using Squidex.Areas.Api.Controllers.Backups.Models; using Squidex.Domain.Apps.Entities.Backup; using Squidex.Infrastructure.Commands; -using Squidex.Infrastructure.Security; +using Squidex.Infrastructure.Orleans; using Squidex.Pipeline; using Squidex.Shared; namespace Squidex.Areas.Api.Controllers.Backups { + /// + /// Manages backups for apps. + /// + [ApiExplorerSettings(GroupName = nameof(Backups))] public class RestoreController : ApiController { private readonly IGrainFactory grainFactory; @@ -28,17 +32,18 @@ namespace Squidex.Areas.Api.Controllers.Backups } /// - /// Get current status. + /// Get current restore status. /// /// /// 200 => Status returned. /// [HttpGet] [Route("apps/restore/")] + [ProducesResponseType(typeof(RestoreJobDto), 200)] [ApiPermission(Permissions.AdminRestoreRead)] public async Task GetJob() { - var restoreGrain = grainFactory.GetGrain(User.OpenIdSubject()); + var restoreGrain = grainFactory.GetGrain(SingleGrain.Id); var job = await restoreGrain.GetJobAsync(); @@ -64,7 +69,7 @@ namespace Squidex.Areas.Api.Controllers.Backups [ApiPermission(Permissions.AdminRestoreCreate)] public async Task PostRestore([FromBody] RestoreRequest request) { - var restoreGrain = grainFactory.GetGrain(User.OpenIdSubject()); + var restoreGrain = grainFactory.GetGrain(SingleGrain.Id); await restoreGrain.RestoreAsync(request.Url, request.Name); diff --git a/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemaSwaggerGenerator.cs b/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemaSwaggerGenerator.cs index 703e77ce3..6f5812945 100644 --- a/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemaSwaggerGenerator.cs +++ b/src/Squidex/Areas/Api/Controllers/Contents/Generator/SchemaSwaggerGenerator.cs @@ -14,7 +14,6 @@ using Squidex.Config; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.GenerateJsonSchema; using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure; using Squidex.Pipeline.Swagger; using Squidex.Shared; diff --git a/src/Squidex/Areas/Api/Controllers/Ping/PingController.cs b/src/Squidex/Areas/Api/Controllers/Ping/PingController.cs index fd72eee9a..c27e14477 100644 --- a/src/Squidex/Areas/Api/Controllers/Ping/PingController.cs +++ b/src/Squidex/Areas/Api/Controllers/Ping/PingController.cs @@ -53,7 +53,7 @@ namespace Squidex.Areas.Api.Controllers.Ping [Route("ping/{app}/")] [ApiPermission(Permissions.AppCommon)] [ApiCosts(0)] - public IActionResult GetPing(string app) + public IActionResult GetAppPing(string app) { return NoContent(); } diff --git a/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs b/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs index f7983a639..3aef01d84 100644 --- a/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs +++ b/src/Squidex/Areas/Api/Controllers/Users/UsersController.cs @@ -136,7 +136,7 @@ namespace Squidex.Areas.Api.Controllers.Users /// [HttpGet] [Route("users/{id}/picture/")] - [ProducesResponseType(200)] + [ProducesResponseType(typeof(FileResult), 200)] [ResponseCache(Duration = 3600)] public async Task GetUserPicture(string id) { diff --git a/src/Squidex/Areas/IdentityServer/Config/LazyClientStore.cs b/src/Squidex/Areas/IdentityServer/Config/LazyClientStore.cs index adc1451ad..af60dc5e3 100644 --- a/src/Squidex/Areas/IdentityServer/Config/LazyClientStore.cs +++ b/src/Squidex/Areas/IdentityServer/Config/LazyClientStore.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; +using System.Security.Claims; using System.Threading.Tasks; using IdentityServer4; using IdentityServer4.Models; @@ -17,6 +18,8 @@ using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Entities; using Squidex.Infrastructure; using Squidex.Pipeline; +using Squidex.Shared; +using Squidex.Shared.Identity; namespace Squidex.Areas.IdentityServer.Config { @@ -25,14 +28,17 @@ namespace Squidex.Areas.IdentityServer.Config private readonly IAppProvider appProvider; private readonly Dictionary staticClients = new Dictionary(StringComparer.OrdinalIgnoreCase); - public LazyClientStore(IOptions urlsOptions, IAppProvider appProvider) + public LazyClientStore( + IOptions urlsOptions, + IOptions identityOptions, + IAppProvider appProvider) { Guard.NotNull(urlsOptions, nameof(urlsOptions)); Guard.NotNull(appProvider, nameof(appProvider)); this.appProvider = appProvider; - CreateStaticClients(urlsOptions); + CreateStaticClients(urlsOptions, identityOptions); } public async Task FindClientByIdAsync(string clientId) @@ -83,15 +89,15 @@ namespace Squidex.Areas.IdentityServer.Config }; } - private void CreateStaticClients(IOptions urlsOptions) + private void CreateStaticClients(IOptions urlsOptions, IOptions identityOptions) { - foreach (var client in CreateStaticClients(urlsOptions.Value)) + foreach (var client in CreateStaticClients(urlsOptions.Value, identityOptions.Value)) { staticClients[client.ClientId] = client; } } - private static IEnumerable CreateStaticClients(MyUrlsOptions urlsOptions) + private static IEnumerable CreateStaticClients(MyUrlsOptions urlsOptions, MyIdentityOptions identityOptions) { var frontendId = Constants.FrontendClient; @@ -150,6 +156,30 @@ namespace Squidex.Areas.IdentityServer.Config }, RequireConsent = false }; + + if (identityOptions.IsAdminClientConfigured()) + { + var id = identityOptions.AdminClientId; + + yield return new Client + { + ClientId = id, + ClientName = id, + ClientSecrets = new List { new Secret(identityOptions.AdminClientSecret.Sha256()) }, + AccessTokenLifetime = (int)TimeSpan.FromDays(30).TotalSeconds, + AllowedGrantTypes = GrantTypes.ClientCredentials, + AllowedScopes = new List + { + Constants.ApiScope, + Constants.RoleScope, + Constants.PermissionsScope + }, + Claims = new List + { + new Claim(SquidexClaimTypes.Permissions, Permissions.Admin) + } + }; + } } } } diff --git a/src/Squidex/Config/Logging.cs b/src/Squidex/Config/Logging.cs index bea1bbd60..ca61f4a2a 100644 --- a/src/Squidex/Config/Logging.cs +++ b/src/Squidex/Config/Logging.cs @@ -5,6 +5,8 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +#define LOG_ALL_IDENTITY_SERVER_NONE + using System; using Microsoft.Extensions.Logging; @@ -40,7 +42,12 @@ namespace Squidex.Config { return level > LogLevel.Information; } - +#if LOG_ALL_IDENTITY_SERVER + if (category.StartsWith("IdentityServer4.", StringComparison.OrdinalIgnoreCase)) + { + return true; + } +#endif return level >= LogLevel.Information; }); } diff --git a/src/Squidex/Config/MyIdentityOptions.cs b/src/Squidex/Config/MyIdentityOptions.cs index 01a3045b8..e8547ff90 100644 --- a/src/Squidex/Config/MyIdentityOptions.cs +++ b/src/Squidex/Config/MyIdentityOptions.cs @@ -13,6 +13,10 @@ namespace Squidex.Config public string AdminPassword { get; set; } + public string AdminClientId { get; set; } + + public string AdminClientSecret { get; set; } + public string GithubClient { get; set; } public string GithubSecret { get; set; } @@ -48,6 +52,11 @@ namespace Squidex.Config return !string.IsNullOrWhiteSpace(AdminEmail) && !string.IsNullOrWhiteSpace(AdminPassword); } + public bool IsAdminClientConfigured() + { + return !string.IsNullOrWhiteSpace(AdminClientId) && !string.IsNullOrWhiteSpace(AdminClientSecret); + } + public bool IsOidcConfigured() { return !string.IsNullOrWhiteSpace(OidcAuthority) && !string.IsNullOrWhiteSpace(OidcClient) && !string.IsNullOrWhiteSpace(OidcSecret); diff --git a/src/Squidex/Pipeline/Extensions.cs b/src/Squidex/Pipeline/Extensions.cs index 35db046e0..98f693727 100644 --- a/src/Squidex/Pipeline/Extensions.cs +++ b/src/Squidex/Pipeline/Extensions.cs @@ -29,12 +29,17 @@ namespace Squidex.Pipeline { var parts = clientId.Split(':', '~'); - if (parts.Length != 2) + if (parts.Length == 1) { - return (null, null); + return (null, parts[0]); } - return (parts[0], parts[1]); + if (parts.Length == 2) + { + return (parts[0], parts[1]); + } + + return (null, null); } } } diff --git a/src/Squidex/Pipeline/Squid/SquidMiddleware.cs b/src/Squidex/Pipeline/Squid/SquidMiddleware.cs index 2a5dd9dae..157c3c381 100644 --- a/src/Squidex/Pipeline/Squid/SquidMiddleware.cs +++ b/src/Squidex/Pipeline/Squid/SquidMiddleware.cs @@ -63,14 +63,9 @@ namespace Squidex.Pipeline.Squid background = backgroundValue; } - var isSmall = false; + var isSmall = request.Query.TryGetValue("small", out _); - if (request.Query.TryGetValue("small", out _)) - { - isSmall = true; - } - - var svg = string.Empty; + string svg; if (isSmall) { diff --git a/src/Squidex/app/features/assets/pages/assets-page.component.ts b/src/Squidex/app/features/assets/pages/assets-page.component.ts index aa0e805ce..2f795ab59 100644 --- a/src/Squidex/app/features/assets/pages/assets-page.component.ts +++ b/src/Squidex/app/features/assets/pages/assets-page.component.ts @@ -5,8 +5,6 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -// tslint:disable:prefer-for-of - import { Component, OnInit } from '@angular/core'; import { FormControl } from '@angular/forms'; import { onErrorResumeNext } from 'rxjs/operators'; diff --git a/src/Squidex/app/features/content/shared/assets-editor.component.html b/src/Squidex/app/features/content/shared/assets-editor.component.html index 10412407d..07fd90bb1 100644 --- a/src/Squidex/app/features/content/shared/assets-editor.component.html +++ b/src/Squidex/app/features/content/shared/assets-editor.component.html @@ -1,8 +1,9 @@ -
+ +
-
+
Drop files or click here to add assets.
diff --git a/src/Squidex/app/features/content/shared/assets-editor.component.ts b/src/Squidex/app/features/content/shared/assets-editor.component.ts index 642805e90..2f84d6a5a 100644 --- a/src/Squidex/app/features/content/shared/assets-editor.component.ts +++ b/src/Squidex/app/features/content/shared/assets-editor.component.ts @@ -5,8 +5,6 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -// tslint:disable:prefer-for-of - import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; @@ -104,23 +102,9 @@ export class AssetsEditorComponent extends StatefulControlComponent ({ ...s, assets })); } - public pasteFiles(event: ClipboardEvent) { - for (let i = 0; i < event.clipboardData.items.length; i++) { - const file = event.clipboardData.items[i].getAsFile(); - - if (file) { - this.next(s => ({ ...s, assetFiles: s.assetFiles.pushFront(file) })); - } - } - } - - public addFiles(files: FileList) { - for (let i = 0; i < files.length; i++) { - const file = files[i]; - - if (file) { - this.next(s => ({ ...s, assetFiles: s.assetFiles.pushFront(file) })); - } + public addFiles(files: File[]) { + for (let file of files) { + this.next(s => ({ ...s, assetFiles: s.assetFiles.pushFront(file) })); } } diff --git a/src/Squidex/app/features/content/shared/references-editor.component.ts b/src/Squidex/app/features/content/shared/references-editor.component.ts index 9e5bfdf32..426413e17 100644 --- a/src/Squidex/app/features/content/shared/references-editor.component.ts +++ b/src/Squidex/app/features/content/shared/references-editor.component.ts @@ -5,8 +5,6 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -// tslint:disable:prefer-for-of - import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; diff --git a/src/Squidex/app/features/rules/pages/rules/triggers/asset-changed-trigger.component.html b/src/Squidex/app/features/rules/pages/rules/triggers/asset-changed-trigger.component.html index e5b367c24..1ae2b45f6 100644 --- a/src/Squidex/app/features/rules/pages/rules/triggers/asset-changed-trigger.component.html +++ b/src/Squidex/app/features/rules/pages/rules/triggers/asset-changed-trigger.component.html @@ -4,7 +4,7 @@ - +
diff --git a/src/Squidex/app/features/rules/pages/rules/triggers/content-changed-trigger.component.html b/src/Squidex/app/features/rules/pages/rules/triggers/content-changed-trigger.component.html index b45b40677..df54ee885 100644 --- a/src/Squidex/app/features/rules/pages/rules/triggers/content-changed-trigger.component.html +++ b/src/Squidex/app/features/rules/pages/rules/triggers/content-changed-trigger.component.html @@ -21,7 +21,7 @@ {{schema.schema.displayName}} - +