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] [Test]
public void StatusCodeShouldBe404ForUnexistingResources() { 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, Is.Not.Null);
Assert.That(download.StatusCode, Is.EqualTo(HttpStatusCode.NotFound)); Assert.That(download.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
Assert.That(download.Content, Is.Null); Assert.That(download.Content, Is.Null);
@@ -28,7 +28,7 @@ namespace Orchard.Tests.Modules.Warmup {
[Test] [Test]
public void StatusCodeShouldBe200ForValidRequests() { 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, Is.Not.Null);
Assert.That(download.StatusCode, Is.EqualTo(HttpStatusCode.OK)); Assert.That(download.StatusCode, Is.EqualTo(HttpStatusCode.OK));
Assert.That(download.Content, Is.Not.Empty); Assert.That(download.Content, Is.Not.Empty);

View File

@@ -121,7 +121,10 @@ namespace Orchard.Core.Contents.Controllers {
} }
private IEnumerable<ContentTypeDefinition> GetCreatableTypes(bool andContainable) { 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")] [HttpPost, ActionName("List")]

View File

@@ -6,9 +6,9 @@
Layout.Title = T("Navigation").ToString(); Layout.Title = T("Navigation").ToString();
Style.Include("navigation-admin.css"); Style.Include("navigation-admin.css");
Script.Require("jQueryUI_Sortable"); Script.Require("jQueryUI_Sortable").AtFoot();
Script.Include("jquery.mjs.nestedSortable.js"); Script.Include("jquery.mjs.nestedSortable.js").AtFoot();
Script.Include("navigation-admin.js"); 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> <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> <fieldset>
@Html.EditorFor(m => m.OnAdminMenu) @Html.EditorFor(m => m.OnAdminMenu)
<label for="OnAdminMenu" class="forcheckbox">@T("Show on admin menu")</label> <label for="@Html.FieldIdFor(m => m.OnAdminMenu)" class="forcheckbox">@T("Show on admin menu")</label>
<div data-controllerid="OnAdminMenu" class=""> <div data-controllerid="@Html.FieldIdFor(m => m.OnAdminMenu)" class="">
<label for="AdminMenuText">@T("Menu text")</label> <label for="@Html.FieldIdFor(m => m.AdminMenuText)">@T("Menu text")</label>
@Html.TextBoxFor(m => m.AdminMenuText, new { @class = "text single-line" }) @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> <label for="@Html.FieldIdFor(m => m.AdminMenuPosition)">@T("Position")</label>
@Html.TextBoxFor(m => m.AdminMenuPosition, new { @class = "text single-line" }) @Html.TextBoxFor(m => m.AdminMenuPosition, new { @class = "text small" })
<span class="hint">@T("The position in the menu.")</span>
</div> </div>
</fieldset> </fieldset>

View File

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

View File

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

View File

@@ -9,6 +9,7 @@ using Orchard.AntiSpam.ViewModels;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.Drivers;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Logging;
using Orchard.UI.Admin; using Orchard.UI.Admin;
using Orchard.UI.Notify; using Orchard.UI.Notify;
@@ -25,10 +26,11 @@ namespace Orchard.AntiSpam.Drivers {
_notifier = notifier; _notifier = notifier;
_workContextAccessor = workContextAccessor; _workContextAccessor = workContextAccessor;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
} }
public Localizer T { get; set; } public Localizer T { get; set; }
public ILogger Logger { get; set; }
protected override DriverResult Editor(ReCaptchaPart part, dynamic shapeHelper) { protected override DriverResult Editor(ReCaptchaPart part, dynamic shapeHelper) {
var workContext = _workContextAccessor.GetContext(); var workContext = _workContextAccessor.GetContext();
@@ -70,16 +72,22 @@ namespace Orchard.AntiSpam.Drivers {
if(updater.TryUpdateModel(submitViewModel, String.Empty, null, null)) { if(updater.TryUpdateModel(submitViewModel, String.Empty, null, null)) {
var context = workContext.HttpContext; var context = workContext.HttpContext;
var result = ExecuteValidateRequest( try {
settings.PrivateKey, var result = ExecuteValidateRequest(
context.Request.ServerVariables["REMOTE_ADDR"], settings.PrivateKey,
submitViewModel.recaptcha_challenge_field, context.Request.ServerVariables["REMOTE_ADDR"],
submitViewModel.recaptcha_response_field submitViewModel.recaptcha_challenge_field,
); submitViewModel.recaptcha_response_field
);
if(!HandleValidateResponse(context, result)) { if (!HandleValidateResponse(context, result)) {
_notifier.Error(T("The text you entered in the Captcha field does not match the image")); _notifier.Error(T("The text you entered in the Captcha field does not match the image"));
updater.AddModelError("", T("The text you entered in the Captcha field does not match the image")); 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"));
} }
} }

View File

@@ -48,6 +48,10 @@ namespace Orchard.Azure.Services.Caching.Output {
} }
public void Set(string key, CacheItem cacheItem) { public void Set(string key, CacheItem cacheItem) {
if (cacheItem.ValidFor <= 0) {
return;
}
Logger.Debug("Set() invoked with key='{0}' in region '{1}'.", key, _regionAlphaNumeric); Logger.Debug("Set() invoked with key='{0}' in region '{1}'.", key, _regionAlphaNumeric);
_cache.Put(key, cacheItem, TimeSpan.FromSeconds(cacheItem.ValidFor), _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 the user who submitted the comment has the right to moderate, don't make this comment moderated
if (Services.Authorizer.Authorize(Permissions.ManageComments)) { if (Services.Authorizer.Authorize(Permissions.ManageComments)) {
commentPart.Status = CommentStatus.Approved; commentPart.Status = CommentStatus.Approved;
Services.Notifier.Information(T("Your comment has been posted."));
} }
else { else {
Services.Notifier.Information(T("Your comment will appear after the site administrator approves it.")); 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 { else {
Services.TransactionManager.Cancel(); Services.TransactionManager.Cancel();

View File

@@ -52,12 +52,32 @@
(function ($) { (function ($) {
var assignPositions = function () { var assignPositions = function () {
var position = 1; var position = 0;
$('.position').each(function() { $('.type').each(function () {
$(this).val(position++); 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(); assignPositions();
var startPos; var startPos;

View File

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

View File

@@ -39,7 +39,9 @@ namespace Orchard.MediaLibrary.Controllers {
public ILogger Logger { get; set; } public ILogger Logger { get; set; }
public ActionResult Index(string folderPath = "", bool dialog = false) { 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 // let other modules enhance the ui by providing custom navigation and actions
var explorer = Services.ContentManager.New("MediaLibraryExplorer"); var explorer = Services.ContentManager.New("MediaLibraryExplorer");
explorer.Weld(new MediaLibraryExplorerPart()); explorer.Weld(new MediaLibraryExplorerPart());
@@ -67,6 +69,8 @@ namespace Orchard.MediaLibrary.Controllers {
} }
public ActionResult Import(string folderPath) { public ActionResult Import(string folderPath) {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot import media")))
return new HttpUnauthorizedResult();
var mediaProviderMenu = _navigationManager.BuildMenu("mediaproviders"); var mediaProviderMenu = _navigationManager.BuildMenu("mediaproviders");
var imageSets = _navigationManager.BuildImageSets("mediaproviders"); var imageSets = _navigationManager.BuildImageSets("mediaproviders");
@@ -83,8 +87,11 @@ namespace Orchard.MediaLibrary.Controllers {
[Themed(false)] [Themed(false)]
public ActionResult MediaItems(string folderPath, int skip = 0, int count = 0, string order = "created", string mediaType = "") { 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); if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot view media")))
var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(folderPath, mediaType, VersionOptions.Latest); 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 { var mediaItems = mediaParts.Select(x => new MediaManagerMediaItemViewModel {
MediaPart = x, MediaPart = x,
@@ -115,8 +122,12 @@ namespace Orchard.MediaLibrary.Controllers {
[Themed(false)] [Themed(false)]
public ActionResult RecentMediaItems(int skip = 0, int count = 0, string order = "created", string mediaType = "") { public ActionResult RecentMediaItems(int skip = 0, int count = 0, string order = "created", string mediaType = "") {
var mediaParts = _mediaLibraryService.GetMediaContentItems(skip, count, order, mediaType, VersionOptions.Latest); if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot view media")))
var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(mediaType, VersionOptions.Latest); return new HttpUnauthorizedResult();
var mediaParts = _mediaLibraryService.GetMediaContentItems(skip, count, order, mediaType);
var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(mediaType);
var mediaItems = mediaParts.Select(x => new MediaManagerMediaItemViewModel { var mediaItems = mediaParts.Select(x => new MediaManagerMediaItemViewModel {
MediaPart = x, MediaPart = x,
@@ -138,7 +149,7 @@ namespace Orchard.MediaLibrary.Controllers {
if (contentItem == null) if (contentItem == null)
return HttpNotFound(); 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(); return new HttpUnauthorizedResult();
dynamic model = Services.ContentManager.BuildDisplay(contentItem, displayType); 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)) if (!(filterContext.Result is ViewResult) || !UI.Admin.AdminFilter.IsApplied(filterContext.RequestContext))
return; return;
_resourceManager.Include("stylesheet", "~/Modules/Orchard.MediaLibrary/Styles/dialog-mode.css", null); _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) { public void OnResultExecuted(ResultExecutedContext filterContext) {

View File

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

View File

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

View File

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

View File

@@ -4,19 +4,19 @@
MediaPart mediaPart = Model.ContentItem.MediaPart; MediaPart mediaPart = Model.ContentItem.MediaPart;
var contentTypeClassName = mediaPart.ContentItem.ContentType.HtmlClassify(); 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> <header>
@Display(Model.Header) @Display(Model.Header)
@if (Model.Meta != null) { @if (Model.Meta != null) {
<div class="properties"> <div class="properties">
@Display(Model.Meta) @Display(Model.Meta)
</div> </div>
} }
</header> </header>
@Display(Model.Content) @Display(Model.Content)
@if(Model.Footer != null) { @if (Model.Footer != null) {
<footer> <footer>
@Display(Model.Footer) @Display(Model.Footer)
</footer> </footer>
} }
</article> </article>

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -38,8 +37,6 @@ namespace Orchard.OutputCache.Filters {
private readonly ICacheControlStrategy _cacheControlStrategy; private readonly ICacheControlStrategy _cacheControlStrategy;
private Stream _previousFilter; private Stream _previousFilter;
private const string RefreshKey = "__r";
public OutputCacheFilter( public OutputCacheFilter(
ICacheManager cacheManager, ICacheManager cacheManager,
IOutputCacheStorageProvider cacheStorageProvider, IOutputCacheStorageProvider cacheStorageProvider,
@@ -51,7 +48,8 @@ namespace Orchard.OutputCache.Filters {
ICacheService cacheService, ICacheService cacheService,
ISignals signals, ISignals signals,
ShellSettings shellSettings, ShellSettings shellSettings,
ICacheControlStrategy cacheControlStrategy) { ICacheControlStrategy cacheControlStrategy
) {
_cacheManager = cacheManager; _cacheManager = cacheManager;
_cacheStorageProvider = cacheStorageProvider; _cacheStorageProvider = cacheStorageProvider;
_tagCache = tagCache; _tagCache = tagCache;
@@ -74,11 +72,10 @@ namespace Orchard.OutputCache.Filters {
private bool _applyCulture; private bool _applyCulture;
private string _cacheKey; private string _cacheKey;
private string _invariantCacheKey; private string _invariantCacheKey;
private string _actionName;
private DateTime _now; private DateTime _now;
private string[] _varyQueryStringParameters; private string[] _varyQueryStringParameters;
private ISet<string> _varyRequestHeaders; private ISet<string> _varyRequestHeaders;
private bool _transformRedirect;
private WorkContext _workContext; private WorkContext _workContext;
private CapturingResponseFilter _filter; private CapturingResponseFilter _filter;
@@ -88,8 +85,6 @@ namespace Orchard.OutputCache.Filters {
public ILogger Logger { get; set; } public ILogger Logger { get; set; }
public void OnActionExecuting(ActionExecutingContext filterContext) { 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 // apply OutputCacheAttribute logic if defined
var actionAttributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof(OutputCacheAttribute), true); 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 // no cache content available, intercept the execution results for caching
_previousFilter = response.Filter; _previousFilter = response.Filter;
response.Filter = _filter = new CapturingResponseFilter(response.Filter); response.Filter = _filter = new CapturingResponseFilter();
} }
public void OnActionExecuted(ActionExecutedContext filterContext) { public void OnActionExecuted(ActionExecutedContext filterContext) {
// handle redirections // handle redirections
TransformRedirect(filterContext); _transformRedirect = TransformRedirect(filterContext);
} }
public void OnResultExecuted(ResultExecutedContext filterContext) { public void OnResultExecuted(ResultExecutedContext filterContext) {
@@ -343,7 +338,7 @@ namespace Orchard.OutputCache.Filters {
} }
return; return;
} }
// save the result only if the content can be intercepted // save the result only if the content can be intercepted
if (_filter == null) return; if (_filter == null) return;
@@ -359,8 +354,7 @@ namespace Orchard.OutputCache.Filters {
response.Filter = null; response.Filter = null;
response.Write(output); response.Write(output);
// check if there is a specific rule not to cache the whole route // check if there is a specific rule not to cache the whole route
var configurations = _cacheService.GetRouteConfigurations(); var configurations = _cacheService.GetRouteConfigurations();
var route = filterContext.Controller.ControllerContext.RouteData.Route; var route = filterContext.Controller.ControllerContext.RouteData.Route;
@@ -373,12 +367,32 @@ namespace Orchard.OutputCache.Filters {
return; 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 ? // default duration of specific one ?
var cacheDuration = configuration != null && configuration.Duration.HasValue ? configuration.Duration.Value : _cacheDuration; 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 // include each of the content item ids as tags for the cache entry
var contentItemIds = _displayedContentItemHandler.GetDisplayed().Select(x => x.ToString(CultureInfo.InvariantCulture)).ToArray(); var contentItemIds = _displayedContentItemHandler.GetDisplayed().Select(x => x.ToString(CultureInfo.InvariantCulture)).ToArray();
if (filterContext.HttpContext.Request.Url == null) {
return;
}
_cacheItem.ContentType = response.ContentType; _cacheItem.ContentType = response.ContentType;
_cacheItem.StatusCode = response.StatusCode; _cacheItem.StatusCode = response.StatusCode;
_cacheItem.CachedOnUtc = _now; _cacheItem.CachedOnUtc = _now;
@@ -408,6 +422,8 @@ namespace Orchard.OutputCache.Filters {
private bool TransformRedirect(ActionExecutedContext filterContext) { private bool TransformRedirect(ActionExecutedContext filterContext) {
// removes the target of the redirection from cache after a POST
if (filterContext.Result == null) { if (filterContext.Result == null) {
throw new ArgumentNullException(); throw new ArgumentNullException();
} }
@@ -439,26 +455,6 @@ namespace Orchard.OutputCache.Filters {
_cacheService.RemoveByTag(invariantCacheKey); _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.Result = new RedirectResult(redirectUrl, ((RedirectResult) filterContext.Result).Permanent);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache); filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
@@ -539,9 +535,6 @@ namespace Orchard.OutputCache.Filters {
// include the theme in the cache key // include the theme in the cache key
keyBuilder.Append("theme=").Append(theme.ToLowerInvariant()).Append(";"); keyBuilder.Append("theme=").Append(theme.ToLowerInvariant()).Append(";");
// include the theme in the cache key
keyBuilder.Append("action=").Append(_actionName.ToLowerInvariant()).Append(";");
if (parameters != null) { if (parameters != null) {
foreach (var pair in parameters) { foreach (var pair in parameters) {
keyBuilder.AppendFormat("{0}={1};", pair.Key.ToLowerInvariant(), Convert.ToString(pair.Value).ToLowerInvariant()); 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 /// Captures the response stream while writing to it
/// </summary> /// </summary>
public class CapturingResponseFilter : Stream { public class CapturingResponseFilter : Stream {
// private readonly Stream _sink;
private readonly MemoryStream _mem; private readonly MemoryStream _mem;
public CapturingResponseFilter(Stream sink) { public CapturingResponseFilter() {
// _sink = sink;
_mem = new MemoryStream(); _mem = new MemoryStream();
} }
@@ -630,27 +621,21 @@ namespace Orchard.OutputCache.Filters {
} }
public override void SetLength(long length) { public override void SetLength(long length) {
// _sink.SetLength(length);
} }
public override void Close() { public override void Close() {
// _sink.Close();
_mem.Close(); _mem.Close();
} }
public override void Flush() { public override void Flush() {
// _sink.Flush();
} }
public override int Read(byte[] buffer, int offset, int count) { public override int Read(byte[] buffer, int offset, int count) {
// return _sink.Read(buffer, offset, count);
return count; return count;
} }
// Override the Write method to filter Response to a file. // Override the Write method to filter Response to a file.
public override void Write(byte[] buffer, int offset, int count) { 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. //Write out the response to the file.
_mem.Write(buffer, 0, count); _mem.Write(buffer, 0, count);

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,8 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Xml.Linq;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers;
using Orchard.Indexing; using Orchard.Indexing;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Search.Models; using Orchard.Search.Models;
@@ -61,5 +63,19 @@ namespace Orchard.Search.Drivers {
return shapeHelper.EditorTemplate(TemplateName: "Parts/Search.SiteSettings", Model: model, Prefix: Prefix); return shapeHelper.EditorTemplate(TemplateName: "Parts/Search.SiteSettings", Model: model, Prefix: Prefix);
}).OnGroup("search"); }).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> <HintPath>..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Web" /> <Reference Include="System.Web" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

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

View File

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

View File

@@ -8,6 +8,16 @@
@Html.ValidationMessage("Enabled", "*") @Html.ValidationMessage("Enabled", "*")
</div> </div>
<div data-controllerid="@Html.FieldIdFor(m => m.Enabled)"> <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> <div>
@Html.EditorFor(m => m.SecureEverything) @Html.EditorFor(m => m.SecureEverything)
<label for="@Html.FieldIdFor(m => m.SecureEverything)" class="forcheckbox">@T("Force SSL on all pages")</label> <label for="@Html.FieldIdFor(m => m.SecureEverything)" class="forcheckbox">@T("Force SSL on all pages")</label>
@@ -29,16 +39,6 @@
</div> </div>
</div> </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> </div>
</fieldset> </fieldset>

View File

@@ -59,7 +59,8 @@
site setting set baseurl site setting set baseurl
theme activate "The Theme Machine" theme activate "The Theme Machine"
menu create /MenuName:"Main Menu" 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" widget create MenuWidget /Title:"Main Menu" /RenderTitle:false /Zone:"Navigation" /Position:"1" /Layer:"Default" /Identity:"MenuWidget1" /MenuName:"Main Menu"
</Command> </Command>
</Orchard> </Orchard>

View File

@@ -26,6 +26,8 @@
<Migration features="*" /> <Migration features="*" />
<Command> <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> </Command>
</Orchard> </Orchard>

View File

@@ -53,7 +53,8 @@
widget create HtmlWidget /Title:"Third Leader Aside" /Zone:"TripelThird" /Position:"5" /Layer:"TheHomepage" /Identity:"SetupHtmlWidget3" /UseLoremIpsumText:true widget create HtmlWidget /Title:"Third Leader Aside" /Zone:"TripelThird" /Position:"5" /Layer:"TheHomepage" /Identity:"SetupHtmlWidget3" /UseLoremIpsumText:true
site setting set baseurl site setting set baseurl
menu create /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 /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" widget create MenuWidget /Title:"Main Menu" /RenderTitle:false /Zone:"Navigation" /Position:"1" /Layer:"Default" /Identity:"MenuWidget1" /MenuName:"Main Menu"
theme activate "The Theme Machine" theme activate "The Theme Machine"
</Command> </Command>

View File

@@ -167,6 +167,9 @@ namespace Orchard.Taxonomies.Controllers {
var term = _taxonomyService.NewTerm(taxonomy); var term = _taxonomyService.NewTerm(taxonomy);
term.Container = parentTerm == null ? taxonomy.ContentItem : parentTerm.ContentItem; 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); var model = Services.ContentManager.UpdateEditor(term, this);
if (!ModelState.IsValid) { if (!ModelState.IsValid) {
@@ -175,7 +178,7 @@ namespace Orchard.Taxonomies.Controllers {
} }
_taxonomyService.ProcessPath(term); _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)); Services.Notifier.Information(T("The {0} term has been created.", term.Name));
return RedirectToAction("Index", "TermAdmin", new { taxonomyId }); return RedirectToAction("Index", "TermAdmin", new { taxonomyId });

View File

@@ -32,7 +32,10 @@ namespace Orchard.Taxonomies.Tokens {
context.For<TaxonomyField>("TaxonomyField") context.For<TaxonomyField>("TaxonomyField")
.Token("Terms", field => String.Join(", ", field.Terms.Select(t => t.Name).ToArray())) .Token("Terms", field => String.Join(", ", field.Terms.Select(t => t.Name).ToArray()))
.Token( .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) => { (token, t) => {
var index = Convert.ToInt32(token); var index = Convert.ToInt32(token);
return index + 1 > t.Terms.Count() ? null : t.Terms.ElementAt(index).Name; 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")] [CommandHelp("user create /UserName:<username> /Password:<password> /Email:<email>\r\n\t" + "Creates a new User")]
[OrchardSwitches("UserName,Password,Email")] [OrchardSwitches("UserName,Password,Email")]
public void Create() { public void Create() {
if (string.IsNullOrWhiteSpace(UserName)) {
Context.Output.WriteLine(T("Username cannot be empty."));
return;
}
if (!_userService.VerifyUserUnicity(UserName, Email)) { if (!_userService.VerifyUserUnicity(UserName, Email)) {
Context.Output.WriteLine(T("User with that username and/or email already exists.")); Context.Output.WriteLine(T("User with that username and/or email already exists."));
return; return;

View File

@@ -121,7 +121,7 @@ namespace Orchard.Users.Controllers {
[HttpPost] [HttpPost]
[AlwaysAccessible] [AlwaysAccessible]
[ValidateInput(false)] [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 // ensure users can register
var registrationSettings = _orchardServices.WorkContext.CurrentSite.As<RegistrationSettingsPart>(); var registrationSettings = _orchardServices.WorkContext.CurrentSite.As<RegistrationSettingsPart>();
if ( !registrationSettings.UsersCanRegister ) { if ( !registrationSettings.UsersCanRegister ) {
@@ -153,7 +153,7 @@ namespace Orchard.Users.Controllers {
} }
_authenticationService.SignIn(user, false /* createPersistentCookie */); _authenticationService.SignIn(user, false /* createPersistentCookie */);
return Redirect("~/"); return this.RedirectLocal(returnUrl);
} }
ModelState.AddModelError("_FORM", T(ErrorCodeToString(/*createStatus*/MembershipCreateStatus.ProviderError))); ModelState.AddModelError("_FORM", T(ErrorCodeToString(/*createStatus*/MembershipCreateStatus.ProviderError)));
@@ -197,7 +197,7 @@ namespace Orchard.Users.Controllers {
_userService.SendLostPasswordEmail(username, nonce => Url.MakeAbsolute(Url.Action("LostPassword", "Account", new { Area = "Orchard.Users", nonce = nonce }), siteUrl)); _userService.SendLostPasswordEmail(username, nonce => Url.MakeAbsolute(Url.Action("LostPassword", "Account", new { Area = "Orchard.Users", nonce = nonce }), siteUrl));
_orchardServices.Notifier.Information(T("Check your e-mail for the confirmation link.")); _orchardServices.Notifier.Information(T("Check your e-mail for the confirmation link."));
return RedirectToAction("LogOn"); return RedirectToAction("LogOn");
} }

View File

@@ -8,7 +8,7 @@
<h1 class="page-title">@Html.TitleForPage((string)Model.Title)</h1> <h1 class="page-title">@Html.TitleForPage((string)Model.Title)</h1>
<p> <p>
@T("Please enter your username and password.") @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") } @if(enableLostPassword) { <text> </text> @Html.ActionLink(T("Lost your Password?").Text, "RequestLostPassword") }
</p> </p>
@Html.ValidationSummary(T("Login was unsuccessful. Please correct the errors and try again.").ToString()) @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("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> <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()) @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> <fieldset>
<legend>@T("Account Information")</legend> <legend>@T("Account Information")</legend>
<div> <div>

View File

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

View File

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

View File

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

View File

@@ -72,7 +72,7 @@
}); });
$(".check-all").change(function () { $(".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); })(jQuery);

View File

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

View File

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

View File

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

View File

@@ -30,6 +30,15 @@ namespace Orchard.ContentManagement.Drivers {
if (string.IsNullOrEmpty(placement.Location) || placement.Location == "-") if (string.IsNullOrEmpty(placement.Location) || placement.Location == "-")
return; 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; dynamic parentShape = context.Shape;
context.ContentPart = ContentPart; context.ContentPart = ContentPart;
@@ -62,15 +71,6 @@ namespace Orchard.ContentManagement.Drivers {
newShapeMetadata.Wrappers.Clear(); 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) { foreach (var alternate in placement.Alternates) {
newShapeMetadata.Alternates.Add(alternate); newShapeMetadata.Alternates.Add(alternate);
} }

View File

@@ -133,13 +133,18 @@ namespace Orchard.ContentManagement {
public interface IAliasFactory { public interface IAliasFactory {
/// <summary> /// <summary>
/// Creates a join on a content part record or returns it if it already exists. /// 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> /// </summary>
IAliasFactory ContentPartRecord<TRecord>() where TRecord : ContentPartRecord; IAliasFactory ContentPartRecord<TRecord>(string type = null, Action<IHqlExpressionFactory> withPredicate = null) where TRecord : ContentPartRecord;
/// <summary> /// <summary>
/// Creates a join on a content part record or returns it if it already exists. /// 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> /// </summary>
IAliasFactory ContentPartRecord(Type contentPartRecord); IAliasFactory ContentPartRecord(Type contentPartRecord, string type = null, Action<IHqlExpressionFactory> withPredicate = null);
/// <summary> /// <summary>
/// Creates a join based on a property, or returns it if it already exists. /// Creates a join based on a property, or returns it if it already exists.

View File

@@ -2,12 +2,32 @@
using Orchard.Reports.Services; using Orchard.Reports.Services;
public static class ReportExtentions { 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) { public static void Information(this IReportsCoordinator reportCoordinator, string reportKey, string message) {
reportCoordinator.Add(reportKey, ReportEntryType.Information, 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) { public static void Warning(this IReportsCoordinator reportCoordinator, string reportKey, string message) {
reportCoordinator.Add(reportKey, ReportEntryType.Warning, 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) { public static void Error(this IReportsCoordinator reportCoordinator, string reportKey, string message) {
reportCoordinator.Add(reportKey, ReportEntryType.Error, message); reportCoordinator.Add(reportKey, ReportEntryType.Error, message);
} }

View File

@@ -1,6 +1,30 @@
namespace Orchard.Reports.Services { 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 { 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); 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); int Register(string reportKey, string activityName, string title);
} }
} }

View File

@@ -1,6 +1,12 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace Orchard.Reports.Services { 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 { public interface IReportsManager : ISingletonDependency {
void Add(int reportId, ReportEntryType type, string message); void Add(int reportId, ReportEntryType type, string message);
int CreateReport(string title, string activityName); int CreateReport(string title, string activityName);

View File

@@ -1,6 +1,12 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace Orchard.Reports.Services { 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 { public interface IReportsPersister : IDependency {
IEnumerable<Report> Fetch(); IEnumerable<Report> Fetch();
void Save(IEnumerable<Report> reports); void Save(IEnumerable<Report> reports);

View File

@@ -5,6 +5,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Orchard.Localization; using Orchard.Localization;
using System.Web;
namespace Orchard.Utility.Extensions { namespace Orchard.Utility.Extensions {
public static class StringExtensions { public static class StringExtensions {
@@ -89,7 +90,7 @@ namespace Orchard.Utility.Extensions {
: new LocalizedString(text); : new LocalizedString(text);
} }
public static string RemoveTags(this string html) { public static string RemoveTags(this string html, bool htmlDecode = false) {
if (String.IsNullOrEmpty(html)) { if (String.IsNullOrEmpty(html)) {
return String.Empty; 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) // 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 = RemoveDiacritics(name);
name = name.Strip(c => name = name.Strip(c =>
c != '_' !c.IsLetter()
&& c != '-'
&& !c.IsLetter()
&& !Char.IsDigit(c) && !Char.IsDigit(c)
); );