Compare commits

..

4 Commits

Author SHA1 Message Date
Sebastiaan Janssen 78bf75615f Merge branch 'dev-v7.6' into master-v76 2017-10-17 11:04:27 +02:00
Sebastiaan Janssen 51649879cd Merge branch 'dev-v7.6' into master-v76 2017-10-17 11:00:28 +02:00
Sebastiaan Janssen ab050eb7ac Merge branch 'dev-v7.6' into master-v76 2017-10-17 10:55:56 +02:00
Sebastiaan Janssen 2461924a89 Merge branch 'master-v76' of https://github.com/umbraco/Umbraco-CMS into master-v76 2017-10-02 13:53:41 +02:00
2282 changed files with 89698 additions and 41799 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ root=true
[*]
end_of_line = lf
indent_style = space
indent_size = 4
indent_size = 2
trim_trailing_whitespace = true
[*.{cs,cshtml,csx,vb,vbx,vbhtml,fs,fsx,txt,ps1,sql}]
+1 -1
View File
@@ -1,4 +1,4 @@
[![Build status](https://ci.appveyor.com/api/projects/status/6by6harxtxt0ocdx/branch/dev-v7?svg=true)](https://ci.appveyor.com/project/Umbraco/umbraco-cms-b2cri/branch/dev-v7)
[![Build status](https://ci.appveyor.com/api/projects/status/ikpgqxiw9v8opltv/branch/dev-v7?svg=true)](https://ci.appveyor.com/project/Umbraco/umbraco-cms-hs8dx/branch/dev-v7)
Umbraco CMS
===========
+19 -23
View File
@@ -377,6 +377,14 @@ function Prepare-Packages
Copy-Files "$src\Umbraco.Web.UI\umbraco\lib" "*" "$tmp\WebApp\umbraco\lib"
Copy-Files "$src\Umbraco.Web.UI\umbraco\views" "*" "$tmp\WebApp\umbraco\views"
Copy-Files "$src\Umbraco.Web.UI\umbraco\preview" "*" "$tmp\WebApp\umbraco\preview"
# prepare WebPI
Write-Host "Prepare WebPI"
Remove-Directory "$tmp\WebPi"
mkdir "$tmp\WebPi" > $null
mkdir "$tmp\WebPi\umbraco" > $null
Copy-Files "$tmp\WebApp" "*" "$tmp\WebPi\umbraco"
Copy-Files "$src\WebPi" "*" "$tmp\WebPi"
}
#
@@ -405,6 +413,17 @@ function Package-Zip
"$tmp\WebApp\*" `
"-x!dotless.Core.*" "-x!Content_Types.xml" "-x!*.pdb"`
> $null
Write-Host "Zip WebPI"
&$uenv.Zip a -r "$out\UmbracoCms.WebPI.$($version.Semver).zip" "-x!*.pdb"`
"$tmp\WebPi\*" `
"-x!dotless.Core.*" `
> $null
# hash the webpi file
Write-Host "Hash WebPI"
$hash = Get-FileHash "$out\UmbracoCms.WebPI.$($version.Semver).zip"
Write $hash | out-file "$out\webpihash.txt" -encoding ascii
}
#
@@ -448,24 +467,6 @@ function Restore-NuGet
&$uenv.NuGet restore "$src\Umbraco.sln" > "$tmp\nuget.restore.log"
}
#
# Copies the Azure Gallery script to output
#
function Prepare-AzureGallery
{
param (
$uenv # an Umbraco build environment (see Get-UmbracoBuildEnv)
)
$src = "$($uenv.SolutionRoot)\src"
$tmp = "$($uenv.SolutionRoot)\build.tmp"
$out = "$($uenv.SolutionRoot)\build.out"
$psScript = "$($uenv.SolutionRoot)\build\azuregalleryrelease.ps1"
Write-Host ">> Copy azuregalleryrelease.ps1 to output folder"
Copy-Item $psScript $out
}
#
# Creates the NuGet packages
#
@@ -575,10 +576,6 @@ function Build-Umbraco
{
Compile-Belle $uenv $version
}
elseif ($target -eq "prepare-azuregallery")
{
Prepare-AzureGallery $uenv
}
elseif ($target -eq "all")
{
Prepare-Build $uenv
@@ -593,7 +590,6 @@ function Build-Umbraco
Verify-NuGet $uenv
Prepare-NuGet $uenv
Package-NuGet $uenv $version
Prepare-AzureGallery $uenv
}
else
{
+25
View File
@@ -1,3 +1,28 @@
# returns a string containing the hash of $file
function Get-FileHash($file)
{
try
{
$crypto = new-object System.Security.Cryptography.SHA1CryptoServiceProvider
$stream = [System.IO.File]::OpenRead($file)
$hash = $crypto.ComputeHash($stream)
$text = ""
$hash | foreach `
{
$text = $text + $_.ToString("x2")
}
return $text
}
finally
{
if ($stream)
{
$stream.Dispose()
}
$crypto.Dispose()
}
}
# returns the full path if $file is relative to $pwd
function Get-FullPath($file)
{
+6 -5
View File
@@ -21,25 +21,26 @@
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.3,6.0.0)" />
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.1, 3.0.0)" />
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.1, 3.0.0)" />
<dependency id="Microsoft.Owin.Security.Cookies" version="[3.1.0, 4.0.0)" />
<dependency id="Microsoft.Owin.Security.OAuth" version="[3.1.0, 4.0.0)" />
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[3.1.0, 4.0.0)" />
<dependency id="Microsoft.Owin.Security.Cookies" version="[3.0.1, 4.0.0)" />
<dependency id="Microsoft.Owin.Security.OAuth" version="[3.0.1, 4.0.0)" />
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[3.0.1, 4.0.0)" />
<dependency id="MiniProfiler" version="[2.1.0, 3.0.0)" />
<dependency id="HtmlAgilityPack" version="[1.4.9.5, 2.0.0)" />
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
<dependency id="SharpZipLib" version="[0.86.0, 1.0.0)" />
<dependency id="MySql.Data" version="[6.9.9, 7.0.0)" />
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
<dependency id="ClientDependency" version="[1.9.2, 2.0.0)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0.0, 2.0.0)" />
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
<dependency id="Examine" version="[0.1.85, 1.0.0)" />
<dependency id="Examine" version="[0.1.83, 1.0.0)" />
<dependency id="ImageProcessor" version="[2.5.3, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[4.8.3, 5.0.0)" />
<dependency id="semver" version="[1.1.2, 3.0.0)" />
<!-- Markdown can not be updated due to: https://github.com/hey-red/markdownsharp/issues/71#issuecomment-233585487 -->
<dependency id="Markdown" version="[1.14.7, 2.0.0)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.7.0, 5.0.0)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.7.0, 5.0.0)" />
</dependencies>
</metadata>
<files>
+4 -4
View File
@@ -8,13 +8,13 @@
----------------------------------------------------
*** IMPORTANT NOTICE FOR 7.7 UPGRADES ***
*** IMPORTANT NOTICE FOR 7.6 UPGRADES ***
Be sure to read the version specific upgrade information before proceeding:
https://our.umbraco.org/documentation/Getting-Started/Setup/Upgrading/version-specific#version-7-7-0
https://our.umbraco.org/documentation/Getting-Started/Setup/Upgrading/version-specific#version-7-6-0
Depending on the version you are upgrading from, you may need to make some changes to your web.config
and you will need to be aware of the breaking changes listed there to see if these affect your installation.
You will most likely need to make some changes to your web.config and you will need to be
aware of the breaking changes listed there to see if these affect your installation.
Don't forget to build!
+4 -7
View File
@@ -15,7 +15,6 @@
<section name="BaseRestExtensions" type="Umbraco.Core.Configuration.BaseRest.BaseRestSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
<section name="FileSystemProviders" type="Umbraco.Core.Configuration.FileSystemProvidersSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
<section name="dashBoard" type="Umbraco.Core.Configuration.Dashboard.DashboardSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
<section name="HealthChecks" type="Umbraco.Core.Configuration.HealthChecks.HealthChecksSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
</sectionGroup>
</configSections>
@@ -24,7 +23,6 @@
<add key="owin:appStartup" value="UmbracoDefaultOwinStartup" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
<add key="Umbraco.ModelsBuilder.Enable" value="false" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
<add key="Umbraco.ModelsBuilder.ModelsMode" value="Nothing" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
<add key="umbracoDefaultUILanguage" value="en-US" xdt:Locator="Match(key)" xdt:Transform="SetAttributes(value)" />
</appSettings>
<umbracoConfiguration xdt:Transform="InsertIfMissing">
@@ -32,7 +30,6 @@
<BaseRestExtensions configSource="config\BaseRestExtensions.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
<FileSystemProviders configSource="config\FileSystemProviders.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
<dashBoard configSource="config\Dashboard.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
<HealthChecks configSource="config\HealthChecks.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
</umbracoConfiguration>
<FileSystemProviders xdt:Transform="Remove" />
@@ -371,19 +368,19 @@
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+7 -8
View File
@@ -102,16 +102,15 @@
xdt:Transform="Remove" />
<!--Users-->
<add initialize="true" sortOrder="0" alias="users" application="users" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.UserTreeController, umbraco"
xdt:Locator="Match(application,alias)"
xdt:Transform="SetAttributes()" />
<add application="users" alias="userTypes"
<add application="users" alias="users" title="Users" type="umbraco.loadUsers, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="0"
xdt:Locator="Match(application,alias)"
xdt:Transform="Remove" />
<add application="users" alias="userPermissions"
xdt:Transform="SetAttributes()" />
<add application="users" alias="userTypes" title="User Types" type="umbraco.cms.presentation.Trees.UserTypes, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="1"
xdt:Locator="Match(application,alias)"
xdt:Transform="Remove" />
xdt:Transform="SetAttributes()" />
<add application="users" alias="userPermissions" title="User Permissions" type="umbraco.cms.presentation.Trees.UserPermissions, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="2"
xdt:Locator="Match(application,alias)"
xdt:Transform="SetAttributes()" />
<!--Members-->
<add initialize="true" sortOrder="0" alias="member" application="member" title="Members" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.MemberTreeController, umbraco"
-59
View File
@@ -1,59 +0,0 @@
Param(
[string]$GitHubPersonalAccessToken,
[string]$Directory
)
$workingDirectory = $Directory
CD $workingDirectory
# Clone repo
$fullGitUrl = "https://$env:GIT_URL/$env:GIT_REPOSITORYNAME.git"
git clone $fullGitUrl 2>&1 | % { $_.ToString() }
# Remove everything so that unzipping the release later will update everything
# Don't remove the readme file nor the git directory
Write-Host "Cleaning up git directory before adding new version"
Remove-Item -Recurse $workingDirectory\$env:GIT_REPOSITORYNAME\* -Exclude README.md,.git
# Find release zip
$zipsDir = "$workingDirectory\$env:BUILD_DEFINITIONNAME\zips"
$pattern = "UmbracoCms.([0-9]{1,2}.[0-9]{1,3}.[0-9]{1,3}).zip"
Write-Host "Searching for Umbraco release files in $workingDirectory\$zipsDir for a file with pattern $pattern"
$file = (Get-ChildItem $zipsDir | Where-Object { $_.Name -match "$pattern" })
if($file)
{
# Get release name
$version = [regex]::Match($file.Name, $pattern).captures.groups[1].value
$releaseName = "Umbraco $version"
Write-Host "Found $releaseName"
# Unzip into repository to update release
Add-Type -AssemblyName System.IO.Compression.FileSystem
Write-Host "Unzipping $($file.FullName) to $workingDirectory\$env:GIT_REPOSITORYNAME"
[System.IO.Compression.ZipFile]::ExtractToDirectory("$($file.FullName)", "$workingDirectory\$env:GIT_REPOSITORYNAME")
# Telling git who we are
git config --global user.email "coffee@umbraco.com" 2>&1 | % { $_.ToString() }
git config --global user.name "Umbraco HQ" 2>&1 | % { $_.ToString() }
# Commit
CD $env:GIT_REPOSITORYNAME
Write-Host "Committing Umbraco $version Release from Build Output"
git add . 2>&1 | % { $_.ToString() }
git commit -m " Release $releaseName from Build Output" 2>&1 | % { $_.ToString() }
# Tag the release
git tag -a "v$version" -m "v$version"
# Push release to master
$fullGitAuthUrl = "https://$($env:GIT_USERNAME):$GitHubPersonalAccessToken@$env:GIT_URL/$env:GIT_REPOSITORYNAME.git"
git push $fullGitAuthUrl 2>&1 | % { $_.ToString() }
#Push tag to master
git push $fullGitAuthUrl --tags 2>&1 | % { $_.ToString() }
}
else
{
Write-Error "Umbraco release file not found, searched in $workingDirectory\$zipsDir for a file with pattern $pattern - cancelling"
}
+4 -4
View File
@@ -16,19 +16,19 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.7.3")]
[assembly: AssemblyInformationalVersion("7.7.3")]
[assembly: AssemblyFileVersion("7.6.10")]
[assembly: AssemblyInformationalVersion("7.6.10")]
+1 -26
View File
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Umbraco.Core.Logging;
@@ -35,31 +34,7 @@ namespace Umbraco.Core
{
return Values;
}
}
/// <summary>
/// This method will return a list of IAction's based on a string (letter) list. Each character in the list may represent
/// an IAction. This will associate any found IActions based on the Letter property of the IAction with the character being referenced.
/// </summary>
/// <param name="actions"></param>
/// <returns>returns a list of actions that have an associated letter found in the action string list</returns>
public IEnumerable<IAction> FromActionSymbols(IEnumerable<string> actions)
{
var allActions = Actions.ToArray();
return actions
.Select(c => allActions.FirstOrDefault(a => a.Letter.ToString(CultureInfo.InvariantCulture) == c))
.WhereNotNull()
.ToArray();
}
/// <summary>
/// Returns the string (letter) representation of the actions that make up the actions collection
/// </summary>
/// <returns></returns>
public IEnumerable<string> ToActionSymbols(IEnumerable<IAction> actions)
{
return actions.Select(x => x.Letter.ToString(CultureInfo.InvariantCulture)).ToArray();
}
}
/// <summary>
/// Gets an Action if it exists.
+2 -4
View File
@@ -55,10 +55,8 @@ namespace Umbraco.Core.Cache
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string UserCacheKey = "UmbracoUser";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
[EditorBrowsable(EditorBrowsableState.Never)]
public const string UserGroupPermissionsCacheKey = "UmbracoUserGroupPermissions";
public const string UserPermissionsCacheKey = "UmbracoUserPermissions";
[UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
public const string ContentTypeCacheKey = "UmbracoContentType";
@@ -1,34 +0,0 @@
using System;
namespace Umbraco.Core.CodeAnnotations
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
internal class ActionMetadataAttribute : Attribute
{
public string Category { get; private set; }
public string Name { get; private set; }
/// <summary>
/// Constructor used to assign a Category, since no name is assigned it will try to be translated from the language files based on the action's alias
/// </summary>
/// <param name="category"></param>
public ActionMetadataAttribute(string category)
{
if (string.IsNullOrWhiteSpace(category)) throw new ArgumentException("Value cannot be null or whitespace.", "category");
Category = category;
}
/// <summary>
/// Constructor used to assign an explicit name and category
/// </summary>
/// <param name="category"></param>
/// <param name="name"></param>
public ActionMetadataAttribute(string category, string name)
{
if (string.IsNullOrWhiteSpace(category)) throw new ArgumentException("Value cannot be null or whitespace.", "category");
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", "name");
Category = category;
Name = name;
}
}
}
@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration
{
internal enum LocalTempStorage
internal enum ContentXmlStorage
{
Default,
AspNetTemp,
@@ -6,7 +6,7 @@ using System.Text;
namespace Umbraco.Core.Configuration
{
public class FileSystemProviderElement : ConfigurationElement, IFileSystemProviderElement
public class FileSystemProviderElement : ConfigurationElement
{
private const string ALIAS_KEY = "alias";
private const string TYPE_KEY = "type";
@@ -38,30 +38,5 @@ namespace Umbraco.Core.Configuration
return ((KeyValueConfigurationCollection)(base[PARAMETERS_KEY]));
}
}
string IFileSystemProviderElement.Alias
{
get { return Alias; }
}
string IFileSystemProviderElement.Type
{
get { return Type; }
}
private IDictionary<string, string> _params;
IDictionary<string, string> IFileSystemProviderElement.Parameters
{
get
{
if (_params != null) return _params;
_params = new Dictionary<string, string>();
foreach (KeyValueConfigurationElement element in Parameters)
{
_params.Add(element.Key, element.Value);
}
return _params;
}
}
}
}
@@ -7,7 +7,7 @@ using System.Text;
namespace Umbraco.Core.Configuration
{
[ConfigurationCollection(typeof(FileSystemProviderElement), AddItemName = "Provider")]
public class FileSystemProviderElementCollection : ConfigurationElementCollection, IEnumerable<IFileSystemProviderElement>
public class FileSystemProviderElementCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
@@ -19,25 +19,12 @@ namespace Umbraco.Core.Configuration
return ((FileSystemProviderElement)(element)).Alias;
}
public new FileSystemProviderElement this[string key]
new public FileSystemProviderElement this[string key]
{
get
{
return (FileSystemProviderElement)BaseGet(key);
}
}
IEnumerator<IFileSystemProviderElement> IEnumerable<IFileSystemProviderElement>.GetEnumerator()
{
for (var i = 0; i < Count; i++)
{
yield return BaseGet(i) as IFileSystemProviderElement;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
@@ -6,7 +6,7 @@ using System.Text;
namespace Umbraco.Core.Configuration
{
public class FileSystemProvidersSection : ConfigurationSection, IFileSystemProvidersSection
public class FileSystemProvidersSection : ConfigurationSection
{
[ConfigurationProperty("", IsDefaultCollection = true, IsRequired = true)]
@@ -14,17 +14,5 @@ namespace Umbraco.Core.Configuration
{
get { return ((FileSystemProviderElementCollection)(base[""])); }
}
private IDictionary<string, IFileSystemProviderElement> _providers;
IDictionary<string, IFileSystemProviderElement> IFileSystemProvidersSection.Providers
{
get
{
if (_providers != null) return _providers;
_providers = Providers.ToDictionary(x => x.Alias, x => x);
return _providers;
}
}
}
}
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net.Configuration;
using System.Web;
using System.Web.Configuration;
using System.Web.Hosting;
@@ -43,6 +42,7 @@ namespace Umbraco.Core.Configuration
//ensure the built on (non-changeable) reserved paths are there at all times
private const string StaticReservedPaths = "~/app_plugins/,~/install/,";
private const string StaticReservedUrls = "~/config/splashes/booting.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd,";
#endregion
/// <summary>
@@ -53,7 +53,6 @@ namespace Umbraco.Core.Configuration
_reservedUrlsCache = null;
_reservedPaths = null;
_reservedUrls = null;
HasSmtpServer = null;
}
/// <summary>
@@ -65,26 +64,7 @@ namespace Umbraco.Core.Configuration
ResetInternal();
}
public static bool HasSmtpServerConfigured(string appPath)
{
if (HasSmtpServer.HasValue) return HasSmtpServer.Value;
var config = WebConfigurationManager.OpenWebConfiguration(appPath);
var settings = (MailSettingsSectionGroup)config.GetSectionGroup("system.net/mailSettings");
if (settings == null || settings.Smtp == null) return false;
if (settings.Smtp.SpecifiedPickupDirectory != null && string.IsNullOrEmpty(settings.Smtp.SpecifiedPickupDirectory.PickupDirectoryLocation) == false)
return true;
if (settings.Smtp.Network != null && string.IsNullOrEmpty(settings.Smtp.Network.Host) == false)
return true;
return false;
}
/// <summary>
/// For testing only
/// </summary>
internal static bool? HasSmtpServer { get; set; }
/// <summary>
/// <summary>
/// Gets the reserved urls from web.config.
/// </summary>
/// <value>The reserved urls.</value>
@@ -538,41 +518,24 @@ namespace Umbraco.Core.Configuration
internal static bool ContentCacheXmlStoredInCodeGen
{
get { return LocalTempStorageLocation == LocalTempStorage.AspNetTemp; }
get { return ContentCacheXmlStorageLocation == ContentXmlStorage.AspNetTemp; }
}
/// <summary>
/// This is the location type to store temporary files such as cache files or other localized files for a given machine
/// </summary>
/// <remarks>
/// Currently used for the xml cache file and the plugin cache files
/// </remarks>
internal static LocalTempStorage LocalTempStorageLocation
internal static ContentXmlStorage ContentCacheXmlStorageLocation
{
get
{
//there's a bunch of backwards compat config checks here....
//This is the current one
if (ConfigurationManager.AppSettings.ContainsKey("umbracoLocalTempStorage"))
{
return Enum<LocalTempStorage>.Parse(ConfigurationManager.AppSettings["umbracoLocalTempStorage"]);
}
//This one is old
{
if (ConfigurationManager.AppSettings.ContainsKey("umbracoContentXMLStorage"))
{
return Enum<LocalTempStorage>.Parse(ConfigurationManager.AppSettings["umbracoContentXMLStorage"]);
}
//This one is older
return Enum<ContentXmlStorage>.Parse(ConfigurationManager.AppSettings["umbracoContentXMLStorage"]);
}
if (ConfigurationManager.AppSettings.ContainsKey("umbracoContentXMLUseLocalTemp"))
{
return bool.Parse(ConfigurationManager.AppSettings["umbracoContentXMLUseLocalTemp"])
? LocalTempStorage.AspNetTemp
: LocalTempStorage.Default;
? ContentXmlStorage.AspNetTemp
: ContentXmlStorage.Default;
}
return LocalTempStorage.Default;
return ContentXmlStorage.Default;
}
}
@@ -9,7 +9,7 @@ using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Configuration.Grid
{
internal class GridEditorsConfig : IGridEditorsConfig
class GridEditorsConfig : IGridEditorsConfig
{
private readonly ILogger _logger;
private readonly IRuntimeCacheProvider _runtimeCache;
@@ -1,42 +0,0 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
namespace Umbraco.Core.Configuration.HealthChecks
{
public class DisabledHealthCheckElement : ConfigurationElement, IDisabledHealthCheck
{
private const string IdKey = "id";
private const string DisabledOnKey = "disabledOn";
private const string DisabledByKey = "disabledBy";
[ConfigurationProperty(IdKey, IsKey = true, IsRequired = true)]
public Guid Id
{
get
{
return ((Guid)(base[IdKey]));
}
}
[ConfigurationProperty(DisabledOnKey, IsKey = false, IsRequired = false)]
public DateTime DisabledOn
{
get
{
return ((DateTime)(base[DisabledOnKey]));
}
}
[ConfigurationProperty(DisabledByKey, IsKey = false, IsRequired = false)]
public int DisabledBy
{
get
{
return ((int)(base[DisabledByKey]));
}
}
}
}
@@ -1,40 +0,0 @@
using System.Collections.Generic;
using System.Configuration;
namespace Umbraco.Core.Configuration.HealthChecks
{
[ConfigurationCollection(typeof(DisabledHealthCheckElement), AddItemName = "check")]
public class DisabledHealthChecksElementCollection : ConfigurationElementCollection, IEnumerable<IDisabledHealthCheck>
{
protected override ConfigurationElement CreateNewElement()
{
return new DisabledHealthCheckElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((DisabledHealthCheckElement)(element)).Id;
}
public new DisabledHealthCheckElement this[string key]
{
get
{
return (DisabledHealthCheckElement)BaseGet(key);
}
}
IEnumerator<IDisabledHealthCheck> IEnumerable<IDisabledHealthCheck>.GetEnumerator()
{
for (var i = 0; i < Count; i++)
{
yield return BaseGet(i) as DisabledHealthCheckElement;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
@@ -1,85 +0,0 @@
using System;
using System.Collections.Generic;
using System.Configuration;
namespace Umbraco.Core.Configuration.HealthChecks
{
public class HealthCheckNotificationSettingsElement : ConfigurationElement, IHealthCheckNotificationSettings
{
private const string EnabledKey = "enabled";
private const string FirstRunTimeKey = "firstRunTime";
private const string PeriodKey = "periodInHours";
private const string NotificationMethodsKey = "notificationMethods";
private const string DisabledChecksKey = "disabledChecks";
[ConfigurationProperty(EnabledKey, IsRequired = true)]
public bool Enabled
{
get
{
return (bool)base[EnabledKey];
}
}
[ConfigurationProperty(FirstRunTimeKey, IsRequired = false)]
public string FirstRunTime
{
get
{
return (string)base[FirstRunTimeKey];
}
}
[ConfigurationProperty(PeriodKey, IsRequired = true)]
public int PeriodInHours
{
get
{
return (int)base[PeriodKey];
}
}
[ConfigurationProperty(NotificationMethodsKey, IsDefaultCollection = true, IsRequired = false)]
public NotificationMethodsElementCollection NotificationMethods
{
get
{
return (NotificationMethodsElementCollection)base[NotificationMethodsKey];
}
}
[ConfigurationProperty(DisabledChecksKey, IsDefaultCollection = false, IsRequired = false)]
public DisabledHealthChecksElementCollection DisabledChecks
{
get
{
return (DisabledHealthChecksElementCollection)base[DisabledChecksKey];
}
}
bool IHealthCheckNotificationSettings.Enabled
{
get { return Enabled; }
}
string IHealthCheckNotificationSettings.FirstRunTime
{
get { return FirstRunTime; }
}
int IHealthCheckNotificationSettings.PeriodInHours
{
get { return PeriodInHours; }
}
IReadOnlyDictionary<string, INotificationMethod> IHealthCheckNotificationSettings.NotificationMethods
{
get { return NotificationMethods; }
}
IEnumerable<IDisabledHealthCheck> IHealthCheckNotificationSettings.DisabledChecks
{
get { return DisabledChecks; }
}
}
}
@@ -1,8 +0,0 @@
namespace Umbraco.Core.Configuration.HealthChecks
{
public enum HealthCheckNotificationVerbosity
{
Summary,
Detailed
}
}
@@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Configuration;
namespace Umbraco.Core.Configuration.HealthChecks
{
public class HealthChecksSection : ConfigurationSection, IHealthChecks
{
private const string DisabledChecksKey = "disabledChecks";
private const string NotificationSettingsKey = "notificationSettings";
[ConfigurationProperty(DisabledChecksKey)]
public DisabledHealthChecksElementCollection DisabledChecks
{
get { return ((DisabledHealthChecksElementCollection)(base[DisabledChecksKey])); }
}
[ConfigurationProperty(NotificationSettingsKey, IsRequired = true)]
public HealthCheckNotificationSettingsElement NotificationSettings
{
get { return ((HealthCheckNotificationSettingsElement)(base[NotificationSettingsKey])); }
}
IEnumerable<IDisabledHealthCheck> IHealthChecks.DisabledChecks
{
get { return DisabledChecks; }
}
IHealthCheckNotificationSettings IHealthChecks.NotificationSettings
{
get { return NotificationSettings; }
}
}
}
@@ -1,11 +0,0 @@
using System;
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface IDisabledHealthCheck
{
Guid Id { get; }
DateTime DisabledOn { get; }
int DisabledBy { get; }
}
}
@@ -1,13 +0,0 @@
using System.Collections.Generic;
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface IHealthCheckNotificationSettings
{
bool Enabled { get; }
string FirstRunTime { get; }
int PeriodInHours { get; }
IReadOnlyDictionary<string, INotificationMethod> NotificationMethods { get; }
IEnumerable<IDisabledHealthCheck> DisabledChecks { get; }
}
}
@@ -1,10 +0,0 @@
using System.Collections.Generic;
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface IHealthChecks
{
IEnumerable<IDisabledHealthCheck> DisabledChecks { get; }
IHealthCheckNotificationSettings NotificationSettings { get; }
}
}
@@ -1,13 +0,0 @@
using System.Collections.Generic;
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface INotificationMethod
{
string Alias { get; }
bool Enabled { get; }
HealthCheckNotificationVerbosity Verbosity { get; }
bool FailureOnly { get; }
IReadOnlyDictionary<string, INotificationMethodSettings> Settings { get; }
}
}
@@ -1,8 +0,0 @@
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface INotificationMethodSettings
{
string Key { get; }
string Value { get; }
}
}
@@ -1,85 +0,0 @@
using System;
using System.Collections.Generic;
using System.Configuration;
namespace Umbraco.Core.Configuration.HealthChecks
{
public class NotificationMethodElement : ConfigurationElement, INotificationMethod
{
private const string AliasKey = "alias";
private const string EnabledKey = "enabled";
private const string VerbosityKey = "verbosity";
private const string FailureonlyKey = "failureOnly";
private const string SettingsKey = "settings";
[ConfigurationProperty(AliasKey, IsKey = true, IsRequired = true)]
public string Alias
{
get
{
return (string)base[AliasKey];
}
}
[ConfigurationProperty(EnabledKey, IsKey = true, IsRequired = true)]
public bool Enabled
{
get
{
return (bool)base[EnabledKey];
}
}
[ConfigurationProperty(VerbosityKey, IsRequired = true)]
public HealthCheckNotificationVerbosity Verbosity
{
get
{
return (HealthCheckNotificationVerbosity)base[VerbosityKey];
}
}
[ConfigurationProperty(FailureonlyKey, IsRequired = false)]
public bool FailureOnly
{
get
{
return (bool)base[FailureonlyKey];
}
}
[ConfigurationProperty(SettingsKey, IsDefaultCollection = true, IsRequired = false)]
public NotificationMethodSettingsElementCollection Settings
{
get
{
return (NotificationMethodSettingsElementCollection)base[SettingsKey];
}
}
string INotificationMethod.Alias
{
get { return Alias; }
}
bool INotificationMethod.Enabled
{
get { return Enabled; }
}
HealthCheckNotificationVerbosity INotificationMethod.Verbosity
{
get { return Verbosity; }
}
bool INotificationMethod.FailureOnly
{
get { return FailureOnly; }
}
IReadOnlyDictionary<string, INotificationMethodSettings> INotificationMethod.Settings
{
get { return Settings; }
}
}
}
@@ -1,28 +0,0 @@
using System.Configuration;
namespace Umbraco.Core.Configuration.HealthChecks
{
public class NotificationMethodSettingsElement : ConfigurationElement, INotificationMethodSettings
{
private const string KeyKey = "key";
private const string ValueKey = "value";
[ConfigurationProperty(KeyKey, IsKey = true, IsRequired = true)]
public string Key
{
get
{
return (string)base[KeyKey];
}
}
[ConfigurationProperty(ValueKey, IsRequired = true)]
public string Value
{
get
{
return (string)base[ValueKey];
}
}
}
}
@@ -1,80 +0,0 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
namespace Umbraco.Core.Configuration.HealthChecks
{
[ConfigurationCollection(typeof(NotificationMethodSettingsElement), AddItemName = "add")]
public class NotificationMethodSettingsElementCollection : ConfigurationElementCollection, IEnumerable<INotificationMethodSettings>, IReadOnlyDictionary<string, INotificationMethodSettings>
{
protected override ConfigurationElement CreateNewElement()
{
return new NotificationMethodSettingsElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((NotificationMethodSettingsElement)(element)).Key;
}
IEnumerator<KeyValuePair<string, INotificationMethodSettings>> IEnumerable<KeyValuePair<string, INotificationMethodSettings>>.GetEnumerator()
{
for (var i = 0; i < Count; i++)
{
var val = (NotificationMethodSettingsElement)BaseGet(i);
var key = (string)BaseGetKey(i);
yield return new KeyValuePair<string, INotificationMethodSettings>(key, val);
}
}
IEnumerator<INotificationMethodSettings> IEnumerable<INotificationMethodSettings>.GetEnumerator()
{
for (var i = 0; i < Count; i++)
{
yield return (NotificationMethodSettingsElement)BaseGet(i);
}
}
bool IReadOnlyDictionary<string, INotificationMethodSettings>.ContainsKey(string key)
{
return ((IReadOnlyDictionary<string, INotificationMethodSettings>)this).Keys.Any(x => x == key);
}
bool IReadOnlyDictionary<string, INotificationMethodSettings>.TryGetValue(string key, out INotificationMethodSettings value)
{
try
{
var val = (NotificationMethodSettingsElement)BaseGet(key);
value = val;
return true;
}
catch (Exception)
{
value = null;
return false;
}
}
INotificationMethodSettings IReadOnlyDictionary<string, INotificationMethodSettings>.this[string key]
{
get { return (NotificationMethodSettingsElement)BaseGet(key); }
}
IEnumerable<string> IReadOnlyDictionary<string, INotificationMethodSettings>.Keys
{
get { return BaseGetAllKeys().Cast<string>(); }
}
IEnumerable<INotificationMethodSettings> IReadOnlyDictionary<string, INotificationMethodSettings>.Values
{
get
{
for (var i = 0; i < Count; i++)
{
yield return (NotificationMethodSettingsElement)BaseGet(i);
}
}
}
}
}
@@ -1,80 +0,0 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
namespace Umbraco.Core.Configuration.HealthChecks
{
[ConfigurationCollection(typeof(NotificationMethodElement), AddItemName = "notificationMethod")]
public class NotificationMethodsElementCollection : ConfigurationElementCollection, IEnumerable<INotificationMethod>, IReadOnlyDictionary<string, INotificationMethod>
{
protected override ConfigurationElement CreateNewElement()
{
return new NotificationMethodElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((NotificationMethodElement)(element)).Alias;
}
IEnumerator<KeyValuePair<string, INotificationMethod>> IEnumerable<KeyValuePair<string, INotificationMethod>>.GetEnumerator()
{
for (var i = 0; i < Count; i++)
{
var val = (NotificationMethodElement)BaseGet(i);
var key = (string)BaseGetKey(i);
yield return new KeyValuePair<string, INotificationMethod>(key, val);
}
}
IEnumerator<INotificationMethod> IEnumerable<INotificationMethod>.GetEnumerator()
{
for (var i = 0; i < Count; i++)
{
yield return (NotificationMethodElement)BaseGet(i);
}
}
bool IReadOnlyDictionary<string, INotificationMethod>.ContainsKey(string key)
{
return ((IReadOnlyDictionary<string, INotificationMethod>) this).Keys.Any(x => x == key);
}
bool IReadOnlyDictionary<string, INotificationMethod>.TryGetValue(string key, out INotificationMethod value)
{
try
{
var val = (NotificationMethodElement)BaseGet(key);
value = val;
return true;
}
catch (Exception)
{
value = null;
return false;
}
}
INotificationMethod IReadOnlyDictionary<string, INotificationMethod>.this[string key]
{
get { return (NotificationMethodElement)BaseGet(key); }
}
IEnumerable<string> IReadOnlyDictionary<string, INotificationMethod>.Keys
{
get { return BaseGetAllKeys().Cast<string>(); }
}
IEnumerable<INotificationMethod> IReadOnlyDictionary<string, INotificationMethod>.Values
{
get
{
for (var i = 0; i < Count; i++)
{
yield return (NotificationMethodElement)BaseGet(i);
}
}
}
}
}
@@ -1,11 +0,0 @@
using System.Collections.Generic;
namespace Umbraco.Core.Configuration
{
public interface IFileSystemProviderElement
{
string Alias { get; }
string Type { get; }
IDictionary<string, string> Parameters { get; }
}
}
@@ -1,9 +0,0 @@
using System.Collections.Generic;
namespace Umbraco.Core.Configuration
{
public interface IFileSystemProvidersSection
{
IDictionary<string, IFileSystemProviderElement> Providers { get; }
}
}
@@ -9,7 +9,6 @@ using Umbraco.Core.Cache;
using Umbraco.Core.Configuration.BaseRest;
using Umbraco.Core.Configuration.Dashboard;
using Umbraco.Core.Configuration.Grid;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Logging;
@@ -53,12 +52,6 @@ namespace Umbraco.Core.Configuration
var dashboardConfig = ConfigurationManager.GetSection("umbracoConfiguration/dashBoard") as IDashboardSection;
SetDashboardSettings(dashboardConfig);
}
if (_healthChecks == null)
{
var healthCheckConfig = ConfigurationManager.GetSection("umbracoConfiguration/HealthChecks") as IHealthChecks;
SetHealthCheckSettings(healthCheckConfig);
}
}
/// <summary>
@@ -67,36 +60,18 @@ namespace Umbraco.Core.Configuration
/// <param name="umbracoSettings"></param>
/// <param name="baseRestSettings"></param>
/// <param name="dashboardSettings"></param>
/// <param name="healthChecks"></param>
public UmbracoConfig(IUmbracoSettingsSection umbracoSettings, IBaseRestSection baseRestSettings, IDashboardSection dashboardSettings, IHealthChecks healthChecks)
public UmbracoConfig(IUmbracoSettingsSection umbracoSettings, IBaseRestSection baseRestSettings, IDashboardSection dashboardSettings)
{
SetHealthCheckSettings(healthChecks);
SetUmbracoSettings(umbracoSettings);
SetBaseRestExtensions(baseRestSettings);
SetDashboardSettings(dashboardSettings);
}
private IHealthChecks _healthChecks;
private IDashboardSection _dashboardSection;
private IUmbracoSettingsSection _umbracoSettings;
private IBaseRestSection _baseRestExtensions;
private IGridConfig _gridConfig;
/// <summary>
/// Gets the IHealthCheck config
/// </summary>
public IHealthChecks HealthCheck()
{
if (_healthChecks == null)
{
var ex = new ConfigurationErrorsException("Could not load the " + typeof(IHealthChecks) + " from config file, ensure the web.config and healthchecks.config files are formatted correctly");
LogHelper.Error<UmbracoConfig>("Config error", ex);
throw ex;
}
return _healthChecks;
}
/// <summary>
/// Gets the IDashboardSection
/// </summary>
@@ -111,23 +86,14 @@ namespace Umbraco.Core.Configuration
return _dashboardSection;
}
/// <summary>
/// Only for testing
/// </summary>
/// <param name="value"></param>
public void SetDashboardSettings(IDashboardSection value)
{
_dashboardSection = value;
}
/// <summary>
/// Only for testing
/// </summary>
/// <param name="value"></param>
public void SetHealthCheckSettings(IHealthChecks value)
internal void SetDashboardSettings(IDashboardSection value)
{
_healthChecks = value;
_dashboardSection = value;
}
/// <summary>
@@ -357,7 +357,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
string IContentSection.LoginBackgroundImage
{
get { return LoginBackgroundImage; }
}
}
}
}
@@ -1,12 +1,8 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections.Generic;
using System.Configuration;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This is no longer used and will be removed in future versions")]
internal class HelpElement : ConfigurationElement, IHelpSection
{
[ConfigurationProperty("defaultUrl", DefaultValue = "http://our.umbraco.org/wiki/umbraco-help/{0}/{1}")]
@@ -74,7 +74,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
bool EnablePropertyValueConverters { get; }
string LoginBackgroundImage { get; }
string LoginBackgroundImage { get; }
}
}
@@ -1,11 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections.Generic;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This is no longer used and will be removed in future versions")]
{
public interface IHelpSection : IUmbracoConfigurationSection
{
string DefaultUrl { get; }
@@ -1,10 +1,5 @@
using System;
using System.ComponentModel;
namespace Umbraco.Core.Configuration.UmbracoSettings
namespace Umbraco.Core.Configuration.UmbracoSettings
{
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This is no longer used and will be removed in future versions")]
public interface ILink
{
string Application { get; }
@@ -5,23 +5,11 @@
bool KeepUserLoggedIn { get; }
bool HideDisabledUsersInBackoffice { get; }
/// <summary>
/// Used to enable/disable the forgot password functionality on the back office login screen
/// </summary>
bool AllowPasswordReset { get; }
string AuthCookieName { get; }
string AuthCookieDomain { get; }
/// <summary>
/// A boolean indicating that by default the email address will be the username
/// </summary>
/// <remarks>
/// Even if this is true and the username is different from the email in the database, the username field will still be shown.
/// When this is false, the username and email fields will be shown in the user section.
/// </remarks>
bool UsernameIsEmail { get; }
string AuthCookieDomain { get; }
}
}
@@ -1,7 +1,4 @@
using System;
using System.ComponentModel;
namespace Umbraco.Core.Configuration.UmbracoSettings
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface IUmbracoSettingsSection : IUmbracoConfigurationSection
{
@@ -27,8 +24,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
IProvidersSection Providers { get; }
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This is no longer used and will be removed in future versions")]
IHelpSection Help { get; }
IWebRoutingSection WebRouting { get; }
@@ -1,11 +1,7 @@
using System;
using System.ComponentModel;
using System.Configuration;
using System.Configuration;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This is no longer used and will be removed in future versions")]
internal class LinkElement : ConfigurationElement, ILink
{
[ConfigurationProperty("application")]
@@ -1,12 +1,8 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections.Generic;
using System.Configuration;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This is no longer used and will be removed in future versions")]
internal class LinksCollection : ConfigurationElementCollection, IEnumerable<ILink>
{
protected override ConfigurationElement CreateNewElement()
@@ -16,28 +16,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get { return GetOptionalTextElement("hideDisabledUsersInBackoffice", false); }
}
/// <summary>
/// Used to enable/disable the forgot password functionality on the back office login screen
/// </summary>
[ConfigurationProperty("allowPasswordReset")]
internal InnerTextConfigurationElement<bool> AllowPasswordReset
{
get { return GetOptionalTextElement("allowPasswordReset", true); }
}
/// <summary>
/// A boolean indicating that by default the email address will be the username
/// </summary>
/// <remarks>
/// Even if this is true and the username is different from the email in the database, the username field will still be shown.
/// When this is false, the username and email fields will be shown in the user section.
/// </remarks>
[ConfigurationProperty("usernameIsEmail")]
internal InnerTextConfigurationElement<bool> UsernameIsEmail
{
get { return GetOptionalTextElement("usernameIsEmail", true); }
}
[ConfigurationProperty("authCookieName")]
internal InnerTextConfigurationElement<string> AuthCookieName
{
@@ -60,26 +44,11 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get { return HideDisabledUsersInBackoffice; }
}
/// <summary>
/// Used to enable/disable the forgot password functionality on the back office login screen
/// </summary>
bool ISecuritySection.AllowPasswordReset
{
get { return AllowPasswordReset; }
}
/// <summary>
/// A boolean indicating that by default the email address will be the username
/// </summary>
/// <remarks>
/// Even if this is true and the username is different from the email in the database, the username field will still be shown.
/// When this is false, the username and email fields will be shown in the user section.
/// </remarks>
bool ISecuritySection.UsernameIsEmail
{
get { return UsernameIsEmail; }
}
string ISecuritySection.AuthCookieName
{
get { return AuthCookieName; }
@@ -1,5 +1,4 @@
using System;
using System.ComponentModel;
using System.Configuration;
using System.Linq;
@@ -184,8 +183,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get { return Providers; }
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This is no longer used and will be removed in future versions")]
IHelpSection IUmbracoSettingsSection.Help
{
get { return Help; }
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.7.3");
private static readonly Version Version = new Version("7.6.10");
/// <summary>
/// Gets the current version of Umbraco.
+1 -8
View File
@@ -56,12 +56,7 @@
/// <summary>
/// alias for the content tree.
/// </summary>
public const string Content = "content";
/// <summary>
/// alias for the content blueprint tree.
/// </summary>
public const string ContentBlueprints = "contentBlueprints";
public const string Content = "content";
/// <summary>
/// alias for the member tree.
@@ -123,8 +118,6 @@
public const string Scripts = "scripts";
public const string Users = "users";
//TODO: Fill in the rest!
}
}
@@ -12,14 +12,6 @@ namespace Umbraco.Core
/// </summary>
public static class Conventions
{
internal static class PermissionCategories
{
public const string ContentCategory = "content";
public const string AdministrationCategory = "administration";
public const string StructureCategory = "structure";
public const string OtherCategory = "other";
}
public static class PublicAccess
{
public const string MemberUsernameRuleType = "MemberUsername";
+1 -11
View File
@@ -68,22 +68,12 @@ namespace Umbraco.Core
/// Guid for a Document object.
/// </summary>
public const string Document = "C66BA18E-EAF3-4CFF-8A22-41B16D66A972";
/// <summary>
/// Guid for a Document object.
/// </summary>
public static readonly Guid DocumentGuid = new Guid(Document);
/// <summary>
/// Guid for a Document Blueprint object.
/// </summary>
public const string DocumentBlueprint = "6EBEF410-03AA-48CF-A792-E1C1CB087ACA";
/// <summary>
/// Guid for a Document object.
/// </summary>
public static readonly Guid DocumentBlueprintGuid = new Guid(DocumentBlueprint);
/// <summary>
/// Guid for a Document Type object.
/// </summary>
@@ -437,11 +437,6 @@ namespace Umbraco.Core
/// </summary>
public const string EmailAddressAlias = "Umbraco.EmailAddress";
/// <summary>
/// Alias for the nested content property editor.
/// </summary>
public const string NestedContentAlias = "Umbraco.NestedContent";
public static class PreValueKeys
{
/// <summary>
+1 -5
View File
@@ -8,9 +8,6 @@ namespace Umbraco.Core
public static class Security
{
public const string AdminGroupAlias = "admin";
public const string TranslatorGroupAlias = "translator";
public const string BackOfficeAuthenticationType = "UmbracoBackOffice";
public const string BackOfficeExternalAuthenticationType = "UmbracoExternalCookie";
public const string BackOfficeExternalCookieName = "UMB_EXTLOGIN";
@@ -18,8 +15,7 @@ namespace Umbraco.Core
public const string BackOfficeTwoFactorAuthenticationType = "UmbracoTwoFactorCookie";
internal const string EmptyPasswordPrefix = "___UIDEMPTYPWORD__";
internal const string ForceReAuthFlag = "umbraco-force-auth";
/// <summary>
/// The prefix used for external identity providers for their authentication type
/// </summary>
+1 -37
View File
@@ -41,43 +41,7 @@ namespace Umbraco.Core
Hour,
Minute,
Second
}
/// <summary>
/// Calculates the number of minutes from a date time, on a rolling daily basis (so if
/// date time is before the time, calculate onto next day)
/// </summary>
/// <param name="fromDateTime">Date to start from</param>
/// <param name="scheduledTime">Time to compare against (in Hmm form, e.g. 330, 2200)</param>
/// <returns></returns>
public static int PeriodicMinutesFrom(this DateTime fromDateTime, string scheduledTime)
{
// Ensure time provided is 4 digits long
if (scheduledTime.Length == 3)
{
scheduledTime = "0" + scheduledTime;
}
var scheduledHour = int.Parse(scheduledTime.Substring(0, 2));
var scheduledMinute = int.Parse(scheduledTime.Substring(2));
DateTime scheduledDateTime;
if (IsScheduledInRemainingDay(fromDateTime, scheduledHour, scheduledMinute))
{
scheduledDateTime = new DateTime(fromDateTime.Year, fromDateTime.Month, fromDateTime.Day, scheduledHour, scheduledMinute, 0);
}
else
{
var nextDay = fromDateTime.AddDays(1);
scheduledDateTime = new DateTime(nextDay.Year, nextDay.Month, nextDay.Day, scheduledHour, scheduledMinute, 0);
}
return (int)(scheduledDateTime - fromDateTime).TotalMinutes;
}
private static bool IsScheduledInRemainingDay(DateTime fromDateTime, int scheduledHour, int scheduledMinute)
{
return scheduledHour > fromDateTime.Hour || (scheduledHour == fromDateTime.Hour && scheduledMinute >= fromDateTime.Minute);
}
}
}
@@ -1,25 +0,0 @@
namespace Umbraco.Core.Deploy
{
/// <summary>
/// Provides a method to retrieve an artifact's unique identifier.
/// </summary>
/// <remarks>
/// Artifacts are uniquely identified by their <see cref="Udi"/>, however they represent
/// elements in Umbraco that may be uniquely identified by another value. For example,
/// a content type is uniquely identified by its alias. If someone creates a new content
/// type, and tries to deploy it to a remote environment where a content type with the
/// same alias already exists, both content types end up having different <see cref="Udi"/>
/// but the same alias. By default, Deploy would fail and throw when trying to save the
/// new content type (duplicate alias). However, if the connector also implements this
/// interface, the situation can be detected beforehand and reported in a nicer way.
/// </remarks>
public interface IUniqueIdentifyingServiceConnector
{
/// <summary>
/// Gets the unique identifier of the specified artifact.
/// </summary>
/// <param name="artifact">The artifact.</param>
/// <returns>The unique identifier.</returns>
string GetUniqueIdentifier(IArtifact artifact);
}
}
-114
View File
@@ -1,114 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Routing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
namespace Umbraco.Core
{
/// <summary>
/// A utility class for sending emails
/// </summary>
public class EmailSender : IEmailSender
{
//TODO: This should encapsulate a BackgroundTaskRunner with a queue to send these emails!
private readonly bool _enableEvents;
/// <summary>
/// Default constructor
/// </summary>
public EmailSender() : this(false)
{
}
internal EmailSender(bool enableEvents)
{
_enableEvents = enableEvents;
}
private static readonly Lazy<bool> SmtpConfigured = new Lazy<bool>(() => GlobalSettings.HasSmtpServerConfigured(HttpRuntime.AppDomainAppVirtualPath));
/// <summary>
/// Sends the message non-async
/// </summary>
/// <param name="message"></param>
public void Send(MailMessage message)
{
if (SmtpConfigured.Value == false && _enableEvents)
{
OnSendEmail(new SendEmailEventArgs(message));
}
else
{
using (var client = new SmtpClient())
{
client.Send(message);
}
}
}
/// <summary>
/// Sends the message async
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public async Task SendAsync(MailMessage message)
{
if (SmtpConfigured.Value == false && _enableEvents)
{
OnSendEmail(new SendEmailEventArgs(message));
}
else
{
using (var client = new SmtpClient())
{
if (client.DeliveryMethod == SmtpDeliveryMethod.Network)
{
await client.SendMailAsync(message);
}
else
{
client.Send(message);
}
}
}
}
/// <summary>
/// Returns true if the application should be able to send a required application email
/// </summary>
/// <remarks>
/// We assume this is possible if either an event handler is registered or an smtp server is configured
/// </remarks>
internal static bool CanSendRequiredEmail
{
get { return EventHandlerRegistered || SmtpConfigured.Value; }
}
/// <summary>
/// returns true if an event handler has been registered
/// </summary>
internal static bool EventHandlerRegistered
{
get { return SendEmail != null; }
}
/// <summary>
/// An event that is raised when no smtp server is configured if events are enabled
/// </summary>
internal static event EventHandler<SendEmailEventArgs> SendEmail;
private static void OnSendEmail(SendEmailEventArgs e)
{
var handler = SendEmail;
if (handler != null) handler(null, e);
}
}
}
-3
View File
@@ -111,9 +111,6 @@ namespace Umbraco.Core
/// <returns></returns>
public static bool ContainsAll<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> other)
{
if (source == null) throw new ArgumentNullException("source");
if (other == null) throw new ArgumentNullException("other");
return other.Except(source).Any() == false;
}
@@ -1,15 +0,0 @@
using System;
using System.Net.Mail;
namespace Umbraco.Core.Events
{
internal class SendEmailEventArgs : EventArgs
{
public MailMessage Message { get; private set; }
public SendEmailEventArgs(MailMessage message)
{
Message = message;
}
}
}
+2 -15
View File
@@ -217,21 +217,8 @@ namespace Umbraco.Core
public static MemberInfo GetMemberInfo<T, TReturn>(Expression<Func<T, TReturn>> fromExpression)
{
if (fromExpression == null) return null;
MemberExpression me;
switch (fromExpression.Body.NodeType)
{
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
var ue = fromExpression.Body as UnaryExpression;
me = ((ue != null) ? ue.Operand : null) as MemberExpression;
break;
default:
me = fromExpression.Body as MemberExpression;
break;
}
return me != null ? me.Member : null;
var body = fromExpression.Body as MemberExpression;
return body != null ? body.Member : null;
}
/// <summary>
-13
View File
@@ -1,13 +0,0 @@
using System.Net.Mail;
using System.Threading.Tasks;
namespace Umbraco.Core
{
/// <summary>
/// Simple abstraction to send an email message
/// </summary>
public interface IEmailSender
{
Task SendAsync(MailMessage message);
}
}
@@ -11,7 +11,7 @@ namespace Umbraco.Core.IO
{
public class FileSystemProviderManager
{
private readonly IFileSystemProvidersSection _config;
private readonly FileSystemProvidersSection _config;
private readonly ConcurrentSet<ShadowWrapper> _wrappers = new ConcurrentSet<ShadowWrapper>();
private readonly ConcurrentDictionary<string, ProviderConstructionInfo> _providerLookup = new ConcurrentDictionary<string, ProviderConstructionInfo>();
@@ -28,45 +28,16 @@ namespace Umbraco.Core.IO
private ShadowWrapper _mvcViewsFileSystem;
#region Singleton & Constructor
private static volatile FileSystemProviderManager _instance;
private static readonly object _instanceLocker = new object();
private static readonly FileSystemProviderManager Instance = new FileSystemProviderManager();
public static FileSystemProviderManager Current
{
get
{
if (_instance != null) return _instance;
lock (_instanceLocker)
{
return _instance ?? (_instance = new FileSystemProviderManager());
}
}
get { return Instance; }
}
/// <summary>
/// For tests only, allows setting the value of the singleton "Current" property
/// </summary>
/// <param name="instance"></param>
public static void SetCurrent(FileSystemProviderManager instance)
{
lock (_instanceLocker)
{
_instance = instance;
}
}
internal static void ResetCurrent()
{
lock (_instanceLocker)
{
if (_instance != null)
_instance.Reset();
}
}
// for tests only, totally unsafe
private void Reset()
internal void Reset()
{
_wrappers.Clear();
_providerLookup.Clear();
@@ -81,24 +52,10 @@ namespace Umbraco.Core.IO
// beware: means that we capture the "current" scope provider - take care in tests!
get { return ApplicationContext.Current == null ? null : ApplicationContext.Current.ScopeProvider as IScopeProviderInternal; }
}
/// <summary>
/// Constructor that can be used for tests
/// </summary>
/// <param name="configSection"></param>
public FileSystemProviderManager(IFileSystemProvidersSection configSection)
internal FileSystemProviderManager()
{
if (configSection == null) throw new ArgumentNullException("configSection");
_config = configSection;
CreateWellKnownFileSystems();
}
/// <summary>
/// Default constructor that will read the config from the locally found config section
/// </summary>
public FileSystemProviderManager()
{
_config = (FileSystemProvidersSection)ConfigurationManager.GetSection("umbracoConfiguration/FileSystemProviders");
_config = (FileSystemProvidersSection) ConfigurationManager.GetSection("umbracoConfiguration/FileSystemProviders");
CreateWellKnownFileSystems();
}
@@ -193,9 +150,8 @@ namespace Umbraco.Core.IO
private ProviderConstructionInfo GetUnderlyingFileSystemCtor(string alias, Func<IFileSystem> fallback)
{
// get config
IFileSystemProviderElement providerConfig;
if (_config.Providers.TryGetValue(alias, out providerConfig) == false)
var providerConfig = _config.Providers[alias];
if (providerConfig == null)
{
if (fallback != null) return null;
throw new ArgumentException(string.Format("No provider found with alias {0}.", alias));
@@ -210,21 +166,17 @@ namespace Umbraco.Core.IO
if (providerType.IsAssignableFrom(typeof(IFileSystem)))
throw new InvalidOperationException(string.Format("Type {0} does not implement IFileSystem.", providerType.FullName));
// find a ctor matching the config parameters
// find a ctor matching the config parameters
var paramCount = providerConfig.Parameters != null ? providerConfig.Parameters.Count : 0;
var constructor = providerType.GetConstructors().SingleOrDefault(x
=> x.GetParameters().Length == paramCount && x.GetParameters().All(y => providerConfig.Parameters.Keys.Contains(y.Name)));
=> x.GetParameters().Length == paramCount && x.GetParameters().All(y => providerConfig.Parameters.AllKeys.Contains(y.Name)));
if (constructor == null)
throw new InvalidOperationException(string.Format("Type {0} has no ctor matching the {1} configuration parameter(s).", providerType.FullName, paramCount));
var parameters = new object[paramCount];
if (providerConfig.Parameters != null)
{
var allKeys = providerConfig.Parameters.Keys.ToArray();
if (providerConfig.Parameters != null) // keeps ReSharper happy
for (var i = 0; i < paramCount; i++)
parameters[i] = providerConfig.Parameters[allKeys[i]];
}
parameters[i] = providerConfig.Parameters[providerConfig.Parameters.AllKeys[i]].Value;
return new ProviderConstructionInfo
{
+8 -8
View File
@@ -73,19 +73,19 @@ namespace Umbraco.Core.IO
{
get
{
switch (GlobalSettings.LocalTempStorageLocation)
switch (GlobalSettings.ContentCacheXmlStorageLocation)
{
case LocalTempStorage.AspNetTemp:
case ContentXmlStorage.AspNetTemp:
return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco.config");
case LocalTempStorage.EnvironmentTemp:
case ContentXmlStorage.EnvironmentTemp:
var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1();
var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData",
//include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back
// to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not
// utilizing an old path
var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoXml",
//include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back
// to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not
// utilizing an old path
appDomainHash);
return Path.Combine(cachePath, "umbraco.config");
case LocalTempStorage.Default:
case ContentXmlStorage.Default:
return IOHelper.ReturnPath("umbracoContentXML", "~/App_Data/umbraco.config");
default:
throw new ArgumentOutOfRangeException();
@@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Models
{
+15 -8
View File
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Models
private DateTime? _expireDate;
private int _writer;
private string _nodeName;//NOTE Once localization is introduced this will be the non-localized Node Name.
private bool _permissionsChanged;
/// <summary>
/// Constructor for creating a Content object
/// </summary>
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Models
/// <param name="contentType">ContentType for the current Content object</param>
public Content(string name, IContent parent, IContentType contentType)
: this(name, parent, contentType, new PropertyCollection())
{
{
}
/// <summary>
@@ -65,7 +65,7 @@ namespace Umbraco.Core.Models
/// <param name="parentId">Id of the Parent content</param>
/// <param name="contentType">ContentType for the current Content object</param>
/// <param name="properties">Collection of properties</param>
public Content(string name, int parentId, IContentType contentType, PropertyCollection properties)
public Content(string name, int parentId, IContentType contentType, PropertyCollection properties)
: base(name, parentId, contentType, properties)
{
Mandate.ParameterNotNull(contentType, "contentType");
@@ -84,6 +84,7 @@ namespace Umbraco.Core.Models
public readonly PropertyInfo ExpireDateSelector = ExpressionHelper.GetPropertyInfo<Content, DateTime?>(x => x.ExpireDate);
public readonly PropertyInfo WriterSelector = ExpressionHelper.GetPropertyInfo<Content, int>(x => x.WriterId);
public readonly PropertyInfo NodeNameSelector = ExpressionHelper.GetPropertyInfo<Content, string>(x => x.NodeName);
public readonly PropertyInfo PermissionsChangedSelector = ExpressionHelper.GetPropertyInfo<Content, bool>(x => x.PermissionsChanged);
}
/// <summary>
@@ -91,7 +92,7 @@ namespace Umbraco.Core.Models
/// This is used to override the default one from the ContentType.
/// </summary>
/// <remarks>
/// If no template is explicitly set on the Content object,
/// If no template is explicitly set on the Content object,
/// the Default template from the ContentType will be returned.
/// </remarks>
[DataMember]
@@ -193,6 +194,15 @@ namespace Umbraco.Core.Models
set { SetPropertyValueAndDetectChanges(value, ref _nodeName, Ps.Value.NodeNameSelector); }
}
/// <summary>
/// Used internally to track if permissions have been changed during the saving process for this entity
/// </summary>
[IgnoreDataMember]
internal bool PermissionsChanged
{
get { return _permissionsChanged; }
set { SetPropertyValueAndDetectChanges(value, ref _permissionsChanged, Ps.Value.PermissionsChangedSelector); }
}
/// <summary>
/// Gets the ContentType used by this content object
@@ -264,9 +274,6 @@ namespace Umbraco.Core.Models
[IgnoreDataMember]
internal DateTime PublishedDate { get; set; }
[DataMember]
public bool IsBlueprint { get; internal set; }
/// <summary>
/// Changes the Trashed state of the content object
/// </summary>
@@ -283,7 +290,7 @@ namespace Umbraco.Core.Models
ChangePublishedState(PublishedState.Unpublished);
}
}
/// <summary>
/// Method to call when Entity is being updated
/// </summary>
+4 -6
View File
@@ -54,11 +54,6 @@ namespace Umbraco.Core.Models
{
public readonly PropertyInfo DefaultTemplateSelector = ExpressionHelper.GetPropertyInfo<ContentType, int>(x => x.DefaultTemplateId);
public readonly PropertyInfo AllowedTemplatesSelector = ExpressionHelper.GetPropertyInfo<ContentType, IEnumerable<ITemplate>>(x => x.AllowedTemplates);
//Custom comparer for enumerable
public readonly DelegateEqualityComparer<IEnumerable<ITemplate>> TemplateComparer = new DelegateEqualityComparer<IEnumerable<ITemplate>>(
(templates, enumerable) => templates.UnsortedSequenceEqual(enumerable),
templates => templates.GetHashCode());
}
/// <summary>
@@ -96,7 +91,10 @@ namespace Umbraco.Core.Models
set
{
SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, Ps.Value.AllowedTemplatesSelector,
Ps.Value.TemplateComparer);
//Custom comparer for enumerable
new DelegateEqualityComparer<IEnumerable<ITemplate>>(
(templates, enumerable) => templates.UnsortedSequenceEqual(enumerable),
templates => templates.GetHashCode()));
}
}
+6 -9
View File
@@ -88,12 +88,6 @@ namespace Umbraco.Core.Models
public readonly PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, PropertyGroupCollection>(x => x.PropertyGroups);
public readonly PropertyInfo PropertyTypeCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, IEnumerable<PropertyType>>(x => x.PropertyTypes);
public readonly PropertyInfo HasPropertyTypeBeenRemovedSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, bool>(x => x.HasPropertyTypeBeenRemoved);
//Custom comparer for enumerable
public readonly DelegateEqualityComparer<IEnumerable<ContentTypeSort>> ContentTypeSortComparer =
new DelegateEqualityComparer<IEnumerable<ContentTypeSort>>(
(sorts, enumerable) => sorts.UnsortedSequenceEqual(enumerable),
sorts => sorts.GetHashCode());
}
@@ -260,7 +254,7 @@ namespace Umbraco.Core.Models
set { SetPropertyValueAndDetectChanges(value, ref _trashed, Ps.Value.TrashedSelector); }
}
private readonly IDictionary<string, object> _additionalData;
private IDictionary<string, object> _additionalData;
/// <summary>
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
/// </summary>
@@ -279,8 +273,11 @@ namespace Umbraco.Core.Models
get { return _allowedContentTypes; }
set
{
SetPropertyValueAndDetectChanges(value, ref _allowedContentTypes, Ps.Value.AllowedContentTypesSelector,
Ps.Value.ContentTypeSortComparer);
SetPropertyValueAndDetectChanges(value, ref _allowedContentTypes, Ps.Value.AllowedContentTypesSelector,
//Custom comparer for enumerable
new DelegateEqualityComparer<IEnumerable<ContentTypeSort>>(
(sorts, enumerable) => sorts.UnsortedSequenceEqual(enumerable),
sorts => sorts.GetHashCode()));
}
}
+4 -7
View File
@@ -37,12 +37,6 @@ namespace Umbraco.Core.Models
public readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, Guid?>(x => x.ParentId);
public readonly PropertyInfo ItemKeySelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, string>(x => x.ItemKey);
public readonly PropertyInfo TranslationsSelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, IEnumerable<IDictionaryTranslation>>(x => x.Translations);
//Custom comparer for enumerable
public readonly DelegateEqualityComparer<IEnumerable<IDictionaryTranslation>> DictionaryTranslationComparer =
new DelegateEqualityComparer<IEnumerable<IDictionaryTranslation>>(
(enumerable, translations) => enumerable.UnsortedSequenceEqual(translations),
enumerable => enumerable.GetHashCode());
}
/// <summary>
@@ -85,7 +79,10 @@ namespace Umbraco.Core.Models
}
SetPropertyValueAndDetectChanges(asArray, ref _translations, Ps.Value.TranslationsSelector,
Ps.Value.DictionaryTranslationComparer);
//Custom comparer for enumerable
new DelegateEqualityComparer<IEnumerable<IDictionaryTranslation>>(
(enumerable, translations) => enumerable.UnsortedSequenceEqual(translations),
enumerable => enumerable.GetHashCode()));
}
}
}
+1 -5
View File
@@ -116,7 +116,7 @@ namespace Umbraco.Core.Models.EntityBase
if (IsPropertyDirty("CreateDate") == false || _createDate == default(DateTime))
CreateDate = DateTime.Now;
if (IsPropertyDirty("UpdateDate") == false || _updateDate == default(DateTime))
UpdateDate = DateTime.Now;
UpdateDate = CreateDate;
}
/// <summary>
@@ -126,10 +126,6 @@ namespace Umbraco.Core.Models.EntityBase
{
if (IsPropertyDirty("UpdateDate") == false || _updateDate == default(DateTime))
UpdateDate = DateTime.Now;
//this is just in case
if (_createDate == default(DateTime))
CreateDate = DateTime.Now;
}
/// <summary>
@@ -1,8 +0,0 @@
namespace Umbraco.Core.Models.EntityBase
{
public class EntityPath
{
public int Id { get; set; }
public string Path { get; set; }
}
}
+2 -5
View File
@@ -1,5 +1,7 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using Umbraco.Core.Persistence.Mappers;
namespace Umbraco.Core.Models
{
@@ -83,10 +85,5 @@ namespace Umbraco.Core.Models
/// Gets the unique identifier of the published version, if any.
/// </summary>
Guid PublishedVersionGuid { get; }
/// <summary>
/// Gets a value indicating whether the content item is a blueprint.
/// </summary>
bool IsBlueprint { get; }
}
}
@@ -2,77 +2,23 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Security;
namespace Umbraco.Core.Models.Identity
{
public class BackOfficeIdentityUser : IdentityUser<int, IIdentityUserLogin, IdentityUserRole<string>, IdentityUserClaim<int>>, IRememberBeingDirty
public class BackOfficeIdentityUser : IdentityUser<int, IIdentityUserLogin, IdentityUserRole<string>, IdentityUserClaim<int>>
{
/// <summary>
/// Used to construct a new instance without an identity
/// </summary>
/// <param name="username"></param>
/// <param name="email">This is allowed to be null (but would need to be filled in if trying to persist this instance)</param>
/// <param name="culture"></param>
/// <returns></returns>
public static BackOfficeIdentityUser CreateNew(string username, string email, string culture)
{
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", "username");
if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value cannot be null or whitespace.", "culture");
var user = new BackOfficeIdentityUser();
user.DisableChangeTracking();
user._userName = username;
user._email = email;
//we are setting minvalue here because the default is "0" which is the id of the admin user
//which we cannot allow because the admin user will always exist
user._id = int.MinValue;
user._hasIdentity = false;
user._culture = culture;
user.EnableChangeTracking();
return user;
public BackOfficeIdentityUser()
{
StartMediaId = -1;
StartContentId = -1;
Culture = Configuration.GlobalSettings.DefaultUILanguage;
}
private BackOfficeIdentityUser()
{
_startMediaIds = new int[] { };
_startContentIds = new int[] { };
_groups = new IReadOnlyUserGroup[] { };
_allowedSections = new string[] { };
_culture = Configuration.GlobalSettings.DefaultUILanguage;
_groups = new IReadOnlyUserGroup[0];
_roles = new ObservableCollection<IdentityUserRole<string>>();
_roles.CollectionChanged += _roles_CollectionChanged;
}
/// <summary>
/// Creates an existing user with the specified groups
/// </summary>
/// <param name="userId"></param>
/// <param name="groups"></param>
public BackOfficeIdentityUser(int userId, IEnumerable<IReadOnlyUserGroup> groups)
{
_startMediaIds = new int[] { };
_startContentIds = new int[] { };
_groups = new IReadOnlyUserGroup[] { };
_allowedSections = new string[] { };
_culture = Configuration.GlobalSettings.DefaultUILanguage;
_groups = groups.ToArray();
_roles = new ObservableCollection<IdentityUserRole<string>>(_groups.Select(x => new IdentityUserRole<string>
{
RoleId = x.Alias,
UserId = userId.ToString()
}));
_roles.CollectionChanged += _roles_CollectionChanged;
}
public virtual async Task<ClaimsIdentity> GenerateUserIdentityAsync(BackOfficeUserManager<BackOfficeIdentityUser> manager)
{
// NOTE the authenticationType must match the umbraco one
@@ -81,155 +27,16 @@ namespace Umbraco.Core.Models.Identity
return userIdentity;
}
/// <summary>
/// Returns true if an Id has been set on this object this will be false if the object is new and not peristed to the database
/// </summary>
public bool HasIdentity
{
get { return _hasIdentity; }
}
public int[] CalculatedMediaStartNodeIds { get; internal set; }
public int[] CalculatedContentStartNodeIds { get; internal set; }
public override int Id
{
get { return _id; }
set
{
_id = value;
_hasIdentity = true;
}
}
/// <summary>
/// Override Email so we can track changes to it
/// </summary>
public override string Email
{
get { return _email; }
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _email, Ps.Value.EmailSelector); }
}
/// <summary>
/// Override UserName so we can track changes to it
/// </summary>
public override string UserName
{
get { return _userName; }
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _userName, Ps.Value.UserNameSelector); }
}
/// <summary>
/// Override LastLoginDateUtc so we can track changes to it
/// </summary>
public override DateTime? LastLoginDateUtc
{
get { return _lastLoginDateUtc; }
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _lastLoginDateUtc, Ps.Value.LastLoginDateUtcSelector); }
}
/// <summary>
/// Override EmailConfirmed so we can track changes to it
/// </summary>
public override bool EmailConfirmed
{
get { return _emailConfirmed; }
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _emailConfirmed, Ps.Value.EmailConfirmedSelector); }
}
/// <summary>
/// Gets/sets the user's real name
/// </summary>
public string Name
{
get { return _name; }
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); }
}
public string Name { get; set; }
public int StartContentId { get; set; }
public int StartMediaId { get; set; }
public string[] AllowedSections { get; set; }
public string Culture { get; set; }
/// <summary>
/// Override AccessFailedCount so we can track changes to it
/// </summary>
public override int AccessFailedCount
{
get { return _accessFailedCount; }
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _accessFailedCount, Ps.Value.AccessFailedCountSelector); }
}
/// <summary>
/// Override PasswordHash so we can track changes to it
/// </summary>
public override string PasswordHash
{
get { return _passwordHash; }
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _passwordHash, Ps.Value.PasswordHashSelector); }
}
/// <summary>
/// Content start nodes assigned to the User (not ones assigned to the user's groups)
/// </summary>
public int[] StartContentIds
{
get { return _startContentIds; }
set
{
if (value == null) value = new int[0];
_tracker.SetPropertyValueAndDetectChanges(value, ref _startContentIds, Ps.Value.StartContentIdsSelector, Ps.Value.StartIdsComparer);
}
}
/// <summary>
/// Media start nodes assigned to the User (not ones assigned to the user's groups)
/// </summary>
public int[] StartMediaIds
{
get { return _startMediaIds; }
set
{
if (value == null) value = new int[0];
_tracker.SetPropertyValueAndDetectChanges(value, ref _startMediaIds, Ps.Value.StartMediaIdsSelector, Ps.Value.StartIdsComparer);
}
}
/// <summary>
/// This is a readonly list of the user's allowed sections which are based on it's user groups
/// </summary>
public string[] AllowedSections
{
get { return _allowedSections ?? (_allowedSections = _groups.SelectMany(x => x.AllowedSections).Distinct().ToArray()); }
}
public string Culture
{
get { return _culture; }
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _culture, Ps.Value.CultureSelector); }
}
public IReadOnlyUserGroup[] Groups
{
get { return _groups; }
set
{
//so they recalculate
_allowedSections = null;
//now clear all roles and re-add them
_roles.CollectionChanged -= _roles_CollectionChanged;
_roles.Clear();
foreach (var identityUserRole in _groups.Select(x => new IdentityUserRole<string>
{
RoleId = x.Alias,
UserId = Id.ToString()
}))
{
_roles.Add(identityUserRole);
}
_roles.CollectionChanged += _roles_CollectionChanged;
_tracker.SetPropertyValueAndDetectChanges(value, ref _groups, Ps.Value.GroupsSelector, Ps.Value.GroupsComparer);
}
}
public string UserTypeAlias { get; set; }
/// <summary>
/// Lockout is always enabled
@@ -237,7 +44,7 @@ namespace Umbraco.Core.Models.Identity
public override bool LockoutEnabled
{
get { return true; }
set
set
{
//do nothing
}
@@ -255,11 +62,6 @@ namespace Umbraco.Core.Models.Identity
}
}
/// <summary>
/// This is a 1:1 mapping with IUser.IsApproved
/// </summary>
internal bool IsApproved { get; set; }
/// <summary>
/// Overridden to make the retrieval lazy
/// </summary>
@@ -280,42 +82,16 @@ namespace Umbraco.Core.Models.Identity
return _logins;
}
}
public bool LoginsChanged { get; private set; }
void Logins_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
_tracker.OnPropertyChanged(Ps.Value.LoginsSelector);
LoginsChanged = true;
}
private void _roles_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
_tracker.OnPropertyChanged(Ps.Value.RolesSelector);
}
private readonly ObservableCollection<IdentityUserRole<string>> _roles;
/// <summary>
/// helper method to easily add a role without having to deal with IdentityUserRole{T}
/// </summary>
/// <param name="role"></param>
/// <remarks>
/// Adding a role this way will not reflect on the user's group's collection or it's allowed sections until the user is persisted
/// </remarks>
public void AddRole(string role)
{
Roles.Add(new IdentityUserRole<string>
{
UserId = this.Id.ToString(),
RoleId = role
});
}
/// <summary>
/// Override Roles because the value of these are the user's group aliases
/// </summary>
public override ICollection<IdentityUserRole<string>> Roles
{
get { return _roles; }
}
private ObservableCollection<IIdentityUserLogin> _logins;
private Lazy<IEnumerable<IIdentityUserLogin>> _getLogins;
/// <summary>
/// Used to set a lazy call back to populate the user's Login list
@@ -325,128 +101,6 @@ namespace Umbraco.Core.Models.Identity
{
if (callback == null) throw new ArgumentNullException("callback");
_getLogins = callback;
}
#region Change tracking
public void DisableChangeTracking()
{
_tracker.DisableChangeTracking();
}
public void EnableChangeTracking()
{
_tracker.EnableChangeTracking();
}
/// <summary>
/// Since this class only has change tracking turned on for Email/Username this will return true if either of those have changed
/// </summary>
/// <returns></returns>
public bool IsDirty()
{
return _tracker.IsDirty();
}
/// <summary>
/// Returns true if the specified property is dirty
/// </summary>
/// <param name="propName"></param>
/// <returns></returns>
public bool IsPropertyDirty(string propName)
{
return _tracker.IsPropertyDirty(propName);
}
/// <summary>
/// Resets dirty properties
/// </summary>
void ICanBeDirty.ResetDirtyProperties()
{
_tracker.ResetDirtyProperties();
}
bool IRememberBeingDirty.WasDirty()
{
return _tracker.WasDirty();
}
bool IRememberBeingDirty.WasPropertyDirty(string propertyName)
{
return _tracker.WasPropertyDirty(propertyName);
}
void IRememberBeingDirty.ForgetPreviouslyDirtyProperties()
{
_tracker.ForgetPreviouslyDirtyProperties();
}
public void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
{
_tracker.ResetDirtyProperties(rememberPreviouslyChangedProperties);
}
private static readonly Lazy<PropertySelectors> Ps = new Lazy<PropertySelectors>();
private class PropertySelectors
{
public readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, string>(x => x.Email);
public readonly PropertyInfo UserNameSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, string>(x => x.UserName);
public readonly PropertyInfo LastLoginDateUtcSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, DateTime?>(x => x.LastLoginDateUtc);
public readonly PropertyInfo EmailConfirmedSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, bool>(x => x.EmailConfirmed);
public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, string>(x => x.Name);
public readonly PropertyInfo AccessFailedCountSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, int>(x => x.AccessFailedCount);
public readonly PropertyInfo PasswordHashSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, string>(x => x.PasswordHash);
public readonly PropertyInfo CultureSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, string>(x => x.Culture);
public readonly PropertyInfo StartMediaIdsSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, int[]>(x => x.StartMediaIds);
public readonly PropertyInfo StartContentIdsSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, int[]>(x => x.StartContentIds);
public readonly PropertyInfo GroupsSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, IReadOnlyUserGroup[]>(x => x.Groups);
public readonly PropertyInfo LoginsSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, IEnumerable<IIdentityUserLogin>>(x => x.Logins);
public readonly PropertyInfo RolesSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, IEnumerable<IdentityUserRole<string>>>(x => x.Roles);
//Custom comparer for enumerables
public readonly DelegateEqualityComparer<IReadOnlyUserGroup[]> GroupsComparer = new DelegateEqualityComparer<IReadOnlyUserGroup[]>(
(groups, enumerable) => groups.Select(x => x.Alias).UnsortedSequenceEqual(enumerable.Select(x => x.Alias)),
groups => groups.GetHashCode());
public readonly DelegateEqualityComparer<int[]> StartIdsComparer = new DelegateEqualityComparer<int[]>(
(groups, enumerable) => groups.UnsortedSequenceEqual(enumerable),
groups => groups.GetHashCode());
}
private readonly ChangeTracker _tracker = new ChangeTracker();
private string _email;
private string _userName;
private int _id;
private bool _hasIdentity = false;
private DateTime? _lastLoginDateUtc;
private bool _emailConfirmed;
private string _name;
private int _accessFailedCount;
private string _passwordHash;
private string _culture;
private ObservableCollection<IIdentityUserLogin> _logins;
private Lazy<IEnumerable<IIdentityUserLogin>> _getLogins;
private IReadOnlyUserGroup[] _groups;
private string[] _allowedSections;
private int[] _startMediaIds;
private int[] _startContentIds;
/// <summary>
/// internal class used to track changes for properties that have it enabled
/// </summary>
private class ChangeTracker : TracksChangesEntityBase
{
/// <summary>
/// Make this public so that it's usable
/// </summary>
/// <param name="propertyInfo"></param>
public new void OnPropertyChanged(PropertyInfo propertyInfo)
{
base.OnPropertyChanged(propertyInfo);
}
}
#endregion
}
}
@@ -1,7 +1,7 @@
using System;
using System.Linq;
using AutoMapper;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Mapping;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Security;
@@ -13,43 +13,28 @@ namespace Umbraco.Core.Models.Identity
public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
{
config.CreateMap<IUser, BackOfficeIdentityUser>()
.BeforeMap((user, identityUser) =>
{
identityUser.DisableChangeTracking();
})
.ConstructUsing(user => new BackOfficeIdentityUser(user.Id, user.Groups))
.ForMember(user => user.LastLoginDateUtc, expression => expression.MapFrom(user => user.LastLoginDate.ToUniversalTime()))
.ForMember(user => user.Email, expression => expression.MapFrom(user => user.Email))
.ForMember(user => user.EmailConfirmed, expression => expression.MapFrom(user => user.EmailConfirmedDate.HasValue))
.ForMember(user => user.Id, expression => expression.MapFrom(user => user.Id))
.ForMember(user => user.LockoutEndDateUtc, expression => expression.MapFrom(user => user.IsLockedOut ? DateTime.MaxValue.ToUniversalTime() : (DateTime?)null))
.ForMember(user => user.IsApproved, expression => expression.MapFrom(user => user.IsApproved))
.ForMember(user => user.UserName, expression => expression.MapFrom(user => user.Username))
.ForMember(user => user.PasswordHash, expression => expression.MapFrom(user => GetPasswordHash(user.RawPasswordValue)))
.ForMember(user => user.Culture, expression => expression.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)))
.ForMember(user => user.Name, expression => expression.MapFrom(user => user.Name))
.ForMember(user => user.StartMediaIds, expression => expression.MapFrom(user => user.StartMediaIds))
.ForMember(user => user.StartContentIds, expression => expression.MapFrom(user => user.StartContentIds))
.ForMember(user => user.StartMediaId, expression => expression.MapFrom(user => user.StartMediaId))
.ForMember(user => user.StartContentId, expression => expression.MapFrom(user => user.StartContentId))
.ForMember(user => user.UserTypeAlias, expression => expression.MapFrom(user => user.UserType.Alias))
.ForMember(user => user.AccessFailedCount, expression => expression.MapFrom(user => user.FailedPasswordAttempts))
.ForMember(user => user.CalculatedContentStartNodeIds, expression => expression.MapFrom(user => user.CalculateContentStartNodeIds(applicationContext.Services.EntityService)))
.ForMember(user => user.CalculatedMediaStartNodeIds, expression => expression.MapFrom(user => user.CalculateMediaStartNodeIds(applicationContext.Services.EntityService)))
.ForMember(user => user.AllowedSections, expression => expression.MapFrom(user => user.AllowedSections.ToArray()))
.AfterMap((user, identityUser) =>
{
identityUser.ResetDirtyProperties(true);
identityUser.EnableChangeTracking();
});
.ForMember(user => user.AllowedSections, expression => expression.MapFrom(user => user.AllowedSections.ToArray()));
config.CreateMap<BackOfficeIdentityUser, UserData>()
.ConstructUsing((BackOfficeIdentityUser user) => new UserData(Guid.NewGuid().ToString("N"))) //this is the 'session id'
.ForMember(detail => detail.Id, opt => opt.MapFrom(user => user.Id))
.ForMember(detail => detail.AllowedApplications, opt => opt.MapFrom(user => user.AllowedSections))
.ForMember(detail => detail.Roles, opt => opt.MapFrom(user => user.Roles.Select(x => x.RoleId).ToArray()))
.ForMember(detail => detail.RealName, opt => opt.MapFrom(user => user.Name))
//When mapping to UserData which is used in the authcookie we want ALL start nodes including ones defined on the groups
.ForMember(detail => detail.StartContentNodes, opt => opt.MapFrom(user => user.CalculatedContentStartNodeIds))
//When mapping to UserData which is used in the authcookie we want ALL start nodes including ones defined on the groups
.ForMember(detail => detail.StartMediaNodes, opt => opt.MapFrom(user => user.CalculatedMediaStartNodeIds))
.ForMember(detail => detail.Roles, opt => opt.MapFrom(user => new[] { user.UserTypeAlias }))
.ForMember(detail => detail.StartContentNode, opt => opt.MapFrom(user => user.StartContentId))
.ForMember(detail => detail.StartMediaNode, opt => opt.MapFrom(user => user.StartMediaId))
.ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.UserName))
.ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.Culture))
.ForMember(detail => detail.SessionId, opt => opt.MapFrom(user => user.SecurityStamp.IsNullOrWhiteSpace() ? Guid.NewGuid().ToString("N") : user.SecurityStamp));
@@ -1,54 +0,0 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents an <see cref="IContent"/> -> user group & permission key value pair collection
/// </summary>
/// <remarks>
/// This implements <see cref="IAggregateRoot"/> purely so it can be used with the repository layer which is why it's explicitly implemented.
/// </remarks>
public class ContentPermissionSet : EntityPermissionSet, IAggregateRoot
{
private readonly IContent _content;
public ContentPermissionSet(IContent content, EntityPermissionCollection permissionsSet)
: base(content.Id, permissionsSet)
{
_content = content;
}
public override int EntityId
{
get { return _content.Id; }
}
#region Explicit implementation of IAggregateRoot
int IEntity.Id
{
get { return EntityId; }
set { throw new NotImplementedException(); }
}
bool IEntity.HasIdentity
{
get { return EntityId > 0; }
}
Guid IEntity.Key { get; set; }
DateTime IEntity.CreateDate { get; set; }
DateTime IEntity.UpdateDate { get; set; }
DateTime? IDeletableEntity.DeletedDate { get; set; }
object IDeepCloneable.DeepClone()
{
throw new NotImplementedException();
}
#endregion
}
}
@@ -1,66 +1,26 @@
using System;
using System.Collections;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents an entity permission (defined on the user group and derived to retrieve permissions for a given user)
/// Represents a user -> entity permission
/// </summary>
public class EntityPermission : IEquatable<EntityPermission>
public class EntityPermission
{
public EntityPermission(int groupId, int entityId, string[] assignedPermissions)
public EntityPermission(int userId, int entityId, string[] assignedPermissions)
{
UserGroupId = groupId;
UserId = userId;
EntityId = entityId;
AssignedPermissions = assignedPermissions;
IsDefaultPermissions = false;
}
public EntityPermission(int groupId, int entityId, string[] assignedPermissions, bool isDefaultPermissions)
{
UserGroupId = groupId;
EntityId = entityId;
AssignedPermissions = assignedPermissions;
IsDefaultPermissions = isDefaultPermissions;
}
public int UserId { get; private set; }
public int EntityId { get; private set; }
public int UserGroupId { get; private set; }
/// <summary>
/// The assigned permissions for the user/entity combo
/// </summary>
public string[] AssignedPermissions { get; private set; }
/// <summary>
/// True if the permissions assigned to this object are the group's default permissions and not explicitly defined permissions
/// </summary>
/// <remarks>
/// This will be the case when looking up entity permissions and falling back to the default permissions
/// </remarks>
public bool IsDefaultPermissions { get; private set; }
public bool Equals(EntityPermission other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return EntityId == other.EntityId && UserGroupId == other.UserGroupId;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((EntityPermission) obj);
}
public override int GetHashCode()
{
unchecked
{
return (EntityId * 397) ^ UserGroupId;
}
}
}
}
@@ -1,57 +0,0 @@
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// A <see cref="HashSet{T}"/> of <see cref="EntityPermission"/>
/// </summary>
public class EntityPermissionCollection : HashSet<EntityPermission>
{
public EntityPermissionCollection()
{
}
public EntityPermissionCollection(IEnumerable<EntityPermission> collection) : base(collection)
{
}
/// <summary>
/// Returns the aggregate permissions in the permission set for a single node
/// </summary>
/// <returns></returns>
/// <remarks>
/// This value is only calculated once per node
/// </remarks>
public IEnumerable<string> GetAllPermissions(int entityId)
{
if (_aggregateNodePermissions == null)
_aggregateNodePermissions = new Dictionary<int, string[]>();
string[] entityPermissions;
if (_aggregateNodePermissions.TryGetValue(entityId, out entityPermissions) == false)
{
entityPermissions = this.Where(x => x.EntityId == entityId).SelectMany(x => x.AssignedPermissions).Distinct().ToArray();
_aggregateNodePermissions[entityId] = entityPermissions;
}
return entityPermissions;
}
private Dictionary<int, string[]> _aggregateNodePermissions;
/// <summary>
/// Returns the aggregate permissions in the permission set for all nodes
/// </summary>
/// <returns></returns>
/// <remarks>
/// This value is only calculated once
/// </remarks>
public IEnumerable<string> GetAllPermissions()
{
return _aggregatePermissions ?? (_aggregatePermissions =
this.SelectMany(x => x.AssignedPermissions).Distinct().ToArray());
}
private string[] _aggregatePermissions;
}
}
@@ -1,55 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Generic;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents an entity -> user group & permission key value pair collection
/// </summary>
/// Represents an entity -> user & permission key value pair collection
/// </summary>
public class EntityPermissionSet
{
private static readonly Lazy<EntityPermissionSet> EmptyInstance = new Lazy<EntityPermissionSet>(() => new EntityPermissionSet(-1, new EntityPermissionCollection()));
/// <summary>
/// Returns an empty permission set
/// </summary>
/// <returns></returns>
public static EntityPermissionSet Empty()
{
return EmptyInstance.Value;
}
public EntityPermissionSet(int entityId, EntityPermissionCollection permissionsSet)
{
EntityId = entityId;
PermissionsSet = permissionsSet;
}
/// <summary>
/// The entity id with permissions assigned
/// </summary>
public virtual int EntityId { get; private set; }
public int EntityId { get; private set; }
/// <summary>
/// The key/value pairs of user group id & single permission
/// The key/value pairs of user id & single permission
/// </summary>
public EntityPermissionCollection PermissionsSet { get; private set; }
public IEnumerable<UserPermission> UserPermissionsSet { get; private set; }
/// <summary>
/// Returns the aggregate permissions in the permission set
/// </summary>
/// <returns></returns>
/// <remarks>
/// This value is only calculated once
/// </remarks>
public IEnumerable<string> GetAllPermissions()
public EntityPermissionSet(int entityId, IEnumerable<UserPermission> userPermissionsSet)
{
return PermissionsSet.GetAllPermissions();
EntityId = entityId;
UserPermissionsSet = userPermissionsSet;
}
public class UserPermission
{
public UserPermission(int userId, string permission)
{
UserId = userId;
Permission = permission;
}
public int UserId { get; private set; }
public string Permission { get; private set; }
protected bool Equals(UserPermission other)
{
return UserId == other.UserId && string.Equals(Permission, other.Permission);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((UserPermission) obj);
}
public override int GetHashCode()
{
unchecked
{
return (UserId*397) ^ Permission.GetHashCode();
}
}
}
}
}
@@ -1,11 +1,15 @@
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Defines the the User Profile interface
/// </summary>
/// Defines the the Profile interface
/// </summary>
/// <remarks>
/// This interface is pretty useless but has been exposed publicly from 6.x so we're stuck with it. It would make more sense
/// if the Id was an int but since it's not people have to cast it to int all of the time!
/// </remarks>
public interface IProfile
{
int Id { get; }
string Name { get; }
object Id { get; set; }
string Name { get; set; }
}
}
@@ -1,31 +0,0 @@
using System.Collections.Generic;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// A readonly user group providing basic information
/// </summary>
public interface IReadOnlyUserGroup
{
string Name { get; }
string Icon { get; }
int Id { get; }
int? StartContentId { get; }
int? StartMediaId { get; }
/// <summary>
/// The alias
/// </summary>
string Alias { get; }
/// <summary>
/// The set of default permissions
/// </summary>
/// <remarks>
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
/// </remarks>
IEnumerable<string> Permissions { get; set; }
IEnumerable<string> AllowedSections { get; }
}
}
+20 -47
View File
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Mappers;
namespace Umbraco.Core.Models.Membership
{
@@ -11,50 +10,29 @@ namespace Umbraco.Core.Models.Membership
/// <remarks>Will be left internal until a proper Membership implementation is part of the roadmap</remarks>
public interface IUser : IMembershipUser, IRememberBeingDirty, ICanBeDirty
{
UserState UserState { get; }
string Name { get; set; }
int SessionTimeout { get; set; }
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
int StartContentId { get; set; }
int[] StartContentIds { get; set; }
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
int StartMediaId { get; set; }
int[] StartMediaIds { get; set; }
string Language { get; set; }
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
IUserType UserType { get; set; }
DateTime? EmailConfirmedDate { get; set; }
DateTime? InvitedDate { get; set; }
/// <summary>
/// Gets the groups that user is part of
/// </summary>
IEnumerable<IReadOnlyUserGroup> Groups { get; }
void RemoveGroup(string group);
void ClearGroups();
void AddGroup(IReadOnlyUserGroup group);
int StartContentId { get; set; }
int StartMediaId { get; set; }
string Language { get; set; }
/// <summary>
/// Gets/sets the user type for the user
/// </summary>
IUserType UserType { get; set; }
//TODO: This should be a private set
/// <summary>
/// The default permission set for the user
/// </summary>
/// <remarks>
/// Currently in umbraco each permission is a single char but with an Enumerable{string} collection this allows for flexible changes to this in the future
/// </remarks>
IEnumerable<string> DefaultPermissions { get; set; }
IEnumerable<string> AllowedSections { get; }
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
void RemoveAllowedSection(string sectionAlias);
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
void AddAllowedSection(string sectionAlias);
void AddAllowedSection(string sectionAlias);
/// <summary>
/// Exposes the basic profile data
@@ -65,10 +43,5 @@ namespace Umbraco.Core.Models.Membership
/// The security stamp used by ASP.Net identity
/// </summary>
string SecurityStamp { get; set; }
/// <summary>
/// Will hold the media file system relative path of the users custom avatar if they uploaded one
/// </summary>
string Avatar { get; set; }
}
}
@@ -1,44 +0,0 @@
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models.Membership
{
public interface IUserGroup : IAggregateRoot
{
string Alias { get; set; }
int? StartContentId { get; set; }
int? StartMediaId { get; set; }
/// <summary>
/// The icon
/// </summary>
string Icon { get; set; }
/// <summary>
/// The name
/// </summary>
string Name { get; set; }
/// <summary>
/// The set of default permissions
/// </summary>
/// <remarks>
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
/// </remarks>
IEnumerable<string> Permissions { get; set; }
IEnumerable<string> AllowedSections { get; }
void RemoveAllowedSection(string sectionAlias);
void AddAllowedSection(string sectionAlias);
void ClearAllowedSections();
/// <summary>
/// Specifies the number of users assigned to this group
/// </summary>
int UserCount { get; }
}
}
+27 -16
View File
@@ -1,17 +1,28 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models.Membership
{
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
public interface IUserType : IAggregateRoot
{
string Alias { get; set; }
string Name { get; set; }
IEnumerable<string> Permissions { get; set; }
}
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Mappers;
namespace Umbraco.Core.Models.Membership
{
public interface IUserType : IAggregateRoot
{
/// <summary>
/// The user type alias
/// </summary>
string Alias { get; set; }
/// <summary>
/// The user type name
/// </summary>
string Name { get; set; }
/// <summary>
/// The set of default permissions for the user type
/// </summary>
/// <remarks>
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
/// </remarks>
IEnumerable<string> Permissions { get; set; }
}
}
@@ -1,70 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Models.Membership
{
public class ReadOnlyUserGroup : IReadOnlyUserGroup, IEquatable<ReadOnlyUserGroup>
{
public ReadOnlyUserGroup(int id, string name, string icon, int? startContentId, int? startMediaId, string @alias,
IEnumerable<string> allowedSections, IEnumerable<string> permissions)
{
Name = name;
Icon = icon;
Id = id;
Alias = alias;
AllowedSections = allowedSections.ToArray();
Permissions = permissions.ToArray();
//Zero is invalid and will be treated as Null
StartContentId = startContentId == 0 ? null : startContentId;
StartMediaId = startMediaId == 0 ? null : startMediaId;
}
public int Id { get; private set; }
public string Name { get; private set; }
public string Icon { get; private set; }
public int? StartContentId { get; private set; }
public int? StartMediaId { get; private set; }
public string Alias { get; private set; }
/// <summary>
/// The set of default permissions
/// </summary>
/// <remarks>
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
/// </remarks>
public IEnumerable<string> Permissions { get; set; }
public IEnumerable<string> AllowedSections { get; private set; }
public bool Equals(ReadOnlyUserGroup other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(Alias, other.Alias);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((ReadOnlyUserGroup) obj);
}
public override int GetHashCode()
{
return Alias.GetHashCode();
}
public static bool operator ==(ReadOnlyUserGroup left, ReadOnlyUserGroup right)
{
return Equals(left, right);
}
public static bool operator !=(ReadOnlyUserGroup left, ReadOnlyUserGroup right)
{
return !Equals(left, right);
}
}
}
@@ -34,11 +34,12 @@ namespace Umbraco.Core.Models.Membership
/// <param name="lastLockoutDate">The last lockout date.</param>
/// <param name="fullName">The full name.</param>
/// <param name="language">The language.</param>
/// <param name="userType">Type of the user.</param>
/// <param name="user"></param>
public UmbracoMembershipUser(string providerName, string name, object providerUserKey, string email,
string passwordQuestion, string comment, bool isApproved, bool isLockedOut,
DateTime creationDate, DateTime lastLoginDate, DateTime lastActivityDate, DateTime lastPasswordChangedDate,
DateTime lastLockoutDate, string fullName, string language, T user)
DateTime lastLockoutDate, string fullName, string language, IUserType userType, T user)
: base( providerName, name, providerUserKey, email, passwordQuestion, comment, isApproved, isLockedOut,
creationDate, lastLoginDate, lastActivityDate, lastPasswordChangedDate, lastLockoutDate)
{
+127 -390
View File
@@ -2,14 +2,13 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
@@ -17,109 +16,66 @@ namespace Umbraco.Core.Models.Membership
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
public class User : Entity, IUser, IProfile
public class User : Entity, IUser
{
/// <summary>
/// Constructor for creating a new/empty user
/// </summary>
public User()
public User(IUserType userType)
{
if (userType == null) throw new ArgumentNullException("userType");
_userType = userType;
_defaultPermissions = _userType.Permissions == null ? Enumerable.Empty<string>() : new List<string>(_userType.Permissions);
//Groups = new List<object> { userType };
SessionTimeout = 60;
_userGroups = new HashSet<IReadOnlyUserGroup>();
_sectionCollection = new ObservableCollection<string>();
_addedSections = new List<string>();
_removedSections = new List<string>();
_language = GlobalSettings.DefaultUILanguage;
_sectionCollection.CollectionChanged += SectionCollectionChanged;
_isApproved = true;
_isLockedOut = false;
_startContentIds = new int[] { };
_startMediaIds = new int[] { };
_startContentId = -1;
_startMediaId = -1;
//cannot be null
_rawPasswordValue = "";
}
/// <summary>
/// Constructor for creating a new/empty user
/// </summary>
/// <param name="name"></param>
/// <param name="email"></param>
/// <param name="username"></param>
/// <param name="rawPasswordValue"></param>
public User(string name, string email, string username, string rawPasswordValue)
: this()
public User(string name, string email, string username, string rawPasswordValue, IUserType userType)
: this(userType)
{
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", "name");
if (string.IsNullOrWhiteSpace(email)) throw new ArgumentException("Value cannot be null or whitespace.", "email");
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", "username");
if (string.IsNullOrEmpty(rawPasswordValue)) throw new ArgumentException("Value cannot be null or empty.", "rawPasswordValue");
_name = name;
_email = email;
_username = username;
_rawPasswordValue = rawPasswordValue;
_userGroups = new HashSet<IReadOnlyUserGroup>();
_isApproved = true;
_isLockedOut = false;
_startContentIds = new int[] { };
_startMediaIds = new int[] { };
}
/// <summary>
/// Constructor for creating a new User instance for an existing user
/// </summary>
/// <param name="id"></param>
/// <param name="name"></param>
/// <param name="email"></param>
/// <param name="username"></param>
/// <param name="rawPasswordValue"></param>
/// <param name="userGroups"></param>
/// <param name="startContentIds"></param>
/// <param name="startMediaIds"></param>
public User(int id, string name, string email, string username, string rawPasswordValue, IEnumerable<IReadOnlyUserGroup> userGroups, int[] startContentIds, int[] startMediaIds)
: this()
{
//we allow whitespace for this value so just check null
if (rawPasswordValue == null) throw new ArgumentNullException("rawPasswordValue");
if (userGroups == null) throw new ArgumentNullException("userGroups");
if (startContentIds == null) throw new ArgumentNullException("startContentIds");
if (startMediaIds == null) throw new ArgumentNullException("startMediaIds");
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", "name");
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", "username");
Id = id;
_name = name;
_email = email;
_username = username;
_rawPasswordValue = rawPasswordValue;
_userGroups = new HashSet<IReadOnlyUserGroup>(userGroups);
_isApproved = true;
_isLockedOut = false;
_startContentIds = startContentIds;
_startMediaIds = startMediaIds;
_startContentId = -1;
_startMediaId = -1;
}
private IUserType _userType;
private string _name;
private string _securityStamp;
private string _avatar;
private List<string> _addedSections;
private List<string> _removedSections;
private ObservableCollection<string> _sectionCollection;
private int _sessionTimeout;
private int[] _startContentIds;
private int[] _startMediaIds;
private int _startContentId;
private int _startMediaId;
private int _failedLoginAttempts;
private string _username;
private DateTime? _emailConfirmedDate;
private DateTime? _invitedDate;
private string _email;
private string _rawPasswordValue;
private IEnumerable<string> _allowedSections;
private HashSet<IReadOnlyUserGroup> _userGroups;
private bool _isApproved;
private bool _isLockedOut;
private string _language;
private DateTime _lastPasswordChangedDate;
private DateTime _lastLoginDate;
private DateTime _lastLockoutDate;
private IEnumerable<string> _defaultPermissions;
private bool _defaultToLiveEditing;
private IDictionary<string, object> _additionalData;
private object _additionalDataLock = new object();
private static readonly Lazy<PropertySelectors> Ps = new Lazy<PropertySelectors>();
@@ -131,10 +87,10 @@ namespace Umbraco.Core.Models.Membership
public readonly PropertyInfo LastPasswordChangeDateSelector = ExpressionHelper.GetPropertyInfo<User, DateTime>(x => x.LastPasswordChangeDate);
public readonly PropertyInfo SecurityStampSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.SecurityStamp);
public readonly PropertyInfo AvatarSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Avatar);
public readonly PropertyInfo SessionTimeoutSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.SessionTimeout);
public readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo<User, int[]>(x => x.StartContentIds);
public readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<User, int[]>(x => x.StartMediaIds);
public readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartContentId);
public readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartMediaId);
public readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<string>>(x => x.AllowedSections);
public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Name);
public readonly PropertyInfo UsernameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Username);
@@ -143,18 +99,9 @@ namespace Umbraco.Core.Models.Membership
public readonly PropertyInfo IsLockedOutSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.IsLockedOut);
public readonly PropertyInfo IsApprovedSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.IsApproved);
public readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Language);
public readonly PropertyInfo EmailConfirmedDateSelector = ExpressionHelper.GetPropertyInfo<User, DateTime?>(x => x.EmailConfirmedDate);
public readonly PropertyInfo InvitedDateSelector = ExpressionHelper.GetPropertyInfo<User, DateTime?>(x => x.InvitedDate);
public readonly PropertyInfo DefaultToLiveEditingSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.DefaultToLiveEditing);
public readonly PropertyInfo UserGroupsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<IReadOnlyUserGroup>>(x => x.Groups);
//Custom comparer for enumerable
public readonly DelegateEqualityComparer<IEnumerable<int>> IntegerEnumerableComparer =
new DelegateEqualityComparer<IEnumerable<int>>(
(enum1, enum2) => enum1.UnsortedSequenceEqual(enum2),
enum1 => enum1.GetHashCode());
public readonly PropertyInfo UserTypeSelector = ExpressionHelper.GetPropertyInfo<User, IUserType>(x => x.UserType);
}
#region Implementation of IMembershipUser
@@ -165,19 +112,8 @@ namespace Umbraco.Core.Models.Membership
get { return Id; }
set { throw new NotSupportedException("Cannot set the provider user key for a user"); }
}
[DataMember]
public DateTime? EmailConfirmedDate
{
get { return _emailConfirmedDate; }
set { SetPropertyValueAndDetectChanges(value, ref _emailConfirmedDate, Ps.Value.EmailConfirmedDateSelector); }
}
[DataMember]
public DateTime? InvitedDate
{
get { return _invitedDate; }
set { SetPropertyValueAndDetectChanges(value, ref _invitedDate, Ps.Value.InvitedDateSelector); }
}
[DataMember]
public string Username
{
@@ -253,22 +189,6 @@ namespace Umbraco.Core.Models.Membership
#region Implementation of IUser
public UserState UserState
{
get
{
if (LastLoginDate == default(DateTime) && IsApproved == false && InvitedDate != null)
return UserState.Invited;
if (IsLockedOut)
return UserState.LockedOut;
if (IsApproved == false)
return UserState.Disabled;
return UserState.Active;
}
}
[DataMember]
public string Name
{
@@ -278,175 +198,28 @@ namespace Umbraco.Core.Models.Membership
public IEnumerable<string> AllowedSections
{
get { return _allowedSections ?? (_allowedSections = new List<string>(_userGroups.SelectMany(x => x.AllowedSections).Distinct())); }
get { return _sectionCollection; }
}
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
IUserType IUser.UserType
public void RemoveAllowedSection(string sectionAlias)
{
get
if (_sectionCollection.Contains(sectionAlias))
{
//the best we can do here is to return the user's first user group as a IUserType object
//but we should attempt to return any group that is the built in ones first
var groups = Groups.ToArray();
if (groups.Length == 0)
{
//In backwards compatibility land, a user type cannot be null! so we need to return a fake one.
return new UserType
{
Alias = "temp",
Id = int.MinValue,
Key = Guid.Empty,
CreateDate = default(DateTime),
DeletedDate = null,
Name = "Temp",
Permissions = new List<string>(),
UpdateDate = default(DateTime)
};
}
var builtIns = new[] { Constants.Security.AdminGroupAlias, "writer", "editor", "translator" };
var foundBuiltIn = groups.FirstOrDefault(x => builtIns.Contains(x.Alias));
IUserGroup realGroup;
if (foundBuiltIn != null)
{
//if the group isn't IUserGroup we'll need to look it up
realGroup = foundBuiltIn as IUserGroup ?? ApplicationContext.Current.Services.UserService.GetUserGroupById(foundBuiltIn.Id);
//return a mapped version of the group
return new UserType
{
Alias = realGroup.Alias,
Id = realGroup.Id,
Key = realGroup.Key,
CreateDate = realGroup.CreateDate,
DeletedDate = realGroup.DeletedDate,
Name = realGroup.Name,
Permissions = realGroup.Permissions,
UpdateDate = realGroup.UpdateDate
};
}
//otherwise return the first
//if the group isn't IUserGroup we'll need to look it up
realGroup = groups[0] as IUserGroup ?? ApplicationContext.Current.Services.UserService.GetUserGroupById(groups[0].Id);
//return a mapped version of the group
return new UserType
{
Alias = realGroup.Alias,
Id = realGroup.Id,
Key = realGroup.Key,
CreateDate = realGroup.CreateDate,
DeletedDate = realGroup.DeletedDate,
Name = realGroup.Name,
Permissions = realGroup.Permissions,
UpdateDate = realGroup.UpdateDate
};
_sectionCollection.Remove(sectionAlias);
}
set
{
//if old APIs are still using this lets first check if the user is part of the user group with the alias specified
if (Groups.Any(x => x.Alias == value.Alias))
return;
//the only other option we have here is to lookup the group (and we'll need to use singletons here :( )
var found = ApplicationContext.Current.Services.UserService.GetUserGroupByAlias(value.Alias);
if (found == null)
throw new InvalidOperationException("No user group was found with the alias " + value.Alias + ", this API (IUser.UserType) is obsolete, use user groups instead");
//if it's found, all we can do is add it, we can't really replace them
AddGroup(found.ToReadOnlyGroup());
}
}
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
void IUser.RemoveAllowedSection(string sectionAlias)
{
//don't do anything if they aren't allowed it already
if (AllowedSections.Contains(sectionAlias) == false)
return;
var groups = Groups.ToArray();
//our only option here is to check if a custom group is created for this user, if so we can remove it from that group, otherwise we'll throw
//now we'll check if the user has a special 1:1 user group created for itself. This will occur if this method is used and also during an upgrade.
//this comes in the alias form of userName + 'Group'
var customUserGroup = groups.FirstOrDefault(x => x.Alias == (Username + "Group"));
if (customUserGroup != null)
{
//if the group isn't IUserGroup we'll need to look it up
var realGroup = customUserGroup as IUserGroup ?? ApplicationContext.Current.Services.UserService.GetUserGroupById(customUserGroup.Id);
realGroup.RemoveAllowedSection(sectionAlias);
//now we need to flag this for saving (hack!)
GroupsToSave.Add(realGroup);
}
else
{
throw new InvalidOperationException("Cannot remove the allowed section using this obsolete API. Modify the user's groups instead");
}
}
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
void IUser.AddAllowedSection(string sectionAlias)
public void AddAllowedSection(string sectionAlias)
{
//don't do anything if they are allowed it already
if (AllowedSections.Contains(sectionAlias))
return;
//This is here for backwards compat only.
//First we'll check if the user is part of the 'admin' group. If so then we can ensure that the admin group has this section available to it.
//otherwise, the only thing we can do is create a custom user group for this user and add this section.
//We are checking for admin here because if the user is an admin and an allowed section is being added, then it's assumed it's to be added
//for the whole admin group (i.e. Forms installer does this for admins)
var groups = Groups.ToArray();
var admin = groups.FirstOrDefault(x => x.Alias == Constants.Security.AdminGroupAlias);
if (admin != null)
if (_sectionCollection.Contains(sectionAlias) == false)
{
//if the group isn't IUserGroup we'll need to look it up
var realGroup = admin as IUserGroup ?? ApplicationContext.Current.Services.UserService.GetUserGroupById(admin.Id);
realGroup.AddAllowedSection(sectionAlias);
//now we need to flag this for saving (hack!)
GroupsToSave.Add(realGroup);
_sectionCollection.Add(sectionAlias);
}
else
{
//now we'll check if the user has a special 1:1 user group created for itself. This will occur if this method is used and also during an upgrade.
//this comes in the alias form of userName + 'Group'
var customUserGroup = groups.FirstOrDefault(x => x.Alias == (Username + "Group"));
if (customUserGroup != null)
{
//if the group isn't IUserGroup we'll need to look it up
var realGroup = customUserGroup as IUserGroup ?? ApplicationContext.Current.Services.UserService.GetUserGroupById(customUserGroup.Id);
realGroup.AddAllowedSection(sectionAlias);
//now we need to flag this for saving (hack!)
GroupsToSave.Add(realGroup);
}
//ok, so the user doesn't have a 1:1 group, we'll need to flag it for creation
var newUserGroup = new UserGroup
{
Alias = Username + "Group",
Name = "Group for " + Username
};
newUserGroup.AddAllowedSection(sectionAlias);
//add this user to this new group
AddGroup(newUserGroup);
GroupsToSave.Add(newUserGroup);
}
}
/// <summary>
/// This used purely for hacking backwards compatibility into this class for &lt; 7.7 compat
/// </summary>
[DoNotClone]
[IgnoreDataMember]
internal List<IUserGroup> GroupsToSave = new List<IUserGroup>();
}
public IProfile ProfileData
{
get { return new WrappedUserProfile(this); }
get { return new UserProfile(this); }
}
/// <summary>
@@ -459,12 +232,21 @@ namespace Umbraco.Core.Models.Membership
set { SetPropertyValueAndDetectChanges(value, ref _securityStamp, Ps.Value.SecurityStampSelector); }
}
[DataMember]
public string Avatar
/// <summary>
/// Used internally to check if we need to add a section in the repository to the db
/// </summary>
internal IEnumerable<string> AddedSections
{
get { return _avatar; }
set { SetPropertyValueAndDetectChanges(value, ref _avatar, Ps.Value.AvatarSelector); }
}
get { return _addedSections; }
}
/// <summary>
/// Used internally to check if we need to remove a section in the repository to the db
/// </summary>
internal IEnumerable<string> RemovedSections
{
get { return _removedSections; }
}
/// <summary>
/// Gets or sets the session timeout.
@@ -479,18 +261,6 @@ namespace Umbraco.Core.Models.Membership
set { SetPropertyValueAndDetectChanges(value, ref _sessionTimeout, Ps.Value.SessionTimeoutSelector); }
}
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
int IUser.StartContentId
{
get
{
var calculatedStartNodes = this.CalculateContentStartNodeIds(ApplicationContext.Current.Services.EntityService);
return calculatedStartNodes.Length == 0 ? -1 : calculatedStartNodes[0];
}
set { StartContentIds = new[] { value }; }
}
/// <summary>
/// Gets or sets the start content id.
/// </summary>
@@ -498,25 +268,12 @@ namespace Umbraco.Core.Models.Membership
/// The start content id.
/// </value>
[DataMember]
[DoNotClone]
public int[] StartContentIds
public int StartContentId
{
get { return _startContentIds; }
set { SetPropertyValueAndDetectChanges(value, ref _startContentIds, Ps.Value.StartContentIdSelector, Ps.Value.IntegerEnumerableComparer); }
get { return _startContentId; }
set { SetPropertyValueAndDetectChanges(value, ref _startContentId, Ps.Value.StartContentIdSelector); }
}
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
int IUser.StartMediaId
{
get
{
var calculatedStartNodes = this.CalculateMediaStartNodeIds(ApplicationContext.Current.Services.EntityService);
return calculatedStartNodes.Length == 0 ? -1 : calculatedStartNodes[0];
}
set { StartMediaIds = new[] {value}; }
}
/// <summary>
/// Gets or sets the start media id.
/// </summary>
@@ -524,11 +281,10 @@ namespace Umbraco.Core.Models.Membership
/// The start media id.
/// </value>
[DataMember]
[DoNotClone]
public int[] StartMediaIds
public int StartMediaId
{
get { return _startMediaIds; }
set { SetPropertyValueAndDetectChanges(value, ref _startMediaIds, Ps.Value.StartMediaIdSelector, Ps.Value.IntegerEnumerableComparer); }
get { return _startMediaId; }
set { SetPropertyValueAndDetectChanges(value, ref _startMediaId, Ps.Value.StartMediaIdSelector); }
}
[DataMember]
@@ -538,6 +294,14 @@ namespace Umbraco.Core.Models.Membership
set { SetPropertyValueAndDetectChanges(value, ref _language, Ps.Value.LanguageSelector); }
}
//TODO: This should be a private set
[DataMember]
public IEnumerable<string> DefaultPermissions
{
get { return _defaultPermissions;}
set { _defaultPermissions = value; }
}
[IgnoreDataMember]
internal bool DefaultToLiveEditing
{
@@ -545,107 +309,78 @@ namespace Umbraco.Core.Models.Membership
set { SetPropertyValueAndDetectChanges(value, ref _defaultToLiveEditing, Ps.Value.DefaultToLiveEditingSelector); }
}
/// <summary>
/// Gets the groups that user is part of
/// </summary>
[DataMember]
public IEnumerable<IReadOnlyUserGroup> Groups
[IgnoreDataMember]
public IUserType UserType
{
get { return _userGroups; }
}
public void RemoveGroup(string group)
{
foreach (var userGroup in _userGroups.ToArray())
get { return _userType; }
set
{
if (userGroup.Alias == group)
if (value.HasIdentity == false)
{
_userGroups.Remove(userGroup);
//reset this flag so it's rebuilt with the assigned groups
_allowedSections = null;
OnPropertyChanged(Ps.Value.UserGroupsSelector);
throw new InvalidOperationException("Cannot assign a User Type that has not been persisted");
}
SetPropertyValueAndDetectChanges(value, ref _userType, Ps.Value.UserTypeSelector);
}
}
public void ClearGroups()
{
if (_userGroups.Count > 0)
{
_userGroups.Clear();
//reset this flag so it's rebuilt with the assigned groups
_allowedSections = null;
OnPropertyChanged(Ps.Value.UserGroupsSelector);
}
}
public void AddGroup(IReadOnlyUserGroup group)
{
if (_userGroups.Add(group))
{
//reset this flag so it's rebuilt with the assigned groups
_allowedSections = null;
OnPropertyChanged(Ps.Value.UserGroupsSelector);
}
}
#endregion
/// <summary>
/// This is used as an internal cache for this entity - specifically for calculating start nodes so we don't re-calculated all of the time
/// Whenever resetting occurs, clear the remembered add/removed collections, even if
/// rememberPreviouslyChangedProperties is true, the AllowedSections property will still
/// be flagged as dirty.
/// </summary>
[IgnoreDataMember]
[DoNotClone]
internal IDictionary<string, object> AdditionalData
/// <param name="rememberPreviouslyChangedProperties"></param>
public override void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
{
get
{
lock (_additionalDataLock)
{
return _additionalData ?? (_additionalData = new Dictionary<string, object>());
}
}
_addedSections.Clear();
_removedSections.Clear();
base.ResetDirtyProperties(rememberPreviouslyChangedProperties);
}
[IgnoreDataMember]
[DoNotClone]
internal object AdditionalDataLock { get { return _additionalDataLock; } }
/// <summary>
/// Handles the collection changed event in order for us to flag the AllowedSections property as changed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void SectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
OnPropertyChanged(Ps.Value.AllowedSectionsSelector);
if (e.Action == NotifyCollectionChangedAction.Add)
{
var item = e.NewItems.Cast<string>().First();
if (_addedSections.Contains(item) == false)
{
_addedSections.Add(item);
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
var item = e.OldItems.Cast<string>().First();
if (_removedSections.Contains(item) == false)
{
_removedSections.Add(item);
}
}
}
public override object DeepClone()
{
var clone = (User)base.DeepClone();
//turn off change tracking
clone.DisableChangeTracking();
//manually clone the start node props
clone._startContentIds = _startContentIds.ToArray();
clone._startMediaIds = _startMediaIds.ToArray();
// this value has been cloned and points to the same object
// which obviously is bad - needs to point to a new object
clone._additionalDataLock = new object();
if (_additionalData != null)
{
// clone._additionalData points to the same dictionary, which is bad, because
// changing one clone impacts all of them - so we need to reset it with a fresh
// dictionary that will contain the same values - and, if some values are deep
// cloneable, they should be deep-cloned too
var cloneAdditionalData = clone._additionalData = new Dictionary<string, object>();
lock (_additionalDataLock)
{
foreach (var kvp in _additionalData)
{
var deepCloneable = kvp.Value as IDeepCloneable;
cloneAdditionalData[kvp.Key] = deepCloneable == null ? kvp.Value : deepCloneable.DeepClone();
}
}
}
//need to create new collections otherwise they'll get copied by ref
clone._userGroups = new HashSet<IReadOnlyUserGroup>(_userGroups);
clone._allowedSections = _allowedSections != null ? new List<string>(_allowedSections) : null;
clone._addedSections = new List<string>();
clone._removedSections = new List<string>();
clone._sectionCollection = new ObservableCollection<string>(_sectionCollection.ToList());
clone._defaultPermissions = new List<string>(_defaultPermissions.ToList());
//re-create the event handler
clone._sectionCollection.CollectionChanged += clone.SectionCollectionChanged;
//this shouldn't really be needed since we're not tracking
clone.ResetDirtyProperties(false);
//re-enable tracking
@@ -657,26 +392,28 @@ namespace Umbraco.Core.Models.Membership
/// <summary>
/// Internal class used to wrap the user in a profile
/// </summary>
private class WrappedUserProfile : IProfile
private class UserProfile : IProfile
{
private readonly IUser _user;
public WrappedUserProfile(IUser user)
public UserProfile(IUser user)
{
_user = user;
}
public int Id
public object Id
{
get { return _user.Id; }
set { _user.Id = (int)value; }
}
public string Name
{
get { return _user.Name; }
set { _user.Name = value; }
}
private bool Equals(WrappedUserProfile other)
protected bool Equals(UserProfile other)
{
return _user.Equals(other._user);
}
@@ -686,7 +423,7 @@ namespace Umbraco.Core.Models.Membership
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((WrappedUserProfile) obj);
return Equals((UserProfile) obj);
}
public override int GetHashCode()
+6 -141
View File
@@ -1,155 +1,20 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents a Group for a Backoffice User
/// </summary>
/// <remarks>
/// Should be internal until a proper user/membership implementation
/// is part of the roadmap.
/// </remarks>
[Serializable]
[DataContract(IsReference = true)]
public class UserGroup : Entity, IUserGroup, IReadOnlyUserGroup
internal class UserGroup : Entity
{
private int? _startContentId;
private int? _startMediaId;
private string _alias;
private string _icon;
private string _name;
private IEnumerable<string> _permissions;
private readonly List<string> _sectionCollection;
private static readonly Lazy<PropertySelectors> Ps = new Lazy<PropertySelectors>();
private class PropertySelectors
{
public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<UserGroup, string>(x => x.Name);
public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<UserGroup, string>(x => x.Alias);
public readonly PropertyInfo PermissionsSelector = ExpressionHelper.GetPropertyInfo<UserGroup, IEnumerable<string>>(x => x.Permissions);
public readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo<UserGroup, string>(x => x.Icon);
public readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo<UserGroup, int?>(x => x.StartContentId);
public readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<UserGroup, int?>(x => x.StartMediaId);
//Custom comparer for enumerable
public readonly DelegateEqualityComparer<IEnumerable<string>> StringEnumerableComparer =
new DelegateEqualityComparer<IEnumerable<string>>(
(enum1, enum2) => enum1.UnsortedSequenceEqual(enum2),
enum1 => enum1.GetHashCode());
}
/// <summary>
/// Constructor to create a new user group
/// </summary>
public UserGroup()
{
_sectionCollection = new List<string>();
}
/// <summary>
/// Constructor to create an existing user group
/// </summary>
/// <param name="userCount"></param>
/// <param name="alias"></param>
/// <param name="name"></param>
/// <param name="permissions"></param>
/// <param name="icon"></param>
public UserGroup(int userCount, string alias, string name, IEnumerable<string> permissions, string icon)
: this()
{
UserCount = userCount;
_alias = alias;
_name = name;
_permissions = permissions;
_icon = icon;
}
[DataMember]
public int? StartMediaId
{
get { return _startMediaId; }
set { SetPropertyValueAndDetectChanges(value, ref _startMediaId, Ps.Value.StartMediaIdSelector); }
}
[DataMember]
public int? StartContentId
{
get { return _startContentId; }
set { SetPropertyValueAndDetectChanges(value, ref _startContentId, Ps.Value.StartContentIdSelector); }
}
[DataMember]
public string Icon
{
get { return _icon; }
set { SetPropertyValueAndDetectChanges(value, ref _icon, Ps.Value.IconSelector); }
}
[DataMember]
public string Alias
{
get { return _alias; }
set
{
SetPropertyValueAndDetectChanges(
value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase),
ref _alias,
Ps.Value.AliasSelector);
}
}
[DataMember]
public string Name
{
get { return _name; }
set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); }
}
/// <summary>
/// The set of default permissions for the user group
/// </summary>
/// <remarks>
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
/// </remarks>
[DataMember]
public IEnumerable<string> Permissions
{
get { return _permissions; }
set
{
SetPropertyValueAndDetectChanges(value, ref _permissions, Ps.Value.PermissionsSelector,
Ps.Value.StringEnumerableComparer);
}
}
public IEnumerable<string> AllowedSections
{
get { return _sectionCollection; }
}
public void RemoveAllowedSection(string sectionAlias)
{
if (_sectionCollection.Contains(sectionAlias))
{
_sectionCollection.Remove(sectionAlias);
}
}
public void AddAllowedSection(string sectionAlias)
{
if (_sectionCollection.Contains(sectionAlias) == false)
{
_sectionCollection.Add(sectionAlias);
}
}
public void ClearAllowedSections()
{
_sectionCollection.Clear();
}
public int UserCount { get; private set; }
//Add UserCollection ?
}
}
@@ -1,26 +0,0 @@
using Umbraco.Core.Models.Rdbms;
using System.Linq;
namespace Umbraco.Core.Models.Membership
{
internal static class UserGroupExtensions
{
public static IReadOnlyUserGroup ToReadOnlyGroup(this IUserGroup group)
{
//this will generally always be the case
var readonlyGroup = group as IReadOnlyUserGroup;
if (readonlyGroup != null) return readonlyGroup;
//otherwise create one
return new ReadOnlyUserGroup(group.Id, group.Name, group.Icon, group.StartContentId, group.StartMediaId, group.Alias, group.AllowedSections, group.Permissions);
}
public static IReadOnlyUserGroup ToReadOnlyGroup(this UserGroupDto group)
{
return new ReadOnlyUserGroup(group.Id, group.Name, group.Icon,
group.StartContentId, group.StartMediaId, group.Alias,
group.UserGroup2AppDtos.Select(x => x.AppAlias).ToArray(),
group.DefaultPermissions == null ? Enumerable.Empty<string>() : group.DefaultPermissions.ToCharArray().Select(x => x.ToString()));
}
}
}
@@ -1,46 +0,0 @@
using System;
namespace Umbraco.Core.Models.Membership
{
internal class UserProfile : IProfile, IEquatable<UserProfile>
{
public UserProfile(int id, string name)
{
Id = id;
Name = name;
}
public int Id { get; private set; }
public string Name { get; private set; }
public bool Equals(UserProfile other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Id == other.Id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((UserProfile) obj);
}
public override int GetHashCode()
{
return Id;
}
public static bool operator ==(UserProfile left, UserProfile right)
{
return Equals(left, right);
}
public static bool operator !=(UserProfile left, UserProfile right)
{
return Equals(left, right) == false;
}
}
}
@@ -1,14 +0,0 @@
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// The state of a user
/// </summary>
public enum UserState
{
All = -1,
Active = 0,
Disabled = 1,
LockedOut = 2,
Invited = 3
}
}
+71 -67
View File
@@ -1,68 +1,72 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Models.Membership
{
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
[Serializable]
[DataContract(IsReference = true)]
internal class UserType : Entity, IUserType
{
private string _alias;
private string _name;
private IEnumerable<string> _permissions;
private static readonly Lazy<PropertySelectors> Ps = new Lazy<PropertySelectors>();
private class PropertySelectors
{
public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<UserType, string>(x => x.Name);
public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<UserType, string>(x => x.Alias);
public readonly PropertyInfo PermissionsSelector = ExpressionHelper.GetPropertyInfo<UserType, IEnumerable<string>>(x => x.Permissions);
}
[DataMember]
public string Alias
{
get { return _alias; }
set
{
SetPropertyValueAndDetectChanges(
value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase),
ref _alias,
Ps.Value.AliasSelector);
}
}
[DataMember]
public string Name
{
get { return _name; }
set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); }
}
/// <summary>
/// The set of default permissions for the user type
/// </summary>
/// <remarks>
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
/// </remarks>
[DataMember]
public IEnumerable<string> Permissions
{
get { return _permissions; }
set
{
SetPropertyValueAndDetectChanges(value, ref _permissions, Ps.Value.PermissionsSelector,
//Custom comparer for enumerable
new DelegateEqualityComparer<IEnumerable<string>>(
(enum1, enum2) => enum1.UnsortedSequenceEqual(enum2),
enum1 => enum1.GetHashCode()));
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents the Type for a Backoffice User
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
internal class UserType : Entity, IUserType
{
private string _alias;
private string _name;
private IEnumerable<string> _permissions;
private static readonly Lazy<PropertySelectors> Ps = new Lazy<PropertySelectors>();
private class PropertySelectors
{
public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<UserType, string>(x => x.Name);
public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<UserType, string>(x => x.Alias);
public readonly PropertyInfo PermissionsSelector = ExpressionHelper.GetPropertyInfo<UserType, IEnumerable<string>>(x => x.Permissions);
}
[DataMember]
public string Alias
{
get { return _alias; }
set
{
SetPropertyValueAndDetectChanges(
value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase),
ref _alias,
Ps.Value.AliasSelector);
}
}
[DataMember]
public string Name
{
get { return _name; }
set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); }
}
/// <summary>
/// The set of default permissions for the user type
/// </summary>
/// <remarks>
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
/// </remarks>
[DataMember]
public IEnumerable<string> Permissions
{
get { return _permissions; }
set
{
SetPropertyValueAndDetectChanges(value, ref _permissions, Ps.Value.PermissionsSelector,
//Custom comparer for enumerable
new DelegateEqualityComparer<IEnumerable<string>>(
(enum1, enum2) => enum1.UnsortedSequenceEqual(enum2),
enum1 => enum1.GetHashCode()));
}
}
}
}
+30 -30
View File
@@ -49,36 +49,36 @@ namespace Umbraco.Core.Models
{
public readonly PropertyInfo ValueSelector = ExpressionHelper.GetPropertyInfo<Property, object>(x => x.Value);
public readonly PropertyInfo VersionSelector = ExpressionHelper.GetPropertyInfo<Property, Guid>(x => x.Version);
public readonly DelegateEqualityComparer<object> PropertyValueComparer = new DelegateEqualityComparer<object>(
(o, o1) =>
{
if (o == null && o1 == null) return true;
//custom comparer for strings.
if (o is string || o1 is string)
{
//if one is null and another is empty then they are the same
if ((o as string).IsNullOrWhiteSpace() && (o1 as string).IsNullOrWhiteSpace())
{
return true;
}
if (o == null || o1 == null) return false;
return o.Equals(o1);
}
if (o == null || o1 == null) return false;
//Custom comparer for enumerable if it is enumerable
var enum1 = o as IEnumerable;
var enum2 = o1 as IEnumerable;
if (enum1 != null && enum2 != null)
{
return enum1.Cast<object>().UnsortedSequenceEqual(enum2.Cast<object>());
}
return o.Equals(o1);
}, o => o.GetHashCode());
}
private static readonly DelegateEqualityComparer<object> ValueComparer = new DelegateEqualityComparer<object>(
(o, o1) =>
{
if (o == null && o1 == null) return true;
//custom comparer for strings.
if (o is string || o1 is string)
{
//if one is null and another is empty then they are the same
if ((o as string).IsNullOrWhiteSpace() && (o1 as string).IsNullOrWhiteSpace())
{
return true;
}
if (o == null || o1 == null) return false;
return o.Equals(o1);
}
if (o == null || o1 == null) return false;
//Custom comparer for enumerable if it is enumerable
var enum1 = o as IEnumerable;
var enum2 = o1 as IEnumerable;
if (enum1 != null && enum2 != null)
{
return enum1.Cast<object>().UnsortedSequenceEqual(enum2.Cast<object>());
}
return o.Equals(o1);
}, o => o.GetHashCode());
/// <summary>
/// Returns the instance of the tag support, by default tags are not enabled
@@ -200,7 +200,7 @@ namespace Umbraco.Core.Models
}
}
SetPropertyValueAndDetectChanges(value, ref _value, Ps.Value.ValueSelector, Ps.Value.PropertyValueComparer);
SetPropertyValueAndDetectChanges(value, ref _value, Ps.Value.ValueSelector, ValueComparer);
}
}
@@ -24,8 +24,7 @@ namespace Umbraco.Core.Models.Rdbms
public Guid? Parent { get; set; }
[Column("key")]
[Length(450)]
[Index(IndexTypes.NonClustered, Name = "IX_cmsDictionary_key")]
[Length(1000)]
public string Key { get; set; }
[ResultColumn]
@@ -1,19 +1,20 @@
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
namespace Umbraco.Core.Models.Rdbms
{
[TableName("umbracoUserGroup2App")]
[ExplicitColumns]
internal class UserGroup2AppDto
{
[Column("userGroupId")]
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_userGroup2App", OnColumns = "userGroupId, app")]
[ForeignKey(typeof(UserGroupDto))]
public int UserGroupId { get; set; }
[Column("app")]
[Length(50)]
public string AppAlias { get; set; }
}
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
namespace Umbraco.Core.Models.Rdbms
{
[TableName("umbracoUser2app")]
[PrimaryKey("user", autoIncrement = false)]
[ExplicitColumns]
internal class User2AppDto
{
[Column("user")]
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_user2app", OnColumns = "user, app")]
[ForeignKey(typeof(UserDto))]
public int UserId { get; set; }
[Column("app")]
[Length(50)]
public string AppAlias { get; set; }
}
}
@@ -3,14 +3,15 @@ using Umbraco.Core.Persistence.DatabaseAnnotations;
namespace Umbraco.Core.Models.Rdbms
{
[TableName("umbracoUserGroup2NodePermission")]
[TableName("umbracoUser2NodePermission")]
[PrimaryKey("userId", autoIncrement = false)]
[ExplicitColumns]
internal class UserGroup2NodePermissionDto
internal class User2NodePermissionDto
{
[Column("userGroupId")]
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_umbracoUserGroup2NodePermission", OnColumns = "userGroupId, nodeId, permission")]
[ForeignKey(typeof(UserGroupDto))]
public int UserGroupId { get; set; }
[Column("userId")]
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_umbracoUser2NodePermission", OnColumns = "userId, nodeId, permission")]
[ForeignKey(typeof(UserDto))]
public int UserId { get; set; }
[Column("nodeId")]
[ForeignKey(typeof(NodeDto))]
@@ -1,19 +0,0 @@
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
namespace Umbraco.Core.Models.Rdbms
{
[TableName("umbracoUser2UserGroup")]
[ExplicitColumns]
internal class User2UserGroupDto
{
[Column("userId")]
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_user2userGroup", OnColumns = "userId, userGroupId")]
[ForeignKey(typeof(UserDto))]
public int UserId { get; set; }
[Column("userGroupId")]
[ForeignKey(typeof(UserGroupDto))]
public int UserGroupId { get; set; }
}
}
+14 -47
View File
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
@@ -11,12 +10,6 @@ namespace Umbraco.Core.Models.Rdbms
[ExplicitColumns]
internal class UserDto
{
public UserDto()
{
UserGroupDtos = new List<UserGroupDto>();
UserStartNodeDtos = new HashSet<UserStartNodeDto>();
}
[Column("id")]
[PrimaryKeyColumn(Name = "PK_user")]
public int Id { get; set; }
@@ -28,7 +21,18 @@ namespace Umbraco.Core.Models.Rdbms
[Column("userNoConsole")]
[Constraint(Default = "0")]
public bool NoConsole { get; set; }
[Column("userType")]
[ForeignKey(typeof(UserTypeDto))]
public short Type { get; set; }
[Column("startStructureID")]
public int ContentStartId { get; set; }
[Column("startMediaID")]
[NullSetting(NullSetting = NullSettings.Null)]
public int? MediaStartId { get; set; }
[Column("userName")]
public string UserName { get; set; }
@@ -40,14 +44,6 @@ namespace Umbraco.Core.Models.Rdbms
[Column("userPassword")]
[Length(500)]
public string Password { get; set; }
/// <summary>
/// This will represent a JSON structure of how the password has been created (i.e hash algorithm, iterations)
/// </summary>
[Column("passwordConfig")]
[NullSetting(NullSetting = NullSettings.Null)]
[Length(500)]
public string PasswordConfig { get; set; }
[Column("userEmail")]
public string Email { get; set; }
@@ -77,37 +73,8 @@ namespace Umbraco.Core.Models.Rdbms
[Column("lastLoginDate")]
[NullSetting(NullSetting = NullSettings.Null)]
public DateTime? LastLoginDate { get; set; }
[Column("emailConfirmedDate")]
[NullSetting(NullSetting = NullSettings.Null)]
public DateTime? EmailConfirmedDate { get; set; }
[Column("invitedDate")]
[NullSetting(NullSetting = NullSettings.Null)]
public DateTime? InvitedDate { get; set; }
[Column("createDate")]
[NullSetting(NullSetting = NullSettings.NotNull)]
[Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime CreateDate { get; set; }
[Column("updateDate")]
[NullSetting(NullSetting = NullSettings.NotNull)]
[Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime UpdateDate { get; set; }
/// <summary>
/// Will hold the media file system relative path of the users custom avatar if they uploaded one
/// </summary>
[Column("avatar")]
[NullSetting(NullSetting = NullSettings.Null)]
[Length(500)]
public string Avatar { get; set; }
[ResultColumn]
public List<UserGroupDto> UserGroupDtos { get; set; }
[ResultColumn]
public HashSet<UserStartNodeDto> UserStartNodeDtos { get; set; }
public List<User2AppDto> User2AppDtos { get; set; }
}
}
@@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
[TableName("umbracoUserGroup")]
[PrimaryKey("id")]
[ExplicitColumns]
internal class UserGroupDto
{
public UserGroupDto()
{
UserGroup2AppDtos = new List<UserGroup2AppDto>();
}
[Column("id")]
[PrimaryKeyColumn(IdentitySeed = 5)]
public int Id { get; set; }
[Column("userGroupAlias")]
[Length(200)]
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoUserGroup_userGroupAlias")]
public string Alias { get; set; }
[Column("userGroupName")]
[Length(200)]
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoUserGroup_userGroupName")]
public string Name { get; set; }
[Column("userGroupDefaultPermissions")]
[Length(50)]
[NullSetting(NullSetting = NullSettings.Null)]
public string DefaultPermissions { get; set; }
[Column("createDate")]
[NullSetting(NullSetting = NullSettings.NotNull)]
[Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime CreateDate { get; set; }
[Column("updateDate")]
[NullSetting(NullSetting = NullSettings.NotNull)]
[Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime UpdateDate { get; set; }
[Column("icon")]
[NullSetting(NullSetting = NullSettings.Null)]
public string Icon { get; set; }
[Column("startContentId")]
[NullSetting(NullSetting = NullSettings.Null)]
[ForeignKey(typeof(NodeDto), Name = "FK_startContentId_umbracoNode_id")]
public int? StartContentId { get; set; }
[Column("startMediaId")]
[NullSetting(NullSetting = NullSettings.Null)]
[ForeignKey(typeof(NodeDto), Name = "FK_startMediaId_umbracoNode_id")]
public int? StartMediaId { get; set; }
[ResultColumn]
public List<UserGroup2AppDto> UserGroup2AppDtos { get; set; }
/// <summary>
/// This is only relevant when this column is included in the results (i.e. GetUserGroupsWithUserCounts)
/// </summary>
[ResultColumn]
public int UserCount { get; set; }
}
}
@@ -1,67 +0,0 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
namespace Umbraco.Core.Models.Rdbms
{
[TableName("umbracoUserStartNode")]
[PrimaryKey("id", autoIncrement = true)]
[ExplicitColumns]
internal class UserStartNodeDto : IEquatable<UserStartNodeDto>
{
[Column("id")]
[PrimaryKeyColumn(Name = "PK_userStartNode")]
public int Id { get; set; }
[Column("userId")]
[NullSetting(NullSetting = NullSettings.NotNull)]
[ForeignKey(typeof(UserDto))]
public int UserId { get; set; }
[Column("startNode")]
[NullSetting(NullSetting = NullSettings.NotNull)]
[ForeignKey(typeof(NodeDto))]
public int StartNode { get; set; }
[Column("startNodeType")]
[NullSetting(NullSetting = NullSettings.NotNull)]
[Index(IndexTypes.UniqueNonClustered, ForColumns = "startNodeType, startNode, userId", Name = "IX_umbracoUserStartNode_startNodeType")]
public int StartNodeType { get; set; }
public enum StartNodeTypeValue
{
Content = 1,
Media = 2
}
public bool Equals(UserStartNodeDto other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Id == other.Id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((UserStartNodeDto) obj);
}
public override int GetHashCode()
{
return Id;
}
public static bool operator ==(UserStartNodeDto left, UserStartNodeDto right)
{
return Equals(left, right);
}
public static bool operator !=(UserStartNodeDto left, UserStartNodeDto right)
{
return !Equals(left, right);
}
}
}
+1 -3
View File
@@ -1,10 +1,8 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
namespace Umbraco.Core.Models.Rdbms
{
[Obsolete("Table no longer exists as of 7.6 - retained only to support migrations from previous versions")]
[TableName("umbracoUserType")]
[PrimaryKey("id")]
[ExplicitColumns]
-2
View File
@@ -51,8 +51,6 @@ namespace Umbraco.Core.Models
private string _contentTypeIcon;
private string _contentTypeThumbnail;
public static readonly UmbracoEntity Root = new UmbracoEntity(false) {Path = "-1", Name = "root", HasChildren = true};
public UmbracoEntity()
{
AdditionalData = new Dictionary<string, object>();

Some files were not shown because too many files have changed in this diff Show More