diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index f4e237a1f2..bada94c30b 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -16,6 +16,7 @@ This project and everyone participating in it, is governed by the [our Code of C
[Contributing code changes](#contributing-code-changes)
* [Guidelines for contributions we welcome](#guidelines-for-contributions-we-welcome)
+ * [Ownership and copyright](#ownership-and-copyright)
* [What can I start with?](#what-can-i-start-with)
* [How do I begin?](#how-do-i-begin)
* [Pull requests](#pull-requests)
@@ -44,6 +45,17 @@ We have [documented what we consider small and large changes](CONTRIBUTION_GUIDE
Remember, it is always worth working on an issue from the `Up for grabs` list or even asking for some feedback before you send us a PR. This way, your PR will not be closed as unwanted.
+#### Ownership and copyright
+
+It is your responsibility to make sure that you're allowed to share the code you're providing us.
+For example, you should have permission from your employer or customer to share code.
+
+Similarly, if your contribution is copied or adapted from somewhere else, make sure that the license allows you to reuse that for a contribution to Umbraco-CMS.
+
+If you're not sure, leave a note on your contribution and we will be happy to guide you.
+
+When your contribution has been accepted, it will be [MIT licensed](https://github.com/umbraco/Umbraco-CMS/blob/v8/contrib/LICENSE.md) from that time onwards.
+
### What can I start with?
Unsure where to begin contributing to Umbraco? You can start by looking through [these `Up for grabs` issues](https://github.com/umbraco/Umbraco-CMS/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Acommunity%2Fup-for-grabs+)
@@ -124,7 +136,7 @@ You can get in touch with [the core contributors team](#the-core-contributors-te
In order to build the Umbraco source code locally, first make sure you have the following installed.
- * [Visual Studio 2019 v16.3+ (with .NET Core 3.0)](https://visualstudio.microsoft.com/vs/)
+ * [Visual Studio 2019 v16.8+ (with .NET Core 3.0)](https://visualstudio.microsoft.com/vs/)
* [Node.js v10+](https://nodejs.org/en/download/)
* npm v6.4.1+ (installed with Node.js)
* [Git command line](https://git-scm.com/download/)
diff --git a/.github/ISSUE_TEMPLATE/01_bug_report.yml b/.github/ISSUE_TEMPLATE/01_bug_report.yml
new file mode 100644
index 0000000000..800ac53e68
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/01_bug_report.yml
@@ -0,0 +1,52 @@
+---
+name: 🐛 Bug Report
+description: "File a bug report, if you've discovered a problem in Umbraco."
+labels: "type/bug"
+body:
+- type: input
+ id: "version"
+ attributes:
+ label: "Which *exact* Umbraco version are you using? For example: 8.13.1 - don't just write v8"
+ description: "Use the help icon in the Umbraco backoffice to find the version you're using"
+ validations:
+ required: true
+- type: textarea
+ id: "summary"
+ attributes:
+ label: "Bug summary"
+ description: "Write a short summary of the bug."
+ placeholder: >
+ Try to pinpoint it as much as possible.
+
+ Try to state the actual problem, and not just what you think the solution might be.
+ validations:
+ required: true
+- type: textarea
+ attributes:
+ label: "Specifics"
+ id: "specifics"
+ description: "Remember that you can format code and logs nicely with the `<>` button"
+ placeholder: >
+ Mention the URL where this bug occurs, if applicable
+
+ Please mention if you've checked it in other browsers as well
+
+ Please include full error messages and screenshots, gifs or mp4 videos if applicable
+- type: textarea
+ attributes:
+ label: "Steps to reproduce"
+ id: "reproduction"
+ description: "How can we reproduce the problem on a clean Umbraco install?"
+ placeholder: >
+ Please include screenshots, gifs or mp4 videos if applicable
+ validations:
+ required: true
+- type: textarea
+ attributes:
+ label: "Expected result / actual result"
+ id: "result"
+ description: "What did you expect that would happen on your Umbraco site and what is the actual result of the above steps?"
+ placeholder: >
+ Describe the intended/desired outcome after you did the steps mentioned.
+
+ Describe the behaviour of the bug
diff --git a/.github/ISSUE_TEMPLATE/1_Bug.md b/.github/ISSUE_TEMPLATE/1_Bug.md
deleted file mode 100644
index d388af0d39..0000000000
--- a/.github/ISSUE_TEMPLATE/1_Bug.md
+++ /dev/null
@@ -1,66 +0,0 @@
----
-name: 🐛 Bug Report
-about: File a bug report, if you've discovered a problem in Umbraco.
----
-
-A brief description of the issue goes here.
-
-
-
-## Umbraco version
-
-I am seeing this issue on Umbraco version:
-
-
-Reproduction
-------------
-
-If you're filing a bug, please describe how to reproduce it. Include as much
-relevant information as possible, such as:
-
-### Bug summary
-
-
-
-### Specifics
-
-
-
-### Steps to reproduce
-
-
-
-### Expected result
-
-
-
-### Actual result
-
-
diff --git a/.github/ISSUE_TEMPLATE/2_Feature_request.md b/.github/ISSUE_TEMPLATE/2_Feature_request.md
deleted file mode 100644
index 16ec2568dd..0000000000
--- a/.github/ISSUE_TEMPLATE/2_Feature_request.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-name: 📮 Feature Request
-about: Open a feature request, if you want to propose a new feature.
----
-
-A brief description of your feature request goes here.
-
-
-
-
-How can you help?
--------------------------------
-
-
diff --git a/.github/ISSUE_TEMPLATE/3_BugNetCore.md b/.github/ISSUE_TEMPLATE/3_BugNetCore.md
deleted file mode 100644
index 989904d4d8..0000000000
--- a/.github/ISSUE_TEMPLATE/3_BugNetCore.md
+++ /dev/null
@@ -1,65 +0,0 @@
----
-name: 🌟 .Net Core Bug Report
-about: For bugs specifically for the upcoming .NET Core release of Umbraco, don't use this if you're working with Umbraco version 7 or 8
-labels: project/net-core
----
-
-ℹ️ If this bug **also** appears on the current version 8 of Umbraco then please [report it as a regular bug](https://github.com/umbraco/Umbraco-CMS/issues/new?template=1_Bug.md), fixes in version 8 will be merged to the .NET Core version.
-
-A brief description of the issue goes here.
-
-
-
-
-Reproduction
-------------
-
-If you're filing a bug, please describe how to reproduce it. Include as much
-relevant information as possible, such as:
-
-### Bug summary
-
-
-
-### Specifics
-
-
-
-### Steps to reproduce
-
-
-
-### Expected result
-
-
-
-### Actual result
-
-
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 37d1be9158..ecf10b8854 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,5 +1,8 @@
-blank_issues_enabled: true
+blank_issues_enabled: false
contact_links:
+ - name: 💡 Features and ideas
+ url: https://github.com/umbraco/Umbraco-CMS/discussions/new?category=features-and-ideas
+ about: Start a new discussion when you have ideas or feature requests, eventually discussions can turn into plans
- name: ⁉️ Support Question
url: https://our.umbraco.com
about: This issue tracker is NOT meant for support questions. If you have a question, please join us on the forum.
@@ -8,4 +11,4 @@ contact_links:
about: Documentation issues should be reported on the Umbraco documentation repository.
- name: 🔐 Security Issue
url: https://umbraco.com/about-us/trust-center/security-and-umbraco/how-to-report-a-vulnerability-in-umbraco/
- about: Discovered a Security Issue in Umbraco?
\ No newline at end of file
+ about: Discovered a Security Issue in Umbraco?
diff --git a/build/NuSpecs/UmbracoCms.Web.nuspec b/build/NuSpecs/UmbracoCms.Web.nuspec
index d8815bab63..7aebfae108 100644
--- a/build/NuSpecs/UmbracoCms.Web.nuspec
+++ b/build/NuSpecs/UmbracoCms.Web.nuspec
@@ -28,7 +28,7 @@
-
+
@@ -43,6 +43,8 @@
+
+
diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs
index 2a7386cb45..201213cffa 100644
--- a/src/SolutionInfo.cs
+++ b/src/SolutionInfo.cs
@@ -18,5 +18,5 @@ using System.Resources;
[assembly: AssemblyVersion("8.0.0")]
// these are FYI and changed automatically
-[assembly: AssemblyFileVersion("8.13.0")]
-[assembly: AssemblyInformationalVersion("8.13.0-rc")]
+[assembly: AssemblyFileVersion("8.15.0")]
+[assembly: AssemblyInformationalVersion("8.15.0")]
diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs
index 0e9a9a3862..642bef6d0c 100644
--- a/src/Umbraco.Core/Cache/CacheKeys.cs
+++ b/src/Umbraco.Core/Cache/CacheKeys.cs
@@ -17,5 +17,8 @@
public const string UserAllMediaStartNodesPrefix = "AllMediaStartNodes";
public const string UserMediaStartNodePathsPrefix = "MediaStartNodePaths";
public const string UserContentStartNodePathsPrefix = "ContentStartNodePaths";
+
+ public const string ContentRecycleBinCacheKey = "recycleBin_content";
+ public const string MediaRecycleBinCacheKey = "recycleBin_media";
}
}
diff --git a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs
index c11309c827..94756ce975 100644
--- a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs
+++ b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Cache
internal class DefaultRepositoryCachePolicy : RepositoryCachePolicyBase
where TEntity : class, IEntity
{
- private static readonly TEntity[] EmptyEntities = new TEntity[0]; // const
+ private static readonly TEntity[] s_emptyEntities = new TEntity[0]; // const
private readonly RepositoryCachePolicyOptions _options;
public DefaultRepositoryCachePolicy(IAppPolicyCache cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options)
@@ -29,16 +29,24 @@ namespace Umbraco.Core.Cache
_options = options ?? throw new ArgumentNullException(nameof(options));
}
- protected string GetEntityCacheKey(object id)
+ protected string GetEntityCacheKey(int id) => EntityTypeCacheKey + id;
+
+ protected string GetEntityCacheKey(TId id)
{
- if (id == null) throw new ArgumentNullException(nameof(id));
- return GetEntityTypeCacheKey() + id;
+ if (EqualityComparer.Default.Equals(id, default))
+ {
+ return string.Empty;
+ }
+
+ if (typeof(TId).IsValueType)
+ {
+ return EntityTypeCacheKey + id;
+ }
+
+ return EntityTypeCacheKey + id.ToString().ToUpperInvariant();
}
- protected string GetEntityTypeCacheKey()
- {
- return $"uRepo_{typeof (TEntity).Name}_";
- }
+ protected string EntityTypeCacheKey { get; } = $"uRepo_{typeof(TEntity).Name}_";
protected virtual void InsertEntity(string cacheKey, TEntity entity)
{
@@ -52,7 +60,7 @@ namespace Umbraco.Core.Cache
// getting all of them, and finding nothing.
// if we can cache a zero count, cache an empty array,
// for as long as the cache is not cleared (no expiration)
- Cache.Insert(GetEntityTypeCacheKey(), () => EmptyEntities);
+ Cache.Insert(EntityTypeCacheKey, () => s_emptyEntities);
}
else
{
@@ -81,7 +89,7 @@ namespace Umbraco.Core.Cache
}
// if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.Clear(GetEntityTypeCacheKey());
+ Cache.Clear(EntityTypeCacheKey);
}
catch
{
@@ -91,7 +99,7 @@ namespace Umbraco.Core.Cache
Cache.Clear(GetEntityCacheKey(entity.Id));
// if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.Clear(GetEntityTypeCacheKey());
+ Cache.Clear(EntityTypeCacheKey);
throw;
}
@@ -113,7 +121,7 @@ namespace Umbraco.Core.Cache
}
// if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.Clear(GetEntityTypeCacheKey());
+ Cache.Clear(EntityTypeCacheKey);
}
catch
{
@@ -123,7 +131,7 @@ namespace Umbraco.Core.Cache
Cache.Clear(GetEntityCacheKey(entity.Id));
// if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.Clear(GetEntityTypeCacheKey());
+ Cache.Clear(EntityTypeCacheKey);
throw;
}
@@ -144,7 +152,7 @@ namespace Umbraco.Core.Cache
var cacheKey = GetEntityCacheKey(entity.Id);
Cache.Clear(cacheKey);
// if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.Clear(GetEntityTypeCacheKey());
+ Cache.Clear(EntityTypeCacheKey);
}
}
@@ -195,7 +203,7 @@ namespace Umbraco.Core.Cache
else
{
// get everything we have
- var entities = Cache.GetCacheItemsByKeySearch(GetEntityTypeCacheKey())
+ var entities = Cache.GetCacheItemsByKeySearch(EntityTypeCacheKey)
.ToArray(); // no need for null checks, we are not caching nulls
if (entities.Length > 0)
@@ -218,7 +226,7 @@ namespace Umbraco.Core.Cache
{
// if none of them were in the cache
// and we allow zero count - check for the special (empty) entry
- var empty = Cache.GetCacheItem(GetEntityTypeCacheKey());
+ var empty = Cache.GetCacheItem(EntityTypeCacheKey);
if (empty != null) return empty;
}
}
@@ -238,7 +246,7 @@ namespace Umbraco.Core.Cache
///
public override void ClearAll()
{
- Cache.ClearByKey(GetEntityTypeCacheKey());
+ Cache.ClearByKey(EntityTypeCacheKey);
}
}
}
diff --git a/src/Umbraco.Core/Compose/RelateOnTrashComponent.cs b/src/Umbraco.Core/Compose/RelateOnTrashComponent.cs
index a216a584ba..27eb559462 100644
--- a/src/Umbraco.Core/Compose/RelateOnTrashComponent.cs
+++ b/src/Umbraco.Core/Compose/RelateOnTrashComponent.cs
@@ -93,7 +93,8 @@ namespace Umbraco.Core.Compose
item.Entity.Id,
ObjectTypes.GetName(UmbracoObjectTypes.Document),
string.Format(textService.Localize(
- "recycleBin/contentTrashed"),
+ "recycleBin","contentTrashed"),
+
item.Entity.Id, originalParentId));
}
}
@@ -132,7 +133,7 @@ namespace Umbraco.Core.Compose
item.Entity.Id,
ObjectTypes.GetName(UmbracoObjectTypes.Media),
string.Format(textService.Localize(
- "recycleBin/mediaTrashed"),
+ "recycleBin", "mediaTrashed"),
item.Entity.Id, originalParentId));
}
}
diff --git a/src/Umbraco.Core/Composing/Current.cs b/src/Umbraco.Core/Composing/Current.cs
index a06f09baf6..a4ccd59f9d 100644
--- a/src/Umbraco.Core/Composing/Current.cs
+++ b/src/Umbraco.Core/Composing/Current.cs
@@ -30,6 +30,7 @@ namespace Umbraco.Core.Composing
public static class Current
{
private static IFactory _factory;
+ private static IRuntimeState _state;
// TODO: get rid of these oddities
// we don't want Umbraco tests to die because the container has not been properly initialized,
@@ -125,7 +126,17 @@ namespace Umbraco.Core.Composing
?? new ProfilingLogger(Logger, Profiler);
public static IRuntimeState RuntimeState
- => Factory.GetInstance();
+ {
+ get
+ {
+ return _state ?? Factory.GetInstance();
+ }
+ internal set
+ {
+ // this is only used when the boot entirely fails, we need to manually set this so we can report
+ _state = value;
+ }
+ }
public static TypeLoader TypeLoader
=> Factory.GetInstance();
diff --git a/src/Umbraco.Core/Composing/WeightedCollectionBuilderBase.cs b/src/Umbraco.Core/Composing/WeightedCollectionBuilderBase.cs
index 88eb61de76..b333fa646d 100644
--- a/src/Umbraco.Core/Composing/WeightedCollectionBuilderBase.cs
+++ b/src/Umbraco.Core/Composing/WeightedCollectionBuilderBase.cs
@@ -16,6 +16,8 @@ namespace Umbraco.Core.Composing
{
protected abstract TBuilder This { get; }
+ private readonly Dictionary _customWeights = new Dictionary();
+
///
/// Clears all types in the collection.
///
@@ -107,6 +109,18 @@ namespace Umbraco.Core.Composing
return This;
}
+ ///
+ /// Changes the default weight of an item
+ ///
+ /// The type of item
+ /// The new weight
+ ///
+ public TBuilder SetWeight(int weight) where T : TItem
+ {
+ _customWeights[typeof(T)] = weight;
+ return This;
+ }
+
protected override IEnumerable GetRegisteringTypes(IEnumerable types)
{
var list = types.ToList();
@@ -118,6 +132,8 @@ namespace Umbraco.Core.Composing
protected virtual int GetWeight(Type type)
{
+ if (_customWeights.ContainsKey(type))
+ return _customWeights[type];
var attr = type.GetCustomAttributes(typeof(WeightAttribute), false).OfType().SingleOrDefault();
return attr?.Weight ?? DefaultWeight;
}
diff --git a/src/Umbraco.Core/Constants-AppSettings.cs b/src/Umbraco.Core/Constants-AppSettings.cs
index 1f096ab9f9..99ea26b4d6 100644
--- a/src/Umbraco.Core/Constants-AppSettings.cs
+++ b/src/Umbraco.Core/Constants-AppSettings.cs
@@ -109,12 +109,17 @@ namespace Umbraco.Core
/// A true or false indicating whether umbraco should force a secure (https) connection to the backoffice.
///
public const string UseHttps = "Umbraco.Core.UseHttps";
-
+
///
/// A true/false value indicating whether the content dashboard should be visible for all user groups.
///
public const string AllowContentDashboardAccessToAllUsers = "Umbraco.Core.AllowContentDashboardAccessToAllUsers";
+ ///
+ /// The path to use when constructing the URL for retrieving data for the content dashboard.
+ ///
+ public const string ContentDashboardPath = "Umbraco.Core.ContentDashboardPath";
+
///
/// TODO: FILL ME IN
///
diff --git a/src/Umbraco.Core/Constants-Conventions.cs b/src/Umbraco.Core/Constants-Conventions.cs
index c1d7103a1c..37267a5e22 100644
--- a/src/Umbraco.Core/Constants-Conventions.cs
+++ b/src/Umbraco.Core/Constants-Conventions.cs
@@ -118,6 +118,46 @@ namespace Umbraco.Core
///
public const string Image = "Image";
+ ///
+ /// MediaType name for a video.
+ ///
+ public const string Video = "Video";
+
+ ///
+ /// MediaType name for an audio.
+ ///
+ public const string Audio = "Audio";
+
+ ///
+ /// MediaType name for an article.
+ ///
+ public const string Article = "Article";
+
+ ///
+ /// MediaType name for vector graphics.
+ ///
+ public const string VectorGraphics = "VectorGraphics";
+
+ ///
+ /// MediaType alias for a video.
+ ///
+ public const string VideoAlias = "umbracoMediaVideo";
+
+ ///
+ /// MediaType alias for an audio.
+ ///
+ public const string AudioAlias = "umbracoMediaAudio";
+
+ ///
+ /// MediaType alias for an article.
+ ///
+ public const string ArticleAlias = "umbracoMediaArticle";
+
+ ///
+ /// MediaType alias for vector graphics.
+ ///
+ public const string VectorGraphicsAlias = "umbracoMediaVectorGraphics";
+
///
/// MediaType alias indicating allowing auto-selection.
///
diff --git a/src/Umbraco.Core/Constants-DataTypes.cs b/src/Umbraco.Core/Constants-DataTypes.cs
index 673da8f9a3..f1af0ba99e 100644
--- a/src/Umbraco.Core/Constants-DataTypes.cs
+++ b/src/Umbraco.Core/Constants-DataTypes.cs
@@ -25,6 +25,10 @@ namespace Umbraco.Core
public const int DropDownSingle = -39;
public const int DropDownMultiple = -42;
public const int Upload = -90;
+ public const int UploadVideo = -100;
+ public const int UploadAudio = -101;
+ public const int UploadArticle = -102;
+ public const int UploadVectorGraphics = -103;
public const int DefaultContentListView = -95;
public const int DefaultMediaListView = -96;
@@ -42,7 +46,7 @@ namespace Umbraco.Core
/// Defines the identifiers for Umbraco data types as constants for easy centralized access/management.
///
public static class Guids
- {
+ {
///
/// Guid for Content Picker as string
@@ -88,6 +92,49 @@ namespace Umbraco.Core
public static readonly Guid MultipleMediaPickerGuid = new Guid(MultipleMediaPicker);
+ ///
+ /// Guid for Media Picker v3 as string
+ ///
+ public const string MediaPicker3 = "4309A3EA-0D78-4329-A06C-C80B036AF19A";
+
+ ///
+ /// Guid for Media Picker v3
+ ///
+ public static readonly Guid MediaPicker3Guid = new Guid(MediaPicker3);
+
+ ///
+ /// Guid for Media Picker v3 multiple as string
+ ///
+ public const string MediaPicker3Multiple = "1B661F40-2242-4B44-B9CB-3990EE2B13C0";
+
+ ///
+ /// Guid for Media Picker v3 multiple
+ ///
+ public static readonly Guid MediaPicker3MultipleGuid = new Guid(MediaPicker3Multiple);
+
+
+ ///
+ /// Guid for Media Picker v3 single-image as string
+ ///
+ public const string MediaPicker3SingleImage = "AD9F0CF2-BDA2-45D5-9EA1-A63CFC873FD3";
+
+ ///
+ /// Guid for Media Picker v3 single-image
+ ///
+ public static readonly Guid MediaPicker3SingleImageGuid = new Guid(MediaPicker3SingleImage);
+
+
+ ///
+ /// Guid for Media Picker v3 multi-image as string
+ ///
+ public const string MediaPicker3MultipleImages = "0E63D883-B62B-4799-88C3-157F82E83ECC";
+
+ ///
+ /// Guid for Media Picker v3 multi-image
+ ///
+ public static readonly Guid MediaPicker3MultipleImagesGuid = new Guid(MediaPicker3MultipleImages);
+
+
///
/// Guid for Related Links as string
///
@@ -307,6 +354,46 @@ namespace Umbraco.Core
///
public static readonly Guid UploadGuid = new Guid(Upload);
+ ///
+ /// Guid for UploadVideo as string
+ ///
+ public const string UploadVideo = "70575fe7-9812-4396-bbe1-c81a76db71b5";
+
+ ///
+ /// Guid for UploadVideo
+ ///
+ public static readonly Guid UploadVideoGuid = new Guid(UploadVideo);
+
+ ///
+ /// Guid for UploadAudio as string
+ ///
+ public const string UploadAudio = "8f430dd6-4e96-447e-9dc0-cb552c8cd1f3";
+
+ ///
+ /// Guid for UploadAudio
+ ///
+ public static readonly Guid UploadAudioGuid = new Guid(UploadAudio);
+
+ ///
+ /// Guid for UploadArticle as string
+ ///
+ public const string UploadArticle = "bc1e266c-dac4-4164-bf08-8a1ec6a7143d";
+
+ ///
+ /// Guid for UploadArticle
+ ///
+ public static readonly Guid UploadArticleGuid = new Guid(UploadArticle);
+
+ ///
+ /// Guid for UploadVectorGraphics as string
+ ///
+ public const string UploadVectorGraphics = "215cb418-2153-4429-9aef-8c0f0041191b";
+
+ ///
+ /// Guid for UploadVectorGraphics
+ ///
+ public static readonly Guid UploadVectorGraphicsGuid = new Guid(UploadVectorGraphics);
+
///
/// Guid for Label as string
@@ -367,8 +454,8 @@ namespace Umbraco.Core
/// Guid for Label decimal
///
public static readonly Guid LabelDecimalGuid = new Guid(LabelDecimal);
-
-
+
+
}
}
}
diff --git a/src/Umbraco.Core/Constants-Icons.cs b/src/Umbraco.Core/Constants-Icons.cs
index d5cc37c9a5..e15c1e162b 100644
--- a/src/Umbraco.Core/Constants-Icons.cs
+++ b/src/Umbraco.Core/Constants-Icons.cs
@@ -59,6 +59,26 @@
///
public const string MediaFile = "icon-document";
+ ///
+ /// System media video icon
+ ///
+ public const string MediaVideo = "icon-video";
+
+ ///
+ /// System media audio icon
+ ///
+ public const string MediaAudio = "icon-sound-waves";
+
+ ///
+ /// System media article icon
+ ///
+ public const string MediaArticle = "icon-article";
+
+ ///
+ /// System media vector icon
+ ///
+ public const string MediaVectorGraphics = "icon-picture";
+
///
/// System media folder icon
///
@@ -93,7 +113,7 @@
/// System packages icon
///
public const string Packages = "icon-box";
-
+
///
/// System property editor icon
///
diff --git a/src/Umbraco.Core/Constants-PropertyEditors.cs b/src/Umbraco.Core/Constants-PropertyEditors.cs
index 87739469d1..f69570dc08 100644
--- a/src/Umbraco.Core/Constants-PropertyEditors.cs
+++ b/src/Umbraco.Core/Constants-PropertyEditors.cs
@@ -95,12 +95,17 @@ namespace Umbraco.Core
/// ListView.
///
public const string ListView = "Umbraco.ListView";
-
+
///
/// Media Picker.
///
public const string MediaPicker = "Umbraco.MediaPicker";
+ ///
+ /// Media Picker v.3.
+ ///
+ public const string MediaPicker3 = "Umbraco.MediaPicker3";
+
///
/// Multiple Media Picker.
///
diff --git a/src/Umbraco.Core/Constants-PropertyTypeGroups.cs b/src/Umbraco.Core/Constants-PropertyTypeGroups.cs
index d3402e69f8..20ada8c0f4 100644
--- a/src/Umbraco.Core/Constants-PropertyTypeGroups.cs
+++ b/src/Umbraco.Core/Constants-PropertyTypeGroups.cs
@@ -8,7 +8,7 @@
public static class PropertyTypeGroups
{
///
- /// Guid for a Image PropertyTypeGroup object.
+ /// Guid for an Image PropertyTypeGroup object.
///
public const string Image = "79ED4D07-254A-42CF-8FA9-EBE1C116A596";
@@ -18,7 +18,27 @@
public const string File = "50899F9C-023A-4466-B623-ABA9049885FE";
///
- /// Guid for a Image PropertyTypeGroup object.
+ /// Guid for a Video PropertyTypeGroup object.
+ ///
+ public const string Video = "2F0A61B6-CF92-4FF4-B437-751AB35EB254";
+
+ ///
+ /// Guid for an Audio PropertyTypeGroup object.
+ ///
+ public const string Audio = "335FB495-0A87-4E82-B902-30EB367B767C";
+
+ ///
+ /// Guid for an Article PropertyTypeGroup object.
+ ///
+ public const string Article = "9AF3BD65-F687-4453-9518-5F180D1898EC";
+
+ ///
+ /// Guid for a VectorGraphics PropertyTypeGroup object.
+ ///
+ public const string VectorGraphics = "F199B4D7-9E84-439F-8531-F87D9AF37711";
+
+ ///
+ /// Guid for a Membership PropertyTypeGroup object.
///
public const string Membership = "0756729D-D665-46E3-B84A-37ACEAA614F8";
}
diff --git a/src/Umbraco.Core/Constants-SqlTemplates.cs b/src/Umbraco.Core/Constants-SqlTemplates.cs
index 5a78b62f5b..8529e6bfbc 100644
--- a/src/Umbraco.Core/Constants-SqlTemplates.cs
+++ b/src/Umbraco.Core/Constants-SqlTemplates.cs
@@ -24,6 +24,20 @@
{
public const string EnsureUniqueNodeName = "Umbraco.Core.DataTypeDefinitionRepository.EnsureUniqueNodeName";
}
+
+ internal static class NuCacheDatabaseDataSource
+ {
+ public const string WhereNodeId = "Umbraco.Web.PublishedCache.NuCache.DataSource.WhereNodeId";
+ public const string WhereNodeIdX = "Umbraco.Web.PublishedCache.NuCache.DataSource.WhereNodeIdX";
+ public const string SourcesSelectUmbracoNodeJoin = "Umbraco.Web.PublishedCache.NuCache.DataSource.SourcesSelectUmbracoNodeJoin";
+ public const string ContentSourcesSelect = "Umbraco.Web.PublishedCache.NuCache.DataSource.ContentSourcesSelect";
+ public const string ContentSourcesCount = "Umbraco.Web.PublishedCache.NuCache.DataSource.ContentSourcesCount";
+ public const string MediaSourcesSelect = "Umbraco.Web.PublishedCache.NuCache.DataSource.MediaSourcesSelect";
+ public const string MediaSourcesCount = "Umbraco.Web.PublishedCache.NuCache.DataSource.MediaSourcesCount";
+ public const string ObjectTypeNotTrashedFilter = "Umbraco.Web.PublishedCache.NuCache.DataSource.ObjectTypeNotTrashedFilter";
+ public const string OrderByLevelIdSortOrder = "Umbraco.Web.PublishedCache.NuCache.DataSource.OrderByLevelIdSortOrder";
+
+ }
}
}
}
diff --git a/src/Umbraco.Core/Dashboards/ContentDashboardSettings.cs b/src/Umbraco.Core/Dashboards/ContentDashboardSettings.cs
index f8fb5c7b06..b370f93eca 100644
--- a/src/Umbraco.Core/Dashboards/ContentDashboardSettings.cs
+++ b/src/Umbraco.Core/Dashboards/ContentDashboardSettings.cs
@@ -4,6 +4,7 @@ namespace Umbraco.Core.Dashboards
{
public class ContentDashboardSettings: IContentDashboardSettings
{
+ private const string DefaultContentDashboardPath = "cms";
///
/// Gets a value indicating whether the content dashboard should be available to all users.
@@ -20,5 +21,14 @@ namespace Umbraco.Core.Dashboards
return value;
}
}
+
+ ///
+ /// Gets the path to use when constructing the URL for retrieving data for the content dashboard.
+ ///
+ /// The URL path.
+ public string ContentDashboardPath =>
+ ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.ContentDashboardPath)
+ ? ConfigurationManager.AppSettings[Constants.AppSettings.ContentDashboardPath]
+ : DefaultContentDashboardPath;
}
}
diff --git a/src/Umbraco.Core/Dashboards/IContentDashboardSettings.cs b/src/Umbraco.Core/Dashboards/IContentDashboardSettings.cs
index 862a28b90e..f5c4e3da78 100644
--- a/src/Umbraco.Core/Dashboards/IContentDashboardSettings.cs
+++ b/src/Umbraco.Core/Dashboards/IContentDashboardSettings.cs
@@ -10,5 +10,11 @@
/// and the default access rules for that dashboard will be in use.
///
bool AllowContentDashboardAccessToAllUsers { get; }
+
+ ///
+ /// Gets the path to use when constructing the URL for retrieving data for the content dashboard.
+ ///
+ /// The URL path.
+ string ContentDashboardPath { get; }
}
}
diff --git a/src/Umbraco.Core/Events/UnattendedInstallEventArgs.cs b/src/Umbraco.Core/Events/UnattendedInstallEventArgs.cs
new file mode 100644
index 0000000000..3029126dea
--- /dev/null
+++ b/src/Umbraco.Core/Events/UnattendedInstallEventArgs.cs
@@ -0,0 +1,9 @@
+namespace Umbraco.Core.Events
+{
+ ///
+ /// Used to notify that an Unattended install has completed
+ ///
+ public class UnattendedInstallEventArgs : System.ComponentModel.CancelEventArgs
+ {
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Expressions/Create/Table/CreateTableOfDtoBuilder.cs b/src/Umbraco.Core/Migrations/Expressions/Create/Table/CreateTableOfDtoBuilder.cs
index 4b73e9435d..a5e2fca1f7 100644
--- a/src/Umbraco.Core/Migrations/Expressions/Create/Table/CreateTableOfDtoBuilder.cs
+++ b/src/Umbraco.Core/Migrations/Expressions/Create/Table/CreateTableOfDtoBuilder.cs
@@ -9,6 +9,8 @@ namespace Umbraco.Core.Migrations.Expressions.Create.Table
public class CreateTableOfDtoBuilder : IExecutableBuilder
{
private readonly IMigrationContext _context;
+
+ // TODO: This doesn't do anything.
private readonly DatabaseType[] _supportedDatabaseTypes;
public CreateTableOfDtoBuilder(IMigrationContext context, params DatabaseType[] supportedDatabaseTypes)
diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs
index 44de611348..d1957f501c 100644
--- a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs
+++ b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs
@@ -107,7 +107,11 @@ namespace Umbraco.Core.Migrations.Install
InsertDataTypeNodeDto(Constants.DataTypes.LabelDateTime, 37, Constants.DataTypes.Guids.LabelDateTime, "Label (datetime)");
InsertDataTypeNodeDto(Constants.DataTypes.LabelTime, 38, Constants.DataTypes.Guids.LabelTime, "Label (time)");
InsertDataTypeNodeDto(Constants.DataTypes.LabelDecimal, 39, Constants.DataTypes.Guids.LabelDecimal, "Label (decimal)");
- _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Upload, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Upload}", SortOrder = 34, UniqueId = Constants.DataTypes.Guids.UploadGuid, Text = "Upload", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Upload, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Upload}", SortOrder = 34, UniqueId = Constants.DataTypes.Guids.UploadGuid, Text = "Upload File", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.UploadVideo, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.UploadVideo}", SortOrder = 35, UniqueId = Constants.DataTypes.Guids.UploadVideoGuid, Text = "Upload Video", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.UploadAudio, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.UploadAudio}", SortOrder = 36, UniqueId = Constants.DataTypes.Guids.UploadAudioGuid, Text = "Upload Audio", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.UploadArticle, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.UploadArticle}", SortOrder = 37, UniqueId = Constants.DataTypes.Guids.UploadArticleGuid, Text = "Upload Article", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.UploadVectorGraphics, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.UploadVectorGraphics}", SortOrder = 38, UniqueId = Constants.DataTypes.Guids.UploadVectorGraphicsGuid, Text = "Upload Vector Graphics", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Textarea, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Textarea}", SortOrder = 33, UniqueId = Constants.DataTypes.Guids.TextareaGuid, Text = "Textarea", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Textbox, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Textbox}", SortOrder = 32, UniqueId = Constants.DataTypes.Guids.TextstringGuid, Text = "Textstring", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.RichtextEditor, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.RichtextEditor}", SortOrder = 4, UniqueId = Constants.DataTypes.Guids.RichtextEditorGuid, Text = "Richtext editor", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
@@ -126,6 +130,10 @@ namespace Umbraco.Core.Migrations.Install
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1031, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1031", SortOrder = 2, UniqueId = new Guid("f38bd2d7-65d0-48e6-95dc-87ce06ec2d3d"), Text = Constants.Conventions.MediaTypes.Folder, NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1032, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1032", SortOrder = 2, UniqueId = new Guid("cc07b313-0843-4aa8-bbda-871c8da728c8"), Text = Constants.Conventions.MediaTypes.Image, NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1033, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1033", SortOrder = 2, UniqueId = new Guid("4c52d8ab-54e6-40cd-999c-7a5f24903e4d"), Text = Constants.Conventions.MediaTypes.File, NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1034, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1034", SortOrder = 2, UniqueId = new Guid("f6c515bb-653c-4bdc-821c-987729ebe327"), Text = Constants.Conventions.MediaTypes.Video, NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1035, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1035", SortOrder = 2, UniqueId = new Guid("a5ddeee0-8fd8-4cee-a658-6f1fcdb00de3"), Text = Constants.Conventions.MediaTypes.Audio, NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1036, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1036", SortOrder = 2, UniqueId = new Guid("a43e3414-9599-4230-a7d3-943a21b20122"), Text = Constants.Conventions.MediaTypes.Article, NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1037, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1037", SortOrder = 2, UniqueId = new Guid("c4b1efcf-a9d5-41c4-9621-e9d273b52a9c"), Text = "Vector Graphics (SVG)", NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Tags, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Tags}", SortOrder = 2, UniqueId = new Guid("b6b73142-b9c1-4bf8-a16d-e1c23320b549"), Text = "Tags", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.ImageCropper, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.ImageCropper}", SortOrder = 2, UniqueId = new Guid("1df9f033-e6d4-451f-b8d2-e0cbc50a836f"), Text = "Image Cropper", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1044, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1044", SortOrder = 0, UniqueId = new Guid("d59be02f-1df9-4228-aa1e-01917d806cda"), Text = Constants.Conventions.MemberTypes.DefaultAlias, NodeObjectType = Constants.ObjectTypes.MemberType, CreateDate = DateTime.Now });
@@ -133,9 +141,15 @@ namespace Umbraco.Core.Migrations.Install
//New UDI pickers with newer Ids
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1046, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1046", SortOrder = 2, UniqueId = new Guid("FD1E0DA5-5606-4862-B679-5D0CF3A52A59"), Text = "Content Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1047, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1047", SortOrder = 2, UniqueId = new Guid("1EA2E01F-EBD8-4CE1-8D71-6B1149E63548"), Text = "Member Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
- _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1048, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1048", SortOrder = 2, UniqueId = new Guid("135D60E0-64D9-49ED-AB08-893C9BA44AE5"), Text = "Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
- _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1049, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1049", SortOrder = 2, UniqueId = new Guid("9DBBCBBB-2327-434A-B355-AF1B84E5010A"), Text = "Multiple Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1048, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1048", SortOrder = 2, UniqueId = new Guid("135D60E0-64D9-49ED-AB08-893C9BA44AE5"), Text = "Media Picker (legacy)", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1049, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1049", SortOrder = 2, UniqueId = new Guid("9DBBCBBB-2327-434A-B355-AF1B84E5010A"), Text = "Multiple Media Picker (legacy)", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1050, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1050", SortOrder = 2, UniqueId = new Guid("B4E3535A-1753-47E2-8568-602CF8CFEE6F"), Text = "Multi URL Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
+
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1051, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1051", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.MediaPicker3Guid, Text = "Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1052, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1052", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.MediaPicker3MultipleGuid, Text = "Multiple Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1053, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1053", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.MediaPicker3SingleImageGuid, Text = "Image Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
+ _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1054, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1054", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.MediaPicker3MultipleImagesGuid, Text = "Multiple Image Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
+
}
private void CreateLockData()
@@ -160,6 +174,10 @@ namespace Umbraco.Core.Migrations.Install
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 532, NodeId = 1031, Alias = Constants.Conventions.MediaTypes.Folder, Icon = Constants.Icons.MediaFolder, Thumbnail = Constants.Icons.MediaFolder, IsContainer = false, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 533, NodeId = 1032, Alias = Constants.Conventions.MediaTypes.Image, Icon = Constants.Icons.MediaImage, Thumbnail = Constants.Icons.MediaImage, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 534, NodeId = 1033, Alias = Constants.Conventions.MediaTypes.File, Icon = Constants.Icons.MediaFile, Thumbnail = Constants.Icons.MediaFile, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 540, NodeId = 1034, Alias = Constants.Conventions.MediaTypes.VideoAlias, Icon = Constants.Icons.MediaVideo, Thumbnail = Constants.Icons.MediaVideo, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 541, NodeId = 1035, Alias = Constants.Conventions.MediaTypes.AudioAlias, Icon = Constants.Icons.MediaAudio, Thumbnail = Constants.Icons.MediaAudio, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 542, NodeId = 1036, Alias = Constants.Conventions.MediaTypes.ArticleAlias, Icon = Constants.Icons.MediaArticle, Thumbnail = Constants.Icons.MediaArticle, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 543, NodeId = 1037, Alias = Constants.Conventions.MediaTypes.VectorGraphicsAlias, Icon = Constants.Icons.MediaVectorGraphics, Thumbnail = Constants.Icons.MediaVectorGraphics, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 531, NodeId = 1044, Alias = Constants.Conventions.MemberTypes.DefaultAlias, Icon = Constants.Icons.Member, Thumbnail = Constants.Icons.Member, Variations = (byte) ContentVariation.Nothing });
}
@@ -207,20 +225,44 @@ namespace Umbraco.Core.Migrations.Install
{
_database.Insert(Constants.DatabaseSchema.Tables.PropertyTypeGroup, "id", false, new PropertyTypeGroupDto { Id = 3, ContentTypeNodeId = 1032, Text = "Image", SortOrder = 1, UniqueId = new Guid(Constants.PropertyTypeGroups.Image) });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyTypeGroup, "id", false, new PropertyTypeGroupDto { Id = 4, ContentTypeNodeId = 1033, Text = "File", SortOrder = 1, UniqueId = new Guid(Constants.PropertyTypeGroups.File) });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyTypeGroup, "id", false, new PropertyTypeGroupDto { Id = 52, ContentTypeNodeId = 1034, Text = "Video", SortOrder = 1, UniqueId = new Guid(Constants.PropertyTypeGroups.Video) });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyTypeGroup, "id", false, new PropertyTypeGroupDto { Id = 53, ContentTypeNodeId = 1035, Text = "Audio", SortOrder = 1, UniqueId = new Guid(Constants.PropertyTypeGroups.Audio) });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyTypeGroup, "id", false, new PropertyTypeGroupDto { Id = 54, ContentTypeNodeId = 1036, Text = "Article", SortOrder = 1, UniqueId = new Guid(Constants.PropertyTypeGroups.Article) });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyTypeGroup, "id", false, new PropertyTypeGroupDto { Id = 55, ContentTypeNodeId = 1037, Text = "Vector Graphics", SortOrder = 1, UniqueId = new Guid(Constants.PropertyTypeGroups.VectorGraphics) });
//membership property group
_database.Insert(Constants.DatabaseSchema.Tables.PropertyTypeGroup, "id", false, new PropertyTypeGroupDto { Id = 11, ContentTypeNodeId = 1044, Text = "Membership", SortOrder = 1, UniqueId = new Guid(Constants.PropertyTypeGroups.Membership) });
}
private void CreatePropertyTypeData()
{
- _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 6, UniqueId = 6.ToGuid(), DataTypeId = Constants.DataTypes.ImageCropper, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.File, Name = "Upload image", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 6, UniqueId = 6.ToGuid(), DataTypeId = Constants.DataTypes.ImageCropper, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.File, Name = "Image", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 7, UniqueId = 7.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Width, Name = "Width", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in pixels", Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 8, UniqueId = 8.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Height, Name = "Height", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in pixels", Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 9, UniqueId = 9.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in bytes", Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 10, UniqueId = 10.ToGuid(), DataTypeId = -92, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
- _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 24, UniqueId = 24.ToGuid(), DataTypeId = Constants.DataTypes.Upload, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.File, Name = "Upload file", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 24, UniqueId = 24.ToGuid(), DataTypeId = Constants.DataTypes.Upload, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.File, Name = "File", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 25, UniqueId = 25.ToGuid(), DataTypeId = -92, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 26, UniqueId = 26.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in bytes", Variations = (byte) ContentVariation.Nothing });
+
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 40, UniqueId = 40.ToGuid(), DataTypeId = Constants.DataTypes.UploadVideo, ContentTypeId = 1034, PropertyTypeGroupId = 52, Alias = Constants.Conventions.Media.File, Name = "Video", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 41, UniqueId = 41.ToGuid(), DataTypeId = -92, ContentTypeId = 1034, PropertyTypeGroupId = 52, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 42, UniqueId = 42.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1034, PropertyTypeGroupId = 52, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in bytes", Variations = (byte) ContentVariation.Nothing });
+
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 43, UniqueId = 43.ToGuid(), DataTypeId = Constants.DataTypes.UploadAudio, ContentTypeId = 1035, PropertyTypeGroupId = 53, Alias = Constants.Conventions.Media.File, Name = "Audio", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 44, UniqueId = 44.ToGuid(), DataTypeId = -92, ContentTypeId = 1035, PropertyTypeGroupId = 53, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 45, UniqueId = 45.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1035, PropertyTypeGroupId = 53, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in bytes", Variations = (byte) ContentVariation.Nothing });
+
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 46, UniqueId = 46.ToGuid(), DataTypeId = Constants.DataTypes.UploadArticle, ContentTypeId = 1036, PropertyTypeGroupId = 54, Alias = Constants.Conventions.Media.File, Name = "Article", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 47, UniqueId = 47.ToGuid(), DataTypeId = -92, ContentTypeId = 1036, PropertyTypeGroupId = 54, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 48, UniqueId = 48.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1036, PropertyTypeGroupId = 54, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in bytes", Variations = (byte) ContentVariation.Nothing });
+
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 49, UniqueId = 49.ToGuid(), DataTypeId = Constants.DataTypes.UploadVectorGraphics, ContentTypeId = 1037, PropertyTypeGroupId = 55, Alias = Constants.Conventions.Media.File, Name = "Vector Graphics", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 50, UniqueId = 50.ToGuid(), DataTypeId = -92, ContentTypeId = 1037, PropertyTypeGroupId = 55, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
+ _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 51, UniqueId = 51.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1037, PropertyTypeGroupId = 55, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in bytes", Variations = (byte) ContentVariation.Nothing });
+
+
+
+
//membership property types
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 28, UniqueId = 28.ToGuid(), DataTypeId = Constants.DataTypes.Textarea, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.Comments, Name = Constants.Conventions.Member.CommentsLabel, SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 29, UniqueId = 29.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.FailedPasswordAttempts, Name = Constants.Conventions.Member.FailedPasswordAttemptsLabel, SortOrder = 1, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
@@ -244,6 +286,10 @@ namespace Umbraco.Core.Migrations.Install
_database.Insert(Constants.DatabaseSchema.Tables.ContentChildType, "Id", false, new ContentTypeAllowedContentTypeDto { Id = 1031, AllowedId = 1031 });
_database.Insert(Constants.DatabaseSchema.Tables.ContentChildType, "Id", false, new ContentTypeAllowedContentTypeDto { Id = 1031, AllowedId = 1032 });
_database.Insert(Constants.DatabaseSchema.Tables.ContentChildType, "Id", false, new ContentTypeAllowedContentTypeDto { Id = 1031, AllowedId = 1033 });
+ _database.Insert(Constants.DatabaseSchema.Tables.ContentChildType, "Id", false, new ContentTypeAllowedContentTypeDto { Id = 1031, AllowedId = 1034 });
+ _database.Insert(Constants.DatabaseSchema.Tables.ContentChildType, "Id", false, new ContentTypeAllowedContentTypeDto { Id = 1031, AllowedId = 1035 });
+ _database.Insert(Constants.DatabaseSchema.Tables.ContentChildType, "Id", false, new ContentTypeAllowedContentTypeDto { Id = 1031, AllowedId = 1036 });
+ _database.Insert(Constants.DatabaseSchema.Tables.ContentChildType, "Id", false, new ContentTypeAllowedContentTypeDto { Id = 1031, AllowedId = 1037 });
}
private void CreateDataTypeData()
@@ -304,9 +350,65 @@ namespace Umbraco.Core.Migrations.Install
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1046, EditorAlias = Constants.PropertyEditors.Aliases.ContentPicker, DbType = "Nvarchar" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1047, EditorAlias = Constants.PropertyEditors.Aliases.MemberPicker, DbType = "Nvarchar" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1048, EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker, DbType = "Ntext" });
- _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1049, EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker, DbType = "Ntext",
- Configuration = "{\"multiPicker\":1}" });
+ _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1049, EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker, DbType = "Ntext", Configuration = "{\"multiPicker\":1}" });
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1050, EditorAlias = Constants.PropertyEditors.Aliases.MultiUrlPicker, DbType = "Ntext" });
+
+ _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto
+ {
+ NodeId = Constants.DataTypes.UploadVideo,
+ EditorAlias = Constants.PropertyEditors.Aliases.UploadField,
+ DbType = "Nvarchar",
+ Configuration = "{\"fileExtensions\":[{\"id\":0, \"value\":\"mp4\"}, {\"id\":1, \"value\":\"webm\"}, {\"id\":2, \"value\":\"ogv\"}]}"
+ });
+
+ _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto
+ {
+ NodeId = Constants.DataTypes.UploadAudio,
+ EditorAlias = Constants.PropertyEditors.Aliases.UploadField,
+ DbType = "Nvarchar",
+ Configuration = "{\"fileExtensions\":[{\"id\":0, \"value\":\"mp3\"}, {\"id\":1, \"value\":\"weba\"}, {\"id\":2, \"value\":\"oga\"}, {\"id\":3, \"value\":\"opus\"}]}"
+ });
+
+ _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto
+ {
+ NodeId = Constants.DataTypes.UploadArticle,
+ EditorAlias = Constants.PropertyEditors.Aliases.UploadField,
+ DbType = "Nvarchar",
+ Configuration = "{\"fileExtensions\":[{\"id\":0, \"value\":\"pdf\"}, {\"id\":1, \"value\":\"docx\"}, {\"id\":2, \"value\":\"doc\"}]}"
+ });
+
+ _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto
+ {
+ NodeId = Constants.DataTypes.UploadVectorGraphics,
+ EditorAlias = Constants.PropertyEditors.Aliases.UploadField,
+ DbType = "Nvarchar",
+ Configuration = "{\"fileExtensions\":[{\"id\":0, \"value\":\"svg\"}]}"
+ });
+
+ _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto {
+ NodeId = 1051,
+ EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker3,
+ DbType = "Ntext",
+ Configuration = "{\"multiple\": false, \"validationLimit\":{\"min\":0,\"max\":1}}"
+ });
+ _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto {
+ NodeId = 1052,
+ EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker3,
+ DbType = "Ntext",
+ Configuration = "{\"multiple\": true}"
+ });
+ _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto {
+ NodeId = 1053,
+ EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker3,
+ DbType = "Ntext",
+ Configuration = "{\"filter\":\"" + Constants.Conventions.MediaTypes.Image + "\", \"multiple\": false, \"validationLimit\":{\"min\":0,\"max\":1}}"
+ });
+ _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto {
+ NodeId = 1054,
+ EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker3,
+ DbType = "Ntext",
+ Configuration = "{\"filter\":\"" + Constants.Conventions.MediaTypes.Image + "\", \"multiple\": true}"
+ });
}
private void CreateRelationTypeData()
diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs
index 3f9e511ec4..d9a71a1cc2 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs
@@ -9,6 +9,7 @@ using Umbraco.Core.Migrations.Upgrade.V_8_1_0;
using Umbraco.Core.Migrations.Upgrade.V_8_6_0;
using Umbraco.Core.Migrations.Upgrade.V_8_9_0;
using Umbraco.Core.Migrations.Upgrade.V_8_10_0;
+using Umbraco.Core.Migrations.Upgrade.V_8_15_0;
namespace Umbraco.Core.Migrations.Upgrade
{
@@ -198,10 +199,14 @@ namespace Umbraco.Core.Migrations.Upgrade
// to 8.9.0
To("{B5838FF5-1D22-4F6C-BCEB-F83ACB14B575}");
-
+
// to 8.10.0
To("{D6A8D863-38EC-44FB-91EC-ACD6A668BD18}");
+ // to 8.15.0...
+ To("{8DDDCD0B-D7D5-4C97-BD6A-6B38CA65752F}");
+ To("{4695D0C9-0729-4976-985B-048D503665D8}");
+
//FINAL
}
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_15_0/AddCmsContentNuByteColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_15_0/AddCmsContentNuByteColumn.cs
new file mode 100644
index 0000000000..5217fc9870
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_15_0/AddCmsContentNuByteColumn.cs
@@ -0,0 +1,63 @@
+using NPoco;
+using System.Data;
+using System.Linq;
+using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.Dtos;
+using Umbraco.Core.PropertyEditors;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_15_0
+{
+ public class AddCmsContentNuByteColumn : MigrationBase
+ {
+ public AddCmsContentNuByteColumn(IMigrationContext context)
+ : base(context)
+ {
+
+ }
+
+ public override void Migrate()
+ {
+ // allow null for the `data` field
+ if (DatabaseType.IsSqlCe())
+ {
+ // SQLCE does not support altering NTEXT, so we have to jump through some hoops to do it
+ // All column ordering must remain the same as what is defined in the DTO so we need to create a temp table,
+ // drop orig and then re-create/copy.
+ Create.Table(withoutKeysAndIndexes: true).Do();
+ Execute.Sql($"INSERT INTO [{TempTableName}] SELECT nodeId, published, data, rv FROM [{Constants.DatabaseSchema.Tables.NodeData}]").Do();
+ Delete.Table(Constants.DatabaseSchema.Tables.NodeData).Do();
+ Create.Table().Do();
+ Execute.Sql($"INSERT INTO [{Constants.DatabaseSchema.Tables.NodeData}] SELECT nodeId, published, data, rv, NULL FROM [{TempTableName}]").Do();
+ }
+ else
+ {
+ AlterColumn(Constants.DatabaseSchema.Tables.NodeData, "data");
+ }
+
+ var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToList();
+ AddColumnIfNotExists(columns, "dataRaw");
+ }
+
+ private const string TempTableName = Constants.DatabaseSchema.TableNamePrefix + "cms" + "ContentNuTEMP";
+
+ [TableName(TempTableName)]
+ [ExplicitColumns]
+ private class ContentNuDtoTemp
+ {
+ [Column("nodeId")]
+ public int NodeId { get; set; }
+
+ [Column("published")]
+ public bool Published { get; set; }
+
+ [Column("data")]
+ [SpecialDbType(SpecialDbTypes.NTEXT)]
+ [NullSetting(NullSetting = NullSettings.Null)]
+ public string Data { get; set; }
+
+ [Column("rv")]
+ public long Rv { get; set; }
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_15_0/UpgradedIncludeIndexes.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_15_0/UpgradedIncludeIndexes.cs
new file mode 100644
index 0000000000..d51f99fb44
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_15_0/UpgradedIncludeIndexes.cs
@@ -0,0 +1,65 @@
+using System.Linq;
+using Umbraco.Core.Migrations.Expressions.Execute.Expressions;
+using Umbraco.Core.Persistence.DatabaseModelDefinitions;
+using Umbraco.Core.Persistence.Dtos;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_15_0
+{
+ public class UpgradedIncludeIndexes : MigrationBase
+ {
+ public UpgradedIncludeIndexes(IMigrationContext context)
+ : base(context)
+ {
+
+ }
+
+ public override void Migrate()
+ {
+ // Need to drop the FK for the redirect table before modifying the unique id index
+ Delete.ForeignKey()
+ .FromTable(Constants.DatabaseSchema.Tables.RedirectUrl)
+ .ForeignColumn("contentKey")
+ .ToTable(NodeDto.TableName)
+ .PrimaryColumn("uniqueID")
+ .Do();
+ var nodeDtoIndexes = new[] { $"IX_{NodeDto.TableName}_UniqueId", $"IX_{NodeDto.TableName}_ObjectType", $"IX_{NodeDto.TableName}_Level" };
+ DeleteIndexes(nodeDtoIndexes); // delete existing ones
+ CreateIndexes(nodeDtoIndexes); // update/add
+ // Now re-create the FK for the redirect table
+ Create.ForeignKey()
+ .FromTable(Constants.DatabaseSchema.Tables.RedirectUrl)
+ .ForeignColumn("contentKey")
+ .ToTable(NodeDto.TableName)
+ .PrimaryColumn("uniqueID")
+ .Do();
+
+
+ var contentVersionIndexes = new[] { $"IX_{ContentVersionDto.TableName}_NodeId", $"IX_{ContentVersionDto.TableName}_Current" };
+ DeleteIndexes(contentVersionIndexes); // delete existing ones
+ CreateIndexes(contentVersionIndexes); // update/add
+ }
+
+ private void DeleteIndexes(params string[] toDelete)
+ {
+ var tableDef = DefinitionFactory.GetTableDefinition(typeof(T), Context.SqlContext.SqlSyntax);
+
+ foreach (var i in toDelete)
+ if (IndexExists(i))
+ Delete.Index(i).OnTable(tableDef.Name).Do();
+
+ }
+
+ private void CreateIndexes(params string[] toCreate)
+ {
+ var tableDef = DefinitionFactory.GetTableDefinition(typeof(T), Context.SqlContext.SqlSyntax);
+
+ foreach (var c in toCreate)
+ {
+ // get the definition by name
+ var index = tableDef.Indexes.First(x => x.Name == c);
+ new ExecuteSqlStatementExpression(Context) { SqlStatement = Context.SqlContext.SqlSyntax.Format(index) }.Execute();
+ }
+
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Models/DataTypeExtensions.cs b/src/Umbraco.Core/Models/DataTypeExtensions.cs
index f460edbde7..913aa4773e 100644
--- a/src/Umbraco.Core/Models/DataTypeExtensions.cs
+++ b/src/Umbraco.Core/Models/DataTypeExtensions.cs
@@ -62,6 +62,10 @@ namespace Umbraco.Core.Models
Constants.DataTypes.Guids.TextstringGuid,
Constants.DataTypes.Guids.TextareaGuid,
Constants.DataTypes.Guids.UploadGuid,
+ Constants.DataTypes.Guids.UploadArticleGuid,
+ Constants.DataTypes.Guids.UploadAudioGuid,
+ Constants.DataTypes.Guids.UploadVectorGraphicsGuid,
+ Constants.DataTypes.Guids.UploadVideoGuid,
Constants.DataTypes.Guids.LabelStringGuid,
Constants.DataTypes.Guids.LabelDecimalGuid,
Constants.DataTypes.Guids.LabelDateTimeGuid,
diff --git a/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs b/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs
index a1f4bad9a1..65aafafbcd 100644
--- a/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs
+++ b/src/Umbraco.Core/Models/Entities/BeingDirtyBase.cs
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Models.Entities
///
public virtual bool IsPropertyDirty(string propertyName)
{
- return _currentChanges != null && _currentChanges.Any(x => x.Key == propertyName);
+ return _currentChanges != null && _currentChanges.ContainsKey(propertyName);
}
///
@@ -61,7 +61,7 @@ namespace Umbraco.Core.Models.Entities
///
public virtual bool WasPropertyDirty(string propertyName)
{
- return _savedChanges != null && _savedChanges.Any(x => x.Key == propertyName);
+ return _savedChanges != null && _savedChanges.ContainsKey(propertyName);
}
///
diff --git a/src/Umbraco.Core/Models/IContentBase.cs b/src/Umbraco.Core/Models/IContentBase.cs
index 0f660181fb..f4fae44ffc 100644
--- a/src/Umbraco.Core/Models/IContentBase.cs
+++ b/src/Umbraco.Core/Models/IContentBase.cs
@@ -4,6 +4,7 @@ using Umbraco.Core.Models.Entities;
namespace Umbraco.Core.Models
{
+
///
/// Provides a base class for content items.
///
diff --git a/src/Umbraco.Core/Models/IReadOnlyContentBase.cs b/src/Umbraco.Core/Models/IReadOnlyContentBase.cs
new file mode 100644
index 0000000000..3ed39b63ab
--- /dev/null
+++ b/src/Umbraco.Core/Models/IReadOnlyContentBase.cs
@@ -0,0 +1,72 @@
+using System;
+
+namespace Umbraco.Core.Models
+{
+ public interface IReadOnlyContentBase
+ {
+ ///
+ /// Gets the integer identifier of the entity.
+ ///
+ int Id { get; }
+
+ ///
+ /// Gets the Guid unique identifier of the entity.
+ ///
+ Guid Key { get; }
+
+ ///
+ /// Gets the creation date.
+ ///
+ DateTime CreateDate { get; }
+
+ ///
+ /// Gets the last update date.
+ ///
+ DateTime UpdateDate { get; }
+
+ ///
+ /// Gets the name of the entity.
+ ///
+ string Name { get; }
+
+ ///
+ /// Gets the identifier of the user who created this entity.
+ ///
+ int CreatorId { get; }
+
+ ///
+ /// Gets the identifier of the parent entity.
+ ///
+ int ParentId { get; }
+
+ ///
+ /// Gets the level of the entity.
+ ///
+ int Level { get; }
+
+ ///
+ /// Gets the path to the entity.
+ ///
+ string Path { get; }
+
+ ///
+ /// Gets the sort order of the entity.
+ ///
+ int SortOrder { get; }
+
+ ///
+ /// Gets the content type id
+ ///
+ int ContentTypeId { get; }
+
+ ///
+ /// Gets the identifier of the writer.
+ ///
+ int WriterId { get; }
+
+ ///
+ /// Gets the version identifier.
+ ///
+ int VersionId { get; }
+ }
+}
diff --git a/src/Umbraco.Core/Models/MediaWithCrops.cs b/src/Umbraco.Core/Models/MediaWithCrops.cs
new file mode 100644
index 0000000000..fefb4e6b80
--- /dev/null
+++ b/src/Umbraco.Core/Models/MediaWithCrops.cs
@@ -0,0 +1,86 @@
+using System;
+using Umbraco.Core.Models.PublishedContent;
+using Umbraco.Core.PropertyEditors.ValueConverters;
+
+namespace Umbraco.Core.Models
+{
+ ///
+ /// Represents a media item with local crops.
+ ///
+ ///
+ public class MediaWithCrops : PublishedContentWrapped
+ {
+ ///
+ /// Gets the media item.
+ ///
+ ///
+ /// The media item.
+ ///
+ [Obsolete("This instance now implements IPublishedContent by wrapping the media item, use the extension methods directly on MediaWithCrops or use the Content property to get the media item instead.")]
+ public IPublishedContent MediaItem => Content;
+
+ ///
+ /// Gets the content/media item.
+ ///
+ ///
+ /// The content/media item.
+ ///
+ public IPublishedContent Content => Unwrap();
+
+ ///
+ /// Gets the local crops.
+ ///
+ ///
+ /// The local crops.
+ ///
+ public ImageCropperValue LocalCrops { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The content.
+ /// The local crops.
+ public MediaWithCrops(IPublishedContent content, ImageCropperValue localCrops)
+ : base(content)
+ {
+ LocalCrops = localCrops;
+ }
+ }
+
+ ///
+ /// Represents a media item with local crops.
+ ///
+ /// The type of the media item.
+ ///
+ public class MediaWithCrops : MediaWithCrops
+ where T : IPublishedContent
+ {
+ ///
+ /// Gets the media item.
+ ///
+ ///
+ /// The media item.
+ ///
+ public new T Content { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The content.
+ /// The local crops.
+ public MediaWithCrops(T content, ImageCropperValue localCrops)
+ : base(content, localCrops)
+ {
+ Content = content;
+ }
+
+ ///
+ /// Performs an implicit conversion from to .
+ ///
+ /// The media with crops.
+ ///
+ /// The result of the conversion.
+ ///
+ public static implicit operator T(MediaWithCrops mediaWithCrops) => mediaWithCrops.Content;
+ }
+}
diff --git a/src/Umbraco.Core/Models/PublishedContent/Fallback.cs b/src/Umbraco.Core/Models/PublishedContent/Fallback.cs
index 0434218555..805f14d21b 100644
--- a/src/Umbraco.Core/Models/PublishedContent/Fallback.cs
+++ b/src/Umbraco.Core/Models/PublishedContent/Fallback.cs
@@ -71,5 +71,11 @@ namespace Umbraco.Core.Models.PublishedContent
{
return GetEnumerator();
}
+
+ public const int DisplayFallbackLanguage = 4;
+ ///
+ /// Gets the fallback to tree ancestors policy.
+ ///
+ public static Fallback ToDisplayFallbackLanguage => new Fallback(new[] { DisplayFallbackLanguage });
}
}
diff --git a/src/Umbraco.Core/Models/ReadOnlyContentBaseAdapter.cs b/src/Umbraco.Core/Models/ReadOnlyContentBaseAdapter.cs
new file mode 100644
index 0000000000..f707d2ab1c
--- /dev/null
+++ b/src/Umbraco.Core/Models/ReadOnlyContentBaseAdapter.cs
@@ -0,0 +1,42 @@
+using System;
+
+namespace Umbraco.Core.Models
+{
+ internal struct ReadOnlyContentBaseAdapter : IReadOnlyContentBase
+ {
+ private readonly IContentBase _content;
+
+ private ReadOnlyContentBaseAdapter(IContentBase content)
+ {
+ _content = content ?? throw new ArgumentNullException(nameof(content));
+ }
+
+ public static ReadOnlyContentBaseAdapter Create(IContentBase content) => new ReadOnlyContentBaseAdapter(content);
+
+ public int Id => _content.Id;
+
+ public Guid Key => _content.Key;
+
+ public DateTime CreateDate => _content.CreateDate;
+
+ public DateTime UpdateDate => _content.UpdateDate;
+
+ public string Name => _content.Name;
+
+ public int CreatorId => _content.CreatorId;
+
+ public int ParentId => _content.ParentId;
+
+ public int Level => _content.Level;
+
+ public string Path => _content.Path;
+
+ public int SortOrder => _content.SortOrder;
+
+ public int ContentTypeId => _content.ContentTypeId;
+
+ public int WriterId => _content.WriterId;
+
+ public int VersionId => _content.VersionId;
+ }
+}
diff --git a/src/Umbraco.Core/Persistence/DatabaseAnnotations/IndexAttribute.cs b/src/Umbraco.Core/Persistence/DatabaseAnnotations/IndexAttribute.cs
index 138dceff09..5aaabbfa6f 100644
--- a/src/Umbraco.Core/Persistence/DatabaseAnnotations/IndexAttribute.cs
+++ b/src/Umbraco.Core/Persistence/DatabaseAnnotations/IndexAttribute.cs
@@ -31,5 +31,10 @@ namespace Umbraco.Core.Persistence.DatabaseAnnotations
/// Gets or sets the column name(s) for the current index
///
public string ForColumns { get; set; }
+
+ ///
+ /// Gets or sets the column name(s) for the columns to include in the index
+ ///
+ public string IncludeColumns { get; set; }
}
}
diff --git a/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs b/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs
index fc3713a3a4..e6f06e4200 100644
--- a/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs
+++ b/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs
@@ -166,6 +166,14 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
definition.Columns.Add(new IndexColumnDefinition {Name = column, Direction = Direction.Ascending});
}
}
+ if (string.IsNullOrEmpty(attribute.IncludeColumns) == false)
+ {
+ var columns = attribute.IncludeColumns.Split(',').Select(p => p.Trim());
+ foreach (var column in columns)
+ {
+ definition.IncludeColumns.Add(new IndexColumnDefinition { Name = column, Direction = Direction.Ascending });
+ }
+ }
return definition;
}
}
diff --git a/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/IndexDefinition.cs b/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/IndexDefinition.cs
index 582f9a40f7..20f75d38c8 100644
--- a/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/IndexDefinition.cs
+++ b/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/IndexDefinition.cs
@@ -6,17 +6,13 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
{
public class IndexDefinition
{
- public IndexDefinition()
- {
- Columns = new List();
- }
-
public virtual string Name { get; set; }
public virtual string SchemaName { get; set; }
public virtual string TableName { get; set; }
public virtual string ColumnName { get; set; }
- public virtual ICollection Columns { get; set; }
+ public virtual ICollection Columns { get; set; } = new List();
+ public virtual ICollection IncludeColumns { get; set; } = new List();
public IndexTypes IndexType { get; set; }
}
}
diff --git a/src/Umbraco.Core/Persistence/Dtos/ContentNuDto.cs b/src/Umbraco.Core/Persistence/Dtos/ContentNuDto.cs
index c6269d5317..a2f36584e0 100644
--- a/src/Umbraco.Core/Persistence/Dtos/ContentNuDto.cs
+++ b/src/Umbraco.Core/Persistence/Dtos/ContentNuDto.cs
@@ -25,9 +25,16 @@ namespace Umbraco.Core.Persistence.Dtos
///
[Column("data")]
[SpecialDbType(SpecialDbTypes.NTEXT)]
+ [NullSetting(NullSetting = NullSettings.Null)]
public string Data { get; set; }
[Column("rv")]
public long Rv { get; set; }
+
+ [Column("dataRaw")]
+ [NullSetting(NullSetting = NullSettings.Null)]
+ public byte[] RawData { get; set; }
+
+
}
}
diff --git a/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs b/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs
index e7a14a26e2..68036dab4b 100644
--- a/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs
+++ b/src/Umbraco.Core/Persistence/Dtos/ContentTypeDto.cs
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Persistence.Dtos
public const string TableName = Constants.DatabaseSchema.Tables.ContentType;
[Column("pk")]
- [PrimaryKeyColumn(IdentitySeed = 535)]
+ [PrimaryKeyColumn(IdentitySeed = 700)]
public int PrimaryKey { get; set; }
[Column("nodeId")]
diff --git a/src/Umbraco.Core/Persistence/Dtos/ContentVersionDto.cs b/src/Umbraco.Core/Persistence/Dtos/ContentVersionDto.cs
index 4b203c128f..f9bf283be9 100644
--- a/src/Umbraco.Core/Persistence/Dtos/ContentVersionDto.cs
+++ b/src/Umbraco.Core/Persistence/Dtos/ContentVersionDto.cs
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Persistence.Dtos
[Column("nodeId")]
[ForeignKey(typeof(ContentDto))]
- [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_NodeId", ForColumns = "nodeId,current")]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_NodeId", ForColumns = "nodeId,current", IncludeColumns = "id,versionDate,text,userId")]
public int NodeId { get; set; }
[Column("versionDate")] // TODO: db rename to 'updateDate'
@@ -32,6 +32,7 @@ namespace Umbraco.Core.Persistence.Dtos
public int? UserId { get => _userId == 0 ? null : _userId; set => _userId = value; } //return null if zero
[Column("current")]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_Current", IncludeColumns = "nodeId")]
public bool Current { get; set; }
// about current:
diff --git a/src/Umbraco.Core/Persistence/Dtos/NodeDto.cs b/src/Umbraco.Core/Persistence/Dtos/NodeDto.cs
index 5800efb97a..207195e594 100644
--- a/src/Umbraco.Core/Persistence/Dtos/NodeDto.cs
+++ b/src/Umbraco.Core/Persistence/Dtos/NodeDto.cs
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Persistence.Dtos
[Column("uniqueId")]
[NullSetting(NullSetting = NullSettings.NotNull)]
- [Index(IndexTypes.UniqueNonClustered, Name = "IX_" + TableName + "_UniqueId")]
+ [Index(IndexTypes.UniqueNonClustered, Name = "IX_" + TableName + "_UniqueId", IncludeColumns = "parentId,level,path,sortOrder,trashed,nodeUser,text,createDate")]
[Constraint(Default = SystemMethods.NewGuid)]
public Guid UniqueId { get; set; }
@@ -29,7 +29,9 @@ namespace Umbraco.Core.Persistence.Dtos
[Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_ParentId")]
public int ParentId { get; set; }
+ // NOTE: This index is primarily for the nucache data lookup, see https://github.com/umbraco/Umbraco-CMS/pull/8365#issuecomment-673404177
[Column("level")]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_Level", ForColumns = "level,parentId,sortOrder,nodeObjectType,trashed", IncludeColumns = "nodeUser,path,uniqueId,createDate")]
public short Level { get; set; }
[Column("path")]
@@ -55,8 +57,8 @@ namespace Umbraco.Core.Persistence.Dtos
public string Text { get; set; }
[Column("nodeObjectType")] // TODO: db rename to 'objectType'
- [NullSetting(NullSetting = NullSettings.Null)]
- [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_ObjectType")]
+ [NullSetting(NullSetting = NullSettings.Null)]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_ObjectType", ForColumns = "nodeObjectType,trashed", IncludeColumns = "uniqueId,parentId,level,path,sortOrder,nodeUser,text,createDate")]
public Guid? NodeObjectType { get; set; }
[Column("createDate")]
diff --git a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs
index 572201c94a..f22e4453f4 100644
--- a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs
+++ b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Persistence.Dtos
internal class PropertyTypeDto
{
[Column("id")]
- [PrimaryKeyColumn(IdentitySeed = 50)]
+ [PrimaryKeyColumn(IdentitySeed = 100)]
public int Id { get; set; }
[Column("dataTypeId")]
diff --git a/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions-Bulk.cs b/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions-Bulk.cs
index 10db1ca18e..77cc0d6601 100644
--- a/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions-Bulk.cs
+++ b/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions-Bulk.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlServerCe;
+using System.Data.SqlTypes;
using System.Linq;
using NPoco;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -61,26 +62,33 @@ namespace Umbraco.Core.Persistence
/// The number of records that were inserted.
public static int BulkInsertRecords(this IUmbracoDatabase database, IEnumerable records, bool useNativeBulkInsert = true)
{
- var recordsA = records.ToArray();
- if (recordsA.Length == 0) return 0;
+ if (!records.Any()) return 0;
var pocoData = database.PocoDataFactory.ForType(typeof(T));
if (pocoData == null) throw new InvalidOperationException("Could not find PocoData for " + typeof(T));
if (database.DatabaseType.IsSqlCe())
{
- if (useNativeBulkInsert) return BulkInsertRecordsSqlCe(database, pocoData, recordsA);
+ if (useNativeBulkInsert)
+ {
+ return BulkInsertRecordsSqlCe(database, pocoData, records);
+ }
+
// else, no other choice
- foreach (var record in recordsA)
+ var count = 0;
+ foreach (var record in records)
+ {
database.Insert(record);
- return recordsA.Length;
+ count++;
+ }
+ return count;
}
if (database.DatabaseType.IsSqlServer())
{
return useNativeBulkInsert && database.DatabaseType.IsSqlServer2008OrLater()
- ? BulkInsertRecordsSqlServer(database, pocoData, recordsA)
- : BulkInsertRecordsWithCommands(database, recordsA);
+ ? BulkInsertRecordsSqlServer(database, pocoData, records)
+ : BulkInsertRecordsWithCommands(database, records.ToArray());
}
throw new NotSupportedException();
}
@@ -95,7 +103,9 @@ namespace Umbraco.Core.Persistence
private static int BulkInsertRecordsWithCommands(IUmbracoDatabase database, T[] records)
{
foreach (var command in database.GenerateBulkInsertCommands(records))
+ {
command.ExecuteNonQuery();
+ }
return records.Length; // what else?
}
@@ -210,7 +220,15 @@ namespace Umbraco.Core.Persistence
if (IncludeColumn(pocoData, columns[i]))
{
var val = columns[i].Value.GetValue(record);
- updatableRecord.SetValue(i, val);
+ if (val is byte[])
+ {
+ var bytes = val as byte[];
+ updatableRecord.SetSqlBinary(i, new SqlBinary(bytes));
+ }
+ else
+ {
+ updatableRecord.SetValue(i, val);
+ }
}
}
resultSet.Insert(updatableRecord);
@@ -232,6 +250,10 @@ namespace Umbraco.Core.Persistence
/// The number of records that were inserted.
internal static int BulkInsertRecordsSqlServer(IUmbracoDatabase database, PocoData pocoData, IEnumerable records)
{
+ // TODO: The main reason this exists is because the NPoco InsertBulk method doesn't return the number of items.
+ // It is worth investigating the performance of this vs NPoco's because we use a custom BulkDataReader
+ // which in theory should be more efficient than NPocos way of building up an in-memory DataTable.
+
// create command against the original database.Connection
using (var command = database.CreateCommand(database.Connection, CommandType.Text, string.Empty))
{
@@ -243,7 +265,13 @@ namespace Umbraco.Core.Persistence
var syntax = database.SqlContext.SqlSyntax as SqlServerSyntaxProvider;
if (syntax == null) throw new NotSupportedException("SqlSyntax must be SqlServerSyntaxProvider.");
- using (var copy = new SqlBulkCopy(tConnection, SqlBulkCopyOptions.Default, tTransaction) { BulkCopyTimeout = 10000, DestinationTableName = tableName })
+ using (var copy = new SqlBulkCopy(tConnection, SqlBulkCopyOptions.Default, tTransaction)
+ {
+ BulkCopyTimeout = 0, // 0 = no bulk copy timeout. If a timeout occurs it will be an connection/command timeout.
+ DestinationTableName = tableName,
+ // be consistent with NPoco: https://github.com/schotime/NPoco/blob/5117a55fde57547e928246c044fd40bd00b2d7d1/src/NPoco.SqlServer/SqlBulkCopyHelper.cs#L50
+ BatchSize = 4096
+ })
using (var bulkReader = new PocoDataDataReader(records, pocoData, syntax))
{
//we need to add column mappings here because otherwise columns will be matched by their order and if the order of them are different in the DB compared
diff --git a/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions.cs b/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions.cs
index 152dcbe6d3..c2100d97ad 100644
--- a/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions.cs
+++ b/src/Umbraco.Core/Persistence/NPocoDatabaseExtensions.cs
@@ -27,12 +27,13 @@ namespace Umbraco.Core.Persistence
/// The number of rows to load per page
///
///
+ /// Specify a custom Sql command to get the total count, if null is specified than the auto-generated sql count will be used
///
///
/// NPoco's normal Page returns a List{T} but sometimes we don't want all that in memory and instead want to
/// iterate over each row with a reader using Query vs Fetch.
///
- internal static IEnumerable QueryPaged(this IDatabase database, long pageSize, Sql sql)
+ internal static IEnumerable QueryPaged(this IDatabase database, long pageSize, Sql sql, Sql sqlCount)
{
var sqlString = sql.SQL;
var sqlArgs = sql.Arguments;
@@ -42,12 +43,12 @@ namespace Umbraco.Core.Persistence
do
{
// Get the paged queries
- database.BuildPageQueries(pageIndex * pageSize, pageSize, sqlString, ref sqlArgs, out var sqlCount, out var sqlPage);
+ database.BuildPageQueries(pageIndex * pageSize, pageSize, sqlString, ref sqlArgs, out var generatedSqlCount, out var sqlPage);
// get the item count once
if (itemCount == null)
{
- itemCount = database.ExecuteScalar(sqlCount, sqlArgs);
+ itemCount = database.ExecuteScalar(sqlCount?.SQL ?? generatedSqlCount, sqlCount?.Arguments ?? sqlArgs);
}
pageIndex++;
@@ -60,6 +61,22 @@ namespace Umbraco.Core.Persistence
} while ((pageIndex * pageSize) < itemCount);
}
+ ///
+ /// Iterates over the result of a paged data set with a db reader
+ ///
+ ///
+ ///
+ ///
+ /// The number of rows to load per page
+ ///
+ ///
+ ///
+ ///
+ /// NPoco's normal Page returns a List{T} but sometimes we don't want all that in memory and instead want to
+ /// iterate over each row with a reader using Query vs Fetch.
+ ///
+ internal static IEnumerable QueryPaged(this IDatabase database, long pageSize, Sql sql) => database.QueryPaged(pageSize, sql, null);
+
// NOTE
//
// proper way to do it with TSQL and SQLCE
diff --git a/src/Umbraco.Core/Persistence/PocoDataDataReader.cs b/src/Umbraco.Core/Persistence/PocoDataDataReader.cs
index 460a4d3d90..397d903cc2 100644
--- a/src/Umbraco.Core/Persistence/PocoDataDataReader.cs
+++ b/src/Umbraco.Core/Persistence/PocoDataDataReader.cs
@@ -40,9 +40,10 @@ namespace Umbraco.Core.Persistence
_tableDefinition = DefinitionFactory.GetTableDefinition(pd.Type, sqlSyntaxProvider);
if (_tableDefinition == null) throw new InvalidOperationException("No table definition found for type " + pd.Type);
- // only real columns, exclude result columns
+ // only real columns, exclude result/computed columns
+ // Like NPoco does: https://github.com/schotime/NPoco/blob/5117a55fde57547e928246c044fd40bd00b2d7d1/src/NPoco.SqlServer/SqlBulkCopyHelper.cs#L59
_readerColumns = pd.Columns
- .Where(x => x.Value.ResultColumn == false)
+ .Where(x => x.Value.ResultColumn == false && x.Value.ComputedColumn == false)
.Select(x => x.Value)
.ToArray();
diff --git a/src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs b/src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs
index f8acbdfade..388286a79b 100644
--- a/src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs
+++ b/src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs
@@ -328,8 +328,11 @@ namespace Umbraco.Core.Persistence.Querying
{
case ExpressionType.MemberAccess:
// false property , i.e. x => !Trashed
- SqlParameters.Add(true);
- return Visited ? string.Empty : $"NOT ({o} = @{SqlParameters.Count - 1})";
+ // BUT we don't want to do a NOT SQL statement since this generally results in indexes not being used
+ // so we want to do an == false
+ SqlParameters.Add(false);
+ return Visited ? string.Empty : $"{o} = @{SqlParameters.Count - 1}";
+ //return Visited ? string.Empty : $"NOT ({o} = @{SqlParameters.Count - 1})";
default:
// could be anything else, such as: x => !x.Path.StartsWith("-20")
return Visited ? string.Empty : string.Concat("NOT (", o, ")");
diff --git a/src/Umbraco.Core/Persistence/Repositories/IDocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IDocumentRepository.cs
index 0971b2047a..6746d6a429 100644
--- a/src/Umbraco.Core/Persistence/Repositories/IDocumentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/IDocumentRepository.cs
@@ -73,5 +73,10 @@ namespace Umbraco.Core.Persistence.Repositories
///
///
void AddOrUpdatePermissions(ContentPermissionSet permission);
+
+ ///
+ /// Returns true if there is any content in the recycle bin
+ ///
+ bool RecycleBinSmells();
}
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/IMediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IMediaRepository.cs
index d4ec08a0df..6f36102a40 100644
--- a/src/Umbraco.Core/Persistence/Repositories/IMediaRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/IMediaRepository.cs
@@ -6,5 +6,6 @@ namespace Umbraco.Core.Persistence.Repositories
public interface IMediaRepository : IContentRepository, IReadRepository
{
IMedia GetMediaByPath(string mediaPath);
+ bool RecycleBinSmells();
}
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ConsentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ConsentRepository.cs
index 57d5dfa864..d73b360677 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/ConsentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ConsentRepository.cs
@@ -86,7 +86,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
Database.Update(dto);
entity.ResetDirtyProperties();
- IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.Id));
+ IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.Id));
}
///
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs
index ddac0ee3d6..85814ef681 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs
@@ -630,6 +630,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
}
if (versions.Count == 0) return new Dictionary();
+ // TODO: This is a bugger of a query and I believe is the main issue with regards to SQL performance drain when querying content
+ // which is done when rebuilding caches/indexes/etc... in bulk. We are using an "IN" query on umbracoPropertyData.VersionId
+ // which then performs a Clustered Index Scan on PK_umbracoPropertyData which means it iterates the entire table which can be enormous!
+ // especially if there are both a lot of content but worse if there is a lot of versions of that content.
+ // So is it possible to return this property data without doing an index scan on PK_umbracoPropertyData and without iterating every row
+ // in the table?
+
// get all PropertyDataDto for all definitions / versions
var allPropertyDataDtos = Database.FetchByGroups(versions, 2000, batch =>
SqlContext.Sql()
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs
index 0b58663952..0e3521f8bc 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs
@@ -130,7 +130,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
foreach (var translation in dictionaryItem.Translations)
translation.Value = translation.Value.ToValidXmlString();
-
+
var dto = DictionaryItemFactory.BuildDto(dictionaryItem);
var id = Convert.ToInt32(Database.Insert(dto));
@@ -152,7 +152,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
foreach (var translation in entity.Translations)
translation.Value = translation.Value.ToValidXmlString();
-
+
var dto = DictionaryItemFactory.BuildDto(entity);
Database.Update(dto);
@@ -174,8 +174,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
entity.ResetDirtyProperties();
//Clear the cache entries that exist by uniqueid/item key
- IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.ItemKey));
- IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.Key));
+ IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.ItemKey));
+ IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.Key));
}
protected override void PersistDeletedItem(IDictionaryItem entity)
@@ -186,8 +186,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
Database.Delete("WHERE id = @Id", new { Id = entity.Key });
//Clear the cache entries that exist by uniqueid/item key
- IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.ItemKey));
- IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.Key));
+ IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.ItemKey));
+ IsolatedCache.Clear(RepositoryCacheKeys.GetKey(entity.Key));
entity.DeleteDate = DateTime.Now;
}
@@ -203,8 +203,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
Database.Delete("WHERE id = @Id", new { Id = dto.UniqueId });
//Clear the cache entries that exist by uniqueid/item key
- IsolatedCache.Clear(RepositoryCacheKeys.GetKey(dto.Key));
- IsolatedCache.Clear(RepositoryCacheKeys.GetKey(dto.UniqueId));
+ IsolatedCache.Clear(RepositoryCacheKeys.GetKey(dto.Key));
+ IsolatedCache.Clear(RepositoryCacheKeys.GetKey(dto.UniqueId));
}
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs
index 09d41a49a0..f5d993070c 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs
@@ -912,6 +912,15 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
public override int RecycleBinId => Constants.System.RecycleBinContent;
+ public bool RecycleBinSmells()
+ {
+ var cache = _appCaches.RuntimeCache;
+ var cacheKey = CacheKeys.ContentRecycleBinCacheKey;
+
+ // always cache either true or false
+ return cache.GetCacheItem(cacheKey, () => CountChildren(RecycleBinId) > 0);
+ }
+
#endregion
#region Read Repository implementation for Guid keys
@@ -1154,7 +1163,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (withCache)
{
// if the cache contains the (proper version of the) item, use it
- var cached = IsolatedCache.GetCacheItem(RepositoryCacheKeys.GetKey(dto.NodeId));
+ var cached = IsolatedCache.GetCacheItem(RepositoryCacheKeys.GetKey(dto.NodeId));
if (cached != null && cached.VersionId == dto.DocumentVersionDto.ContentVersionDto.Id)
{
content[i] = (Content)cached;
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs
index 02bef366cb..c456a0b2ad 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs
@@ -24,6 +24,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
///
internal class MediaRepository : ContentRepositoryBase, IMediaRepository
{
+ private readonly AppCaches _cache;
private readonly IMediaTypeRepository _mediaTypeRepository;
private readonly ITagRepository _tagRepository;
private readonly MediaByGuidReadRepository _mediaByGuidReadRepository;
@@ -32,6 +33,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
Lazy propertyEditorCollection, DataValueReferenceFactoryCollection dataValueReferenceFactories)
: base(scopeAccessor, cache, logger, languageRepository, relationRepository, relationTypeRepository, propertyEditorCollection, dataValueReferenceFactories)
{
+ _cache = cache;
_mediaTypeRepository = mediaTypeRepository ?? throw new ArgumentNullException(nameof(mediaTypeRepository));
_tagRepository = tagRepository ?? throw new ArgumentNullException(nameof(tagRepository));
_mediaByGuidReadRepository = new MediaByGuidReadRepository(this, scopeAccessor, cache, logger);
@@ -369,6 +371,15 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
public override int RecycleBinId => Constants.System.RecycleBinMedia;
+ public bool RecycleBinSmells()
+ {
+ var cache = _cache.RuntimeCache;
+ var cacheKey = CacheKeys.MediaRecycleBinCacheKey;
+
+ // always cache either true or false
+ return cache.GetCacheItem(cacheKey, () => CountChildren(RecycleBinId) > 0);
+ }
+
#endregion
#region Read Repository implementation for Guid keys
@@ -497,10 +508,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (withCache)
{
// if the cache contains the (proper version of the) item, use it
- var cached = IsolatedCache.GetCacheItem(RepositoryCacheKeys.GetKey(dto.NodeId));
+ var cached = IsolatedCache.GetCacheItem(RepositoryCacheKeys.GetKey(dto.NodeId));
if (cached != null && cached.VersionId == dto.ContentVersionDto.Id)
{
- content[i] = (Models.Media) cached;
+ content[i] = (Models.Media)cached;
continue;
}
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs
index 78dbbe317a..15c707c624 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs
@@ -331,7 +331,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
}
protected override void PersistUpdatedItem(IMember entity)
- {
+ {
// update
entity.UpdatingEntity();
@@ -534,7 +534,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
var sqlSelectTemplateVersion = SqlContext.Templates.Get("Umbraco.Core.MemberRepository.SetLastLogin2", s => s
.Select(x => x.Id)
- .From()
+ .From()
.InnerJoin().On((l, r) => l.NodeId == r.NodeId)
.InnerJoin().On((l, r) => l.NodeId == r.NodeId)
.Where(x => x.NodeObjectType == SqlTemplate.Arg("nodeObjectType"))
@@ -606,7 +606,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (withCache)
{
// if the cache contains the (proper version of the) item, use it
- var cached = IsolatedCache.GetCacheItem(RepositoryCacheKeys.GetKey(dto.NodeId));
+ var cached = IsolatedCache.GetCacheItem(RepositoryCacheKeys.GetKey(dto.NodeId));
if (cached != null && cached.VersionId == dto.ContentVersionDto.Id)
{
content[i] = (Member) cached;
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryCacheKeys.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryCacheKeys.cs
index 09a7c021f8..e2d0e26274 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryCacheKeys.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryCacheKeys.cs
@@ -8,14 +8,27 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
///
internal static class RepositoryCacheKeys
{
- private static readonly Dictionary Keys = new Dictionary();
+ private static readonly Dictionary s_keys = new Dictionary();
public static string GetKey()
{
var type = typeof(T);
- return Keys.TryGetValue(type, out var key) ? key : (Keys[type] = "uRepo_" + type.Name + "_");
+ return s_keys.TryGetValue(type, out var key) ? key : (s_keys[type] = "uRepo_" + type.Name + "_");
}
- public static string GetKey(object id) => GetKey() + id;
+ public static string GetKey(TId id)
+ {
+ if (EqualityComparer.Default.Equals(id, default))
+ {
+ return string.Empty;
+ }
+
+ if (typeof(TId).IsValueType)
+ {
+ return GetKey() + id;
+ }
+
+ return GetKey() + id.ToString().ToUpperInvariant();
+ }
}
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs
index c9f85c343c..9bc0bbeb47 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs
@@ -83,6 +83,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override IUser PerformGet(int id)
{
+ // This will never resolve to a user, yet this is asked
+ // for all of the time (especially in cases of members).
+ // Don't issue a SQL call for this, we know it will not exist.
+ if (id == default || id < -1)
+ {
+ return null;
+ }
+
var sql = SqlContext.Sql()
.Select()
.From()
@@ -168,7 +176,7 @@ ORDER BY colName";
}
public Guid CreateLoginSession(int userId, string requestingIpAddress, bool cleanStaleSessions = true)
- {
+ {
var now = DateTime.UtcNow;
var dto = new UserLoginDto
{
diff --git a/src/Umbraco.Core/Persistence/SqlCeImageMapper.cs b/src/Umbraco.Core/Persistence/SqlCeImageMapper.cs
new file mode 100644
index 0000000000..33303c68f0
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/SqlCeImageMapper.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Data;
+using System.Data.Common;
+using System.Data.SqlServerCe;
+using System.Linq;
+using System.Reflection;
+using NPoco;
+using Umbraco.Core.Composing;
+
+namespace Umbraco.Core.Persistence
+{
+ ///
+ /// Custom NPoco mapper for SqlCe
+ ///
+ ///
+ /// Work arounds to handle special columns
+ ///
+ internal class SqlCeImageMapper : DefaultMapper
+ {
+ public override Func