Files
Umbraco-CMS/src/Umbraco.Web/Editors/TemplateQueryController.cs

259 lines
12 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Diagnostics;
2014-06-08 09:51:06 -07:00
using System.Linq;
using System.Text;
2019-01-21 18:50:27 +01:00
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Persistence;
2017-05-12 14:49:44 +02:00
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Web.Models.TemplateQuery;
using Umbraco.Web.Mvc;
using Umbraco.Web.Routing;
using Umbraco.Web.WebApi;
2014-06-08 09:51:06 -07:00
namespace Umbraco.Web.Editors
{
/// <summary>
/// The API controller used for building content queries within the template
/// </summary>
[PluginController("UmbracoApi")]
[JsonCamelCaseFormatter]
2014-06-08 09:51:06 -07:00
public class TemplateQueryController : UmbracoAuthorizedJsonController
{
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly IPublishedContentQuery _publishedContentQuery;
public TemplateQueryController(
IGlobalSettings globalSettings,
IUmbracoContextAccessor umbracoContextAccessor,
ISqlContext sqlContext,
ServiceContext services,
AppCaches appCaches,
IProfilingLogger logger,
IRuntimeState runtimeState,
IVariationContextAccessor variationContextAccessor,
IShortStringHelper shortStringHelper,
UmbracoMapper umbracoMapper,
IPublishedUrlProvider publishedUrlProvider,
IPublishedContentQuery publishedContentQuery)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider)
{
_variationContextAccessor = variationContextAccessor;
_publishedContentQuery = publishedContentQuery;
}
2019-01-21 18:50:27 +01:00
private IEnumerable<OperatorTerm> Terms => new List<OperatorTerm>
2017-05-12 14:49:44 +02:00
{
2019-01-21 18:50:27 +01:00
new OperatorTerm(Services.TextService.Localize("template/is"), Operator.Equals, new [] {"string"}),
new OperatorTerm(Services.TextService.Localize("template/isNot"), Operator.NotEquals, new [] {"string"}),
new OperatorTerm(Services.TextService.Localize("template/before"), Operator.LessThan, new [] {"datetime"}),
new OperatorTerm(Services.TextService.Localize("template/beforeIncDate"), Operator.LessThanEqualTo, new [] {"datetime"}),
new OperatorTerm(Services.TextService.Localize("template/after"), Operator.GreaterThan, new [] {"datetime"}),
new OperatorTerm(Services.TextService.Localize("template/afterIncDate"), Operator.GreaterThanEqualTo, new [] {"datetime"}),
new OperatorTerm(Services.TextService.Localize("template/equals"), Operator.Equals, new [] {"int"}),
new OperatorTerm(Services.TextService.Localize("template/doesNotEqual"), Operator.NotEquals, new [] {"int"}),
new OperatorTerm(Services.TextService.Localize("template/contains"), Operator.Contains, new [] {"string"}),
new OperatorTerm(Services.TextService.Localize("template/doesNotContain"), Operator.NotContains, new [] {"string"}),
new OperatorTerm(Services.TextService.Localize("template/greaterThan"), Operator.GreaterThan, new [] {"int"}),
new OperatorTerm(Services.TextService.Localize("template/greaterThanEqual"), Operator.GreaterThanEqualTo, new [] {"int"}),
new OperatorTerm(Services.TextService.Localize("template/lessThan"), Operator.LessThan, new [] {"int"}),
new OperatorTerm(Services.TextService.Localize("template/lessThanEqual"), Operator.LessThanEqualTo, new [] {"int"})
};
private IEnumerable<PropertyModel> Properties => new List<PropertyModel>
{
2019-01-21 18:50:27 +01:00
new PropertyModel { Name = Services.TextService.Localize("template/id"), Alias = "Id", Type = "int" },
new PropertyModel { Name = Services.TextService.Localize("template/name"), Alias = "Name", Type = "string" },
new PropertyModel { Name = Services.TextService.Localize("template/createdDate"), Alias = "CreateDate", Type = "datetime" },
new PropertyModel { Name = Services.TextService.Localize("template/lastUpdatedDate"), Alias = "UpdateDate", Type = "datetime" }
};
public QueryResultModel PostTemplateQuery(QueryModel model)
2014-06-08 09:51:06 -07:00
{
2019-01-21 18:50:27 +01:00
var queryExpression = new StringBuilder();
IEnumerable<IPublishedContent> contents;
2019-01-21 18:50:27 +01:00
if (model == null)
{
contents = _publishedContentQuery.ContentAtRoot().FirstOrDefault().Children(_variationContextAccessor);
2019-01-21 18:50:27 +01:00
queryExpression.Append("Umbraco.ContentAtRoot().FirstOrDefault().Children()");
}
else
{
contents = PostTemplateValue(model, queryExpression);
}
2017-05-30 10:50:09 +02:00
2019-01-21 18:50:27 +01:00
// timing should be fairly correct, due to the fact that all the linq statements are yield returned.
var timer = new Stopwatch();
timer.Start();
var results = contents.ToList();
timer.Stop();
2017-07-20 11:21:28 +02:00
2019-01-21 18:50:27 +01:00
return new QueryResultModel
{
QueryExpression = queryExpression.ToString(),
ResultCount = results.Count,
ExecutionTime = timer.ElapsedMilliseconds,
SampleResults = results.Take(20).Select(x => new TemplateQueryResult { Icon = "icon-file", Name = x.Name })
};
}
2014-06-08 09:51:06 -07:00
2019-01-21 18:50:27 +01:00
private IEnumerable<IPublishedContent> PostTemplateValue(QueryModel model, StringBuilder queryExpression)
{
var indent = Environment.NewLine + " ";
2019-01-21 18:50:27 +01:00
// set the source
IPublishedContent sourceDocument;
if (model.Source != null && model.Source.Id > 0)
{
sourceDocument = _publishedContentQuery.Content(model.Source.Id);
2019-01-21 18:50:27 +01:00
if (sourceDocument == null)
queryExpression.AppendFormat("Umbraco.Content({0})", model.Source.Id);
else
queryExpression.AppendFormat("Umbraco.Content(Guid.Parse(\"{0}\"))", sourceDocument.Key);
}
else
2014-06-08 09:51:06 -07:00
{
sourceDocument = _publishedContentQuery.ContentAtRoot().FirstOrDefault();
2019-01-21 18:50:27 +01:00
queryExpression.Append("Umbraco.ContentAtRoot().FirstOrDefault()");
2014-06-08 09:51:06 -07:00
}
2019-01-21 18:50:27 +01:00
// get children, optionally filtered by type
2014-06-08 09:51:06 -07:00
IEnumerable<IPublishedContent> contents;
2019-01-21 18:50:27 +01:00
queryExpression.Append(indent);
if (model.ContentType != null && !model.ContentType.Alias.IsNullOrWhiteSpace())
2014-06-08 09:51:06 -07:00
{
2019-01-21 18:50:27 +01:00
contents = sourceDocument == null
? Enumerable.Empty<IPublishedContent>()
: sourceDocument.ChildrenOfType(model.ContentType.Alias);
queryExpression.AppendFormat(".ChildrenOfType(\"{0}\")", model.ContentType.Alias);
2014-06-08 09:51:06 -07:00
}
2014-06-08 22:39:01 +01:00
else
{
2019-01-21 18:50:27 +01:00
contents = sourceDocument == null
? Enumerable.Empty<IPublishedContent>()
: sourceDocument.Children(_variationContextAccessor);
2019-01-21 18:50:27 +01:00
queryExpression.Append(".Children()");
2014-06-08 22:39:01 +01:00
}
2019-01-21 18:50:27 +01:00
// apply filters
foreach (var condition in model.Filters.Where(x => !x.ConstraintValue.IsNullOrWhiteSpace()))
2014-06-08 09:51:06 -07:00
{
2019-01-21 18:50:27 +01:00
//x is passed in as the parameter alias for the linq where statement clause
var operation = condition.BuildCondition<IPublishedContent>("x");
//for review - this uses a tonized query rather then the normal linq query.
2019-01-21 18:50:27 +01:00
contents = contents.Where(operation.Compile());
queryExpression.Append(indent);
queryExpression.AppendFormat(".Where({0})", operation);
}
2014-06-08 09:51:06 -07:00
2019-01-21 18:50:27 +01:00
// always add IsVisible() to the query
contents = contents.Where(x => x.IsVisible());
queryExpression.Append(indent);
queryExpression.Append(".Where(x => x.IsVisible())");
2019-01-21 18:50:27 +01:00
// apply sort
if (model.Sort != null && !model.Sort.Property.Alias.IsNullOrWhiteSpace())
{
contents = SortByDefaultPropertyValue(contents, model.Sort);
2019-01-21 18:50:27 +01:00
queryExpression.Append(indent);
queryExpression.AppendFormat(model.Sort.Direction == "ascending"
? ".OrderBy(x => x.{0})"
: ".OrderByDescending(x => x.{0})"
, model.Sort.Property.Alias);
}
2019-01-21 18:50:27 +01:00
// take
if (model.Take > 0)
2017-05-30 10:50:09 +02:00
{
2019-01-21 18:50:27 +01:00
contents = contents.Take(model.Take);
queryExpression.Append(indent);
queryExpression.AppendFormat(".Take({0})", model.Take);
}
2019-01-21 18:50:27 +01:00
return contents;
2014-06-08 09:51:06 -07:00
}
private object GetConstraintValue(QueryCondition condition)
{
switch (condition.Property.Type)
{
2017-05-30 10:50:09 +02:00
case "int":
return int.Parse(condition.ConstraintValue);
case "datetime":
DateTime dt;
return DateTime.TryParse(condition.ConstraintValue, out dt) ? dt : DateTime.Today;
default:
return condition.ConstraintValue;
}
}
2017-05-30 10:50:09 +02:00
private IEnumerable<IPublishedContent> SortByDefaultPropertyValue(IEnumerable<IPublishedContent> contents, SortExpression sortExpression)
{
switch (sortExpression.Property.Alias)
{
2017-05-30 10:50:09 +02:00
case "id":
return sortExpression.Direction == "ascending"
2017-05-30 10:50:09 +02:00
? contents.OrderBy(x => x.Id)
: contents.OrderByDescending(x => x.Id);
case "createDate":
return sortExpression.Direction == "ascending"
2017-05-30 10:50:09 +02:00
? contents.OrderBy(x => x.CreateDate)
: contents.OrderByDescending(x => x.CreateDate);
case "publishDate":
return sortExpression.Direction == "ascending"
2017-05-30 10:50:09 +02:00
? contents.OrderBy(x => x.UpdateDate)
: contents.OrderByDescending(x => x.UpdateDate);
case "name":
return sortExpression.Direction == "ascending"
2017-05-30 10:50:09 +02:00
? contents.OrderBy(x => x.Name)
: contents.OrderByDescending(x => x.Name);
default:
return sortExpression.Direction == "ascending"
2017-05-30 10:50:09 +02:00
? contents.OrderBy(x => x.Name)
: contents.OrderByDescending(x => x.Name);
}
}
/// <summary>
/// Gets a list of all content types
/// </summary>
/// <returns></returns>
public IEnumerable<ContentTypeModel> GetContentTypes()
{
var contentTypes = Services.ContentTypeService.GetAll()
.Select(x => new ContentTypeModel { Alias = x.Alias, Name = Services.TextService.Localize("template/contentOfType", tokens: new string[] { x.Name }) })
.OrderBy(x => x.Name).ToList();
2017-05-12 14:49:44 +02:00
contentTypes.Insert(0, new ContentTypeModel { Alias = string.Empty, Name = Services.TextService.Localize("template/allContent") });
return contentTypes;
}
/// <summary>
/// Returns a collection of allowed properties.
/// </summary>
public IEnumerable<PropertyModel> GetAllowedProperties()
{
return Properties.OrderBy(x => x.Name);
}
2014-06-08 09:51:06 -07:00
/// <summary>
/// Returns a collection of constraint conditions that can be used in the query
/// </summary>
public IEnumerable<object> GetFilterConditions()
2014-06-08 09:51:06 -07:00
{
return Terms;
2014-06-08 09:51:06 -07:00
}
}
2017-07-20 11:21:28 +02:00
}