Merge with 1.x

This commit is contained in:
Sebastien Ros 2012-10-26 19:00:13 -07:00
commit 395029fdbd
41 changed files with 156 additions and 414 deletions

View File

@ -84,7 +84,7 @@
<ItemGroup>
<!-- filter to exclude any binary from a folder -->
<Excluded Include="$(SrcFolder)\**\bin\**\*;$(SrcFolder)\**\obj\**\*;$(SrcFolder)\**\*.user; $(SrcFolder)\**\*.cs;$(SrcFolder)\**\*.csproj" />
<Excluded Include="$(SrcFolder)\**\bin\**\*;$(SrcFolder)\**\obj\**\*;$(SrcFolder)\**\*.user; $(SrcFolder)\**\*.cs;$(SrcFolder)\**\*.csproj;$(SrcFolder)\**\.hg\**\*" />
<!-- list of files from Themes, Core and Modules to export -->
<Stage-Themes Include="$(SrcFolder)\Orchard.Web\Themes\**\*" Exclude="@(Excluded)" />

View File

@ -1,5 +1,5 @@
REM Check if this task is running on the compute emulator, if not then sets the Idle Timeout to zero
IF "%ComputeEmulatorRunning%" == "true" (
IF "%ComputeEmulatorRunning%" == "false" (
%windir%\system32\inetsrv\appcmd set config -section:applicationPools -applicationPoolDefaults.processModel.idleTimeout:00:00:00
)

View File

@ -190,5 +190,17 @@ namespace Orchard.Tests.Data {
Assert.That(one.Name, Is.EqualTo("one"));
Assert.That(one.Timespan.Value.Millisecond, Is.EqualTo(489));
}
[Test]
public void RepositoryFetchTakesExistsPredicate() {
CreateThreeFoos();
var array = new[] { "one", "two" };
var result = _fooRepos.Fetch(f => array.Contains(f.Name)).ToList();
Assert.That(result.Count(), Is.EqualTo(2));
}
}
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<HostComponents>
<Components>
<Component Type="Orchard.Environment.Extensions.Loaders.DynamicExtensionLoader">
<Component Type="Orchard.Environment.Extensions.ExtensionMonitoringCoordinator">
<Properties>
<Property Name="Disabled" Value="true"/>
</Properties>

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.5.1
OrchardVersion: 1.5.1
Version: 1.6
OrchardVersion: 1.6
Description: The common module introduces content parts that are going to be used by most content types (common, body, identity).
FeatureDescription: Core content parts.
Dependencies: Settings

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.5.1
OrchardVersion: 1.5.1
Version: 1.6
OrchardVersion: 1.6
Description: The containers module introduces container and containable behaviors for content items.
FeatureDescription: Container and containable parts to enable parent-child relationships between content items.
Dependencies: Contents, Feeds

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.5.1
OrchardVersion: 1.5.1
Version: 1.6
OrchardVersion: 1.6
Description: The contents module enables the creation of custom content types.
Features:
Contents

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.5.1
OrchardVersion: 1.5.1
Version: 1.6
OrchardVersion: 1.6
Description: The dashboard module is providing the dashboard screen of the admininstration UI of the application.
FeatureDescription: Standard admin dashboard.
Category: Core

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.5.1
OrchardVersion: 1.5.1
Version: 1.6
OrchardVersion: 1.6
Description: The Feeds module is providing RSS feeds to content items.
FeatureDescription: RSS feeds for content items.
Category: Syndication

View File

@ -27,6 +27,12 @@ namespace Orchard.Core.Navigation.Handlers {
var contentMenuItemPart = context.ContentItem.As<ContentMenuItemPart>();
// the display route for the menu item is the one for the referenced content item
if(contentMenuItemPart != null) {
// if the content doesn't exist anymore
if(contentMenuItemPart.Content == null) {
return;
}
context.Metadata.DisplayRouteValues = _contentManager.GetItemMetadata(contentMenuItemPart.Content).DisplayRouteValues;
}
}

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.5.1
OrchardVersion: 1.5.1
Version: 1.6
OrchardVersion: 1.6
Description: The navigation module creates and manages a simple navigation menu for the front-end of the application and allows you to add content items to the admin menu.
FeatureDescription: Menu management.
Category: Core

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.5.1
OrchardVersion: 1.5.1
Version: 1.6
OrchardVersion: 1.6
Description: The dashboard module is providing the reports screen of the application.
FeatureDescription: Reports management.
Category: Core

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.5.1
OrchardVersion: 1.5.1
Version: 1.6
OrchardVersion: 1.6
Description: The scheduling module enables background task scheduling.
FeatureDescription: Scheduled background tasks.
Category: Core

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.5.1
OrchardVersion: 1.5.1
Version: 1.6
OrchardVersion: 1.6
Description: The settings module creates site settings that other modules can contribute to.
FeatureDescription: Site settings.
Category: Core

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.5.1
OrchardVersion: 1.5.1
Version: 1.6
OrchardVersion: 1.6
Description: The shapes module contains core shape templates and display hooks.
FeatureDescription: Core shape templates and display hooks.
Category: Core

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.5.1
OrchardVersion: 1.5.1
Version: 1.6
OrchardVersion: 1.6
Description: The title module enables content items to have titles.
FeatureDescription: Title content part.
Category: Core

View File

@ -2,8 +2,8 @@
AntiForgery: enabled
Author: The Orchard Team
Website: http://orchardproject.net
Version: 1.5.1
OrchardVersion: 1.5.1
Version: 1.6
OrchardVersion: 1.6
Description: The XmlRpc module enables creation of contents from client applications such as LiveWriter.
FeatureDescription: XML-RPC opt-in implementation.
Category: Content Publishing

View File

@ -22,7 +22,7 @@ namespace Orchard.Alias.Controllers {
public AdminController(
IAliasService aliasService,
IOrchardServices orchardServices,
IAliasHolder aliasHolder ) {
IAliasHolder aliasHolder) {
_aliasService = aliasService;
_aliasHolder = aliasHolder;
Services = orchardServices;
@ -65,7 +65,7 @@ namespace Orchard.Alias.Controllers {
aliases = aliases.OrderBy(x => x.Path);
break;
}
if (pager.PageSize != 0) {
aliases = aliases.Skip(pager.GetStartIndex()).Take(pager.PageSize);
}
@ -73,7 +73,7 @@ namespace Orchard.Alias.Controllers {
var model = new AdminIndexViewModel {
Options = options,
Pager = pagerShape,
AliasEntries = aliases.Select(x => new AliasEntry() {Alias = x, IsChecked = false}).ToList()
AliasEntries = aliases.Select(x => new AliasEntry() { Alias = x, IsChecked = false }).ToList()
};
return View(model);
@ -103,7 +103,7 @@ namespace Orchard.Alias.Controllers {
throw new ArgumentOutOfRangeException();
}
return RedirectToAction("Index");
return RedirectToAction("Index");
}
public ActionResult Add() {
@ -118,7 +118,7 @@ namespace Orchard.Alias.Controllers {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage aliases")))
return new HttpUnauthorizedResult();
if(aliasPath == "/") {
if (aliasPath == "/") {
aliasPath = String.Empty;
}
@ -130,7 +130,7 @@ namespace Orchard.Alias.Controllers {
ModelState.AddModelError("Route", T("Route can't be empty").Text);
}
if(!ModelState.IsValid) {
if (!ModelState.IsValid) {
return View();
}
@ -162,11 +162,11 @@ namespace Orchard.Alias.Controllers {
var routeValues = _aliasService.Get(path);
if (routeValues==null)
if (routeValues == null)
return HttpNotFound();
var virtualPaths = _aliasService.LookupVirtualPaths(routeValues,HttpContext)
.Select(vpd=>vpd.VirtualPath);
var virtualPaths = _aliasService.LookupVirtualPaths(routeValues, HttpContext)
.Select(vpd => vpd.VirtualPath);
ViewBag.AliasPath = path;
ViewBag.RoutePath = virtualPaths.FirstOrDefault();
@ -181,19 +181,18 @@ namespace Orchard.Alias.Controllers {
// TODO: (PH:Autoroute) This could overwrite an existing Alias without warning, should handle this
_aliasService.Set(aliasPath, routePath, "Custom");
// Remove previous alias
if (path != aliasPath)
{
if (path != aliasPath) {
// TODO: (PH:Autoroute) Ability to fire an "AliasChanged" event so we make a redirect
_aliasService.Delete(path);
}
Services.Notifier.Information(T("Alias {0} updated", path));
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Delete(string path) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage aliases")))

View File

@ -2,10 +2,8 @@
using System.Collections.Generic;
using System.Web.Routing;
namespace Orchard.Alias
{
public interface IAliasService : IDependency
{
namespace Orchard.Alias {
public interface IAliasService : IDependency {
RouteValueDictionary Get(string aliasPath);
void Set(string aliasPath, RouteValueDictionary routeValues, string aliasSource);
void Set(string aliasPath, string routePath, string aliasSource);
@ -24,7 +22,7 @@ namespace Orchard.Alias
void Replace(string aliasPath, string routePath, string aliasSource);
IEnumerable<Tuple<string, RouteValueDictionary>> List();
IEnumerable<Tuple<string, RouteValueDictionary,string>> List(string sourceStartsWith);
IEnumerable<Tuple<string, RouteValueDictionary, string>> List(string sourceStartsWith);
IEnumerable<VirtualPathData> LookupVirtualPaths(RouteValueDictionary routeValues, System.Web.HttpContextBase HttpContext);
}

View File

@ -8,34 +8,33 @@ using System.Web.Routing;
using Orchard.Alias.Implementation.Holder;
using Orchard.Alias.Implementation.Map;
namespace Orchard.Alias.Implementation
{
public class AliasRoute : RouteBase, IRouteWithArea
{
namespace Orchard.Alias.Implementation {
public class AliasRoute : RouteBase, IRouteWithArea {
private readonly AliasMap _aliasMap;
private readonly IRouteHandler _routeHandler;
public AliasRoute(IAliasHolder aliasHolder, string areaName, IRouteHandler routeHandler)
{
public AliasRoute(IAliasHolder aliasHolder, string areaName, IRouteHandler routeHandler) {
Area = areaName;
_aliasMap = aliasHolder.GetMap(areaName);
_routeHandler = routeHandler;
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
public override RouteData GetRouteData(HttpContextBase httpContext) {
// don't compute unnecessary virtual path if the map is empty
if (!_aliasMap.Any()) {
return null;
}
// Get the full inbound request path
var virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
// Attempt to lookup RouteValues in the alias map
IDictionary<string, string> routeValues;
// TODO: Might as well have the lookup in AliasHolder...
if (_aliasMap.TryGetAlias(virtualPath, out routeValues))
{
if (_aliasMap.TryGetAlias(virtualPath, out routeValues)) {
// Construct RouteData from the route values
var data = new RouteData(this, _routeHandler);
foreach (var routeValue in routeValues)
{
foreach (var routeValue in routeValues) {
var key = routeValue.Key;
if (key.EndsWith("-"))
data.Values.Add(key.Substring(0, key.Length - 1), routeValue.Value);
@ -51,22 +50,19 @@ namespace Orchard.Alias.Implementation
return null;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary routeValues)
{
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary routeValues) {
// Lookup best match for route values in the expanded tree
var match = _aliasMap.Locate(routeValues);
if (match != null)
{
if (match != null) {
// Build any "spare" route values onto the Alias (so we correctly support any additional query parameters)
var sb = new StringBuilder(match.Item2);
var extra = 0;
foreach (var routeValue in routeValues)
{
foreach (var routeValue in routeValues) {
// Ignore any we already have
if (match.Item1.ContainsKey(routeValue.Key))
{
if (match.Item1.ContainsKey(routeValue.Key)) {
continue;
}
// Add a query string fragment
sb.Append((extra++ == 0) ? '?' : '&');
sb.Append(Uri.EscapeDataString(routeValue.Key));

View File

@ -25,7 +25,7 @@ namespace Orchard.Alias.Implementation.Holder {
}
public void SetAlias(AliasInfo alias) {
foreach(var map in _aliasMaps.Values) {
foreach (var map in _aliasMaps.Values) {
map.Remove(alias);
}

View File

@ -53,6 +53,10 @@ namespace Orchard.Alias.Implementation.Map {
CollapseTree(_root, info.Path, info.RouteValues);
}
public bool Any() {
return _aliases.Any();
}
private static void CollapseTree(Node root, string path, IDictionary<string, string> routeValues) {
foreach (var expanded in Expand(routeValues)) {
var focus = root;
@ -96,14 +100,6 @@ namespace Orchard.Alias.Implementation.Map {
return from item1 in source1 from item2 in source2 select produce(item1, item2);
}
private static IEnumerable<T> Single<T>(T t) {
yield return t;
}
private static IEnumerable<T> Empty<T>() {
return Enumerable.Empty<T>();
}
/// <summary>
/// Expand the route values into all possible combinations of keys
/// </summary>
@ -111,7 +107,7 @@ namespace Orchard.Alias.Implementation.Map {
/// <returns></returns>
private static IEnumerable<IEnumerable<KeyValuePair<string, string>>> Expand(IDictionary<string, string> routeValues) {
var ordered = routeValues.OrderBy(kv => kv.Key, StringComparer.InvariantCultureIgnoreCase);
var empty = Empty<KeyValuePair<string, string>>();
var empty = Enumerable.Empty<KeyValuePair<string, string>>();
// For each key/value pair, we want a list containing a single list with either the term, or the term and the "default" value
var termSets = ordered.Select(term => {
@ -119,15 +115,15 @@ namespace Orchard.Alias.Implementation.Map {
var termKey = term.Key.Substring(0, term.Key.Length - 1);
return new[] {
// This entry will auto-match in some cases because it was omitted from the route values
Single(new KeyValuePair<string, string>(termKey, "\u0000")),
Single(new KeyValuePair<string, string>(termKey, term.Value))
new [] { new KeyValuePair<string, string>(termKey, "\u0000") },
new [] { new KeyValuePair<string, string>(termKey, term.Value) }
};
}
return new[] {new[] {term}};
});
// Run each of those lists through an aggregation function, by taking the product of each set, so producting a tree of possibilities
var produced = termSets.Aggregate(Single(empty), (coords, termSet) => Product(coords, termSet, (coord, term) => coord.Concat(term)));
var produced = termSets.Aggregate(new[] { empty }.AsEnumerable(), (coords, termSet) => Product(coords, termSet, (coord, term) => coord.Concat(term)));
return produced;
}

View File

@ -9,38 +9,33 @@ using Orchard.Environment;
using Orchard.Tasks;
using Orchard.Logging;
namespace Orchard.Alias.Implementation.Updater
{
public class AliasHolderUpdater : IOrchardShellEvents, IBackgroundTask
{
namespace Orchard.Alias.Implementation.Updater {
public class AliasHolderUpdater : IOrchardShellEvents, IBackgroundTask {
private readonly IAliasHolder _aliasHolder;
private readonly IAliasStorage _storage;
public ILogger Logger { get; set; }
public AliasHolderUpdater(IAliasHolder aliasHolder, IAliasStorage storage)
{
public AliasHolderUpdater(IAliasHolder aliasHolder, IAliasStorage storage) {
_aliasHolder = aliasHolder;
_storage = storage;
Logger = NullLogger.Instance;
}
void IOrchardShellEvents.Activated()
{
void IOrchardShellEvents.Activated() {
Refresh();
}
void IOrchardShellEvents.Terminating()
{
void IOrchardShellEvents.Terminating() {
}
private void Refresh() {
try {
var aliases = _storage.List();
_aliasHolder.SetAliases(aliases.Select(alias=>new AliasInfo{Path = alias.Item1, Area = alias.Item2, RouteValues=alias.Item3}));
_aliasHolder.SetAliases(aliases.Select(alias => new AliasInfo { Path = alias.Item1, Area = alias.Item2, RouteValues = alias.Item3 }));
}
catch(Exception ex) {
Logger.Error(ex,"Exception during Alias refresh");
catch (Exception ex) {
Logger.Error(ex, "Exception during Alias refresh");
}
}

View File

@ -8,15 +8,12 @@ using Orchard.Mvc.Extensions;
using Orchard.Mvc.Routes;
using Orchard.Mvc.Wrappers;
namespace Orchard.Alias.Implementation
{
public static class Utils
{
namespace Orchard.Alias.Implementation {
public static class Utils {
public static IDictionary<string, string> LookupRouteValues
(HttpContextBase httpContext, IEnumerable<RouteDescriptor>
routeDescriptors,
string routePath)
{
(HttpContextBase httpContext, IEnumerable<RouteDescriptor>
routeDescriptors,
string routePath) {
var queryStringIndex = routePath.IndexOf('?');
var routePathNoQueryString = queryStringIndex == -1 ? routePath : routePath.Substring(0, queryStringIndex);
var queryString = queryStringIndex == -1 ? null : routePath.Substring(queryStringIndex + 1);
@ -51,8 +48,8 @@ namespace Orchard.Alias.Implementation
public static IEnumerable<VirtualPathData> LookupVirtualPaths(
HttpContextBase httpContext,
IEnumerable<RouteDescriptor> routeDescriptors,
string areaName,
IDictionary<string,string> routeValues) {
string areaName,
IDictionary<string, string> routeValues) {
var routeValueDictionary = new RouteValueDictionary(routeValues.ToDictionary(kv => RemoveDash(kv.Key), kv => (object)kv.Value));
var virtualPathDatas = routeDescriptors.Where(r2 => r2.Route.GetAreaName() == areaName)
@ -68,26 +65,21 @@ namespace Orchard.Alias.Implementation
}
private static Dictionary<string, string> ToRouteValues(RouteData routeData, string queryString)
{
private static Dictionary<string, string> ToRouteValues(RouteData routeData, string queryString) {
var routeValues = routeData.Values
.Select(kv =>
{
.Select(kv => {
var value = Convert.ToString(kv.Value, CultureInfo.InvariantCulture);
var defaultValue = FindDefault(routeData.Route, kv.Key);
if (defaultValue != null && string.Equals(defaultValue, value, StringComparison.InvariantCultureIgnoreCase))
{
if (defaultValue != null && string.Equals(defaultValue, value, StringComparison.InvariantCultureIgnoreCase)) {
return new { Key = kv.Key + "-", Value = value };
}
return new { kv.Key, Value = value };
})
.ToDictionary(kv => kv.Key, kv => kv.Value);
if (queryString != null)
{
if (queryString != null) {
foreach (var term in queryString
.Split(new[] { "&" }, StringSplitOptions.RemoveEmptyEntries)
.Select(ParseTerm))
{
.Select(ParseTerm)) {
if (!routeValues.ContainsKey(term[0]))
routeValues[term[0]] = term[1];
}
@ -95,75 +87,61 @@ namespace Orchard.Alias.Implementation
return routeValues;
}
private static string[] ParseTerm(string term)
{
private static string[] ParseTerm(string term) {
var equalsIndex = term.IndexOf('=');
if (equalsIndex == -1)
{
if (equalsIndex == -1) {
return new[] { Uri.UnescapeDataString(term), null };
}
return new[] { Uri.UnescapeDataString(term.Substring(0, equalsIndex)), Uri.UnescapeDataString(term.Substring(equalsIndex + 1)) };
}
private static string FindDefault(RouteBase route, string key)
{
private static string FindDefault(RouteBase route, string key) {
var route2 = route as Route;
if (route2 == null)
{
if (route2 == null) {
return null;
}
object defaultValue;
if (!route2.Defaults.TryGetValue(key, out defaultValue))
{
if (!route2.Defaults.TryGetValue(key, out defaultValue)) {
return null;
}
return Convert.ToString(defaultValue, CultureInfo.InvariantCulture);
}
public class LookupHttpContext : HttpContextBaseWrapper
{
public class LookupHttpContext : HttpContextBaseWrapper {
private readonly string _path;
public LookupHttpContext(HttpContextBase httpContext, string path)
: base(httpContext)
{
: base(httpContext) {
_path = path;
}
public override HttpRequestBase Request
{
public override HttpRequestBase Request {
get { return new LookupHttpRequest(this, base.Request, _path); }
}
private class LookupHttpRequest : HttpRequestBaseWrapper
{
private class LookupHttpRequest : HttpRequestBaseWrapper {
private readonly string _path;
public LookupHttpRequest(HttpContextBase httpContextBase, HttpRequestBase httpRequestBase, string path)
: base( /*httpContextBase,*/ httpRequestBase)
{
: base( /*httpContextBase,*/ httpRequestBase) {
_path = path;
}
public override string AppRelativeCurrentExecutionFilePath
{
public override string AppRelativeCurrentExecutionFilePath {
get { return "~/" + _path; }
}
public override string ApplicationPath
{
public override string ApplicationPath {
get { return "/"; }
}
public override string Path
{
public override string Path {
get { return "/" + _path; }
}
public override string PathInfo
{
public override string PathInfo {
get { return ""; }
}
}

View File

@ -98,7 +98,7 @@ namespace Orchard.Autoroute.Drivers {
if (path.StartsWith(".") || path.EndsWith("."))
updater.AddModelError("CurrentUrl", T("The \".\" can't be used at either end of the permalink."));
else
updater.AddModelError("CurrentUrl", T("Please do not use any of the following characters in your permalink: \":\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\", \", \"<\", \">\", \"\\\". No spaces are allowed (please use dashes or underscores instead)."));
updater.AddModelError("CurrentUrl", T("Please do not use any of the following characters in your permalink: \":\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\", \", \"<\", \">\", \"\\\", \"|\". No spaces are allowed (please use dashes or underscores instead)."));
}
// if CurrentUrl is set, the handler won't try to create an alias for it

View File

@ -166,7 +166,7 @@ namespace Orchard.Autoroute.Services {
}
public bool IsPathValid(string slug) {
return String.IsNullOrWhiteSpace(slug) || Regex.IsMatch(slug, @"^[^:?#\[\]@!$&'()*+,;=\s\""\<\>\\]+$") && !(slug.StartsWith(".") || slug.EndsWith("."));
return String.IsNullOrWhiteSpace(slug) || Regex.IsMatch(slug, @"^[^:?#\[\]@!$&'()*+,;=\s\""\<\>\\\|]+$") && !(slug.StartsWith(".") || slug.EndsWith("."));
}
public bool ProcessPath(AutoroutePart part) {

View File

@ -7,7 +7,7 @@ namespace Orchard.Autoroute.Services {
public class DefaultSlugService : ISlugService {
private readonly ISlugEventHandler _slugEventHandler;
public DefaultSlugService(
ISlugEventHandler slugEventHander
) {
@ -26,7 +26,7 @@ namespace Orchard.Autoroute.Services {
if (!slugContext.Adjusted) {
var disallowed = new Regex(@"[/:?#\[\]@!$&'()*+,;=\s\""\<\>\\]+");
var disallowed = new Regex(@"[/:?#\[\]@!$&'()*+,;=\s\""\<\>\\\|]+");
slugContext.Slug = disallowed.Replace(slugContext.Title, "-").Trim('-','.');

View File

@ -131,8 +131,9 @@ namespace Orchard.CustomForms.Controllers {
foreach (var error in ModelState.Values.SelectMany(m => m.Errors).Select(e => e.ErrorMessage)) {
Services.Notifier.Error(T(error));
}
if (returnUrl != null) {
return Redirect(returnUrl);
return this.RedirectLocal(returnUrl);
}
}
@ -165,7 +166,8 @@ namespace Orchard.CustomForms.Controllers {
}
}
return this.RedirectLocal(returnUrl, () => Redirect(Request.RawUrl));
var referrer = Request.UrlReferrer != null ? Request.UrlReferrer.ToString() : null;
return this.RedirectLocal(returnUrl, () => this.RedirectLocal(referrer, () => Redirect(Request.RawUrl)));
}
bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {

View File

@ -33,8 +33,7 @@ namespace Orchard.CustomForms.Drivers {
return ContentShape("Parts_CustomForm_Wrapper", () => {
return shapeHelper.Parts_CustomForm_Wrapper()
.Editor(_orchardServices.ContentManager.BuildEditor(contentItem))
.ContenItem(part)
.ReturnUrl(part.Redirect ? part.RedirectUrl : _orchardServices.WorkContext.HttpContext.Request.RawUrl);
.ContenItem(part);
});
}

View File

@ -2,7 +2,6 @@
@{
ContentItem customForm = Model.ContentItem;
string returnUrl = Model.ReturnUrl;
// remove default Save/Publish buttons
Model.Editor.Zones["Sidebar"].Items.Clear();
@ -13,7 +12,7 @@
// Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type
@Display(Model.Editor)
@Html.Hidden("returnUrl", returnUrl);
@Html.Hidden("returnUrl", Request.RawUrl);
<fieldset class="submit-button">
<button type="submit" name="submit.Save" value="submit.Save">@T("Submit")</button>

View File

@ -67,7 +67,7 @@ shapeTracingMetadataHost[@Model.ShapeId].shape = {
@if (!String.IsNullOrEmpty((string)Model.PlacementSource) && (WorkContext.HttpContext.Items[(string)Model.PlacementSource] == null)) {
WorkContext.HttpContext.Items[(string)Model.PlacementSource] = new object();
<text>shapeTracingMetadataHost.placement['@Model.PlacementSource.ToString()'] = '@ShapeTracingFactory.FormatJsonValue((string)Model.PlacementContent)'; </text>
<text>shapeTracingMetadataHost.placement['@Model.PlacementSource.ToString()'] = '@HttpUtility.JavaScriptStringEncode((string)Model.PlacementContent)'; </text>
}
</script>

View File

@ -21,14 +21,13 @@
@Html.HiddenFor(m => m.Class)
@Html.HiddenFor(m => m.Style)
@Html.HiddenFor(m => m.Alignment)
@Html.HiddenFor(m => m.Alignment)
@Html.HiddenFor(m => m.Width)
@Html.HiddenFor(m => m.Height)
</fieldset>
@using (Script.Foot())
{
@using (Script.Foot()) {
<script type="text/javascript">
//<![CDATA[
@ -37,8 +36,22 @@
});
jQuery('#btn-@Html.FieldIdFor(m => m.Url)').click(function () {
var currentImageUrl = $('#@Html.FieldIdFor(m => m.Url)').val();
if (currentImageUrl && currentImageUrl.length > 2 && currentImageUrl.substr(0, 2) == "~/") {
currentImageUrl = '@Url.Content("~/")' + currentImageUrl.substr(2);
}
jQuery('#btn-@Html.FieldIdFor(m => m.Url)').trigger("orchard-admin-pickimage-open", {
img: null,
img: {
src: currentImageUrl,
"class": $('#@Html.FieldIdFor(m => m.Class)').val(),
style: $('#@Html.FieldIdFor(m => m.Style)').val(),
alt: $('#@Html.FieldIdFor(m => m.AlternateText)').val(),
width: $('#@Html.FieldIdFor(m => m.Width)').val(),
height: $('#@Html.FieldIdFor(m => m.Height)').val(),
align: $('#@Html.FieldIdFor(m => m.Alignment)').val()
},
uploadMediaPath: 'images',
callback: function (data) {
var applicationPath = '@Url.RequestContext.HttpContext.Request.ApplicationPath.ToLower()';

View File

@ -36,7 +36,7 @@
@foreach (var module in Model.Entries) {
<li>
@{
string iconUrl = @module.NewVersionToInstall.IconUrl;
string iconUrl = module.NewVersionToInstall.IconUrl;
if (string.IsNullOrWhiteSpace(iconUrl)) {
iconUrl = Href("../../Content/Images/ModuleDefaultIcon.png");
}

View File

@ -37,9 +37,9 @@
<li>
@{
string extensionClass = "iconThumbnail";
string iconUrl = @theme.NewVersionToInstall.IconUrl;
string iconUrl = theme.NewVersionToInstall.IconUrl;
if (!string.IsNullOrWhiteSpace(@theme.NewVersionToInstall.FirstScreenshot)) {
iconUrl = @theme.NewVersionToInstall.FirstScreenshot;
iconUrl = theme.NewVersionToInstall.FirstScreenshot;
extensionClass = "screenshotThumbnail";
} else if (string.IsNullOrWhiteSpace(iconUrl)) {
iconUrl = Href("../../Content/Images/imagePlaceholder.png");

View File

@ -59,10 +59,6 @@ namespace Orchard.Environment.Extensions.Loaders {
return GetDependencies(dependency.VirtualPath);
}
public IEnumerable<string> GetFileHashDependencies(DependencyDescriptor dependency) {
return GetDependencies(dependency.VirtualPath);
}
public override void Monitor(ExtensionDescriptor descriptor, Action<IVolatileToken> monitor) {
if (Disabled)
return;

View File

@ -173,7 +173,7 @@ namespace Orchard.Environment.Extensions.Loaders {
// A pre-compiled module is _not_ compatible with a dynamically loaded module
// because a pre-compiled module usually references a pre-compiled assembly binary
// which will have a different identity (i.e. name) from the dynamic module.
bool result = references.All(r => r.Loader.GetType() != typeof(DynamicExtensionLoader) && r.Loader.GetType() != typeof(ProbingExtensionLoader));
bool result = references.All(r => r.Loader.GetType() != typeof(DynamicExtensionLoader));
if (!result) {
Logger.Information("Extension \"{0}\" will not be loaded as pre-compiled extension because one or more referenced extension is dynamically compiled", extension.Id);
}

View File

@ -1,248 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Orchard.Caching;
using Orchard.Environment.Extensions.Compilers;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.Dependencies;
using Orchard.FileSystems.VirtualPath;
using Orchard.Logging;
using Orchard.Utility.Extensions;
namespace Orchard.Environment.Extensions.Loaders {
/// <summary>
/// In case <see cref="DynamicExtensionLoader"/> is disabled, this loader will dynamically compile the assembly
/// and save a copy to the probing folder so that next restart doesn't need to compile it again.
/// </summary>
public class ProbingExtensionLoader : ExtensionLoaderBase {
public static readonly string[] ExtensionsVirtualPathPrefixes = { "~/Modules/", "~/Themes/" };
private readonly IBuildManager _buildManager;
private readonly IVirtualPathProvider _virtualPathProvider;
private readonly IHostEnvironment _hostEnvironment;
private readonly IAssemblyProbingFolder _assemblyProbingFolder;
private readonly IDependenciesFolder _dependenciesFolder;
private readonly IProjectFileParser _projectFileParser;
public ProbingExtensionLoader(
IBuildManager buildManager,
IVirtualPathProvider virtualPathProvider,
IVirtualPathMonitor virtualPathMonitor,
IHostEnvironment hostEnvironment,
IAssemblyProbingFolder assemblyProbingFolder,
IDependenciesFolder dependenciesFolder,
IProjectFileParser projectFileParser)
: base(dependenciesFolder) {
_buildManager = buildManager;
_virtualPathProvider = virtualPathProvider;
_hostEnvironment = hostEnvironment;
_assemblyProbingFolder = assemblyProbingFolder;
_projectFileParser = projectFileParser;
_dependenciesFolder = dependenciesFolder;
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public bool Disabled { get; set; }
public override int Order { get { return 110; } }
public override IEnumerable<ExtensionCompilationReference> GetCompilationReferences(DependencyDescriptor dependency) {
yield return new ExtensionCompilationReference { BuildProviderTarget = dependency.VirtualPath };
}
public override void ExtensionRemoved(ExtensionLoadingContext ctx, DependencyDescriptor dependency) {
}
public override void ExtensionDeactivated(ExtensionLoadingContext ctx, ExtensionDescriptor extension) {
}
public override void ExtensionActivated(ExtensionLoadingContext ctx, ExtensionDescriptor extension) {
}
public override IEnumerable<ExtensionReferenceProbeEntry> ProbeReferences(ExtensionDescriptor descriptor) {
if (Disabled)
return Enumerable.Empty<ExtensionReferenceProbeEntry>();
Logger.Information("Probing references for module '{0}'", descriptor.Id);
string projectPath = GetProjectPath(descriptor);
if (projectPath == null)
return Enumerable.Empty<ExtensionReferenceProbeEntry>();
var projectFile = _projectFileParser.Parse(projectPath);
var result = projectFile.References.Select(r => new ExtensionReferenceProbeEntry {
Descriptor = descriptor,
Loader = this,
Name = r.SimpleName,
VirtualPath = _virtualPathProvider.GetProjectReferenceVirtualPath(projectPath, r.SimpleName, r.Path)
});
Logger.Information("Done probing references for module '{0}'", descriptor.Id);
return result;
}
public override void ReferenceActivated(ExtensionLoadingContext context, ExtensionReferenceProbeEntry referenceEntry) {
//Note: This is the same implementation as "PrecompiledExtensionLoader"
if (string.IsNullOrEmpty(referenceEntry.VirtualPath))
return;
string sourceFileName = _virtualPathProvider.MapPath(referenceEntry.VirtualPath);
// Copy the assembly if it doesn't exist or if it is older than the source file.
bool copyAssembly =
!_assemblyProbingFolder.AssemblyExists(referenceEntry.Name) ||
File.GetLastWriteTimeUtc(sourceFileName) > _assemblyProbingFolder.GetAssemblyDateTimeUtc(referenceEntry.Name);
if (copyAssembly) {
context.CopyActions.Add(() => _assemblyProbingFolder.StoreAssembly(referenceEntry.Name, sourceFileName));
// We need to restart the appDomain if the assembly is loaded
if (_hostEnvironment.IsAssemblyLoaded(referenceEntry.Name)) {
Logger.Information("ReferenceActivated: Reference \"{0}\" is activated with newer file and its assembly is loaded, forcing AppDomain restart", referenceEntry.Name);
context.RestartAppDomain = true;
}
}
}
public override Assembly LoadReference(DependencyReferenceDescriptor reference) {
if (Disabled)
return null;
Logger.Information("Loading reference '{0}'", reference.Name);
// DynamicExtensionLoader has 2 types of references: assemblies from module bin directory
// and .csproj.
Assembly result;
if (StringComparer.OrdinalIgnoreCase.Equals(Path.GetExtension(reference.VirtualPath), ".dll"))
result = _assemblyProbingFolder.LoadAssembly(reference.Name);
else {
result = ProbeAssembly(reference.Name, reference.VirtualPath);
}
Logger.Information("Done loading reference '{0}'", reference.Name);
return result;
}
public override ExtensionProbeEntry Probe(ExtensionDescriptor descriptor) {
if (Disabled)
return null;
Logger.Information("Probing for module '{0}'", descriptor.Id);
string projectPath = GetProjectPath(descriptor);
if (projectPath == null)
return null;
var result = new ExtensionProbeEntry {
Descriptor = descriptor,
Loader = this,
Priority = 50,
VirtualPath = projectPath,
VirtualPathDependencies = new string[] { projectPath },
};
Logger.Information("Done probing for module '{0}'", descriptor.Id);
return result;
}
protected override ExtensionEntry LoadWorker(ExtensionDescriptor descriptor) {
if (Disabled)
return null;
Logger.Information("Start loading dynamic extension \"{0}\"", descriptor.Name);
var assembly = _assemblyProbingFolder.LoadAssembly(descriptor.Id);
if (assembly == null) {
string projectPath = GetProjectPath(descriptor);
if (projectPath == null)
return null;
assembly = ProbeAssembly(descriptor.Id, projectPath);
}
if (assembly == null)
return null;
Logger.Information("Done loading dynamic extension \"{0}\": assembly name=\"{1}\"", descriptor.Name, assembly.FullName);
return new ExtensionEntry {
Descriptor = descriptor,
Assembly = assembly,
ExportedTypes = assembly.GetExportedTypes(),
};
}
private void AddDependencies(string projectPath, HashSet<string> currentSet) {
// Skip files from locations other than "~/Modules" and "~/Themes"
if (string.IsNullOrEmpty(PrefixMatch(projectPath, ExtensionsVirtualPathPrefixes))) {
return;
}
// Add project path
currentSet.Add(projectPath);
// Add source file paths
var projectFile = _projectFileParser.Parse(projectPath);
string basePath = _virtualPathProvider.GetDirectoryName(projectPath);
currentSet.UnionWith(projectFile.SourceFilenames.Select(f => _virtualPathProvider.Combine(basePath, f)));
// Add Project and Library references
if (projectFile.References != null) {
foreach (ReferenceDescriptor referenceDescriptor in projectFile.References.Where(reference => !string.IsNullOrEmpty(reference.Path))) {
string path = referenceDescriptor.ReferenceType == ReferenceType.Library
? _virtualPathProvider.GetProjectReferenceVirtualPath(projectPath, referenceDescriptor.SimpleName, referenceDescriptor.Path)
: _virtualPathProvider.Combine(basePath, referenceDescriptor.Path);
// Normalize the virtual path (avoid ".." in the path name)
if (!string.IsNullOrEmpty(path)) {
path = _virtualPathProvider.ToAppRelative(path);
}
// Attempt to reference the project / library file
if (!string.IsNullOrEmpty(path) && !currentSet.Contains(path) && _virtualPathProvider.TryFileExists(path)) {
switch (referenceDescriptor.ReferenceType) {
case ReferenceType.Project:
AddDependencies(path, currentSet);
break;
case ReferenceType.Library:
currentSet.Add(path);
break;
}
}
}
}
}
private Assembly ProbeAssembly(string moduleName, string virtualPath) {
var assembly = _buildManager.GetCompiledAssembly(virtualPath);
if (assembly != null) {
_assemblyProbingFolder.StoreAssembly(moduleName, assembly.Location);
return assembly;
}
return null;
}
private static string PrefixMatch(string virtualPath, params string[] prefixes) {
return prefixes
.FirstOrDefault(p => virtualPath.StartsWith(p, StringComparison.OrdinalIgnoreCase));
}
private string GetProjectPath(ExtensionDescriptor descriptor) {
string projectPath = _virtualPathProvider.Combine(descriptor.Location, descriptor.Id,
descriptor.Id + ".csproj");
if (!_virtualPathProvider.FileExists(projectPath)) {
return null;
}
return projectPath;
}
}
}

View File

@ -103,7 +103,6 @@ namespace Orchard.Environment {
builder.RegisterType<ReferencedExtensionLoader>().As<IExtensionLoader>().SingleInstance();
builder.RegisterType<PrecompiledExtensionLoader>().As<IExtensionLoader>().SingleInstance();
builder.RegisterType<DynamicExtensionLoader>().As<IExtensionLoader>().SingleInstance();
builder.RegisterType<ProbingExtensionLoader>().As<IExtensionLoader>().SingleInstance();
builder.RegisterType<RawThemeExtensionLoader>().As<IExtensionLoader>().SingleInstance();
}
}

View File

@ -111,7 +111,6 @@ namespace Orchard.FileSystems.Dependencies {
// implementations.
return
loaderName == "DynamicExtensionLoader" ||
loaderName == "ProbingExtensionLoader" ||
loaderName == "PrecompiledExtensionLoader";
}

View File

@ -202,7 +202,6 @@
<Compile Include="Environment\Extensions\Folders\CoreModuleFolders.cs" />
<Compile Include="Environment\Extensions\Folders\IExtensionHarvester.cs" />
<Compile Include="Environment\Extensions\IExtensionMonitoringCoordinator.cs" />
<Compile Include="Environment\Extensions\Loaders\ProbingExtensionLoader.cs" />
<Compile Include="Environment\Extensions\OrchardSuppressDependencyAttribute.cs" />
<Compile Include="Environment\Features\IFeatureManager.cs" />
<Compile Include="Environment\IAssemblyNameResolver.cs" />

View File

@ -72,6 +72,10 @@ namespace Orchard.Utility.Extensions {
return false;
}
if (url.StartsWith("~/")) {
return true;
}
if (url.StartsWith("//") || url.StartsWith("/\\")) {
return false;
}