Compare commits

..

48 Commits

Author SHA1 Message Date
Shannon efd6bd82bd Revert "V8: Don't show multiple open menus (take two) (#5609)"
This reverts commit 9ce996cbba.

(cherry picked from commit 1d49c8626e)
2019-07-24 12:02:41 +02:00
Sebastiaan Janssen 17527c99eb Makes checks a little more robust
(cherry picked from commit ca75a25802)
2019-07-24 11:37:29 +02:00
Steve Megson 361557dc39 Handle CSV values in TagsPropertyEditor
(cherry picked from commit a97604d6c4)
2019-07-24 11:37:17 +02:00
Kenn Jacobsen 342b2087e9 Make sure save options are up to date with the content state
(cherry picked from commit 8a43e3a87e)
2019-07-24 10:59:01 +02:00
Steve Megson dc371c1979 Include CheckBoxList in ValueListPreValueMigrator 2019-07-23 12:48:48 +02:00
Shannon 2faa4defd8 Merge remote-tracking branch 'origin/v7/7.15' into v8/8.1
# Conflicts:
#	src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
2019-07-23 19:03:14 +10:00
Warren Buckley bb8356d7db Merge pull request #5924 from umbraco/v/bugfix/5035-slot-swap2
Fixes race condition in PublishedSnapshotService and more...
2019-07-23 09:18:44 +01:00
Shannon Deminick 686f6752f3 Merge pull request #5951 from umbraco/v7/hotfix/5921-preview-failing
https://github.com/umbraco/Umbraco-CMS/issues/5921 - AB#1794 - Remove…
2019-07-23 16:58:13 +10:00
Warren Buckley 66ff4d191a Merge pull request #5946 from umbraco/v8/bugfix/5886-fixes-Children
Fixes issue with Children(culture) method
2019-07-22 14:54:49 +01:00
Shannon 21218b0332 Merge remote-tracking branch 'origin/v7/7.15' into v8/8.1
# Conflicts:
#	src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/rte.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js
2019-07-22 13:59:14 +10:00
Shannon Deminick 23ccdeb2cf Merge pull request #5868 from umbraco/v7/hotfix/5835-AB#1693-add-null-checks-when-using-dataTypeId
Added null checks when *.dataTypeId is used
2019-07-22 13:44:05 +10:00
Shannon 6148ce4e52 oops no es6 support in 7.x 2019-07-22 13:41:26 +10:00
Shannon 06850ed25c Merge branch 'v7/7.15' into v7/hotfix/5835-AB#1693-add-null-checks-when-using-dataTypeId 2019-07-22 13:40:35 +10:00
Shannon 0320a56cb5 Fixes up dataTypeId var declarations 2019-07-22 13:27:51 +10:00
Warren Buckley b9e44f381b Merge pull request #5923 from umbraco/v8/hotfix/5902-migration-should-not-warn-about-build-in-renamed-data-types
V8: Migration should not warn about build in data types that is handled correct but renamed
2019-07-19 10:56:38 +01:00
Bjarke Berg cd27bb210f https://github.com/umbraco/Umbraco-CMS/issues/5921 - AB#1794 - Remove trashed nodes from sql when building xml for previews 2019-07-19 11:25:33 +02:00
Bjarke Berg 67f680a675 Revert "https://github.com/umbraco/Umbraco-CMS/issues/5921 - AB#1794 - Remove trashed nodes from sql when building xml for previews"
This reverts commit 47c3e3a7
2019-07-19 11:24:01 +02:00
Bjarke Berg 47c3e3a79f https://github.com/umbraco/Umbraco-CMS/issues/5921 - AB#1794 - Remove trashed nodes from sql when building xml for previews 2019-07-19 11:20:31 +02:00
Shannon 02f49a0039 Cherry picks fix for 5894 and makes adjustments 2019-07-19 16:00:42 +10:00
Shannon b07df63422 Adds some better notes to the api docs 2019-07-19 15:49:39 +10:00
Shannon 487e45b45b updates note 2019-07-19 15:26:31 +10:00
Shannon 929c84822a Fixes the Children ext method and adds unit tests 2019-07-19 15:18:00 +10:00
Warren Buckley 993f11cd2c Merge pull request #5898 from umbraco/v8/hotfix/5846-AB#1695-Fix-for-migration-of-corrupt-data
V8: Give better exception if a json exception happens doing migration
2019-07-18 13:36:35 +01:00
Warren Buckley 6544b5c272 Update src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/ConvertTinyMceAndGridMediaUrlsToLocalLink.cs
Co-Authored-By: Bjarke Berg <mail@bergmania.dk>
2019-07-18 13:03:14 +01:00
Shannon 817a458334 Merge remote-tracking branch 'origin/v7/7.15' into v8/8.1
# Conflicts:
#	src/SolutionInfo.cs
#	src/Umbraco.Core/Configuration/UmbracoVersion.cs
#	src/Umbraco.Web.UI/packages.config
2019-07-18 16:22:38 +10:00
Shannon f3bfc1ffb2 Puts back UmbracoAntiForgeryAdditionalDataProvider for backwards compat reasons but it is not used 2019-07-18 16:18:11 +10:00
Shannon 3603090421 Fixes race condition in PublishedSnapshotService and more... 2019-07-17 22:51:14 +10:00
Bjarke Berg 79159b684d https://github.com/umbraco/Umbraco-CMS/issues/5902
- Fixed issue with migration of Umbraco.Date if it was never saved in v7, the default format was added the time-part.
- Fixed issue with warnings of migrations of build in types, that was renamed between v7 and v8. These are handled correct.
- Added constants for some of the legacy property editor aliases.
2019-07-17 14:30:02 +02:00
Shannon 26d4d056be bumps version 2019-07-17 22:28:06 +10:00
Shannon 6ad28f1103 Merge remote-tracking branch 'origin/v7/7.15' into v8/8.1
# Conflicts:
#	build/NuSpecs/tools/Web.config.install.xdt
#	src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
#	src/Umbraco.Core/Services/EntityService.cs
#	src/Umbraco.Core/Services/IEntityService.cs
#	src/Umbraco.Tests/Web/Mvc/HtmlHelperExtensionMethodsTests.cs
#	src/Umbraco.Web.UI.Client/src/views/member/member.edit.controller.js
#	src/Umbraco.Web/Controllers/UmbLoginController.cs
#	src/Umbraco.Web/Controllers/UmbLoginStatusController.cs
#	src/Umbraco.Web/Controllers/UmbProfileController.cs
#	src/Umbraco.Web/Controllers/UmbRegisterController.cs
#	src/Umbraco.Web/HtmlHelperRenderExtensions.cs
#	src/Umbraco.Web/Mvc/HttpUmbracoFormRouteStringException.cs
#	src/Umbraco.Web/Mvc/ValidateUmbracoFormRouteStringAttribute.cs
#	src/Umbraco.Web/UmbracoHelper.cs
#	src/Umbraco.Web/WebBootManager.cs
2019-07-17 21:58:33 +10:00
Shannon 89cd655df2 Merge remote-tracking branch 'origin/v7/bugfix/build-without-vs2017' into v7/7.15 2019-07-17 21:48:21 +10:00
Shannon 14c4c4815d bumps version 2019-07-17 21:35:43 +10:00
Shannon bfb69a34ef re-adds back in the serialization overloads for the custom exception, re-adds detailed error messages, adds more documentation. Adds unit tests. 2019-07-17 21:15:18 +10:00
Shannon b675f6252c removes files (should have been part of cherry pick?), fixes logic 2019-07-16 23:07:31 +10:00
Shannon d52420183e Cherry picks ValidateUmbracoFormRouteStringAttribute implementation and fixes up some logic 2019-07-16 23:03:26 +10:00
Shannon 0cbe0b4796 Cherry picks ValidateUmbracoFormRouteStringAttribute implementation 2019-07-16 22:34:34 +10:00
Steve Megson 0feb053e51 Fixes #5852 - TablesForScheduledPublishing 2019-07-16 13:39:09 +02:00
Bjarke Berg 09c8ae4e7e Fixed null ref exception in related links migrations 2019-07-16 13:36:16 +02:00
skttl 2aaca865e7 changes innerjoin to left join, to allow folders in sql query 2019-07-16 07:26:26 +02:00
Shannon 77dda5a70f Fixes issue during upgrade where umbraco can't clear cdf log files 2019-07-15 14:34:32 +02:00
Bjarke Berg f6a8d487cc AB#1695 - https://github.com/umbraco/Umbraco-CMS/issues/5846
Give better exception, if a json exception happens doing migration of grid properties in ConvertTinyMceAndGridMediaUrlsToLocalLink
2019-07-15 13:06:47 +02:00
Bjarke Berg 59bf24c461 Added null checks when *.dataTypeId is used 2019-07-12 11:22:31 +02:00
Bjarke Berg 2748c3635d Merge pull request #5863 from umbraco/v7/bugfix/5822-entityservice-overloads
Fixes Change to Entity Service GetByKey isn't breaking in 7.15 #5822
2019-07-12 09:29:45 +02:00
Shannon 2252db0d55 Fixes 5822 by reinstating optional method overloads of loadBaseType 2019-07-12 13:40:21 +10:00
Claus df896af476 adding build targets package. 2019-07-10 12:58:15 +02:00
Claus 4b605b2580 Merge pull request #5799 from kjac/v7-fix-save-member
V7: Can't save members without resetting their password
2019-07-08 09:28:46 +02:00
Kenn Jacobsen 80d7f1b2c9 Make it possible to save a member without resetting the password 2019-07-07 11:36:26 +02:00
Sebastiaan Janssen 5ada85df29 Provide the correct assembly redirects 2019-07-05 12:11:03 +02:00
48 changed files with 662 additions and 417 deletions
+2 -2
View File
@@ -18,5 +18,5 @@ using System.Resources;
[assembly: AssemblyVersion("8.0.0")]
// these are FYI and changed automatically
[assembly: AssemblyFileVersion("8.1.0")]
[assembly: AssemblyInformationalVersion("8.1.0")]
[assembly: AssemblyFileVersion("8.1.1")]
[assembly: AssemblyInformationalVersion("8.1.1")]
+25 -22
View File
@@ -67,31 +67,34 @@ namespace Umbraco.Core
: new NamedSemaphoreReleaser(_semaphore2);
}
public Task<IDisposable> LockAsync()
{
var wait = _semaphore != null
? _semaphore.WaitAsync()
: _semaphore2.WaitOneAsync();
//NOTE: We don't use the "Async" part of this lock at all
//TODO: Remove this and rename this class something like SystemWideLock, then we can re-instate this logic if we ever need an Async lock again
return wait.IsCompleted
? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
: wait.ContinueWith((_, state) => (((AsyncLock) state).CreateReleaser()),
this, CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
//public Task<IDisposable> LockAsync()
//{
// var wait = _semaphore != null
// ? _semaphore.WaitAsync()
// : _semaphore2.WaitOneAsync();
public Task<IDisposable> LockAsync(int millisecondsTimeout)
{
var wait = _semaphore != null
? _semaphore.WaitAsync(millisecondsTimeout)
: _semaphore2.WaitOneAsync(millisecondsTimeout);
// return wait.IsCompleted
// ? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
// : wait.ContinueWith((_, state) => (((AsyncLock) state).CreateReleaser()),
// this, CancellationToken.None,
// TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
//}
return wait.IsCompleted
? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
: wait.ContinueWith((_, state) => (((AsyncLock)state).CreateReleaser()),
this, CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
//public Task<IDisposable> LockAsync(int millisecondsTimeout)
//{
// var wait = _semaphore != null
// ? _semaphore.WaitAsync(millisecondsTimeout)
// : _semaphore2.WaitOneAsync(millisecondsTimeout);
// return wait.IsCompleted
// ? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
// : wait.ContinueWith((_, state) => (((AsyncLock)state).CreateReleaser()),
// this, CancellationToken.None,
// TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
//}
public IDisposable Lock()
{
@@ -14,6 +14,23 @@ namespace Umbraco.Core
/// </summary>
public const string InternalGenericPropertiesPrefix = "_umb_";
public static class Legacy
{
public static class Aliases
{
public const string Textbox = "Umbraco.Textbox";
public const string Date = "Umbraco.Date";
public const string ContentPicker2 = "Umbraco.ContentPicker2";
public const string MediaPicker2 = "Umbraco.MediaPicker2";
public const string MemberPicker2 = "Umbraco.MemberPicker2";
public const string MultiNodeTreePicker2 = "Umbraco.MultiNodeTreePicker2";
public const string TextboxMultiple = "Umbraco.TextboxMultiple";
public const string RelatedLinks2 = "Umbraco.RelatedLinks2";
public const string RelatedLinks = "Umbraco.RelatedLinks";
}
}
/// <summary>
/// Defines Umbraco built-in property editor aliases.
/// </summary>
+6 -1
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Web.Hosting;
@@ -113,7 +114,7 @@ namespace Umbraco.Core
lock (_locko)
{
_logger.Debug<MainDom>("Signaled {Signaled} ({SignalSource})", _signaled ? "(again)" : string.Empty, source);
_logger.Debug<MainDom>("Signaled ({Signaled}) ({SignalSource})", _signaled ? "again" : "first", source);
if (_signaled) return;
if (_isMainDom == false) return; // probably not needed
_signaled = true;
@@ -171,6 +172,7 @@ namespace Umbraco.Core
// if more than 1 instance reach that point, one will get the lock
// and the other one will timeout, which is accepted
//TODO: This can throw a TimeoutException - in which case should this be in a try/finally to ensure the signal is always reset?
_asyncLocker = _asyncLock.Lock(LockTimeoutMilliseconds);
_isMainDom = true;
@@ -181,6 +183,9 @@ namespace Umbraco.Core
// which is accepted
_signal.Reset();
//WaitOneAsync (ext method) will wait for a signal without blocking the main thread, the waiting is done on a background thread
_signal.WaitOneAsync()
.ContinueWith(_ => OnSignal("signal"));
@@ -19,8 +19,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
var sqlDataTypes = Sql()
.Select<DataTypeDto>()
.From<DataTypeDto>()
.Where<DataTypeDto>(x => x.EditorAlias == "Umbraco.RelatedLinks"
|| x.EditorAlias == "Umbraco.RelatedLinks2");
.Where<DataTypeDto>(x => x.EditorAlias == Constants.PropertyEditors.Legacy.Aliases.RelatedLinks
|| x.EditorAlias == Constants.PropertyEditors.Legacy.Aliases.RelatedLinks2);
var dataTypes = Database.Fetch<DataTypeDto>(sqlDataTypes);
var dataTypeIds = dataTypes.Select(x => x.NodeId).ToList();
@@ -50,10 +50,10 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
var properties = Database.Fetch<PropertyDataDto>(sqlPropertyData);
// Create a Multi URL Picker datatype for the converted RelatedLinks data
foreach (var property in properties)
{
var value = property.Value.ToString();
var value = property.Value?.ToString();
if (string.IsNullOrWhiteSpace(value))
continue;
@@ -89,7 +89,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
Name = relatedLink.Caption,
Target = relatedLink.NewWindow ? "_blank" : null,
Udi = udi,
// Should only have a URL if it's an external link otherwise it wil be a UDI
// Should only have a URL if it's an external link otherwise it wil be a UDI
Url = relatedLink.IsInternal == false ? relatedLink.Link : null
};
@@ -103,7 +103,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
Database.Update(property);
}
}
}
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core.Composing;
@@ -18,6 +19,18 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
private readonly PropertyEditorCollection _propertyEditors;
private readonly ILogger _logger;
private static readonly ISet<string> LegacyAliases = new HashSet<string>()
{
Constants.PropertyEditors.Legacy.Aliases.Date,
Constants.PropertyEditors.Legacy.Aliases.Textbox,
Constants.PropertyEditors.Legacy.Aliases.ContentPicker2,
Constants.PropertyEditors.Legacy.Aliases.MediaPicker2,
Constants.PropertyEditors.Legacy.Aliases.MemberPicker2,
Constants.PropertyEditors.Legacy.Aliases.RelatedLinks2,
Constants.PropertyEditors.Legacy.Aliases.TextboxMultiple,
Constants.PropertyEditors.Legacy.Aliases.MultiNodeTreePicker2,
};
public DataTypeMigration(IMigrationContext context, PreValueMigratorCollection preValueMigrators, PropertyEditorCollection propertyEditors, ILogger logger)
: base(context)
{
@@ -70,16 +83,23 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
var newAlias = migrator.GetNewAlias(dataType.EditorAlias);
if (newAlias == null)
{
_logger.Warn<DataTypeMigration>("Skipping validation of configuration for data type {NodeId} : {EditorAlias}."
+ " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, dataType.EditorAlias);
if (!LegacyAliases.Contains(dataType.EditorAlias))
{
_logger.Warn<DataTypeMigration>(
"Skipping validation of configuration for data type {NodeId} : {EditorAlias}."
+ " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, dataType.EditorAlias);
}
}
else if (!_propertyEditors.TryGet(newAlias, out var propertyEditor))
{
_logger.Warn<DataTypeMigration>("Skipping validation of configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})"
+ " because no property editor with that alias was found."
+ " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, newAlias, dataType.EditorAlias);
if (!LegacyAliases.Contains(newAlias))
{
_logger.Warn<DataTypeMigration>("Skipping validation of configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})"
+ " because no property editor with that alias was found."
+ " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
dataType.NodeId, newAlias, dataType.EditorAlias);
}
}
else
{
@@ -3,7 +3,7 @@
class ContentPickerPreValueMigrator : DefaultPreValueMigrator
{
public override bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.ContentPicker2";
=> editorAlias == Constants.PropertyEditors.Legacy.Aliases.ContentPicker2;
public override string GetNewAlias(string editorAlias)
=> null;
@@ -6,15 +6,15 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
private readonly string[] _editors =
{
"Umbraco.MediaPicker2",
"Umbraco.MediaPicker"
Constants.PropertyEditors.Legacy.Aliases.MediaPicker2,
Constants.PropertyEditors.Aliases.MediaPicker
};
public override bool CanMigrate(string editorAlias)
=> _editors.Contains(editorAlias);
public override string GetNewAlias(string editorAlias)
=> "Umbraco.MediaPicker";
=> Constants.PropertyEditors.Aliases.MediaPicker;
// you wish - but MediaPickerConfiguration lives in Umbraco.Web
/*
@@ -9,6 +9,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
private readonly string[] _editors =
{
"Umbraco.RadioButtonList",
"Umbraco.CheckBoxList",
"Umbraco.DropDown",
"Umbraco.DropdownlistPublishingKeys",
"Umbraco.DropDownMultiple",
@@ -16,7 +16,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
var dataTypes = GetDataTypes("Umbraco.Date");
var dataTypes = GetDataTypes(Constants.PropertyEditors.Legacy.Aliases.Date);
foreach (var dataType in dataTypes)
{
@@ -25,6 +25,14 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
config = (DateTimeConfiguration) new CustomDateTimeConfigurationEditor().FromDatabase(
dataType.Configuration);
// If the Umbraco.Date type is the default from V7 and it has never been updated, then the
// configuration is empty, and the format stuff is handled by in JS by moment.js. - We can't do that
// after the migration, so we force the format to the default from V7.
if (string.IsNullOrEmpty(dataType.Configuration))
{
config.Format = "YYYY-MM-DD";
};
}
catch (Exception ex)
{
@@ -12,12 +12,12 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
RenameDataType(Constants.PropertyEditors.Aliases.ContentPicker + "2", Constants.PropertyEditors.Aliases.ContentPicker);
RenameDataType(Constants.PropertyEditors.Aliases.MediaPicker + "2", Constants.PropertyEditors.Aliases.MediaPicker);
RenameDataType(Constants.PropertyEditors.Aliases.MemberPicker + "2", Constants.PropertyEditors.Aliases.MemberPicker);
RenameDataType(Constants.PropertyEditors.Aliases.MultiNodeTreePicker + "2", Constants.PropertyEditors.Aliases.MultiNodeTreePicker);
RenameDataType("Umbraco.TextboxMultiple", Constants.PropertyEditors.Aliases.TextArea, false);
RenameDataType("Umbraco.Textbox", Constants.PropertyEditors.Aliases.TextBox, false);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.ContentPicker2, Constants.PropertyEditors.Aliases.ContentPicker);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.MediaPicker2, Constants.PropertyEditors.Aliases.MediaPicker);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.MemberPicker2, Constants.PropertyEditors.Aliases.MemberPicker);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.MultiNodeTreePicker2, Constants.PropertyEditors.Aliases.MultiNodeTreePicker);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.TextboxMultiple, Constants.PropertyEditors.Aliases.TextArea, false);
RenameDataType(Constants.PropertyEditors.Legacy.Aliases.Textbox, Constants.PropertyEditors.Aliases.TextBox, false);
}
private void RenameDataType(string fromAlias, string toAlias, bool checkCollision = true)
@@ -43,7 +43,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
$"Property Editors. Before upgrading to v8, any Data Types using property editors that are named with the prefix '(Obsolete)' must be migrated " +
$"to the non-obsolete v7 property editors of the same type.");
}
}
Database.Execute(Sql()
@@ -14,11 +14,18 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
//Get anything currently scheduled
var scheduleSql = new Sql()
.Select("nodeId", "releaseDate", "expireDate")
var releaseSql = new Sql()
.Select("nodeId", "releaseDate")
.From("umbracoDocument")
.Where("releaseDate IS NOT NULL OR expireDate IS NOT NULL");
var schedules = Database.Dictionary<int, (DateTime? releaseDate, DateTime? expireDate)> (scheduleSql);
.Where("releaseDate IS NOT NULL");
var releases = Database.Dictionary<int, DateTime> (releaseSql);
var expireSql = new Sql()
.Select("nodeId", "expireDate")
.From("umbracoDocument")
.Where("expireDate IS NOT NULL");
var expires = Database.Dictionary<int, DateTime>(expireSql);
//drop old cols
Delete.Column("releaseDate").FromTable("umbracoDocument").Do();
@@ -27,20 +34,25 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
Create.Table<ContentScheduleDto>(true).Do();
//migrate the schedule
foreach(var s in schedules)
foreach(var s in releases)
{
var date = s.Value.releaseDate;
var date = s.Value;
var action = ContentScheduleAction.Release.ToString();
if (!date.HasValue)
{
date = s.Value.expireDate;
action = ContentScheduleAction.Expire.ToString();
}
Insert.IntoTable(ContentScheduleDto.TableName)
.Row(new { nodeId = s.Key, date = date.Value, action = action })
.Row(new { id = Guid.NewGuid(), nodeId = s.Key, date = date, action = action })
.Do();
}
foreach (var s in expires)
{
var date = s.Value;
var action = ContentScheduleAction.Expire.ToString();
Insert.IntoTable(ContentScheduleDto.TableName)
.Row(new { id = Guid.NewGuid(), nodeId = s.Key, date = date, action = action })
.Do();
}
}
}
}
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
@@ -36,6 +37,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
var properties = Database.Fetch<PropertyDataDto>(sqlPropertyData);
var exceptions = new List<Exception>();
foreach (var property in properties)
{
var value = property.TextValue;
@@ -43,19 +45,34 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
if (property.PropertyTypeDto.DataTypeDto.EditorAlias == Constants.PropertyEditors.Aliases.Grid)
{
var obj = JsonConvert.DeserializeObject<JObject>(value);
var allControls = obj.SelectTokens("$.sections..rows..areas..controls");
foreach (var control in allControls.SelectMany(c => c))
try
{
var controlValue = control["value"];
if (controlValue.Type == JTokenType.String)
var obj = JsonConvert.DeserializeObject<JObject>(value);
var allControls = obj.SelectTokens("$.sections..rows..areas..controls");
foreach (var control in allControls.SelectMany(c => c))
{
control["value"] = UpdateMediaUrls(mediaLinkPattern, controlValue.Value<string>());
var controlValue = control["value"];
if (controlValue.Type == JTokenType.String)
{
control["value"] = UpdateMediaUrls(mediaLinkPattern, controlValue.Value<string>());
}
}
property.TextValue = JsonConvert.SerializeObject(obj);
}
catch (JsonException e)
{
exceptions.Add(new InvalidOperationException(
"Cannot deserialize the value as json. This can be because the property editor " +
"type is changed from another type into a grid. Old versions of the value in this " +
"property can have the structure from the old property editor type. This needs to be " +
"changed manually before updating the database.\n" +
$"Property info: Id = {property.Id}, LanguageId = {property.LanguageId}, VersionId = {property.VersionId}, Value = {property.Value}"
, e));
continue;
}
property.TextValue = JsonConvert.SerializeObject(obj);
}
else
{
@@ -65,6 +82,12 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
Database.Update(property);
}
if (exceptions.Any())
{
throw new AggregateException("One or more errors related to unexpected data in grid values occurred.", exceptions);
}
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
+14 -6
View File
@@ -103,18 +103,26 @@ namespace Umbraco.Core
/// Gets the children of the content item.
/// </summary>
/// <param name="content">The content item.</param>
/// <param name="culture">The specific culture to get the url children for. If null is used the current culture is used (Default is null).</param>
/// <param name="culture">
/// The specific culture to get the url children for. Default is null which will use the current culture in <see cref="VariationContext"/>
/// </param>
/// <remarks>
/// <para>Gets children that are available for the specified culture.</para>
/// <para>Children are sorted by their sortOrder.</para>
/// <para>The '*' culture and supported and returns everything.</para>
/// <para>
/// For culture,
/// if null is used the current culture is used.
/// If an empty string is used only invariant children are returned.
/// If "*" is used all children are returned.
/// </para>
/// <para>
/// If a variant culture is specified or there is a current culture in the <see cref="VariationContext"/> then the Children returned
/// will include both the variant children matching the culture AND the invariant children because the invariant children flow with the current culture.
/// However, if an empty string is specified only invariant children are returned.
/// </para>
/// </remarks>
public static IEnumerable<IPublishedContent> Children(this IPublishedContent content, string culture = null)
{
// invariant has invariant value (whatever the requested culture)
if (!content.ContentType.VariesByCulture() && culture != "*")
culture = "";
// handle context culture for variant
if (culture == null)
culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
+3 -3
View File
@@ -139,7 +139,7 @@ namespace Umbraco.Core.Runtime
// there should be none, really - this is here "just in case"
Compose(composition);
// acquire the main domain
// acquire the main domain - if this fails then anything that should be registered with MainDom will not operate
AcquireMainDom(mainDom);
// determine our runtime level
@@ -218,13 +218,13 @@ namespace Umbraco.Core.Runtime
IOHelper.SetRootDirectory(path);
}
private void AcquireMainDom(MainDom mainDom)
private bool AcquireMainDom(MainDom mainDom)
{
using (var timer = ProfilingLogger.DebugDuration<CoreRuntime>("Acquiring MainDom.", "Acquired."))
{
try
{
mainDom.Acquire();
return mainDom.Acquire();
}
catch
{
+5
View File
@@ -97,6 +97,11 @@ namespace Umbraco.Core
/// <param name="request"></param>
internal void EnsureApplicationUrl(HttpRequestBase request = null)
{
//Fixme: This causes problems with site swap on azure because azure pre-warms a site by calling into `localhost` and when it does that
// it changes the URL to `localhost:80` which actually doesn't work for pinging itself, it only works internally in Azure. The ironic part
// about this is that this is here specifically for the slot swap scenario https://issues.umbraco.org/issue/U4-10626
// see U4-10626 - in some cases we want to reset the application url
// (this is a simplified version of what was in 7.x)
// note: should this be optional? is it expensive?
+2
View File
@@ -23,6 +23,8 @@ namespace Umbraco.Core
handle,
(state, timedOut) =>
{
//TODO: We aren't checking if this is timed out
tcs.SetResult(null);
// we take a lock here to make sure the outer method has completed setting the local variable callbackHandle.
@@ -124,7 +124,7 @@ namespace Umbraco.Tests.PublishedContent
_source = new TestDataSource(kits);
// at last, create the complete NuCache snapshot service!
var options = new PublishedSnapshotService.Options { IgnoreLocalDb = true };
var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true };
_snapshotService = new PublishedSnapshotService(options,
null,
runtime,
@@ -151,117 +151,139 @@ namespace Umbraco.Tests.PublishedContent
Mock.Get(factory).Setup(x => x.GetInstance(typeof(IVariationContextAccessor))).Returns(_variationAccesor);
}
private IEnumerable<ContentNodeKit> GetNestedVariantKits()
{
var paths = new Dictionary<int, string> { { -1, "-1" } };
//1x variant (root)
yield return CreateVariantKit(1, -1, 1, paths);
//1x invariant under root
yield return CreateInvariantKit(4, 1, 1, paths);
//1x variant under root
yield return CreateVariantKit(7, 1, 4, paths);
//2x mixed under invariant
yield return CreateVariantKit(10, 4, 1, paths);
yield return CreateInvariantKit(11, 4, 2, paths);
//2x mixed under variant
yield return CreateVariantKit(12, 7, 1, paths);
yield return CreateInvariantKit(13, 7, 2, paths);
}
private IEnumerable<ContentNodeKit> GetInvariantKits()
{
var paths = new Dictionary<int, string> { { -1, "-1" } };
ContentNodeKit CreateKit(int id, int parentId, int sortOrder)
yield return CreateInvariantKit(1, -1, 1, paths);
yield return CreateInvariantKit(2, -1, 2, paths);
yield return CreateInvariantKit(3, -1, 3, paths);
yield return CreateInvariantKit(4, 1, 1, paths);
yield return CreateInvariantKit(5, 1, 2, paths);
yield return CreateInvariantKit(6, 1, 3, paths);
yield return CreateInvariantKit(7, 2, 3, paths);
yield return CreateInvariantKit(8, 2, 2, paths);
yield return CreateInvariantKit(9, 2, 1, paths);
yield return CreateInvariantKit(10, 3, 1, paths);
yield return CreateInvariantKit(11, 4, 1, paths);
yield return CreateInvariantKit(12, 4, 2, paths);
}
private ContentNodeKit CreateInvariantKit(int id, int parentId, int sortOrder, Dictionary<int, string> paths)
{
if (!paths.TryGetValue(parentId, out var parentPath))
throw new Exception("Unknown parent.");
var path = paths[id] = parentPath + "," + id;
var level = path.Count(x => x == ',');
var now = DateTime.Now;
return new ContentNodeKit
{
if (!paths.TryGetValue(parentId, out var parentPath))
throw new Exception("Unknown parent.");
var path = paths[id] = parentPath + "," + id;
var level = path.Count(x => x == ',');
var now = DateTime.Now;
return new ContentNodeKit
ContentTypeId = _contentTypeInvariant.Id,
Node = new ContentNode(id, Guid.NewGuid(), level, path, sortOrder, parentId, DateTime.Now, 0),
DraftData = null,
PublishedData = new ContentData
{
ContentTypeId = _contentTypeInvariant.Id,
Node = new ContentNode(id, Guid.NewGuid(), level, path, sortOrder, parentId, DateTime.Now, 0),
DraftData = null,
PublishedData = new ContentData
{
Name = "N" + id,
Published = true,
TemplateId = 0,
VersionId = 1,
VersionDate = now,
WriterId = 0,
Properties = new Dictionary<string, PropertyData[]>(),
CultureInfos = new Dictionary<string, CultureVariation>()
}
};
}
yield return CreateKit(1, -1, 1);
yield return CreateKit(2, -1, 2);
yield return CreateKit(3, -1, 3);
yield return CreateKit(4, 1, 1);
yield return CreateKit(5, 1, 2);
yield return CreateKit(6, 1, 3);
yield return CreateKit(7, 2, 3);
yield return CreateKit(8, 2, 2);
yield return CreateKit(9, 2, 1);
yield return CreateKit(10, 3, 1);
yield return CreateKit(11, 4, 1);
yield return CreateKit(12, 4, 2);
Name = "N" + id,
Published = true,
TemplateId = 0,
VersionId = 1,
VersionDate = now,
WriterId = 0,
Properties = new Dictionary<string, PropertyData[]>(),
CultureInfos = new Dictionary<string, CultureVariation>()
}
};
}
private IEnumerable<ContentNodeKit> GetVariantKits()
{
var paths = new Dictionary<int, string> { { -1, "-1" } };
Dictionary<string, CultureVariation> GetCultureInfos(int id, DateTime now)
yield return CreateVariantKit(1, -1, 1, paths);
yield return CreateVariantKit(2, -1, 2, paths);
yield return CreateVariantKit(3, -1, 3, paths);
yield return CreateVariantKit(4, 1, 1, paths);
yield return CreateVariantKit(5, 1, 2, paths);
yield return CreateVariantKit(6, 1, 3, paths);
yield return CreateVariantKit(7, 2, 3, paths);
yield return CreateVariantKit(8, 2, 2, paths);
yield return CreateVariantKit(9, 2, 1, paths);
yield return CreateVariantKit(10, 3, 1, paths);
yield return CreateVariantKit(11, 4, 1, paths);
yield return CreateVariantKit(12, 4, 2, paths);
}
private static Dictionary<string, CultureVariation> GetCultureInfos(int id, DateTime now)
{
var en = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
var fr = new[] { 1, 3, 4, 6, 7, 9, 10, 12 };
var infos = new Dictionary<string, CultureVariation>();
if (en.Contains(id))
infos["en-US"] = new CultureVariation { Name = "N" + id + "-" + "en-US", Date = now, IsDraft = false };
if (fr.Contains(id))
infos["fr-FR"] = new CultureVariation { Name = "N" + id + "-" + "fr-FR", Date = now, IsDraft = false };
return infos;
}
private ContentNodeKit CreateVariantKit(int id, int parentId, int sortOrder, Dictionary<int, string> paths)
{
if (!paths.TryGetValue(parentId, out var parentPath))
throw new Exception("Unknown parent.");
var path = paths[id] = parentPath + "," + id;
var level = path.Count(x => x == ',');
var now = DateTime.Now;
return new ContentNodeKit
{
var en = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
var fr = new[] { 1, 3, 4, 6, 7, 9, 10, 12 };
var infos = new Dictionary<string, CultureVariation>();
if (en.Contains(id))
infos["en-US"] = new CultureVariation { Name = "N" + id + "-" + "en-US", Date = now, IsDraft = false };
if (fr.Contains(id))
infos["fr-FR"] = new CultureVariation { Name = "N" + id + "-" + "fr-FR", Date = now, IsDraft = false };
return infos;
}
ContentNodeKit CreateKit(int id, int parentId, int sortOrder)
{
if (!paths.TryGetValue(parentId, out var parentPath))
throw new Exception("Unknown parent.");
var path = paths[id] = parentPath + "," + id;
var level = path.Count(x => x == ',');
var now = DateTime.Now;
return new ContentNodeKit
ContentTypeId = _contentTypeVariant.Id,
Node = new ContentNode(id, Guid.NewGuid(), level, path, sortOrder, parentId, DateTime.Now, 0),
DraftData = null,
PublishedData = new ContentData
{
ContentTypeId = _contentTypeVariant.Id,
Node = new ContentNode(id, Guid.NewGuid(), level, path, sortOrder, parentId, DateTime.Now, 0),
DraftData = null,
PublishedData = new ContentData
{
Name = "N" + id,
Published = true,
TemplateId = 0,
VersionId = 1,
VersionDate = now,
WriterId = 0,
Properties = new Dictionary<string, PropertyData[]>(),
CultureInfos = GetCultureInfos(id, now)
}
};
}
yield return CreateKit(1, -1, 1);
yield return CreateKit(2, -1, 2);
yield return CreateKit(3, -1, 3);
yield return CreateKit(4, 1, 1);
yield return CreateKit(5, 1, 2);
yield return CreateKit(6, 1, 3);
yield return CreateKit(7, 2, 3);
yield return CreateKit(8, 2, 2);
yield return CreateKit(9, 2, 1);
yield return CreateKit(10, 3, 1);
yield return CreateKit(11, 4, 1);
yield return CreateKit(12, 4, 2);
Name = "N" + id,
Published = true,
TemplateId = 0,
VersionId = 1,
VersionDate = now,
WriterId = 0,
Properties = new Dictionary<string, PropertyData[]>(),
CultureInfos = GetCultureInfos(id, now)
}
};
}
private IEnumerable<ContentNodeKit> GetVariantWithDraftKits()
@@ -660,6 +682,96 @@ namespace Umbraco.Tests.PublishedContent
Assert.AreEqual(1, snapshot.Content.GetById(7).Parent?.Id);
}
[Test]
public void NestedVariationChildrenTest()
{
var mixedKits = GetNestedVariantKits();
Init(mixedKits);
var snapshot = _snapshotService.CreatePublishedSnapshot(previewToken: null);
_snapshotAccessor.PublishedSnapshot = snapshot;
//TEST with en-us variation context
_variationAccesor.VariationContext = new VariationContext("en-US");
var documents = snapshot.Content.GetAtRoot().ToArray();
AssertDocuments(documents, "N1-en-US");
documents = snapshot.Content.GetById(1).Children().ToArray();
AssertDocuments(documents, "N4", "N7-en-US");
//Get the invariant and list children, there's a variation context so it should return invariant AND en-us variants
documents = snapshot.Content.GetById(4).Children().ToArray();
AssertDocuments(documents, "N10-en-US", "N11");
//Get the variant and list children, there's a variation context so it should return invariant AND en-us variants
documents = snapshot.Content.GetById(7).Children().ToArray();
AssertDocuments(documents, "N12-en-US", "N13");
//TEST with fr-fr variation context
_variationAccesor.VariationContext = new VariationContext("fr-FR");
documents = snapshot.Content.GetAtRoot().ToArray();
AssertDocuments(documents, "N1-fr-FR");
documents = snapshot.Content.GetById(1).Children().ToArray();
AssertDocuments(documents, "N4", "N7-fr-FR");
//Get the invariant and list children, there's a variation context so it should return invariant AND en-us variants
documents = snapshot.Content.GetById(4).Children().ToArray();
AssertDocuments(documents, "N10-fr-FR", "N11");
//Get the variant and list children, there's a variation context so it should return invariant AND en-us variants
documents = snapshot.Content.GetById(7).Children().ToArray();
AssertDocuments(documents, "N12-fr-FR", "N13");
//TEST specific cultures
documents = snapshot.Content.GetAtRoot("fr-FR").ToArray();
AssertDocuments(documents, "N1-fr-FR");
documents = snapshot.Content.GetById(1).Children("fr-FR").ToArray();
AssertDocuments(documents, "N4", "N7-fr-FR"); //NOTE: Returns invariant, this is expected
documents = snapshot.Content.GetById(1).Children("").ToArray();
AssertDocuments(documents, "N4"); //Only returns invariant since that is what was requested
documents = snapshot.Content.GetById(4).Children("fr-FR").ToArray();
AssertDocuments(documents, "N10-fr-FR", "N11"); //NOTE: Returns invariant, this is expected
documents = snapshot.Content.GetById(4).Children("").ToArray();
AssertDocuments(documents, "N11"); //Only returns invariant since that is what was requested
documents = snapshot.Content.GetById(7).Children("fr-FR").ToArray();
AssertDocuments(documents, "N12-fr-FR", "N13"); //NOTE: Returns invariant, this is expected
documents = snapshot.Content.GetById(7).Children("").ToArray();
AssertDocuments(documents, "N13"); //Only returns invariant since that is what was requested
//TEST without variation context
// This will actually convert the culture to "" which will be invariant since that's all it will know how to do
// This will return a NULL name for culture specific entities because there is no variation context
_variationAccesor.VariationContext = null;
documents = snapshot.Content.GetAtRoot().ToArray();
//will return nothing because there's only variant at root
Assert.AreEqual(0, documents.Length);
//so we'll continue to getting the known variant, do not fully assert this because the Name will NULL
documents = snapshot.Content.GetAtRoot("fr-FR").ToArray();
Assert.AreEqual(1, documents.Length);
documents = snapshot.Content.GetById(1).Children().ToArray();
AssertDocuments(documents, "N4");
//Get the invariant and list children
documents = snapshot.Content.GetById(4).Children().ToArray();
AssertDocuments(documents, "N11");
//Get the variant and list children
documents = snapshot.Content.GetById(7).Children().ToArray();
AssertDocuments(documents, "N13");
}
[Test]
public void VariantChildrenTest()
{
@@ -169,7 +169,7 @@ namespace Umbraco.Tests.PublishedContent
_variationAccesor = new TestVariationContextAccessor();
// at last, create the complete NuCache snapshot service!
var options = new PublishedSnapshotService.Options { IgnoreLocalDb = true };
var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true };
_snapshotService = new PublishedSnapshotService(options,
null,
runtime,
@@ -72,7 +72,7 @@ namespace Umbraco.Tests.Scoping
protected override IPublishedSnapshotService CreatePublishedSnapshotService()
{
var options = new PublishedSnapshotService.Options { IgnoreLocalDb = true };
var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true };
var publishedSnapshotAccessor = new UmbracoContextPublishedSnapshotAccessor(Umbraco.Web.Composing.Current.UmbracoContextAccessor);
var runtimeStateMock = new Mock<IRuntimeState>();
runtimeStateMock.Setup(x => x.Level).Returns(() => RuntimeLevel.Run);
@@ -1,157 +0,0 @@
using System.Collections.Specialized;
using System.Web;
using System.Web.Helpers;
using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web.Mvc;
using Umbraco.Web.Security;
namespace Umbraco.Tests.Security
{
[TestFixture]
public class UmbracoAntiForgeryAdditionalDataProviderTests
{
[Test]
public void Test_Wrapped_Non_BeginUmbracoForm()
{
var wrapped = Mock.Of<IAntiForgeryAdditionalDataProvider>(x => x.GetAdditionalData(It.IsAny<HttpContextBase>()) == "custom");
var provider = new UmbracoAntiForgeryAdditionalDataProvider(wrapped);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var data = provider.GetAdditionalData(httpContextFactory.HttpContext);
Assert.IsTrue(data.DetectIsJson());
var json = JsonConvert.DeserializeObject<UmbracoAntiForgeryAdditionalDataProvider.AdditionalData>(data);
Assert.AreEqual(null, json.Ufprt);
Assert.IsTrue(json.Stamp != default);
Assert.AreEqual("custom", json.WrappedValue);
}
[Test]
public void Null_Wrapped_Non_BeginUmbracoForm()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var data = provider.GetAdditionalData(httpContextFactory.HttpContext);
Assert.IsTrue(data.DetectIsJson());
var json = JsonConvert.DeserializeObject<UmbracoAntiForgeryAdditionalDataProvider.AdditionalData>(data);
Assert.AreEqual(null, json.Ufprt);
Assert.IsTrue(json.Stamp != default);
Assert.AreEqual("default", json.WrappedValue);
}
[Test]
public void Validate_Non_Json()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "hello");
Assert.IsFalse(isValid);
}
[Test]
public void Validate_Invalid_Json()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '0'}");
Assert.IsFalse(isValid);
isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': ''}");
Assert.IsFalse(isValid);
isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'hello': 'world'}");
Assert.IsFalse(isValid);
}
[Test]
public void Validate_No_Request_Ufprt()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
//there is a ufprt in the additional data, but not in the request
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': 'ASBVDFDFDFDF'}");
Assert.IsFalse(isValid);
}
[Test]
public void Validate_No_AdditionalData_Ufprt()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var requestMock = Mock.Get(httpContextFactory.HttpContext.Request);
requestMock.SetupGet(x => x["ufprt"]).Returns("ABCDEFG");
//there is a ufprt in the additional data, but not in the request
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': ''}");
Assert.IsFalse(isValid);
}
[Test]
public void Validate_No_AdditionalData_Or_Request_Ufprt()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
//there is a ufprt in the additional data, but not in the request
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': ''}");
Assert.IsTrue(isValid);
}
[Test]
public void Validate_Request_And_AdditionalData_Ufprt()
{
var provider = new UmbracoAntiForgeryAdditionalDataProvider(null);
var routeParams1 = $"{RenderRouteHandler.ReservedAdditionalKeys.Controller}={HttpUtility.UrlEncode("Test")}&{RenderRouteHandler.ReservedAdditionalKeys.Action}={HttpUtility.UrlEncode("Index")}&{RenderRouteHandler.ReservedAdditionalKeys.Area}=Umbraco";
var routeParams2 = $"{RenderRouteHandler.ReservedAdditionalKeys.Controller}={HttpUtility.UrlEncode("Test")}&{RenderRouteHandler.ReservedAdditionalKeys.Action}={HttpUtility.UrlEncode("Index")}&{RenderRouteHandler.ReservedAdditionalKeys.Area}=Umbraco";
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var requestMock = Mock.Get(httpContextFactory.HttpContext.Request);
requestMock.SetupGet(x => x["ufprt"]).Returns(routeParams1.EncryptWithMachineKey());
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': '" + routeParams2.EncryptWithMachineKey() + "'}");
Assert.IsTrue(isValid);
routeParams2 = $"{RenderRouteHandler.ReservedAdditionalKeys.Controller}={HttpUtility.UrlEncode("Invalid")}&{RenderRouteHandler.ReservedAdditionalKeys.Action}={HttpUtility.UrlEncode("Index")}&{RenderRouteHandler.ReservedAdditionalKeys.Area}=Umbraco";
isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': '" + routeParams2.EncryptWithMachineKey() + "'}");
Assert.IsFalse(isValid);
}
[Test]
public void Validate_Wrapped_Request_And_AdditionalData_Ufprt()
{
var wrapped = Mock.Of<IAntiForgeryAdditionalDataProvider>(x => x.ValidateAdditionalData(It.IsAny<HttpContextBase>(), "custom") == true);
var provider = new UmbracoAntiForgeryAdditionalDataProvider(wrapped);
var routeParams1 = $"{RenderRouteHandler.ReservedAdditionalKeys.Controller}={HttpUtility.UrlEncode("Test")}&{RenderRouteHandler.ReservedAdditionalKeys.Action}={HttpUtility.UrlEncode("Index")}&{RenderRouteHandler.ReservedAdditionalKeys.Area}=Umbraco";
var routeParams2 = $"{RenderRouteHandler.ReservedAdditionalKeys.Controller}={HttpUtility.UrlEncode("Test")}&{RenderRouteHandler.ReservedAdditionalKeys.Action}={HttpUtility.UrlEncode("Index")}&{RenderRouteHandler.ReservedAdditionalKeys.Area}=Umbraco";
var httpContextFactory = new FakeHttpContextFactory("/hello/world");
var requestMock = Mock.Get(httpContextFactory.HttpContext.Request);
requestMock.SetupGet(x => x["ufprt"]).Returns(routeParams1.EncryptWithMachineKey());
var isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': '" + routeParams2.EncryptWithMachineKey() + "'}");
Assert.IsFalse(isValid);
isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'custom', 'Ufprt': '" + routeParams2.EncryptWithMachineKey() + "'}");
Assert.IsTrue(isValid);
routeParams2 = $"{RenderRouteHandler.ReservedAdditionalKeys.Controller}={HttpUtility.UrlEncode("Invalid")}&{RenderRouteHandler.ReservedAdditionalKeys.Action}={HttpUtility.UrlEncode("Index")}&{RenderRouteHandler.ReservedAdditionalKeys.Area}=Umbraco";
isValid = provider.ValidateAdditionalData(httpContextFactory.HttpContext, "{'Stamp': '636970328040070330', 'WrappedValue': 'default', 'Ufprt': '" + routeParams2.EncryptWithMachineKey() + "'}");
Assert.IsFalse(isValid);
}
}
}
@@ -42,7 +42,7 @@ namespace Umbraco.Tests.Services
protected override IPublishedSnapshotService CreatePublishedSnapshotService()
{
var options = new PublishedSnapshotService.Options { IgnoreLocalDb = true };
var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true };
var publishedSnapshotAccessor = new UmbracoContextPublishedSnapshotAccessor(Umbraco.Web.Composing.Current.UmbracoContextAccessor);
var runtimeStateMock = new Mock<IRuntimeState>();
runtimeStateMock.Setup(x => x.Level).Returns(() => RuntimeLevel.Run);
+1 -1
View File
@@ -147,7 +147,6 @@
<Compile Include="Routing\MediaUrlProviderTests.cs" />
<Compile Include="Runtimes\StandaloneTests.cs" />
<Compile Include="Routing\GetContentUrlsTests.cs" />
<Compile Include="Security\UmbracoAntiForgeryAdditionalDataProviderTests.cs" />
<Compile Include="Services\AmbiguousEventTests.cs" />
<Compile Include="Services\ContentServiceEventTests.cs" />
<Compile Include="Services\ContentServicePublishBranchTests.cs" />
@@ -268,6 +267,7 @@
<Compile Include="StringNewlineExtensions.cs" />
<Compile Include="Strings\StylesheetHelperTests.cs" />
<Compile Include="Strings\StringValidationTests.cs" />
<Compile Include="Web\Mvc\ValidateUmbracoFormRouteStringAttributeTests.cs" />
<Compile Include="Web\UmbracoHelperTests.cs" />
<Compile Include="Membership\MembershipProviderBaseTests.cs" />
<Compile Include="Membership\UmbracoServiceMembershipProviderTests.cs" />
@@ -4,6 +4,7 @@ using Umbraco.Web;
namespace Umbraco.Tests.Web.Mvc
{
[TestFixture]
public class HtmlHelperExtensionMethodsTests
{
@@ -0,0 +1,37 @@
using NUnit.Framework;
using Umbraco.Web;
using Umbraco.Web.Mvc;
namespace Umbraco.Tests.Web.Mvc
{
[TestFixture]
public class ValidateUmbracoFormRouteStringAttributeTests
{
[Test]
public void Validate_Route_String()
{
var attribute = new ValidateUmbracoFormRouteStringAttribute();
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(null, null, null, null));
const string ControllerName = "Test";
const string ControllerAction = "Index";
const string Area = "MyArea";
var validUfprt = UrlHelperRenderExtensions.CreateEncryptedRouteString(ControllerName, ControllerAction, Area);
var invalidUfprt = validUfprt + "z";
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(invalidUfprt, null, null, null));
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(validUfprt, ControllerName, ControllerAction, "doesntMatch"));
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(validUfprt, ControllerName, ControllerAction, null));
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(validUfprt, ControllerName, "doesntMatch", Area));
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(validUfprt, ControllerName, null, Area));
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(validUfprt, "doesntMatch", ControllerAction, Area));
Assert.Throws<HttpUmbracoFormRouteStringException>(() => attribute.ValidateRouteString(validUfprt, null, ControllerAction, Area));
Assert.DoesNotThrow(() => attribute.ValidateRouteString(validUfprt, ControllerName, ControllerAction, Area));
Assert.DoesNotThrow(() => attribute.ValidateRouteString(validUfprt, ControllerName.ToLowerInvariant(), ControllerAction.ToLowerInvariant(), Area.ToLowerInvariant()));
}
}
}
@@ -94,6 +94,10 @@
content.apps[0].active = true;
$scope.appChanged(content.apps[0]);
}
// otherwise make sure the save options are up to date with the current content state
else {
createButtons($scope.content);
}
editorState.set(content);
@@ -101,14 +101,14 @@ angular.module('umbraco.directives')
var eventBindings = [];
function oneTimeClick(event) {
// ignore clicks on button groups toggles (i.e. the save and publish button)
var parents = $(event.target).closest("[data-element='button-group-toggle']");
if (parents.length > 0) {
return;
}
var el = event.target.nodeName;
//ignore link and button clicks
var els = ["INPUT", "A", "BUTTON"];
if (els.indexOf(el) >= 0) { return; }
// ignore clicks on new overlay
parents = $(event.target).parents(".umb-overlay,.umb-tour");
var parents = $(event.target).parents("a,button,.umb-overlay,.umb-tour");
if (parents.length > 0) {
return;
}
@@ -131,12 +131,6 @@ angular.module('umbraco.directives')
return;
}
// ignore clicks on dialog actions
var actions = $(event.target).parents(".umb-action");
if (actions.length === 1) {
return;
}
//ignore clicks inside this element
if ($(element).has($(event.target)).length > 0) {
return;
@@ -404,7 +404,8 @@ function entityResource($q, $http, umbRequestHelper) {
pageNumber: 100,
filter: '',
orderDirection: "Ascending",
orderBy: "SortOrder"
orderBy: "SortOrder",
dataTypeKey: null
};
if (options === undefined) {
options = {};
@@ -421,6 +422,7 @@ function entityResource($q, $http, umbRequestHelper) {
options.orderDirection = "Descending";
}
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
@@ -51,13 +51,17 @@ angular.module("umbraco")
$scope.acceptedMediatypes = types;
});
var dataTypeKey = null;
if($scope.model && $scope.model.dataTypeKey) {
dataTypeKey = $scope.model.dataTypeKey;
}
$scope.searchOptions = {
pageNumber: 1,
pageSize: 100,
totalItems: 0,
totalPages: 0,
filter: '',
dataTypeKey: $scope.model.dataTypeKey
dataTypeKey: dataTypeKey
};
//preload selected item
@@ -160,7 +164,7 @@ angular.module("umbraco")
}
if (folder.id > 0) {
entityResource.getAncestors(folder.id, "media", null, { dataTypeKey: $scope.model.dataTypeKey })
entityResource.getAncestors(folder.id, "media", null, { dataTypeKey: dataTypeKey })
.then(function (anc) {
$scope.path = _.filter(anc,
function (f) {
@@ -311,6 +315,7 @@ angular.module("umbraco")
if ($scope.searchOptions.filter) {
searchMedia();
} else {
// reset pagination
$scope.searchOptions = {
pageNumber: 1,
@@ -318,7 +323,7 @@ angular.module("umbraco")
totalItems: 0,
totalPages: 0,
filter: '',
dataTypeKey: $scope.model.dataTypeKey
dataTypeKey: dataTypeKey
};
getChildren($scope.currentFolder.id);
}
@@ -19,6 +19,7 @@
$scope.hasError = false;
$scope.internal = function ($event) {
$scope.currentEditLink = null;
var contentPicker = {
@@ -41,6 +42,7 @@
};
$scope.selectInternal = function ($event, link) {
$scope.currentEditLink = link;
var contentPicker = {
+2 -2
View File
@@ -345,9 +345,9 @@
<WebProjectProperties>
<UseIIS>False</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>8100</DevelopmentServerPort>
<DevelopmentServerPort>8110</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:8100</IISUrl>
<IISUrl>http://localhost:8110</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -22,6 +22,7 @@ namespace Umbraco.Web.Controllers
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateUmbracoFormRouteString]
public ActionResult HandleLogin([Bind(Prefix = "loginModel")]LoginModel model)
{
if (ModelState.IsValid == false)
@@ -24,6 +24,7 @@ namespace Umbraco.Web.Controllers
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateUmbracoFormRouteString]
public ActionResult HandleLogout([Bind(Prefix = "logoutModel")]PostRedirectModel model)
{
if (ModelState.IsValid == false)
@@ -23,6 +23,7 @@ namespace Umbraco.Web.Controllers
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateUmbracoFormRouteString]
public ActionResult HandleUpdateProfile([Bind(Prefix = "profileModel")] ProfileModel model)
{
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
@@ -24,6 +24,7 @@ namespace Umbraco.Web.Controllers
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateUmbracoFormRouteString]
public ActionResult HandleRegisterMember([Bind(Prefix = "registerModel")]RegisterModel model)
{
if (ModelState.IsValid == false)
@@ -224,13 +224,6 @@ namespace Umbraco.Web
_controllerName = controllerName;
_encryptedString = UrlHelperRenderExtensions.CreateEncryptedRouteString(controllerName, controllerAction, area, additionalRouteVals);
//For UmbracoForm's we want to add our routing string to the httpcontext items in the case where anti-forgery tokens are used.
//In which case our custom UmbracoAntiForgeryAdditionalDataProvider will kick in and validate the values in the request against
//the values that will be appended to the token. This essentially means that when anti-forgery tokens are used with UmbracoForm's forms,
//that each token is unique to the controller/action/area instead of the default ASP.Net implementation which is that the token is unique
//per user.
_viewContext.HttpContext.Items["ufprt"] = _encryptedString;
}
@@ -106,8 +106,10 @@ namespace Umbraco.Web.JavaScript
}
try
{
var fullPath = currentHttpContext.Server.MapPath(XmlFileMapper.FileMapDefaultFolder);
{
var fullPath = XmlFileMapper.FileMapDefaultFolder.StartsWith("~/")
? currentHttpContext.Server.MapPath(XmlFileMapper.FileMapDefaultFolder)
: XmlFileMapper.FileMapDefaultFolder;
if (fullPath != null)
{
cdfTempDirectories.Add(fullPath);
@@ -122,13 +124,12 @@ namespace Umbraco.Web.JavaScript
var success = true;
foreach (var directory in cdfTempDirectories)
{
var directoryInfo = new DirectoryInfo(directory);
if (directoryInfo.Exists == false)
continue;
try
{
directoryInfo.Delete(true);
if (!Directory.Exists(directory))
continue;
Directory.Delete(directory, true);
}
catch (Exception ex)
{
@@ -0,0 +1,41 @@
using System;
using System.Net;
using System.Runtime.Serialization;
using System.Web;
namespace Umbraco.Web.Mvc
{
/// <summary>
/// Exception that occurs when an Umbraco form route string is invalid
/// </summary>
/// <seealso cref="System.Web.HttpException" />
[Serializable]
public sealed class HttpUmbracoFormRouteStringException : HttpException
{
/// Initializes a new instance of the <see cref="HttpUmbracoFormRouteStringException" /> class.
/// </summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that holds the contextual information about the source or destination.</param>
private HttpUmbracoFormRouteStringException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="HttpUmbracoFormRouteStringException" /> class.
/// </summary>
/// <param name="message">The error message displayed to the client when the exception is thrown.</param>
public HttpUmbracoFormRouteStringException(string message)
: base(message)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="HttpUmbracoFormRouteStringException" /> class.
/// </summary>
/// <param name="message">The error message displayed to the client when the exception is thrown.</param>
/// <param name="innerException">The <see cref="P:System.Exception.InnerException" />, if any, that threw the current exception.</param>
public HttpUmbracoFormRouteStringException(string message, Exception innerException)
: base(message, innerException)
{ }
}
}
@@ -0,0 +1,62 @@
using System;
using System.Net;
using System.Net.Http;
using System.Web.Mvc;
using Umbraco.Core;
namespace Umbraco.Web.Mvc
{
/// <summary>
/// Attribute used to check that the request contains a valid Umbraco form request string.
/// </summary>
/// <seealso cref="System.Web.Mvc.FilterAttribute" />
/// <seealso cref="System.Web.Mvc.IAuthorizationFilter" />
/// <remarks>
/// Applying this attribute/filter to a <see cref="SurfaceController"/> or SurfaceController Action will ensure that the Action can only be executed
/// when it is routed to from within Umbraco, typically when rendering a form with BegingUmbracoForm. It will mean that the natural MVC route for this Action
/// will fail with a <see cref="HttpUmbracoFormRouteStringException"/>.
/// </remarks>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class ValidateUmbracoFormRouteStringAttribute : FilterAttribute, IAuthorizationFilter
{
/// <summary>
/// Called when authorization is required.
/// </summary>
/// <param name="filterContext">The filter context.</param>
/// <exception cref="ArgumentNullException">filterContext</exception>
/// <exception cref="Umbraco.Web.Mvc.HttpUmbracoFormRouteStringException">The required request field \"ufprt\" is not present.
/// or
/// The Umbraco form request route string could not be decrypted.
/// or
/// The provided Umbraco form request route string was meant for a different controller and action.</exception>
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
throw new ArgumentNullException(nameof(filterContext));
var ufprt = filterContext.HttpContext.Request["ufprt"];
ValidateRouteString(ufprt, filterContext.ActionDescriptor?.ControllerDescriptor.ControllerName, filterContext.ActionDescriptor?.ActionName, filterContext.RouteData?.DataTokens["area"]?.ToString());
}
public void ValidateRouteString(string ufprt, string currentController, string currentAction, string currentArea)
{
if (ufprt.IsNullOrWhiteSpace())
{
throw new HttpUmbracoFormRouteStringException("The required request field \"ufprt\" is not present.");
}
if (!UmbracoHelper.DecryptAndValidateEncryptedRouteString(ufprt, out var additionalDataParts))
{
throw new HttpUmbracoFormRouteStringException("The Umbraco form request route string could not be decrypted.");
}
if (!additionalDataParts[RenderRouteHandler.ReservedAdditionalKeys.Controller].InvariantEquals(currentController) ||
!additionalDataParts[RenderRouteHandler.ReservedAdditionalKeys.Action].InvariantEquals(currentAction) ||
(!additionalDataParts[RenderRouteHandler.ReservedAdditionalKeys.Area].IsNullOrWhiteSpace() && !additionalDataParts[RenderRouteHandler.ReservedAdditionalKeys.Area].InvariantEquals(currentArea)))
{
throw new HttpUmbracoFormRouteStringException("The provided Umbraco form request route string was meant for a different controller and action.");
}
}
}
}
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Newtonsoft.Json.Linq;
@@ -38,9 +39,24 @@ namespace Umbraco.Web.PropertyEditors
/// <inheritdoc />
public override object FromEditor(ContentPropertyData editorValue, object currentValue)
{
return editorValue.Value is JArray json
? json.Select(x => x.Value<string>())
: null;
var value = editorValue?.Value?.ToString();
if (string.IsNullOrEmpty(value))
{
return null;
}
if (editorValue.Value is JArray json)
{
return json.Select(x => x.Value<string>());
}
if (string.IsNullOrWhiteSpace(value) == false)
{
return value.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
}
return null;
}
/// <inheritdoc />
@@ -15,7 +15,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// register the NuCache published snapshot service
// must register default options, required in the service ctor
composition.Register(factory => new PublishedSnapshotService.Options());
composition.Register(factory => new PublishedSnapshotServiceOptions());
composition.SetPublishedSnapshotService<PublishedSnapshotService>();
// add the NuCache health check (hidden from type finder)
@@ -30,7 +30,8 @@ using File = System.IO.File;
namespace Umbraco.Web.PublishedCache.NuCache
{
class PublishedSnapshotService : PublishedSnapshotServiceBase
internal class PublishedSnapshotService : PublishedSnapshotServiceBase
{
private readonly ServiceContext _serviceContext;
private readonly IPublishedContentTypeFactory _publishedContentTypeFactory;
@@ -56,7 +57,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
private BPlusTree<int, ContentNodeKit> _localContentDb;
private BPlusTree<int, ContentNodeKit> _localMediaDb;
private readonly bool _localDbExists;
private bool _localDbExists;
// define constant - determines whether to use cache when previewing
// to store eg routes, property converted values, anything - caching
@@ -68,7 +69,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
//private static int _singletonCheck;
public PublishedSnapshotService(Options options, IMainDom mainDom, IRuntimeState runtime,
public PublishedSnapshotService(PublishedSnapshotServiceOptions options, IMainDom mainDom, IRuntimeState runtime,
ServiceContext serviceContext, IPublishedContentTypeFactory publishedContentTypeFactory, IdkMap idkMap,
IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, ILogger logger, IScopeProvider scopeProvider,
IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository,
@@ -115,30 +116,36 @@ namespace Umbraco.Web.PublishedCache.NuCache
if (options.IgnoreLocalDb == false)
{
var registered = mainDom.Register(
null,
() =>
{
//"install" phase of MainDom
//this is inside of a lock in MainDom so this is guaranteed to run if MainDom was acquired and guaranteed
//to not run if MainDom wasn't acquired.
//If MainDom was not acquired, then _localContentDb and _localMediaDb will remain null which means this appdomain
//will load in published content via the DB and in that case this appdomain will probably not exist long enough to
//serve more than a page of content.
var path = GetLocalFilesPath();
var localContentDbPath = Path.Combine(path, "NuCache.Content.db");
var localMediaDbPath = Path.Combine(path, "NuCache.Media.db");
_localDbExists = File.Exists(localContentDbPath) && File.Exists(localMediaDbPath);
// if both local databases exist then GetTree will open them, else new databases will be created
_localContentDb = BTree.GetTree(localContentDbPath, _localDbExists);
_localMediaDb = BTree.GetTree(localMediaDbPath, _localDbExists);
},
() =>
{
//"release" phase of MainDom
lock (_storesLock)
{
_contentStore.ReleaseLocalDb();
_contentStore?.ReleaseLocalDb(); //null check because we could shut down before being assigned
_localContentDb = null;
_mediaStore.ReleaseLocalDb();
_mediaStore?.ReleaseLocalDb(); //null check because we could shut down before being assigned
_localMediaDb = null;
}
});
if (registered)
{
var path = GetLocalFilesPath();
var localContentDbPath = Path.Combine(path, "NuCache.Content.db");
var localMediaDbPath = Path.Combine(path, "NuCache.Media.db");
_localDbExists = System.IO.File.Exists(localContentDbPath) && System.IO.File.Exists(localMediaDbPath);
// if both local databases exist then GetTree will open them, else new databases will be created
_localContentDb = BTree.GetTree(localContentDbPath, _localDbExists);
_localMediaDb = BTree.GetTree(localMediaDbPath, _localDbExists);
}
// stores are created with a db so they can write to it, but they do not read from it,
// stores need to be populated, happens in OnResolutionFrozen which uses _localDbExists to
// figure out whether it can read the databases or it should populate them from sql
@@ -251,19 +258,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
base.Dispose();
}
public class Options
{
// disabled: prevents the published snapshot from updating and exposing changes
// or even creating a new published snapshot to see changes, uses old cache = bad
//
//// indicates that the snapshot cache should reuse the application request cache
//// otherwise a new cache object would be created for the snapshot specifically,
//// which is the default - web boot manager uses this to optimize facades
//public bool PublishedSnapshotCacheIsApplicationRequestCache;
public bool IgnoreLocalDb;
}
#endregion
#region Local files
@@ -1056,8 +1050,10 @@ namespace Umbraco.Web.PublishedCache.NuCache
: _dataSource.GetTypeMediaSources(scope, refreshedIds).ToArray();
_mediaStore.UpdateContentTypes(removedIds, typesA, kits);
_mediaStore.UpdateContentTypes(CreateContentTypes(PublishedItemType.Media, otherIds.ToArray()).ToArray());
_mediaStore.NewContentTypes(CreateContentTypes(PublishedItemType.Media, newIds.ToArray()).ToArray());
if (!otherIds.IsCollectionEmpty())
_mediaStore.UpdateContentTypes(CreateContentTypes(PublishedItemType.Media, otherIds.ToArray()).ToArray());
if (!newIds.IsCollectionEmpty())
_mediaStore.NewContentTypes(CreateContentTypes(PublishedItemType.Media, newIds.ToArray()).ToArray());
scope.Complete();
}
}
@@ -0,0 +1,28 @@
namespace Umbraco.Web.PublishedCache.NuCache
{
/// <summary>
/// Options class for configuring the <see cref="IPublishedSnapshotService"/>
/// </summary>
public class PublishedSnapshotServiceOptions
{
// disabled: prevents the published snapshot from updating and exposing changes
// or even creating a new published snapshot to see changes, uses old cache = bad
//
//// indicates that the snapshot cache should reuse the application request cache
//// otherwise a new cache object would be created for the snapshot specifically,
//// which is the default - web boot manager uses this to optimize facades
//public bool PublishedSnapshotCacheIsApplicationRequestCache;
/// <summary>
/// If true this disables the persisted local cache files for content and media
/// </summary>
/// <remarks>
/// By default this is false which means umbraco will use locally persisted cache files for reading in all published content and media on application startup.
/// The reason for this is to improve startup times because the alternative to populating the published content and media on application startup is to read
/// these values from the database. In scenarios where sites are relatively small (below a few thousand nodes) reading the content/media from the database to populate
/// the in memory cache isn't that slow and is only marginally slower than reading from the locally persisted cache files.
/// </remarks>
public bool IgnoreLocalDb { get; set; }
}
}
@@ -36,8 +36,6 @@ namespace Umbraco.Web.Runtime
// ensure WebAPI is initialized, after everything
GlobalConfiguration.Configuration.EnsureInitialized();
AntiForgeryConfig.AdditionalDataProvider = new UmbracoAntiForgeryAdditionalDataProvider(AntiForgeryConfig.AdditionalDataProvider);
}
public void Terminate()
+1 -1
View File
@@ -64,7 +64,7 @@ namespace Umbraco.Web.Scheduling
}
catch (Exception ex)
{
_logger.Error<KeepAlive>(ex, "Failed (at '{UmbracoAppUrl}').", umbracoAppUrl);
_logger.Error<KeepAlive>(ex, "Keep alive failed (at '{UmbracoAppUrl}').", umbracoAppUrl);
}
}
@@ -4,13 +4,12 @@ using Umbraco.Core;
using System.Web.Helpers;
using System.Web;
using Newtonsoft.Json;
using Umbraco.Web.Composing;
using System.ComponentModel;
namespace Umbraco.Web.Security
{
/// <summary>
/// A custom <see cref="IAntiForgeryAdditionalDataProvider"/> to create a unique antiforgery token/validator per form created with BeginUmbracoForm
/// </summary>
[Obsolete("This is no longer used and will be removed from the codebase in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
public class UmbracoAntiForgeryAdditionalDataProvider : IAntiForgeryAdditionalDataProvider
{
private readonly IAntiForgeryAdditionalDataProvider _defaultProvider;
+4 -1
View File
@@ -219,9 +219,12 @@
<Compile Include="Models\Mapping\MapperContextExtensions.cs" />
<Compile Include="Models\PublishedContent\HybridVariationContextAccessor.cs" />
<Compile Include="Models\TemplateQuery\QueryConditionExtensions.cs" />
<Compile Include="Mvc\HttpUmbracoFormRouteStringException.cs" />
<Compile Include="Mvc\ModelBindingExceptionFilter.cs" />
<Compile Include="Mvc\SurfaceControllerTypeCollectionBuilder.cs" />
<Compile Include="Mvc\ValidateUmbracoFormRouteStringAttribute.cs" />
<Compile Include="Profiling\WebProfilingController.cs" />
<Compile Include="PublishedCache\NuCache\PublishedSnapshotServiceOptions.cs" />
<Compile Include="PublishedCache\NuCache\Snap\GenObj.cs" />
<Compile Include="PublishedCache\NuCache\Snap\GenRef.cs" />
<Compile Include="PublishedCache\NuCache\Snap\LinkedNode.cs" />
@@ -230,7 +233,6 @@
<Compile Include="Routing\IPublishedRouter.cs" />
<Compile Include="Routing\MediaUrlProviderCollection.cs" />
<Compile Include="Routing\MediaUrlProviderCollectionBuilder.cs" />
<Compile Include="Security\UmbracoAntiForgeryAdditionalDataProvider.cs" />
<Compile Include="Services\DashboardService.cs" />
<Compile Include="Services\IDashboardService.cs" />
<Compile Include="Models\Link.cs" />
@@ -340,6 +342,7 @@
<Compile Include="Editors\TourController.cs" />
<Compile Include="HealthCheck\Checks\Security\XssProtectionCheck.cs" />
<Compile Include="HealthCheck\Checks\Security\HstsCheck.cs" />
<Compile Include="Security\UmbracoAntiForgeryAdditionalDataProvider.cs" />
<Compile Include="Editors\UserEditorAuthorizationHelper.cs" />
<Compile Include="Editors\Filters\UserGroupAuthorizationAttribute.cs" />
<Compile Include="Editors\Filters\UserGroupEditorAuthorizationHelper.cs" />
+1 -1
View File
@@ -820,7 +820,7 @@ namespace Umbraco.Web
{
decryptedString = ufprt.DecryptWithMachineKey();
}
catch (FormatException)
catch (Exception ex) when (ex is FormatException || ex is ArgumentException)
{
Current.Logger.Warn(typeof(UmbracoHelper), "A value was detected in the ufprt parameter but Umbraco could not decrypt the string");
parts = null;