230 lines
10 KiB
C#
230 lines
10 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Umbraco.Core;
|
|
using Umbraco.Core.Models.PublishedContent;
|
|
using Umbraco.Core.Services;
|
|
using Umbraco.Web.Models.TemplateQuery;
|
|
using Umbraco.Web.Mvc;
|
|
using Umbraco.Web.WebApi;
|
|
|
|
namespace Umbraco.Web.Editors
|
|
{
|
|
/// <summary>
|
|
/// The API controller used for building content queries within the template
|
|
/// </summary>
|
|
[PluginController("UmbracoApi")]
|
|
[JsonCamelCaseFormatter]
|
|
public class TemplateQueryController : UmbracoAuthorizedJsonController
|
|
{
|
|
private IEnumerable<OperatorTerm> Terms => new List<OperatorTerm>
|
|
{
|
|
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>
|
|
{
|
|
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)
|
|
{
|
|
var queryExpression = new StringBuilder();
|
|
IEnumerable<IPublishedContent> contents;
|
|
|
|
if (model == null)
|
|
{
|
|
contents = Umbraco.ContentAtRoot().FirstOrDefault().Children();
|
|
queryExpression.Append("Umbraco.ContentAtRoot().FirstOrDefault().Children()");
|
|
}
|
|
else
|
|
{
|
|
contents = PostTemplateValue(model, queryExpression);
|
|
}
|
|
|
|
// 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();
|
|
|
|
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 })
|
|
};
|
|
}
|
|
|
|
private IEnumerable<IPublishedContent> PostTemplateValue(QueryModel model, StringBuilder queryExpression)
|
|
{
|
|
var indent = Environment.NewLine + " ";
|
|
|
|
// set the source
|
|
IPublishedContent sourceDocument;
|
|
if (model.Source != null && model.Source.Id > 0)
|
|
{
|
|
sourceDocument = Umbraco.Content(model.Source.Id);
|
|
|
|
if (sourceDocument == null)
|
|
queryExpression.AppendFormat("Umbraco.Content({0})", model.Source.Id);
|
|
else
|
|
queryExpression.AppendFormat("Umbraco.Content(Guid.Parse(\"{0}\"))", sourceDocument.Key);
|
|
}
|
|
else
|
|
{
|
|
sourceDocument = Umbraco.ContentAtRoot().FirstOrDefault();
|
|
queryExpression.Append("Umbraco.ContentAtRoot().FirstOrDefault()");
|
|
}
|
|
|
|
// get children, optionally filtered by type
|
|
IEnumerable<IPublishedContent> contents;
|
|
queryExpression.Append(indent);
|
|
if (model.ContentType != null && !model.ContentType.Alias.IsNullOrWhiteSpace())
|
|
{
|
|
contents = sourceDocument == null
|
|
? Enumerable.Empty<IPublishedContent>()
|
|
: sourceDocument.Children(model.ContentType.Alias);
|
|
queryExpression.AppendFormat(".Children(\"{0}\")", model.ContentType.Alias);
|
|
}
|
|
else
|
|
{
|
|
contents = sourceDocument == null
|
|
? Enumerable.Empty<IPublishedContent>()
|
|
: sourceDocument.Children();
|
|
queryExpression.Append(".Children()");
|
|
}
|
|
|
|
// apply filters
|
|
foreach (var condition in model.Filters.Where(x => !x.ConstraintValue.IsNullOrWhiteSpace()))
|
|
{
|
|
//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.
|
|
contents = contents.Where(operation.Compile());
|
|
queryExpression.Append(indent);
|
|
queryExpression.AppendFormat(".Where({0})", operation);
|
|
}
|
|
|
|
// always add IsVisible() to the query
|
|
contents = contents.Where(x => x.IsVisible());
|
|
queryExpression.Append(indent);
|
|
queryExpression.Append(".Where(x => x.IsVisible())");
|
|
|
|
// apply sort
|
|
if (model.Sort != null && !model.Sort.Property.Alias.IsNullOrWhiteSpace())
|
|
{
|
|
contents = SortByDefaultPropertyValue(contents, model.Sort);
|
|
|
|
queryExpression.Append(indent);
|
|
queryExpression.AppendFormat(model.Sort.Direction == "ascending"
|
|
? ".OrderBy(x => x.{0})"
|
|
: ".OrderByDescending(x => x.{0})"
|
|
, model.Sort.Property.Alias);
|
|
}
|
|
|
|
// take
|
|
if (model.Take > 0)
|
|
{
|
|
contents = contents.Take(model.Take);
|
|
queryExpression.Append(indent);
|
|
queryExpression.AppendFormat(".Take({0})", model.Take);
|
|
}
|
|
|
|
return contents;
|
|
}
|
|
|
|
private object GetConstraintValue(QueryCondition condition)
|
|
{
|
|
switch (condition.Property.Type)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
private IEnumerable<IPublishedContent> SortByDefaultPropertyValue(IEnumerable<IPublishedContent> contents, SortExpression sortExpression)
|
|
{
|
|
switch (sortExpression.Property.Alias)
|
|
{
|
|
case "id":
|
|
return sortExpression.Direction == "ascending"
|
|
? contents.OrderBy(x => x.Id)
|
|
: contents.OrderByDescending(x => x.Id);
|
|
case "createDate":
|
|
return sortExpression.Direction == "ascending"
|
|
? contents.OrderBy(x => x.CreateDate)
|
|
: contents.OrderByDescending(x => x.CreateDate);
|
|
case "publishDate":
|
|
return sortExpression.Direction == "ascending"
|
|
? contents.OrderBy(x => x.UpdateDate)
|
|
: contents.OrderByDescending(x => x.UpdateDate);
|
|
case "name":
|
|
return sortExpression.Direction == "ascending"
|
|
? contents.OrderBy(x => x.Name)
|
|
: contents.OrderByDescending(x => x.Name);
|
|
default:
|
|
return sortExpression.Direction == "ascending"
|
|
? 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();
|
|
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a collection of constraint conditions that can be used in the query
|
|
/// </summary>
|
|
public IEnumerable<object> GetFilterConditions()
|
|
{
|
|
return Terms;
|
|
}
|
|
}
|
|
}
|