mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-04-05 21:01:35 +08:00
Merge with 1.x
This commit is contained in:
commit
395029fdbd
@ -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)" />
|
||||
|
@ -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
|
||||
)
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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")))
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 ""; }
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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('-','.');
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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()';
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,6 @@ namespace Orchard.FileSystems.Dependencies {
|
||||
// implementations.
|
||||
return
|
||||
loaderName == "DynamicExtensionLoader" ||
|
||||
loaderName == "ProbingExtensionLoader" ||
|
||||
loaderName == "PrecompiledExtensionLoader";
|
||||
}
|
||||
|
||||
|
@ -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" />
|
||||
|
@ -72,6 +72,10 @@ namespace Orchard.Utility.Extensions {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (url.StartsWith("~/")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (url.StartsWith("//") || url.StartsWith("/\\")) {
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user