public UserMapping(RefToken initiator) { Guard.NotNull(initiator, nameof(initiator)); this.initiator = initiator; }
public Task StartBackupAsync(DomainId appId, RefToken actor) { var grain = grainFactory.GetGrain <IBackupGrain>(appId.ToString()); return(grain.BackupAsync(actor)); }
public async override Task RestoreEventAsync(Envelope <IEvent> @event, Guid appId, BackupReader reader, RefToken actor) { switch (@event.Payload) { case AppCreated appCreated: { appName = appCreated.Name; await ResolveUsersAsync(reader, actor); await ReserveAppAsync(appId); break; } case AppContributorAssigned contributorAssigned: { if (isActorAssigned) { contributorAssigned.ContributorId = MapUser(contributorAssigned.ContributorId, actor).Identifier; } else { isActorAssigned = true; contributorAssigned.ContributorId = actor.Identifier; } activeUsers.Add(contributorAssigned.ContributorId); break; } case AppContributorRemoved contributorRemoved: { contributorRemoved.ContributorId = MapUser(contributorRemoved.ContributorId, actor).Identifier; activeUsers.Remove(contributorRemoved.ContributorId); break; } } if (@event.Payload is SquidexEvent squidexEvent) { squidexEvent.Actor = MapUser(squidexEvent.Actor.Identifier, actor); } }
private RefToken MapUser(string userId, RefToken fallback) { return(userMapping.GetOrAdd(userId, fallback)); }
public async Task Should_retrieve_new_app(short numSilos, bool shouldBreak) { var env = new GrainEnvironment(); var cluster = new TestClusterBuilder(numSilos) .AddSiloBuilderConfigurator <Configurator>() .Build(); await cluster.DeployAsync(); try { var indexes = GetIndexes(shouldBreak, env, cluster); var appId = env.AppId; foreach (var index in indexes) { Assert.Null(await index.GetAppAsync(appId.Id, true)); Assert.Null(await index.GetAppByNameAsync(appId.Name, true)); } var creatorId = Guid.NewGuid().ToString(); var creatorToken = new RefToken(RefTokenType.Subject, creatorId); var createCommand = new CreateApp { Actor = creatorToken, AppId = appId.Id }; var commandContext = new CommandContext(createCommand, A.Fake <ICommandBus>()); var randomIndex = indexes[new Random().Next(3)]; await indexes[0].HandleAsync(commandContext, x => { if (x.Command is CreateApp command) { env.HandleCommand(command); } x.Complete(true); return(Task.CompletedTask); }); foreach (var index in indexes) { var appById = await index.GetAppAsync(appId.Id, true); var appByName = await index.GetAppByNameAsync(appId.Name, true); if (index == randomIndex || !shouldBreak) { Assert.True(appById?.Contributors.ContainsKey(creatorId)); Assert.True(appByName?.Contributors.ContainsKey(creatorId)); } else { Assert.False(appById?.Contributors.ContainsKey(creatorId)); Assert.False(appByName?.Contributors.ContainsKey(creatorId)); } } } finally { await Task.WhenAny(Task.Delay(2000), cluster.StopAllSilosAsync()); } }
protected void On(AppPlanChanged @event) { planId = @event.PlanId; planOwner = string.IsNullOrWhiteSpace(planId) ? null : @event.Actor; }
private void Process(BackupJob job, RefToken actor, CancellationToken ct) { ProcessAsync(job, actor, ct).Forget(); }
private static RefToken Client(string identifier) { return(RefToken.Client(identifier)); }
private static RefToken Subject(string identifier) { return(RefToken.User(identifier)); }
private static AppLanguageAdded CreateInitialLanguage(NamedId <Guid> appId, RefToken actor) { return(new AppLanguageAdded { AppId = appId, Actor = actor, Language = Language.EN }); }
private static AppContributorAssigned CreateInitialOwner(NamedId <Guid> appId, RefToken actor) { return(new AppContributorAssigned { AppId = appId, Actor = actor, ContributorId = actor.Identifier, Permission = AppContributorPermission.Owner }); }
private static AppPatternAdded CreateInitialPattern(NamedId <Guid> appId, RefToken actor, Guid id, AppPattern p) { return(new AppPatternAdded { AppId = appId, Actor = actor, PatternId = id, Name = p.Name, Pattern = p.Pattern, Message = p.Message }); }
private static AppCreated CreateInitalEvent(NamedId <Guid> appId, RefToken actor, string name) { return(new AppCreated { AppId = appId, Actor = actor, Name = name }); }
public async Task UpdateAsync() { var apps = new Dictionary <NamedId <DomainId>, Dictionary <DomainId, (string Name, string Pattern, string?Message)> >(); await eventStore.QueryAsync(storedEvent => { var @event = eventDataFormatter.ParseIfKnown(storedEvent); if (@event != null) { switch (@event.Payload) { case AppPatternAdded patternAdded: { var patterns = apps.GetOrAddNew(patternAdded.AppId); patterns[patternAdded.PatternId] = (patternAdded.Name, patternAdded.Pattern, patternAdded.Message); break; } case AppPatternUpdated patternUpdated: { var patterns = apps.GetOrAddNew(patternUpdated.AppId); patterns[patternUpdated.PatternId] = (patternUpdated.Name, patternUpdated.Pattern, patternUpdated.Message); break; } case AppPatternDeleted patternDeleted: { var patterns = apps.GetOrAddNew(patternDeleted.AppId); patterns.Remove(patternDeleted.PatternId); break; } case AppArchived appArchived: { apps.Remove(appArchived.AppId); break; } } } return(Task.CompletedTask); }, "^app\\-"); var actor = RefToken.Client("Migrator"); foreach (var(appId, patterns) in apps) { if (patterns.Count > 0) { var settings = new AppSettings { Patterns = patterns.Values.Select(x => new Pattern(x.Name, x.Pattern) { Message = x.Message }).ToReadOnlyCollection() }; await commandBus.PublishAsync(new UpdateAppSettings { AppId = appId, Settings = settings, FromRule = true, Actor = actor }); } } }
public static IEnrichedContentEntity Create(DomainId id, DomainId refId = default, DomainId assetId = default, ContentData?data = null) { var now = SystemClock.Instance.GetCurrentInstant(); data ??= new ContentData() .AddField("my-localized-string", new ContentFieldData() .AddLocalized("de-DE", "de-DE")) .AddField("my-string", new ContentFieldData() .AddInvariant(null)) .AddField("my-assets", new ContentFieldData() .AddInvariant(JsonValue.Array(assetId.ToString()))) .AddField("my-number", new ContentFieldData() .AddInvariant(1.0)) .AddField("my-boolean", new ContentFieldData() .AddInvariant(true)) .AddField("my-datetime", new ContentFieldData() .AddInvariant(now)) .AddField("my-tags", new ContentFieldData() .AddInvariant(JsonValue.Array("tag1", "tag2"))) .AddField("my-references", new ContentFieldData() .AddInvariant(JsonValue.Array(refId.ToString()))) .AddField("my-union", new ContentFieldData() .AddInvariant(JsonValue.Array(refId.ToString()))) .AddField("my-geolocation", new ContentFieldData() .AddInvariant( JsonValue.Object() .Add("latitude", 10) .Add("longitude", 20))) .AddField("my-component", new ContentFieldData() .AddInvariant( JsonValue.Object() .Add(Component.Discriminator, TestSchemas.Ref1.Id) .Add("schemaRef1Field", "Component1"))) .AddField("my-components", new ContentFieldData() .AddInvariant( JsonValue.Array( JsonValue.Object() .Add(Component.Discriminator, TestSchemas.Ref1.Id) .Add("schemaRef1Field", "Component1"), JsonValue.Object() .Add(Component.Discriminator, TestSchemas.Ref2.Id) .Add("schemaRef2Field", "Component2")))) .AddField("my-json", new ContentFieldData() .AddInvariant( JsonValue.Object() .Add("value", 1))) .AddField("my-array", new ContentFieldData() .AddInvariant(JsonValue.Array( JsonValue.Object() .Add("nested-number", 10) .Add("nested-boolean", true), JsonValue.Object() .Add("nested-number", 20) .Add("nested-boolean", false)))); var content = new ContentEntity { Id = id, AppId = TestApp.DefaultId, Version = 1, Created = now, CreatedBy = RefToken.User("user1"), LastModified = now, LastModifiedBy = RefToken.Client("client1"), Data = data, SchemaId = TestSchemas.DefaultId, Status = Status.Draft, StatusColor = "red" }; return(content); }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { return(reader.TokenType == JsonToken.Null ? null : RefToken.Parse((string)reader.Value)); }
private static AppContributorAssigned CreateInitialOwner(RefToken actor) { return(new AppContributorAssigned { ContributorId = actor.Identifier, Permission = AppContributorPermission.Owner }); }
public override Task <bool> RestoreEventAsync(Envelope <IEvent> @event, Guid appId, BackupReader reader, RefToken actor) { switch (@event.Payload) { case RuleCreated ruleCreated: ruleIds.Add(ruleCreated.RuleId); break; case RuleDeleted ruleDeleted: ruleIds.Remove(ruleDeleted.RuleId); break; } return(TaskHelper.True); }
protected IEnrichedContentEntity CreateContent(Guid id, Guid refId, Guid assetId, NamedContentData?data = null, NamedContentData?dataDraft = null) { var now = SystemClock.Instance.GetCurrentInstant(); data ??= new NamedContentData() .AddField("my-string", new ContentFieldData() .AddValue("de", "value")) .AddField("my-assets", new ContentFieldData() .AddValue("iv", JsonValue.Array(assetId.ToString()))) .AddField("my-number", new ContentFieldData() .AddValue("iv", 1.0)) .AddField("my_number", new ContentFieldData() .AddValue("iv", 2.0)) .AddField("my-boolean", new ContentFieldData() .AddValue("iv", true)) .AddField("my-datetime", new ContentFieldData() .AddValue("iv", now)) .AddField("my-tags", new ContentFieldData() .AddValue("iv", JsonValue.Array("tag1", "tag2"))) .AddField("my-references", new ContentFieldData() .AddValue("iv", JsonValue.Array(refId.ToString()))) .AddField("my-union", new ContentFieldData() .AddValue("iv", JsonValue.Array(refId.ToString()))) .AddField("my-geolocation", new ContentFieldData() .AddValue("iv", JsonValue.Object().Add("latitude", 10).Add("longitude", 20))) .AddField("my-json", new ContentFieldData() .AddValue("iv", JsonValue.Object().Add("value", 1))) .AddField("my-localized", new ContentFieldData() .AddValue("de-DE", "de-DE")) .AddField("my-array", new ContentFieldData() .AddValue("iv", JsonValue.Array( JsonValue.Object() .Add("nested-boolean", true) .Add("nested-number", 10) .Add("nested_number", 11), JsonValue.Object() .Add("nested-boolean", false) .Add("nested-number", 20) .Add("nested_number", 21)))); var content = new ContentEntity { Id = id, Version = 1, Created = now, CreatedBy = new RefToken(RefTokenType.Subject, "user1"), LastModified = now, LastModifiedBy = new RefToken(RefTokenType.Subject, "user2"), Data = data, DataDraft = dataDraft !, SchemaId = schemaId, Status = Status.Draft, StatusColor = "red" }; return(content); }
public override async Task <bool> RestoreEventAsync(Envelope <IEvent> @event, Guid appId, BackupReader reader, RefToken actor) { switch (@event.Payload) { case AssetCreated assetCreated: await ReadAssetAsync(assetCreated.AssetId, assetCreated.FileVersion, reader); break; case AssetUpdated assetUpdated: await ReadAssetAsync(assetUpdated.AssetId, assetUpdated.FileVersion, reader); break; } return(true); }
private async Task ProcessAsync(BackupJob job, RefToken actor, CancellationToken ct) { var handlers = CreateHandlers(); var lastTimestamp = job.Started; try { using (var stream = backupArchiveLocation.OpenStream(job.Id)) { using (var writer = await backupArchiveLocation.OpenWriterAsync(stream)) { var userMapping = new UserMapping(actor); var context = new BackupContext(Key, userMapping, writer); await eventStore.QueryAsync(async storedEvent => { var @event = eventDataFormatter.Parse(storedEvent.Data); if (@event.Payload is SquidexEvent squidexEvent) { context.UserMapping.Backup(squidexEvent.Actor); } foreach (var handler in handlers) { await handler.BackupEventAsync(@event, context); } writer.WriteEvent(storedEvent); job.HandledEvents = writer.WrittenEvents; job.HandledAssets = writer.WrittenAttachments; lastTimestamp = await WritePeriodically(lastTimestamp); }, SquidexHeaders.AppId, Key.ToString(), null, ct); foreach (var handler in handlers) { ct.ThrowIfCancellationRequested(); await handler.BackupAsync(context); } foreach (var handler in handlers) { ct.ThrowIfCancellationRequested(); await handler.CompleteBackupAsync(context); } await userMapping.StoreAsync(writer, userResolver); } stream.Position = 0; ct.ThrowIfCancellationRequested(); await backupArchiveStore.UploadAsync(job.Id, stream, ct); } job.Status = JobStatus.Completed; } catch (OperationCanceledException) { await RemoveAsync(job); } catch (Exception ex) { log.LogError(ex, job.Id.ToString(), (ctx, w) => w .WriteProperty("action", "makeBackup") .WriteProperty("status", "failed") .WriteProperty("backupId", ctx)); job.Status = JobStatus.Failed; } finally { job.Stopped = clock.GetCurrentInstant(); await state.WriteAsync(); currentTaskToken = null; currentJob = null; } }
public async Task Should_replace_asset_url_in_content() { var me = RefToken.User("123"); var newAssetsUrl = "https://new.squidex.com/api/assets"; var newAssetsUrlApp = "https://old.squidex.com/api/assets/my-new-app"; var oldAssetsUrl = "https://old.squidex.com/api/assets"; var oldAssetsUrlApp = "https://old.squidex.com/api/assets/my-old-app"; var reader = A.Fake <IBackupReader>(); A.CallTo(() => urlGenerator.AssetContentBase()) .Returns(newAssetsUrl); A.CallTo(() => urlGenerator.AssetContentBase(appId.Name)) .Returns(newAssetsUrlApp); A.CallTo(() => reader.ReadJsonAsync <BackupContents.Urls>(A <string> ._, ct)) .Returns(new BackupContents.Urls { Assets = oldAssetsUrl, AssetsApp = oldAssetsUrlApp }); var data = new ContentData() .AddField("asset", new ContentFieldData() .AddLocalized("en", $"Asset: {oldAssetsUrlApp}/my-asset.jpg.") .AddLocalized("it", $"Asset: {oldAssetsUrl}/my-asset.jpg.")) .AddField("assetsInArray", new ContentFieldData() .AddLocalized("iv", JsonValue.Array( $"Asset: {oldAssetsUrlApp}/my-asset.jpg."))) .AddField("assetsInObj", new ContentFieldData() .AddLocalized("iv", JsonValue.Object() .Add("asset", $"Asset: {oldAssetsUrlApp}/my-asset.jpg."))); var updateData = new ContentData() .AddField("asset", new ContentFieldData() .AddLocalized("en", $"Asset: {newAssetsUrlApp}/my-asset.jpg.") .AddLocalized("it", $"Asset: {newAssetsUrl}/my-asset.jpg.")) .AddField("assetsInArray", new ContentFieldData() .AddLocalized("iv", JsonValue.Array( $"Asset: {newAssetsUrlApp}/my-asset.jpg."))) .AddField("assetsInObj", new ContentFieldData() .AddLocalized("iv", JsonValue.Object() .Add("asset", $"Asset: {newAssetsUrlApp}/my-asset.jpg."))); var context = new RestoreContext(appId.Id, new UserMapping(me), reader, DomainId.NewGuid()); await sut.RestoreEventAsync(Envelope.Create(new AppCreated { Name = appId.Name }), context, ct); await sut.RestoreEventAsync(Envelope.Create(new ContentUpdated { Data = data }), context, ct); Assert.Equal(updateData, data); }
public override async Task <bool> RestoreEventAsync(Envelope <IEvent> @event, Guid appId, BackupReader reader, RefToken actor) { switch (@event.Payload) { case AppCreated appCreated: { appName = appCreated.Name; await ResolveUsersAsync(reader); await ReserveAppAsync(appId); break; } case AppContributorAssigned contributorAssigned: { if (!userMapping.TryGetValue(contributorAssigned.ContributorId, out var user) || user.Equals(actor)) { return(false); } contributorAssigned.ContributorId = user.Identifier; contributors.Add(contributorAssigned.ContributorId); break; } case AppContributorRemoved contributorRemoved: { if (!userMapping.TryGetValue(contributorRemoved.ContributorId, out var user) || user.Equals(actor)) { return(false); } contributorRemoved.ContributorId = user.Identifier; contributors.Remove(contributorRemoved.ContributorId); break; } } if (@event.Payload is SquidexEvent squidexEvent) { squidexEvent.Actor = MapUser(squidexEvent.Actor.Identifier, actor); } return(true); }
public static IEnrichedContentEntity Create(NamedId <DomainId> appId, NamedId <DomainId> schemaId, DomainId id, DomainId refId, DomainId assetId, ContentData?data = null) { var now = SystemClock.Instance.GetCurrentInstant(); data ??= new ContentData() .AddField("my-string", new ContentFieldData() .AddLocalized("de", "value")) .AddField("my-string2", new ContentFieldData() .AddInvariant(null)) .AddField("my-assets", new ContentFieldData() .AddInvariant(JsonValue.Array(assetId.ToString()))) .AddField("2_numbers", new ContentFieldData() .AddInvariant(22)) .AddField("2-numbers", new ContentFieldData() .AddInvariant(23)) .AddField("content", new ContentFieldData() .AddInvariant(24)) .AddField("my-number", new ContentFieldData() .AddInvariant(1.0)) .AddField("my_number", new ContentFieldData() .AddInvariant(null)) .AddField("my-boolean", new ContentFieldData() .AddInvariant(true)) .AddField("my-datetime", new ContentFieldData() .AddInvariant(now)) .AddField("my-tags", new ContentFieldData() .AddInvariant(JsonValue.Array("tag1", "tag2"))) .AddField("my-references", new ContentFieldData() .AddInvariant(JsonValue.Array(refId.ToString()))) .AddField("my-union", new ContentFieldData() .AddInvariant(JsonValue.Array(refId.ToString()))) .AddField("my-geolocation", new ContentFieldData() .AddInvariant(JsonValue.Object().Add("latitude", 10).Add("longitude", 20))) .AddField("my-json", new ContentFieldData() .AddInvariant(JsonValue.Object().Add("value", 1))) .AddField("my-localized", new ContentFieldData() .AddLocalized("de-DE", "de-DE")) .AddField("my-array", new ContentFieldData() .AddInvariant(JsonValue.Array( JsonValue.Object() .Add("nested-number", 10) .Add("nested_number", null) .Add("nested-boolean", true), JsonValue.Object() .Add("nested-number", 20) .Add("nested_number", null) .Add("nested-boolean", false)))); var content = new ContentEntity { Id = id, AppId = appId, Version = 1, Created = now, CreatedBy = RefToken.User("user1"), LastModified = now, LastModifiedBy = RefToken.User("user2"), Data = data, SchemaId = schemaId, Status = Status.Draft, StatusColor = "red" }; return(content); }
public virtual Task <bool> RestoreEventAsync(Envelope <IEvent> @event, Guid appId, BackupReader reader, RefToken actor) { return(TaskHelper.True); }
public override Task <bool> RestoreEventAsync(Envelope <IEvent> @event, Guid appId, BackupReader reader, RefToken actor) { switch (@event.Payload) { case ContentCreated contentCreated: contentIdsBySchemaId.GetOrAddNew(contentCreated.SchemaId.Id).Add(contentCreated.ContentId); break; case SchemaDeleted schemaDeleted: contentIdsBySchemaId.Remove(schemaDeleted.SchemaId.Id); break; } return(TaskHelper.True); }
public Task StartRestoreAsync(RefToken actor, Uri url, string?newAppName) { var grain = grainFactory.GetGrain <IRestoreGrain>(SingleGrain.Id); return(grain.RestoreAsync(url, actor, newAppName)); }
public static ScheduleJob Build(Status status, RefToken scheduledBy, Instant dueTime) { return(new ScheduleJob(Guid.NewGuid(), status, scheduledBy, dueTime)); }