Skip to content

Commit

Permalink
feat: New content queries
Browse files Browse the repository at this point in the history
- ContentAll (Gets all the content items avaliable)
- ContentDescendantsByGuid (Gets descendants on a content item selected by guid)
- ContentDescendantsById (Gets descendants on a content item selected by id)
- ContentDescendantsByContentType (Gets all descendants of content items with a specific content type)
- ContentDescendantsByAbsoluteRoute (Gets content item descendants by an absolute route)
- ContentByTag (Gets content items by tag)
  • Loading branch information
nikcio committed Nov 16, 2022
1 parent e51b72e commit 8a28fc7
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 2 deletions.
158 changes: 158 additions & 0 deletions src/Nikcio.UHeadless.Content/Queries/ContentQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
using Nikcio.UHeadless.Content.Models;
using Nikcio.UHeadless.Content.Repositories;
using Nikcio.UHeadless.Content.Router;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;

namespace Nikcio.UHeadless.Content.Queries;

Expand Down Expand Up @@ -135,4 +138,159 @@ public class ContentQuery<TContent, TProperty, TContentRedirect>
return publishedContentType != null ? x?.GetByContentType(publishedContentType) : default;
}, culture);
}

/// <summary>
/// Gets all the content items avaliable
/// </summary>
/// <param name="contentRepository"></param>
/// <param name="culture"></param>
/// <param name="preview"></param>
/// <returns></returns>
[GraphQLDescription("Gets all the content items avaliable.")]
[UsePaging]
[UseFiltering]
[UseSorting]
public virtual IEnumerable<TContent?> GetContentAll([Service] IContentRepository<TContent, TProperty> contentRepository,
[GraphQLDescription("The culture.")] string? culture = null,
[GraphQLDescription("Fetch preview values. Preview will show unpublished items.")] bool preview = false)
{
return contentRepository.GetContentList(x =>
{
return x?.GetAtRoot(preview, culture).SelectMany(content => content.Descendants(culture))
.Concat(x?.GetAtRoot(preview, culture) ?? Enumerable.Empty<IPublishedContent>());
}, culture);
}

/// <summary>
/// Gets descendants on a content item selected by guid
/// </summary>
/// <param name="id"></param>
/// <param name="contentRepository"></param>
/// <param name="culture"></param>
/// <param name="preview"></param>
/// <returns></returns>
[GraphQLDescription("Gets descendants on a content item selected by guid.")]
[UsePaging]
[UseFiltering]
[UseSorting]
public virtual IEnumerable<TContent?> GetContentDescendantsByGuid([Service] IContentRepository<TContent, TProperty> contentRepository,
[GraphQLDescription("The id to fetch.")] Guid id,
[GraphQLDescription("The culture.")] string? culture = null,
[GraphQLDescription("Fetch preview values. Preview will show unpublished items.")] bool preview = false)
{
return contentRepository.GetContentList(x =>
{
return x?.GetById(preview, id)?.Descendants(culture) ?? Enumerable.Empty<IPublishedContent>();
}, culture);
}

/// <summary>
/// Gets descendants on a content item selected by id
/// </summary>
/// <param name="id"></param>
/// <param name="contentRepository"></param>
/// <param name="culture"></param>
/// <param name="preview"></param>
/// <returns></returns>
[GraphQLDescription("Gets descendants on a content item selected by id.")]
[UsePaging]
[UseFiltering]
[UseSorting]
public virtual IEnumerable<TContent?> GetContentDescendantsById([Service] IContentRepository<TContent, TProperty> contentRepository,
[GraphQLDescription("The id to fetch.")] int id,
[GraphQLDescription("The culture.")] string? culture = null,
[GraphQLDescription("Fetch preview values. Preview will show unpublished items.")] bool preview = false)
{
return contentRepository.GetContentList(x =>
{
return x?.GetById(preview, id)?.Descendants(culture) ?? Enumerable.Empty<IPublishedContent>();
}, culture);
}

/// <summary>
/// Gets all descendants of content items with a specific content type (Missing preview)
/// </summary>
/// <param name="contentRepository"></param>
/// <param name="contentType"></param>
/// <param name="culture"></param>
/// <returns></returns>
[GraphQLDescription("Gets all descendants of content items with a specific content type.")]
[UsePaging]
[UseFiltering]
[UseSorting]
public virtual IEnumerable<TContent?> GetContentDescendantsByContentType([Service] IContentRepository<TContent, TProperty> contentRepository,
[GraphQLDescription("The contentType to fetch.")] string contentType,
[GraphQLDescription("The culture.")] string? culture = null)
{

return contentRepository.GetContentList(x =>
{
var publishedContentType = x?.GetContentType(contentType);
return publishedContentType != null ? x?.GetByContentType(publishedContentType).SelectMany(content => content.Descendants(culture)) : default;
}, culture);
}

/// <summary>
/// Gets content item descendants by an absolute route
/// </summary>
/// <param name="contentRouter"></param>
/// <param name="route"></param>
/// <param name="baseUrl"></param>
/// <param name="culture"></param>
/// <param name="preview"></param>
/// <param name="routeMode"></param>
/// <returns></returns>
[GraphQLDescription("Gets content item descendants by an absolute route.")]
[UsePaging]
[UseFiltering]
[UseSorting]
public virtual async Task<IEnumerable<TContent?>> GetContentDescendantsByAbsoluteRoute(
[Service] IContentRouter<TContent, TProperty, TContentRedirect> contentRouter,
[GraphQLDescription("The route to fetch. Example '/da/frontpage/'.")] string route,
[GraphQLDescription("The base url for the request. Example: 'https://localhost:4000'. Default is the current domain")] string baseUrl = "",
[GraphQLDescription("The culture.")] string? culture = null,
[GraphQLDescription("Fetch preview values. Preview will show unpublished items.")] bool preview = false,
[GraphQLDescription("Modes for requesting by route")] RouteMode routeMode = RouteMode.Routing)
{

if (routeMode is RouteMode.Routing or RouteMode.RoutingOrCache)
{
baseUrl = contentRouter.SetBaseUrl(baseUrl);
}

return routeMode switch
{
RouteMode.Routing => await contentRouter.GetContentDescendantsByRouting(route, baseUrl, culture),
RouteMode.RoutingOrCache => await contentRouter.GetContentDescendantsByRouting(route, baseUrl, culture) ?? contentRouter.GetContentDescendantsByRouteCache(route, culture, preview),
RouteMode.CacheOrRouting => contentRouter.GetContentDescendantsByRouteCache(route, culture, preview) ?? await contentRouter.GetContentDescendantsByRouting(route, baseUrl, culture),
RouteMode.CacheOnly => contentRouter.GetContentDescendantsByRouteCache(route, culture, preview),
_ => await contentRouter.GetContentDescendantsByRouting(route, baseUrl, culture),
};
}

/// <summary>
/// Gets content items by tag
/// </summary>
/// <param name="contentRepository"></param>
/// <param name="tagService"></param>
/// <param name="tag"></param>
/// <param name="tagGroup"></param>
/// <param name="culture"></param>
/// <returns></returns>
[GraphQLDescription("Gets content items by tag.")]
[UsePaging]
[UseFiltering]
[UseSorting]
public virtual IEnumerable<TContent?> GetContentByTag([Service] IContentRepository<TContent, TProperty> contentRepository,
[Service] ITagService tagService,
[GraphQLDescription("The tag to fetch.")] string tag,
[GraphQLDescription("The tag group to fetch.")] string? tagGroup = null,
[GraphQLDescription("The culture to fetch.")] string? culture = null)
{
return contentRepository.GetContentList(x =>
{
var taggedEntities = tagService.GetTaggedContentByTag(tag, tagGroup, culture);
return taggedEntities.Select(entity => x?.GetById(entity.EntityId)).OfType<IPublishedContent>();
}, culture);
}
}
22 changes: 22 additions & 0 deletions src/Nikcio.UHeadless.Content/Router/ContentRouter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
using Nikcio.UHeadless.Content.Commands;
using Nikcio.UHeadless.Content.Models;
using Nikcio.UHeadless.Content.Repositories;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Routing;
using Umbraco.Extensions;

namespace Nikcio.UHeadless.Content.Router;

Expand Down Expand Up @@ -110,4 +112,24 @@ public virtual string SetBaseUrl(string baseUrl)
return contentRepository.GetContent(x => x?.GetByRoute(preview, route, culture: culture), culture);
}

/// <inheritdoc/>
public IEnumerable<TContent?> GetContentDescendantsByRouteCache(string route, string? culture, bool preview)
{
return contentRepository.GetContentList(x => x?.GetByRoute(preview, route, culture: culture)?.Descendants(culture) ?? Enumerable.Empty<IPublishedContent>(), culture);
}

/// <inheritdoc/>
public async Task<IEnumerable<TContent?>> GetContentDescendantsByRouting(string route, string baseUrl, string? culture)
{
var builder = await publishedRouter.CreateRequestAsync(new Uri($"{baseUrl}{route}"));
var request = await publishedRouter.RouteRequestAsync(builder, new RouteRequestOptions(RouteDirection.Inbound));

return request.GetRouteResult() switch
{
UmbracoRouteResult.Redirect => GetRedirect(request).AsEnumerableOfOne() ?? Enumerable.Empty<TContent>(),
UmbracoRouteResult.NotFound => default,
UmbracoRouteResult.Success => request.PublishedContent != null ? request.PublishedContent.Descendants(culture).Select(content => contentRepository.GetConvertedContent(content, culture)) : Enumerable.Empty<TContent>(),
_ => default,
};
}
}
18 changes: 18 additions & 0 deletions src/Nikcio.UHeadless.Content/Router/IContentRouter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,24 @@ public interface IContentRouter<TContent, TProperty, TContentRedirect>
/// <returns></returns>
Task<TContent?> GetContentByRouting(string route, string baseUrl, string? culture);

/// <summary>
/// Gets content descendants by cache
/// </summary>
/// <param name="route"></param>
/// <param name="culture"></param>
/// <param name="preview"></param>
/// <returns></returns>
IEnumerable<TContent?> GetContentDescendantsByRouteCache(string route, string? culture, bool preview);

/// <summary>
/// Gets content descendants by routing
/// </summary>
/// <param name="route"></param>
/// <param name="baseUrl"></param>
/// <param name="culture"></param>
/// <returns></returns>
Task<IEnumerable<TContent?>> GetContentDescendantsByRouting(string route, string baseUrl, string? culture);

/// <summary>
/// Gets a content redirect result
/// </summary>
Expand Down
29 changes: 27 additions & 2 deletions test/v10/uSync/v9/ContentTypes/default.config
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,31 @@
<Structure>
<ContentType Key="6f3ed131-e834-47e0-9f19-dc6e311dd9d3" SortOrder="0">default</ContentType>
</Structure>
<GenericProperties />
<Tabs />
<GenericProperties>
<GenericProperty>
<Key>46d16fdd-6f68-4483-849a-6ae7c877521f</Key>
<Name>tageditor</Name>
<Alias>tageditor</Alias>
<Definition>b6b73142-b9c1-4bf8-a16d-e1c23320b549</Definition>
<Type>Umbraco.Tags</Type>
<Mandatory>false</Mandatory>
<Validation></Validation>
<Description><![CDATA[]]></Description>
<SortOrder>0</SortOrder>
<Tab Alias="content">Content</Tab>
<Variations>Nothing</Variations>
<MandatoryMessage></MandatoryMessage>
<ValidationRegExpMessage></ValidationRegExpMessage>
<LabelOnTop>false</LabelOnTop>
</GenericProperty>
</GenericProperties>
<Tabs>
<Tab>
<Key>07d1ae3b-64f7-4a29-8ebf-6201a7239c67</Key>
<Caption>Content</Caption>
<Alias>content</Alias>
<Type>Tab</Type>
<SortOrder>0</SortOrder>
</Tab>
</Tabs>
</ContentType>

0 comments on commit 8a28fc7

Please sign in to comment.