#3539 - Re-enabled url redirect tracking and implemented support for culture variants
This commit is contained in:
@@ -119,6 +119,7 @@ namespace Umbraco.Core.Migrations.Upgrade
|
||||
To<DropTemplateDesignColumn>("{08919C4B-B431-449C-90EC-2B8445B5C6B1}");
|
||||
To<TablesForScheduledPublishing>("{7EB0254C-CB8B-4C75-B15B-D48C55B449EB}");
|
||||
To<MakeTagsVariant>("{C39BF2A7-1454-4047-BBFE-89E40F66ED63}");
|
||||
To<MakeRedirectUrlVariant>("{64EBCE53-E1F0-463A-B40B-E98EFCCA8AE2}");
|
||||
|
||||
//FINAL
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
{
|
||||
public class MakeRedirectUrlVariant : MigrationBase
|
||||
{
|
||||
public MakeRedirectUrlVariant(IMigrationContext context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
AddColumn<RedirectUrlDto>("culture");
|
||||
|
||||
Delete.Index("IX_umbracoRedirectUrl").OnTable(Constants.DatabaseSchema.Tables.RedirectUrl).Do();
|
||||
Create.Index("IX_umbracoRedirectUrl").OnTable(Constants.DatabaseSchema.Tables.RedirectUrl)
|
||||
.OnColumn("urlHash")
|
||||
.Ascending()
|
||||
.OnColumn("contentKey")
|
||||
.Ascending()
|
||||
.OnColumn("culture")
|
||||
.Ascending()
|
||||
.OnColumn("createDateUtc")
|
||||
.Ascending()
|
||||
.WithOptions().Unique()
|
||||
.Do();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,11 +27,18 @@ namespace Umbraco.Core.Models
|
||||
[DataMember]
|
||||
DateTime CreateDateUtc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the culture.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
string Culture { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the redirect url route.
|
||||
/// </summary>
|
||||
/// <remarks>Is a proper Umbraco route eg /path/to/foo or 123/path/tofoo.</remarks>
|
||||
[DataMember]
|
||||
string Url { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,12 +28,14 @@ namespace Umbraco.Core.Models
|
||||
public readonly PropertyInfo ContentIdSelector = ExpressionHelper.GetPropertyInfo<RedirectUrl, int>(x => x.ContentId);
|
||||
public readonly PropertyInfo ContentKeySelector = ExpressionHelper.GetPropertyInfo<RedirectUrl, Guid>(x => x.ContentKey);
|
||||
public readonly PropertyInfo CreateDateUtcSelector = ExpressionHelper.GetPropertyInfo<RedirectUrl, DateTime>(x => x.CreateDateUtc);
|
||||
public readonly PropertyInfo CultureSelector = ExpressionHelper.GetPropertyInfo<RedirectUrl, string>(x => x.Culture);
|
||||
public readonly PropertyInfo UrlSelector = ExpressionHelper.GetPropertyInfo<RedirectUrl, string>(x => x.Url);
|
||||
}
|
||||
|
||||
private int _contentId;
|
||||
private Guid _contentKey;
|
||||
private DateTime _createDateUtc;
|
||||
private string _culture;
|
||||
private string _url;
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -57,6 +59,13 @@ namespace Umbraco.Core.Models
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _createDateUtc, Ps.Value.CreateDateUtcSelector); }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Culture
|
||||
{
|
||||
get { return _culture; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _culture, Ps.Value.CultureSelector); }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Url
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
|
||||
// notes
|
||||
//
|
||||
// we want a unique, non-clustered index on (url ASC, contentId ASC, createDate DESC) but the
|
||||
// we want a unique, non-clustered index on (url ASC, contentId ASC, culture ASC, createDate DESC) but the
|
||||
// problem is that the index key must be 900 bytes max. should we run without an index? done
|
||||
// some perfs comparisons, and running with an index on a hash is only slightly slower on
|
||||
// inserts, and much faster on reads, so... we have an index on a hash.
|
||||
@@ -41,9 +41,13 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
public string Url { get; set; }
|
||||
|
||||
[Column("culture")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public string Culture { get; set; }
|
||||
|
||||
[Column("urlHash")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRedirectUrl", ForColumns = "urlHash, contentKey, createDateUtc")]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRedirectUrl", ForColumns = "urlHash, contentKey, culture, createDateUtc")]
|
||||
[Length(40)]
|
||||
public string UrlHash { get; set; }
|
||||
}
|
||||
|
||||
@@ -14,8 +14,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </summary>
|
||||
/// <param name="url">The Umbraco redirect url route.</param>
|
||||
/// <param name="contentKey">The content unique key.</param>
|
||||
/// <param name="culture">The culture.</param>
|
||||
/// <returns></returns>
|
||||
IRedirectUrl Get(string url, Guid contentKey);
|
||||
IRedirectUrl Get(string url, Guid contentKey, string culture);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a redirect url.
|
||||
|
||||
@@ -104,6 +104,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
ContentKey = redirectUrl.ContentKey,
|
||||
CreateDateUtc = redirectUrl.CreateDateUtc,
|
||||
Url = redirectUrl.Url,
|
||||
Culture = redirectUrl.Culture,
|
||||
UrlHash = redirectUrl.Url.ToSHA1()
|
||||
};
|
||||
}
|
||||
@@ -121,6 +122,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
url.ContentId = dto.ContentId;
|
||||
url.ContentKey = dto.ContentKey;
|
||||
url.CreateDateUtc = dto.CreateDateUtc;
|
||||
url.Culture = dto.Culture;
|
||||
url.Url = dto.Url;
|
||||
return url;
|
||||
}
|
||||
@@ -130,10 +132,10 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
}
|
||||
}
|
||||
|
||||
public IRedirectUrl Get(string url, Guid contentKey)
|
||||
public IRedirectUrl Get(string url, Guid contentKey, string culture)
|
||||
{
|
||||
var urlHash = url.ToSHA1();
|
||||
var sql = GetBaseQuery(false).Where<RedirectUrlDto>(x => x.Url == url && x.UrlHash == urlHash && x.ContentKey == contentKey);
|
||||
var sql = GetBaseQuery(false).Where<RedirectUrlDto>(x => x.Url == url && x.UrlHash == urlHash && x.ContentKey == contentKey && x.Culture == culture);
|
||||
var dto = Database.Fetch<RedirectUrlDto>(sql).FirstOrDefault();
|
||||
return dto == null ? null : Map(dto);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,9 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
/// <param name="url">The Umbraco url route.</param>
|
||||
/// <param name="contentKey">The content unique key.</param>
|
||||
/// <param name="culture">The culture.</param>
|
||||
/// <remarks>Is a proper Umbraco route eg /path/to/foo or 123/path/tofoo.</remarks>
|
||||
void Register(string url, Guid contentKey);
|
||||
void Register(string url, Guid contentKey, string culture = null);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all redirect urls for a given content.
|
||||
|
||||
@@ -19,15 +19,15 @@ namespace Umbraco.Core.Services.Implement
|
||||
_redirectUrlRepository = redirectUrlRepository;
|
||||
}
|
||||
|
||||
public void Register(string url, Guid contentKey)
|
||||
public void Register(string url, Guid contentKey, string culture = null)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var redir = _redirectUrlRepository.Get(url, contentKey);
|
||||
var redir = _redirectUrlRepository.Get(url, contentKey, culture);
|
||||
if (redir != null)
|
||||
redir.CreateDateUtc = DateTime.UtcNow;
|
||||
else
|
||||
redir = new RedirectUrl { Key = Guid.NewGuid(), Url = url, ContentKey = contentKey };
|
||||
redir = new RedirectUrl { Key = Guid.NewGuid(), Url = url, ContentKey = contentKey, Culture = culture};
|
||||
_redirectUrlRepository.Save(redir);
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
@@ -367,6 +367,7 @@
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DropTemplateDesignColumn.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\FixLockTablePrimaryKey.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\LanguageColumns.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\MakeRedirectUrlVariant.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\MakeTagsVariant.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\PropertyEditorsMigration.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\RefactorMacroColumns.cs" />
|
||||
|
||||
@@ -54,9 +54,10 @@
|
||||
|
||||
<div class="umb-table-head">
|
||||
<div class="umb-table-row">
|
||||
<div class="umb-table-cell not-fixed flx-s1 flx-g1 flx-b4"><localize key="redirectUrls_originalUrl">Original URL</localize></div>
|
||||
<div class="umb-table-cell not-fixed flx-s1 flx-g1 flx-b1"><localize key="redirectUrls_culture">Culture</localize></div>
|
||||
<div class="umb-table-cell flx-s1 flx-g1 flx-b4"><localize key="redirectUrls_originalUrl">Original URL</localize></div>
|
||||
<div class="umb-table-cell flx-s0 flx-g0" style="flex-basis: 20px;"></div>
|
||||
<div class="umb-table-cell flx-s1 flx-g1 flx-b6"><localize key="redirectUrls_redirectedTo">Redirected To</localize></div>
|
||||
<div class="umb-table-cell flx-s1 flx-g1 flx-b5"><localize key="redirectUrls_redirectedTo">Redirected To</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -64,8 +65,10 @@
|
||||
|
||||
<div class="umb-table-row -solid" ng-repeat="redirectUrl in vm.redirectUrls">
|
||||
|
||||
|
||||
<div class="umb-table-cell not-fixed flx-s1 flx-g1 flx-b4">
|
||||
<div class="umb-table-cell not-fixed flx-s1 flx-g1 flx-b1">
|
||||
{{redirectUrl.culture ||'*'}}
|
||||
</div>
|
||||
<div class="umb-table-cell flx-s1 flx-g1 flx-b4">
|
||||
<a class="umb-table-body__link" href="{{redirectUrl.originalUrl}}" target="_blank" title="{{redirectUrl.originalUrl}}">{{redirectUrl.originalUrl}}</a>
|
||||
</div>
|
||||
|
||||
@@ -73,7 +76,7 @@
|
||||
<i class="umb-table-body__icon umb-table-body__fileicon icon-arrow-right" style="font-size: 12px; line-height: 1;"></i>
|
||||
</div>
|
||||
|
||||
<div class="umb-table-cell flx-s1 flx-g1 flx-b6 items-center">
|
||||
<div class="umb-table-cell flx-s1 flx-g1 flx-b5 items-center">
|
||||
<div class="flx-s1 flx-g1 flx-b0" style="margin-right: 20px;">
|
||||
<a class="umb-table-body__link" href="{{redirectUrl.destinationUrl}}" target="_blank" title="{{redirectUrl.destinationUrl}}">{{redirectUrl.destinationUrl}}</a>
|
||||
</div>
|
||||
|
||||
@@ -1995,6 +1995,7 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<area alias="redirectUrls">
|
||||
<key alias="disableUrlTracker">Disable URL tracker</key>
|
||||
<key alias="enableUrlTracker">Enable URL tracker</key>
|
||||
<key alias="culture">Culture</key>
|
||||
<key alias="originalUrl">Original URL</key>
|
||||
<key alias="redirectedTo">Redirected To</key>
|
||||
<key alias="redirectUrlManagement">Redirect Url Management</key>
|
||||
|
||||
@@ -51,12 +51,6 @@ namespace Umbraco.Web.Editors
|
||||
: redirectUrlService.SearchRedirectUrls(searchTerm, page, pageSize, out resultCount);
|
||||
|
||||
searchResult.SearchResults = Mapper.Map<IEnumerable<ContentRedirectUrl>>(redirects).ToArray();
|
||||
//now map the Content/published url
|
||||
foreach (var result in searchResult.SearchResults)
|
||||
{
|
||||
result.DestinationUrl = result.ContentId > 0 ? Umbraco.Url(result.ContentId) : "#";
|
||||
}
|
||||
|
||||
searchResult.TotalCount = resultCount;
|
||||
searchResult.CurrentPage = page;
|
||||
searchResult.PageCount = ((int)resultCount + pageSize - 1) / pageSize;
|
||||
|
||||
@@ -20,5 +20,8 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
|
||||
[DataMember(Name = "contentId")]
|
||||
public int ContentId { get; set; }
|
||||
|
||||
[DataMember(Name = "culture")]
|
||||
public string Culture { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,18 +8,12 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class RedirectUrlMapperProfile : Profile
|
||||
{
|
||||
private readonly UrlProvider _urlProvider;
|
||||
|
||||
public RedirectUrlMapperProfile(UrlProvider urlProvider)
|
||||
{
|
||||
_urlProvider = urlProvider;
|
||||
}
|
||||
|
||||
public RedirectUrlMapperProfile()
|
||||
{
|
||||
CreateMap<IRedirectUrl, ContentRedirectUrl>()
|
||||
.ForMember(x => x.OriginalUrl, expression => expression.MapFrom(item => _urlProvider.GetUrlFromRoute(item.ContentId, item.Url, null)))
|
||||
.ForMember(x => x.DestinationUrl, expression => expression.Ignore())
|
||||
.ForMember(x => x.OriginalUrl, expression => expression.MapFrom(item => Current.UmbracoContext.UrlProvider.GetUrlFromRoute(item.ContentId, item.Url, item.Culture)))
|
||||
.ForMember(x => x.DestinationUrl, expression => expression.MapFrom(item => item.ContentId > 0 ? new UmbracoHelper(Current.UmbracoContext, Current.Services).Url(item.ContentId, item.Culture) : "#"))
|
||||
.ForMember(x => x.RedirectId, expression => expression.MapFrom(item => item.Key));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,85 @@
|
||||
using System;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Events;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Web.Cache;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.Redirects
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements an Application Event Handler for managing redirect urls tracking.
|
||||
/// Implements an Application Event Handler for managing redirect urls tracking.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>when content is renamed or moved, we want to create a permanent 301 redirect from it's old url</para>
|
||||
/// <para>not managing domains because we don't know how to do it - changing domains => must create a higher level strategy using rewriting rules probably</para>
|
||||
/// <para>recycle bin = moving to and from does nothing: to = the node is gone, where would we redirect? from = same</para>
|
||||
/// <para>when content is renamed or moved, we want to create a permanent 301 redirect from it's old url</para>
|
||||
/// <para>
|
||||
/// not managing domains because we don't know how to do it - changing domains => must create a higher level
|
||||
/// strategy using rewriting rules probably
|
||||
/// </para>
|
||||
/// <para>recycle bin = moving to and from does nothing: to = the node is gone, where would we redirect? from = same</para>
|
||||
/// </remarks>
|
||||
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
|
||||
[DisableComponent] // fixme - re-enable when we fix redirect tracking with variants
|
||||
public class RedirectTrackingComponent : UmbracoComponentBase, IUmbracoCoreComponent
|
||||
{
|
||||
private const string ContextKey1 = "Umbraco.Web.Redirects.RedirectTrackingEventHandler.1";
|
||||
private const string ContextKey2 = "Umbraco.Web.Redirects.RedirectTrackingEventHandler.2";
|
||||
private const string ContextKey3 = "Umbraco.Web.Redirects.RedirectTrackingEventHandler.3";
|
||||
|
||||
protected void Initialize()
|
||||
private static Dictionary<ContentIdAndCulture, ContentKeyAndOldRoute> OldRoutes
|
||||
{
|
||||
get
|
||||
{
|
||||
var oldRoutes =
|
||||
(Dictionary<ContentIdAndCulture, ContentKeyAndOldRoute>) UmbracoContext.Current.HttpContext.Items[
|
||||
ContextKey3];
|
||||
if (oldRoutes == null)
|
||||
UmbracoContext.Current.HttpContext.Items[ContextKey3] =
|
||||
oldRoutes = new Dictionary<ContentIdAndCulture, ContentKeyAndOldRoute>();
|
||||
return oldRoutes;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool LockedEvents
|
||||
{
|
||||
get => Moving && UmbracoContext.Current.HttpContext.Items[ContextKey2] != null;
|
||||
set
|
||||
{
|
||||
if (Moving && value)
|
||||
UmbracoContext.Current.HttpContext.Items[ContextKey2] = true;
|
||||
else
|
||||
UmbracoContext.Current.HttpContext.Items.Remove(ContextKey2);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool Moving
|
||||
{
|
||||
get => UmbracoContext.Current.HttpContext.Items[ContextKey1] != null;
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
UmbracoContext.Current.HttpContext.Items[ContextKey1] = true;
|
||||
else
|
||||
{
|
||||
UmbracoContext.Current.HttpContext.Items.Remove(ContextKey1);
|
||||
UmbracoContext.Current.HttpContext.Items.Remove(ContextKey2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void Initialize(ContentFinderCollectionBuilder contentFinderCollectionBuilder)
|
||||
{
|
||||
// don't let the event handlers kick in if Redirect Tracking is turned off in the config
|
||||
if (UmbracoConfig.For.UmbracoSettings().WebRouting.DisableRedirectUrlTracking) return;
|
||||
|
||||
// events are weird
|
||||
// on 'published' we 'could' get the old or the new route depending on event handlers order
|
||||
// so it is not reliable. getting the old route in 'publishing' to be sure and storing in http
|
||||
@@ -50,6 +99,7 @@ namespace Umbraco.Web.Redirects
|
||||
ContentService.Moved += ContentService_Moved;
|
||||
ContentCacheRefresher.CacheUpdated += ContentCacheRefresher_CacheUpdated;
|
||||
|
||||
|
||||
// kill all redirects once a content is deleted
|
||||
//ContentService.Deleted += ContentService_Deleted;
|
||||
// BUT, doing it here would prevent content deletion due to FK
|
||||
@@ -58,69 +108,38 @@ namespace Umbraco.Web.Redirects
|
||||
// rolled back items have to be published, so publishing will take care of that
|
||||
}
|
||||
|
||||
private static void ContentCacheRefresher_CacheUpdated(ContentCacheRefresher sender, CacheRefresherEventArgs args)
|
||||
private static void ContentCacheRefresher_CacheUpdated(ContentCacheRefresher sender,
|
||||
CacheRefresherEventArgs args)
|
||||
{
|
||||
// sanity checks
|
||||
|
||||
if (args.MessageType != MessageType.RefreshByPayload)
|
||||
{
|
||||
throw new InvalidOperationException("ContentCacheRefresher MessageType should be ByPayload.");
|
||||
|
||||
if (args.MessageObject == null) return;
|
||||
var payloads = args.MessageObject as ContentCacheRefresher.JsonPayload[];
|
||||
if (payloads == null)
|
||||
}
|
||||
if (args.MessageObject == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (args.MessageObject is ContentCacheRefresher.JsonPayload[])
|
||||
{
|
||||
throw new InvalidOperationException("ContentCacheRefresher MessageObject should be JsonPayload[].");
|
||||
}
|
||||
|
||||
// manage routes
|
||||
|
||||
var removeKeys = new List<int>();
|
||||
var removeKeys = new List<ContentIdAndCulture>();
|
||||
|
||||
foreach (var oldRoute in OldRoutes)
|
||||
{
|
||||
// assuming we cannot have 'CacheUpdated' for only part of the infos else we'd need
|
||||
// to set a flag in 'Published' to indicate which entities have been refreshed ok
|
||||
CreateRedirect(oldRoute.Key, oldRoute.Value.Item1, oldRoute.Value.Item2);
|
||||
CreateRedirect(oldRoute.Key.ContentId, oldRoute.Key.Culture, oldRoute.Value.ContentKey,
|
||||
oldRoute.Value.OldRoute);
|
||||
removeKeys.Add(oldRoute.Key);
|
||||
}
|
||||
|
||||
foreach (var k in removeKeys)
|
||||
{
|
||||
OldRoutes.Remove(k);
|
||||
}
|
||||
|
||||
private static Dictionary<int, Tuple<Guid, string>> OldRoutes
|
||||
{
|
||||
get
|
||||
{
|
||||
var oldRoutes = (Dictionary<int, Tuple<Guid, string>>) UmbracoContext.Current.HttpContext.Items[ContextKey3];
|
||||
if (oldRoutes == null)
|
||||
UmbracoContext.Current.HttpContext.Items[ContextKey3] = oldRoutes = new Dictionary<int, Tuple<Guid, string>>();
|
||||
return oldRoutes;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool LockedEvents
|
||||
{
|
||||
get { return Moving && UmbracoContext.Current.HttpContext.Items[ContextKey2] != null; }
|
||||
set
|
||||
{
|
||||
if (Moving && value)
|
||||
UmbracoContext.Current.HttpContext.Items[ContextKey2] = true;
|
||||
else
|
||||
UmbracoContext.Current.HttpContext.Items.Remove(ContextKey2);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool Moving
|
||||
{
|
||||
get { return UmbracoContext.Current.HttpContext.Items[ContextKey1] != null; }
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
UmbracoContext.Current.HttpContext.Items[ContextKey1] = true;
|
||||
else
|
||||
{
|
||||
UmbracoContext.Current.HttpContext.Items.Remove(ContextKey1);
|
||||
UmbracoContext.Current.HttpContext.Items.Remove(ContextKey2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,9 +154,14 @@ namespace Umbraco.Web.Redirects
|
||||
if (entityContent == null) continue;
|
||||
foreach (var x in entityContent.DescendantsOrSelf())
|
||||
{
|
||||
var route = contentCache.GetRouteById(x.Id);
|
||||
if (IsNotRoute(route)) continue;
|
||||
OldRoutes[x.Id] = Tuple.Create(x.Key, route);
|
||||
var cultures = x.Cultures.Any() ? x.Cultures.Select(c => c.Key) : new[] {(string) null};
|
||||
|
||||
foreach (var culture in cultures)
|
||||
{
|
||||
var route = contentCache.GetRouteById(x.Id, culture);
|
||||
if (IsNotRoute(route)) return;
|
||||
OldRoutes[new ContentIdAndCulture(x.Id, culture)] = new ContentKeyAndOldRoute(x.Key, route);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,13 +186,13 @@ namespace Umbraco.Web.Redirects
|
||||
LockedEvents = false;
|
||||
}
|
||||
|
||||
private static void CreateRedirect(int contentId, Guid contentKey, string oldRoute)
|
||||
private static void CreateRedirect(int contentId, string culture, Guid contentKey, string oldRoute)
|
||||
{
|
||||
var contentCache = UmbracoContext.Current.ContentCache;
|
||||
var newRoute = contentCache.GetRouteById(contentId);
|
||||
var newRoute = contentCache.GetRouteById(contentId, culture);
|
||||
if (IsNotRoute(newRoute) || oldRoute == newRoute) return;
|
||||
var redirectUrlService = Current.Services.RedirectUrlService;
|
||||
redirectUrlService.Register(oldRoute, contentKey);
|
||||
redirectUrlService.Register(oldRoute, contentKey, culture);
|
||||
}
|
||||
|
||||
private static bool IsNotRoute(string route)
|
||||
@@ -177,5 +201,25 @@ namespace Umbraco.Web.Redirects
|
||||
// err/- if collision or anomaly or ...
|
||||
return route == null || route.StartsWith("err/");
|
||||
}
|
||||
|
||||
private class ContentIdAndCulture : Tuple<int, string>
|
||||
{
|
||||
public ContentIdAndCulture(int contentId, string culture) : base(contentId, culture)
|
||||
{
|
||||
}
|
||||
|
||||
public int ContentId => Item1;
|
||||
public string Culture => Item2;
|
||||
}
|
||||
|
||||
private class ContentKeyAndOldRoute : Tuple<Guid, string>
|
||||
{
|
||||
public ContentKeyAndOldRoute(Guid contentKey, string oldRoute) : base(contentKey, oldRoute)
|
||||
{
|
||||
}
|
||||
|
||||
public Guid ContentKey => Item1;
|
||||
public string OldRoute => Item2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user