public async Task <IActionResult> GetContents(string app, string name, [FromQuery] bool archived = false, [FromQuery] string ids = null) { HashSet <Guid> idsList = null; if (!string.IsNullOrWhiteSpace(ids)) { idsList = new HashSet <Guid>(); foreach (var id in ids.Split(',')) { if (Guid.TryParse(id, out var guid)) { idsList.Add(guid); } } } var isFrontendClient = User.IsFrontendClient(); var result = idsList?.Count > 0 ? await contentQuery.QueryAsync(App, name, User, archived, idsList) : await contentQuery.QueryAsync(App, name, User, archived, Request.QueryString.ToString()); var response = new ContentsDto { Total = result.Total, Items = result.Take(200).Select(ContentDto.FromContent).ToArray() }; Response.Headers["Surrogate-Key"] = string.Join(" ", response.Items.Select(x => x.Id)); return(Ok(response)); }
public async Task Should_upsert_content_with_custom_id() { var(id, data, query) = CreateTestData(true); A.CallTo(() => contentQuery.QueryAsync(requestContext, A <string> ._, A <Q> .That.Matches(x => x.JsonQuery == query))) .Returns(ResultList.CreateFrom(1, CreateContent(id))); var command = new BulkUpdateContents { Jobs = new[] { new BulkUpdateJob { Type = BulkUpdateType.Upsert, Data = data, Query = query } }, SchemaId = schemaId }; var context = new CommandContext(command, commandBus); await sut.HandleAsync(context); var result = context.Result <BulkUpdateResult>(); Assert.Single(result); Assert.Equal(1, result.Count(x => x.ContentId != default && x.Exception == null)); A.CallTo(() => commandBus.PublishAsync( A <UpsertContent> .That.Matches(x => x.Data == data && x.ContentId == id))) .MustHaveHappenedOnceExactly(); }
public async Task Should_add_referenced_id_as_dependency() { var ref1_1 = CreateRefContent(Guid.NewGuid(), "ref1_1", 13); var ref1_2 = CreateRefContent(Guid.NewGuid(), "ref1_2", 17); var ref2_1 = CreateRefContent(Guid.NewGuid(), "ref2_1", 23); var ref2_2 = CreateRefContent(Guid.NewGuid(), "ref2_2", 29); var source = new IContentEntity[] { CreateContent(new[] { ref1_1.Id }, new[] { ref2_1.Id }), CreateContent(new[] { ref1_2.Id }, new[] { ref2_2.Id }) }; A.CallTo(() => contentQuery.QueryAsync(A <Context> .Ignored, A <IReadOnlyList <Guid> > .That.Matches(x => x.Count == 4))) .Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2)); var enriched = await sut.EnrichAsync(source, requestContext); var enriched1 = enriched.ElementAt(0); var enriched2 = enriched.ElementAt(1); Assert.Contains(refSchemaId1.Id.ToString(), enriched1.CacheDependencies); Assert.Contains(refSchemaId2.Id.ToString(), enriched1.CacheDependencies); Assert.Contains(refSchemaId1.Id.ToString(), enriched2.CacheDependencies); Assert.Contains(refSchemaId2.Id.ToString(), enriched2.CacheDependencies); }
public async Task <IResultList <IContentEntity> > QueryContentsAsync(string schemaIdOrName, string query) { var result = await contentQuery.QueryAsync(context.WithSchemaName(schemaIdOrName), query); foreach (var content in result) { cachedContents[content.Id] = content; } return(result); }
public virtual async Task <IResultList <IContentEntity> > QueryContentsAsync(string schemaIdOrName, string query) { var result = await contentQuery.QueryAsync(context, schemaIdOrName, Q.Empty.WithODataQuery(query)); foreach (var content in result) { cachedContents[content.Id] = content; } return(result); }
public async Task <IResultList <IContentEntity> > QueryContentsAsync(string schemaIdOrName, string query) { var result = await contentQuery.QueryAsync(app, schemaIdOrName, user, false, query); foreach (var content in result.Contents) { cachedContents[content.Id] = content; } return(result.Contents); }
public async Task <IActionResult> GetAllContents(string app, [FromQuery] string ids) { var contents = await contentQuery.QueryAsync(Context, Q.Empty.WithIds(ids).Ids); var response = Deferred.AsyncResponse(() => { return(ContentsDto.FromContentsAsync(contents, Context, this, null, contentWorkflow)); }); return(Ok(response)); }
public async Task Should_not_invoke_context_query_if_no_id_found() { var ctx = ContextWithPermissions(schemaId1, schemaId2); A.CallTo(() => contentIndex.SearchAsync(ctx.App, A <TextQuery> .That.Matches(x => x.Text == "query~"), ctx.Scope())) .Returns(new List <DomainId>()); var result = await sut.SearchAsync("query", ctx, default); Assert.Empty(result); A.CallTo(() => contentQuery.QueryAsync(ctx, A <Q> ._, A <CancellationToken> ._)) .MustNotHaveHappened(); }
public async Task Should_enrich_with_reference_data() { var ref1_1 = CreateRefContent(Guid.NewGuid(), "ref1_1", 13); var ref1_2 = CreateRefContent(Guid.NewGuid(), "ref1_2", 17); var ref2_1 = CreateRefContent(Guid.NewGuid(), "ref2_1", 23); var ref2_2 = CreateRefContent(Guid.NewGuid(), "ref2_2", 29); var source = new IContentEntity[] { CreateContent(new Guid[] { ref1_1.Id }, new Guid[] { ref2_1.Id }), CreateContent(new Guid[] { ref1_2.Id }, new Guid[] { ref2_2.Id }) }; A.CallTo(() => contentQuery.QueryAsync(A <Context> .Ignored, A <IReadOnlyList <Guid> > .That.Matches(x => x.Count == 4))) .Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2)); var enriched = await sut.EnrichAsync(source, requestContext); Assert.Equal( new NamedContentData() .AddField("ref1", new ContentFieldData() .AddJsonValue("iv", JsonValue.Object() .Add("en", "ref1_1, 13") .Add("de", "ref1_1, 13"))) .AddField("ref2", new ContentFieldData() .AddJsonValue("iv", JsonValue.Object() .Add("en", "ref2_1, 23") .Add("de", "ref2_1, 23"))), enriched.ElementAt(0).ReferenceData); Assert.Equal( new NamedContentData() .AddField("ref1", new ContentFieldData() .AddJsonValue("iv", JsonValue.Object() .Add("en", "ref1_2, 17") .Add("de", "ref1_2, 17"))) .AddField("ref2", new ContentFieldData() .AddJsonValue("iv", JsonValue.Object() .Add("en", "ref2_2, 29") .Add("de", "ref2_2, 29"))), enriched.ElementAt(1).ReferenceData); }
public async Task Should_not_invoke_context_query_if_no_id_found() { var ctx = ContextWithPermissions(schemaId1, schemaId2); A.CallTo(() => contentIndex.SearchAsync("query~", ctx.App, A <SearchFilter> ._, ctx.Scope())) .Returns(new List <Guid>()); var result = await sut.SearchAsync("query", ctx); Assert.Empty(result); A.CallTo(() => contentQuery.QueryAsync(ctx, A <IReadOnlyList <Guid> > ._)) .MustNotHaveHappened(); }
private (ScriptVars, IContentEntity[]) SetupReferenceVars(int count) { var references = Enumerable.Range(0, count).Select((x, i) => CreateReference(i + 1)).ToArray(); var referenceIds = references.Select(x => x.Id); var user = new ClaimsPrincipal(); var data = new ContentData() .AddField("references", new ContentFieldData() .AddInvariant(JsonValue.Array(referenceIds))); A.CallTo(() => contentQuery.QueryAsync( A <Context> .That.Matches(x => x.App.Id == appId.Id && x.User == user), A <Q> .That.HasIds(referenceIds), A <CancellationToken> ._)) .Returns(ResultList.CreateFrom(2, references)); var vars = new ScriptVars { ["appId"] = appId.Id, ["data"] = data, ["dataOld"] = null, ["user"] = user }; return(vars, references); }
public async Task <IActionResult> GetAllContents(string app, [FromQuery] string ids) { var context = Context(); var contents = await contentQuery.QueryAsync(context, Q.Empty.WithIds(ids).Ids); var response = await ContentsDto.FromContentsAsync(contents, context, this, null, contentWorkflow); if (controllerOptions.Value.EnableSurrogateKeys && response.Items.Length <= controllerOptions.Value.MaxItemsForSurrogateKeys) { Response.Headers["Surrogate-Key"] = response.ToSurrogateKeys(); } Response.Headers[HeaderNames.ETag] = response.ToEtag(); return(Ok(response)); }
public async Task <SearchResults> SearchAsync(string query, Context context) { var result = new SearchResults(); var searchFilter = await CreateSearchFilterAsync(context); if (searchFilter == null) { return(result); } var ids = await contentTextIndexer.SearchAsync($"{query}~", context.App, searchFilter, context.Scope()); if (ids == null || ids.Count == 0) { return(result); } var appId = context.App.NamedId(); var contents = await contentQuery.QueryAsync(context, ids); foreach (var content in contents) { var url = urlGenerator.ContentUI(appId, content.SchemaId, content.Id); var name = FormatName(content, context.App.LanguagesConfig.Master); result.Add(name, SearchResultType.Content, url, content.SchemaDisplayName); } return(result); }
private static async Task <IContentEntity?> ResolveContentAsync(IAppProvider appProvider, IContentQueryService contentQuery, DomainId appId, FluidValue id) { var app = await appProvider.GetAppAsync(appId); if (app == null) { return(null); } var domainId = DomainId.Create(id.ToStringValue()); var domainIds = new List <DomainId> { domainId }; var requestContext = Context.Admin(app).Clone(b => b .WithUnpublished() .WithoutTotal()); var contents = await contentQuery.QueryAsync(requestContext, Q.Empty.WithIds(domainIds)); var content = contents.FirstOrDefault(); return(content); }
private async Task <DomainId[]> FindIdAsync(BulkTask task) { var id = task.CommandJob.Id; if (id != null) { return(new[] { id.Value }); } if (task.CommandJob.Query != null) { task.CommandJob.Query.Take = task.CommandJob.ExpectedCount; var existing = await contentQuery.QueryAsync(contextProvider.Context, task.Schema, Q.Empty.WithJsonQuery(task.CommandJob.Query)); if (existing.Total > task.CommandJob.ExpectedCount) { throw new DomainException(T.Get("contents.bulkInsertQueryNotUnique")); } if (existing.Count == 0 && task.CommandJob.Type == BulkUpdateContentType.Upsert) { return(new[] { DomainId.NewGuid() }); } return(existing.Select(x => x.Id).ToArray()); } if (task.CommandJob.Type == BulkUpdateContentType.Create || task.CommandJob.Type == BulkUpdateContentType.Upsert) { return(new[] { DomainId.NewGuid() }); } return(Array.Empty <DomainId>()); }
public async Task <IActionResult> GetAllContents(string app, [FromQuery] string ids) { var contents = await contentQuery.QueryAsync(Context, Q.Empty.WithIds(ids).Ids); var response = Deferred.AsyncResponse(() => { return(ContentsDto.FromContentsAsync(contents, Context, this, null, contentWorkflow)); }); if (ShouldProvideSurrogateKeys(contents)) { Response.Headers["Surrogate-Key"] = contents.ToSurrogateKeys(); } Response.Headers[HeaderNames.ETag] = contents.ToEtag(); return(Ok(response)); }
public async Task Should_throw_exception_when_query_resolves_multiple_contents() { var requestContext = SetupContext(Permissions.AppContentsUpdateOwn); var(id, _, query) = CreateTestData(true); A.CallTo(() => contentQuery.QueryAsync(requestContext, A <string> ._, A <Q> .That.Matches(x => x.JsonQuery == query))) .Returns(ResultList.CreateFrom(2, CreateContent(id), CreateContent(id))); var command = BulkCommand(BulkUpdateType.ChangeStatus, query); var result = await PublishAsync(command); Assert.Single(result, x => x.JobIndex == 0 && x.ContentId == null && x.Exception is DomainException); A.CallTo(() => commandBus.PublishAsync(A <ICommand> ._)) .MustNotHaveHappened(); }
public async Task <IActionResult> GetContents(string app, string name, [FromQuery] bool archived = false, [FromQuery] string ids = null) { HashSet <Guid> idsList = null; if (!string.IsNullOrWhiteSpace(ids)) { idsList = new HashSet <Guid>(); foreach (var id in ids.Split(',')) { if (Guid.TryParse(id, out var guid)) { idsList.Add(guid); } } } var isFrontendClient = User.IsFrontendClient(); var result = idsList?.Count > 0 ? await contentQuery.QueryAsync(App, name, User, archived, idsList) : await contentQuery.QueryAsync(App, name, User, archived, Request.QueryString.ToString()); var response = new ContentsDto { Total = result.Contents.Total, Items = result.Contents.Take(200).Select(item => { var itemModel = SimpleMapper.Map(item, new ContentDto()); if (item.Data != null) { itemModel.Data = item.Data.ToApiModel(result.Schema.SchemaDef, App.LanguagesConfig, !isFrontendClient); } return(itemModel); }).ToArray() }; Response.Headers["Surrogate-Key"] = string.Join(" ", response.Items.Select(x => x.Id)); return(Ok(response)); }
public async Task Should_resolve_references_in_loop() { var referenceId1 = DomainId.NewGuid(); var reference1 = CreateReference(referenceId1, 1); var referenceId2 = DomainId.NewGuid(); var reference2 = CreateReference(referenceId1, 2); var @event = new EnrichedContentEvent { Data = new NamedContentData() .AddField("references", new ContentFieldData() .AddJsonValue(JsonValue.Array(referenceId1, referenceId2))), AppId = appId }; A.CallTo(() => contentQuery.QueryAsync(A <Context> ._, A <IReadOnlyList <DomainId> > .That.Contains(referenceId1))) .Returns(ResultList.CreateFrom(1, reference1)); A.CallTo(() => contentQuery.QueryAsync(A <Context> ._, A <IReadOnlyList <DomainId> > .That.Contains(referenceId2))) .Returns(ResultList.CreateFrom(1, reference2)); var vars = new TemplateVars { ["event"] = @event }; var template = @" {% for id in event.data.references.iv %} {% reference 'ref', id %} Text: {{ ref.data.field1.iv }} {{ ref.data.field2.iv }} {% endfor %} "; var expected = @" Text: Hello 1 World 1 Text: Hello 2 World 2 "; var result = await sut.RenderAsync(template, vars); Assert.Equal(expected, result); }
public async Task <IActionResult> GetAllContents(string app, [FromQuery] string ids, [FromQuery] string status = null) { var context = Context().WithFrontendStatus(status); var result = await contentQuery.QueryAsync(context, Q.Empty.WithIds(ids).Ids); var response = new ContentsDto { Total = result.Count, Items = result.Take(200).Select(x => ContentDto.FromContent(x, context)).ToArray() }; if (controllerOptions.Value.EnableSurrogateKeys && response.Items.Length <= controllerOptions.Value.MaxItemsForSurrogateKeys) { Response.Headers["Surrogate-Key"] = response.Items.ToSurrogateKeys(); } Response.Headers[HeaderNames.ETag] = response.Items.ToManyEtag(); return(Ok(response)); }
public async Task Should_resolve_reference() { var referenceId1 = DomainId.NewGuid(); var reference1 = CreateReference(referenceId1, 1); var user = new ClaimsPrincipal(); var data = new ContentData() .AddField("references", new ContentFieldData() .AddInvariant(JsonValue.Array(referenceId1))); A.CallTo(() => contentQuery.QueryAsync( A<Context>.That.Matches(x => x.App.Id == appId.Id && x.User == user), A<Q>.That.HasIds(referenceId1), A<CancellationToken>._)) .Returns(ResultList.CreateFrom(1, reference1)); var vars = new ScriptVars { ["appId"] = appId.Id, ["data"] = data, ["dataOld"] = null, ["user"] = user }; var expected = @" Text: Hello 1 World 1 "; var script = @" getReference(data.references.iv[0], function (references) { var result1 = `Text: ${references[0].data.field1.iv} ${references[0].data.field2.iv}`; complete(`${result1}`); })"; var result = (await sut.ExecuteAsync(vars, script)).ToString(); Assert.Equal(Cleanup(expected), Cleanup(result)); }
public async Task <IActionResult> GetContents(string app, string name, [FromQuery] bool archived = false, [FromQuery] string ids = null) { HashSet <Guid> idsList = null; if (!string.IsNullOrWhiteSpace(ids)) { idsList = new HashSet <Guid>(); foreach (var id in ids.Split(',')) { if (Guid.TryParse(id, out var guid)) { idsList.Add(guid); } } } var context = Context().WithSchemaName(name).WithArchived(archived); var result = idsList?.Count > 0 ? await contentQuery.QueryAsync(context, idsList) : await contentQuery.QueryAsync(context, Request.QueryString.ToString()); var response = new ContentsDto { Total = result.Total, Items = result.Take(200).Select(x => ContentDto.FromContent(x, context)).ToArray() }; var options = controllerOptions.Value; if (options.EnableSurrogateKeys && response.Items.Length <= options.MaxItemsForSurrogateKeys) { Response.Headers["Surrogate-Key"] = string.Join(" ", response.Items.Select(x => x.Id)); } return(Ok(response)); }
public virtual async Task <IResultList <IEnrichedContentEntity> > QueryContentsAsync(string schemaIdOrName, Q q) { IResultList <IEnrichedContentEntity> contents; await maxRequests.WaitAsync(); try { contents = await contentQuery.QueryAsync(Context, schemaIdOrName, q); } finally { maxRequests.Release(); } foreach (var content in contents) { cachedContents[content.Id] = content; } return(contents); }
public async Task Should_throw_exception_if_query_resolves_multiple_contents() { var requestContext = SetupContext(Permissions.AppContentsUpdateOwn); var(id, _, query) = CreateTestData(true); A.CallTo(() => contentQuery.QueryAsync( A <Context> .That.Matches(x => x.ShouldSkipCleanup() && x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), schemaId.Name, A <Q> .That.Matches(x => x.JsonQuery == query), A <CancellationToken> ._)) .Returns(ResultList.CreateFrom(2, CreateContent(id), CreateContent(id))); var command = BulkCommand(BulkUpdateContentType.ChangeStatus, query); var result = await PublishAsync(command); Assert.Single(result); Assert.Single(result, x => x.JobIndex == 0 && x.Id == null && x.Exception is DomainException); A.CallTo(() => commandBus.PublishAsync(A <ICommand> ._)) .MustNotHaveHappened(); }
public async Task <IActionResult> GetAllContents(string app, AllContentsByGetDto query) { var contents = await contentQuery.QueryAsync(Context, query?.ToQuery() ?? Q.Empty, HttpContext.RequestAborted); var response = Deferred.AsyncResponse(() => { return(ContentsDto.FromContentsAsync(contents, Resources, null, contentWorkflow)); }); return(Ok(response)); }
private async Task <Guid?> FindIdAsync(Context context, string schema, BulkUpdateJob job) { var id = job.Id; if (id == null && job.Query != null) { job.Query.Take = 1; var existing = await contentQuery.QueryAsync(context, schema, Q.Empty.WithJsonQuery(job.Query)); if (existing.Total > 1) { throw new DomainException("More than one content matches to the query."); } id = existing.FirstOrDefault()?.Id; } return(id); }
private async Task <DomainId?> FindIdAsync(Context context, string schema, BulkUpdateJob job) { var id = job.Id; if (id == null && job.Query != null) { job.Query.Take = 1; var existing = await contentQuery.QueryAsync(context, schema, Q.Empty.WithJsonQuery(job.Query)); if (existing.Total > 1) { throw new DomainException(T.Get("contents.bulkInsertQueryNotUnique")); } id = existing.FirstOrDefault()?.Id; } return(id); }
public async Task <IActionResult> GetContents(string app, string name, [FromQuery] bool archived = false, [FromQuery] string ids = null) { var context = Context().WithArchived(archived); var result = await contentQuery.QueryAsync(context, name, Q.Empty.WithIds(ids).WithODataQuery(Request.QueryString.ToString())); var response = new ContentsDto { Total = result.Total, Items = result.Take(200).Select(x => ContentDto.FromContent(x, context)).ToArray() }; if (controllerOptions.Value.EnableSurrogateKeys && response.Items.Length <= controllerOptions.Value.MaxItemsForSurrogateKeys) { Response.Headers["Surrogate-Key"] = response.Items.ToSurrogateKeys(); } Response.Headers["ETag"] = response.Items.ToManyEtag(response.Total); return(Ok(response)); }
public async Task <IActionResult> GetContents(string app, string name, [FromQuery] bool archived = false, [FromQuery] string ids = null) { var context = Context().WithArchived(archived).WithSchemaName(name); var result = await contentQuery.QueryAsync(context, Query.Empty.WithIds(ids).WithODataQuery(Request.QueryString.ToString())); var response = new ContentsDto { Total = result.Total, Items = result.Take(200).Select(x => ContentDto.FromContent(x, context.Base)).ToArray() }; var options = controllerOptions.Value; if (options.EnableSurrogateKeys && response.Items.Length <= options.MaxItemsForSurrogateKeys) { Response.Headers["Surrogate-Key"] = string.Join(" ", response.Items.Select(x => x.Id)); } return(Ok(response)); }
public override async ValueTask <Completion> WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context, FilterArgument[] arguments) { if (arguments.Length == 2 && context.GetValue("event")?.ToObjectValue() is EnrichedEvent enrichedEvent) { var app = await appProvider.GetAppAsync(enrichedEvent.AppId.Id); if (app == null) { return(Completion.Normal); } var appContext = Context.Admin() .WithoutContentEnrichment() .WithoutCleanup() .WithUnpublished(); appContext.App = app; var id = (await arguments[1].Expression.EvaluateAsync(context)).ToStringValue(); if (Guid.TryParse(id, out var guid)) { var references = await contentQueryService.QueryAsync(appContext, new List <Guid> { guid }); var reference = references.FirstOrDefault(); if (reference != null) { var name = (await arguments[0].Expression.EvaluateAsync(context)).ToStringValue(); context.SetValue(name, reference); } } } return(Completion.Normal); }