From 721db5828878502e20190b5baa5bfa7802a7d336 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 16 Dec 2016 22:56:09 +0100 Subject: [PATCH] History V1 --- src/Squidex.Events/EventExtensions.cs | 5 ++ .../{IUserCommand.cs => IActorCommand.cs} | 6 +- .../CQRS/CommonHeaders.cs | 2 +- .../CQRS/EnvelopeExtensions.cs | 8 +- ...ocessor.cs => EnrichWithActorProcessor.cs} | 8 +- ...TokenConverter.cs => RefTokenConverter.cs} | 8 +- .../{UserToken.cs => RefToken.cs} | 14 +-- .../History/IHistoryEventEntity.cs | 3 + .../{IAppEntity.cs => IAppRefEntity.cs} | 4 +- src/Squidex.Read/ITrackCreatedByEntity.cs | 13 +++ .../ITrackLastModifiedByEntity.cs | 17 ++++ .../Schemas/Repositories/ISchemaEntity.cs | 2 +- .../History/MessagesEN.cs | 4 +- .../History/MongoHistoryEventEntity.cs | 22 +++-- .../History/MongoHistoryEventRepository.cs | 10 +-- .../History/ParsedHistoryEvent.cs | 6 ++ src/Squidex.Store.MongoDb/MongoDbModule.cs | 12 ++- .../Utils/EntityMapper.cs | 83 ++++++++++++++---- .../Utils/RefTokenSerializer.cs | 60 +++++++++++++ src/Squidex.Write/Apps/AppDomainObject.cs | 4 +- src/Squidex.Write/Apps/Commands/CreateApp.cs | 4 +- src/Squidex.Write/SquidexCommand.cs | 4 +- .../pages/clients/clients-page.component.html | 2 +- .../contributors-page.component.html | 2 +- .../languages/languages-page.component.html | 2 +- .../app/framework/utils/date-time.spec.ts | 6 ++ src/Squidex/app/framework/utils/date-time.ts | 4 + .../shared/components/app-form.component.html | 4 +- .../shared/components/app-form.component.ts | 2 +- .../shared/components/history.component.html | 7 +- .../shared/components/history.component.scss | 20 ++++- .../shared/components/history.component.ts | 32 +++++++ .../shared/services/history.service.spec.ts | 4 +- .../app/shared/services/history.service.ts | 4 +- .../shared/services/users-provider.service.ts | 9 +- src/Squidex/app/theme/_history.scss | 6 ++ src/Squidex/app/theme/_panels.scss | 5 +- .../app/theme/icomoon/fonts/icomoon.eot | Bin 3976 -> 4128 bytes .../app/theme/icomoon/fonts/icomoon.svg | 1 + .../app/theme/icomoon/fonts/icomoon.ttf | Bin 3812 -> 3964 bytes .../app/theme/icomoon/fonts/icomoon.woff | Bin 3888 -> 4040 bytes src/Squidex/app/theme/icomoon/selection.json | 27 ++++++ src/Squidex/app/theme/icomoon/style.css | 13 +-- src/Squidex/app/theme/theme.scss | 3 +- .../CQRS/EnvelopeExtensionsTests.cs | 10 +-- ...ts.cs => EnrichWithActorProcessorTests.cs} | 18 ++-- .../{UserTokenTests.cs => RefTokenTests.cs} | 46 +++++----- .../Apps/AppCommandHandlerTests.cs | 8 +- .../Apps/AppDomainObjectTests.cs | 6 +- 49 files changed, 402 insertions(+), 138 deletions(-) rename src/Squidex.Infrastructure/CQRS/Commands/{IUserCommand.cs => IActorCommand.cs} (78%) rename src/Squidex.Infrastructure/CQRS/Events/{EnrichWithUserProcessor.cs => EnrichWithActorProcessor.cs} (77%) rename src/Squidex.Infrastructure/Json/{UserTokenConverter.cs => RefTokenConverter.cs} (76%) rename src/Squidex.Infrastructure/{UserToken.cs => RefToken.cs} (81%) rename src/Squidex.Read/{IAppEntity.cs => IAppRefEntity.cs} (85%) create mode 100644 src/Squidex.Read/ITrackCreatedByEntity.cs create mode 100644 src/Squidex.Read/ITrackLastModifiedByEntity.cs create mode 100644 src/Squidex.Store.MongoDb/Utils/RefTokenSerializer.cs create mode 100644 src/Squidex/app/theme/_history.scss rename tests/Squidex.Infrastructure.Tests/CQRS/Events/{EnrichWithUserProcessorTests.cs => EnrichWithActorProcessorTests.cs} (64%) rename tests/Squidex.Infrastructure.Tests/{UserTokenTests.cs => RefTokenTests.cs} (67%) diff --git a/src/Squidex.Events/EventExtensions.cs b/src/Squidex.Events/EventExtensions.cs index 1e5a4d10f..2c7f3d12f 100644 --- a/src/Squidex.Events/EventExtensions.cs +++ b/src/Squidex.Events/EventExtensions.cs @@ -14,6 +14,11 @@ namespace Squidex.Events { public static class EventExtensions { + public static bool HasAppId(this EnvelopeHeaders headers) + { + return headers.Contains("AppId"); + } + public static Guid AppId(this EnvelopeHeaders headers) { return headers["AppId"].ToGuid(CultureInfo.InvariantCulture); diff --git a/src/Squidex.Infrastructure/CQRS/Commands/IUserCommand.cs b/src/Squidex.Infrastructure/CQRS/Commands/IActorCommand.cs similarity index 78% rename from src/Squidex.Infrastructure/CQRS/Commands/IUserCommand.cs rename to src/Squidex.Infrastructure/CQRS/Commands/IActorCommand.cs index ee6d10154..1e6852c3a 100644 --- a/src/Squidex.Infrastructure/CQRS/Commands/IUserCommand.cs +++ b/src/Squidex.Infrastructure/CQRS/Commands/IActorCommand.cs @@ -1,5 +1,5 @@ // ========================================================================== -// IUserCommand.cs +// IActorCommand.cs // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex Group @@ -8,8 +8,8 @@ namespace Squidex.Infrastructure.CQRS.Commands { - public interface IUserCommand : ICommand + public interface IActorCommand : ICommand { - UserToken User { get; set; } + RefToken Actor { get; set; } } } diff --git a/src/Squidex.Infrastructure/CQRS/CommonHeaders.cs b/src/Squidex.Infrastructure/CQRS/CommonHeaders.cs index ee13f6f42..eecc2275d 100644 --- a/src/Squidex.Infrastructure/CQRS/CommonHeaders.cs +++ b/src/Squidex.Infrastructure/CQRS/CommonHeaders.cs @@ -20,6 +20,6 @@ namespace Squidex.Infrastructure.CQRS public const string Timestamp = "Timestamp"; - public const string User = "User"; + public const string Actor = "Actor"; } } diff --git a/src/Squidex.Infrastructure/CQRS/EnvelopeExtensions.cs b/src/Squidex.Infrastructure/CQRS/EnvelopeExtensions.cs index f3a39631e..a82550571 100644 --- a/src/Squidex.Infrastructure/CQRS/EnvelopeExtensions.cs +++ b/src/Squidex.Infrastructure/CQRS/EnvelopeExtensions.cs @@ -62,14 +62,14 @@ namespace Squidex.Infrastructure.CQRS return envelope; } - public static UserToken User(this EnvelopeHeaders headers) + public static RefToken Actor(this EnvelopeHeaders headers) { - return UserToken.Parse(headers[CommonHeaders.User].ToString()); + return RefToken.Parse(headers[CommonHeaders.Actor].ToString()); } - public static Envelope SetUser(this Envelope envelope, UserToken value) where T : class + public static Envelope SetActor(this Envelope envelope, RefToken value) where T : class { - envelope.Headers.Set(CommonHeaders.User, value.ToString()); + envelope.Headers.Set(CommonHeaders.Actor, value.ToString()); return envelope; } diff --git a/src/Squidex.Infrastructure/CQRS/Events/EnrichWithUserProcessor.cs b/src/Squidex.Infrastructure/CQRS/Events/EnrichWithActorProcessor.cs similarity index 77% rename from src/Squidex.Infrastructure/CQRS/Events/EnrichWithUserProcessor.cs rename to src/Squidex.Infrastructure/CQRS/Events/EnrichWithActorProcessor.cs index b94924521..62000129e 100644 --- a/src/Squidex.Infrastructure/CQRS/Events/EnrichWithUserProcessor.cs +++ b/src/Squidex.Infrastructure/CQRS/Events/EnrichWithActorProcessor.cs @@ -1,5 +1,5 @@ // ========================================================================== -// EnrichWithUserProcessor.cs +// EnrichWithActorProcessor.cs // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex Group @@ -12,15 +12,15 @@ using Squidex.Infrastructure.Tasks; namespace Squidex.Infrastructure.CQRS.Events { - public sealed class EnrichWithUserProcessor : IEventProcessor + public sealed class EnrichWithActorProcessor : IEventProcessor { public Task ProcessEventAsync(Envelope @event, IAggregate aggregate, ICommand command) { - var userCommand = command as IUserCommand; + var userCommand = command as IActorCommand; if (userCommand != null) { - @event.SetUser(userCommand.User); + @event.SetActor(userCommand.Actor); } return TaskHelper.Done; diff --git a/src/Squidex.Infrastructure/Json/UserTokenConverter.cs b/src/Squidex.Infrastructure/Json/RefTokenConverter.cs similarity index 76% rename from src/Squidex.Infrastructure/Json/UserTokenConverter.cs rename to src/Squidex.Infrastructure/Json/RefTokenConverter.cs index 1b04b2d9f..7dcb1d3db 100644 --- a/src/Squidex.Infrastructure/Json/UserTokenConverter.cs +++ b/src/Squidex.Infrastructure/Json/RefTokenConverter.cs @@ -1,5 +1,5 @@ // ========================================================================== -// UserTokenConverter.cs +// RefTokenConverter.cs // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex Group @@ -11,7 +11,7 @@ using Newtonsoft.Json; namespace Squidex.Infrastructure.Json { - public sealed class UserTokenConverter : JsonConverter + public sealed class RefTokenConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { @@ -20,12 +20,12 @@ namespace Squidex.Infrastructure.Json public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - return reader.TokenType == JsonToken.Null ? null : UserToken.Parse((string)reader.Value); + return reader.TokenType == JsonToken.Null ? null : RefToken.Parse((string)reader.Value); } public override bool CanConvert(Type objectType) { - return objectType == typeof(UserToken); + return objectType == typeof(RefToken); } } } \ No newline at end of file diff --git a/src/Squidex.Infrastructure/UserToken.cs b/src/Squidex.Infrastructure/RefToken.cs similarity index 81% rename from src/Squidex.Infrastructure/UserToken.cs rename to src/Squidex.Infrastructure/RefToken.cs index 3d8ef974a..5a8214576 100644 --- a/src/Squidex.Infrastructure/UserToken.cs +++ b/src/Squidex.Infrastructure/RefToken.cs @@ -1,5 +1,5 @@ // ========================================================================== -// UserToken.cs +// RefToken.cs // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex Group @@ -11,13 +11,13 @@ using System.Linq; namespace Squidex.Infrastructure { - public sealed class UserToken : IEquatable + public sealed class RefToken : IEquatable { public string Type { get; } public string Identifier { get; } - public UserToken(string type, string identifier) + public RefToken(string type, string identifier) { Guard.NotNullOrEmpty(type, nameof(type)); Guard.NotNullOrEmpty(identifier, nameof(identifier)); @@ -27,7 +27,7 @@ namespace Squidex.Infrastructure Identifier = identifier; } - public static UserToken Parse(string input) + public static RefToken Parse(string input) { Guard.NotNullOrEmpty(input, nameof(input)); @@ -38,7 +38,7 @@ namespace Squidex.Infrastructure throw new ArgumentException("Input must have more than 2 parts divided by colon", nameof(input)); } - return new UserToken(parts[0], string.Join(":", parts.Skip(1))); + return new RefToken(parts[0], string.Join(":", parts.Skip(1))); } public override string ToString() @@ -48,10 +48,10 @@ namespace Squidex.Infrastructure public override bool Equals(object obj) { - return Equals(obj as UserToken); + return Equals(obj as RefToken); } - public bool Equals(UserToken other) + public bool Equals(RefToken other) { return other != null && (ReferenceEquals(this, other) || (Type.Equals(other.Type) && Identifier.Equals(other.Identifier))); } diff --git a/src/Squidex.Read/History/IHistoryEventEntity.cs b/src/Squidex.Read/History/IHistoryEventEntity.cs index 1c11d1224..e36911b69 100644 --- a/src/Squidex.Read/History/IHistoryEventEntity.cs +++ b/src/Squidex.Read/History/IHistoryEventEntity.cs @@ -7,6 +7,7 @@ // ========================================================================== using System; +using Squidex.Infrastructure; namespace Squidex.Read.History { @@ -15,5 +16,7 @@ namespace Squidex.Read.History Guid EventId { get; } string Message { get; } + + RefToken Actor { get; } } } diff --git a/src/Squidex.Read/IAppEntity.cs b/src/Squidex.Read/IAppRefEntity.cs similarity index 85% rename from src/Squidex.Read/IAppEntity.cs rename to src/Squidex.Read/IAppRefEntity.cs index 49113f791..a48eeb507 100644 --- a/src/Squidex.Read/IAppEntity.cs +++ b/src/Squidex.Read/IAppRefEntity.cs @@ -1,5 +1,5 @@ // ========================================================================== -// IAppEntity.cs +// IAppRefEntity.cs // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex Group @@ -10,7 +10,7 @@ using System; namespace Squidex.Read { - public interface IAppEntity : IEntity + public interface IAppRefEntity : IEntity { Guid AppId { get; set; } } diff --git a/src/Squidex.Read/ITrackCreatedByEntity.cs b/src/Squidex.Read/ITrackCreatedByEntity.cs new file mode 100644 index 000000000..4525c1a63 --- /dev/null +++ b/src/Squidex.Read/ITrackCreatedByEntity.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Squidex.Infrastructure; + +namespace Squidex.Read +{ + public interface ITrackCreatedByEntity + { + RefToken CreatedBy { get; set; } + } +} diff --git a/src/Squidex.Read/ITrackLastModifiedByEntity.cs b/src/Squidex.Read/ITrackLastModifiedByEntity.cs new file mode 100644 index 000000000..d19b36266 --- /dev/null +++ b/src/Squidex.Read/ITrackLastModifiedByEntity.cs @@ -0,0 +1,17 @@ +// ========================================================================== +// ITrackLastModifiedByEntity.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using Squidex.Infrastructure; + +namespace Squidex.Read +{ + public interface ITrackLastModifiedByEntity + { + RefToken LastModifiedBy { get; set; } + } +} diff --git a/src/Squidex.Read/Schemas/Repositories/ISchemaEntity.cs b/src/Squidex.Read/Schemas/Repositories/ISchemaEntity.cs index de0434aec..cbb3443c9 100644 --- a/src/Squidex.Read/Schemas/Repositories/ISchemaEntity.cs +++ b/src/Squidex.Read/Schemas/Repositories/ISchemaEntity.cs @@ -7,7 +7,7 @@ // ========================================================================== namespace Squidex.Read.Schemas.Repositories { - public interface ISchemaEntity : IAppEntity + public interface ISchemaEntity : IAppRefEntity { string Name { get; } } diff --git a/src/Squidex.Store.MongoDb/History/MessagesEN.cs b/src/Squidex.Store.MongoDb/History/MessagesEN.cs index 0470188dc..bdc3f93b8 100644 --- a/src/Squidex.Store.MongoDb/History/MessagesEN.cs +++ b/src/Squidex.Store.MongoDb/History/MessagesEN.cs @@ -19,11 +19,11 @@ namespace Squidex.Store.MongoDb.History { { TypeNameRegistry.GetName(), - "[User] assigned [Contributor] to app with permission [Permission]" + "assigned {user:[Contributor]} to app with permission [Permission]" }, { TypeNameRegistry.GetName(), - "[User] removed [Contributor] from app" + "removed {user:[Contributor]} from app" } }; } diff --git a/src/Squidex.Store.MongoDb/History/MongoHistoryEventEntity.cs b/src/Squidex.Store.MongoDb/History/MongoHistoryEventEntity.cs index bf7baab14..d81232c91 100644 --- a/src/Squidex.Store.MongoDb/History/MongoHistoryEventEntity.cs +++ b/src/Squidex.Store.MongoDb/History/MongoHistoryEventEntity.cs @@ -11,11 +11,12 @@ using System.Collections.Generic; using MongoDB.Bson.Serialization.Attributes; using Squidex.Infrastructure; using Squidex.Infrastructure.CQRS; +using Squidex.Read; using Squidex.Store.MongoDb.Utils; namespace Squidex.Store.MongoDb.History { - public sealed class MongoHistoryEventEntity : MongoEntity + public sealed class MongoHistoryEventEntity : MongoEntity, IAppRefEntity, ITrackCreatedByEntity { [BsonRequired] [BsonElement] @@ -31,12 +32,24 @@ namespace Squidex.Store.MongoDb.History [BsonRequired] [BsonElement] - public UserToken User { get; set; } + public RefToken Actor { get; set; } [BsonRequired] [BsonElement] public Dictionary Parameters { get; set; } + RefToken ITrackCreatedByEntity.CreatedBy + { + get + { + return Actor; + } + set + { + Actor = value; + } + } + public MongoHistoryEventEntity() { Parameters = new Dictionary(); @@ -46,11 +59,6 @@ namespace Squidex.Store.MongoDb.History { Channel = channel; - if (headers.Contains(CommonHeaders.User)) - { - AddParameter("User", headers[CommonHeaders.User].ToString()); - } - Message = TypeNameRegistry.GetName(); return this; diff --git a/src/Squidex.Store.MongoDb/History/MongoHistoryEventRepository.cs b/src/Squidex.Store.MongoDb/History/MongoHistoryEventRepository.cs index 4cdbe6551..20b300afb 100644 --- a/src/Squidex.Store.MongoDb/History/MongoHistoryEventRepository.cs +++ b/src/Squidex.Store.MongoDb/History/MongoHistoryEventRepository.cs @@ -44,7 +44,7 @@ namespace Squidex.Store.MongoDb.History public async Task> QueryEventsByChannel(Guid appId, string channelPrefix, int count) { var entities = - await Collection.Find(x => x.AppId == appId && x.Channel.StartsWith(channelPrefix)).Limit(count).ToListAsync(); + await Collection.Find(x => x.AppId == appId && x.Channel.StartsWith(channelPrefix)).SortByDescending(x => x.Created).Limit(count).ToListAsync(); return entities.Select(x => (IHistoryEventEntity)new ParsedHistoryEvent(x, MessagesEN.Texts)).ToList(); } @@ -53,23 +53,23 @@ namespace Squidex.Store.MongoDb.History { return Collection.CreateAsync(headers, x => { - var channel = $"Apps.{headers.AggregateId()}.Contributors"; + const string channel = "settings.contributors"; x.Setup(headers, channel) .AddParameter("Contributor", @event.ContributorId) .AddParameter("Permission", @event.Permission.ToString()); - }); + }, false); } protected Task On(AppContributorRemoved @event, EnvelopeHeaders headers) { return Collection.CreateAsync(headers, x => { - var channel = $"Apps.{headers.AggregateId()}.Contributors"; + const string channel = "settings.contributors"; x.Setup(headers, channel) .AddParameter("Contributor", @event.ContributorId); - }); + }, false); } public Task On(Envelope @event) diff --git a/src/Squidex.Store.MongoDb/History/ParsedHistoryEvent.cs b/src/Squidex.Store.MongoDb/History/ParsedHistoryEvent.cs index 99030c6c3..06282b7f0 100644 --- a/src/Squidex.Store.MongoDb/History/ParsedHistoryEvent.cs +++ b/src/Squidex.Store.MongoDb/History/ParsedHistoryEvent.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; +using Squidex.Infrastructure; using Squidex.Read.History; namespace Squidex.Store.MongoDb.History @@ -27,6 +28,11 @@ namespace Squidex.Store.MongoDb.History get { return inner.Id; } } + public RefToken Actor + { + get { return inner.Actor; } + } + public DateTime Created { get { return inner.Created; } diff --git a/src/Squidex.Store.MongoDb/MongoDbModule.cs b/src/Squidex.Store.MongoDb/MongoDbModule.cs index 1b5bdc6ee..795ea6b9a 100644 --- a/src/Squidex.Store.MongoDb/MongoDbModule.cs +++ b/src/Squidex.Store.MongoDb/MongoDbModule.cs @@ -23,6 +23,7 @@ using Squidex.Store.MongoDb.History; using Squidex.Store.MongoDb.Infrastructure; using Squidex.Store.MongoDb.Schemas; using Squidex.Store.MongoDb.Users; +using Squidex.Store.MongoDb.Utils; namespace Squidex.Store.MongoDb { @@ -30,6 +31,8 @@ namespace Squidex.Store.MongoDb { protected override void Load(ContainerBuilder builder) { + RefTokenSerializer.Register(); + builder.Register(context => { var options = context.Resolve>().Value; @@ -67,12 +70,13 @@ namespace Squidex.Store.MongoDb .As() .SingleInstance(); - builder.RegisterType() - .As() - .SingleInstance(); - builder.RegisterType() .As() + .InstancePerLifetimeScope(); + + builder.RegisterType() + .As() + .As() .SingleInstance(); builder.RegisterType() diff --git a/src/Squidex.Store.MongoDb/Utils/EntityMapper.cs b/src/Squidex.Store.MongoDb/Utils/EntityMapper.cs index c22f71fd0..5be7b195a 100644 --- a/src/Squidex.Store.MongoDb/Utils/EntityMapper.cs +++ b/src/Squidex.Store.MongoDb/Utils/EntityMapper.cs @@ -14,25 +14,83 @@ using Newtonsoft.Json.Linq; using Squidex.Events; using Squidex.Infrastructure.CQRS; using Squidex.Read; +// ReSharper disable ConvertIfStatementToConditionalTernaryExpression +// ReSharper disable SuspiciousTypeConversion.Global namespace Squidex.Store.MongoDb.Utils { public static class EntityMapper { - public static T Create(EnvelopeHeaders headers) where T : MongoEntity, new() + public static T Create(EnvelopeHeaders headers, bool useAggregateId = true) where T : MongoEntity, new() { - var timestamp = headers.Timestamp().ToDateTimeUtc(); + var entity = new T(); - var entity = new T { Id = headers.AggregateId(), Created = timestamp }; + AssignId(headers, entity, useAggregateId); + AssignAppId(headers, entity); + AssignCreated(headers, entity); + AssignCreatedBy(headers, entity); - var appEntity = entity as IAppEntity; + return Update(entity, headers); + } + + public static T Update(T entity, EnvelopeHeaders headers) where T : MongoEntity + { + AssignLastModified(headers, entity); + AssignLastModifiedBy(headers, entity); + + return entity; + } + + private static void AssignCreated(EnvelopeHeaders headers, MongoEntity entity) + { + entity.Created = headers.Timestamp().ToDateTimeUtc(); + } + + private static void AssignLastModified(EnvelopeHeaders headers, MongoEntity entity) + { + entity.LastModified = headers.Timestamp().ToDateTimeUtc(); + } + + private static void AssignCreatedBy(EnvelopeHeaders headers, MongoEntity entity) + { + var createdBy = entity as ITrackCreatedByEntity; + + if (createdBy != null) + { + createdBy.CreatedBy = headers.Actor(); + } + } + + private static void AssignLastModifiedBy(EnvelopeHeaders headers, MongoEntity entity) + { + var modifiedBy = entity as ITrackLastModifiedByEntity; + + if (modifiedBy != null) + { + modifiedBy.LastModifiedBy = headers.Actor(); + } + } + + private static void AssignAppId(EnvelopeHeaders headers, MongoEntity entity) + { + var appEntity = entity as IAppRefEntity; if (appEntity != null) { appEntity.AppId = headers.AppId(); } - - return Update(entity, headers); + } + + private static void AssignId(EnvelopeHeaders headers, MongoEntity entity, bool useAggregateId) + { + if (useAggregateId) + { + entity.Id = headers.AggregateId(); + } + else + { + entity.Id = Guid.NewGuid(); + } } public static BsonDocument ToBsonDocument(this JToken value) @@ -49,18 +107,9 @@ namespace Squidex.Store.MongoDb.Utils return JToken.Parse(json); } - public static T Update(T entity, EnvelopeHeaders headers) where T : MongoEntity - { - var timestamp = headers.Timestamp().ToDateTimeUtc(); - - entity.LastModified = timestamp; - - return entity; - } - - public static Task CreateAsync(this IMongoCollection collection, EnvelopeHeaders headers, Action updater) where T : MongoEntity, new() + public static Task CreateAsync(this IMongoCollection collection, EnvelopeHeaders headers, Action updater, bool useAggregateId = true) where T : MongoEntity, new() { - var entity = Create(headers); + var entity = Create(headers, useAggregateId); updater(entity); diff --git a/src/Squidex.Store.MongoDb/Utils/RefTokenSerializer.cs b/src/Squidex.Store.MongoDb/Utils/RefTokenSerializer.cs new file mode 100644 index 000000000..7168b23a8 --- /dev/null +++ b/src/Squidex.Store.MongoDb/Utils/RefTokenSerializer.cs @@ -0,0 +1,60 @@ +// ========================================================================== +// RefTokenSerializer.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; +using Squidex.Infrastructure; + +// ReSharper disable InvertIf + +namespace Squidex.Store.MongoDb.Utils +{ + public class RefTokenSerializer : SerializerBase + { + private static bool isRegistered; + private static readonly object LockObject = new object(); + + public static bool Register() + { + if (!isRegistered) + { + lock (LockObject) + { + if (!isRegistered) + { + BsonSerializer.RegisterSerializer(new RefTokenSerializer()); + + isRegistered = true; + return true; + } + } + } + + return false; + } + + public override RefToken Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) + { + var value = context.Reader.ReadString(); + + return value != null ? RefToken.Parse(value) : null; + } + + public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, RefToken value) + { + if (value != null) + { + context.Writer.WriteString(value.ToString()); + } + else + { + context.Writer.WriteNull(); + } + } + } +} diff --git a/src/Squidex.Write/Apps/AppDomainObject.cs b/src/Squidex.Write/Apps/AppDomainObject.cs index 38fd1e1af..59116064d 100644 --- a/src/Squidex.Write/Apps/AppDomainObject.cs +++ b/src/Squidex.Write/Apps/AppDomainObject.cs @@ -207,9 +207,9 @@ namespace Squidex.Write.Apps return new AppMasterLanguageSet { Language = DefaultLanguage }; } - private static AppContributorAssigned CreateInitialOwner(IUserCommand command) + private static AppContributorAssigned CreateInitialOwner(IActorCommand command) { - return new AppContributorAssigned { ContributorId = command.User.Identifier, Permission = PermissionLevel.Owner }; + return new AppContributorAssigned { ContributorId = command.Actor.Identifier, Permission = PermissionLevel.Owner }; } private void ThrowIfNotCreated() diff --git a/src/Squidex.Write/Apps/Commands/CreateApp.cs b/src/Squidex.Write/Apps/Commands/CreateApp.cs index ee9294669..7f8d2964e 100644 --- a/src/Squidex.Write/Apps/Commands/CreateApp.cs +++ b/src/Squidex.Write/Apps/Commands/CreateApp.cs @@ -13,11 +13,11 @@ using Squidex.Infrastructure.CQRS.Commands; namespace Squidex.Write.Apps.Commands { - public sealed class CreateApp : AggregateCommand, IUserCommand, IValidatable + public sealed class CreateApp : AggregateCommand, IActorCommand, IValidatable { public string Name { get; set; } - public UserToken User { get; set; } + public RefToken Actor { get; set; } public CreateApp() { diff --git a/src/Squidex.Write/SquidexCommand.cs b/src/Squidex.Write/SquidexCommand.cs index caa4d027d..ec08da4f7 100644 --- a/src/Squidex.Write/SquidexCommand.cs +++ b/src/Squidex.Write/SquidexCommand.cs @@ -11,8 +11,8 @@ using Squidex.Infrastructure.CQRS.Commands; namespace Squidex.Write { - public abstract class SquidexCommand : AggregateCommand, IUserCommand + public abstract class SquidexCommand : AggregateCommand, IActorCommand { - public UserToken User { get; set; } + public RefToken Actor { get; set; } } } diff --git a/src/Squidex/app/features/settings/pages/clients/clients-page.component.html b/src/Squidex/app/features/settings/pages/clients/clients-page.component.html index d16645f16..2e2453574 100644 --- a/src/Squidex/app/features/settings/pages/clients/clients-page.component.html +++ b/src/Squidex/app/features/settings/pages/clients/clients-page.component.html @@ -47,7 +47,7 @@ diff --git a/src/Squidex/app/features/settings/pages/contributors/contributors-page.component.html b/src/Squidex/app/features/settings/pages/contributors/contributors-page.component.html index 2f789a9ca..9ae4ef147 100644 --- a/src/Squidex/app/features/settings/pages/contributors/contributors-page.component.html +++ b/src/Squidex/app/features/settings/pages/contributors/contributors-page.component.html @@ -67,7 +67,7 @@ diff --git a/src/Squidex/app/features/settings/pages/languages/languages-page.component.html b/src/Squidex/app/features/settings/pages/languages/languages-page.component.html index 24a87ec26..c3f1c5dc2 100644 --- a/src/Squidex/app/features/settings/pages/languages/languages-page.component.html +++ b/src/Squidex/app/features/settings/pages/languages/languages-page.component.html @@ -78,7 +78,7 @@ diff --git a/src/Squidex/app/framework/utils/date-time.spec.ts b/src/Squidex/app/framework/utils/date-time.spec.ts index c79345186..7b8e49acf 100644 --- a/src/Squidex/app/framework/utils/date-time.spec.ts +++ b/src/Squidex/app/framework/utils/date-time.spec.ts @@ -81,6 +81,12 @@ describe('DateTime', () => { expect(actual).toEqual(expected); }); + it('should convert to local time', () => { + const value = DateTime.parseISO_UTC('2013-10-16T12:13:14'); + + expect(value.toLocal().ne(value)).toBeTruthy(); + }); + it('should print to formatted string', () => { const value = DateTime.parseISO_UTC('2013-10-16T12:13:14'); const actual = value.toStringFormat('hh:mm'); diff --git a/src/Squidex/app/framework/utils/date-time.ts b/src/Squidex/app/framework/utils/date-time.ts index 8fc266420..d3e78485b 100644 --- a/src/Squidex/app/framework/utils/date-time.ts +++ b/src/Squidex/app/framework/utils/date-time.ts @@ -221,6 +221,10 @@ export class DateTime { return new DateTime(clone); } + public toLocal(): DateTime { + return new DateTime(new Date(this.value.getTime() - this.value.getTimezoneOffset() * 60 * 1000)); + } + public toUTCString(): string { return this.value.toUTCString(); } diff --git a/src/Squidex/app/shared/components/app-form.component.html b/src/Squidex/app/shared/components/app-form.component.html index 7308c967e..4b5c44cdf 100644 --- a/src/Squidex/app/shared/components/app-form.component.html +++ b/src/Squidex/app/shared/components/app-form.component.html @@ -8,7 +8,7 @@
-
+
Name is required. @@ -33,6 +33,6 @@
- +
\ No newline at end of file diff --git a/src/Squidex/app/shared/components/app-form.component.ts b/src/Squidex/app/shared/components/app-form.component.ts index 01110eb29..ce73e9f47 100644 --- a/src/Squidex/app/shared/components/app-form.component.ts +++ b/src/Squidex/app/shared/components/app-form.component.ts @@ -59,7 +59,7 @@ export class AppFormComponent implements OnInit { } public createApp() { - this.createForm.markAsDirty(); + this.createForm.markAsTouched(); if (this.createForm.valid) { this.createForm.disable(); diff --git a/src/Squidex/app/shared/components/history.component.html b/src/Squidex/app/shared/components/history.component.html index fc3be669f..307f0c837 100644 --- a/src/Squidex/app/shared/components/history.component.html +++ b/src/Squidex/app/shared/components/history.component.html @@ -11,8 +11,11 @@
-
- {{event.message}} +
+
{{event.created.toLocal() | fromNow}}
+
+ {{actorName(event.actor) | async}} +
diff --git a/src/Squidex/app/shared/components/history.component.scss b/src/Squidex/app/shared/components/history.component.scss index 992daf82e..8ef337ad2 100644 --- a/src/Squidex/app/shared/components/history.component.scss +++ b/src/Squidex/app/shared/components/history.component.scss @@ -2,6 +2,22 @@ @import '_mixins'; .panel { - min-width: 220px; - max-width: 1220px80px; + min-width: 250px; + max-width: 250px; +} + +.event { + & { + margin-bottom: .8rem; + } + + &-message { + font-size: .9rem; + } + + &-created { + font-size: .65rem; + font-weight: normal; + color: $color-empty; + } } \ No newline at end of file diff --git a/src/Squidex/app/shared/components/history.component.ts b/src/Squidex/app/shared/components/history.component.ts index 753d094e4..a42d59754 100644 --- a/src/Squidex/app/shared/components/history.component.ts +++ b/src/Squidex/app/shared/components/history.component.ts @@ -7,6 +7,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; +import { Observable } from 'rxjs'; import { ImmutableArray, NotificationService } from 'framework'; @@ -16,6 +17,8 @@ import { HistoryEventDto, HistoryService } from './../services/history.service'; import { UsersProviderService } from './../services/users-provider.service'; const FALLBACK_NAME = 'my-app'; +const REPLACEMENT_REGEXP = new RegExp('{([^\s:]*):([^}]*)}'); +const REPLACEMENT_TEMP = '$TEMP$'; @Component({ selector: 'sqx-history', @@ -56,4 +59,33 @@ export class HistoryComponent extends AppComponentBase implements OnDestroy, OnI this.events = ImmutableArray.of(dtos); }); } + + public actorName(actor: string): Observable { + const parts = actor.split(':'); + + if (parts[0] === 'subject') { + return this.userName(parts[1]).map(n => n === 'Me' ? 'I' : n); + } + + return Observable.of(parts[1]); + } + + public format(message: string): Observable { + let foundUserId: string; + + message = message.replace(/{([^\s:]*):([^}]*)}/, (match: string, type: string, id: string) => { + if (type === 'user') { + foundUserId = id; + return REPLACEMENT_TEMP; + } else { + return id; + } + }); + + if (foundUserId) { + return this.userName(foundUserId).map(t => message.replace(REPLACEMENT_TEMP, `${t}`)); + } + + return Observable.of(message); + } } \ No newline at end of file diff --git a/src/Squidex/app/shared/services/history.service.spec.ts b/src/Squidex/app/shared/services/history.service.spec.ts index a5b296037..c890ab2d2 100644 --- a/src/Squidex/app/shared/services/history.service.spec.ts +++ b/src/Squidex/app/shared/services/history.service.spec.ts @@ -33,12 +33,12 @@ describe('HistoryService', () => { new Response( new ResponseOptions({ body: [{ - user: 'User1', + actor: 'User1', eventId: '1', message: 'Message 1', created: '2016-12-12T10:10' }, { - user: 'User2', + actor: 'User2', eventId: '2', message: 'Message 2', created: '2016-12-13T10:10' diff --git a/src/Squidex/app/shared/services/history.service.ts b/src/Squidex/app/shared/services/history.service.ts index 4d51c6d31..8e65a9a80 100644 --- a/src/Squidex/app/shared/services/history.service.ts +++ b/src/Squidex/app/shared/services/history.service.ts @@ -19,7 +19,7 @@ import { AuthService } from './auth.service'; export class HistoryEventDto { constructor( public readonly eventId: string, - public readonly user: string, + public readonly actor: string, public readonly message: string, public readonly created: DateTime ) { @@ -45,7 +45,7 @@ export class HistoryService { return items.map(item => { return new HistoryEventDto( item.eventId, - item.user, + item.actor, item.message, DateTime.parseISO_UTC(item.created)); }); diff --git a/src/Squidex/app/shared/services/users-provider.service.ts b/src/Squidex/app/shared/services/users-provider.service.ts index 1b1be0d41..572cd137c 100644 --- a/src/Squidex/app/shared/services/users-provider.service.ts +++ b/src/Squidex/app/shared/services/users-provider.service.ts @@ -31,12 +31,11 @@ export class UsersProviderService { .catch(err => { return Observable.of(new UserDto('NOT FOUND', 'NOT FOUND', 'NOT FOUND', '')); }) - .map(u => { - if (this.authService.user && u.id === this.authService.user.id) { - return new UserDto(u.id, u.email, 'Me', u.pictureUrl); - } else { - return u; + .map(dto => { + if (this.authService.user && dto.id === this.authService.user.id) { + dto = new UserDto(dto.id, dto.email, 'Me', dto.pictureUrl); } + return dto; }) .publishLast(); diff --git a/src/Squidex/app/theme/_history.scss b/src/Squidex/app/theme/_history.scss new file mode 100644 index 000000000..c43153385 --- /dev/null +++ b/src/Squidex/app/theme/_history.scss @@ -0,0 +1,6 @@ +@import '_mixins'; +@import '_vars'; + +.user-ref { + color: $color-theme-blue-dark; +} \ No newline at end of file diff --git a/src/Squidex/app/theme/_panels.scss b/src/Squidex/app/theme/_panels.scss index bf20f50e9..44d197c44 100644 --- a/src/Squidex/app/theme/_panels.scss +++ b/src/Squidex/app/theme/_panels.scss @@ -3,7 +3,7 @@ $panel-padding: 20px; $panel-header: 70px; -$panel-sidebar: 60px; +$panel-sidebar: 61px; .panel-container { @include absolute($size-navbar-height, 0, 0, $size-sidebar-width); @@ -68,12 +68,13 @@ $panel-sidebar: 60px; & .nav-link { text-align: center; + color: $color-text; } } &-close { & { - @include absolute($panel-padding, $panel-padding, auto, auto); + @include absolute($panel-padding, $panel-padding - 2px, auto, auto); font-size: 1.5rem; font-weight: 400; cursor: pointer; diff --git a/src/Squidex/app/theme/icomoon/fonts/icomoon.eot b/src/Squidex/app/theme/icomoon/fonts/icomoon.eot index f513f08c53703e4b91adb8dd277d12b7f802e672..69167196f82c113592faa1cd61c58f0486123796 100644 GIT binary patch delta 514 zcmeB>U!cIIAi%&-!#|PDj77C!*R9DHc||6MB-a-*Ffi-^;)LYf#DXNIcxDC$Mj4P; zdSY<_kOpdEyaA*+(sL@)tT|Vf0QnCX7`Rz7QWH~nCTC1%VBmQIlsC%&3UD~FgfKAh zg7m9oGC)79eC~PD_?SdRidl|%8S^Wa2$plKGOSI&@L*sNW;n~h4${uRG&zw;c=Kc4rHlXtWq*wT delta 375 zcmZ3W&>_#(!Oy_(gl{678FT5gPZRAc>I)bc81?{hLUL|m!Ng;3xeN@9GC=;8^u%J2 zoB)u20Z4PC=TxTgNhHey`8OCCxGFMI6H|Cv=QuJj@B{$m%`$)j98N63Kz;|1uac2l zQek(1=@XE@2FUlw$xlucJtVXQ$o~T5tK}wE6fj8XF`Q>$;00Nzke8U7I@62uH;``w zw4|*dzqo{f87RZRcLXHQz|8!5atdR$@C+bN3CL$*U}9ioP + diff --git a/src/Squidex/app/theme/icomoon/fonts/icomoon.ttf b/src/Squidex/app/theme/icomoon/fonts/icomoon.ttf index 8dcd5aa35ba2d53aa8c03fcf5a373fd0803f2558..95c49587b10b60fc85526f4628e53f9388eba456 100644 GIT binary patch delta 536 zcmaDN`$w*xfsuiMft#U$ftkU;KUm+0Ux>XBD6$8L6OwZi3zC@PnHd-uWk6!-iNys# zS^&tu0i-$7b1KuUIaihd`451Guw;dFE0Qo*S`N@unB8$W?00nx00vfrA6$K2^4CjITEkM3PUSe+QOfSygK>ih= zC2a-y#U((80s(&vNS=Y2`OU-w)xrya92Fp!1qc}#6rP@av30T!qY4v{DqvKW4G?D& zXBPV{_EhY?*gdf`Vh6>l#j?awMYjXZVw}8@QDO1{M%Kv}87u0U8NwJCnO8A~GO#j8 zGUx*B6cuMz7Zf(KV=^_-V^UV)V-gjSV-hx!1JZmzz8+BAj)_U^fWiYUx7t`Uv)CGU z7#%UE*x9*wb|jQ$YJ5;+*1^c|_X wjGGuAFu5^pVS2?Z$GnXB6-xxmIaV3gCUDFPGn{2$2Ww^m288ftd)}pt00$aW`D6$8L6OwZi3nm_O%Vl6-lmYU$q$d`G z(WLfhPbcZcPJXguqUa%^B|w2MKmoPf#EJq2DTeb547?x<74i~uQ)hZ{{s!`G zfR?lssK_Jv-TtQHALx!{h))X<5eq zkEP7TS;d*eeu+I1yC-&6?6lYcu`01lu@up5lQ%G`Prk`mvH32O0GITqXQlD{HeVUI zSwMC$Tq)Lm1fwT&@R~CUO?KcFpB&9=tHc<@n8P@WiGeAPX$jK}<^<*?EJ7?DEZ10p O?gR&^(B@sdhZq5)(N^pL diff --git a/src/Squidex/app/theme/icomoon/fonts/icomoon.woff b/src/Squidex/app/theme/icomoon/fonts/icomoon.woff index 2c3e789968e38d8fa4c752a65f814d2a7d0f10d2..7ef84f5865a7a9a803fa15c10a7b98520d3e9862 100644 GIT binary patch delta 575 zcmdlWcS2sQ+~3WOfsp|S_)jo!gXtOu#>tFKViR?Q>kE@}6AKs^7&Cwpdq6meDV{k! zu^1@Eqypq~K(Ro2PGuTUOoxGin+1feIaiisq$Z{?Fz^}x)tG@W&*Y5h89+gx7|1-3 zeiaTUmXM6xk_w<$50LKz!cGU6J#zAsf$IEtZvX`}Kv-mv_=ViW3ZTV&KrVv<7)vvp z&r8fr1&RUrjBOx1(~I+WL4I)w&_65S>X?BnX684Oc^Ioj7XaBRK>aL0$jG4Z^z4hR zFBvEAW0d9uNM!21y28pesbh+0_MwjqI3AP4t+QmH3!MMdX--jpTqdACRvH z6t`ny5<8&qK+CN**32xn#vMjS%qezuE}k6;rI{KZ6q$7}GW@-QP*m&YUK4A^%-~!y zJ0fy+36GOg2~hp)5@(?MH&0;_C_^A#KyK*1|jLcAc)f#}Hxc+4e*fpG)} zOh6Wpe+`JkCiCz*C^6JA&S2cc_<+fcX$#XUW;y0%%&%A?SkAG^ur>jMjDbOTa~|&@ FMgW+=eTV=6 delta 424 zcmX>hzd=r{+~3WOfsp|S_zf7iK{VeJ2FA&ZOkxvtgzF2Ea}x^~7#K5v;#)v?;xV_} z^u%JI7?TW;&jG~(={c2YKrs~t2CfPa=95U4&qz&7VPN2y15{%M!aS{W95aA|K(Q-8 zK2R-#3WpO*a7JzkP!G=!Am0Oo?G7+~%E?a#s`KM@01Bvqu;?M7CAo%we3x#K4rt qw1nvfa{}`c79o}nmTRmwKvj%DEW~h@fgP-o2^a^$o0a*NG6Ddi#8s*Q diff --git a/src/Squidex/app/theme/icomoon/selection.json b/src/Squidex/app/theme/icomoon/selection.json index 418c6007d..c34d1af71 100644 --- a/src/Squidex/app/theme/icomoon/selection.json +++ b/src/Squidex/app/theme/icomoon/selection.json @@ -1,6 +1,33 @@ { "IcoMoonType": "selection", "icons": [ + { + "icon": { + "paths": [ + "M534 298v224l192 114-32 54-224-136v-256h64zM512 854c188 0 342-154 342-342s-154-342-342-342-342 154-342 342 154 342 342 342zM512 86c236 0 426 190 426 426s-190 426-426 426-426-190-426-426 190-426 426-426z" + ], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "schedule" + ], + "defaultCode": 59573, + "grid": 24 + }, + "attrs": [], + "properties": { + "order": 17, + "ligatures": "access_time, query_builder, schedule", + "id": 4, + "prevSize": 24, + "code": 59573, + "name": "time" + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 4 + }, { "icon": { "paths": [ diff --git a/src/Squidex/app/theme/icomoon/style.css b/src/Squidex/app/theme/icomoon/style.css index 9ecdcec48..f9f731bb8 100644 --- a/src/Squidex/app/theme/icomoon/style.css +++ b/src/Squidex/app/theme/icomoon/style.css @@ -1,10 +1,10 @@ @font-face { font-family: 'icomoon'; - src: url('fonts/icomoon.eot?sylov9'); - src: url('fonts/icomoon.eot?sylov9#iefix') format('embedded-opentype'), - url('fonts/icomoon.ttf?sylov9') format('truetype'), - url('fonts/icomoon.woff?sylov9') format('woff'), - url('fonts/icomoon.svg?sylov9#icomoon') format('svg'); + src: url('fonts/icomoon.eot?2yz9dj'); + src: url('fonts/icomoon.eot?2yz9dj#iefix') format('embedded-opentype'), + url('fonts/icomoon.ttf?2yz9dj') format('truetype'), + url('fonts/icomoon.woff?2yz9dj') format('woff'), + url('fonts/icomoon.svg?2yz9dj#icomoon') format('svg'); font-weight: normal; font-style: normal; } @@ -24,6 +24,9 @@ -moz-osx-font-smoothing: grayscale; } +.icon-time:before { + content: "\e8b5"; +} .icon-close:before { content: "\e5cd"; } diff --git a/src/Squidex/app/theme/theme.scss b/src/Squidex/app/theme/theme.scss index 69a0fe5e1..887576507 100644 --- a/src/Squidex/app/theme/theme.scss +++ b/src/Squidex/app/theme/theme.scss @@ -1,3 +1,4 @@ @import '_bootstrap.scss'; @import '_layout.scss'; -@import '_panels.scss'; \ No newline at end of file +@import '_panels.scss'; +@import '_history.scss'; \ No newline at end of file diff --git a/tests/Squidex.Infrastructure.Tests/CQRS/EnvelopeExtensionsTests.cs b/tests/Squidex.Infrastructure.Tests/CQRS/EnvelopeExtensionsTests.cs index 9302496c5..54039638f 100644 --- a/tests/Squidex.Infrastructure.Tests/CQRS/EnvelopeExtensionsTests.cs +++ b/tests/Squidex.Infrastructure.Tests/CQRS/EnvelopeExtensionsTests.cs @@ -63,14 +63,14 @@ namespace Squidex.Infrastructure.CQRS } [Fact] - public void Should_set_and_get_user() + public void Should_set_and_get_actor() { - var user = new UserToken("subject", "123"); + var actor = new RefToken("subject", "123"); - sut.SetUser(user); + sut.SetActor(actor); - Assert.Equal(user, sut.Headers.User()); - Assert.Equal(user, UserToken.Parse(sut.Headers["User"].ToString())); + Assert.Equal(actor, sut.Headers.Actor()); + Assert.Equal(actor, RefToken.Parse(sut.Headers["User"].ToString())); } [Fact] diff --git a/tests/Squidex.Infrastructure.Tests/CQRS/Events/EnrichWithUserProcessorTests.cs b/tests/Squidex.Infrastructure.Tests/CQRS/Events/EnrichWithActorProcessorTests.cs similarity index 64% rename from tests/Squidex.Infrastructure.Tests/CQRS/Events/EnrichWithUserProcessorTests.cs rename to tests/Squidex.Infrastructure.Tests/CQRS/Events/EnrichWithActorProcessorTests.cs index 07e34f213..eb0597b5e 100644 --- a/tests/Squidex.Infrastructure.Tests/CQRS/Events/EnrichWithUserProcessorTests.cs +++ b/tests/Squidex.Infrastructure.Tests/CQRS/Events/EnrichWithActorProcessorTests.cs @@ -12,11 +12,11 @@ using Xunit; namespace Squidex.Infrastructure.CQRS.Events { - public class EnrichWithUserProcessorTests + public class EnrichWithActorProcessorTests { - public sealed class MyUserCommand : IUserCommand + public sealed class MyActorCommand : IActorCommand { - public UserToken User { get; set; } + public RefToken Actor { get; set; } } public sealed class MyNormalCommand : ICommand @@ -27,10 +27,10 @@ namespace Squidex.Infrastructure.CQRS.Events { } - private readonly EnrichWithUserProcessor sut = new EnrichWithUserProcessor(); + private readonly EnrichWithActorProcessor sut = new EnrichWithActorProcessor(); [Fact] - public async Task Should_not_do_anything_if_not_user_command() + public async Task Should_not_do_anything_if_not_actor_command() { var envelope = new Envelope(new MyEvent()); @@ -42,14 +42,14 @@ namespace Squidex.Infrastructure.CQRS.Events [Fact] public async Task Should_attach_user_to_event_envelope() { - var user = new UserToken("subject", "123"); - var userCommand = new MyUserCommand { User = user }; + var actorToken = new RefToken("subject", "123"); + var actorCommand = new MyActorCommand { Actor = actorToken }; var envelope = new Envelope(new MyEvent()); - await sut.ProcessEventAsync(envelope, null, userCommand); + await sut.ProcessEventAsync(envelope, null, actorCommand); - Assert.Equal(user, envelope.Headers.User()); + Assert.Equal(actorToken, envelope.Headers.Actor()); } } } diff --git a/tests/Squidex.Infrastructure.Tests/UserTokenTests.cs b/tests/Squidex.Infrastructure.Tests/RefTokenTests.cs similarity index 67% rename from tests/Squidex.Infrastructure.Tests/UserTokenTests.cs rename to tests/Squidex.Infrastructure.Tests/RefTokenTests.cs index bb9615219..fcc8aab6f 100644 --- a/tests/Squidex.Infrastructure.Tests/UserTokenTests.cs +++ b/tests/Squidex.Infrastructure.Tests/RefTokenTests.cs @@ -1,5 +1,5 @@ // ========================================================================== -// UserTokenTests.cs +// RefTokenTests.cs // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex Group @@ -14,13 +14,13 @@ using Xunit; namespace Squidex.Infrastructure { - public class UserTokenTests + public class RefTokenTests { private static readonly JsonSerializerSettings serializerSettings = new JsonSerializerSettings(); - static UserTokenTests() + static RefTokenTests() { - serializerSettings.Converters.Add(new UserTokenConverter()); + serializerSettings.Converters.Add(new RefTokenConverter()); serializerSettings.NullValueHandling = NullValueHandling.Include; } @@ -31,13 +31,13 @@ namespace Squidex.Infrastructure [InlineData("user")] public void Should_throw_if_parsing_invalid_input(string input) { - Assert.Throws(() => UserToken.Parse(input)); + Assert.Throws(() => RefToken.Parse(input)); } [Fact] public void Should_instantiate_token() { - var token = new UserToken("client", "client1"); + var token = new RefToken("client", "client1"); Assert.Equal("client", token.Type); Assert.Equal("client1", token.Identifier); @@ -46,7 +46,7 @@ namespace Squidex.Infrastructure [Fact] public void Should_instantiate_token_and_lower_type() { - var token = new UserToken("Client", "client1"); + var token = new RefToken("Client", "client1"); Assert.Equal("client", token.Type); Assert.Equal("client1", token.Identifier); @@ -55,7 +55,7 @@ namespace Squidex.Infrastructure [Fact] public void Should_parse_user_token_from_string() { - var token = UserToken.Parse("client:client1"); + var token = RefToken.Parse("client:client1"); Assert.Equal("client", token.Type); Assert.Equal("client1", token.Identifier); @@ -64,7 +64,7 @@ namespace Squidex.Infrastructure [Fact] public void Should_parse_user_token_with_colon_in_identifier() { - var token = UserToken.Parse("client:client1:app"); + var token = RefToken.Parse("client:client1:app"); Assert.Equal("client", token.Type); Assert.Equal("client1:app", token.Identifier); @@ -73,7 +73,7 @@ namespace Squidex.Infrastructure [Fact] public void Should_convert_user_token_to_string() { - var token = UserToken.Parse("client:client1"); + var token = RefToken.Parse("client:client1"); Assert.Equal("client:client1", token.ToString()); } @@ -81,9 +81,9 @@ namespace Squidex.Infrastructure [Fact] public void Should_make_correct_equal_comparisons() { - var token1a = UserToken.Parse("client:client1"); - var token1b = UserToken.Parse("client:client1"); - var token2 = UserToken.Parse("client:client2"); + var token1a = RefToken.Parse("client:client1"); + var token1b = RefToken.Parse("client:client1"); + var token2 = RefToken.Parse("client:client2"); Assert.True(token1a.Equals(token1b)); @@ -93,10 +93,10 @@ namespace Squidex.Infrastructure [Fact] public void Should_make_correct_object_equal_comparisons() { - var token1a = UserToken.Parse("client:client1"); + var token1a = RefToken.Parse("client:client1"); - object token1b = UserToken.Parse("client:client1"); - object token2 = UserToken.Parse("client:client2"); + object token1b = RefToken.Parse("client:client1"); + object token2 = RefToken.Parse("client:client2"); Assert.True(token1a.Equals(token1b)); @@ -106,9 +106,9 @@ namespace Squidex.Infrastructure [Fact] public void Should_provide_correct_hash_codes() { - var token1a = UserToken.Parse("client:client1"); - var token1b = UserToken.Parse("client:client1"); - var token2 = UserToken.Parse("client:client2"); + var token1a = RefToken.Parse("client:client1"); + var token1b = RefToken.Parse("client:client1"); + var token2 = RefToken.Parse("client:client2"); Assert.Equal(token1a.GetHashCode(), token1b.GetHashCode()); @@ -118,9 +118,9 @@ namespace Squidex.Infrastructure [Fact] public void Should_serialize_and_deserialize_null_token() { - var input = Tuple.Create(null); + var input = Tuple.Create(null); var json = JsonConvert.SerializeObject(input, serializerSettings); - var output = JsonConvert.DeserializeObject>(json, serializerSettings); + var output = JsonConvert.DeserializeObject>(json, serializerSettings); Assert.Equal(output.Item1, input.Item1); } @@ -128,9 +128,9 @@ namespace Squidex.Infrastructure [Fact] public void Should_serialize_and_deserialize_valid_token() { - var input = Tuple.Create(UserToken.Parse("client:client1")); + var input = Tuple.Create(RefToken.Parse("client:client1")); var json = JsonConvert.SerializeObject(input, serializerSettings); - var output = JsonConvert.DeserializeObject>(json, serializerSettings); + var output = JsonConvert.DeserializeObject>(json, serializerSettings); Assert.Equal(output.Item1, input.Item1); } diff --git a/tests/Squidex.Write.Tests/Apps/AppCommandHandlerTests.cs b/tests/Squidex.Write.Tests/Apps/AppCommandHandlerTests.cs index bb76795f6..f4694796d 100644 --- a/tests/Squidex.Write.Tests/Apps/AppCommandHandlerTests.cs +++ b/tests/Squidex.Write.Tests/Apps/AppCommandHandlerTests.cs @@ -32,7 +32,7 @@ namespace Squidex.Write.Apps private readonly Mock userRepository = new Mock(); private readonly AppCommandHandler sut; private readonly AppDomainObject app; - private readonly UserToken subjectId = new UserToken("subject", Guid.NewGuid().ToString()); + private readonly RefToken subjectId = new RefToken("subject", Guid.NewGuid().ToString()); private readonly DateTime expiresUtc = DateTime.UtcNow.AddYears(1); private readonly Language language = Language.GetLanguage("de"); private readonly string contributorId = Guid.NewGuid().ToString(); @@ -50,7 +50,7 @@ namespace Squidex.Write.Apps [Fact] public async Task Create_should_throw_if_a_name_with_same_name_already_exists() { - var command = new CreateApp { Name = appName, AggregateId = Id, User = subjectId }; + var command = new CreateApp { Name = appName, AggregateId = Id, Actor = subjectId }; var context = new CommandContext(command); appRepository.Setup(x => x.FindAppByNameAsync(appName)).Returns(Task.FromResult(new Mock().Object)).Verifiable(); @@ -66,7 +66,7 @@ namespace Squidex.Write.Apps [Fact] public async Task Create_should_create_app_if_name_is_free() { - var command = new CreateApp { Name = appName, AggregateId = Id, User = subjectId }; + var command = new CreateApp { Name = appName, AggregateId = Id, Actor = subjectId }; var context = new CommandContext(command); appRepository.Setup(x => x.FindAppByNameAsync(appName)).Returns(Task.FromResult(null)).Verifiable(); @@ -241,7 +241,7 @@ namespace Squidex.Write.Apps private AppDomainObject CreateApp() { - app.Create(new CreateApp { Name = appName, User = subjectId }); + app.Create(new CreateApp { Name = appName, Actor = subjectId }); return app; } diff --git a/tests/Squidex.Write.Tests/Apps/AppDomainObjectTests.cs b/tests/Squidex.Write.Tests/Apps/AppDomainObjectTests.cs index 73b397f74..3ab392639 100644 --- a/tests/Squidex.Write.Tests/Apps/AppDomainObjectTests.cs +++ b/tests/Squidex.Write.Tests/Apps/AppDomainObjectTests.cs @@ -25,7 +25,7 @@ namespace Squidex.Write.Apps { private const string TestName = "app"; private readonly AppDomainObject sut; - private readonly UserToken user = new UserToken("subject", Guid.NewGuid().ToString()); + private readonly RefToken user = new RefToken("subject", Guid.NewGuid().ToString()); private readonly DateTime expiresUtc = DateTime.UtcNow.AddYears(1); private readonly string contributorId = Guid.NewGuid().ToString(); private readonly string clientSecret = Guid.NewGuid().ToString(); @@ -54,7 +54,7 @@ namespace Squidex.Write.Apps [Fact] public void Create_should_specify_name_and_owner() { - sut.Create(new CreateApp { Name = TestName, User = user }); + sut.Create(new CreateApp { Name = TestName, Actor = user }); Assert.Equal(TestName, sut.Name); @@ -410,7 +410,7 @@ namespace Squidex.Write.Apps private void CreateApp() { - sut.Create(new CreateApp { Name = TestName, User = user }); + sut.Create(new CreateApp { Name = TestName, Actor = user }); ((IAggregate)sut).ClearUncommittedEvents(); }