Cleaning Alias code

--HG--
branch : 1.x
This commit is contained in:
Sebastien Ros
2012-10-24 15:51:35 -07:00
parent d01ff9df75
commit 20a4a8f019
7 changed files with 75 additions and 113 deletions

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 ""; }
}
}