Merge branch '1.7.x' into 1.x

Conflicts:
	src/Orchard.Web/Modules/Orchard.AntiSpam/Drivers/ReCaptchaPartDriver.cs
	src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs
	src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj
This commit is contained in:
Sebastien Ros
2014-03-17 12:09:21 -07:00
53 changed files with 409 additions and 225 deletions

View File

@@ -20,7 +20,7 @@ namespace Orchard.Tests.Modules.Warmup {
[Test]
public void StatusCodeShouldBe404ForUnexistingResources() {
var download = _webDownloader.Download("http://www.microsoft.com/yepyep");
var download = _webDownloader.Download("http://orchardproject.net/yepyep");
Assert.That(download, Is.Not.Null);
Assert.That(download.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
Assert.That(download.Content, Is.Null);
@@ -28,7 +28,7 @@ namespace Orchard.Tests.Modules.Warmup {
[Test]
public void StatusCodeShouldBe200ForValidRequests() {
var download = _webDownloader.Download("http://www.microsoft.com/");
var download = _webDownloader.Download("http://orchardproject.net/");
Assert.That(download, Is.Not.Null);
Assert.That(download.StatusCode, Is.EqualTo(HttpStatusCode.OK));
Assert.That(download.Content, Is.Not.Empty);

View File

@@ -121,7 +121,10 @@ namespace Orchard.Core.Contents.Controllers {
}
private IEnumerable<ContentTypeDefinition> GetCreatableTypes(bool andContainable) {
return _contentDefinitionManager.ListTypeDefinitions().Where(ctd => ctd.Settings.GetModel<ContentTypeSettings>().Creatable && (!andContainable || ctd.Parts.Any(p => p.PartDefinition.Name == "ContainablePart")));
return _contentDefinitionManager.ListTypeDefinitions().Where(ctd =>
Services.Authorizer.Authorize(Permissions.EditContent, _contentManager.New(ctd.Name)) &&
ctd.Settings.GetModel<ContentTypeSettings>().Creatable &&
(!andContainable || ctd.Parts.Any(p => p.PartDefinition.Name == "ContainablePart")));
}
[HttpPost, ActionName("List")]

View File

@@ -6,9 +6,9 @@
Layout.Title = T("Navigation").ToString();
Style.Include("navigation-admin.css");
Script.Require("jQueryUI_Sortable");
Script.Include("jquery.mjs.nestedSortable.js");
Script.Include("navigation-admin.js");
Script.Require("jQueryUI_Sortable").AtFoot();
Script.Include("jquery.mjs.nestedSortable.js").AtFoot();
Script.Include("navigation-admin.js").AtFoot();
}
<div id="save-message" class="message message-Warning">@T("You need to hit \"Save All\" in order to save your changes.")</div>

View File

@@ -5,12 +5,14 @@
}
<fieldset>
@Html.EditorFor(m => m.OnAdminMenu)
<label for="OnAdminMenu" class="forcheckbox">@T("Show on admin menu")</label>
<div data-controllerid="OnAdminMenu" class="">
<label for="AdminMenuText">@T("Menu text")</label>
<label for="@Html.FieldIdFor(m => m.OnAdminMenu)" class="forcheckbox">@T("Show on admin menu")</label>
<div data-controllerid="@Html.FieldIdFor(m => m.OnAdminMenu)" class="">
<label for="@Html.FieldIdFor(m => m.AdminMenuText)">@T("Menu text")</label>
@Html.TextBoxFor(m => m.AdminMenuText, new { @class = "text single-line" })
<span class="hint">@T("The text that should appear in the menu.")</span>
<label for="AdminMenuPosition">@T("Position")</label>
@Html.TextBoxFor(m => m.AdminMenuPosition, new { @class = "text single-line" })
<label for="@Html.FieldIdFor(m => m.AdminMenuPosition)">@T("Position")</label>
@Html.TextBoxFor(m => m.AdminMenuPosition, new { @class = "text small" })
<span class="hint">@T("The position in the menu.")</span>
</div>
</fieldset>

View File

@@ -263,26 +263,24 @@ namespace Orchard.Core.Shapes {
IDictionary<string, string> attributes = Shape.Attributes;
var zoneWrapper = GetTagBuilder("div", id, classes, attributes);
Output.Write(zoneWrapper.ToString(TagRenderMode.StartTag));
foreach (var item in ordered_hack(Shape))
foreach (var item in Order(Shape))
Output.Write(Display(item));
Output.Write(zoneWrapper.ToString(TagRenderMode.EndTag));
}
[Shape]
public void ContentZone(dynamic Display, dynamic Shape, TextWriter Output) {
foreach (var item in ordered_hack(Shape))
foreach (var item in Order(Shape))
Output.Write(Display(item));
}
[Shape]
public void DocumentZone(dynamic Display, dynamic Shape, TextWriter Output) {
foreach (var item in ordered_hack(Shape))
foreach (var item in Order(Shape))
Output.Write(Display(item));
}
#region ordered_hack
private static IEnumerable<dynamic> ordered_hack(dynamic shape) {
public static IEnumerable<dynamic> Order(dynamic shape) {
IEnumerable<dynamic> unordered = shape;
if (unordered == null || unordered.Count() < 2)
return shape;
@@ -317,8 +315,6 @@ namespace Orchard.Core.Shapes {
return ordering.Select(ordered => ordered.item).ToList();
}
#endregion
[Shape]
public void HeadScripts(dynamic Display, TextWriter Output) {
WriteResources(Display, Output, "script", ResourceLocation.Head, null);
@@ -618,7 +614,7 @@ namespace Orchard.Core.Shapes {
IEnumerable<string> classes = Shape.Classes;
IDictionary<string, string> attributes = Shape.Attributes;
attributes.Add("href", action);
attributes["href"] = action;
string id = Shape.Id;
var tag = GetTagBuilder("a", id, classes, attributes);
tag.InnerHtml = EncodeOrDisplay(Value, Display, Html).ToString();

View File

@@ -100,7 +100,7 @@ namespace Lucene.Models {
switch(_typeCode) {
case TypeCode.String:
if(_removeTags) {
_stringValue = _stringValue.RemoveTags();
_stringValue = _stringValue.RemoveTags(true);
}
Fields.Add(new Field(_name, _stringValue ?? String.Empty,
_store ? Field.Store.YES : Field.Store.NO,

View File

@@ -9,6 +9,7 @@ using Orchard.AntiSpam.ViewModels;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Localization;
using Orchard.Logging;
using Orchard.UI.Admin;
using Orchard.UI.Notify;
@@ -25,10 +26,11 @@ namespace Orchard.AntiSpam.Drivers {
_notifier = notifier;
_workContextAccessor = workContextAccessor;
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
}
public Localizer T { get; set; }
public ILogger Logger { get; set; }
protected override DriverResult Editor(ReCaptchaPart part, dynamic shapeHelper) {
var workContext = _workContextAccessor.GetContext();
@@ -70,6 +72,7 @@ namespace Orchard.AntiSpam.Drivers {
if(updater.TryUpdateModel(submitViewModel, String.Empty, null, null)) {
var context = workContext.HttpContext;
try {
var result = ExecuteValidateRequest(
settings.PrivateKey,
context.Request.ServerVariables["REMOTE_ADDR"],
@@ -82,6 +85,11 @@ namespace Orchard.AntiSpam.Drivers {
updater.AddModelError("", T("The text you entered in the Captcha field does not match the image"));
}
}
catch(Exception e) {
Logger.Error(e, "An unexcepted error occured while submitting a reCaptcha");
updater.AddModelError("Parts_ReCaptcha_Fields", T("There was an error while validating the Captcha image"));
}
}
return Editor(part, shapeHelper);
}

View File

@@ -48,6 +48,10 @@ namespace Orchard.Azure.Services.Caching.Output {
}
public void Set(string key, CacheItem cacheItem) {
if (cacheItem.ValidFor <= 0) {
return;
}
Logger.Debug("Set() invoked with key='{0}' in region '{1}'.", key, _regionAlphaNumeric);
_cache.Put(key, cacheItem, TimeSpan.FromSeconds(cacheItem.ValidFor), _regionAlphaNumeric);
}

View File

@@ -108,11 +108,15 @@ namespace Orchard.Comments.Controllers {
// if the user who submitted the comment has the right to moderate, don't make this comment moderated
if (Services.Authorizer.Authorize(Permissions.ManageComments)) {
commentPart.Status = CommentStatus.Approved;
Services.Notifier.Information(T("Your comment has been posted."));
}
else {
Services.Notifier.Information(T("Your comment will appear after the site administrator approves it."));
}
}
else {
Services.Notifier.Information(T("Your comment has been posted."));
}
}
else {
Services.TransactionManager.Cancel();

View File

@@ -52,12 +52,32 @@
(function ($) {
var assignPositions = function () {
var position = 1;
$('.position').each(function() {
$(this).val(position++);
var position = 0;
$('.type').each(function () {
var input = $(this);
reAssignIdName(input, position); // type
input = input.next();
reAssignIdName(input, position); // differentiator
input = input.next();
reAssignIdName(input, position); // zone
input = input.next();
reAssignIdName(input, position); // position
input.val(++position);
});
};
var reAssignIdName = function (input, pos) {
var name = input.attr('name');
input.attr('name', name.replace(new RegExp("\\[.*\\]", 'gi'), '[' + pos + ']'));
var id = input.attr('id');
input.attr('id', id.replace(new RegExp('_.*__', 'i'), '_' + pos + '__'));
};
assignPositions();
var startPos;

View File

@@ -5,6 +5,7 @@ using System.Xml;
using System.Xml.Linq;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData;
using Orchard.Environment.Descriptor;
using Orchard.FileSystems.AppData;
@@ -139,31 +140,48 @@ namespace Orchard.ImportExport.Services {
}
private XElement ExportSiteSettings() {
var settings = new XElement("Settings");
var hasSetting = false;
var siteContentItem = _orchardServices.WorkContext.CurrentSite.ContentItem;
var exportedElements = ExportContentItem(siteContentItem).Elements().ToList();
foreach (var sitePart in _orchardServices.WorkContext.CurrentSite.ContentItem.Parts) {
var setting = new XElement(sitePart.PartDefinition.Name);
foreach (var contentPart in siteContentItem.Parts) {
var exportedElement = exportedElements.FirstOrDefault(element => element.Name == contentPart.PartDefinition.Name);
//Get all simple attributes if exported element is null
//Get exclude the simple attributes that already exist if element is not null
var simpleAttributes =
ExportSettingsPartAttributes(contentPart)
.Where(attribute => exportedElement == null || exportedElement.Attributes().All(xAttribute => xAttribute.Name != attribute.Name))
.ToList();
if (simpleAttributes.Any()) {
if (exportedElement == null) {
exportedElement = new XElement(contentPart.PartDefinition.Name);
exportedElements.Add(exportedElement);
}
exportedElement.Add(simpleAttributes);
}
}
return new XElement("Settings", exportedElements);
}
private IEnumerable<XAttribute> ExportSettingsPartAttributes(ContentPart sitePart) {
foreach (var property in sitePart.GetType().GetProperties()) {
var propertyType = property.PropertyType;
// Supported types (we also know they are not indexed properties).
if (propertyType == typeof(string) || propertyType == typeof(bool) || propertyType == typeof(int)) {
// Exclude read-only properties.
if (property.GetSetMethod() != null) {
setting.SetAttributeValue(property.Name, property.GetValue(sitePart, null));
hasSetting = true;
}
}
}
var value = property.GetValue(sitePart, null);
if (value == null)
continue;
if (hasSetting) {
settings.Add(setting);
hasSetting = false;
yield return new XAttribute(property.Name, value);
}
}
}
return settings;
}
private XElement ExportData(IEnumerable<string> contentTypes, IEnumerable<ContentItem> contentItems, int? batchSize) {

View File

@@ -39,6 +39,8 @@ namespace Orchard.MediaLibrary.Controllers {
public ILogger Logger { get; set; }
public ActionResult Index(string folderPath = "", bool dialog = false) {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot view media")))
return new HttpUnauthorizedResult();
// let other modules enhance the ui by providing custom navigation and actions
var explorer = Services.ContentManager.New("MediaLibraryExplorer");
@@ -67,6 +69,8 @@ namespace Orchard.MediaLibrary.Controllers {
}
public ActionResult Import(string folderPath) {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot import media")))
return new HttpUnauthorizedResult();
var mediaProviderMenu = _navigationManager.BuildMenu("mediaproviders");
var imageSets = _navigationManager.BuildImageSets("mediaproviders");
@@ -83,8 +87,11 @@ namespace Orchard.MediaLibrary.Controllers {
[Themed(false)]
public ActionResult MediaItems(string folderPath, int skip = 0, int count = 0, string order = "created", string mediaType = "") {
var mediaParts = _mediaLibraryService.GetMediaContentItems(folderPath, skip, count, order, mediaType, VersionOptions.Latest);
var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(folderPath, mediaType, VersionOptions.Latest);
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot view media")))
return new HttpUnauthorizedResult();
var mediaParts = _mediaLibraryService.GetMediaContentItems(folderPath, skip, count, order, mediaType);
var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(folderPath, mediaType);
var mediaItems = mediaParts.Select(x => new MediaManagerMediaItemViewModel {
MediaPart = x,
@@ -115,8 +122,12 @@ namespace Orchard.MediaLibrary.Controllers {
[Themed(false)]
public ActionResult RecentMediaItems(int skip = 0, int count = 0, string order = "created", string mediaType = "") {
var mediaParts = _mediaLibraryService.GetMediaContentItems(skip, count, order, mediaType, VersionOptions.Latest);
var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(mediaType, VersionOptions.Latest);
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot view media")))
return new HttpUnauthorizedResult();
var mediaParts = _mediaLibraryService.GetMediaContentItems(skip, count, order, mediaType);
var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(mediaType);
var mediaItems = mediaParts.Select(x => new MediaManagerMediaItemViewModel {
MediaPart = x,
@@ -138,7 +149,7 @@ namespace Orchard.MediaLibrary.Controllers {
if (contentItem == null)
return HttpNotFound();
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, contentItem, T("Cannot edit media")))
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, contentItem, T("Cannot view media")))
return new HttpUnauthorizedResult();
dynamic model = Services.ContentManager.BuildDisplay(contentItem, displayType);

View File

@@ -15,7 +15,7 @@ namespace Orchard.MediaLibrary {
if (!(filterContext.Result is ViewResult) || !UI.Admin.AdminFilter.IsApplied(filterContext.RequestContext))
return;
_resourceManager.Include("stylesheet", "~/Modules/Orchard.MediaLibrary/Styles/dialog-mode.css", null);
_resourceManager.Include("script", "~/Modules/Orchard.MediaLibrary/Scripts/modal-window.js", null);
_resourceManager.Include("script", "~/Modules/Orchard.MediaLibrary/Scripts/modal-window.js", null).AtFoot();
}
public void OnResultExecuted(ResultExecutedContext filterContext) {

View File

@@ -3,13 +3,13 @@
@{
var viewModel = Model;
Script.Require("ShapesBase");
Script.Require("ShapesBase").AtFoot();
Style.Require("MediaManagerAdmin");
Script.Require("jQuery");
Script.Require("jQueryUI_Droppable");
Script.Include("knockout-2.3.0.js");
Script.Include("history.js");
Script.Include("media-library.js");
Script.Require("jQuery").AtFoot();
Script.Require("jQueryUI_Droppable").AtFoot();
Script.Include("knockout-2.3.0.js").AtFoot();
Script.Include("history.js").AtFoot();
Script.Include("media-library.js").AtFoot();
Style.Require("FontAwesome");
Layout.Title = T("Media Library");

View File

@@ -4,15 +4,15 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@{
Script.Require("jQuery");
Script.Require("jQueryUI");
Script.Require("jQuery").AtFoot();
Script.Require("jQueryUI").AtFoot();
Style.Include("orchard-medialibrary-admin.css");
Style.Include("orchard-mediaproviders-admin.css");
Style.Include("orchard-clientstorage-admin.css");
Script.Require("jQueryFileUpload");
Script.Include("knockout-2.3.0.js");
Script.Require("jQueryFileUpload").AtFoot();
Script.Include("knockout-2.3.0.js").AtFoot();
}
@Display.Metas()

View File

@@ -7,7 +7,7 @@
Script.Require("jQueryUI_Sortable").AtFoot();
Style.Include("media-library-picker-admin.css");
Script.Require("jQueryColorBox");
Script.Require("jQueryColorBox").AtFoot();
Style.Require("jQueryColorBox");
var settings = Model.Field.PartFieldDefinition.Settings.GetModel<MediaLibraryPickerFieldSettings>();

View File

@@ -4,7 +4,7 @@
MediaPart mediaPart = Model.ContentItem.MediaPart;
var contentTypeClassName = mediaPart.ContentItem.ContentType.HtmlClassify();
}
<article class="media-item media-item-summary-admin @contentTypeClassName">
<article class="media-item media-item-summary-admin summary @contentTypeClassName" itemid="@mediaPart.Id">
<header>
@Display(Model.Header)
@if (Model.Meta != null) {

View File

@@ -4,8 +4,8 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@{
Script.Require("jQuery");
Script.Require("jQueryUI");
Script.Require("jQuery").AtFoot();
Script.Require("jQueryUI").AtFoot();
Style.Include("orchard-medialibrary-admin.css");
Style.Include("orchard-mediaproviders-admin.css");

View File

@@ -8,8 +8,8 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
@{
Script.Require("jQuery");
Script.Include("knockout-2.3.0.js");
Script.Require("jQuery").AtFoot();
Script.Include("knockout-2.3.0.js").AtFoot();
Style.Include("orchard-mediaproviders-admin.css");
Style.Include("orchard-websearch-admin.css");

View File

@@ -8,7 +8,7 @@
@{
Style.Require("ModulesAdmin");
Style.Require("Switchable");
Script.Require("Switchable");
Script.Require("Switchable").AtFoot();
Script.Include("features.admin.js", "features.admin.min.js").AtFoot();
Layout.Title = T("Modules").ToString();

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -38,8 +37,6 @@ namespace Orchard.OutputCache.Filters {
private readonly ICacheControlStrategy _cacheControlStrategy;
private Stream _previousFilter;
private const string RefreshKey = "__r";
public OutputCacheFilter(
ICacheManager cacheManager,
IOutputCacheStorageProvider cacheStorageProvider,
@@ -51,7 +48,8 @@ namespace Orchard.OutputCache.Filters {
ICacheService cacheService,
ISignals signals,
ShellSettings shellSettings,
ICacheControlStrategy cacheControlStrategy) {
ICacheControlStrategy cacheControlStrategy
) {
_cacheManager = cacheManager;
_cacheStorageProvider = cacheStorageProvider;
_tagCache = tagCache;
@@ -74,11 +72,10 @@ namespace Orchard.OutputCache.Filters {
private bool _applyCulture;
private string _cacheKey;
private string _invariantCacheKey;
private string _actionName;
private DateTime _now;
private string[] _varyQueryStringParameters;
private ISet<string> _varyRequestHeaders;
private bool _transformRedirect;
private WorkContext _workContext;
private CapturingResponseFilter _filter;
@@ -88,8 +85,6 @@ namespace Orchard.OutputCache.Filters {
public ILogger Logger { get; set; }
public void OnActionExecuting(ActionExecutingContext filterContext) {
// use the action in the cacheKey so that the same route can't return cache for different actions
_actionName = filterContext.ActionDescriptor.ActionName;
// apply OutputCacheAttribute logic if defined
var actionAttributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof(OutputCacheAttribute), true);
@@ -285,12 +280,12 @@ namespace Orchard.OutputCache.Filters {
// no cache content available, intercept the execution results for caching
_previousFilter = response.Filter;
response.Filter = _filter = new CapturingResponseFilter(response.Filter);
response.Filter = _filter = new CapturingResponseFilter();
}
public void OnActionExecuted(ActionExecutedContext filterContext) {
// handle redirections
TransformRedirect(filterContext);
_transformRedirect = TransformRedirect(filterContext);
}
public void OnResultExecuted(ResultExecutedContext filterContext) {
@@ -360,7 +355,6 @@ namespace Orchard.OutputCache.Filters {
response.Filter = null;
response.Write(output);
// check if there is a specific rule not to cache the whole route
var configurations = _cacheService.GetRouteConfigurations();
var route = filterContext.Controller.ControllerContext.RouteData.Route;
@@ -373,12 +367,32 @@ namespace Orchard.OutputCache.Filters {
return;
}
// don't cache the result of a POST redirection as it could contain notifications
if (_transformRedirect) {
return;
}
// don't cache the result if there were some notifications
var messagesZone = _workContextAccessor.GetContext(filterContext).Layout.Zones["Messages"];
var hasNotifications = messagesZone != null && ((IEnumerable<dynamic>)messagesZone).Any();
if (hasNotifications) {
return;
}
// default duration of specific one ?
var cacheDuration = configuration != null && configuration.Duration.HasValue ? configuration.Duration.Value : _cacheDuration;
if (cacheDuration <= 0) {
return;
}
// include each of the content item ids as tags for the cache entry
var contentItemIds = _displayedContentItemHandler.GetDisplayed().Select(x => x.ToString(CultureInfo.InvariantCulture)).ToArray();
if (filterContext.HttpContext.Request.Url == null) {
return;
}
_cacheItem.ContentType = response.ContentType;
_cacheItem.StatusCode = response.StatusCode;
_cacheItem.CachedOnUtc = _now;
@@ -408,6 +422,8 @@ namespace Orchard.OutputCache.Filters {
private bool TransformRedirect(ActionExecutedContext filterContext) {
// removes the target of the redirection from cache after a POST
if (filterContext.Result == null) {
throw new ArgumentNullException();
}
@@ -439,26 +455,6 @@ namespace Orchard.OutputCache.Filters {
_cacheService.RemoveByTag(invariantCacheKey);
// adding a refresh key so that the next request will not be cached
var epIndex = redirectUrl.IndexOf('?');
var qs = new NameValueCollection();
if (epIndex > 0) {
qs = HttpUtility.ParseQueryString(redirectUrl.Substring(epIndex));
}
var refresh = _now.Ticks;
qs.Remove(RefreshKey);
qs.Add(RefreshKey, refresh.ToString("x"));
var querystring = "?" + string.Join("&", Array.ConvertAll(qs.AllKeys, k => string.Format("{0}={1}", HttpUtility.UrlEncode(k), HttpUtility.UrlEncode(qs[k]))));
if (epIndex > 0) {
redirectUrl = redirectUrl.Substring(0, epIndex) + querystring;
}
else {
redirectUrl = redirectUrl + querystring;
}
filterContext.Result = new RedirectResult(redirectUrl, ((RedirectResult) filterContext.Result).Permanent);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
@@ -539,9 +535,6 @@ namespace Orchard.OutputCache.Filters {
// include the theme in the cache key
keyBuilder.Append("theme=").Append(theme.ToLowerInvariant()).Append(";");
// include the theme in the cache key
keyBuilder.Append("action=").Append(_actionName.ToLowerInvariant()).Append(";");
if (parameters != null) {
foreach (var pair in parameters) {
keyBuilder.AppendFormat("{0}={1};", pair.Key.ToLowerInvariant(), Convert.ToString(pair.Value).ToLowerInvariant());
@@ -598,11 +591,9 @@ namespace Orchard.OutputCache.Filters {
/// Captures the response stream while writing to it
/// </summary>
public class CapturingResponseFilter : Stream {
// private readonly Stream _sink;
private readonly MemoryStream _mem;
public CapturingResponseFilter(Stream sink) {
// _sink = sink;
public CapturingResponseFilter() {
_mem = new MemoryStream();
}
@@ -630,27 +621,21 @@ namespace Orchard.OutputCache.Filters {
}
public override void SetLength(long length) {
// _sink.SetLength(length);
}
public override void Close() {
// _sink.Close();
_mem.Close();
}
public override void Flush() {
// _sink.Flush();
}
public override int Read(byte[] buffer, int offset, int count) {
// return _sink.Read(buffer, offset, count);
return count;
}
// Override the Write method to filter Response to a file.
public override void Write(byte[] buffer, int offset, int count) {
//Here we will not write to the sink b/c we want to capture
// _sink.Write(buffer, offset, count);
//Write out the response to the file.
_mem.Write(buffer, 0, count);

View File

@@ -3,9 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Orchard.OutputCache.Models;
using Orchard;
using Orchard.Environment.Configuration;
using Orchard.Services;
namespace Orchard.OutputCache.Services {
public class DefaultCacheStorageProvider : IOutputCacheStorageProvider {

View File

@@ -31,11 +31,8 @@ namespace Orchard.Packaging.Controllers {
ShellSettings shellSettings,
IOrchardServices services,
IPackagingSourceManager packagingSourceManager,
INotifier notifier,
IPackageUpdateService packageUpdateService,
IBackgroundPackageUpdateStatus backgroundPackageUpdateStatus,
IReportsCoordinator reportsCoordinator,
IReportsManager reportsManager,
IShapeFactory shapeFactory) {
_shellSettings = shellSettings;
@@ -45,7 +42,6 @@ namespace Orchard.Packaging.Controllers {
Services = services;
Shape = shapeFactory;
PackageUpdateService = packageUpdateService;
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
@@ -55,7 +51,6 @@ namespace Orchard.Packaging.Controllers {
public Localizer T { get; set; }
public ILogger Logger { get; set; }
public dynamic Shape { get; set; }
public IPackageUpdateService PackageUpdateService { get; set; }
public ActionResult ThemesUpdates(int? reportId, PagerParameters pagerParameters) {
return PackageUpdate("ThemesUpdates", DefaultExtensionTypes.Theme, reportId, pagerParameters);

View File

@@ -311,8 +311,8 @@ namespace Orchard.Projections.Drivers {
int layoutIndexValue;
if (layoutIndex != null
&& Int32.TryParse(layoutIndex, out layoutIndexValue)
&& layoutIndexValue != -1
&& part.Record.QueryPartRecord.Layouts.Count >= layoutIndexValue + 1)
&& layoutIndexValue >= 0
&& part.Record.QueryPartRecord.Layouts.Count > layoutIndexValue)
{
part.Record.LayoutRecord = part.Record.QueryPartRecord.Layouts[Int32.Parse(layoutIndex)];
}

View File

@@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
using System.Security.Policy;
using System.Xml;
using System.Xml.Linq;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Localization;
using Orchard.Logging;
using Orchard.Recipes.Models;
@@ -11,15 +14,20 @@ using Orchard.Settings;
namespace Orchard.Recipes.RecipeHandlers {
public class SettingsRecipeHandler : IRecipeHandler {
private readonly ISiteService _siteService;
private readonly IContentManager _contentManager;
private readonly Lazy<IEnumerable<IContentHandler>> _handlers;
public SettingsRecipeHandler(ISiteService siteService) {
public SettingsRecipeHandler(ISiteService siteService, IContentManager contentManager, Lazy<IEnumerable<IContentHandler>> handlers) {
_siteService = siteService;
_contentManager = contentManager;
_handlers = handlers;
Logger = NullLogger.Instance;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
public ILogger Logger { get; set; }
private IEnumerable<IContentHandler> Handlers { get { return _handlers.Value; } }
/*
<Settings>
@@ -33,41 +41,52 @@ namespace Orchard.Recipes.RecipeHandlers {
return;
}
var site = _siteService.GetSiteSettings();
foreach (var element in recipeContext.RecipeStep.Step.Elements()) {
var partName = XmlConvert.DecodeName(element.Name.LocalName);
foreach (var contentPart in site.ContentItem.Parts) {
if (!String.Equals(contentPart.PartDefinition.Name, partName, StringComparison.OrdinalIgnoreCase)) {
var siteContentItem = _siteService.GetSiteSettings().ContentItem;
var importContentSession = new ImportContentSession(_contentManager);
var context = new ImportContentContext(siteContentItem, recipeContext.RecipeStep.Step, importContentSession);
foreach (var contentHandler in Handlers) {
contentHandler.Importing(context);
}
foreach (var contentPart in siteContentItem.Parts) {
var partElement = context.Data.Element(contentPart.PartDefinition.Name);
if (partElement == null) {
continue;
}
foreach (var attribute in element.Attributes()) {
SetSetting(attribute, contentPart);
}
ImportSettingPart(contentPart, partElement);
}
foreach (var contentHandler in Handlers) {
contentHandler.Imported(context);
}
recipeContext.Executed = true;
}
private static void SetSetting(XAttribute attribute, ContentPart contentPart) {
private void ImportSettingPart(ContentPart sitePart, XElement element) {
foreach (var attribute in element.Attributes()) {
var attributeName = attribute.Name.LocalName;
var attributeValue = attribute.Value;
var property = contentPart.GetType().GetProperty(attributeName);
var property = sitePart.GetType().GetProperty(attributeName);
if (property == null) {
throw new InvalidOperationException(string.Format("Could set setting {0} for part {1} because it was not found.", attributeName, contentPart.PartDefinition.Name));
throw new InvalidOperationException(string.Format("Could set setting {0} for part {1} because it was not found.", attributeName, sitePart.PartDefinition.Name));
}
var propertyType = property.PropertyType;
if (propertyType == typeof(string)) {
property.SetValue(contentPart, attributeValue, null);
property.SetValue(sitePart, attributeValue, null);
}
else if (propertyType == typeof(bool)) {
property.SetValue(contentPart, Boolean.Parse(attributeValue), null);
property.SetValue(sitePart, Boolean.Parse(attributeValue), null);
}
else if (propertyType == typeof(int)) {
property.SetValue(contentPart, Int32.Parse(attributeValue), null);
}
else {
throw new InvalidOperationException(string.Format("Could set setting {0} for part {1} because its type is not supported. Settings should be integer,boolean or string.", attributeName, contentPart.PartDefinition.Name));
property.SetValue(sitePart, Int32.Parse(attributeValue), null);
}
}
}
}

View File

@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers;
using Orchard.Indexing;
using Orchard.Localization;
using Orchard.Search.Models;
@@ -61,5 +63,19 @@ namespace Orchard.Search.Drivers {
return shapeHelper.EditorTemplate(TemplateName: "Parts/Search.SiteSettings", Model: model, Prefix: Prefix);
}).OnGroup("search");
}
protected override void Exporting(SearchSettingsPart part, ExportContentContext context) {
context.Element(part.PartDefinition.Name).Add(new XAttribute("SearchedFields", string.Join(",", part.SearchedFields)));
}
protected override void Importing(SearchSettingsPart part, ImportContentContext context) {
var xElement = context.Data.Element(part.PartDefinition.Name);
if (xElement == null) return;
var searchedFields = xElement.Attribute("SearchedFields");
searchedFields.Remove();
part.SearchedFields = searchedFields.Value.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
}
}
}

View File

@@ -60,6 +60,7 @@
<HintPath>..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,4 +1,5 @@
using System;
using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.FieldStorage.InfosetStorage;
@@ -45,11 +46,13 @@ namespace Orchard.SecureSocketsLayer.Models {
set { this.As<InfosetPart>().Set<SslSettingsPart>("CustomEnabled", value.ToString()); }
}
[Required]
public string SecureHostName {
get { return this.As<InfosetPart>().Get<SslSettingsPart>("SecureHostName"); }
set { this.As<InfosetPart>().Set<SslSettingsPart>("SecureHostName", value); }
}
[Required]
public string InsecureHostName {
get { return this.As<InfosetPart>().Get<SslSettingsPart>("InsecureHostName"); }
set { this.As<InfosetPart>().Set<SslSettingsPart>("InsecureHostName", value); }

View File

@@ -99,6 +99,10 @@ namespace Orchard.SecureSocketsLayer.Services {
var urlHelper = new UrlHelper(requestContext);
var url = urlHelper.Action(actionName, controllerName, requestContext.RouteData);
if (String.IsNullOrWhiteSpace(url)) {
return false;
}
return IsRequestProtected(
url, requestContext.HttpContext.Request.ApplicationPath, settings);
}

View File

@@ -8,6 +8,16 @@
@Html.ValidationMessage("Enabled", "*")
</div>
<div data-controllerid="@Html.FieldIdFor(m => m.Enabled)">
<div>
<label for="@Html.FieldIdFor(m => m.SecureHostName)">@T("Secure Host Name")</label>
@Html.TextBoxFor(m => m.SecureHostName, new { @class = "textMedium" })
<span class="hint">@T("(Mandatory) The host name secured traffic should be redirected to (e.g. localhost:44300, secure.mydomain.com). Don't include the protocol or anything else than the host name. A port can be specified after a colon if necessary (e.g. secure.127-0-0-1.org.uk:4333).")</span>
</div>
<div>
<label for="@Html.FieldIdFor(m => m.InsecureHostName)">@T("Insecure Host Name")</label>
@Html.TextBoxFor(m => m.InsecureHostName, new { @class = "textMedium" })
<span class="hint">@T("(Mandatory) The host name non-secured traffic should be redirected to (e.g. localhost:30321, mydomain.com). Don't include the protocol or anything else than the host name. A port can be specified after a colon if necessary (e.g. dev.127-0-0-1.org.uk:4333).")</span>
</div>
<div>
@Html.EditorFor(m => m.SecureEverything)
<label for="@Html.FieldIdFor(m => m.SecureEverything)" class="forcheckbox">@T("Force SSL on all pages")</label>
@@ -29,16 +39,6 @@
</div>
</div>
</div>
<div>
<label for="@Html.FieldIdFor(m => m.SecureHostName)">@T("Secure Host Name")</label>
@Html.TextBoxFor(m => m.SecureHostName, new { @class = "textMedium" })
<span class="hint">@T("Provide the host name secure traffic should be redirected to (e.g. secure.mydomain.com). Don't include the protocol or anything else than the host name. A port can be specified after a colon if necessary (e.g. secure.127-0-0-1.org.uk:4333).")</span>
</div>
<div>
<label for="@Html.FieldIdFor(m => m.InsecureHostName)">@T("Insecure Host Name")</label>
@Html.TextBoxFor(m => m.InsecureHostName, new { @class = "textMedium" })
<span class="hint">@T("Provide the host name non-secured traffic should be redirected to (e.g. mydomain.com). Don't include the protocol or anything else than the host name. A port can be specified after a colon if necessary (e.g. dev.127-0-0-1.org.uk:4333).")</span>
</div>
</div>
</fieldset>

View File

@@ -59,7 +59,8 @@
site setting set baseurl
theme activate "The Theme Machine"
menu create /MenuName:"Main Menu"
blog create /Title:"Blog" /Homepage:true /Description:"This is your Orchard Blog." /MenuText:"Home" /MenuName:"Main Menu"
blog create /Title:"Blog" /Homepage:true /Description:"This is your Orchard Blog."
menuitem create /MenuPosition:"0" /MenuText:"Home" /Url:"~/" /MenuName:"Main Menu"
widget create MenuWidget /Title:"Main Menu" /RenderTitle:false /Zone:"Navigation" /Position:"1" /Layer:"Default" /Identity:"MenuWidget1" /MenuName:"Main Menu"
</Command>
</Orchard>

View File

@@ -26,6 +26,8 @@
<Migration features="*" />
<Command>
page create /Slug:"welcome-to-orchard" /Title:"Welcome to Orchard!" /Path:"welcome-to-orchard" /Homepage:true /Publish:true /Text:"Welcome To Orchard!" /MenuText:"Home" /MenuName:"Main Menu"
menu create /MenuName:"Main Menu"
page create /Slug:"welcome-to-orchard" /Title:"Welcome to Orchard!" /Path:"welcome-to-orchard" /Homepage:true /Publish:true /Text:"Welcome To Orchard!"
menuitem create /MenuPosition:"0" /MenuText:"Home" /Url:"~/" /MenuName:"Main Menu"
</Command>
</Orchard>

View File

@@ -53,7 +53,8 @@
widget create HtmlWidget /Title:"Third Leader Aside" /Zone:"TripelThird" /Position:"5" /Layer:"TheHomepage" /Identity:"SetupHtmlWidget3" /UseLoremIpsumText:true
site setting set baseurl
menu create /MenuName:"Main Menu"
page create /Slug:"welcome-to-orchard" /Title:"Welcome to Orchard!" /Path:"welcome-to-orchard" /Homepage:true /Publish:true /UseWelcomeText:true /MenuText:"Home" /MenuName:"Main Menu"
page create /Slug:"welcome-to-orchard" /Title:"Welcome to Orchard!" /Path:"welcome-to-orchard" /Homepage:true /Publish:true /UseWelcomeText:true
menuitem create /MenuPosition:"0" /MenuText:"Home" /Url:"~/" /MenuName:"Main Menu"
widget create MenuWidget /Title:"Main Menu" /RenderTitle:false /Zone:"Navigation" /Position:"1" /Layer:"Default" /Identity:"MenuWidget1" /MenuName:"Main Menu"
theme activate "The Theme Machine"
</Command>

View File

@@ -167,6 +167,9 @@ namespace Orchard.Taxonomies.Controllers {
var term = _taxonomyService.NewTerm(taxonomy);
term.Container = parentTerm == null ? taxonomy.ContentItem : parentTerm.ContentItem;
// Create content item before updating so attached fields save correctly
Services.ContentManager.Create(term, VersionOptions.Draft);
var model = Services.ContentManager.UpdateEditor(term, this);
if (!ModelState.IsValid) {
@@ -175,7 +178,7 @@ namespace Orchard.Taxonomies.Controllers {
}
_taxonomyService.ProcessPath(term);
Services.ContentManager.Create(term, VersionOptions.Published);
Services.ContentManager.Publish(term.ContentItem);
Services.Notifier.Information(T("The {0} term has been created.", term.Name));
return RedirectToAction("Index", "TermAdmin", new { taxonomyId });

View File

@@ -32,7 +32,10 @@ namespace Orchard.Taxonomies.Tokens {
context.For<TaxonomyField>("TaxonomyField")
.Token("Terms", field => String.Join(", ", field.Terms.Select(t => t.Name).ToArray()))
.Token(
token => token.StartsWith("Terms:", StringComparison.OrdinalIgnoreCase) ? token.Substring("Terms:".Length) : null,
token => {
var index = 0;
return (token.StartsWith("Terms:", StringComparison.OrdinalIgnoreCase) && int.TryParse(token.Substring("Terms:".Length), out index)) ? index.ToString() : null;
},
(token, t) => {
var index = Convert.ToInt32(token);
return index + 1 > t.Terms.Count() ? null : t.Terms.ElementAt(index).Name;

View File

@@ -30,6 +30,11 @@ namespace Orchard.Users.Commands {
[CommandHelp("user create /UserName:<username> /Password:<password> /Email:<email>\r\n\t" + "Creates a new User")]
[OrchardSwitches("UserName,Password,Email")]
public void Create() {
if (string.IsNullOrWhiteSpace(UserName)) {
Context.Output.WriteLine(T("Username cannot be empty."));
return;
}
if (!_userService.VerifyUserUnicity(UserName, Email)) {
Context.Output.WriteLine(T("User with that username and/or email already exists."));
return;

View File

@@ -121,7 +121,7 @@ namespace Orchard.Users.Controllers {
[HttpPost]
[AlwaysAccessible]
[ValidateInput(false)]
public ActionResult Register(string userName, string email, string password, string confirmPassword) {
public ActionResult Register(string userName, string email, string password, string confirmPassword, string returnUrl = null) {
// ensure users can register
var registrationSettings = _orchardServices.WorkContext.CurrentSite.As<RegistrationSettingsPart>();
if ( !registrationSettings.UsersCanRegister ) {
@@ -153,7 +153,7 @@ namespace Orchard.Users.Controllers {
}
_authenticationService.SignIn(user, false /* createPersistentCookie */);
return Redirect("~/");
return this.RedirectLocal(returnUrl);
}
ModelState.AddModelError("_FORM", T(ErrorCodeToString(/*createStatus*/MembershipCreateStatus.ProviderError)));

View File

@@ -8,7 +8,7 @@
<h1 class="page-title">@Html.TitleForPage((string)Model.Title)</h1>
<p>
@T("Please enter your username and password.")
@if(userCanRegister) { @Html.ActionLink(T("Register").Text, "Register") @T(" if you don't have an account.") }
@if(userCanRegister) { @Html.ActionLink(T("Register").Text, "Register", new { ReturnUrl = Request.QueryString["ReturnUrl"] }) @T(" if you don't have an account.") }
@if(enableLostPassword) { <text> </text> @Html.ActionLink(T("Lost your Password?").Text, "RequestLostPassword") }
</p>
@Html.ValidationSummary(T("Login was unsuccessful. Please correct the errors and try again.").ToString())

View File

@@ -2,7 +2,7 @@
<p>@T("Use the form below to create a new account.")</p>
<p>@T("Passwords are required to be a minimum of {0} characters in length.", ViewData["PasswordLength"])</p>
@Html.ValidationSummary(T("Account creation was unsuccessful. Please correct the errors and try again.").ToString())
@using (Html.BeginFormAntiForgeryPost()) {
@using (Html.BeginFormAntiForgeryPost(Url.Action("Register", new { ReturnUrl = Request.QueryString["ReturnUrl"] }))) {
<fieldset>
<legend>@T("Account Information")</legend>
<div>

View File

@@ -2,7 +2,7 @@
@using Orchard.Widgets.Models;
@{
Style.Require("WidgetsAdmin");
Script.Require("Switchable");
Script.Require("Switchable").AtFoot();
Style.Require("Switchable");
IEnumerable<LayerPart> layers = Model.Layers;
var returnUrl = Request.RawUrl;

View File

@@ -7,7 +7,7 @@
Style.Require("WorkflowsAdmin");
Style.Require("WorkflowsActivities");
Style.Require("jQueryUI_Orchard");
Script.Require("jsPlumb");
Script.Require("jsPlumb").AtFoot();
Script.Include("orchard-workflows-serialize.js").AtFoot();
Script.Include("orchard-workflows.js").AtFoot();
}

View File

@@ -1,6 +1,6 @@
@{
Layout.Title = @T("Edit Activity");
Script.Include("orchard-workflows-serialize.js");
Script.Include("orchard-workflows-serialize.js").AtFoot();
}
@Html.ValidationSummary()

View File

@@ -72,7 +72,7 @@
});
$(".check-all").change(function () {
$(this).parents("table.items").find(":checkbox").prop('checked', $(this).prop("checked"));
$(this).parents("table.items").find(":checkbox:not(:disabled)").prop('checked', $(this).prop("checked"));
});
})(jQuery);

View File

@@ -11,9 +11,9 @@
Style.Include("ie.css").UseCondition("gte IE 9").SetAttribute("media", "screen, projection");
Style.Include("ie8.css").UseCondition("IE 8").SetAttribute("media", "screen, projection");
Style.Include("ie7.css").UseCondition("lte IE 7").SetAttribute("media", "screen, projection");
Script.Require("jQuery");
Script.Require("ShapesBase");
Script.Include("admin.js");
Script.Require("jQuery").AtFoot();
Script.Require("ShapesBase").AtFoot();
Script.Include("admin.js").AtFoot();
/* Some useful shortcuts or settings
***************************************************************/

View File

@@ -1,7 +1,7 @@
@using Orchard.Utility.Extensions;
@{
Script.Require("jQuery");
Script.Include("admin.js");
Script.Include("admin.js").AtFoot();
IEnumerable<dynamic> firstLevelMenuItems = Model;
if (Model.ImageSets != null) {

View File

@@ -52,17 +52,17 @@ namespace Orchard.ContentManagement {
return tuple == null ? null : tuple.Item2;
}
internal IAlias BindCriteriaByPath(IAlias alias, string path) {
return BindCriteriaByAlias(alias, path, PathToAlias(path));
internal IAlias BindCriteriaByPath(IAlias alias, string path, string type = null, Action<IHqlExpressionFactory> withPredicate = null) {
return BindCriteriaByAlias(alias, path, PathToAlias(path), type, withPredicate);
}
internal IAlias BindCriteriaByAlias(IAlias alias, string path, string aliasName) {
internal IAlias BindCriteriaByAlias(IAlias alias, string path, string aliasName, string type = null, Action<IHqlExpressionFactory> withPredicate = null) {
// is this Join already existing (based on aliasName)
Join join = BindNamedAlias(aliasName);
if (join == null) {
join = new Join(path, aliasName);
join = new Join(path, aliasName, type, withPredicate);
_joins.Add(new Tuple<IAlias, Join>(alias, join));
}
@@ -88,19 +88,19 @@ namespace Orchard.ContentManagement {
return _from;
}
internal IAlias BindPartCriteria<TRecord>() where TRecord : ContentPartRecord {
return BindPartCriteria(typeof(TRecord));
internal IAlias BindPartCriteria<TRecord>(string type = null, Action<IHqlExpressionFactory> withPredicate = null) where TRecord : ContentPartRecord {
return BindPartCriteria(typeof(TRecord), type, withPredicate);
}
internal IAlias BindPartCriteria(Type contentPartRecordType) {
internal IAlias BindPartCriteria(Type contentPartRecordType, string type = null, Action<IHqlExpressionFactory> withPredicate = null) {
if (!contentPartRecordType.IsSubclassOf(typeof(ContentPartRecord))) {
throw new ArgumentException("The type must inherit from ContentPartRecord", "contentPartRecordType");
}
if (contentPartRecordType.IsSubclassOf(typeof(ContentPartVersionRecord))) {
return BindCriteriaByPath(BindItemVersionCriteria(), contentPartRecordType.Name);
return BindCriteriaByPath(BindItemVersionCriteria(), contentPartRecordType.Name, type, withPredicate);
}
return BindCriteriaByPath(BindItemCriteria(), contentPartRecordType.Name);
return BindCriteriaByPath(BindItemCriteria(), contentPartRecordType.Name, type, withPredicate);
}
internal void Where(IAlias alias, Action<IHqlExpressionFactory> predicate) {
@@ -246,7 +246,16 @@ namespace Orchard.ContentManagement {
sb.Append("from ").Append(_from.TableName).Append(" as ").Append(_from.Name).AppendLine();
foreach (var join in _joins) {
sb.Append(join.Item2.Type).Append(" ").Append(join.Item1.Name + "." + join.Item2.TableName).Append(" as ").Append(join.Item2.Name).AppendLine();
sb.Append(join.Item2.Type + " " +
join.Item1.Name + "." + join.Item2.TableName +
" as " + join.Item2.Name);
if (join.Item2.WithPredicate != null) {
var predicate = join.Item2.WithPredicate;
var expressionFactory = new DefaultHqlExpressionFactory();
predicate(expressionFactory);
sb.Append(" with " + expressionFactory.Criterion.ToHql(join.Item2));
}
sb.AppendLine();
}
// generating where clause
@@ -378,6 +387,7 @@ namespace Orchard.ContentManagement {
public interface IJoin : IAlias {
string TableName { get; set; }
string Type { get; set; }
Action<IHqlExpressionFactory> WithPredicate { get; set; }
}
public class Sort {
@@ -396,20 +406,26 @@ namespace Orchard.ContentManagement {
public class Join : Alias, IJoin {
public Join(string tableName, string alias)
: this(tableName, alias, "join") {}
: this(tableName, alias, "join", null) {}
public Join(string tableName, string alias, string type)
: this(tableName, alias, type, null) {
}
public Join(string tableName, string alias, string type, Action<IHqlExpressionFactory> withPredicate)
: base(alias) {
if (String.IsNullOrEmpty(tableName)) {
throw new ArgumentException("Table Name can't be empty");
}
TableName = tableName;
Type = type;
Type = type ?? "join";
WithPredicate = withPredicate;
}
public string TableName { get; set; }
public string Type { get; set; }
public Action<IHqlExpressionFactory> WithPredicate { get; set; }
}
public class DefaultHqlSortFactory : IHqlSortFactory
@@ -442,17 +458,17 @@ namespace Orchard.ContentManagement {
Current = _query.BindItemCriteria();
}
public IAliasFactory ContentPartRecord<TRecord>() where TRecord : ContentPartRecord {
Current = _query.BindPartCriteria<TRecord>();
public IAliasFactory ContentPartRecord<TRecord>(string type = null, Action<IHqlExpressionFactory> withPredicate = null) where TRecord : ContentPartRecord {
Current = _query.BindPartCriteria<TRecord>(type, withPredicate);
return this;
}
public IAliasFactory ContentPartRecord(Type contentPartRecord) {
public IAliasFactory ContentPartRecord(Type contentPartRecord, string type = null, Action<IHqlExpressionFactory> withPredicate = null) {
if(!contentPartRecord.IsSubclassOf(typeof(ContentPartRecord))) {
throw new ArgumentException("Type must inherit from ContentPartRecord", "contentPartRecord");
}
Current = _query.BindPartCriteria(contentPartRecord);
Current = _query.BindPartCriteria(contentPartRecord, type, withPredicate);
return this;
}

View File

@@ -30,6 +30,15 @@ namespace Orchard.ContentManagement.Drivers {
if (string.IsNullOrEmpty(placement.Location) || placement.Location == "-")
return;
// parse group placement
var group = placement.GetGroup();
if (!String.IsNullOrEmpty(group)) {
_groupId = group;
}
if (!string.Equals(context.GroupId ?? "", _groupId ?? "", StringComparison.OrdinalIgnoreCase))
return;
dynamic parentShape = context.Shape;
context.ContentPart = ContentPart;
@@ -62,15 +71,6 @@ namespace Orchard.ContentManagement.Drivers {
newShapeMetadata.Wrappers.Clear();
}
// parse group placement
var group = placement.GetGroup();
if (!String.IsNullOrEmpty(group)) {
_groupId = group;
}
if (!string.Equals(context.GroupId ?? "", _groupId ?? "", StringComparison.OrdinalIgnoreCase))
return;
foreach (var alternate in placement.Alternates) {
newShapeMetadata.Alternates.Add(alternate);
}

View File

@@ -133,13 +133,18 @@ namespace Orchard.ContentManagement {
public interface IAliasFactory {
/// <summary>
/// Creates a join on a content part record or returns it if it already exists.
/// <param name="type">The type of join, e.g. "left outer join"</param>
/// <param name="withPredicate">An expression for an additional constraint on the join</param>
/// </summary>
IAliasFactory ContentPartRecord<TRecord>() where TRecord : ContentPartRecord;
IAliasFactory ContentPartRecord<TRecord>(string type = null, Action<IHqlExpressionFactory> withPredicate = null) where TRecord : ContentPartRecord;
/// <summary>
/// Creates a join on a content part record or returns it if it already exists.
/// <param name="contentPartRecord">The type of the part to join</param>
/// <param name="type">The type of join, e.g. "left outer join"</param>
/// <param name="withPredicate">An expression for an additional constraint on the join</param>
/// </summary>
IAliasFactory ContentPartRecord(Type contentPartRecord);
IAliasFactory ContentPartRecord(Type contentPartRecord, string type = null, Action<IHqlExpressionFactory> withPredicate = null);
/// <summary>
/// Creates a join based on a property, or returns it if it already exists.

View File

@@ -2,12 +2,32 @@
using Orchard.Reports.Services;
public static class ReportExtentions {
/// <summary>
/// Adds a new report entry of type information to a report that was previously registered.
/// </summary>
/// <seealso cref="Register()"/>
/// <param name="reportKey">Key, i.e. technical name of the report. Should be the same as the one used when registering the report.</param>
/// <param name="message">The message to include in the entry.</param>
public static void Information(this IReportsCoordinator reportCoordinator, string reportKey, string message) {
reportCoordinator.Add(reportKey, ReportEntryType.Information, message);
}
/// <summary>
/// Adds a new report entry of type warning to a report that was previously registered.
/// </summary>
/// <seealso cref="Register()"/>
/// <param name="reportKey">Key, i.e. technical name of the report. Should be the same as the one used when registering the report.</param>
/// <param name="message">The message to include in the entry.</param>
public static void Warning(this IReportsCoordinator reportCoordinator, string reportKey, string message) {
reportCoordinator.Add(reportKey, ReportEntryType.Warning, message);
}
/// <summary>
/// Adds a new report entry of type error to a report that was previously registered.
/// </summary>
/// <seealso cref="Register()"/>
/// <param name="reportKey">Key, i.e. technical name of the report. Should be the same as the one used when registering the report.</param>
/// <param name="message">The message to include in the entry.</param>
public static void Error(this IReportsCoordinator reportCoordinator, string reportKey, string message) {
reportCoordinator.Add(reportKey, ReportEntryType.Error, message);
}

View File

@@ -1,6 +1,30 @@
namespace Orchard.Reports.Services {
/// <summary>
/// Exposes a simplified interface for creating reports. Reports provide user-accessible log-like functionality.
/// </summary>
/// <remarks>
/// <see cref="Orchard.Reports.Services.IReportsManager"/> can be used too to create reports directly.
/// </remarks>
public interface IReportsCoordinator : IDependency {
/// <summary>
/// Adds a new report entry to a report that was previously registered.
/// </summary>
/// <remarks>
/// Entries can be only added to a report that was previously registered through Register().
/// </remarks>
/// <seealso cref="Register()"/>
/// <param name="reportKey">Key, i.e. technical name of the report. Should be the same as the one used when registering the report.</param>
/// <param name="type">Type of the entry.</param>
/// <param name="message">The message to include in the entry.</param>
void Add(string reportKey, ReportEntryType type, string message);
/// <summary>
/// Registers a new report so entries can be added to it.
/// </summary>
/// <param name="reportKey">Key, i.e. technical name of the report.</param>
/// <param name="activityName">Name of the activity the report is about (e.g. "Upgrade").</param>
/// <param name="title">A title better describing what the report is about (e.g. "Migrating routes of Pages, Blog Posts").</param>
/// <returns>The report's numerical ID.</returns>
int Register(string reportKey, string activityName, string title);
}
}

View File

@@ -1,6 +1,12 @@
using System.Collections.Generic;
namespace Orchard.Reports.Services {
/// <summary>
/// Service for handling reports. Reports provide user-accessible log-like functionality.
/// </summary>
/// <remarks>
/// You can use <see cref="Orchard.Reports.Services.IReportsCoordinator"/> to create reports through a simplified interface.
/// </remarks>
public interface IReportsManager : ISingletonDependency {
void Add(int reportId, ReportEntryType type, string message);
int CreateReport(string title, string activityName);

View File

@@ -1,6 +1,12 @@
using System.Collections.Generic;
namespace Orchard.Reports.Services {
/// <summary>
/// Defines a service that can be used to persist reports.
/// </summary>
/// <remarks>
/// Implementations of this interface are commonly used from <see cref="Orchard.Reports.Services.IReportsManager"/> implementations.
/// </remarks>
public interface IReportsPersister : IDependency {
IEnumerable<Report> Fetch();
void Save(IEnumerable<Report> reports);

View File

@@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Orchard.Localization;
using System.Web;
namespace Orchard.Utility.Extensions {
public static class StringExtensions {
@@ -89,7 +90,7 @@ namespace Orchard.Utility.Extensions {
: new LocalizedString(text);
}
public static string RemoveTags(this string html) {
public static string RemoveTags(this string html, bool htmlDecode = false) {
if (String.IsNullOrEmpty(html)) {
return String.Empty;
}
@@ -115,7 +116,13 @@ namespace Orchard.Utility.Extensions {
}
}
return new string(result, 0, cursor);
var stringResult = new string(result, 0, cursor);
if (htmlDecode) {
stringResult = HttpUtility.HtmlDecode(stringResult);
}
return stringResult;
}
// not accounting for only \r (e.g. Apple OS 9 carriage return only new lines)
@@ -167,9 +174,7 @@ namespace Orchard.Utility.Extensions {
name = RemoveDiacritics(name);
name = name.Strip(c =>
c != '_'
&& c != '-'
&& !c.IsLetter()
!c.IsLetter()
&& !Char.IsDigit(c)
);