Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7
This commit is contained in:
@@ -21,14 +21,6 @@ ECHO Building Umbraco %version%
|
||||
|
||||
ReplaceIISExpressPortNumber.exe ..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj %release%
|
||||
|
||||
ECHO Installing the Microsoft.Bcl.Build package before anything else, otherwise you'd have to run build.cmd twice
|
||||
SET nuGetFolder=%CD%\..\src\packages\
|
||||
..\src\.nuget\NuGet.exe sources Remove -Name MyGetUmbracoCore >NUL
|
||||
..\src\.nuget\NuGet.exe sources Add -Name MyGetUmbracoCore -Source https://www.myget.org/F/umbracocore/api/v2/ >NUL
|
||||
..\src\.nuget\NuGet.exe install ..\src\Umbraco.Web.UI\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
..\src\.nuget\NuGet.exe install ..\src\umbraco.businesslogic\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
..\src\.nuget\NuGet.exe install ..\src\Umbraco.Core\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
|
||||
ECHO Removing the belle build folder and bower_components folder to make sure everything is clean as a whistle
|
||||
RD ..\src\Umbraco.Web.UI.Client\build /Q /S
|
||||
RD ..\src\Umbraco.Web.UI.Client\bower_components /Q /S
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
<dependencies>
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[5.2.3,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.3,6.0.0)" />
|
||||
<dependency id="Microsoft.Net.Http" version="[2.2.29, 3.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.1, 3.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)" />
|
||||
@@ -37,6 +36,7 @@
|
||||
<dependency id="ImageProcessor.Web" version="[4.5.1, 5.0.0)" />
|
||||
<dependency id="semver" version="[1.1.2, 2.0.0)" />
|
||||
<dependency id="UrlRewritingNet" version="[2.0.7, 3.0.0)" />
|
||||
<dependency id="Markdown" version="[1.14.4, 2.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
@@ -72,6 +72,7 @@
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.xml" target="lib\UmbracoExamine.xml" />
|
||||
<file src="tools\install.core.ps1" target="tools\install.ps1" />
|
||||
<file src="tools\uninstall.core.ps1" target="tools\uninstall.ps1" />
|
||||
|
||||
<!-- Added to be able to produce a symbols package -->
|
||||
<file src="..\_BuildOutput\bin\SQLCE4Umbraco.pdb" target="lib" />
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.5, 7.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder.AspNet" version="[3.0.0-beta006, 3.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.0-RC1, 3.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
@@ -33,9 +33,11 @@
|
||||
<file src="..\_BuildOutput\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
|
||||
<file src="..\_BuildOutput\WebApp\umbraco_client\**" target="UmbracoFiles\umbraco_client" />
|
||||
<file src="tools\install.ps1" target="tools\install.ps1" />
|
||||
<file src="tools\uninstall.ps1" target="tools\uninstall.ps1" />
|
||||
<file src="tools\Readme.txt" target="tools\Readme.txt" />
|
||||
<file src="tools\ReadmeUpgrade.txt" target="tools\ReadmeUpgrade.txt" />
|
||||
<file src="tools\Web.config.install.xdt" target="Content\Web.config.install.xdt" />
|
||||
<file src="tools\Web.config.uninstall.xdt" target="Content\Web.config.uninstall.xdt" />
|
||||
<file src="tools\applications.config.install.xdt" target="Content\config\applications.config.install.xdt" />
|
||||
<file src="tools\ClientDependency.config.install.xdt" target="Content\config\ClientDependency.config.install.xdt" />
|
||||
<file src="tools\Dashboard.config.install.xdt" target="Content\config\Dashboard.config.install.xdt" />
|
||||
|
||||
@@ -77,4 +77,8 @@
|
||||
<section alias="uGoLiveDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="Remove" />
|
||||
|
||||
<section alias="ExamineManagement" xdt:Locator="Match(alias)" xdt:Transform="Remove" />
|
||||
|
||||
<section alias="StartupDashboardSection">
|
||||
<tab caption="Change Password" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
|
||||
</section>
|
||||
</dashBoard>
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
Don't forget to build!
|
||||
|
||||
|
||||
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
|
||||
file (and config files in the config folder).
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
Don't forget to build!
|
||||
|
||||
|
||||
We've done our best to transform your configuration files but in case something is not quite right: remember we
|
||||
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.1" newVersion="4.0.0.1" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Web.WebPages.Razor" publicKeyToken="31bf3856ad364e35" />
|
||||
|
||||
90
build/NuSpecs/tools/Web.config.uninstall.xdt
Normal file
90
build/NuSpecs/tools/Web.config.uninstall.xdt
Normal file
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
|
||||
<configSections xdt:Transform="InsertIfMissing" />
|
||||
<configSections>
|
||||
<section name="BaseRestExtensions" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<section name="FileSystemProviders" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<section name="ExamineLuceneIndexSets" type="Examine.LuceneEngine.Config.IndexSets, Examine" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<sectionGroup name="applicationSettings" xdt:Locator="Match(name)">
|
||||
<section name="umbraco.presentation.Properties.Settings" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
</sectionGroup>
|
||||
<sectionGroup name="system.web.webPages.razor" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<sectionGroup name="umbracoConfiguration" xdt:Locator="Match(name)" xdt:Transform="Remove"/>
|
||||
</configSections>
|
||||
|
||||
<ExamineLuceneIndexSets xdt:Transform="Remove"/>
|
||||
<urlrewritingnet xdt:Transform="Remove"/>
|
||||
<microsoft.scripting xdt:Transform="Remove"/>
|
||||
<clientDependency xdt:Transform="Remove"/>
|
||||
<Examine xdt:Transform="Remove"/>
|
||||
<log4net xdt:Transform="Remove"/>
|
||||
|
||||
<appSettings>
|
||||
<add key="umbracoConfigurationStatus" xdt:Locator="Match(key)" xdt:Transform="Remove"/>
|
||||
<add key="umbracoReservedUrls" xdt:Locator="Match(key)" xdt:Transform="Remove"/>
|
||||
<add key="umbracoReservedPaths" xdt:Locator="Match(key)" xdt:Transform="Remove"/>
|
||||
<add key="umbracoPath" xdt:Locator="Match(key)" xdt:Transform="Remove"/>
|
||||
<add key="umbracoHideTopLevelNodeFromPath" xdt:Locator="Match(key)" xdt:Transform="Remove"/>
|
||||
<add key="umbracoUseDirectoryUrls" xdt:Locator="Match(key)" xdt:Transform="Remove"/>
|
||||
<add key="umbracoTimeOutInMinutes" xdt:Locator="Match(key)" xdt:Transform="Remove"/>
|
||||
<add key="umbracoDefaultUILanguage" xdt:Locator="Match(key)" xdt:Transform="Remove"/>
|
||||
<add key="umbracoUseSSL" xdt:Locator="Match(key)" xdt:Transform="Remove"/>
|
||||
<add key="owin:appStartup" value="UmbracoDefaultOwinStartup" xdt:Locator="Match(key,value)" xdt:Transform="Remove" />
|
||||
</appSettings>
|
||||
|
||||
<umbracoConfiguration xdt:Transform="Remove"/>
|
||||
<FileSystemProviders xdt:Transform="Remove" />
|
||||
<BaseRestExtensions xdt:Transform="Remove" />
|
||||
<connectionStrings>
|
||||
<remove name="umbracoDbDSN" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="umbracoDbDSN" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
</connectionStrings>
|
||||
|
||||
<system.web>
|
||||
<pages>
|
||||
<controls>
|
||||
<add tagPrefix="umbraco" xdt:Locator="Match(tagPrefix)" xdt:Transform="Remove" />
|
||||
</controls>
|
||||
</pages>
|
||||
<httpModules>
|
||||
<add name="UmbracoModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
</httpModules>
|
||||
<httpHandlers>
|
||||
<add type="umbraco.presentation.channels.api, umbraco" xdt:Locator="Match(type)" xdt:Transform="Remove" />
|
||||
<add type="umbraco.presentation.channels.wordApi, umbraco" xdt:Locator="Match(type)" xdt:Transform="Remove" />
|
||||
</httpHandlers>
|
||||
<compilation>
|
||||
<buildProviders>
|
||||
<add type="umbraco.MacroEngines.RazorBuildProvider, umbraco.MacroEngines" xdt:Locator="Match(type)" xdt:Transform="Remove" />
|
||||
<add type="umbraco.MacroEngines.RazorBuildProvider, umbraco.MacroEngines" xdt:Locator="Match(type)" xdt:Transform="Remove" />
|
||||
<add type="umbraco.MacroEngines.RazorBuildProvider, umbraco.MacroEngines" xdt:Locator="Match(type)" xdt:Transform="Remove" />
|
||||
</buildProviders>
|
||||
</compilation>
|
||||
<membership>
|
||||
<providers>
|
||||
<add name="UmbracoMembershipProvider" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="UsersMembershipProvider" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
</providers>
|
||||
</membership>
|
||||
<roleManager>
|
||||
<providers>
|
||||
<add name="UmbracoRoleProvider" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
</providers>
|
||||
</roleManager>
|
||||
</system.web>
|
||||
<system.webServer>
|
||||
<modules>
|
||||
<remove name="UmbracoModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="UmbracoModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
</modules>
|
||||
<handlers>
|
||||
<remove name="Channels" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<remove name="Channels_Word" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="Channels" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="Channels_Word" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
<location path="umbraco" xdt:Locator="Match(path)" xdt:Transform="Remove" />/>
|
||||
<location path="App_Plugins" xdt:Locator="Match(path)" xdt:Transform="Remove" />/>
|
||||
|
||||
</configuration>
|
||||
@@ -1,18 +1,30 @@
|
||||
param($rootPath, $toolsPath, $package, $project)
|
||||
param($installPath, $toolsPath, $package, $project)
|
||||
|
||||
Write-Host "installPath:" "${installPath}"
|
||||
Write-Host "toolsPath:" "${toolsPath}"
|
||||
|
||||
Write-Host " "
|
||||
|
||||
if ($project) {
|
||||
$dateTime = Get-Date -Format yyyyMMdd-HHmmss
|
||||
$backupPath = Join-Path (Split-Path $project.FullName -Parent) "\App_Data\NuGetBackup\$dateTime"
|
||||
|
||||
# Create paths and list them
|
||||
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
|
||||
Write-Host "projectPath:" "${projectPath}"
|
||||
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup\$dateTime"
|
||||
Write-Host "backupPath:" "${backupPath}"
|
||||
$copyLogsPath = Join-Path $backupPath "CopyLogs"
|
||||
$projectDestinationPath = Split-Path $project.FullName -Parent
|
||||
|
||||
Write-Host "copyLogsPath:" "${copyLogsPath}"
|
||||
$umbracoBinFolder = Join-Path $projectPath "bin"
|
||||
Write-Host "umbracoBinFolder:" "${umbracoBinFolder}"
|
||||
|
||||
# Create backup folder and logs folder if it doesn't exist yet
|
||||
New-Item -ItemType Directory -Force -Path $backupPath
|
||||
New-Item -ItemType Directory -Force -Path $copyLogsPath
|
||||
|
||||
# After backing up, remove all umbraco dlls from bin folder in case dll files are included in the VS project
|
||||
# See: http://issues.umbraco.org/issue/U4-4930
|
||||
$umbracoBinFolder = Join-Path $projectDestinationPath "bin"
|
||||
|
||||
if(Test-Path $umbracoBinFolder) {
|
||||
$umbracoBinBackupPath = Join-Path $backupPath "bin"
|
||||
|
||||
@@ -20,7 +32,7 @@ if ($project) {
|
||||
|
||||
robocopy $umbracoBinFolder $umbracoBinBackupPath /e /LOG:$copyLogsPath\UmbracoBinBackup.log
|
||||
|
||||
# Delete files Umbraco brings in
|
||||
# Delete files Umbraco ships with
|
||||
if(Test-Path $umbracoBinFolder\businesslogic.dll) { Remove-Item $umbracoBinFolder\businesslogic.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\cms.dll) { Remove-Item $umbracoBinFolder\cms.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\controls.dll) { Remove-Item $umbracoBinFolder\controls.dll -Force -Confirm:$false }
|
||||
@@ -36,16 +48,18 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\umbraco.DataLayer.dll) { Remove-Item $umbracoBinFolder\umbraco.DataLayer.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.editorControls.dll) { Remove-Item $umbracoBinFolder\umbraco.editorControls.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.MacroEngines.dll) { Remove-Item $umbracoBinFolder\umbraco.MacroEngines.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Umbraco.ModelsBuilder.dll) { Remove-Item $umbracoBinFolder\Umbraco.ModelsBuilder.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Umbraco.ModelsBuilder.AspNet.dll) { Remove-Item $umbracoBinFolder\Umbraco.ModelsBuilder.AspNet.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.providers.dll) { Remove-Item $umbracoBinFolder\umbraco.providers.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Umbraco.Web.UI.dll) { Remove-Item $umbracoBinFolder\Umbraco.Web.UI.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\UmbracoExamine.dll) { Remove-Item $umbracoBinFolder\UmbracoExamine.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\UrlRewritingNet.UrlRewriter.dll) { Remove-Item $umbracoBinFolder\UrlRewritingNet.UrlRewriter.dll -Force -Confirm:$false }
|
||||
|
||||
# Delete files Umbraco depends upon
|
||||
$amd64Folder = Join-Path $projectDestinationPath "bin\amd64"
|
||||
$amd64Folder = Join-Path $umbracoBinFolder "amd64"
|
||||
if(Test-Path $amd64Folder) { Remove-Item $amd64Folder -Force -Recurse -Confirm:$false }
|
||||
$x86Folder = Join-Path $projectDestinationPath "bin\x86"
|
||||
if(Test-Path $x86Folder) { Remove-Item $x86Folder -Force -Recurse -Confirm:$false }
|
||||
$x86Folder = Join-Path $umbracoBinFolder "x86"
|
||||
if(Test-Path $x86Folder) { Remove-Item $x86Folder -Force -Recurse -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\AutoMapper.dll) { Remove-Item $umbracoBinFolder\AutoMapper.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\AutoMapper.Net4.dll) { Remove-Item $umbracoBinFolder\AutoMapper.Net4.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\ClientDependency.Core.dll) { Remove-Item $umbracoBinFolder\ClientDependency.Core.dll -Force -Confirm:$false }
|
||||
@@ -59,6 +73,8 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\Lucene.Net.dll) { Remove-Item $umbracoBinFolder\Lucene.Net.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Security.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Security.dll -Force -Confirm:$false }
|
||||
@@ -72,6 +88,8 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\Newtonsoft.Json.dll) { Remove-Item $umbracoBinFolder\Newtonsoft.Json.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Owin.dll) { Remove-Item $umbracoBinFolder\Owin.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Semver.dll) { Remove-Item $umbracoBinFolder\Semver.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Collections.Immutable.dll) { Remove-Item $umbracoBinFolder\System.Collections.Immutable.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Reflection.Metadata.dll) { Remove-Item $umbracoBinFolder\System.Reflection.Metadata.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Net.Http.Extensions.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Extensions.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Net.Http.Formatting.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Formatting.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Net.Http.Primitives.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Primitives.dll -Force -Confirm:$false }
|
||||
@@ -82,6 +100,6 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\System.Web.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.Razor.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.WebPages.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Deployment.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Deployment.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Razor.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Razor.dll -Force -Confirm:$false }
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,33 @@
|
||||
param($rootPath, $toolsPath, $package, $project)
|
||||
param($installPath, $toolsPath, $package, $project)
|
||||
|
||||
Write-Host "installPath:" "${installPath}"
|
||||
Write-Host "toolsPath:" "${toolsPath}"
|
||||
|
||||
Write-Host " "
|
||||
|
||||
if ($project) {
|
||||
$dateTime = Get-Date -Format yyyyMMdd-HHmmss
|
||||
$backupPath = Join-Path (Split-Path $project.FullName -Parent) "\App_Data\NuGetBackup\$dateTime"
|
||||
|
||||
# Create paths and list them
|
||||
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
|
||||
Write-Host "projectPath:" "${projectPath}"
|
||||
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup\$dateTime"
|
||||
Write-Host "backupPath:" "${backupPath}"
|
||||
$copyLogsPath = Join-Path $backupPath "CopyLogs"
|
||||
$projectDestinationPath = Split-Path $project.FullName -Parent
|
||||
Write-Host "copyLogsPath:" "${copyLogsPath}"
|
||||
$webConfigSource = Join-Path $projectPath "Web.config"
|
||||
Write-Host "webConfigSource:" "${webConfigSource}"
|
||||
$configFolder = Join-Path $projectPath "Config"
|
||||
Write-Host "configFolder:" "${configFolder}"
|
||||
|
||||
# Create backup folder and logs folder if it doesn't exist yet
|
||||
New-Item -ItemType Directory -Force -Path $backupPath
|
||||
New-Item -ItemType Directory -Force -Path $copyLogsPath
|
||||
|
||||
# Create a backup of original web.config
|
||||
$webConfigSource = Join-Path $projectDestinationPath "Web.config"
|
||||
Copy-Item $webConfigSource $backupPath -Force
|
||||
|
||||
# Backup config files folder
|
||||
$configFolder = Join-Path $projectDestinationPath "Config"
|
||||
# Backup config files folder
|
||||
if(Test-Path $configFolder) {
|
||||
$umbracoBackupPath = Join-Path $backupPath "Config"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
|
||||
@@ -24,32 +36,24 @@ if ($project) {
|
||||
}
|
||||
|
||||
# Copy umbraco and umbraco_files from package to project folder
|
||||
# This is only done when these folders already exist because we
|
||||
# only want to do this for upgrades
|
||||
$umbracoFolder = Join-Path $projectDestinationPath "Umbraco"
|
||||
if(Test-Path $umbracoFolder) {
|
||||
$umbracoFolderSource = Join-Path $rootPath "UmbracoFiles\Umbraco"
|
||||
|
||||
$umbracoBackupPath = Join-Path $backupPath "Umbraco"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
|
||||
|
||||
robocopy $umbracoFolder $umbracoBackupPath /e /LOG:$copyLogsPath\UmbracoBackup.log
|
||||
robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
|
||||
}
|
||||
$umbracoFolder = Join-Path $projectPath "Umbraco"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoFolder
|
||||
$umbracoFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco"
|
||||
$umbracoBackupPath = Join-Path $backupPath "Umbraco"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
|
||||
robocopy $umbracoFolder $umbracoBackupPath /e /LOG:$copyLogsPath\UmbracoBackup.log
|
||||
robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
|
||||
|
||||
$umbracoClientFolder = Join-Path $projectDestinationPath "Umbraco_Client"
|
||||
if(Test-Path $umbracoClientFolder) {
|
||||
$umbracoClientFolderSource = Join-Path $rootPath "UmbracoFiles\Umbraco_Client"
|
||||
|
||||
$umbracoClientBackupPath = Join-Path $backupPath "Umbraco_Client"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoClientBackupPath
|
||||
|
||||
robocopy $umbracoClientFolder $umbracoClientBackupPath /e /LOG:$copyLogsPath\UmbracoClientBackup.log
|
||||
robocopy $umbracoClientFolderSource $umbracoClientFolder /is /it /e /LOG:$copyLogsPath\UmbracoClientCopy.log
|
||||
}
|
||||
$umbracoClientFolder = Join-Path $projectPath "Umbraco_Client"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoClientFolder
|
||||
$umbracoClientFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco_Client"
|
||||
$umbracoClientBackupPath = Join-Path $backupPath "Umbraco_Client"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoClientBackupPath
|
||||
robocopy $umbracoClientFolder $umbracoClientBackupPath /e /LOG:$copyLogsPath\UmbracoClientBackup.log
|
||||
robocopy $umbracoClientFolderSource $umbracoClientFolder /is /it /e /LOG:$copyLogsPath\UmbracoClientCopy.log
|
||||
|
||||
$copyWebconfig = $true
|
||||
$destinationWebConfig = Join-Path $projectDestinationPath "Web.config"
|
||||
$destinationWebConfig = Join-Path $projectPath "Web.config"
|
||||
|
||||
if(Test-Path $destinationWebConfig)
|
||||
{
|
||||
@@ -71,11 +75,11 @@ if ($project) {
|
||||
|
||||
if($copyWebconfig -eq $true)
|
||||
{
|
||||
$packageWebConfigSource = Join-Path $rootPath "UmbracoFiles\Web.config"
|
||||
$packageWebConfigSource = Join-Path $installPath "UmbracoFiles\Web.config"
|
||||
Copy-Item $packageWebConfigSource $destinationWebConfig -Force
|
||||
}
|
||||
|
||||
$installFolder = Join-Path $projectDestinationPath "Install"
|
||||
$installFolder = Join-Path $projectPath "Install"
|
||||
if(Test-Path $installFolder) {
|
||||
Remove-Item $installFolder -Force -Recurse -Confirm:$false
|
||||
}
|
||||
|
||||
48
build/NuSpecs/tools/uninstall.core.ps1
Normal file
48
build/NuSpecs/tools/uninstall.core.ps1
Normal file
@@ -0,0 +1,48 @@
|
||||
param($installPath, $toolsPath, $package, $project)
|
||||
|
||||
Write-Host "installPath:" "${installPath}"
|
||||
Write-Host "toolsPath:" "${toolsPath}"
|
||||
|
||||
Write-Host " "
|
||||
|
||||
if ($project) {
|
||||
|
||||
# Create paths and list them
|
||||
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
|
||||
Write-Host "projectPath:" "${projectPath}"
|
||||
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup"
|
||||
Write-Host "backupPath:" "${backupPath}"
|
||||
$umbracoBinFolder = Join-Path $projectPath "bin"
|
||||
Write-Host "umbracoBinFolder:" "${umbracoBinFolder}"
|
||||
|
||||
# Remove backups
|
||||
Write-Host "removing backups:" "${backupPath}"
|
||||
if(Test-Path $backupPath) { Remove-Item -Recurse -Force $backupPath -Confirm:$false }
|
||||
|
||||
# Delete files Umbraco ships with
|
||||
|
||||
Write-Host "removing dlls:" "${umbracoBinFolder}"
|
||||
if(Test-Path $umbracoBinFolder\businesslogic.dll) { Remove-Item $umbracoBinFolder\businesslogic.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\cms.dll) { Remove-Item $umbracoBinFolder\cms.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\controls.dll) { Remove-Item $umbracoBinFolder\controls.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\interfaces.dll) { Remove-Item $umbracoBinFolder\interfaces.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\log4net.dll) { Remove-Item $umbracoBinFolder\log4net.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll) { Remove-Item $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\SQLCE4Umbraco.dll) { Remove-Item $umbracoBinFolder\SQLCE4Umbraco.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\TidyNet.dll) { Remove-Item $umbracoBinFolder\TidyNet.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.dll) { Remove-Item $umbracoBinFolder\umbraco.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Umbraco.Core.dll) { Remove-Item $umbracoBinFolder\Umbraco.Core.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.DataLayer.dll) { Remove-Item $umbracoBinFolder\umbraco.DataLayer.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.editorControls.dll) { Remove-Item $umbracoBinFolder\umbraco.editorControls.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.MacroEngines.dll) { Remove-Item $umbracoBinFolder\umbraco.MacroEngines.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.providers.dll) { Remove-Item $umbracoBinFolder\umbraco.providers.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Umbraco.Web.UI.dll) { Remove-Item $umbracoBinFolder\Umbraco.Web.UI.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\UmbracoExamine.dll) { Remove-Item $umbracoBinFolder\UmbracoExamine.dll -Force -Confirm:$false }
|
||||
|
||||
$amd64Folder = Join-Path $umbracoBinFolder "amd64"
|
||||
if(Test-Path $amd64Folder) { Remove-Item $amd64Folder -Force -Recurse -Confirm:$false }
|
||||
$x86Folder = Join-Path $umbracoBinFolder "x86"
|
||||
if(Test-Path $x86Folder) { Remove-Item $x86Folder -Force -Recurse -Confirm:$false }
|
||||
}
|
||||
39
build/NuSpecs/tools/uninstall.ps1
Normal file
39
build/NuSpecs/tools/uninstall.ps1
Normal file
@@ -0,0 +1,39 @@
|
||||
param($installPath, $toolsPath, $package, $project)
|
||||
|
||||
Write-Host "installPath:" "${installPath}"
|
||||
Write-Host "toolsPath:" "${toolsPath}"
|
||||
|
||||
Write-Host " "
|
||||
|
||||
if ($project) {
|
||||
|
||||
# Create paths and list them
|
||||
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
|
||||
Write-Host "projectPath:" "${projectPath}"
|
||||
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup"
|
||||
Write-Host "backupPath:" "${backupPath}"
|
||||
$appBrowsers = Join-Path $projectPath "App_Browsers"
|
||||
Write-Host "appBrowsers:" "${appBrowsers}"
|
||||
$appData = Join-Path $projectPath "App_Data"
|
||||
Write-Host "appData:" "${appData}"
|
||||
|
||||
# Remove backups
|
||||
Write-Host "removing backups:" "${backupPath}"
|
||||
if(Test-Path $backupPath) { Remove-Item -Recurse -Force $backupPath -Confirm:$false }
|
||||
|
||||
# Remove app_data files
|
||||
Write-Host "removing app_data files:" "${appData}"
|
||||
if(Test-Path $appData\packages) { Remove-Item $appData\packages -Recurse -Force -Confirm:$false }
|
||||
|
||||
Write-Host "removing app_browsers:" "${appBrowsers}"
|
||||
if(Test-Path $appBrowsers\Form.browser) { Remove-Item $appBrowsers\Form.browser -Force -Confirm:$false }
|
||||
if(Test-Path $appBrowsers\w3cvalidator.browser) { Remove-Item $appBrowsers\w3cvalidator.browser -Force -Confirm:$false }
|
||||
|
||||
# Remove umbraco and umbraco_files
|
||||
$umbracoFolder = Join-Path $projectPath "Umbraco"
|
||||
Write-Host "removing umbraco folder:" "${umbracoFolder}"
|
||||
if(Test-Path $umbracoFolder) { Remove-Item $umbracoFolder -Recurse -Force -Confirm:$false }
|
||||
$umbracoClientFolder = Join-Path $projectPath "Umbraco_Client"
|
||||
Write-Host "removing umbraco client folder:" "${umbracoClientFolder}"
|
||||
if(Test-Path $umbracoClientFolder) { Remove-Item $umbracoClientFolder -Recurse -Force -Confirm:$false }
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.4.0
|
||||
beta4
|
||||
RC1
|
||||
@@ -12,4 +12,4 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.4.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.4.0-beta4")]
|
||||
[assembly: AssemblyInformationalVersion("7.4.0-RC1")]
|
||||
@@ -7,14 +7,22 @@ using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface describing this cache provider as a wrapper for another
|
||||
/// </summary>
|
||||
internal interface IRuntimeCacheProviderWrapper
|
||||
{
|
||||
IRuntimeCacheProvider InnerProvider { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A wrapper for any IRuntimeCacheProvider that ensures that all inserts and returns
|
||||
/// are a deep cloned copy of the item when the item is IDeepCloneable and that tracks changes are
|
||||
/// reset if the object is TracksChangesEntityBase
|
||||
/// </summary>
|
||||
internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider
|
||||
internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider, IRuntimeCacheProviderWrapper
|
||||
{
|
||||
internal IRuntimeCacheProvider InnerProvider { get; private set; }
|
||||
public IRuntimeCacheProvider InnerProvider { get; private set; }
|
||||
|
||||
public DeepCloneRuntimeCacheProvider(IRuntimeCacheProvider innerProvider)
|
||||
{
|
||||
|
||||
@@ -15,35 +15,31 @@ namespace Umbraco.Core.Cache
|
||||
/// This cache policy uses sliding expiration and caches instances for 5 minutes. However if allow zero count is true, then we use the
|
||||
/// default policy with no expiry.
|
||||
/// </remarks>
|
||||
internal class DefaultRepositoryCachePolicy<TEntity, TId> : DisposableObject, IRepositoryCachePolicy<TEntity, TId>
|
||||
internal class DefaultRepositoryCachePolicy<TEntity, TId> : RepositoryCachePolicyBase<TEntity, TId>
|
||||
where TEntity : class, IAggregateRoot
|
||||
{
|
||||
private readonly RepositoryCachePolicyOptions _options;
|
||||
protected IRuntimeCacheProvider Cache { get; private set; }
|
||||
private Action _action;
|
||||
|
||||
public DefaultRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options)
|
||||
{
|
||||
if (cache == null) throw new ArgumentNullException("cache");
|
||||
: base(cache)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException("options");
|
||||
|
||||
_options = options;
|
||||
Cache = cache;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public string GetCacheIdKey(object id)
|
||||
protected string GetCacheIdKey(object id)
|
||||
{
|
||||
if (id == null) throw new ArgumentNullException("id");
|
||||
|
||||
return string.Format("{0}{1}", GetCacheTypeKey(), id);
|
||||
}
|
||||
|
||||
public string GetCacheTypeKey()
|
||||
protected string GetCacheTypeKey()
|
||||
{
|
||||
return string.Format("uRepo_{0}_", typeof(TEntity).Name);
|
||||
}
|
||||
|
||||
public void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod)
|
||||
public override void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
|
||||
@@ -85,24 +81,29 @@ namespace Umbraco.Core.Cache
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(TEntity entity, Action<TEntity> persistMethod)
|
||||
public override void Remove(TEntity entity, Action<TEntity> persistMethod)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
|
||||
|
||||
persistMethod(entity);
|
||||
|
||||
//set the disposal action
|
||||
var cacheKey = GetCacheIdKey(entity.Id);
|
||||
SetCacheAction(() =>
|
||||
try
|
||||
{
|
||||
Cache.ClearCacheItem(cacheKey);
|
||||
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
persistMethod(entity);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//set the disposal action
|
||||
var cacheKey = GetCacheIdKey(entity.Id);
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
Cache.ClearCacheItem(cacheKey);
|
||||
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public TEntity Get(TId id, Func<TId, TEntity> getFromRepo)
|
||||
public override TEntity Get(TId id, Func<TId, TEntity> getFromRepo)
|
||||
{
|
||||
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
|
||||
|
||||
@@ -119,13 +120,13 @@ namespace Umbraco.Core.Cache
|
||||
return entity;
|
||||
}
|
||||
|
||||
public TEntity Get(TId id)
|
||||
public override TEntity Get(TId id)
|
||||
{
|
||||
var cacheKey = GetCacheIdKey(id);
|
||||
return Cache.GetCacheItem<TEntity>(cacheKey);
|
||||
}
|
||||
|
||||
public bool Exists(TId id, Func<TId, bool> getFromRepo)
|
||||
public override bool Exists(TId id, Func<TId, bool> getFromRepo)
|
||||
{
|
||||
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
|
||||
|
||||
@@ -134,7 +135,7 @@ namespace Umbraco.Core.Cache
|
||||
return fromCache != null || getFromRepo(id);
|
||||
}
|
||||
|
||||
public virtual TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
|
||||
public override TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
|
||||
{
|
||||
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
|
||||
|
||||
@@ -188,7 +189,7 @@ namespace Umbraco.Core.Cache
|
||||
/// Looks up the zero count cache, must return null if it doesn't exist
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual bool HasZeroCountCache()
|
||||
protected bool HasZeroCountCache()
|
||||
{
|
||||
var zeroCount = Cache.GetCacheItem<TEntity[]>(GetCacheTypeKey());
|
||||
return (zeroCount != null && zeroCount.Any() == false);
|
||||
@@ -198,24 +199,13 @@ namespace Umbraco.Core.Cache
|
||||
/// Performs the lookup for all entities of this type from the cache
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual TEntity[] GetAllFromCache()
|
||||
protected TEntity[] GetAllFromCache()
|
||||
{
|
||||
var allEntities = Cache.GetCacheItemsByKeySearch<TEntity>(GetCacheTypeKey())
|
||||
.WhereNotNull()
|
||||
.ToArray();
|
||||
return allEntities.Any() ? allEntities : new TEntity[] {};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The disposal performs the caching
|
||||
/// </summary>
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
if (_action != null)
|
||||
{
|
||||
_action();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the action to execute on disposal for a single entity
|
||||
@@ -273,14 +263,6 @@ namespace Umbraco.Core.Cache
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the action to execute on disposal
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
protected void SetCacheAction(Action action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,40 +11,157 @@ namespace Umbraco.Core.Cache
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <typeparam name="TId"></typeparam>
|
||||
/// <remarks>
|
||||
/// This caching policy has no sliding expiration but uses the default ObjectCache.InfiniteAbsoluteExpiration as it's timeout, so it
|
||||
/// should not leave the cache unless the cache memory is exceeded and it gets thrown out.
|
||||
/// </remarks>
|
||||
internal class FullDataSetRepositoryCachePolicy<TEntity, TId> : DefaultRepositoryCachePolicy<TEntity, TId>
|
||||
internal class FullDataSetRepositoryCachePolicy<TEntity, TId> : RepositoryCachePolicyBase<TEntity, TId>
|
||||
where TEntity : class, IAggregateRoot
|
||||
{
|
||||
private readonly Func<TEntity, TId> _getEntityId;
|
||||
private readonly Func<IEnumerable<TEntity>> _getAllFromRepo;
|
||||
private readonly bool _expires;
|
||||
|
||||
public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, Func<TEntity, TId> getEntityId) : base(cache,
|
||||
new RepositoryCachePolicyOptions
|
||||
{
|
||||
//Definitely allow zero'd cache entires since this is a full set, in many cases there will be none,
|
||||
// and we must cache this!
|
||||
GetAllCacheAllowZeroCount = true
|
||||
})
|
||||
public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, Func<TEntity, TId> getEntityId, Func<IEnumerable<TEntity>> getAllFromRepo, bool expires)
|
||||
: base(cache)
|
||||
{
|
||||
_getEntityId = getEntityId;
|
||||
_getAllFromRepo = getAllFromRepo;
|
||||
_expires = expires;
|
||||
}
|
||||
|
||||
private bool? _hasZeroCountCache;
|
||||
|
||||
|
||||
protected string GetCacheTypeKey()
|
||||
{
|
||||
return string.Format("uRepo_{0}_", typeof(TEntity).Name);
|
||||
}
|
||||
|
||||
public override void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
|
||||
|
||||
try
|
||||
{
|
||||
persistMethod(entity);
|
||||
|
||||
//set the disposal action
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
//Clear all
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
//set the disposal action
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
//Clear all
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Remove(TEntity entity, Action<TEntity> persistMethod)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
|
||||
|
||||
try
|
||||
{
|
||||
persistMethod(entity);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//set the disposal action
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
//Clear all
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override TEntity Get(TId id, Func<TId, TEntity> getFromRepo)
|
||||
{
|
||||
//Force get all with cache
|
||||
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
|
||||
|
||||
//we don't have anything in cache (this should never happen), just return from the repo
|
||||
if (found == null) return getFromRepo(id);
|
||||
var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
|
||||
if (entity == null) return null;
|
||||
|
||||
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
|
||||
return (TEntity)entity.DeepClone();
|
||||
}
|
||||
|
||||
public override TEntity Get(TId id)
|
||||
{
|
||||
//Force get all with cache
|
||||
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
|
||||
|
||||
//we don't have anything in cache (this should never happen), just return null
|
||||
if (found == null) return null;
|
||||
var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
|
||||
if (entity == null) return null;
|
||||
|
||||
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
|
||||
return (TEntity)entity.DeepClone();
|
||||
}
|
||||
|
||||
public override bool Exists(TId id, Func<TId, bool> getFromRepo)
|
||||
{
|
||||
//Force get all with cache
|
||||
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
|
||||
|
||||
//we don't have anything in cache (this should never happen), just return from the repo
|
||||
return found == null
|
||||
? getFromRepo(id)
|
||||
: found.Any(x => _getEntityId(x).Equals(id));
|
||||
}
|
||||
|
||||
public override TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
|
||||
{
|
||||
//process the base logic without any Ids - we want to cache them all!
|
||||
var result = base.GetAll(new TId[] { }, getFromRepo);
|
||||
//process getting all including setting the cache callback
|
||||
var result = PerformGetAll(getFromRepo);
|
||||
|
||||
//now that the base result has been calculated, they will all be cached.
|
||||
// Now we can just filter by ids if they have been supplied
|
||||
|
||||
return ids.Any()
|
||||
? result.Where(x => ids.Contains(_getEntityId(x))).ToArray()
|
||||
: result;
|
||||
|
||||
return (ids.Any()
|
||||
? result.Where(x => ids.Contains(_getEntityId(x))).ToArray()
|
||||
: result)
|
||||
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
|
||||
.Select(x => (TEntity)x.DeepClone())
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private TEntity[] PerformGetAll(Func<TId[], IEnumerable<TEntity>> getFromRepo)
|
||||
{
|
||||
var allEntities = GetAllFromCache();
|
||||
if (allEntities.Any())
|
||||
{
|
||||
return allEntities;
|
||||
}
|
||||
|
||||
//check the zero count cache
|
||||
if (HasZeroCountCache())
|
||||
{
|
||||
//there is a zero count cache so return an empty list
|
||||
return new TEntity[] { };
|
||||
}
|
||||
|
||||
//we need to do the lookup from the repo
|
||||
var entityCollection = getFromRepo(new TId[] { })
|
||||
//ensure we don't include any null refs in the returned collection!
|
||||
.WhereNotNull()
|
||||
.ToArray();
|
||||
|
||||
//set the disposal action
|
||||
SetCacheAction(entityCollection);
|
||||
|
||||
return entityCollection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -52,26 +169,32 @@ namespace Umbraco.Core.Cache
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="entity"></param>
|
||||
protected override void SetCacheAction(string cacheKey, TEntity entity)
|
||||
protected void SetCacheAction(string cacheKey, TEntity entity)
|
||||
{
|
||||
//do nothing
|
||||
//No-op
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the action to execute on disposal for an entity collection
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <param name="entityCollection"></param>
|
||||
protected override void SetCacheAction(TId[] ids, TEntity[] entityCollection)
|
||||
protected void SetCacheAction(TEntity[] entityCollection)
|
||||
{
|
||||
//for this type of caching policy, we don't want to cache any GetAll request containing specific Ids
|
||||
if (ids.Any()) return;
|
||||
|
||||
//set the disposal action
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
//We want to cache the result as a single collection
|
||||
Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList<TEntity>(entityCollection));
|
||||
|
||||
if (_expires)
|
||||
{
|
||||
Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList<TEntity>(entityCollection),
|
||||
timeout: TimeSpan.FromMinutes(5),
|
||||
isSliding: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList<TEntity>(entityCollection));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -79,7 +202,7 @@ namespace Umbraco.Core.Cache
|
||||
/// Looks up the zero count cache, must return null if it doesn't exist
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override bool HasZeroCountCache()
|
||||
protected bool HasZeroCountCache()
|
||||
{
|
||||
if (_hasZeroCountCache.HasValue)
|
||||
return _hasZeroCountCache.Value;
|
||||
@@ -92,14 +215,15 @@ namespace Umbraco.Core.Cache
|
||||
/// This policy will cache the full data set as a single collection
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override TEntity[] GetAllFromCache()
|
||||
protected TEntity[] GetAllFromCache()
|
||||
{
|
||||
var found = Cache.GetCacheItem<DeepCloneableList<TEntity>>(GetCacheTypeKey());
|
||||
|
||||
|
||||
//This method will get called before checking for zero count cache, so we'll just set the flag here
|
||||
_hasZeroCountCache = found != null;
|
||||
|
||||
return found == null ? new TEntity[] { } : found.WhereNotNull().ToArray();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
@@ -13,16 +14,20 @@ namespace Umbraco.Core.Cache
|
||||
{
|
||||
private readonly IRuntimeCacheProvider _runtimeCache;
|
||||
private readonly Func<TEntity, TId> _getEntityId;
|
||||
private readonly Func<IEnumerable<TEntity>> _getAllFromRepo;
|
||||
private readonly bool _expires;
|
||||
|
||||
public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, Func<TEntity, TId> getEntityId)
|
||||
public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, Func<TEntity, TId> getEntityId, Func<IEnumerable<TEntity>> getAllFromRepo, bool expires)
|
||||
{
|
||||
_runtimeCache = runtimeCache;
|
||||
_getEntityId = getEntityId;
|
||||
_getAllFromRepo = getAllFromRepo;
|
||||
_expires = expires;
|
||||
}
|
||||
|
||||
public virtual IRepositoryCachePolicy<TEntity, TId> CreatePolicy()
|
||||
{
|
||||
return new FullDataSetRepositoryCachePolicy<TEntity, TId>(_runtimeCache, _getEntityId);
|
||||
return new FullDataSetRepositoryCachePolicy<TEntity, TId>(_runtimeCache, _getEntityId, _getAllFromRepo, _expires);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,7 @@ namespace Umbraco.Core.Cache
|
||||
TEntity Get(TId id, Func<TId, TEntity> getFromRepo);
|
||||
TEntity Get(TId id);
|
||||
bool Exists(TId id, Func<TId, bool> getFromRepo);
|
||||
|
||||
string GetCacheIdKey(object id);
|
||||
string GetCacheTypeKey();
|
||||
|
||||
void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod);
|
||||
void Remove(TEntity entity, Action<TEntity> persistMethod);
|
||||
TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo);
|
||||
|
||||
48
src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs
Normal file
48
src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
internal abstract class RepositoryCachePolicyBase<TEntity, TId> : DisposableObject, IRepositoryCachePolicy<TEntity, TId>
|
||||
where TEntity : class, IAggregateRoot
|
||||
{
|
||||
private Action _action;
|
||||
|
||||
protected RepositoryCachePolicyBase(IRuntimeCacheProvider cache)
|
||||
{
|
||||
if (cache == null) throw new ArgumentNullException("cache");
|
||||
|
||||
Cache = cache;
|
||||
}
|
||||
|
||||
protected IRuntimeCacheProvider Cache { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The disposal performs the caching
|
||||
/// </summary>
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
if (_action != null)
|
||||
{
|
||||
_action();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the action to execute on disposal
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
protected void SetCacheAction(Action action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
public abstract TEntity Get(TId id, Func<TId, TEntity> getFromRepo);
|
||||
public abstract TEntity Get(TId id);
|
||||
public abstract bool Exists(TId id, Func<TId, bool> getFromRepo);
|
||||
public abstract void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod);
|
||||
public abstract void Remove(TEntity entity, Action<TEntity> persistMethod);
|
||||
public abstract TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
protected override void SetCacheAction(TId[] ids, TEntity[] entityCollection)
|
||||
{
|
||||
//do nothing
|
||||
//no-op
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,7 +290,7 @@ namespace Umbraco.Core
|
||||
TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
var cache = RuntimeCache as HttpRuntimeCacheProvider;
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
|
||||
@@ -314,7 +314,7 @@ namespace Umbraco.Core
|
||||
CacheDependency cacheDependency,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
var cache = RuntimeCache as HttpRuntimeCacheProvider;
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency);
|
||||
@@ -374,7 +374,7 @@ namespace Umbraco.Core
|
||||
TimeSpan timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
var cache = RuntimeCache as HttpRuntimeCacheProvider;
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency);
|
||||
@@ -400,7 +400,7 @@ namespace Umbraco.Core
|
||||
TimeSpan? timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
var cache = RuntimeCache as HttpRuntimeCacheProvider;
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
|
||||
@@ -409,6 +409,20 @@ namespace Umbraco.Core
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
private HttpRuntimeCacheProvider GetHttpRuntimeCacheProvider(IRuntimeCacheProvider runtimeCache)
|
||||
{
|
||||
HttpRuntimeCacheProvider cache;
|
||||
var wrapper = RuntimeCache as IRuntimeCacheProviderWrapper;
|
||||
if (wrapper != null)
|
||||
{
|
||||
cache = wrapper.InnerProvider as HttpRuntimeCacheProvider;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache = RuntimeCache as HttpRuntimeCacheProvider;
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,18 +14,24 @@ namespace Umbraco.Core.Collections
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class DeepCloneableList<T> : List<T>, IDeepCloneable, IRememberBeingDirty
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Collections.Generic.List`1"/> class that is empty and has the default initial capacity.
|
||||
/// </summary>
|
||||
public DeepCloneableList()
|
||||
private readonly ListCloneBehavior _listCloneBehavior;
|
||||
|
||||
public DeepCloneableList(ListCloneBehavior listCloneBehavior)
|
||||
{
|
||||
_listCloneBehavior = listCloneBehavior;
|
||||
}
|
||||
|
||||
public DeepCloneableList(IEnumerable<T> collection, ListCloneBehavior listCloneBehavior) : base(collection)
|
||||
{
|
||||
_listCloneBehavior = listCloneBehavior;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Collections.Generic.List`1"/> class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied.
|
||||
/// Default behavior is CloneOnce
|
||||
/// </summary>
|
||||
/// <param name="collection">The collection whose elements are copied to the new list.</param><exception cref="T:System.ArgumentNullException"><paramref name="collection"/> is null.</exception>
|
||||
public DeepCloneableList(IEnumerable<T> collection) : base(collection)
|
||||
/// <param name="collection"></param>
|
||||
public DeepCloneableList(IEnumerable<T> collection)
|
||||
: this(collection, ListCloneBehavior.CloneOnce)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -35,20 +41,47 @@ namespace Umbraco.Core.Collections
|
||||
/// <returns></returns>
|
||||
public object DeepClone()
|
||||
{
|
||||
var newList = new DeepCloneableList<T>();
|
||||
foreach (var item in this)
|
||||
switch (_listCloneBehavior)
|
||||
{
|
||||
var dc = item as IDeepCloneable;
|
||||
if (dc != null)
|
||||
{
|
||||
newList.Add((T) dc.DeepClone());
|
||||
}
|
||||
else
|
||||
{
|
||||
newList.Add(item);
|
||||
}
|
||||
case ListCloneBehavior.CloneOnce:
|
||||
//we are cloning once, so create a new list in none mode
|
||||
// and deep clone all items into it
|
||||
var newList = new DeepCloneableList<T>(ListCloneBehavior.None);
|
||||
foreach (var item in this)
|
||||
{
|
||||
var dc = item as IDeepCloneable;
|
||||
if (dc != null)
|
||||
{
|
||||
newList.Add((T)dc.DeepClone());
|
||||
}
|
||||
else
|
||||
{
|
||||
newList.Add(item);
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
case ListCloneBehavior.None:
|
||||
//we are in none mode, so just return a new list with the same items
|
||||
return new DeepCloneableList<T>(this, ListCloneBehavior.None);
|
||||
case ListCloneBehavior.Always:
|
||||
//always clone to new list
|
||||
var newList2 = new DeepCloneableList<T>(ListCloneBehavior.Always);
|
||||
foreach (var item in this)
|
||||
{
|
||||
var dc = item as IDeepCloneable;
|
||||
if (dc != null)
|
||||
{
|
||||
newList2.Add((T)dc.DeepClone());
|
||||
}
|
||||
else
|
||||
{
|
||||
newList2.Add(item);
|
||||
}
|
||||
}
|
||||
return newList2;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
public bool IsDirty()
|
||||
|
||||
20
src/Umbraco.Core/Collections/ListCloneBehavior.cs
Normal file
20
src/Umbraco.Core/Collections/ListCloneBehavior.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace Umbraco.Core.Collections
|
||||
{
|
||||
internal enum ListCloneBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// When set, DeepClone will clone the items one time and the result list behavior will be None
|
||||
/// </summary>
|
||||
CloneOnce,
|
||||
|
||||
/// <summary>
|
||||
/// When set, DeepClone will not clone any items
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// When set, DeepClone will always clone all items
|
||||
/// </summary>
|
||||
Always
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return "beta4"; } }
|
||||
public static string CurrentComment { get { return "RC1"; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -136,7 +136,10 @@ namespace Umbraco.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
x.OnApplicationInitialized(UmbracoApplication, ApplicationContext);
|
||||
using (ProfilingLogger.DebugDuration<CoreBootManager>(string.Format("Executing {0} in ApplicationInitialized", x.GetType())))
|
||||
{
|
||||
x.OnApplicationInitialized(UmbracoApplication, ApplicationContext);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -299,7 +302,10 @@ namespace Umbraco.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
x.OnApplicationStarting(UmbracoApplication, ApplicationContext);
|
||||
using (ProfilingLogger.DebugDuration<CoreBootManager>(string.Format("Executing {0} in ApplicationStarting", x.GetType())))
|
||||
{
|
||||
x.OnApplicationStarting(UmbracoApplication, ApplicationContext);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -350,7 +356,10 @@ namespace Umbraco.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
x.OnApplicationStarted(UmbracoApplication, ApplicationContext);
|
||||
using (ProfilingLogger.DebugDuration<CoreBootManager>(string.Format("Executing {0} in ApplicationStarted", x.GetType())))
|
||||
{
|
||||
x.OnApplicationStarted(UmbracoApplication, ApplicationContext);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -9,10 +9,30 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
public static class DeepCloneHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores the metadata for the properties for a given type so we know how to create them
|
||||
/// </summary>
|
||||
private struct ClonePropertyInfo
|
||||
{
|
||||
public ClonePropertyInfo(PropertyInfo propertyInfo) : this()
|
||||
{
|
||||
if (propertyInfo == null) throw new ArgumentNullException("propertyInfo");
|
||||
PropertyInfo = propertyInfo;
|
||||
}
|
||||
|
||||
public PropertyInfo PropertyInfo { get; private set; }
|
||||
public bool IsDeepCloneable { get; set; }
|
||||
public Type GenericListType { get; set; }
|
||||
public bool IsList
|
||||
{
|
||||
get { return GenericListType != null; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to avoid constant reflection (perf)
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> PropCache = new ConcurrentDictionary<Type, PropertyInfo[]>();
|
||||
private static readonly ConcurrentDictionary<Type, ClonePropertyInfo[]> PropCache = new ConcurrentDictionary<Type, ClonePropertyInfo[]>();
|
||||
|
||||
/// <summary>
|
||||
/// Used to deep clone any reference properties on the object (should be done after a MemberwiseClone for which the outcome is 'output')
|
||||
@@ -30,81 +50,99 @@ namespace Umbraco.Core.Models
|
||||
throw new InvalidOperationException("Both the input and output types must be the same");
|
||||
}
|
||||
|
||||
//get the property metadata from cache so we only have to figure this out once per type
|
||||
var refProperties = PropCache.GetOrAdd(inputType, type =>
|
||||
inputType.GetProperties()
|
||||
.Where(x =>
|
||||
//is not attributed with the ignore clone attribute
|
||||
x.GetCustomAttribute<DoNotCloneAttribute>() == null
|
||||
.Select<PropertyInfo, ClonePropertyInfo?>(propertyInfo =>
|
||||
{
|
||||
if (
|
||||
//is not attributed with the ignore clone attribute
|
||||
propertyInfo.GetCustomAttribute<DoNotCloneAttribute>() != null
|
||||
//reference type but not string
|
||||
&& x.PropertyType.IsValueType == false && x.PropertyType != typeof (string)
|
||||
|| propertyInfo.PropertyType.IsValueType || propertyInfo.PropertyType == typeof (string)
|
||||
//settable
|
||||
&& x.CanWrite
|
||||
|| propertyInfo.CanWrite == false
|
||||
//non-indexed
|
||||
&& x.GetIndexParameters().Any() == false)
|
||||
|| propertyInfo.GetIndexParameters().Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if (TypeHelper.IsTypeAssignableFrom<IDeepCloneable>(propertyInfo.PropertyType))
|
||||
{
|
||||
return new ClonePropertyInfo(propertyInfo) { IsDeepCloneable = true };
|
||||
}
|
||||
|
||||
if (TypeHelper.IsTypeAssignableFrom<IEnumerable>(propertyInfo.PropertyType)
|
||||
&& TypeHelper.IsTypeAssignableFrom<string>(propertyInfo.PropertyType) == false)
|
||||
{
|
||||
if (propertyInfo.PropertyType.IsGenericType
|
||||
&& (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|
||||
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)
|
||||
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
|
||||
{
|
||||
//if it is a IEnumerable<>, IList<T> or ICollection<> we'll use a List<>
|
||||
var genericType = typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments());
|
||||
return new ClonePropertyInfo(propertyInfo) { GenericListType = genericType };
|
||||
}
|
||||
if (propertyInfo.PropertyType.IsArray
|
||||
|| (propertyInfo.PropertyType.IsInterface && propertyInfo.PropertyType.IsGenericType == false))
|
||||
{
|
||||
//if its an array, we'll create a list to work with first and then convert to array later
|
||||
//otherwise if its just a regular derivitave of IEnumerable, we can use a list too
|
||||
return new ClonePropertyInfo(propertyInfo) { GenericListType = typeof(List<object>) };
|
||||
}
|
||||
//skip instead of trying to create instance of abstract or interface
|
||||
if (propertyInfo.PropertyType.IsAbstract || propertyInfo.PropertyType.IsInterface)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//its a custom IEnumerable, we'll try to create it
|
||||
try
|
||||
{
|
||||
var custom = Activator.CreateInstance(propertyInfo.PropertyType);
|
||||
//if it's an IList we can work with it, otherwise we cannot
|
||||
var newList = custom as IList;
|
||||
if (newList == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new ClonePropertyInfo(propertyInfo) {GenericListType = propertyInfo.PropertyType};
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//could not create this type so we'll skip it
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return new ClonePropertyInfo(propertyInfo);
|
||||
})
|
||||
.Where(x => x.HasValue)
|
||||
.Select(x => x.Value)
|
||||
.ToArray());
|
||||
|
||||
foreach (var propertyInfo in refProperties)
|
||||
foreach (var clonePropertyInfo in refProperties)
|
||||
{
|
||||
if (TypeHelper.IsTypeAssignableFrom<IDeepCloneable>(propertyInfo.PropertyType))
|
||||
if (clonePropertyInfo.IsDeepCloneable)
|
||||
{
|
||||
//this ref property is also deep cloneable so clone it
|
||||
var result = (IDeepCloneable)propertyInfo.GetValue(input, null);
|
||||
var result = (IDeepCloneable)clonePropertyInfo.PropertyInfo.GetValue(input, null);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
//set the cloned value to the property
|
||||
propertyInfo.SetValue(output, result.DeepClone(), null);
|
||||
clonePropertyInfo.PropertyInfo.SetValue(output, result.DeepClone(), null);
|
||||
}
|
||||
}
|
||||
else if (TypeHelper.IsTypeAssignableFrom<IEnumerable>(propertyInfo.PropertyType)
|
||||
&& TypeHelper.IsTypeAssignableFrom<string>(propertyInfo.PropertyType) == false)
|
||||
else if (clonePropertyInfo.IsList)
|
||||
{
|
||||
IList newList;
|
||||
if (propertyInfo.PropertyType.IsGenericType
|
||||
&& (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|
||||
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)
|
||||
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
|
||||
{
|
||||
//if it is a IEnumerable<>, IList<T> or ICollection<> we'll use a List<>
|
||||
var genericType = typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments());
|
||||
newList = (IList)Activator.CreateInstance(genericType);
|
||||
}
|
||||
else if (propertyInfo.PropertyType.IsArray
|
||||
|| (propertyInfo.PropertyType.IsInterface && propertyInfo.PropertyType.IsGenericType == false))
|
||||
{
|
||||
//if its an array, we'll create a list to work with first and then convert to array later
|
||||
//otherwise if its just a regular derivitave of IEnumerable, we can use a list too
|
||||
newList = new List<object>();
|
||||
}
|
||||
else
|
||||
{
|
||||
//skip instead of trying to create instance of abstract or interface
|
||||
if (propertyInfo.PropertyType.IsAbstract || propertyInfo.PropertyType.IsInterface)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//its a custom IEnumerable, we'll try to create it
|
||||
try
|
||||
{
|
||||
var custom = Activator.CreateInstance(propertyInfo.PropertyType);
|
||||
//if it's an IList we can work with it, otherwise we cannot
|
||||
newList = custom as IList;
|
||||
if (newList == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//could not create this type so we'll skip it
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var enumerable = (IEnumerable)propertyInfo.GetValue(input, null);
|
||||
var enumerable = (IEnumerable)clonePropertyInfo.PropertyInfo.GetValue(input, null);
|
||||
if (enumerable == null) continue;
|
||||
|
||||
var newList = (IList)Activator.CreateInstance(clonePropertyInfo.GenericListType);
|
||||
|
||||
var isUsableType = true;
|
||||
|
||||
//now clone each item
|
||||
@@ -136,21 +174,21 @@ namespace Umbraco.Core.Models
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propertyInfo.PropertyType.IsArray)
|
||||
if (clonePropertyInfo.PropertyInfo.PropertyType.IsArray)
|
||||
{
|
||||
//need to convert to array
|
||||
var arr = (object[])Activator.CreateInstance(propertyInfo.PropertyType, newList.Count);
|
||||
var arr = (object[])Activator.CreateInstance(clonePropertyInfo.PropertyInfo.PropertyType, newList.Count);
|
||||
for (int i = 0; i < newList.Count; i++)
|
||||
{
|
||||
arr[i] = newList[i];
|
||||
}
|
||||
//set the cloned collection
|
||||
propertyInfo.SetValue(output, arr, null);
|
||||
clonePropertyInfo.PropertyInfo.SetValue(output, arr, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
//set the cloned collection
|
||||
propertyInfo.SetValue(output, newList, null);
|
||||
clonePropertyInfo.PropertyInfo.SetValue(output, newList, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -98,10 +98,45 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Cache
|
||||
|
||||
// these methods are called by ContentTypeCacheRefresher and DataTypeCacheRefresher
|
||||
|
||||
internal static void ClearAll()
|
||||
{
|
||||
Logging.LogHelper.Debug<PublishedContentType>("Clear all.");
|
||||
// ok and faster to do it by types, assuming noone else caches PublishedContentType instances
|
||||
//ApplicationContext.Current.ApplicationCache.ClearStaticCacheByKeySearch("PublishedContentType_");
|
||||
ApplicationContext.Current.ApplicationCache.StaticCache.ClearCacheObjectTypes<PublishedContentType>();
|
||||
}
|
||||
|
||||
internal static void ClearContentType(int id)
|
||||
{
|
||||
Logging.LogHelper.Debug<PublishedContentType>("Clear content type w/id {0}.", () => id);
|
||||
// requires a predicate because the key does not contain the ID
|
||||
// faster than key strings comparisons anyway
|
||||
ApplicationContext.Current.ApplicationCache.StaticCache.ClearCacheObjectTypes<PublishedContentType>(
|
||||
(key, value) => value.Id == id);
|
||||
}
|
||||
|
||||
internal static void ClearDataType(int id)
|
||||
{
|
||||
Logging.LogHelper.Debug<PublishedContentType>("Clear data type w/id {0}.", () => id);
|
||||
// there is no recursion to handle here because a PublishedContentType contains *all* its
|
||||
// properties ie both its own properties and those that were inherited (it's based upon an
|
||||
// IContentTypeComposition) and so every PublishedContentType having a property based upon
|
||||
// the cleared data type, be it local or inherited, will be cleared.
|
||||
ApplicationContext.Current.ApplicationCache.StaticCache.ClearCacheObjectTypes<PublishedContentType>(
|
||||
(key, value) => value.PropertyTypes.Any(x => x.DataTypeId == id));
|
||||
}
|
||||
|
||||
public static PublishedContentType Get(PublishedItemType itemType, string alias)
|
||||
{
|
||||
var type = CreatePublishedContentType(itemType, alias);
|
||||
var key = string.Format("PublishedContentType_{0}_{1}",
|
||||
itemType.ToString().ToLowerInvariant(), alias.ToLowerInvariant());
|
||||
|
||||
var type = ApplicationContext.Current.ApplicationCache.StaticCache.GetCacheItem<PublishedContentType>(key,
|
||||
() => CreatePublishedContentType(itemType, alias));
|
||||
|
||||
return type;
|
||||
}
|
||||
@@ -134,8 +169,21 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
return new PublishedContentType(contentType);
|
||||
}
|
||||
|
||||
// for unit tests
|
||||
internal static Func<string, PublishedContentType> GetPublishedContentTypeCallback { get; set; }
|
||||
|
||||
// for unit tests - changing the callback must reset the cache obviously
|
||||
private static Func<string, PublishedContentType> _getPublishedContentTypeCallBack;
|
||||
internal static Func<string, PublishedContentType> GetPublishedContentTypeCallback
|
||||
{
|
||||
get { return _getPublishedContentTypeCallBack; }
|
||||
set
|
||||
{
|
||||
// see note above
|
||||
//ClearAll();
|
||||
ApplicationContext.Current.ApplicationCache.StaticCache.ClearCacheByKeySearch("PublishedContentType_");
|
||||
|
||||
_getPublishedContentTypeCallBack = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,13 +230,13 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
_sourceCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.Source);
|
||||
_objectCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.Object);
|
||||
_objectCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.XPath);
|
||||
_xpathCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.XPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sourceCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Source);
|
||||
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Object);
|
||||
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.XPath);
|
||||
_xpathCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.XPath);
|
||||
}
|
||||
if (_objectCacheLevel < _sourceCacheLevel) _objectCacheLevel = _sourceCacheLevel;
|
||||
if (_xpathCacheLevel < _sourceCacheLevel) _xpathCacheLevel = _sourceCacheLevel;
|
||||
|
||||
@@ -37,9 +37,9 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
|
||||
|
||||
if (!dataTypeIds.Any()) return string.Empty;
|
||||
|
||||
var propertyData =
|
||||
database.Fetch<PropertyDataDto>(
|
||||
"WHERE propertyTypeId in (SELECT id from cmsPropertyType where dataTypeID IN (@dataTypeIds))", new { dataTypeIds = dataTypeIds });
|
||||
// need to use dynamic, as PropertyDataDto has new properties
|
||||
var propertyData = database.Fetch<dynamic>("SELECT * FROM cmsPropertyData"
|
||||
+ " WHERE propertyTypeId in (SELECT id from cmsPropertyType where dataTypeID IN (@dataTypeIds))", new { dataTypeIds = dataTypeIds });
|
||||
if (!propertyData.Any()) return string.Empty;
|
||||
|
||||
var nodesIdsWithProperty = propertyData.Select(x => x.NodeId).Distinct().ToArray();
|
||||
@@ -71,13 +71,16 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
|
||||
xml = new XmlDocument();
|
||||
xml.LoadXml(data.Text);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error<UpdateRelatedLinksData>("The data stored for property id " + data.Id + " on document " + data.NodeId +
|
||||
" is not valid XML, the data will be removed because it cannot be converted to the new format. The value was: " + data.Text, ex);
|
||||
int dataId = data.id;
|
||||
int dataNodeId = data.nodeId;
|
||||
string dataText = data.dataNText;
|
||||
Logger.Error<UpdateRelatedLinksData>("The data stored for property id " + dataId + " on document " + dataNodeId +
|
||||
" is not valid XML, the data will be removed because it cannot be converted to the new format. The value was: " + dataText, ex);
|
||||
|
||||
data.Text = "";
|
||||
database.Update(data);
|
||||
data.dataNText = "";
|
||||
database.Update("cmsPropertyData", "id", data, new[] { "dataNText" });
|
||||
|
||||
UpdateXmlTable(propertyTypes, data, cmsContentXmlEntries, database);
|
||||
|
||||
@@ -91,11 +94,11 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
|
||||
{
|
||||
var title = node.Attributes["title"].Value;
|
||||
var type = node.Attributes["type"].Value;
|
||||
var newwindow = node.Attributes["newwindow"].Value.Equals("1") ? true : false;
|
||||
var newwindow = node.Attributes["newwindow"].Value.Equals("1");
|
||||
var lnk = node.Attributes["link"].Value;
|
||||
|
||||
//create the links in the format the new prop editor expects it to be
|
||||
var link = new ExpandoObject() as IDictionary<string, Object>;
|
||||
var link = new ExpandoObject() as IDictionary<string, object>;
|
||||
link.Add("title", title);
|
||||
link.Add("caption", title);
|
||||
link.Add("link", lnk);
|
||||
@@ -110,9 +113,9 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
|
||||
}
|
||||
|
||||
//store the serialized data
|
||||
data.Text = JsonConvert.SerializeObject(links);
|
||||
data.dataNText = JsonConvert.SerializeObject(links);
|
||||
|
||||
database.Update(data);
|
||||
database.Update("cmsPropertyData", "id", data, new[] { "dataNText" });
|
||||
|
||||
UpdateXmlTable(propertyTypes, data, cmsContentXmlEntries, database);
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -33,45 +35,57 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFourZer
|
||||
|
||||
// fill in the data in a way that is consistent over all environments
|
||||
// (ie cannot use random guids, http://issues.umbraco.org/issue/U4-6942)
|
||||
Execute.Code(UpdateGuids);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var data in Context.Database.Query<dynamic>(@"
|
||||
private static string UpdateGuids(Database database)
|
||||
{
|
||||
var updates = new List<Tuple<Guid, int>>();
|
||||
|
||||
foreach (var data in database.Query<dynamic>(@"
|
||||
SELECT cmsPropertyTypeGroup.id grId, cmsPropertyTypeGroup.text grName, cmsContentType.alias ctAlias, umbracoNode.nodeObjectType nObjType
|
||||
FROM cmsPropertyTypeGroup
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsPropertyTypeGroup.contentTypeNodeId = cmsContentType.nodeId
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType.nodeId = umbracoNode.id"))
|
||||
{
|
||||
Guid guid;
|
||||
// see BaseDataCreation... built-in groups have their own guids
|
||||
if (data.grId == 3)
|
||||
{
|
||||
Guid guid;
|
||||
// see BaseDataCreation... built-in groups have their own guids
|
||||
if (data.grId == 3)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Image);
|
||||
}
|
||||
else if (data.grId == 4)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.File);
|
||||
}
|
||||
else if (data.grId == 5)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Contents);
|
||||
}
|
||||
else if (data.grId == 11)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Membership);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create a consistent guid from
|
||||
// group name + content type alias + object type
|
||||
string guidSource = data.grName + data.ctAlias + data.nObjType;
|
||||
guid = guidSource.ToGuid();
|
||||
}
|
||||
|
||||
// set the Unique Id to the one we've generated
|
||||
Update.Table("cmsPropertyTypeGroup").Set(new { uniqueID = guid }).Where(new { id = data.grId });
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Image);
|
||||
}
|
||||
else if (data.grId == 4)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.File);
|
||||
}
|
||||
else if (data.grId == 5)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Contents);
|
||||
}
|
||||
else if (data.grId == 11)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Membership);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create a consistent guid from
|
||||
// group name + content type alias + object type
|
||||
string guidSource = data.grName + data.ctAlias + data.nObjType;
|
||||
guid = guidSource.ToGuid();
|
||||
}
|
||||
|
||||
// set the Unique Id to the one we've generated
|
||||
// but not within the foreach loop (as we already have a data reader open)
|
||||
updates.Add(Tuple.Create(guid, data.grId));
|
||||
}
|
||||
|
||||
foreach (var update in updates)
|
||||
database.Execute("UPDATE cmsPropertyTypeGroup SET uniqueID=@uid WHERE id=@id", new { uid = update.Item1, id = update.Item2 });
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
|
||||
@@ -33,36 +33,40 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
|
||||
// won't exist yet
|
||||
var propertyTypes = database.Fetch<dynamic>("SELECT * FROM cmsPropertyType WHERE propertyTypeGroupId > 0");
|
||||
|
||||
var propertyGroups = database.Fetch<PropertyTypeGroupDto>("WHERE id > 0");
|
||||
// need to use dynamic, as PropertyTypeGroupDto has new properties
|
||||
var propertyGroups = database.Fetch<dynamic>("SELECT * FROM cmsPropertyTypeGroup WHERE id > 0");
|
||||
|
||||
foreach (var propertyType in propertyTypes)
|
||||
{
|
||||
// get the PropertyTypeGroup of the current PropertyType, skip if not found
|
||||
var propertyTypeGroup = propertyGroups.FirstOrDefault(x => x.Id == propertyType.propertyTypeGroupId);
|
||||
var propertyTypeGroup = propertyGroups.FirstOrDefault(x => x.id == propertyType.propertyTypeGroupId);
|
||||
if (propertyTypeGroup == null) continue;
|
||||
|
||||
// if the PropretyTypeGroup belongs to the same content type as the PropertyType, then fine
|
||||
if (propertyTypeGroup.ContentTypeNodeId == propertyType.contentTypeId) continue;
|
||||
if (propertyTypeGroup.contenttypeNodeId == propertyType.contentTypeId) continue;
|
||||
|
||||
// else we want to assign the PropertyType to a proper PropertyTypeGroup
|
||||
// ie one that does belong to the same content - look for it
|
||||
var okPropertyTypeGroup = propertyGroups.FirstOrDefault(x =>
|
||||
x.Text == propertyTypeGroup.Text && // same name
|
||||
x.ContentTypeNodeId == propertyType.contentTypeId); // but for proper content type
|
||||
x.text == propertyTypeGroup.text && // same name
|
||||
x.contenttypeNodeId == propertyType.contentTypeId); // but for proper content type
|
||||
|
||||
if (okPropertyTypeGroup == null)
|
||||
{
|
||||
// does not exist, create a new PropertyTypeGroup,
|
||||
var propertyGroup = new PropertyTypeGroupDto
|
||||
// does not exist, create a new PropertyTypeGroup
|
||||
// cannot use a PropertyTypeGroupDto because of the new (not-yet-existing) uniqueID property
|
||||
// cannot use a dynamic because database.Insert fails to set the value of property
|
||||
var propertyGroup = new PropertyTypeGroupDtoTemp
|
||||
{
|
||||
ContentTypeNodeId = propertyType.contentTypeId,
|
||||
Text = propertyTypeGroup.Text,
|
||||
SortOrder = propertyTypeGroup.SortOrder
|
||||
id = 0,
|
||||
contenttypeNodeId = propertyType.contentTypeId,
|
||||
text = propertyTypeGroup.text,
|
||||
sortorder = propertyTypeGroup.sortorder
|
||||
};
|
||||
|
||||
// save + add to list of groups
|
||||
int id = Convert.ToInt16(database.Insert(propertyGroup));
|
||||
propertyGroup.Id = id;
|
||||
int id = Convert.ToInt16(database.Insert("cmsPropertyTypeGroup", "id", propertyGroup));
|
||||
propertyGroup.id = id;
|
||||
propertyGroups.Add(propertyGroup);
|
||||
|
||||
// update the PropertyType to use the new PropertyTypeGroup
|
||||
@@ -71,7 +75,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
|
||||
else
|
||||
{
|
||||
// exists, update PropertyType to use the PropertyTypeGroup
|
||||
propertyType.propertyTypeGroupId = okPropertyTypeGroup.Id;
|
||||
propertyType.propertyTypeGroupId = okPropertyTypeGroup.id;
|
||||
}
|
||||
database.Update("cmsPropertyType", "id", propertyType);
|
||||
}
|
||||
@@ -79,5 +83,13 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private class PropertyTypeGroupDtoTemp
|
||||
{
|
||||
public int id { get; set; }
|
||||
public int contenttypeNodeId { get; set; }
|
||||
public string text { get; set; }
|
||||
public int sortorder { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -834,7 +834,7 @@ namespace Umbraco.Core.Persistence
|
||||
var pd = PocoData.ForType(typeof(T));
|
||||
try
|
||||
{
|
||||
r = cmd.ExecuteReader();
|
||||
r = cmd.ExecuteReaderWithRetry();
|
||||
OnExecutedCommand(cmd);
|
||||
}
|
||||
catch (Exception x)
|
||||
|
||||
@@ -689,8 +689,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public int CountPublished()
|
||||
{
|
||||
var sql = GetBaseQuery(true).Where<NodeDto>(x => x.Trashed == false)
|
||||
.Where<DocumentDto>(x => x.Published == true)
|
||||
.Where<DocumentDto>(x => x.Newest == true);
|
||||
.Where<DocumentDto>(x => x.Published == true);
|
||||
return Database.ExecuteScalar<int>(sql);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,12 +32,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
protected ContentTypeBaseRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
{
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public IEnumerable<MoveEventInfo<TEntity>> Move(TEntity toMove, EntityContainer container)
|
||||
{
|
||||
var parentId = -1;
|
||||
var parentId = Constants.System.Root;
|
||||
if (container != null)
|
||||
{
|
||||
// Check on paths
|
||||
@@ -54,33 +54,32 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
new MoveEventInfo<TEntity>(toMove, toMove.Path, parentId)
|
||||
};
|
||||
|
||||
var origPath = toMove.Path;
|
||||
|
||||
//do the move to a new parent
|
||||
// get the level delta (old pos to new pos)
|
||||
var levelDelta = container == null
|
||||
? 1 - toMove.Level
|
||||
: container.Level + 1 - toMove.Level;
|
||||
|
||||
// move to parent (or -1), update path, save
|
||||
toMove.ParentId = parentId;
|
||||
|
||||
//set the updated path
|
||||
toMove.Path = string.Concat(container == null ? parentId.ToInvariantString() : container.Path, ",", toMove.Id);
|
||||
|
||||
//schedule it for updating in the transaction
|
||||
var toMovePath = toMove.Path + ","; // save before changing
|
||||
toMove.Path = (container == null ? Constants.System.Root.ToString() : container.Path) + "," + toMove.Id;
|
||||
toMove.Level = container == null ? 1 : container.Level + 1;
|
||||
AddOrUpdate(toMove);
|
||||
|
||||
//update all descendants, update in order of level
|
||||
var descendants = this.GetByQuery(
|
||||
new Query<TEntity>().Where(type => type.Path.StartsWith(origPath + ",")));
|
||||
var descendants = GetByQuery(new Query<TEntity>().Where(type => type.Path.StartsWith(toMovePath)));
|
||||
var paths = new Dictionary<int, string>();
|
||||
paths[toMove.Id] = toMove.Path;
|
||||
|
||||
var lastParent = toMove;
|
||||
foreach (var descendant in descendants.OrderBy(x => x.Level))
|
||||
{
|
||||
moveInfo.Add(new MoveEventInfo<TEntity>(descendant, descendant.Path, descendant.ParentId));
|
||||
|
||||
descendant.ParentId = lastParent.Id;
|
||||
descendant.Path = string.Concat(lastParent.Path, ",", descendant.Id);
|
||||
descendant.Path = paths[descendant.Id] = paths[descendant.ParentId] + "," + descendant.Id;
|
||||
descendant.Level += levelDelta;
|
||||
|
||||
//schedule it for updating in the transaction
|
||||
AddOrUpdate(descendant);
|
||||
|
||||
lastParent = descendant;
|
||||
}
|
||||
|
||||
return moveInfo;
|
||||
@@ -286,7 +285,7 @@ AND umbracoNode.id <> @id",
|
||||
{
|
||||
//Find PropertyTypes for the removed ContentType
|
||||
var propertyTypes = Database.Fetch<PropertyTypeDto>("WHERE contentTypeId = @Id", new { Id = key });
|
||||
//Loop through the Content that is based on the current ContentType in order to remove the Properties that are
|
||||
//Loop through the Content that is based on the current ContentType in order to remove the Properties that are
|
||||
//based on the PropertyTypes that belong to the removed ContentType.
|
||||
foreach (var contentDto in contentDtos)
|
||||
{
|
||||
@@ -410,7 +409,7 @@ AND umbracoNode.id <> @id",
|
||||
AssignDataTypeFromPropertyEditor(propertyType);
|
||||
}
|
||||
|
||||
//validate the alias!
|
||||
//validate the alias!
|
||||
ValidateAlias(propertyType);
|
||||
|
||||
var propertyTypeDto = propertyGroupFactory.BuildPropertyTypeDto(tabId, propertyType);
|
||||
@@ -647,17 +646,14 @@ AND umbracoNode.id <> @id",
|
||||
var allParentIdsAsArray = allParentContentTypeIds.SelectMany(x => x.Value).Distinct().ToArray();
|
||||
if (allParentIdsAsArray.Any())
|
||||
{
|
||||
//NO!!!!!!!!!!! Do not recurse lookup, we've already looked them all up
|
||||
//var allParentContentTypes = contentTypeRepository.GetAll(allParentIdsAsArray).ToArray();
|
||||
|
||||
var allParentContentTypes = contentTypes.Where(x => allParentIdsAsArray.Contains(x.Id)).ToArray();
|
||||
|
||||
foreach (var contentType in contentTypes)
|
||||
{
|
||||
{
|
||||
var entityId = contentType.Id;
|
||||
|
||||
var parentContentTypes = allParentContentTypes.Where(x =>
|
||||
{
|
||||
{
|
||||
var parentEntityId = x.Id;
|
||||
|
||||
return allParentContentTypeIds[entityId].Contains(parentEntityId);
|
||||
@@ -665,7 +661,7 @@ AND umbracoNode.id <> @id",
|
||||
foreach (var parentContentType in parentContentTypes)
|
||||
{
|
||||
var result = contentType.AddContentType(parentContentType);
|
||||
//Do something if adding fails? (Should hopefully not be possible unless someone created a circular reference)
|
||||
//Do something if adding fails? (Should hopefully not be possible unless someone created a circular reference)
|
||||
}
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
@@ -701,7 +697,7 @@ AND umbracoNode.id <> @id",
|
||||
foreach (var contentType in contentTypes)
|
||||
{
|
||||
var entityId = contentType.Id;
|
||||
|
||||
|
||||
var associatedTemplateIds = associatedTemplates[entityId].Select(x => x.TemplateId)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
@@ -716,9 +712,9 @@ AND umbracoNode.id <> @id",
|
||||
|
||||
internal static IEnumerable<IMediaType> MapMediaTypes(Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
out IDictionary<int, List<int>> parentMediaTypeIds)
|
||||
{
|
||||
Mandate.ParameterNotNull(db, "db");
|
||||
|
||||
{
|
||||
Mandate.ParameterNotNull(db, "db");
|
||||
|
||||
var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
@@ -730,19 +726,19 @@ AND umbracoNode.id <> @id",
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType.nodeId = umbracoNode.id
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
|
||||
) AllowedTypes
|
||||
ON AllowedTypes.Id = cmsContentType.nodeId
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentType2ContentType.parentContentTypeId, umbracoNode.uniqueID AS parentContentTypeKey, cmsContentType2ContentType.childContentTypeId
|
||||
FROM cmsContentType2ContentType
|
||||
FROM cmsContentType2ContentType
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
|
||||
ORDER BY ctId";
|
||||
|
||||
@@ -762,10 +758,11 @@ AND umbracoNode.id <> @id",
|
||||
// we used to do.
|
||||
var queue = new Queue<dynamic>(result);
|
||||
var currAllowedContentTypes = new List<ContentTypeSort>();
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var ct = queue.Dequeue();
|
||||
|
||||
|
||||
//check for allowed content types
|
||||
int? allowedCtId = ct.ctaAllowedId;
|
||||
int? allowedCtSort = ct.ctaSortOrder;
|
||||
@@ -801,7 +798,7 @@ AND umbracoNode.id <> @id",
|
||||
//Here we need to reset the current variables, we're now collecting data for a different content type
|
||||
currAllowedContentTypes = new List<ContentTypeSort>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mappedMediaTypes;
|
||||
}
|
||||
@@ -864,7 +861,7 @@ AND umbracoNode.id <> @id",
|
||||
ParentTypes.parentContentTypeId as chtParentId,ParentTypes.parentContentTypeKey as chtParentKey,
|
||||
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
|
||||
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
|
||||
umbracoNode.uniqueID as nUniqueId,
|
||||
umbracoNode.uniqueID as nUniqueId,
|
||||
Template.alias as tAlias, Template.nodeId as tId,Template.text as tText
|
||||
FROM cmsContentType
|
||||
INNER JOIN umbracoNode
|
||||
@@ -872,8 +869,8 @@ AND umbracoNode.id <> @id",
|
||||
LEFT JOIN cmsDocumentType
|
||||
ON cmsDocumentType.contentTypeNodeId = cmsContentType.nodeId
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
|
||||
) AllowedTypes
|
||||
@@ -886,14 +883,14 @@ AND umbracoNode.id <> @id",
|
||||
ON Template.nodeId = cmsDocumentType.templateNodeId
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentType2ContentType.parentContentTypeId, umbracoNode.uniqueID AS parentContentTypeKey, cmsContentType2ContentType.childContentTypeId
|
||||
FROM cmsContentType2ContentType
|
||||
FROM cmsContentType2ContentType
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
|
||||
ORDER BY ctId";
|
||||
|
||||
|
||||
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.DocumentType)});
|
||||
|
||||
if (result.Any() == false)
|
||||
@@ -907,7 +904,7 @@ AND umbracoNode.id <> @id",
|
||||
associatedTemplates = new Dictionary<int, List<AssociatedTemplate>>();
|
||||
var mappedContentTypes = new List<IContentType>();
|
||||
|
||||
var queue = new Queue<dynamic>(result);
|
||||
var queue = new Queue<dynamic>(result);
|
||||
var currDefaultTemplate = -1;
|
||||
var currAllowedContentTypes = new List<ContentTypeSort>();
|
||||
while (queue.Count > 0)
|
||||
@@ -1053,14 +1050,14 @@ AND umbracoNode.id <> @id",
|
||||
// therefore the union of the two contains all of the property type and property group information we need
|
||||
// NOTE: MySQL requires a SELECT * FROM the inner union in order to be able to sort . lame.
|
||||
|
||||
var sqlBuilder = new StringBuilder(@"SELECT PG.contenttypeNodeId as contentTypeId,
|
||||
PT.ptUniqueId as ptUniqueID, PT.ptId, PT.ptAlias, PT.ptDesc,PT.ptMandatory,PT.ptName,PT.ptSortOrder,PT.ptRegExp,
|
||||
var sqlBuilder = new StringBuilder(@"SELECT PG.contenttypeNodeId as contentTypeId,
|
||||
PT.ptUniqueId as ptUniqueID, PT.ptId, PT.ptAlias, PT.ptDesc,PT.ptMandatory,PT.ptName,PT.ptSortOrder,PT.ptRegExp,
|
||||
PT.dtId,PT.dtDbType,PT.dtPropEdAlias,
|
||||
PG.id as pgId, PG.uniqueID as pgKey, PG.sortorder as pgSortOrder, PG." + sqlSyntax.GetQuotedColumnName("text") + @" as pgText
|
||||
FROM cmsPropertyTypeGroup as PG
|
||||
LEFT JOIN
|
||||
(
|
||||
SELECT PT.uniqueID as ptUniqueId, PT.id as ptId, PT.Alias as ptAlias, PT." + sqlSyntax.GetQuotedColumnName("Description") + @" as ptDesc,
|
||||
SELECT PT.uniqueID as ptUniqueId, PT.id as ptId, PT.Alias as ptAlias, PT." + sqlSyntax.GetQuotedColumnName("Description") + @" as ptDesc,
|
||||
PT.mandatory as ptMandatory, PT.Name as ptName, PT.sortOrder as ptSortOrder, PT.validationRegExp as ptRegExp,
|
||||
PT.propertyTypeGroupId as ptGroupId,
|
||||
DT.dbType as dtDbType, DT.nodeId as dtId, DT.propertyEditorAlias as dtPropEdAlias
|
||||
@@ -1070,11 +1067,11 @@ AND umbracoNode.id <> @id",
|
||||
) as PT
|
||||
ON PT.ptGroupId = PG.id
|
||||
WHERE (PG.contenttypeNodeId in (@contentTypeIds))
|
||||
|
||||
|
||||
UNION
|
||||
|
||||
SELECT PT.contentTypeId as contentTypeId,
|
||||
PT.uniqueID as ptUniqueID, PT.id as ptId, PT.Alias as ptAlias, PT." + sqlSyntax.GetQuotedColumnName("Description") + @" as ptDesc,
|
||||
PT.uniqueID as ptUniqueID, PT.id as ptId, PT.Alias as ptAlias, PT." + sqlSyntax.GetQuotedColumnName("Description") + @" as ptDesc,
|
||||
PT.mandatory as ptMandatory, PT.Name as ptName, PT.sortOrder as ptSortOrder, PT.validationRegExp as ptRegExp,
|
||||
DT.nodeId as dtId, DT.dbType as dtDbType, DT.propertyEditorAlias as dtPropEdAlias,
|
||||
PG.id as pgId, PG.uniqueID as pgKey, PG.sortorder as pgSortOrder, PG." + sqlSyntax.GetQuotedColumnName("text") + @" as pgText
|
||||
|
||||
@@ -37,7 +37,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IContentType, int>(RuntimeCache, GetEntityId));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IContentType, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(),
|
||||
//allow this cache to expire
|
||||
expires:true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,13 +66,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IContentType>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.Text, SqlSyntax);
|
||||
var sql = translator.Translate();
|
||||
|
||||
var dtos = Database.Fetch<ContentTypeTemplateDto, ContentTypeDto, NodeDto>(sql);
|
||||
return dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.ContentTypeDto.NodeId).Select(x => x.ContentTypeDto.NodeId).ToArray())
|
||||
: Enumerable.Empty<IContentType>();
|
||||
|
||||
return
|
||||
//This returns a lookup from the GetAll cached looup
|
||||
(dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.ContentTypeDto.NodeId).Select(x => x.ContentTypeDto.NodeId).ToArray())
|
||||
: Enumerable.Empty<IContentType>())
|
||||
//order the result by name
|
||||
.OrderBy(x => x.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IDomain, int>(RuntimeCache, GetEntityId));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IDomain, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ILanguage, int>(RuntimeCache, GetEntityId));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ILanguage, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMediaType, int>(RuntimeCache, GetEntityId));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMediaType, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(),
|
||||
//allow this cache to expire
|
||||
expires: true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,13 +63,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IMediaType>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.Text, SqlSyntax);
|
||||
var sql = translator.Translate();
|
||||
|
||||
var dtos = Database.Fetch<ContentTypeDto, NodeDto>(sql);
|
||||
return dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.NodeId).Select(x => x.NodeId).ToArray())
|
||||
: Enumerable.Empty<IMediaType>();
|
||||
|
||||
return
|
||||
//This returns a lookup from the GetAll cached looup
|
||||
(dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.NodeId).Select(x => x.NodeId).ToArray())
|
||||
: Enumerable.Empty<IMediaType>())
|
||||
//order the result by name
|
||||
.OrderBy(x => x.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -33,7 +33,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMemberType, int>(RuntimeCache, GetEntityId));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMemberType, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(),
|
||||
//allow this cache to expire
|
||||
expires: true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<PublicAccessEntry, Guid>(RuntimeCache, GetEntityId));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<PublicAccessEntry, Guid>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ITemplate, int>(RuntimeCache, GetEntityId));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ITemplate, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,7 +489,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var parent = all.FirstOrDefault(x => x.Id == masterTemplateId);
|
||||
if (parent == null) return Enumerable.Empty<ITemplate>();
|
||||
|
||||
var children = all.Where(x => x.MasterTemplateAlias == parent.Alias);
|
||||
var children = all.Where(x => x.MasterTemplateAlias.InvariantEquals(parent.Alias));
|
||||
return children;
|
||||
}
|
||||
|
||||
@@ -497,7 +498,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//return from base.GetAll, this is all cached
|
||||
return base.GetAll().Where(x => alias.IsNullOrWhiteSpace()
|
||||
? x.MasterTemplateAlias.IsNullOrWhiteSpace()
|
||||
: x.MasterTemplateAlias == alias);
|
||||
: x.MasterTemplateAlias.InvariantEquals(alias));
|
||||
}
|
||||
|
||||
public IEnumerable<ITemplate> GetDescendants(int masterTemplateId)
|
||||
@@ -532,7 +533,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var descendants = new List<ITemplate>();
|
||||
if (alias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
var parent = all.FirstOrDefault(x => x.Alias == alias);
|
||||
var parent = all.FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
if (parent == null) return Enumerable.Empty<ITemplate>();
|
||||
//recursively add all children
|
||||
AddChildren(all, descendants, parent.Alias);
|
||||
@@ -552,7 +553,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
private void AddChildren(ITemplate[] all, List<ITemplate> descendants, string masterAlias)
|
||||
{
|
||||
var c = all.Where(x => x.MasterTemplateAlias == masterAlias).ToArray();
|
||||
var c = all.Where(x => x.MasterTemplateAlias.InvariantEquals(masterAlias)).ToArray();
|
||||
descendants.AddRange(c);
|
||||
if (c.Any() == false) return;
|
||||
//recurse through all children
|
||||
@@ -573,7 +574,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//first get all template objects
|
||||
var allTemplates = base.GetAll().ToArray();
|
||||
|
||||
var selfTemplate = allTemplates.SingleOrDefault(x => x.Alias == alias);
|
||||
var selfTemplate = allTemplates.SingleOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
if (selfTemplate == null)
|
||||
{
|
||||
return null;
|
||||
@@ -582,11 +583,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var top = selfTemplate;
|
||||
while (top.MasterTemplateAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
top = allTemplates.Single(x => x.Alias == top.MasterTemplateAlias);
|
||||
top = allTemplates.Single(x => x.Alias.InvariantEquals(top.MasterTemplateAlias));
|
||||
}
|
||||
|
||||
var topNode = new TemplateNode(allTemplates.Single(x => x.Id == top.Id));
|
||||
var childTemplates = allTemplates.Where(x => x.MasterTemplateAlias == top.Alias);
|
||||
var childTemplates = allTemplates.Where(x => x.MasterTemplateAlias.InvariantEquals(top.Alias));
|
||||
//This now creates the hierarchy recursively
|
||||
topNode.Children = CreateChildren(topNode, childTemplates, allTemplates);
|
||||
|
||||
@@ -598,7 +599,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private static TemplateNode WalkTree(TemplateNode current, string alias)
|
||||
{
|
||||
//now walk the tree to find the node
|
||||
if (current.Template.Alias == alias)
|
||||
if (current.Template.Alias.InvariantEquals(alias))
|
||||
{
|
||||
return current;
|
||||
}
|
||||
@@ -730,7 +731,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//get this node's children
|
||||
var local = childTemplate;
|
||||
var kids = allTemplates.Where(x => x.MasterTemplateAlias == local.Alias);
|
||||
var kids = allTemplates.Where(x => x.MasterTemplateAlias.InvariantEquals(local.Alias));
|
||||
|
||||
//recurse
|
||||
child.Children = CreateChildren(child, kids, allTemplates);
|
||||
@@ -760,7 +761,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
private bool AliasAlreadExists(ITemplate template)
|
||||
{
|
||||
var sql = GetBaseQuery(true).Where<TemplateDto>(x => x.Alias == template.Alias && x.NodeId != template.Id);
|
||||
var sql = GetBaseQuery(true).Where<TemplateDto>(x => x.Alias.InvariantEquals(template.Alias) && x.NodeId != template.Id);
|
||||
var count = Database.ExecuteScalar<int>(sql);
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace Umbraco.Core.Persistence
|
||||
/// Represents the Umbraco implementation of the PetaPoco Database object
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently this object exists for 'future proofing' our implementation. By having our own inheritied implementation we
|
||||
/// Currently this object exists for 'future proofing' our implementation. By having our own inheritied implementation we
|
||||
/// can then override any additional execution (such as additional loggging, functionality, etc...) that we need to without breaking compatibility since we'll always be exposing
|
||||
/// this object instead of the base PetaPoco database object.
|
||||
/// this object instead of the base PetaPoco database object.
|
||||
/// </remarks>
|
||||
public class UmbracoDatabase : Database, IDisposeOnRequestEnd
|
||||
{
|
||||
@@ -111,7 +111,9 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
public override IDbConnection OnConnectionOpened(IDbConnection connection)
|
||||
{
|
||||
// wrap the connection with a profiling connection that tracks timings
|
||||
// propagate timeout if none yet
|
||||
|
||||
// wrap the connection with a profiling connection that tracks timings
|
||||
return new StackExchange.Profiling.Data.ProfiledDbConnection(connection as DbConnection, MiniProfiler.Current);
|
||||
}
|
||||
|
||||
@@ -121,6 +123,14 @@ namespace Umbraco.Core.Persistence
|
||||
base.OnException(x);
|
||||
}
|
||||
|
||||
public override void OnExecutingCommand(IDbCommand cmd)
|
||||
{
|
||||
// if no timeout is specified, and the connection has a longer timeout, use it
|
||||
if (OneTimeCommandTimeout == 0 && CommandTimeout == 0 && cmd.Connection.ConnectionTimeout > 30)
|
||||
cmd.CommandTimeout = cmd.Connection.ConnectionTimeout;
|
||||
base.OnExecutingCommand(cmd);
|
||||
}
|
||||
|
||||
public override void OnExecutedCommand(IDbCommand cmd)
|
||||
{
|
||||
if (EnableSqlTrace)
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using StackExchange.Profiling;
|
||||
|
||||
namespace Umbraco.Core.Profiling
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows us to profile items during app startup - before an HttpRequest is created
|
||||
/// </summary>
|
||||
internal class StartupWebProfilerProvider : WebRequestProfilerProvider
|
||||
{
|
||||
public StartupWebProfilerProvider()
|
||||
{
|
||||
_startupPhase = StartupPhase.Boot;
|
||||
//create the startup profiler
|
||||
_startupProfiler = new MiniProfiler("http://localhost/umbraco-startup", ProfileLevel.Verbose)
|
||||
{
|
||||
Name = "StartupProfiler"
|
||||
};
|
||||
}
|
||||
|
||||
private MiniProfiler _startupProfiler;
|
||||
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim();
|
||||
|
||||
private enum StartupPhase
|
||||
{
|
||||
None = 0,
|
||||
Boot = 1,
|
||||
Request = 2
|
||||
}
|
||||
|
||||
private volatile StartupPhase _startupPhase;
|
||||
|
||||
public void BootComplete()
|
||||
{
|
||||
using (new ReadLock(_locker))
|
||||
{
|
||||
if (_startupPhase != StartupPhase.Boot) return;
|
||||
}
|
||||
|
||||
using (var l = new UpgradeableReadLock(_locker))
|
||||
{
|
||||
if (_startupPhase == StartupPhase.Boot)
|
||||
{
|
||||
l.UpgradeToWriteLock();
|
||||
|
||||
////Now we need to transfer some information from our startup phase to the normal
|
||||
////web request phase to output the startup profiled information.
|
||||
////Stop our internal startup profiler, this will write out it's results to storage.
|
||||
//StopProfiler(_startupProfiler);
|
||||
//SaveProfiler(_startupProfiler);
|
||||
|
||||
_startupPhase = StartupPhase.Request;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Stop(bool discardResults)
|
||||
{
|
||||
using (new ReadLock(_locker))
|
||||
{
|
||||
if (_startupPhase == StartupPhase.None)
|
||||
{
|
||||
base.Stop(discardResults);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
using (var l = new UpgradeableReadLock(_locker))
|
||||
{
|
||||
if (_startupPhase > 0 && base.GetCurrentProfiler() == null)
|
||||
{
|
||||
l.UpgradeToWriteLock();
|
||||
|
||||
_startupPhase = StartupPhase.None;
|
||||
|
||||
if (HttpContext.Current != null)
|
||||
{
|
||||
HttpContext.Current.Items[":mini-profiler:"] = _startupProfiler;
|
||||
base.Stop(discardResults);
|
||||
_startupProfiler = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.Stop(discardResults);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override MiniProfiler Start(ProfileLevel level)
|
||||
{
|
||||
using (new ReadLock(_locker))
|
||||
{
|
||||
if (_startupPhase > 0 && base.GetCurrentProfiler() == null)
|
||||
{
|
||||
SetProfilerActive(_startupProfiler);
|
||||
return _startupProfiler;
|
||||
}
|
||||
|
||||
return base.Start(level);
|
||||
}
|
||||
}
|
||||
|
||||
public override MiniProfiler GetCurrentProfiler()
|
||||
{
|
||||
using (new ReadLock(_locker))
|
||||
{
|
||||
if (_startupPhase > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
var current = base.GetCurrentProfiler();
|
||||
if (current == null) return _startupProfiler;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return _startupProfiler;
|
||||
}
|
||||
}
|
||||
|
||||
return base.GetCurrentProfiler();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,24 +12,15 @@ namespace Umbraco.Core.Profiling
|
||||
/// </summary>
|
||||
internal class WebProfiler : IProfiler
|
||||
{
|
||||
private StartupWebProfilerProvider _startupWebProfilerProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Binds to application events to enable the MiniProfiler
|
||||
/// </remarks>
|
||||
internal WebProfiler()
|
||||
{
|
||||
//setup some defaults
|
||||
MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter();
|
||||
MiniProfiler.Settings.StackMaxLength = 5000;
|
||||
|
||||
//At this point we know that we've been constructed during app startup, there won't be an HttpRequest in the HttpContext
|
||||
// since it hasn't started yet. So we need to do some hacking to enable profiling during startup.
|
||||
_startupWebProfilerProvider = new StartupWebProfilerProvider();
|
||||
//this should always be the case during startup, we'll need to set a custom profiler provider
|
||||
MiniProfiler.Settings.ProfilerProvider = _startupWebProfilerProvider;
|
||||
|
||||
//Binds to application events to enable the MiniProfiler with a real HttpRequest
|
||||
UmbracoApplicationBase.ApplicationInit += UmbracoApplicationApplicationInit;
|
||||
}
|
||||
|
||||
@@ -62,12 +53,7 @@ namespace Umbraco.Core.Profiling
|
||||
/// <param name="e"></param>
|
||||
void UmbracoApplicationEndRequest(object sender, EventArgs e)
|
||||
{
|
||||
if (_startupWebProfilerProvider != null)
|
||||
{
|
||||
Stop();
|
||||
_startupWebProfilerProvider = null;
|
||||
}
|
||||
else if (CanPerformProfilingAction(sender))
|
||||
if (CanPerformProfilingAction(sender))
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
@@ -80,11 +66,6 @@ namespace Umbraco.Core.Profiling
|
||||
/// <param name="e"></param>
|
||||
void UmbracoApplicationBeginRequest(object sender, EventArgs e)
|
||||
{
|
||||
if (_startupWebProfilerProvider != null)
|
||||
{
|
||||
_startupWebProfilerProvider.BootComplete();
|
||||
}
|
||||
|
||||
if (CanPerformProfilingAction(sender))
|
||||
{
|
||||
Start();
|
||||
@@ -143,7 +124,9 @@ namespace Umbraco.Core.Profiling
|
||||
/// Start the profiler
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
{
|
||||
MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter();
|
||||
MiniProfiler.Settings.StackMaxLength = 5000;
|
||||
MiniProfiler.Start();
|
||||
}
|
||||
|
||||
|
||||
@@ -167,74 +167,18 @@ namespace Umbraco.Core.Security
|
||||
/// This clears the forms authentication cookie for webapi since cookies are handled differently
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
[Obsolete("Use OWIN IAuthenticationManager.SignOut instead")]
|
||||
[Obsolete("Use OWIN IAuthenticationManager.SignOut instead", true)]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static void UmbracoLogoutWebApi(this HttpResponseMessage response)
|
||||
{
|
||||
if (response == null) throw new ArgumentNullException("response");
|
||||
//remove the cookie
|
||||
var authCookie = new CookieHeaderValue(UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, "")
|
||||
{
|
||||
Expires = DateTime.Now.AddYears(-1),
|
||||
Path = "/"
|
||||
};
|
||||
//remove the preview cookie too
|
||||
var prevCookie = new CookieHeaderValue(Constants.Web.PreviewCookieName, "")
|
||||
{
|
||||
Expires = DateTime.Now.AddYears(-1),
|
||||
Path = "/"
|
||||
};
|
||||
//remove the external login cookie too
|
||||
var extLoginCookie = new CookieHeaderValue(Constants.Security.BackOfficeExternalCookieName, "")
|
||||
{
|
||||
Expires = DateTime.Now.AddYears(-1),
|
||||
Path = "/"
|
||||
};
|
||||
|
||||
response.Headers.AddCookies(new[] { authCookie, prevCookie, extLoginCookie });
|
||||
throw new NotSupportedException("This method is not supported and should not be used, it has been removed in Umbraco 7.4");
|
||||
}
|
||||
|
||||
[Obsolete("Use WebSecurity.SetPrincipalForRequest")]
|
||||
[Obsolete("Use WebSecurity.SetPrincipalForRequest", true)]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static FormsAuthenticationTicket UmbracoLoginWebApi(this HttpResponseMessage response, IUser user)
|
||||
{
|
||||
if (response == null) throw new ArgumentNullException("response");
|
||||
|
||||
//remove the external login cookie
|
||||
var extLoginCookie = new CookieHeaderValue(Constants.Security.BackOfficeExternalCookieName, "")
|
||||
{
|
||||
Expires = DateTime.Now.AddYears(-1),
|
||||
Path = "/"
|
||||
};
|
||||
|
||||
var userDataString = JsonConvert.SerializeObject(Mapper.Map<UserData>(user));
|
||||
|
||||
var ticket = new FormsAuthenticationTicket(
|
||||
4,
|
||||
user.Username,
|
||||
DateTime.Now,
|
||||
DateTime.Now.AddMinutes(GlobalSettings.TimeOutInMinutes),
|
||||
true,
|
||||
userDataString,
|
||||
"/"
|
||||
);
|
||||
|
||||
// Encrypt the cookie using the machine key for secure transport
|
||||
var encrypted = FormsAuthentication.Encrypt(ticket);
|
||||
|
||||
//add the cookie
|
||||
var authCookie = new CookieHeaderValue(UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, encrypted)
|
||||
{
|
||||
//Umbraco has always persisted it's original cookie for 1 day so we'll keep it that way
|
||||
Expires = DateTime.Now.AddMinutes(1440),
|
||||
Path = "/",
|
||||
Secure = GlobalSettings.UseSSL,
|
||||
HttpOnly = true
|
||||
};
|
||||
|
||||
response.Headers.AddCookies(new[] { authCookie, extLoginCookie });
|
||||
|
||||
return ticket;
|
||||
throw new NotSupportedException("This method is not supported and should not be used, it has been removed in Umbraco 7.4");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -9,6 +9,12 @@ namespace Umbraco.Core.Security
|
||||
{
|
||||
public class BackOfficeClaimsIdentityFactory : ClaimsIdentityFactory<BackOfficeIdentityUser, int>
|
||||
{
|
||||
public BackOfficeClaimsIdentityFactory()
|
||||
{
|
||||
SecurityStampClaimType = Constants.Security.SessionIdClaimType;
|
||||
UserNameClaimType = ClaimTypes.Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a ClaimsIdentity from a user
|
||||
/// </summary>
|
||||
@@ -20,7 +26,7 @@ namespace Umbraco.Core.Security
|
||||
|
||||
var umbracoIdentity = new UmbracoBackOfficeIdentity(baseIdentity,
|
||||
//set a new session id
|
||||
new UserData(Guid.NewGuid().ToString("N"))
|
||||
new UserData
|
||||
{
|
||||
Id = user.Id,
|
||||
Username = user.UserName,
|
||||
@@ -29,7 +35,8 @@ namespace Umbraco.Core.Security
|
||||
Culture = user.Culture,
|
||||
Roles = user.Roles.Select(x => x.RoleId).ToArray(),
|
||||
StartContentNode = user.StartContentId,
|
||||
StartMediaNode = user.StartMediaId
|
||||
StartMediaNode = user.StartMediaId,
|
||||
SessionId = user.SecurityStamp
|
||||
});
|
||||
|
||||
return umbracoIdentity;
|
||||
|
||||
@@ -759,12 +759,13 @@ namespace Umbraco.Core.Security
|
||||
|
||||
//This is the correct way to implement this (as per the sql membership provider)
|
||||
|
||||
switch ((int)PasswordFormat)
|
||||
switch (PasswordFormat)
|
||||
{
|
||||
case 0:
|
||||
case MembershipPasswordFormat.Clear:
|
||||
return pass;
|
||||
case 1:
|
||||
case MembershipPasswordFormat.Hashed:
|
||||
throw new ProviderException("Provider can not decrypt hashed password");
|
||||
case MembershipPasswordFormat.Encrypted:
|
||||
default:
|
||||
var bytes = DecryptPassword(Convert.FromBase64String(pass));
|
||||
return bytes == null ? null : Encoding.Unicode.GetString(bytes, 16, bytes.Length - 16);
|
||||
|
||||
@@ -209,17 +209,19 @@ namespace Umbraco.Core.Security
|
||||
|
||||
if (HasClaim(x => x.Type == ClaimTypes.Locality) == false)
|
||||
AddClaim(new Claim(ClaimTypes.Locality, Culture, ClaimValueTypes.String, Issuer, Issuer, this));
|
||||
|
||||
////TODO: Not sure why this is null sometimes, it shouldn't be. Somewhere it's not being set
|
||||
/// I think it's due to some bug I had in chrome, we'll see
|
||||
//if (UserData.SessionId.IsNullOrWhiteSpace())
|
||||
//{
|
||||
// UserData.SessionId = Guid.NewGuid().ToString();
|
||||
//}
|
||||
|
||||
if (HasClaim(x => x.Type == Constants.Security.SessionIdClaimType) == false)
|
||||
if (HasClaim(x => x.Type == Constants.Security.SessionIdClaimType) == false && SessionId.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
AddClaim(new Claim(Constants.Security.SessionIdClaimType, SessionId, ClaimValueTypes.String, Issuer, Issuer, this));
|
||||
|
||||
//The security stamp claim is also required... this is because this claim type is hard coded
|
||||
// by the SecurityStampValidator, see: https://katanaproject.codeplex.com/workitem/444
|
||||
if (HasClaim(x => x.Type == Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType) == false)
|
||||
{
|
||||
AddClaim(new Claim(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType, SessionId, ClaimValueTypes.String, Issuer, Issuer, this));
|
||||
}
|
||||
}
|
||||
|
||||
//Add each app as a separate claim
|
||||
if (HasClaim(x => x.Type == Constants.Security.AllowedApplicationsClaimType) == false)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Security
|
||||
/// Use this constructor to create/assign new UserData to the ticket
|
||||
/// </summary>
|
||||
/// <param name="sessionId">
|
||||
/// A unique id that is assigned to this ticket
|
||||
/// The security stamp for the user
|
||||
/// </param>
|
||||
public UserData(string sessionId)
|
||||
{
|
||||
@@ -30,8 +30,7 @@ namespace Umbraco.Core.Security
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used to Id the current ticket which we can then use to mitigate csrf attacks
|
||||
/// and other things that require request validation.
|
||||
/// This is the 'security stamp' for validation
|
||||
/// </summary>
|
||||
[DataMember(Name = "sessionId")]
|
||||
public string SessionId { get; set; }
|
||||
@@ -42,8 +41,6 @@ namespace Umbraco.Core.Security
|
||||
[DataMember(Name = "roles")]
|
||||
public string[] Roles { get; set; }
|
||||
|
||||
//public int SessionTimeout { get; set; }
|
||||
|
||||
[DataMember(Name = "username")]
|
||||
public string Username { get; set; }
|
||||
|
||||
|
||||
@@ -1227,6 +1227,13 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional Id of the user issueing the delete operation</param>
|
||||
public void DeleteContentOfType(int contentTypeId, int userId = 0)
|
||||
{
|
||||
//TODO: This currently this is called from the ContentTypeService but that needs to change,
|
||||
// if we are deleting a content type, we should just delete the data and do this operation slightly differently.
|
||||
// This method will recursively go lookup every content item, check if any of it's descendants are
|
||||
// of a different type, move them to the recycle bin, then permanently delete the content items.
|
||||
// The main problem with this is that for every content item being deleted, events are raised...
|
||||
// which we need for many things like keeping caches in sync, but we can surely do this MUCH better.
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Services
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IMediaService _mediaService;
|
||||
|
||||
//Support recursive locks because some of the methods that require locking call other methods that require locking.
|
||||
//Support recursive locks because some of the methods that require locking call other methods that require locking.
|
||||
//for example, the Move method needs to be locked but this calls the Save method which also needs to be locked.
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
|
||||
|
||||
@@ -135,8 +135,8 @@ namespace Umbraco.Core.Services
|
||||
private Attempt<OperationStatus> SaveContainer(
|
||||
TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> savingEvent,
|
||||
TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> savedEvent,
|
||||
EntityContainer container,
|
||||
Guid containerObjectType,
|
||||
EntityContainer container,
|
||||
Guid containerObjectType,
|
||||
string objectTypeName, int userId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
@@ -164,7 +164,7 @@ namespace Umbraco.Core.Services
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, containerObjectType))
|
||||
{
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
savedEvent.RaiseEvent(new SaveEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
@@ -253,14 +253,14 @@ namespace Umbraco.Core.Services
|
||||
.Where(x => x != int.MinValue && x != contentType.Id)
|
||||
.ToArray();
|
||||
|
||||
return GetContentTypeContainers(ancestorIds);
|
||||
return GetContentTypeContainers(ancestorIds);
|
||||
}
|
||||
|
||||
public EntityContainer GetMediaTypeContainer(Guid containerId)
|
||||
{
|
||||
return GetContainer(containerId, Constants.ObjectTypes.MediaTypeGuid);
|
||||
}
|
||||
|
||||
|
||||
private EntityContainer GetContainer(Guid containerId, Guid containerObjectType)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -380,7 +380,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
public IContentType Copy(IContentType original, string alias, string name, int parentId = -1)
|
||||
{
|
||||
IContentType parent = null;
|
||||
IContentType parent = null;
|
||||
if (parentId > 0)
|
||||
{
|
||||
parent = GetContentType(parentId);
|
||||
@@ -414,7 +414,7 @@ namespace Umbraco.Core.Services
|
||||
Mandate.ParameterNotNullOrEmpty(alias, "alias");
|
||||
if (parent != null)
|
||||
{
|
||||
Mandate.That(parent.HasIdentity, () => new InvalidOperationException("The parent content type must have an identity"));
|
||||
Mandate.That(parent.HasIdentity, () => new InvalidOperationException("The parent content type must have an identity"));
|
||||
}
|
||||
|
||||
var clone = original.DeepCloneWithResetIdentities(alias);
|
||||
@@ -440,7 +440,7 @@ namespace Umbraco.Core.Services
|
||||
//set to root
|
||||
clone.ParentId = -1;
|
||||
}
|
||||
|
||||
|
||||
Save(clone);
|
||||
return clone;
|
||||
}
|
||||
@@ -505,7 +505,7 @@ namespace Umbraco.Core.Services
|
||||
public IEnumerable<IContentType> GetAllContentTypes(IEnumerable<Guid> ids)
|
||||
{
|
||||
using (var repository = RepositoryFactory.CreateContentTypeRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
{
|
||||
return repository.GetAll(ids.ToArray());
|
||||
}
|
||||
}
|
||||
@@ -599,7 +599,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
//this should never occur, the content service should always be typed but we'll check anyways.
|
||||
_contentService.RePublishAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (firstType is IMediaType)
|
||||
{
|
||||
@@ -608,10 +608,10 @@ namespace Umbraco.Core.Services
|
||||
if (typedContentService != null)
|
||||
{
|
||||
typedContentService.RebuildXmlStructures(toUpdate.Select(x => x.Id).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public int CountContentTypes()
|
||||
@@ -661,14 +661,17 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var contentType = compositionContentType as IContentType;
|
||||
var mediaType = compositionContentType as IMediaType;
|
||||
var memberType = compositionContentType as IMemberType; // should NOT do it here but... v8!
|
||||
|
||||
IContentTypeComposition[] allContentTypes;
|
||||
if (contentType != null)
|
||||
allContentTypes = GetAllContentTypes().Cast<IContentTypeComposition>().ToArray();
|
||||
else if (mediaType != null)
|
||||
allContentTypes = GetAllMediaTypes().Cast<IContentTypeComposition>().ToArray();
|
||||
else if (memberType != null)
|
||||
return; // no compositions on members, always validate
|
||||
else
|
||||
throw new Exception("Composition is neither IContentType nor IMediaType?");
|
||||
throw new Exception("Composition is neither IContentType nor IMediaType nor IMemberType?");
|
||||
|
||||
var compositionAliases = compositionContentType.CompositionAliases();
|
||||
var compositions = allContentTypes.Where(x => compositionAliases.Any(y => x.Alias.Equals(y)));
|
||||
@@ -684,7 +687,7 @@ namespace Umbraco.Core.Services
|
||||
dependencies.Add(indirectReference);
|
||||
//Get all compositions for the current indirect reference
|
||||
var directReferences = indirectReference.ContentTypeComposition;
|
||||
|
||||
|
||||
foreach (var directReference in directReferences)
|
||||
{
|
||||
if (directReference.Id == compositionContentType.Id || directReference.Alias.Equals(compositionContentType.Alias)) continue;
|
||||
@@ -704,7 +707,7 @@ namespace Umbraco.Core.Services
|
||||
if (contentTypeDependency == null) continue;
|
||||
var intersect = contentTypeDependency.PropertyTypes.Select(x => x.Alias.ToLowerInvariant()).Intersect(propertyTypeAliases).ToArray();
|
||||
if (intersect.Length == 0) continue;
|
||||
|
||||
|
||||
throw new InvalidCompositionException(compositionContentType.Alias, intersect.ToArray());
|
||||
}
|
||||
}
|
||||
@@ -716,7 +719,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional id of the user saving the ContentType</param>
|
||||
public void Save(IContentType contentType, int userId = 0)
|
||||
{
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(contentType), this))
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(contentType), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
@@ -746,7 +749,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var asArray = contentTypes.ToArray();
|
||||
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(asArray), this))
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(asArray), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
@@ -782,12 +785,19 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional id of the user issueing the delete</param>
|
||||
/// <remarks>Deleting a <see cref="IContentType"/> will delete all the <see cref="IContent"/> objects based on this <see cref="IContentType"/></remarks>
|
||||
public void Delete(IContentType contentType, int userId = 0)
|
||||
{
|
||||
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(contentType), this))
|
||||
{
|
||||
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(contentType), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
|
||||
//TODO: This needs to change, if we are deleting a content type, we should just delete the data,
|
||||
// this method will recursively go lookup every content item, check if any of it's descendants are
|
||||
// of a different type, move them to the recycle bin, then permanently delete the content items.
|
||||
// The main problem with this is that for every content item being deleted, events are raised...
|
||||
// which we need for many things like keeping caches in sync, but we can surely do this MUCH better.
|
||||
|
||||
_contentService.DeleteContentOfType(contentType.Id);
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -815,7 +825,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var asArray = contentTypes.ToArray();
|
||||
|
||||
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(asArray), this))
|
||||
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(asArray), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
@@ -841,7 +851,7 @@ namespace Umbraco.Core.Services
|
||||
Audit(AuditType.Delete, string.Format("Delete ContentTypes performed by user"), userId, -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IMediaType"/> object by its Id
|
||||
/// </summary>
|
||||
@@ -974,7 +984,7 @@ namespace Umbraco.Core.Services
|
||||
public Attempt<OperationStatus<MoveOperationStatusType>> MoveMediaType(IMediaType toMove, int containerId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
|
||||
if (MovingMediaType.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IMediaType>(evtMsgs, new MoveEventInfo<IMediaType>(toMove, toMove.Path, containerId)),
|
||||
this))
|
||||
@@ -1029,7 +1039,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IContentType>>();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
using (var repository = RepositoryFactory.CreateContentTypeRepository(uow))
|
||||
{
|
||||
try
|
||||
@@ -1064,7 +1074,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional Id of the user saving the MediaType</param>
|
||||
public void Save(IMediaType mediaType, int userId = 0)
|
||||
{
|
||||
if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs<IMediaType>(mediaType), this))
|
||||
if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs<IMediaType>(mediaType), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
@@ -1076,7 +1086,7 @@ namespace Umbraco.Core.Services
|
||||
mediaType.CreatorId = userId;
|
||||
repository.AddOrUpdate(mediaType);
|
||||
uow.Commit();
|
||||
|
||||
|
||||
}
|
||||
|
||||
UpdateContentXmlStructure(mediaType);
|
||||
@@ -1115,7 +1125,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
//save it all in one go
|
||||
uow.Commit();
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
UpdateContentXmlStructure(asArray.Cast<IContentTypeBase>().ToArray());
|
||||
@@ -1133,7 +1143,7 @@ namespace Umbraco.Core.Services
|
||||
/// <remarks>Deleting a <see cref="IMediaType"/> will delete all the <see cref="IMedia"/> objects based on this <see cref="IMediaType"/></remarks>
|
||||
public void Delete(IMediaType mediaType, int userId = 0)
|
||||
{
|
||||
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(mediaType), this))
|
||||
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(mediaType), this))
|
||||
return;
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
@@ -1163,7 +1173,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var asArray = mediaTypes.ToArray();
|
||||
|
||||
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(asArray), this))
|
||||
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(asArray), this))
|
||||
return;
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
@@ -1185,7 +1195,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
Audit(AuditType.Delete, string.Format("Delete MediaTypes performed by user"), userId, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1274,7 +1284,7 @@ namespace Umbraco.Core.Services
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IContentType>> DeletedContentType;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
@@ -1284,7 +1294,7 @@ namespace Umbraco.Core.Services
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IMediaType>> DeletedMediaType;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Save
|
||||
/// </summary>
|
||||
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -41,6 +41,16 @@ namespace Umbraco.Core
|
||||
ToCSharpEscapeChars[escape[0]] = escape[1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes new lines and tabs
|
||||
/// </summary>
|
||||
/// <param name="txt"></param>
|
||||
/// <returns></returns>
|
||||
internal static string StripWhitespace(this string txt)
|
||||
{
|
||||
return Regex.Replace(txt, @"\s", string.Empty);
|
||||
}
|
||||
|
||||
internal static string StripFileExtension(this string fileName)
|
||||
{
|
||||
//filenames cannot contain line breaks
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Umbraco.Core.Sync
|
||||
|
||||
protected override bool RequiresDistributed(IEnumerable<IServerAddress> servers, ICacheRefresher refresher, MessageType dispatchType)
|
||||
{
|
||||
// we don't care if there's servers listed or not,
|
||||
// we don't care if there's servers listed or not,
|
||||
// if distributed call is enabled we will make the call
|
||||
return _initialized && DistributedEnabled;
|
||||
}
|
||||
@@ -139,12 +139,35 @@ namespace Umbraco.Core.Sync
|
||||
{
|
||||
if (_released) return;
|
||||
|
||||
var coldboot = false;
|
||||
if (_lastId < 0) // never synced before
|
||||
{
|
||||
// we haven't synced - in this case we aren't going to sync the whole thing, we will assume this is a new
|
||||
// we haven't synced - in this case we aren't going to sync the whole thing, we will assume this is a new
|
||||
// server and it will need to rebuild it's own caches, eg Lucene or the xml cache file.
|
||||
_logger.Warn<DatabaseServerMessenger>("No last synced Id found, this generally means this is a new server/install. The server will rebuild its caches and indexes and then adjust it's last synced id to the latest found in the database and will start maintaining cache updates based on that id");
|
||||
_logger.Warn<DatabaseServerMessenger>("No last synced Id found, this generally means this is a new server/install."
|
||||
+ " The server will build its caches and indexes, and then adjust its last synced Id to the latest found in"
|
||||
+ " the database and maintain cache updates based on that Id.");
|
||||
|
||||
coldboot = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//check for how many instructions there are to process
|
||||
var count = _appContext.DatabaseContext.Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoCacheInstruction WHERE id > @lastId", new {lastId = _lastId});
|
||||
if (count > _options.MaxProcessingInstructionCount)
|
||||
{
|
||||
//too many instructions, proceed to cold boot
|
||||
_logger.Warn<DatabaseServerMessenger>("The instruction count ({0}) exceeds the specified MaxProcessingInstructionCount ({1})."
|
||||
+ " The server will skip existing instructions, rebuild its caches and indexes entirely, adjust its last synced Id"
|
||||
+ " to the latest found in the database and maintain cache updates based on that Id.",
|
||||
() => count, () => _options.MaxProcessingInstructionCount);
|
||||
|
||||
coldboot = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (coldboot)
|
||||
{
|
||||
// go get the last id in the db and store it
|
||||
// note: do it BEFORE initializing otherwise some instructions might get lost
|
||||
// when doing it before, some instructions might run twice - not an issue
|
||||
@@ -169,7 +192,7 @@ namespace Umbraco.Core.Sync
|
||||
{
|
||||
lock (_locko)
|
||||
{
|
||||
if (_syncing)
|
||||
if (_syncing)
|
||||
return;
|
||||
|
||||
if (_released)
|
||||
@@ -213,9 +236,9 @@ namespace Umbraco.Core.Sync
|
||||
private void ProcessDatabaseInstructions()
|
||||
{
|
||||
// NOTE
|
||||
// we 'could' recurse to ensure that no remaining instructions are pending in the table before proceeding but I don't think that
|
||||
// we 'could' recurse to ensure that no remaining instructions are pending in the table before proceeding but I don't think that
|
||||
// would be a good idea since instructions could keep getting added and then all other threads will probably get stuck from serving requests
|
||||
// (depending on what the cache refreshers are doing). I think it's best we do the one time check, process them and continue, if there are
|
||||
// (depending on what the cache refreshers are doing). I think it's best we do the one time check, process them and continue, if there are
|
||||
// pending requests after being processed, they'll just be processed on the next poll.
|
||||
//
|
||||
// FIXME not true if we're running on a background thread, assuming we can?
|
||||
@@ -281,7 +304,7 @@ namespace Umbraco.Core.Sync
|
||||
/// Remove old instructions from the database
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Always leave the last (most recent) record in the db table, this is so that not all instructions are removed which would cause
|
||||
/// Always leave the last (most recent) record in the db table, this is so that not all instructions are removed which would cause
|
||||
/// the site to cold boot if there's been no instruction activity for more than DaysToRetainInstructions.
|
||||
/// See: http://issues.umbraco.org/issue/U4-7643#comment=67-25085
|
||||
/// </remarks>
|
||||
@@ -290,15 +313,15 @@ namespace Umbraco.Core.Sync
|
||||
var pruneDate = DateTime.UtcNow.AddDays(-_options.DaysToRetainInstructions);
|
||||
var sqlSyntax = _appContext.DatabaseContext.SqlSyntax;
|
||||
|
||||
//NOTE: this query could work on SQL server and MySQL:
|
||||
//NOTE: this query could work on SQL server and MySQL:
|
||||
/*
|
||||
SELECT id
|
||||
FROM umbracoCacheInstruction
|
||||
WHERE utcStamp < getdate()
|
||||
WHERE utcStamp < getdate()
|
||||
AND id <> (SELECT MAX(id) FROM umbracoCacheInstruction)
|
||||
*/
|
||||
// However, this will not work on SQLCE and in fact it will be slower than the query we are
|
||||
// using if the SQL server doesn't perform it's own query optimizations (i.e. since the above
|
||||
// using if the SQL server doesn't perform it's own query optimizations (i.e. since the above
|
||||
// query could actually execute a sub query for every row found). So we've had to go with an
|
||||
// inner join which is faster and works on SQLCE but it's uglier to read.
|
||||
|
||||
@@ -331,9 +354,9 @@ namespace Umbraco.Core.Sync
|
||||
var dtos = _appContext.DatabaseContext.Database.Fetch<CacheInstructionDto>(sql);
|
||||
|
||||
if (dtos.Count == 0)
|
||||
_lastId = -1;
|
||||
_lastId = -1;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads the last-synced id from file into memory.
|
||||
/// </summary>
|
||||
@@ -502,4 +525,3 @@ namespace Umbraco.Core.Sync
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides options to the <see cref="DatabaseServerMessenger"/>.
|
||||
/// </summary>
|
||||
@@ -14,9 +14,15 @@ namespace Umbraco.Core.Sync
|
||||
public DatabaseServerMessengerOptions()
|
||||
{
|
||||
DaysToRetainInstructions = 2; // 2 days
|
||||
ThrottleSeconds = 5; // 5 seconds
|
||||
ThrottleSeconds = 5; // 5 second
|
||||
MaxProcessingInstructionCount = 1000;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of instructions that can be processed at startup; otherwise the server cold-boots (rebuilds its caches).
|
||||
/// </summary>
|
||||
public int MaxProcessingInstructionCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of callbacks that will be invoked if the lastsynced.txt file does not exist.
|
||||
/// </summary>
|
||||
|
||||
@@ -112,18 +112,6 @@
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.Formatting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Client.4.0.30506.0\lib\net40\System.Net.Http.Formatting.dll</HintPath>
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http.WebRequest" />
|
||||
<Reference Include="System.Runtime.Caching" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
@@ -175,6 +163,7 @@
|
||||
<Compile Include="Cache\IJsonCacheRefresher.cs" />
|
||||
<Compile Include="Cache\JsonCacheRefresherBase.cs" />
|
||||
<Compile Include="Cache\NullCacheProvider.cs" />
|
||||
<Compile Include="Cache\RepositoryCachePolicyBase.cs" />
|
||||
<Compile Include="Cache\SingleItemsOnlyRepositoryCachePolicy.cs" />
|
||||
<Compile Include="Cache\OnlySingleItemsRepositoryCachePolicyFactory.cs" />
|
||||
<Compile Include="Cache\PayloadCacheRefresherBase.cs" />
|
||||
@@ -188,6 +177,7 @@
|
||||
<Compile Include="CodeAnnotations\UmbracoExperimentalFeatureAttribute.cs" />
|
||||
<Compile Include="CodeAnnotations\UmbracoProposedPublicAttribute.cs" />
|
||||
<Compile Include="Collections\DeepCloneableList.cs" />
|
||||
<Compile Include="Collections\ListCloneBehavior.cs" />
|
||||
<Compile Include="ConcurrentHashSet.cs" />
|
||||
<Compile Include="Configuration\BaseRest\IBaseRestSection.cs" />
|
||||
<Compile Include="Configuration\BaseRest\IExtension.cs" />
|
||||
@@ -484,7 +474,6 @@
|
||||
<Compile Include="Persistence\Repositories\PublicAccessRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\TaskRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\TaskTypeRepository.cs" />
|
||||
<Compile Include="Profiling\StartupWebProfilerProvider.cs" />
|
||||
<Compile Include="PropertyEditors\DecimalValidator.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\GridValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\DecimalValueConverter.cs" />
|
||||
@@ -1414,7 +1403,9 @@
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="FileResources\BlockingWeb.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\umbraco.interfaces\umbraco.interfaces.csproj">
|
||||
@@ -1430,11 +1421,6 @@
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
|
||||
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
|
||||
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
|
||||
</Target>
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net4" />
|
||||
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Identity.Owin" version="2.2.1" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.WebApi.Client" version="4.0.30506.0" targetFramework="net45" />
|
||||
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
|
||||
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
|
||||
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin.Security.Cookies" version="3.0.1" targetFramework="net45" />
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Umbraco.Tests.Cache
|
||||
[Test]
|
||||
public void Clones_List()
|
||||
{
|
||||
var original = new DeepCloneableList<DeepCloneableListTests.TestClone>();
|
||||
var original = new DeepCloneableList<DeepCloneableListTests.TestClone>(ListCloneBehavior.Always);
|
||||
original.Add(new DeepCloneableListTests.TestClone());
|
||||
original.Add(new DeepCloneableListTests.TestClone());
|
||||
original.Add(new DeepCloneableListTests.TestClone());
|
||||
|
||||
@@ -120,5 +120,37 @@ namespace Umbraco.Tests.Cache
|
||||
Assert.IsTrue(cacheCleared);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void If_Removes_Throws_Cache_Is_Removed()
|
||||
{
|
||||
var cacheCleared = false;
|
||||
var cache = new Mock<IRuntimeCacheProvider>();
|
||||
cache.Setup(x => x.ClearCacheItem(It.IsAny<string>()))
|
||||
.Callback(() =>
|
||||
{
|
||||
cacheCleared = true;
|
||||
});
|
||||
|
||||
var defaultPolicy = new DefaultRepositoryCachePolicy<AuditItem, object>(cache.Object, new RepositoryCachePolicyOptions());
|
||||
try
|
||||
{
|
||||
using (defaultPolicy)
|
||||
{
|
||||
defaultPolicy.Remove(new AuditItem(1, "blah", AuditType.Copy, 123), item =>
|
||||
{
|
||||
throw new Exception("blah!");
|
||||
});
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//we need this catch or nunit throw up
|
||||
}
|
||||
finally
|
||||
{
|
||||
Assert.IsTrue(cacheCleared);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,57 @@ namespace Umbraco.Tests.Cache
|
||||
[TestFixture]
|
||||
public class FullDataSetCachePolicyTests
|
||||
{
|
||||
[Test]
|
||||
public void Caches_Single()
|
||||
{
|
||||
var getAll = new[]
|
||||
{
|
||||
new AuditItem(1, "blah", AuditType.Copy, 123),
|
||||
new AuditItem(2, "blah2", AuditType.Copy, 123)
|
||||
};
|
||||
|
||||
var isCached = false;
|
||||
var cache = new Mock<IRuntimeCacheProvider>();
|
||||
cache.Setup(x => x.InsertCacheItem(It.IsAny<string>(), It.IsAny<Func<object>>(), It.IsAny<TimeSpan?>(), It.IsAny<bool>(),
|
||||
It.IsAny<CacheItemPriority>(), It.IsAny<CacheItemRemovedCallback>(), It.IsAny<string[]>()))
|
||||
.Callback(() =>
|
||||
{
|
||||
isCached = true;
|
||||
});
|
||||
|
||||
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id, () => getAll, false);
|
||||
using (defaultPolicy)
|
||||
{
|
||||
var found = defaultPolicy.Get(1, o => new AuditItem(1, "blah", AuditType.Copy, 123));
|
||||
}
|
||||
Assert.IsTrue(isCached);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Single_From_Cache()
|
||||
{
|
||||
var getAll = new[]
|
||||
{
|
||||
new AuditItem(1, "blah", AuditType.Copy, 123),
|
||||
new AuditItem(2, "blah2", AuditType.Copy, 123)
|
||||
};
|
||||
|
||||
var cache = new Mock<IRuntimeCacheProvider>();
|
||||
cache.Setup(x => x.GetCacheItem(It.IsAny<string>())).Returns(new AuditItem(1, "blah", AuditType.Copy, 123));
|
||||
|
||||
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id, () => getAll, false);
|
||||
using (defaultPolicy)
|
||||
{
|
||||
var found = defaultPolicy.Get(1, o => (AuditItem)null);
|
||||
Assert.IsNotNull(found);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_All_Caches_Empty_List()
|
||||
{
|
||||
var getAll = new AuditItem[] {};
|
||||
|
||||
var cached = new List<string>();
|
||||
|
||||
IList list = null;
|
||||
@@ -33,23 +81,23 @@ namespace Umbraco.Tests.Cache
|
||||
cache.Setup(x => x.GetCacheItem(It.IsAny<string>())).Returns(() =>
|
||||
{
|
||||
//return null if this is the first pass
|
||||
return cached.Any() ? new DeepCloneableList<AuditItem>() : null;
|
||||
return cached.Any() ? new DeepCloneableList<AuditItem>(ListCloneBehavior.CloneOnce) : null;
|
||||
});
|
||||
|
||||
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id);
|
||||
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id, () => getAll, false);
|
||||
using (defaultPolicy)
|
||||
{
|
||||
var found = defaultPolicy.GetAll(new object[] {}, o => new AuditItem[] {});
|
||||
var found = defaultPolicy.GetAll(new object[] {}, o => getAll);
|
||||
}
|
||||
|
||||
Assert.AreEqual(1, cached.Count);
|
||||
Assert.IsNotNull(list);
|
||||
|
||||
//Do it again, ensure that its coming from the cache!
|
||||
defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id);
|
||||
defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id, () => getAll, false);
|
||||
using (defaultPolicy)
|
||||
{
|
||||
var found = defaultPolicy.GetAll(new object[] { }, o => new AuditItem[] { });
|
||||
var found = defaultPolicy.GetAll(new object[] { }, o => getAll);
|
||||
}
|
||||
|
||||
Assert.AreEqual(1, cached.Count);
|
||||
@@ -59,6 +107,12 @@ namespace Umbraco.Tests.Cache
|
||||
[Test]
|
||||
public void Get_All_Caches_As_Single_List()
|
||||
{
|
||||
var getAll = new[]
|
||||
{
|
||||
new AuditItem(1, "blah", AuditType.Copy, 123),
|
||||
new AuditItem(2, "blah2", AuditType.Copy, 123)
|
||||
};
|
||||
|
||||
var cached = new List<string>();
|
||||
IList list = null;
|
||||
|
||||
@@ -73,14 +127,10 @@ namespace Umbraco.Tests.Cache
|
||||
});
|
||||
cache.Setup(x => x.GetCacheItem(It.IsAny<string>())).Returns(new AuditItem[] { });
|
||||
|
||||
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id);
|
||||
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id, () => getAll, false);
|
||||
using (defaultPolicy)
|
||||
{
|
||||
var found = defaultPolicy.GetAll(new object[] { }, o => new[]
|
||||
{
|
||||
new AuditItem(1, "blah", AuditType.Copy, 123),
|
||||
new AuditItem(2, "blah2", AuditType.Copy, 123)
|
||||
});
|
||||
var found = defaultPolicy.GetAll(new object[] { }, o => getAll);
|
||||
}
|
||||
|
||||
Assert.AreEqual(1, cached.Count);
|
||||
@@ -89,21 +139,99 @@ namespace Umbraco.Tests.Cache
|
||||
|
||||
[Test]
|
||||
public void Get_All_Without_Ids_From_Cache()
|
||||
{
|
||||
{
|
||||
var getAll = new[] { (AuditItem)null };
|
||||
|
||||
var cache = new Mock<IRuntimeCacheProvider>();
|
||||
|
||||
cache.Setup(x => x.GetCacheItem(It.IsAny<string>())).Returns(() => new DeepCloneableList<AuditItem>
|
||||
cache.Setup(x => x.GetCacheItem(It.IsAny<string>())).Returns(() => new DeepCloneableList<AuditItem>(ListCloneBehavior.CloneOnce)
|
||||
{
|
||||
new AuditItem(1, "blah", AuditType.Copy, 123),
|
||||
new AuditItem(2, "blah2", AuditType.Copy, 123)
|
||||
});
|
||||
|
||||
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id);
|
||||
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id, () => getAll, false);
|
||||
using (defaultPolicy)
|
||||
{
|
||||
var found = defaultPolicy.GetAll(new object[] { }, o => new[] { (AuditItem)null });
|
||||
var found = defaultPolicy.GetAll(new object[] { }, o => getAll);
|
||||
Assert.AreEqual(2, found.Length);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void If_CreateOrUpdate_Throws_Cache_Is_Removed()
|
||||
{
|
||||
var getAll = new[]
|
||||
{
|
||||
new AuditItem(1, "blah", AuditType.Copy, 123),
|
||||
new AuditItem(2, "blah2", AuditType.Copy, 123)
|
||||
};
|
||||
|
||||
var cacheCleared = false;
|
||||
var cache = new Mock<IRuntimeCacheProvider>();
|
||||
cache.Setup(x => x.ClearCacheItem(It.IsAny<string>()))
|
||||
.Callback(() =>
|
||||
{
|
||||
cacheCleared = true;
|
||||
});
|
||||
|
||||
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id, () => getAll, false);
|
||||
try
|
||||
{
|
||||
using (defaultPolicy)
|
||||
{
|
||||
defaultPolicy.CreateOrUpdate(new AuditItem(1, "blah", AuditType.Copy, 123), item =>
|
||||
{
|
||||
throw new Exception("blah!");
|
||||
});
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//we need this catch or nunit throw up
|
||||
}
|
||||
finally
|
||||
{
|
||||
Assert.IsTrue(cacheCleared);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void If_Removes_Throws_Cache_Is_Removed()
|
||||
{
|
||||
var getAll = new[]
|
||||
{
|
||||
new AuditItem(1, "blah", AuditType.Copy, 123),
|
||||
new AuditItem(2, "blah2", AuditType.Copy, 123)
|
||||
};
|
||||
|
||||
var cacheCleared = false;
|
||||
var cache = new Mock<IRuntimeCacheProvider>();
|
||||
cache.Setup(x => x.ClearCacheItem(It.IsAny<string>()))
|
||||
.Callback(() =>
|
||||
{
|
||||
cacheCleared = true;
|
||||
});
|
||||
|
||||
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object, item => item.Id, () => getAll, false);
|
||||
try
|
||||
{
|
||||
using (defaultPolicy)
|
||||
{
|
||||
defaultPolicy.Remove(new AuditItem(1, "blah", AuditType.Copy, 123), item =>
|
||||
{
|
||||
throw new Exception("blah!");
|
||||
});
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//we need this catch or nunit throw up
|
||||
}
|
||||
finally
|
||||
{
|
||||
Assert.IsTrue(cacheCleared);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,10 +12,44 @@ namespace Umbraco.Tests.Collections
|
||||
[TestFixture]
|
||||
public class DeepCloneableListTests
|
||||
{
|
||||
[Test]
|
||||
public void Deep_Clones_Each_Item_Once()
|
||||
{
|
||||
var list = new DeepCloneableList<TestClone>(ListCloneBehavior.CloneOnce);
|
||||
list.Add(new TestClone());
|
||||
list.Add(new TestClone());
|
||||
list.Add(new TestClone());
|
||||
|
||||
var cloned = list.DeepClone() as DeepCloneableList<TestClone>;
|
||||
|
||||
//Test that each item in the sequence is equal - based on the equality comparer of TestClone (i.e. it's ID)
|
||||
Assert.IsTrue(list.SequenceEqual(cloned));
|
||||
|
||||
//Test that each instance in the list is not the same one
|
||||
foreach (var item in list)
|
||||
{
|
||||
var clone = cloned.Single(x => x.Id == item.Id);
|
||||
Assert.AreNotSame(item, clone);
|
||||
}
|
||||
|
||||
//clone again from the clone - since it's clone once the items should be the same
|
||||
var cloned2 = cloned.DeepClone() as DeepCloneableList<TestClone>;
|
||||
|
||||
//Test that each item in the sequence is equal - based on the equality comparer of TestClone (i.e. it's ID)
|
||||
Assert.IsTrue(cloned.SequenceEqual(cloned2));
|
||||
|
||||
//Test that each instance in the list is the same one
|
||||
foreach (var item in cloned)
|
||||
{
|
||||
var clone = cloned2.Single(x => x.Id == item.Id);
|
||||
Assert.AreSame(item, clone);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Deep_Clones_All_Elements()
|
||||
{
|
||||
var list = new DeepCloneableList<TestClone>();
|
||||
var list = new DeepCloneableList<TestClone>(ListCloneBehavior.Always);
|
||||
list.Add(new TestClone());
|
||||
list.Add(new TestClone());
|
||||
list.Add(new TestClone());
|
||||
@@ -30,7 +64,7 @@ namespace Umbraco.Tests.Collections
|
||||
[Test]
|
||||
public void Clones_Each_Item()
|
||||
{
|
||||
var list = new DeepCloneableList<TestClone>();
|
||||
var list = new DeepCloneableList<TestClone>(ListCloneBehavior.Always);
|
||||
list.Add(new TestClone());
|
||||
list.Add(new TestClone());
|
||||
list.Add(new TestClone());
|
||||
@@ -46,7 +80,7 @@ namespace Umbraco.Tests.Collections
|
||||
[Test]
|
||||
public void Cloned_Sequence_Equals()
|
||||
{
|
||||
var list = new DeepCloneableList<TestClone>();
|
||||
var list = new DeepCloneableList<TestClone>(ListCloneBehavior.Always);
|
||||
list.Add(new TestClone());
|
||||
list.Add(new TestClone());
|
||||
list.Add(new TestClone());
|
||||
|
||||
@@ -12,7 +12,7 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
@@ -514,6 +514,35 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Perform_Query_On_ContentTypeRepository_Sort_By_Name()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var contentType = repository.Get(NodeDto.NodeIdSeed + 1);
|
||||
var child1 = MockedContentTypes.CreateSimpleContentType("aabc", "aabc", contentType, randomizeAliases: true);
|
||||
repository.AddOrUpdate(child1);
|
||||
var child3 = MockedContentTypes.CreateSimpleContentType("zyx", "zyx", contentType, randomizeAliases: true);
|
||||
repository.AddOrUpdate(child3);
|
||||
var child2 = MockedContentTypes.CreateSimpleContentType("a123", "a123", contentType, randomizeAliases: true);
|
||||
repository.AddOrUpdate(child2);
|
||||
unitOfWork.Commit();
|
||||
|
||||
// Act
|
||||
var contentTypes = repository.GetByQuery(new Query<IContentType>().Where(x => x.ParentId == contentType.Id));
|
||||
|
||||
// Assert
|
||||
Assert.That(contentTypes.Count(), Is.EqualTo(3));
|
||||
Assert.AreEqual("a123", contentTypes.ElementAt(0).Name);
|
||||
Assert.AreEqual("aabc", contentTypes.ElementAt(1).Name);
|
||||
Assert.AreEqual("zyx", contentTypes.ElementAt(2).Name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Perform_Get_On_ContentTypeRepository()
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
@@ -103,7 +104,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
<asp:Content ContentPlaceHolderID=""ContentPlaceHolderDefault"" runat=""server"">
|
||||
|
||||
</asp:Content>
|
||||
".CrLf(), template.Content);
|
||||
".StripWhitespace(), template.Content.StripWhitespace());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -132,7 +133,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
Assert.That(_masterPageFileSystem.FileExists("test2.master"), Is.True);
|
||||
Assert.AreEqual(@"<%@ Master Language=""C#"" MasterPageFile=""~/masterpages/test.master"" AutoEventWireup=""true"" %>
|
||||
|
||||
".CrLf(), template2.Content);
|
||||
".StripWhitespace(), template2.Content.StripWhitespace());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -176,10 +177,9 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
//Assert
|
||||
Assert.That(repository.Get("test"), Is.Not.Null);
|
||||
Assert.That(_viewsFileSystem.FileExists("test.cshtml"), Is.True);
|
||||
Assert.AreEqual(@"@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
|
||||
@{
|
||||
" + "\t" + @"Layout = null;
|
||||
}".Lf(), template.Content.Lf());
|
||||
Assert.AreEqual(
|
||||
@"@inherits Umbraco.Web.Mvc.UmbracoTemplatePage @{ Layout = null;}".StripWhitespace(),
|
||||
template.Content.StripWhitespace());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -206,12 +206,10 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
//Assert
|
||||
Assert.That(repository.Get("test2"), Is.Not.Null);
|
||||
Assert.That(_viewsFileSystem.FileExists("test2.cshtml"), Is.True);
|
||||
Assert.AreEqual(@"@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
|
||||
@{
|
||||
" + "\t" + @"Layout = ""test.cshtml"";
|
||||
}".Lf(), template2.Content.Lf());
|
||||
Assert.AreEqual(
|
||||
"@inherits Umbraco.Web.Mvc.UmbracoTemplatePage @{ Layout = \"test.cshtml\";}".StripWhitespace(),
|
||||
template2.Content.StripWhitespace());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace Umbraco.Tests.Security
|
||||
|
||||
var identity = new UmbracoBackOfficeIdentity(userData);
|
||||
|
||||
Assert.AreEqual(10, identity.Claims.Count());
|
||||
Assert.AreEqual(11, identity.Claims.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -132,7 +132,7 @@ namespace Umbraco.Tests.Security
|
||||
|
||||
var backofficeIdentity = new UmbracoBackOfficeIdentity(claimsIdentity, userData);
|
||||
|
||||
Assert.AreEqual(12, backofficeIdentity.Claims.Count());
|
||||
Assert.AreEqual(13, backofficeIdentity.Claims.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -156,7 +156,7 @@ namespace Umbraco.Tests.Security
|
||||
|
||||
var identity = new UmbracoBackOfficeIdentity(ticket);
|
||||
|
||||
Assert.AreEqual(11, identity.Claims.Count());
|
||||
Assert.AreEqual(12, identity.Claims.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -182,7 +182,7 @@ namespace Umbraco.Tests.Security
|
||||
|
||||
var cloned = identity.Clone();
|
||||
|
||||
Assert.AreEqual(11, cloned.Claims.Count());
|
||||
Assert.AreEqual(12, cloned.Claims.Count());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Strings.Css;
|
||||
|
||||
namespace Umbraco.Tests.Strings
|
||||
@@ -22,7 +23,7 @@ namespace Umbraco.Tests.Strings
|
||||
});
|
||||
|
||||
Assert.AreEqual(@"body {font-family:Arial;}/**umb_name:My new rule*/
|
||||
p{font-size:1em; color:blue;} /** umb_name: Test2 */ li {padding:0px;} table {margin:0;}".CrLf(), result);
|
||||
p{font-size:1em; color:blue;} /** umb_name: Test2 */ li {padding:0px;} table {margin:0;}".StripWhitespace(), result.StripWhitespace());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -40,7 +41,7 @@ p{font-size:1em; color:blue;} /** umb_name: Test2 */ li {padding:0px;} table {m
|
||||
Assert.AreEqual(@"body {font-family:Arial;}/** Umb_Name: Test1 */ p { font-size: 1em; } /** umb_name: Test2 */ li {padding:0px;} table {margin:0;}
|
||||
|
||||
/**umb_name:My new rule*/
|
||||
p{font-size:1em; color:blue;}".CrLf(), result);
|
||||
p{font-size:1em; color:blue;}".StripWhitespace(), result.StripWhitespace());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -95,7 +96,7 @@ font-size: 1em;
|
||||
//Assert.IsTrue(results.First().RuleId.Value.Value.ToString() == file.Id.Value.Value + "/" + name);
|
||||
Assert.AreEqual(name, results.First().Name);
|
||||
Assert.AreEqual(selector, results.First().Selector);
|
||||
Assert.AreEqual(styles.CrLf(), results.First().Styles);
|
||||
Assert.AreEqual(styles.StripWhitespace(), results.First().Styles.StripWhitespace());
|
||||
}
|
||||
|
||||
// No Name: keyword
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"name": "umbraco",
|
||||
"homepage": "https://github.com/umbraco/umbraco-cms/",
|
||||
"version": "7.1.2",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:umbraco/umbraco-cms.git"
|
||||
@@ -10,12 +11,6 @@
|
||||
"bugs": {
|
||||
"url": "https://issues.umbraco.org"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/umbraco/Umbraco-CMS/blob/7.0.0/docs/License.txt"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 0.8.4"
|
||||
},
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 957 B |
@@ -1,52 +1,57 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
function EditorHeaderDirective(iconHelper) {
|
||||
function EditorHeaderDirective(iconHelper) {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
scope.openIconPicker = function() {
|
||||
scope.dialogModel = {
|
||||
view: "iconpicker",
|
||||
show: true,
|
||||
submit: function(model) {
|
||||
if (model.color) {
|
||||
scope.icon = model.icon + " " + model.color;
|
||||
} else {
|
||||
scope.icon = model.icon;
|
||||
scope.openIconPicker = function() {
|
||||
scope.dialogModel = {
|
||||
view: "iconpicker",
|
||||
show: true,
|
||||
submit: function(model) {
|
||||
if (model.color) {
|
||||
scope.icon = model.icon + " " + model.color;
|
||||
} else {
|
||||
scope.icon = model.icon;
|
||||
}
|
||||
|
||||
// set form to dirty
|
||||
ctrl.$setDirty();
|
||||
|
||||
scope.dialogModel.show = false;
|
||||
scope.dialogModel = null;
|
||||
}
|
||||
scope.dialogModel.show = false;
|
||||
scope.dialogModel = null;
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var directive = {
|
||||
transclude: true,
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/editor/umb-editor-header.html',
|
||||
scope: {
|
||||
tabs: "=",
|
||||
actions: "=",
|
||||
name: "=",
|
||||
nameLocked: "=",
|
||||
menu: "=",
|
||||
icon: "=",
|
||||
hideIcon: "@",
|
||||
alias: "=",
|
||||
hideAlias: "@",
|
||||
description: "=",
|
||||
hideDescription: "@",
|
||||
navigation: "="
|
||||
},
|
||||
link: link
|
||||
};
|
||||
var directive = {
|
||||
require: '^form',
|
||||
transclude: true,
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/editor/umb-editor-header.html',
|
||||
scope: {
|
||||
tabs: "=",
|
||||
actions: "=",
|
||||
name: "=",
|
||||
nameLocked: "=",
|
||||
menu: "=",
|
||||
icon: "=",
|
||||
hideIcon: "@",
|
||||
alias: "=",
|
||||
hideAlias: "@",
|
||||
description: "=",
|
||||
hideDescription: "@",
|
||||
navigation: "="
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
}
|
||||
return directive;
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbEditorHeader', EditorHeaderDirective);
|
||||
angular.module('umbraco.directives').directive('umbEditorHeader', EditorHeaderDirective);
|
||||
|
||||
})();
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function GroupsBuilderDirective(contentTypeHelper, contentTypeResource, mediaTypeResource, dataTypeHelper, dataTypeResource, $filter, iconHelper, $q, $timeout) {
|
||||
function GroupsBuilderDirective(contentTypeHelper, contentTypeResource, mediaTypeResource, dataTypeHelper, dataTypeResource, $filter, iconHelper, $q, $timeout, notificationsService, localizationService) {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
var validationTranslated = "";
|
||||
var tabNoSortOrderTranslated = "";
|
||||
|
||||
scope.sortingMode = false;
|
||||
scope.toolbar = [];
|
||||
scope.sortableOptionsGroup = {};
|
||||
@@ -25,6 +28,14 @@
|
||||
// add init tab
|
||||
addInitGroup(scope.model.groups);
|
||||
|
||||
// localize texts
|
||||
localizationService.localize("validation_validation").then(function(value) {
|
||||
validationTranslated = value;
|
||||
});
|
||||
|
||||
localizationService.localize("contentTypeEditor_tabHasNoSortOrder").then(function(value) {
|
||||
tabNoSortOrderTranslated = value;
|
||||
});
|
||||
}
|
||||
|
||||
function setSortingOptions() {
|
||||
@@ -202,13 +213,30 @@
|
||||
|
||||
scope.toggleSortingMode = function(tool) {
|
||||
|
||||
scope.sortingMode = !scope.sortingMode;
|
||||
if (scope.sortingMode === true) {
|
||||
|
||||
if(scope.sortingMode === true) {
|
||||
scope.sortingButtonKey = "general_reorderDone";
|
||||
} else {
|
||||
scope.sortingButtonKey = "general_reorder";
|
||||
}
|
||||
var sortOrderMissing = false;
|
||||
|
||||
for (var i = 0; i < scope.model.groups.length; i++) {
|
||||
var group = scope.model.groups[i];
|
||||
if (group.tabState !== "init" && group.sortOrder === undefined) {
|
||||
sortOrderMissing = true;
|
||||
group.showSortOrderMissing = true;
|
||||
notificationsService.error(validationTranslated + ": " + group.name + " " + tabNoSortOrderTranslated);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sortOrderMissing) {
|
||||
scope.sortingMode = false;
|
||||
scope.sortingButtonKey = "general_reorder";
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
scope.sortingMode = true;
|
||||
scope.sortingButtonKey = "general_reorderDone";
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -394,8 +422,12 @@
|
||||
}
|
||||
};
|
||||
|
||||
scope.changeSortOrderValue = function() {
|
||||
scope.model.groups = $filter('orderBy')(scope.model.groups, 'sortOrder');
|
||||
scope.changeSortOrderValue = function(group) {
|
||||
|
||||
if (group.sortOrder !== undefined) {
|
||||
group.showSortOrderMissing = false;
|
||||
}
|
||||
scope.model.groups = $filter('orderBy')(scope.model.groups, 'sortOrder');
|
||||
};
|
||||
|
||||
function addInitGroup(groups) {
|
||||
|
||||
@@ -51,13 +51,14 @@
|
||||
templateUrl: 'views/components/umb-table.html',
|
||||
scope: {
|
||||
items: '=',
|
||||
itemProperties: "=",
|
||||
itemProperties: '=',
|
||||
allowSelectAll: '=',
|
||||
onSelect: '=',
|
||||
onClick: "=",
|
||||
onSelectAll: "=",
|
||||
onSelectedAll: "=",
|
||||
onSortingDirection: "=",
|
||||
onSort:"="
|
||||
onClick: '=',
|
||||
onSelectAll: '=',
|
||||
onSelectedAll: '=',
|
||||
onSortingDirection: '=',
|
||||
onSort: '='
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ function valServerField(serverValidationManager) {
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
|
||||
var fieldName = null;
|
||||
var eventBindings = [];
|
||||
|
||||
attr.$observe("valServerField", function (newVal) {
|
||||
if (newVal && fieldName === null) {
|
||||
@@ -22,11 +23,11 @@ function valServerField(serverValidationManager) {
|
||||
// resubmitted. So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
ctrl.$viewChangeListeners.push(function () {
|
||||
eventBindings.push(scope.$watch('ngModel', function(newValue){
|
||||
if (ctrl.$invalid) {
|
||||
ctrl.$setValidity('valServerField', true);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
//subscribe to the server validation changes
|
||||
serverValidationManager.subscribe(null, fieldName, function (isValid, fieldErrors, allErrors) {
|
||||
@@ -48,10 +49,17 @@ function valServerField(serverValidationManager) {
|
||||
element.bind('$destroy', function () {
|
||||
serverValidationManager.unsubscribe(null, fieldName);
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
scope.$on('$destroy', function(){
|
||||
// unbind watchers
|
||||
for(var e in eventBindings) {
|
||||
eventBindings[e]();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives.validation').directive("valServerField", valServerField);
|
||||
angular.module('umbraco.directives.validation').directive("valServerField", valServerField);
|
||||
|
||||
@@ -716,7 +716,7 @@ angular.module('umbraco.mocks').
|
||||
"user_administrators": "Administrator",
|
||||
"user_categoryField": "Category field",
|
||||
"user_changePassword": "Change Your Password",
|
||||
"user_newPassword": "Change Your Password",
|
||||
"user_newPassword": "New password",
|
||||
"user_confirmNewPassword": "Confirm new password",
|
||||
"user_changePasswordDescription": "You can change your password for accessing the Umbraco Back Office by filling out the form below and click the 'Change Password' button",
|
||||
"user_contentChannel": "Content Channel",
|
||||
@@ -730,6 +730,7 @@ angular.module('umbraco.mocks').
|
||||
"user_mediastartnode": "Start Node in Media Library",
|
||||
"user_modules": "Sections",
|
||||
"user_noConsole": "Disable Umbraco Access",
|
||||
"user_oldPassword": "Old password",
|
||||
"user_password": "Password",
|
||||
"user_resetPassword": "Reset password",
|
||||
"user_passwordChanged": "Your password has been changed!",
|
||||
|
||||
@@ -88,8 +88,7 @@
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.umb-card-grid li {
|
||||
padding: 5px;
|
||||
@@ -98,31 +97,42 @@
|
||||
text-align: center;
|
||||
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
height: 105px;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-card-grid li.-four-in-row {
|
||||
flex: 0 0 25%;
|
||||
}
|
||||
.umb-card-grid li.-four-in-row {
|
||||
flex: 0 0 25%;
|
||||
}
|
||||
|
||||
.umb-card-grid li.-three-in-row {
|
||||
flex: 0 0 33.33%;
|
||||
}
|
||||
.umb-card-grid li.-three-in-row {
|
||||
flex: 0 0 33.33%;
|
||||
}
|
||||
|
||||
.umb-card-grid li:hover, .umb-card-grid li:hover * {
|
||||
background: @blue;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
.umb-card-grid .umb-card-grid-item {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
.umb-card-grid .umb-card-grid-item:hover,
|
||||
.umb-card-grid .umb-card-grid-item:focus,
|
||||
.umb-card-grid .umb-card-grid-item:hover > *,
|
||||
.umb-card-grid .umb-card-grid-item:focus > * {
|
||||
background: @blue;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.umb-card-grid a {
|
||||
color: #222;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.umb-card-grid i{
|
||||
.umb-card-grid i {
|
||||
font-size: 30px;
|
||||
line-height: 50px;
|
||||
display: block;
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
}
|
||||
|
||||
.umb-group-builder__group.-inherited {
|
||||
background: #FDFDFD;
|
||||
border-color: #F2F2F2;
|
||||
animation: fadeIn 0.5s;
|
||||
}
|
||||
@@ -90,7 +89,6 @@
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.umb-group-builder__group-title-icon {
|
||||
@@ -109,7 +107,6 @@
|
||||
|
||||
.umb-group-builder__group-title.-inherited {
|
||||
border-color: #F2F2F2;
|
||||
background: #FDFDFD;
|
||||
}
|
||||
|
||||
input.umb-group-builder__group-title-input {
|
||||
@@ -134,6 +131,15 @@ input.umb-group-builder__group-title-input {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.umb-group-builder__group-sort-order {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 10px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
input.umb-group-builder__group-sort-value {
|
||||
@@ -141,10 +147,7 @@ input.umb-group-builder__group-sort-value {
|
||||
padding: 0px 0 0px 5px;
|
||||
width: 40px;
|
||||
margin-bottom: 0;
|
||||
margin-right: 10px;
|
||||
border-color: #d9d9d9;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
/* ---------- PROPERTIES ---------- */
|
||||
@@ -182,7 +185,6 @@ input.umb-group-builder__group-sort-value {
|
||||
|
||||
.umb-group-builder__property.-inherited {
|
||||
border: transparent;
|
||||
background: #FDFDFD;
|
||||
animation: fadeIn 0.5s;
|
||||
}
|
||||
|
||||
@@ -192,7 +194,6 @@ input.umb-group-builder__group-sort-value {
|
||||
|
||||
.umb-group-builder__property.-locked {
|
||||
border: transparent;
|
||||
background: #FDFDFD;
|
||||
animation: fadeIn 0.5s;
|
||||
}
|
||||
|
||||
@@ -233,7 +234,9 @@ input.umb-group-builder__group-sort-value {
|
||||
.umb-group-builder__property-meta-alias {
|
||||
font-size: 10px;
|
||||
color: @gray;
|
||||
word-wrap: break-word;
|
||||
word-break: break-word;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.umb-group-builder__property-meta-label textarea {
|
||||
@@ -257,6 +260,7 @@ input.umb-group-builder__group-sort-value {
|
||||
|
||||
.umb-group-builder__property-meta-description textarea {
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
color: @grayDark;
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
@@ -275,6 +279,7 @@ input.umb-group-builder__group-sort-value {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
padding: 35px 10px 25px 10px;
|
||||
background: url("../img/checkered-background-20.png");
|
||||
}
|
||||
|
||||
.umb-group-builder__property-preview:hover {
|
||||
@@ -293,17 +298,6 @@ input.umb-group-builder__group-sort-value {
|
||||
display:none !important;
|
||||
}
|
||||
|
||||
.umb-group-builder__property-preview-background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
background: url("../img/checkered-background.png");
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.umb-group-builder__property-preview-label {
|
||||
font-size: 11px;
|
||||
position: absolute;
|
||||
|
||||
@@ -78,3 +78,94 @@ iframe, .content-column-body {
|
||||
.icon-chevron-down:before {
|
||||
content: "\e0c9";
|
||||
}
|
||||
|
||||
|
||||
/* Styling for validation in Public Access */
|
||||
|
||||
.pa-umb-overlay {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.pa-umb-overlay + .pa-umb-overlay {
|
||||
padding-top: 30px;
|
||||
border-top: 1px solid @grayLight;
|
||||
}
|
||||
|
||||
.pa-select-type {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.pa-select-type label {
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.pa-access-header {
|
||||
font-weight: bold;
|
||||
margin: 0 0 3px 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.pa-access-description {
|
||||
color: #b3b3b3;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.pa-validation-message {
|
||||
padding: 6px 12px !important;
|
||||
margin: 5px 0 0 0 !important;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.pa-select-pages label {
|
||||
margin: 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.pa-select-pages label + .controls-row {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.pa-select-pages .umb-detail {
|
||||
font-size: 13px;
|
||||
margin: 2px 0 5px;
|
||||
}
|
||||
|
||||
.pa-choose-page a {
|
||||
color: @blue;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.pa-choose-page a:hover, .pa-choose-page a:active, .pa-choose-page a:focus {
|
||||
color: @blueDark;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.pa-choose-page a:before {
|
||||
content:"+";
|
||||
margin-right: 3px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.pa-choose-page .treePickerTitle {
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
font-style: italic;
|
||||
background: whitesmoke;
|
||||
padding: 3px 5px;
|
||||
color: grey;
|
||||
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
|
||||
.pa-form + .pa-form {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
@@ -200,10 +200,6 @@ ul.color-picker li a {
|
||||
border: 1px solid #f8f8f8;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails li:hover a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails li img {
|
||||
max-width:100%;
|
||||
max-height:100%;
|
||||
@@ -228,6 +224,43 @@ ul.color-picker li a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails .umb-sortable-thumbnails__actions {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails li:hover .umb-sortable-thumbnails__actions {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails .umb-sortable-thumbnails__action {
|
||||
font-size: 16px;
|
||||
background: white;
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
border-radius: 15px;
|
||||
color: @grayDarker;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails .umb-sortable-thumbnails__action.-red {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails .umb-sortable-thumbnails__action:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Cropper
|
||||
@@ -644,3 +677,10 @@ ul.color-picker li a {
|
||||
height: 100%;
|
||||
min-height:200px;
|
||||
}
|
||||
|
||||
//
|
||||
// Nested boolean (e.g. list view bulk action permissions)
|
||||
// ---------------------=====-----------------------------
|
||||
.umb-nested-boolean label {margin-bottom: 8px; float: left; width: 320px;}
|
||||
.umb-nested-boolean label span {float: left; width: 80%;}
|
||||
.umb-nested-boolean label input[type='checkbox'] {margin-right: 10px; float: left;}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
ng-mouseover="vm.showDetailsOverlay(systemDataType)"
|
||||
ng-click="vm.pickEditor(systemDataType)"
|
||||
class="-four-in-row">
|
||||
<a href="" title="{{ systemDataType.name }}">
|
||||
<a class="umb-card-grid-item" href="" title="{{ systemDataType.name }}">
|
||||
<i class="{{ systemDataType.icon }}" ng-class="{'icon-autofill': systemDataType.icon == null}"></i>
|
||||
{{ systemDataType.name }}
|
||||
</a>
|
||||
@@ -51,7 +51,7 @@
|
||||
ng-mouseover="vm.showDetailsOverlay(dataType)"
|
||||
ng-click="vm.pickDataType(dataType)"
|
||||
class="-four-in-row">
|
||||
<a href="" title="{{ dataType.name }}">
|
||||
<a class="umb-card-grid-item" href="" title="{{ dataType.name }}">
|
||||
<i class="{{ dataType.icon }}" ng-class="{'icon-autofill': dataType.icon == null}"></i>
|
||||
{{ dataType.name }}
|
||||
</a>
|
||||
@@ -78,7 +78,7 @@
|
||||
ng-mouseover="vm.showDetailsOverlay(dataType)"
|
||||
ng-click="vm.pickDataType(dataType)"
|
||||
class="-four-in-row">
|
||||
<a href="" title="{{ dataType.name }}">
|
||||
<a class="umb-card-grid-item" href="" title="{{ dataType.name }}">
|
||||
<i class="{{ dataType.icon }}" ng-class="{'icon-autofill': dataType.icon == null}"></i>
|
||||
{{ dataType.name }}
|
||||
</a>
|
||||
@@ -96,7 +96,7 @@
|
||||
ng-mouseover="vm.showDetailsOverlay(systemDataType)"
|
||||
ng-click="vm.pickEditor(systemDataType)"
|
||||
class="-four-in-row">
|
||||
<a href="" title="{{ systemDataType.name }}">
|
||||
<a class="umb-card-grid-item" href="" title="{{ systemDataType.name }}">
|
||||
<i class="{{ systemDataType.icon }}" ng-class="{'icon-autofill': systemDataType.icon == null}"></i>
|
||||
{{ systemDataType.name }}
|
||||
</a>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
ng-repeat="availableItem in model.availableItems | compareArrays:model.selectedItems:'alias' | orderBy:'name' | filter:searchTerm"
|
||||
ng-click="selectItem(availableItem)"
|
||||
class="-three-in-row">
|
||||
<a href="" title="{{ availableItem.name }}">
|
||||
<a class="umb-card-grid-item" href="" title="{{ availableItem.name }}">
|
||||
<i class="{{ availableItem.icon }}"></i>
|
||||
{{ availableItem.name }}
|
||||
</a>
|
||||
|
||||
@@ -30,18 +30,18 @@ angular.module("umbraco")
|
||||
var pendingChangeEvent = eventsService.on("valFormManager.pendingChanges", function (e, args) {
|
||||
//one time listener, remove the event
|
||||
pendingChangeEvent();
|
||||
$scope.closeOverLay();
|
||||
$scope.model.close();
|
||||
});
|
||||
|
||||
|
||||
//perform the path change, if it is successful then the promise will resolve otherwise it will fail
|
||||
$scope.closeOverLay();
|
||||
$scope.model.close();
|
||||
$location.path("/logout");
|
||||
};
|
||||
|
||||
$scope.gotoHistory = function (link) {
|
||||
$location.path(link);
|
||||
$scope.closeOverLay();
|
||||
$scope.model.close();
|
||||
};
|
||||
|
||||
//Manually update the remaining timeout seconds
|
||||
@@ -147,6 +147,9 @@ angular.module("umbraco")
|
||||
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
|
||||
|
||||
$scope.changePasswordButtonState = "success";
|
||||
$timeout(function() {
|
||||
$scope.togglePasswordFields();
|
||||
}, 2000);
|
||||
|
||||
}, function (err) {
|
||||
|
||||
|
||||
@@ -10,23 +10,32 @@
|
||||
</small>
|
||||
</p>
|
||||
|
||||
<a href="#/users/framed/%252Fumbraco%252Fusers%252Fedituser.aspx%253Fid%253D{{user.id}}"
|
||||
class="btn btn-primary"
|
||||
ng-click="closeOverLay()"
|
||||
ng-if="canEditProfile">
|
||||
<localize key="general_edit">Edit</localize>
|
||||
</a>
|
||||
|
||||
<umb-button
|
||||
type="button"
|
||||
action="togglePasswordFields()"
|
||||
label="Change password"
|
||||
button-style="success">
|
||||
<umb-button
|
||||
type="link"
|
||||
href="#/users/framed/%252Fumbraco%252Fusers%252Fedituser.aspx%253Fid%253D{{user.id}}"
|
||||
action="model.close()"
|
||||
button-style="primary"
|
||||
label="Edit"
|
||||
label-key="general_edit"
|
||||
ng-if="canEditProfile">
|
||||
</umb-button>
|
||||
|
||||
<button ng-click="logout()" hotkey="ctrl+shift+l" class="btn btn-warning">
|
||||
<localize key="general_logout">Log out</localize>
|
||||
</button>
|
||||
<umb-button
|
||||
type="button"
|
||||
action="togglePasswordFields()"
|
||||
label="Change password"
|
||||
label-key="general_changePassword"
|
||||
button-style="success">
|
||||
</umb-button>
|
||||
|
||||
<umb-button
|
||||
type="button"
|
||||
action="logout()"
|
||||
shortcut="ctrl+shift+l"
|
||||
button-style="warning"
|
||||
label="Log out"
|
||||
label-key="general_logout">
|
||||
</umb-button>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -91,19 +100,21 @@
|
||||
|
||||
<umb-editor model="changePasswordModel"></umb-editor>
|
||||
|
||||
<umb-button
|
||||
type="button"
|
||||
action="togglePasswordFields()"
|
||||
label="Back"
|
||||
button-style="Cancel">
|
||||
<umb-button
|
||||
type="button"
|
||||
action="togglePasswordFields()"
|
||||
label="Back"
|
||||
label-key="general_back"
|
||||
button-style="cancel">
|
||||
</umb-button>
|
||||
|
||||
<umb-button
|
||||
type="submit"
|
||||
label="Change password"
|
||||
state="changePasswordButtonState"
|
||||
button-style="success">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
type="submit"
|
||||
label="Change password"
|
||||
label-key="general_changePassword"
|
||||
state="changePasswordButtonState"
|
||||
button-style="success">
|
||||
</umb-button>
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<div ng-if="state !== 'init'" class="umb-button__overlay"></div>
|
||||
|
||||
<a ng-if="type === 'link'" href="{{href}}" class="btn umb-button__button {{style}}" hotkey="{{shortcut}}" hotkey-when-hidden="{{shortcutWhenHidden}}">
|
||||
<a ng-if="type === 'link'" href="{{href}}" class="btn umb-button__button {{style}}" ng-click="action(model)" hotkey="{{shortcut}}" hotkey-when-hidden="{{shortcutWhenHidden}}">
|
||||
<span class="umb-button__content" ng-class="{'-hidden': state !== 'init'}">
|
||||
<i ng-if="icon && buttonStyle==='link'" class="{{icon}} umb-button__icon"></i>
|
||||
<localize ng-if="labelKey" key="{{labelKey}}">{{label}}</localize>
|
||||
|
||||
@@ -84,7 +84,13 @@
|
||||
</div>
|
||||
</ng-form>
|
||||
|
||||
<input type="number" class="umb-group-builder__group-sort-value" ng-if="sortingMode" ng-model="tab.sortOrder" ng-disabled="tab.inherited" on-blur="changeSortOrderValue()" />
|
||||
<ng-form name="groupSortOrderForm">
|
||||
<div class="umb-group-builder__group-sort-order" ng-if="sortingMode">
|
||||
<input name="groupSortOrder" type="number" class="umb-group-builder__group-sort-value" ng-model="tab.sortOrder" ng-disabled="tab.inherited" on-blur="changeSortOrderValue(tab)" required />
|
||||
<div class="umb-validation-label -arrow-left" ng-if="groupSortOrderForm.groupSortOrder.$error.required && tab.showSortOrderMissing"><localize key="required"></localize></div>
|
||||
<div class="umb-validation-label -arrow-left" ng-if="!tab.showSortOrderMissing" val-msg-for="groupSortOrder" val-toggle-msg="required"><localize key="required"></localize></div>
|
||||
</div>
|
||||
</ng-form>
|
||||
|
||||
<div class="umb-group-builder__group-inherited-label" ng-if="tab.inherited">
|
||||
<i class="icon icon-merge"></i>
|
||||
@@ -226,8 +232,6 @@
|
||||
</umb-property-editor>
|
||||
</ng-form>
|
||||
|
||||
<div class="umb-group-builder__property-preview-background"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- row tools -->
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
<div class="umb-table-cell">
|
||||
<input class="umb-table__input" type="checkbox"
|
||||
ng-click="selectAll($event)"
|
||||
ng-checked="isSelectedAll()"
|
||||
>
|
||||
ng-if="allowSelectAll"
|
||||
ng-click="selectAll($event)"
|
||||
ng-checked="isSelectedAll()">
|
||||
</div>
|
||||
|
||||
<div class="umb-table-cell umb-table__name">
|
||||
@@ -22,8 +22,8 @@
|
||||
|
||||
<div class="umb-table-cell" ng-repeat="column in itemProperties">
|
||||
<a class="umb-table-head__link" title="Sort by {{ column.header }}" href="#"
|
||||
ng-click="sort(column.alias, column.allowSorting)"
|
||||
ng-class="{'sortable':column.allowSorting}" prevent-default>
|
||||
ng-click="sort(column.alias, column.allowSorting)"
|
||||
ng-class="{'sortable':column.allowSorting}" prevent-default>
|
||||
|
||||
<span ng-bind="column.header"></span>
|
||||
<i class="umb-table-head__icon icon" ng-class="{'icon-navigation-up': isSortDirection(column.alias, 'asc'), 'icon-navigation-down': isSortDirection(column.alias, 'desc')}"></i>
|
||||
@@ -36,14 +36,13 @@
|
||||
<!-- Listview body section -->
|
||||
<div class="umb-table-body">
|
||||
<div class="umb-table-row"
|
||||
ng-repeat="item in items"
|
||||
ng-class="{
|
||||
ng-repeat="item in items"
|
||||
ng-class="{
|
||||
'-selected':item.selected,
|
||||
'-published':item.published,
|
||||
'-unpublished':!item.published
|
||||
}"
|
||||
ng-click="selectItem(item, $index, $event)"
|
||||
>
|
||||
ng-click="selectItem(item, $index, $event)">
|
||||
|
||||
|
||||
<div class="umb-table-cell">
|
||||
@@ -53,8 +52,8 @@
|
||||
|
||||
<div class="umb-table-cell umb-table__name">
|
||||
<a title="{{ item.name }}" class="umb-table-body__link" href=""
|
||||
ng-click="clickItem(item, $event)"
|
||||
ng-bind="item.name">
|
||||
ng-click="clickItem(item, $event)"
|
||||
ng-bind="item.name">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @description
|
||||
* The controller for the content editor
|
||||
*/
|
||||
function DataTypeEditController($scope, $routeParams, $location, appState, navigationService, treeService, dataTypeResource, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, formHelper, editorState, dataTypeHelper) {
|
||||
function DataTypeEditController($scope, $routeParams, $location, appState, navigationService, treeService, dataTypeResource, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, formHelper, editorState, dataTypeHelper, eventsService) {
|
||||
|
||||
//setup scope vars
|
||||
$scope.page = {};
|
||||
@@ -15,6 +15,7 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig
|
||||
$scope.page.menu = {};
|
||||
$scope.page.menu.currentSection = appState.getSectionState("currentSection");
|
||||
$scope.page.menu.currentNode = null;
|
||||
var evts = [];
|
||||
|
||||
//method used to configure the pre-values when we retrieve them from the server
|
||||
function createPreValueProps(preVals) {
|
||||
@@ -68,6 +69,10 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig
|
||||
});
|
||||
}
|
||||
else {
|
||||
loadDataType();
|
||||
}
|
||||
|
||||
function loadDataType() {
|
||||
|
||||
$scope.page.loading = true;
|
||||
|
||||
@@ -180,6 +185,17 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig
|
||||
|
||||
};
|
||||
|
||||
evts.push(eventsService.on("app.refreshEditor", function(name, error) {
|
||||
loadDataType();
|
||||
}));
|
||||
|
||||
//ensure to unregister from all events!
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.DataType.EditController", DataTypeEditController);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Editors.DataType.MoveController",
|
||||
function ($scope, dataTypeResource, treeService, navigationService, notificationsService, appState) {
|
||||
function ($scope, dataTypeResource, treeService, navigationService, notificationsService, appState, eventsService) {
|
||||
var dialogOptions = $scope.dialogOptions;
|
||||
$scope.dialogTreeEventHandler = $({});
|
||||
|
||||
@@ -45,6 +45,8 @@ angular.module("umbraco")
|
||||
}
|
||||
});
|
||||
|
||||
eventsService.emit('app.refreshEditor');
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function DocumentTypesEditController($scope, $routeParams, $injector, contentTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService, overlayHelper) {
|
||||
function DocumentTypesEditController($scope, $routeParams, $injector, contentTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService, overlayHelper, eventsService) {
|
||||
|
||||
var vm = this;
|
||||
var localizeSaving = localizationService.localize("general_saving");
|
||||
var evts = [];
|
||||
|
||||
vm.save = save;
|
||||
|
||||
@@ -158,6 +159,11 @@
|
||||
});
|
||||
}
|
||||
else {
|
||||
loadDocumentType();
|
||||
}
|
||||
|
||||
function loadDocumentType() {
|
||||
|
||||
vm.page.loading = true;
|
||||
|
||||
contentTypeResource.getById($routeParams.id).then(function (dt) {
|
||||
@@ -168,6 +174,7 @@
|
||||
vm.page.loading = false;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -317,6 +324,17 @@
|
||||
});
|
||||
}
|
||||
|
||||
evts.push(eventsService.on("app.refreshEditor", function(name, error) {
|
||||
loadDocumentType();
|
||||
}));
|
||||
|
||||
//ensure to unregister from all events!
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.DocumentTypes.EditController", DocumentTypesEditController);
|
||||
|
||||
@@ -2,61 +2,63 @@
|
||||
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
|
||||
<form novalidate name="contentTypeForm"
|
||||
ng-submit="vm.save()"
|
||||
val-form-manager>
|
||||
<form novalidate name="contentTypeForm" val-form-manager>
|
||||
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
|
||||
<umb-editor-header
|
||||
name="vm.contentType.name"
|
||||
alias="vm.contentType.alias"
|
||||
description="vm.contentType.description"
|
||||
navigation="vm.page.navigation"
|
||||
icon="vm.contentType.icon">
|
||||
name="vm.contentType.name"
|
||||
alias="vm.contentType.alias"
|
||||
description="vm.contentType.description"
|
||||
navigation="vm.page.navigation"
|
||||
icon="vm.contentType.icon">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container>
|
||||
<umb-editor-container class="editors-document-type-container">
|
||||
|
||||
<umb-editor-sub-views ng-if="!vm.page.loading" sub-views="vm.page.navigation" model="vm.contentType"></umb-editor-sub-views>
|
||||
<div class="editors-document-type-canvas">
|
||||
<umb-editor-sub-views
|
||||
ng-if="!vm.page.loading"
|
||||
sub-views="vm.page.navigation"
|
||||
model="vm.contentType">
|
||||
</umb-editor-sub-views>
|
||||
</div>
|
||||
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
|
||||
<umb-editor-footer-content-left>
|
||||
<umb-editor-footer-content-left>
|
||||
|
||||
<umb-keyboard-shortcuts-overview
|
||||
model="vm.page.keyboardShortcutsOverview">
|
||||
</umb-keyboard-shortcuts-overview>
|
||||
<umb-keyboard-shortcuts-overview
|
||||
model="vm.page.keyboardShortcutsOverview">
|
||||
</umb-keyboard-shortcuts-overview>
|
||||
|
||||
</umb-editor-footer-content-left>
|
||||
</umb-editor-footer-content-left>
|
||||
|
||||
<umb-editor-footer-content-right>
|
||||
<umb-editor-footer-content-right>
|
||||
|
||||
<umb-button
|
||||
ng-if="!vm.page.modelsBuilder"
|
||||
type="submit"
|
||||
state="vm.page.saveButtonState"
|
||||
button-style="success"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
|
||||
<umb-button
|
||||
ng-if="!vm.page.modelsBuilder"
|
||||
type="button"
|
||||
action="vm.save()"
|
||||
state="vm.page.saveButtonState"
|
||||
button-style="success"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
|
||||
<umb-button-group
|
||||
ng-if="vm.page.modelsBuilder"
|
||||
default-button="vm.page.defaultButton"
|
||||
sub-buttons="vm.page.subButtons"
|
||||
state="vm.page.saveButtonState"
|
||||
direction="up"
|
||||
float="right">
|
||||
</umb-button-group>
|
||||
|
||||
|
||||
</umb-editor-footer-content-right>
|
||||
<umb-button-group
|
||||
ng-if="vm.page.modelsBuilder"
|
||||
default-button="vm.page.defaultButton"
|
||||
sub-buttons="vm.page.subButtons"
|
||||
state="vm.page.saveButtonState"
|
||||
direction="up"
|
||||
float="right">
|
||||
</umb-button-group>
|
||||
|
||||
</umb-editor-footer-content-right>
|
||||
|
||||
</umb-editor-footer>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Editors.DocumentTypes.MoveController",
|
||||
function ($scope, contentTypeResource, treeService, navigationService, notificationsService, appState) {
|
||||
function ($scope, contentTypeResource, treeService, navigationService, notificationsService, appState, eventsService) {
|
||||
var dialogOptions = $scope.dialogOptions;
|
||||
$scope.dialogTreeEventHandler = $({});
|
||||
|
||||
@@ -45,6 +45,8 @@ angular.module("umbraco")
|
||||
}
|
||||
});
|
||||
|
||||
eventsService.emit('app.refreshEditor');
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function MediaTypesEditController($scope, $routeParams, mediaTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService, overlayHelper) {
|
||||
function MediaTypesEditController($scope, $routeParams, mediaTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService, overlayHelper, eventsService) {
|
||||
|
||||
var vm = this;
|
||||
var localizeSaving = localizationService.localize("general_saving");
|
||||
var evts = [];
|
||||
|
||||
vm.save = save;
|
||||
|
||||
@@ -140,6 +142,10 @@
|
||||
});
|
||||
}
|
||||
else {
|
||||
loadMediaType();
|
||||
}
|
||||
|
||||
function loadMediaType() {
|
||||
vm.page.loading = true;
|
||||
|
||||
mediaTypeResource.getById($routeParams.id).then(function(dt) {
|
||||
@@ -174,8 +180,39 @@
|
||||
// type when server side validation fails - as opposed to content where we are capable of saving the content
|
||||
// item if server side validation fails
|
||||
redirectOnFailure: false,
|
||||
//no-op for rebind callback... we don't really need to rebind for content types
|
||||
rebindCallback: angular.noop
|
||||
// we need to rebind... the IDs that have been created!
|
||||
rebindCallback: function (origContentType, savedContentType) {
|
||||
vm.contentType.id = savedContentType.id;
|
||||
vm.contentType.groups.forEach(function (group) {
|
||||
if (!group.name) return;
|
||||
|
||||
var k = 0;
|
||||
while (k < savedContentType.groups.length && savedContentType.groups[k].name != group.name)
|
||||
k++;
|
||||
if (k == savedContentType.groups.length) {
|
||||
group.id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var savedGroup = savedContentType.groups[k];
|
||||
if (!group.id) group.id = savedGroup.id;
|
||||
|
||||
group.properties.forEach(function (property) {
|
||||
if (property.id || !property.alias) return;
|
||||
|
||||
k = 0;
|
||||
while (k < savedGroup.properties.length && savedGroup.properties[k].alias != property.alias)
|
||||
k++;
|
||||
if (k == savedGroup.properties.length) {
|
||||
property.id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var savedProperty = savedGroup.properties[k];
|
||||
property.id = savedProperty.id;
|
||||
});
|
||||
});
|
||||
}
|
||||
}).then(function (data) {
|
||||
//success
|
||||
syncTreeNode(vm.contentType, data.path);
|
||||
@@ -260,6 +297,17 @@
|
||||
vm.currentNode = syncArgs.node;
|
||||
});
|
||||
}
|
||||
|
||||
evts.push(eventsService.on("app.refreshEditor", function(name, error) {
|
||||
loadMediaType();
|
||||
}));
|
||||
|
||||
//ensure to unregister from all events!
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.MediaTypes.EditController", MediaTypesEditController);
|
||||
|
||||
@@ -1,70 +1,69 @@
|
||||
<div ng-controller="Umbraco.Editors.MediaTypes.EditController as vm">
|
||||
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
|
||||
<form novalidate name="contentTypeForm"
|
||||
ng-submit="vm.save()"
|
||||
val-form-manager>
|
||||
<form novalidate name="contentTypeForm" val-form-manager>
|
||||
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
|
||||
<umb-editor-header
|
||||
name="vm.contentType.name"
|
||||
alias="vm.contentType.alias"
|
||||
description="vm.contentType.description"
|
||||
navigation="vm.page.navigation"
|
||||
icon="vm.contentType.icon">
|
||||
name="vm.contentType.name"
|
||||
alias="vm.contentType.alias"
|
||||
description="vm.contentType.description"
|
||||
navigation="vm.page.navigation"
|
||||
icon="vm.contentType.icon">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container class="editors-document-type-container">
|
||||
|
||||
<div class="editors-document-type-canvas">
|
||||
|
||||
<umb-editor-sub-views ng-if="!vm.page.loading" sub-views="vm.page.navigation" model="vm.contentType"></umb-editor-sub-views>
|
||||
|
||||
<umb-editor-sub-views
|
||||
ng-if="!vm.page.loading"
|
||||
sub-views="vm.page.navigation"
|
||||
model="vm.contentType">
|
||||
</umb-editor-sub-views>
|
||||
</div>
|
||||
|
||||
</umb-editor-container>
|
||||
|
||||
|
||||
<umb-editor-footer>
|
||||
|
||||
<umb-editor-footer-content-left>
|
||||
<umb-editor-footer-content-left>
|
||||
|
||||
<umb-keyboard-shortcuts-overview
|
||||
model="vm.page.keyboardShortcutsOverview">
|
||||
</umb-keyboard-shortcuts-overview>
|
||||
<umb-keyboard-shortcuts-overview
|
||||
model="vm.page.keyboardShortcutsOverview">
|
||||
</umb-keyboard-shortcuts-overview>
|
||||
|
||||
</umb-editor-footer-content-left>
|
||||
</umb-editor-footer-content-left>
|
||||
|
||||
<umb-editor-footer-content-right>
|
||||
<umb-editor-footer-content-right>
|
||||
|
||||
<umb-button ng-if="!vm.page.modelsBuilder"
|
||||
type="submit"
|
||||
state="vm.page.saveButtonState"
|
||||
button-style="success"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
ng-if="!vm.page.modelsBuilder"
|
||||
type="button"
|
||||
action="vm.save()"
|
||||
state="vm.page.saveButtonState"
|
||||
button-style="success"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
|
||||
<umb-button-group
|
||||
ng-if="vm.page.modelsBuilder"
|
||||
default-button="vm.page.defaultButton"
|
||||
sub-buttons="vm.page.subButtons"
|
||||
state="vm.page.saveButtonState"
|
||||
direction="up"
|
||||
float="right">
|
||||
</umb-button-group>
|
||||
|
||||
<umb-button-group ng-if="vm.page.modelsBuilder"
|
||||
default-button="vm.page.defaultButton"
|
||||
sub-buttons="vm.page.subButtons"
|
||||
state="vm.page.saveButtonState"
|
||||
direction="up"
|
||||
float="right">
|
||||
</umb-button-group>
|
||||
|
||||
</umb-editor-footer-content-right>
|
||||
|
||||
</umb-editor-footer-content-right>
|
||||
|
||||
</umb-editor-footer>
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Editors.MediaTypes.MoveController",
|
||||
function ($scope, mediaTypeResource, treeService, navigationService, notificationsService, appState) {
|
||||
function ($scope, mediaTypeResource, treeService, navigationService, notificationsService, appState, eventsService) {
|
||||
|
||||
var dialogOptions = $scope.dialogOptions;
|
||||
$scope.dialogTreeEventHandler = $({});
|
||||
@@ -46,6 +46,8 @@ angular.module("umbraco")
|
||||
}
|
||||
});
|
||||
|
||||
eventsService.emit('app.refreshEditor');
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
|
||||
@@ -129,8 +129,39 @@
|
||||
// type when server side validation fails - as opposed to content where we are capable of saving the content
|
||||
// item if server side validation fails
|
||||
redirectOnFailure: false,
|
||||
//no-op for rebind callback... we don't really need to rebind for content types
|
||||
rebindCallback: angular.noop
|
||||
// we need to rebind... the IDs that have been created!
|
||||
rebindCallback: function (origContentType, savedContentType) {
|
||||
vm.contentType.id = savedContentType.id;
|
||||
vm.contentType.groups.forEach(function (group) {
|
||||
if (!group.name) return;
|
||||
|
||||
var k = 0;
|
||||
while (k < savedContentType.groups.length && savedContentType.groups[k].name != group.name)
|
||||
k++;
|
||||
if (k == savedContentType.groups.length) {
|
||||
group.id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var savedGroup = savedContentType.groups[k];
|
||||
if (!group.id) group.id = savedGroup.id;
|
||||
|
||||
group.properties.forEach(function (property) {
|
||||
if (property.id || !property.alias) return;
|
||||
|
||||
k = 0;
|
||||
while (k < savedGroup.properties.length && savedGroup.properties[k].alias != property.alias)
|
||||
k++;
|
||||
if (k == savedGroup.properties.length) {
|
||||
property.id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var savedProperty = savedGroup.properties[k];
|
||||
property.id = savedProperty.id;
|
||||
});
|
||||
});
|
||||
}
|
||||
}).then(function (data) {
|
||||
//success
|
||||
syncTreeNode(vm.contentType, data.path);
|
||||
|
||||
@@ -1,67 +1,69 @@
|
||||
<div ng-controller="Umbraco.Editors.MemberTypes.EditController as vm">
|
||||
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
|
||||
<form novalidate name="contentTypeForm" val-form-manager>
|
||||
|
||||
<form novalidate name="contentTypeForm"
|
||||
ng-submit="vm.save()"
|
||||
val-form-manager>
|
||||
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
|
||||
<umb-editor-header
|
||||
name="vm.contentType.name"
|
||||
alias="vm.contentType.alias"
|
||||
description="vm.contentType.description"
|
||||
navigation="vm.page.navigation"
|
||||
icon="vm.contentType.icon">
|
||||
name="vm.contentType.name"
|
||||
alias="vm.contentType.alias"
|
||||
description="vm.contentType.description"
|
||||
navigation="vm.page.navigation"
|
||||
icon="vm.contentType.icon">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container class="editors-document-type-container">
|
||||
|
||||
<div class="editors-document-type-canvas">
|
||||
<umb-editor-sub-views ng-if="!vm.page.loading" sub-views="vm.page.navigation" model="vm.contentType"></umb-editor-sub-views>
|
||||
<umb-editor-sub-views
|
||||
ng-if="!vm.page.loading"
|
||||
sub-views="vm.page.navigation"
|
||||
model="vm.contentType">
|
||||
</umb-editor-sub-views>
|
||||
</div>
|
||||
|
||||
</umb-editor-container>
|
||||
|
||||
|
||||
<umb-editor-footer>
|
||||
|
||||
<umb-editor-footer-content-left>
|
||||
<umb-editor-footer-content-left>
|
||||
|
||||
<umb-keyboard-shortcuts-overview
|
||||
model="vm.page.keyboardShortcutsOverview">
|
||||
</umb-keyboard-shortcuts-overview>
|
||||
<umb-keyboard-shortcuts-overview
|
||||
model="vm.page.keyboardShortcutsOverview">
|
||||
</umb-keyboard-shortcuts-overview>
|
||||
|
||||
</umb-editor-footer-content-left>
|
||||
</umb-editor-footer-content-left>
|
||||
|
||||
<umb-editor-footer-content-right>
|
||||
<umb-editor-footer-content-right>
|
||||
|
||||
<umb-button ng-if="!vm.page.modelsBuilder"
|
||||
type="submit"
|
||||
state="vm.page.saveButtonState"
|
||||
button-style="success"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
ng-if="!vm.page.modelsBuilder"
|
||||
type="button"
|
||||
action="vm.save()"
|
||||
state="vm.page.saveButtonState"
|
||||
button-style="success"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
|
||||
<umb-button-group
|
||||
ng-if="vm.page.modelsBuilder"
|
||||
default-button="vm.page.defaultButton"
|
||||
sub-buttons="vm.page.subButtons"
|
||||
state="vm.page.saveButtonState"
|
||||
direction="up"
|
||||
float="right">
|
||||
</umb-button-group>
|
||||
|
||||
<umb-button-group ng-if="vm.page.modelsBuilder"
|
||||
default-button="vm.page.defaultButton"
|
||||
sub-buttons="vm.page.subButtons"
|
||||
state="vm.page.saveButtonState"
|
||||
direction="up"
|
||||
float="right">
|
||||
</umb-button-group>
|
||||
|
||||
</umb-editor-footer-content-right>
|
||||
</umb-editor-footer-content-right>
|
||||
|
||||
</umb-editor-footer>
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
<strong>{{model.value.generatedPassword}}</strong>
|
||||
</div>
|
||||
<div ng-switch="changing">
|
||||
<div ng-switch-when="false">
|
||||
<a href="" ng-click="doChange()" class="btn btn-small">Change password</a>
|
||||
<div ng-switch-when="false">
|
||||
<a href="" ng-click="doChange()" class="btn btn-small">
|
||||
<localize key="general_changePassword">Change password</localize>
|
||||
</a>
|
||||
</div>
|
||||
<div ng-switch-when="true">
|
||||
|
||||
<umb-control-group alias="resetPassword" label="Reset password?" ng-show="$parent.showReset()">
|
||||
<umb-control-group alias="resetPassword" label="@user_resetPassword" ng-show="$parent.showReset()">
|
||||
<input type="checkbox" ng-model="$parent.model.value.reset"
|
||||
id="Checkbox1"
|
||||
name="resetPassword"
|
||||
@@ -19,7 +21,7 @@
|
||||
</umb-control-group>
|
||||
|
||||
<!-- we need to show the old pass field when the provider cannot retrieve the password -->
|
||||
<umb-control-group alias="oldPassword" label="Old password" ng-show="$parent.showOldPass()">
|
||||
<umb-control-group alias="oldPassword" label="@user_oldPassword" ng-show="$parent.showOldPass()">
|
||||
<input type="password" name="oldPassword" ng-model="$parent.model.value.oldPassword"
|
||||
class="input-large umb-textstring textstring"
|
||||
ng-required="$parent.showOldPass()"
|
||||
@@ -29,7 +31,7 @@
|
||||
<span class="help-inline" val-msg-for="oldPassword" val-toggle-msg="valServer"></span>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group alias="password" label="New password" ng-show="$parent.showNewPass()">
|
||||
<umb-control-group alias="password" label="@user_newPassword" ng-show="$parent.showNewPass()">
|
||||
<input type="password" name="password" ng-model="$parent.model.value.newPassword"
|
||||
class="input-large umb-textstring textstring"
|
||||
ng-required="!$parent.model.value.reset"
|
||||
@@ -41,16 +43,20 @@
|
||||
<span class="help-inline" val-msg-for="password" val-toggle-msg="valServer"></span>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group alias="confirmpassword" label="Confirm password" ng-show="$parent.showConfirmPass()">
|
||||
<umb-control-group alias="confirmpassword" label="@user_confirmNewPassword" ng-show="$parent.showConfirmPass()">
|
||||
<input type="password" name="confirmpassword" ng-model="$parent.model.confirm"
|
||||
class="input-large umb-textstring textstring"
|
||||
val-compare="password" no-dirty-check
|
||||
autocomplete="off" />
|
||||
autocomplete="off"/>
|
||||
|
||||
<span class="help-inline" val-msg-for="confirmpassword" val-toggle-msg="valCompare">Passwords must match</span>
|
||||
</umb-control-group>
|
||||
<span class="help-inline" val-msg-for="confirmpassword" val-toggle-msg="valCompare">
|
||||
<localize key="user_passwordMismatch">The confirmed password doesn't match the new password!</localize>
|
||||
</span>
|
||||
</umb-control-group>
|
||||
|
||||
<a href="" ng-click="cancelChange()" ng-show="showCancelBtn()" class="btn btn-small">Cancel</a>
|
||||
<a href="" ng-click="cancelChange()" ng-show="showCancelBtn()" class="btn btn-small">
|
||||
<localize key="general_cancel">Cancel</localize>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<img
|
||||
ng-if="url"
|
||||
ng-click="setImage()"
|
||||
ng-src="{{url}}"
|
||||
ng-src="{{url}}?width=800&upscale=false"
|
||||
class="fullSizeImage" />
|
||||
<input type="text" class="caption" ng-model="control.value.caption" localize="placeholder" placeholder="@grid_placeholderImageCaption" />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<div class="umb-editor">
|
||||
<div class="umb-nested-boolean">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="model.value.allowBulkPublish" id="allowBulkPublish"/>
|
||||
<span>Allow bulk publish (content only)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="umb-nested-boolean">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="model.value.allowBulkUnpublish" id="allowBulkUnpublish" />
|
||||
<span>Allow bulk unpublish (content only)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="umb-nested-boolean">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="model.value.allowBulkCopy" id="allowBulkCopy" />
|
||||
<span>Allow bulk copy (content only)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="umb-nested-boolean">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="model.value.allowBulkMove" id="allowBulkMove" />
|
||||
<span>Allow bulk move</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="umb-nested-boolean">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="model.value.allowBulkDelete" id="allowBulkDelete" />
|
||||
<span>Allow bulk delete</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -22,6 +22,7 @@
|
||||
<umb-table
|
||||
ng-if="items"
|
||||
items="items"
|
||||
allow-select-all="options.bulkActionsAllowed"
|
||||
item-properties="options.includeProperties"
|
||||
on-select="vm.selectItem"
|
||||
on-click="vm.clickItem"
|
||||
@@ -38,6 +39,7 @@
|
||||
<umb-table
|
||||
ng-if="items"
|
||||
items="items"
|
||||
allow-select-all="options.bulkActionsAllowed"
|
||||
item-properties="options.includeProperties"
|
||||
on-select="vm.selectItem"
|
||||
on-click="vm.clickItem"
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
var vm = this;
|
||||
|
||||
|
||||
vm.nodeId = $scope.contentId;
|
||||
vm.acceptedFileTypes = mediaHelper.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes);
|
||||
vm.maxFileSize = Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB";
|
||||
|
||||
@@ -73,11 +73,11 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie
|
||||
layouts: $scope.model.config.layouts,
|
||||
activeLayout: listViewHelper.getLayout($routeParams.id, $scope.model.config.layouts)
|
||||
},
|
||||
allowBulkPublish: true,
|
||||
allowBulkUnpublish: true,
|
||||
allowBulkCopy: true,
|
||||
allowBulkMove: true,
|
||||
allowBulkDelete: true,
|
||||
allowBulkPublish: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkPublish,
|
||||
allowBulkUnpublish: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkUnpublish,
|
||||
allowBulkCopy: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkCopy,
|
||||
allowBulkMove: $scope.model.config.bulkActionPermissions.allowBulkMove,
|
||||
allowBulkDelete: $scope.model.config.bulkActionPermissions.allowBulkDelete
|
||||
};
|
||||
|
||||
//update all of the system includeProperties to enable sorting
|
||||
@@ -437,6 +437,15 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie
|
||||
$scope.contentId = id;
|
||||
$scope.isTrashed = id === "-20" || id === "-21";
|
||||
|
||||
$scope.options.allowBulkPublish = $scope.options.allowBulkPublish && !$scope.isTrashed;
|
||||
$scope.options.allowBulkUnpublish = $scope.options.allowBulkUnpublish && !$scope.isTrashed;
|
||||
|
||||
$scope.options.bulkActionsAllowed = $scope.options.allowBulkPublish ||
|
||||
$scope.options.allowBulkUnpublish ||
|
||||
$scope.options.allowBulkCopy ||
|
||||
$scope.options.allowBulkMove ||
|
||||
$scope.options.allowBulkDelete;
|
||||
|
||||
$scope.reloadView($scope.contentId);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user