porting 7.6@5c5baca into 8

This commit is contained in:
Stephan
2017-05-30 10:50:09 +02:00
parent 13ec3db2d3
commit d34a425dd1
178 changed files with 3002 additions and 4131 deletions

2
.gitignore vendored
View File

@@ -146,3 +146,5 @@ build/csharp-docs.zip
build/msbuild.log
.vs/
src/packages/
build/tools/
src/PrecompiledWeb/*

View File

@@ -160,18 +160,61 @@ CALL InstallGit.cmd
:: but the path setting is lost due to SETLOCAL
SET PATH="C:\Program Files (x86)\Git\cmd";"C:\Program Files\Git\cmd";%PATH%
SET toolsFolder=%CD%\tools\
IF NOT EXIST "%toolsFolder%" (
MD tools
)
SET nuGetExecutable=%CD%\tools\nuget.exe
IF NOT EXIST "%nuGetExecutable%" (
ECHO Getting NuGet so we can fetch some tools
ECHO Downloading https://dist.nuget.org/win-x86-commandline/latest/nuget.exe to %nuGetExecutable%
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', '%nuGetExecutable%')"
)
:: We need 7za.exe for BuildBelle.bat
IF NOT EXIST "%toolsFolder%7za.exe" (
ECHO 7zip not found - fetching now
"%nuGetExecutable%" install 7-Zip.CommandLine -OutputDirectory tools -Verbosity quiet
)
:: We need vswhere.exe for VS2017+
IF NOT EXIST "%toolsFolder%vswhere.exe" (
ECHO vswhere not found - fetching now
"%nuGetExecutable%" install vswhere -OutputDirectory tools -Verbosity quiet
)
:: Put 7za.exe and vswhere.exe in a predictable path (not version specific)
FOR /f "delims=" %%A in ('dir "%toolsFolder%7-Zip.CommandLine.*" /b') DO SET "sevenZipExePath=%toolsFolder%%%A\"
MOVE "%sevenZipExePath%tools\7za.exe" "%toolsFolder%7za.exe"
FOR /f "delims=" %%A in ('dir "%toolsFolder%vswhere.*" /b') DO SET "vswhereExePath=%toolsFolder%%%A\"
MOVE "%vswhereExePath%tools\vswhere.exe" "%toolsFolder%vswhere.exe"
ECHO.
ECHO Making sure we have a web.config
IF NOT EXIST "%CD%\..\src\Umbraco.Web.UI\web.config" COPY "%CD%\..\src\Umbraco.Web.UI\web.Template.config" "%CD%\..\src\Umbraco.Web.UI\web.config"
for /f "usebackq tokens=1* delims=: " %%i in (`"%CD%\tools\vswhere.exe" -latest -requires Microsoft.Component.MSBuild`) do (
if /i "%%i"=="installationPath" set InstallDir=%%j
)
SET VSWherePath="%InstallDir%\MSBuild"
ECHO.
ECHO Visual Studio is installed in: %InstallDir%
SET MSBUILDPATH=C:\Program Files (x86)\MSBuild\14.0\Bin
SET MSBUILD="%MSBUILDPATH%\MsBuild.exe"
ECHO.
ECHO Reporting NuGet version
"%CD%\..\src\.nuget\NuGet.exe" help | findstr "^NuGet Version:"
"%nuGetExecutable%" help | findstr "^NuGet Version:"
ECHO.
ECHO Restoring NuGet packages
ECHO Into %nuGetFolder%
"%CD%\..\src\.nuget\NuGet.exe" restore "%CD%\..\src\umbraco.sln" -Verbosity Quiet -NonInteractive -PackagesDirectory "%nuGetFolder%"
"%nuGetExecutable%" restore "%CD%\..\src\umbraco.sln" -Verbosity Quiet -NonInteractive -PackagesDirectory "%nuGetFolder%"
IF ERRORLEVEL 1 GOTO :error
ECHO.
@@ -187,6 +230,7 @@ ECHO.
/p:BUILD_NUMBER=%BUILD% ^
/p:BUILD_TESTS=%TESTS% ^
/p:NugetPackagesDirectory="%nuGetFolder%" ^
/p:VSWherePath="%VSWherePath%" ^
/consoleloggerparameters:Summary;ErrorsOnly ^
/fileLogger
IF ERRORLEVEL 1 GOTO error

View File

@@ -1,33 +1,59 @@
@ECHO OFF
SETLOCAL
:: SETLOCAL is on, so changes to the path not persist to the actual user's path
SET release=%1
ECHO Installing Npm NuGet Package
SET nuGetFolder=%CD%\..\src\packages\
ECHO Configured packages folder: %nuGetFolder%
SET toolsFolder=%CD%\tools\
ECHO Current folder: %CD%
%CD%\..\src\.nuget\NuGet.exe install Npm.js -OutputDirectory %nuGetFolder% -Verbosity quiet
SET nodeFileName=node-v6.9.1-win-x86.7z
SET nodeExtractFolder=%toolsFolder%node.js.691
for /f "delims=" %%A in ('dir %nuGetFolder%node.js.* /b') do set "nodePath=%nuGetFolder%%%A\"
for /f "delims=" %%A in ('dir %nuGetFolder%npm.js.* /b') do set "npmPath=%nuGetFolder%%%A\tools\"
IF NOT EXIST "%nodeExtractFolder%" (
ECHO Downloading http://nodejs.org/dist/v6.9.1/%nodeFileName% to %toolsFolder%%nodeFileName%
powershell -Command "(New-Object Net.WebClient).DownloadFile('http://nodejs.org/dist/v6.9.1/%nodeFileName%', '%toolsFolder%%nodeFileName%')"
ECHO Extracting %nodeFileName% to %nodeExtractFolder%
"%toolsFolder%\7za.exe" x "%toolsFolder%\%nodeFileName%" -o"%nodeExtractFolder%" -aos > nul
)
FOR /f "delims=" %%A in ('dir "%nodeExtractFolder%\node*" /b') DO SET "nodePath=%nodeExtractFolder%\%%A"
ECHO Adding Npm and Node to path
REM SETLOCAL is on, so changes to the path not persist to the actual user's path
PATH=%npmPath%;%nodePath%;%PATH%
SET buildFolder=%CD%
SET nuGetExecutable=%CD%\tools\nuget.exe
IF NOT EXIST "%nuGetExecutable%" (
ECHO Downloading https://dist.nuget.org/win-x86-commandline/latest/nuget.exe to %nuGetExecutable%
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', '%nuGetExecutable%')"
)
ECHO Change directory to %CD%\..\src\Umbraco.Web.UI.Client\
CD %CD%\..\src\Umbraco.Web.UI.Client\
SET drive=%CD:~0,2%
SET nuGetFolder=%drive%\packages\
FOR /f "delims=" %%A in ('dir "%nuGetFolder%npm.*" /b') DO SET "npmPath=%nuGetFolder%%%A\"
ECHO Do npm install and the grunt build of Belle
call npm cache clean --quiet
call npm install --quiet
call npm install -g grunt-cli --quiet
call npm install -g bower --quiet
call grunt build --buildversion=%release%
IF [%npmPath%] == [] GOTO :installnpm
IF NOT [%npmPath%] == [] GOTO :build
ECHO Move back to the build folder
CD %buildFolder%
:installnpm
ECHO Downloading npm
ECHO Configured packages folder: %nuGetFolder%
ECHO Installing Npm NuGet Package
"%nuGetExecutable%" install Npm -OutputDirectory %nuGetFolder% -Verbosity detailed
REM Ensures that we look for the just downloaded NPM, not whatever the user has installed on their machine
FOR /f "delims=" %%A in ('dir %nuGetFolder%npm.* /b') DO SET "npmPath=%nuGetFolder%%%A\"
GOTO :build
:build
ECHO Adding Npm and Node to path
REM SETLOCAL is on, so changes to the path not persist to the actual user's path
PATH="%npmPath%";"%nodePath%";%PATH%
SET buildFolder=%CD%
ECHO Change directory to %CD%\..\src\Umbraco.Web.UI.Client\
CD %CD%\..\src\Umbraco.Web.UI.Client\
ECHO Do npm install and the grunt build of Belle
call npm cache clean --quiet
call npm install --quiet
call npm install -g grunt-cli --quiet
call npm install -g bower --quiet
call grunt build --buildversion=%release%
ECHO Move back to the build folder
CD "%buildFolder%"

View File

@@ -57,6 +57,20 @@ $IndexPath = "../src/umbraco.web.ui.client/docs/api/index.html"
# Build the solution in debug mode
$SolutionPath = Join-Path -Path $SolutionRoot -ChildPath "umbraco.sln"
# Go get nuget.exe if we don't hae it
$NuGet = "$ToolsRoot\nuget.exe"
$FileExists = Test-Path $NuGet
If ($FileExists -eq $False) {
Write-Host "Retrieving nuget.exe..."
$SourceNugetExe = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
Invoke-WebRequest $SourceNugetExe -OutFile $NuGet
}
#restore nuget packages
Write-Host "Restoring nuget packages..."
& $NuGet restore $SolutionPath
& $MSBuild "$SolutionPath" /p:Configuration=Debug /maxcpucount /t:Clean
if (-not $?)
{

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<metadata minClientVersion="3.4.4">
<id>UmbracoCms.Core</id>
<version>7.0.0</version>
<title>Umbraco Cms Core Binaries</title>
@@ -38,10 +38,10 @@
<dependency id="Examine" version="[0.1.70, 3.0.0)" />
<dependency id="ImageProcessor" version="[2.4.5, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[4.6.6, 5.0.0)" />
<dependency id="semver" version="[1.1.2, 2.0.0)" />
<dependency id="semver" version="[2.0.4, 3.0.0)" />
<dependency id="UrlRewritingNet" version="[2.0.7, 3.0.0)" />
<!-- Markdown can not be updated due to: https://github.com/hey-red/markdownsharp/issues/71#issuecomment-233585487 -->
<dependency id="Markdown" version="[1.14.4, 2.0.0)" />
<dependency id="Markdown" version="[1.14.7, 2.0.0)" />
<dependency id="log4net" version="[2.0.5, 3.0.0)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.6.0, 5.0.0)" />
</dependencies>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="2.8">
<metadata minClientVersion="3.4.4">
<id>UmbracoCms</id>
<version>7.0.0</version>
<title>Umbraco Cms</title>
@@ -16,7 +16,7 @@
<tags>umbraco</tags>
<dependencies>
<dependency id="UmbracoCms.Core" version="[$version$]" />
<dependency id="Newtonsoft.Json" version="[8.0.3, 10.0.0)" />
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
<dependency id="Umbraco.ModelsBuilder" version="[8.0.0, 9.0.0)" />
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.1, 3.0.0)" />
</dependencies>

View File

@@ -330,6 +330,7 @@
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security.Cookies')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http.Formatting')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Data.SqlServerCe')" xdt:Transform="Remove" />
</assemblyBinding>
</runtime>
@@ -383,6 +384,10 @@
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Data.SqlServerCe" publicKeyToken="89845DCD8080CC91" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.0.1" newVersion="4.0.0.1"/>
</dependentAssembly>
</assemblyBinding>
</runtime>

View File

@@ -118,6 +118,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get { return GetOptionalDelimitedElement("disallowedUploadFiles", new[] {"ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd"}); }
}
[ConfigurationProperty("allowedUploadFiles")]
internal CommaDelimitedConfigurationElement AllowedUploadFiles
{
get { return GetOptionalDelimitedElement("allowedUploadFiles", new string[0]); }
}
[ConfigurationProperty("cloneXmlContent")]
internal InnerTextConfigurationElement<bool> CloneXmlContent
{
@@ -265,6 +271,11 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get { return DisallowedUploadFiles; }
}
IEnumerable<string> IContentSection.AllowedUploadFiles
{
get { return AllowedUploadFiles; }
}
bool IContentSection.CloneXmlContent
{
get { return CloneXmlContent; }

View File

@@ -0,0 +1,19 @@
using System.Linq;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public static class ContentSectionExtensions
{
/// <summary>
/// Determines if file extension is allowed for upload based on (optional) white list and black list
/// held in settings.
/// Allow upload if extension is whitelisted OR if there is no whitelist and extension is NOT blacklisted.
/// </summary>
public static bool IsFileAllowedForUpload(this IContentSection contentSection, string extension)
{
return contentSection.AllowedUploadFiles.Any(x => x.InvariantEquals(extension)) ||
(contentSection.AllowedUploadFiles.Any() == false &&
contentSection.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)) == false);
}
}
}

View File

@@ -49,6 +49,8 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
IEnumerable<string> DisallowedUploadFiles { get; }
IEnumerable<string> AllowedUploadFiles { get; }
bool CloneXmlContent { get; }
bool GlobalPreviewStorageEnabled { get; }

View File

@@ -9,5 +9,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
string RepositoryUrl { get; }
string WebServiceUrl { get; }
bool HasCustomWebServiceUrl { get; }
string RestApiUrl { get; }
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Linq;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public static class RepositoryConfigExtensions
{
//Our package repo
private static readonly Guid RepoGuid = new Guid("65194810-1f85-11dd-bd0b-0800200c9a66");
public static IRepository GetDefault(this IRepositoriesSection repos)
{
var found = repos.Repositories.FirstOrDefault(x => x.Id == RepoGuid);
if (found == null)
throw new InvalidOperationException("No default package repository found with id " + RepoGuid);
return found;
}
}
}

View File

@@ -38,9 +38,16 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get
{
var prop = Properties["webserviceurl"];
var repoUrl = this[prop] as ConfigurationElement;
return (repoUrl != null && repoUrl.ElementInformation.IsPresent);
return (string) prop.DefaultValue != (string) this[prop];
}
}
[ConfigurationProperty("restapiurl", DefaultValue = "https://our.umbraco.org/webapi/packages/v1")]
public string RestApiUrl
{
get { return (string)base["restapiurl"]; }
set { base["restapiurl"] = value; }
}
}
}

View File

@@ -25,6 +25,5 @@
public const string UmbracoConnectionName = "umbracoDbDSN";
public const string UmbracoMigrationName = "Umbraco";
}
}
}

View File

@@ -81,7 +81,7 @@ namespace Umbraco.Core
composition.Container.RegisterSingleton<IServerRegistrar>(f =>
{
if (UmbracoConfig.For.UmbracoSettings().DistributedCall.Enabled)
return new ConfigServerRegistrar(UmbracoConfig.For.UmbracoSettings());
return new ConfigServerRegistrar(UmbracoConfig.For.UmbracoSettings(), f.GetInstance<ILogger>());
if ("true".InvariantEquals(ConfigurationManager.AppSettings["umbracoDisableElectionForSingleServer"]))
return new SingleServerRegistrar(f.GetInstance<IRuntimeState>());
return new DatabaseServerRegistrar(

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Security.Permissions;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
@@ -7,36 +9,35 @@ using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Events
{
/// <summary>
/// Event args for a strongly typed object that can support cancellation
/// Used as a base class for the generic type CancellableObjectEventArgs{T} so that we can get direct 'object' access to the underlying EventObject
/// </summary>
/// <typeparam name="T"></typeparam>
[HostProtection(SecurityAction.LinkDemand, SharedState = true)]
public class CancellableObjectEventArgs<T> : CancellableEventArgs, IEquatable<CancellableObjectEventArgs<T>>
public abstract class CancellableObjectEventArgs : CancellableEventArgs
{
public CancellableObjectEventArgs(T eventObject, bool canCancel, EventMessages messages, IDictionary<string, object> additionalData)
protected CancellableObjectEventArgs(object eventObject, bool canCancel, EventMessages messages, IDictionary<string, object> additionalData)
: base(canCancel, messages, additionalData)
{
EventObject = eventObject;
}
public CancellableObjectEventArgs(T eventObject, bool canCancel, EventMessages eventMessages)
protected CancellableObjectEventArgs(object eventObject, bool canCancel, EventMessages eventMessages)
: base(canCancel, eventMessages)
{
EventObject = eventObject;
}
public CancellableObjectEventArgs(T eventObject, EventMessages eventMessages)
protected CancellableObjectEventArgs(object eventObject, EventMessages eventMessages)
: this(eventObject, true, eventMessages)
{
}
public CancellableObjectEventArgs(T eventObject, bool canCancel)
protected CancellableObjectEventArgs(object eventObject, bool canCancel)
: base(canCancel)
{
EventObject = eventObject;
}
public CancellableObjectEventArgs(T eventObject)
protected CancellableObjectEventArgs(object eventObject)
: this(eventObject, true)
{
}
@@ -47,7 +48,53 @@ namespace Umbraco.Core.Events
/// <remarks>
/// This is protected so that inheritors can expose it with their own name
/// </remarks>
protected T EventObject { get; set; }
internal object EventObject { get; set; }
}
/// <summary>
/// Event args for a strongly typed object that can support cancellation
/// </summary>
/// <typeparam name="T"></typeparam>
[HostProtection(SecurityAction.LinkDemand, SharedState = true)]
public class CancellableObjectEventArgs<T> : CancellableObjectEventArgs, IEquatable<CancellableObjectEventArgs<T>>
{
public CancellableObjectEventArgs(T eventObject, bool canCancel, EventMessages messages, IDictionary<string, object> additionalData)
: base(eventObject, canCancel, messages, additionalData)
{
}
public CancellableObjectEventArgs(T eventObject, bool canCancel, EventMessages eventMessages)
: base(eventObject, canCancel, eventMessages)
{
}
public CancellableObjectEventArgs(T eventObject, EventMessages eventMessages)
: base(eventObject, eventMessages)
{
}
public CancellableObjectEventArgs(T eventObject, bool canCancel)
: base(eventObject, canCancel)
{
}
public CancellableObjectEventArgs(T eventObject)
: base(eventObject)
{
}
/// <summary>
/// Returns the object relating to the event
/// </summary>
/// <remarks>
/// This is protected so that inheritors can expose it with their own name
/// </remarks>
protected new T EventObject
{
get { return (T) base.EventObject; }
set { base.EventObject = value; }
}
public bool Equals(CancellableObjectEventArgs<T> other)
{
@@ -61,7 +108,7 @@ namespace Umbraco.Core.Events
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((CancellableObjectEventArgs<T>) obj);
return Equals((CancellableObjectEventArgs<T>)obj);
}
public override int GetHashCode()
@@ -82,4 +129,49 @@ namespace Umbraco.Core.Events
return !Equals(left, right);
}
}
[HostProtection(SecurityAction.LinkDemand, SharedState = true)]
public class CancellableEnumerableObjectEventArgs<T> : CancellableObjectEventArgs<IEnumerable<T>>, IEquatable<CancellableEnumerableObjectEventArgs<T>>
{
public CancellableEnumerableObjectEventArgs(IEnumerable<T> eventObject, bool canCancel, EventMessages messages, IDictionary<string, object> additionalData)
: base(eventObject, canCancel, messages, additionalData)
{ }
public CancellableEnumerableObjectEventArgs(IEnumerable<T> eventObject, bool canCancel, EventMessages eventMessages)
: base(eventObject, canCancel, eventMessages)
{ }
public CancellableEnumerableObjectEventArgs(IEnumerable<T> eventObject, EventMessages eventMessages)
: base(eventObject, eventMessages)
{ }
public CancellableEnumerableObjectEventArgs(IEnumerable<T> eventObject, bool canCancel)
: base(eventObject, canCancel)
{ }
public CancellableEnumerableObjectEventArgs(IEnumerable<T> eventObject)
: base(eventObject)
{ }
public bool Equals(CancellableEnumerableObjectEventArgs<T> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return EventObject.SequenceEqual(other.EventObject);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((CancellableEnumerableObjectEventArgs<T>)obj);
}
public override int GetHashCode()
{
return HashCodeHelper.GetHashCode(EventObject);
}
}
}

View File

@@ -1,9 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Events
{
public class DeleteEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>, IEquatable<DeleteEventArgs<TEntity>>, IDeletingMediaFilesEventArgs
[SupersedeEvent(typeof(SaveEventArgs<>))]
[SupersedeEvent(typeof(PublishEventArgs<>))]
[SupersedeEvent(typeof(MoveEventArgs<>))]
[SupersedeEvent(typeof(CopyEventArgs<>))]
public class DeleteEventArgs<TEntity> : CancellableEnumerableObjectEventArgs<TEntity>, IEquatable<DeleteEventArgs<TEntity>>, IDeletingMediaFilesEventArgs
{
/// <summary>
/// Constructor accepting multiple entities that are used in the delete operation
@@ -106,7 +111,7 @@ namespace Umbraco.Core.Events
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return base.Equals(other) && MediaFilesToDelete.Equals(other.MediaFilesToDelete);
return base.Equals(other) && MediaFilesToDelete.SequenceEqual(other.MediaFilesToDelete);
}
public override bool Equals(object obj)

View File

@@ -4,7 +4,7 @@ using System.Xml.Linq;
namespace Umbraco.Core.Events
{
public class ImportEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>, IEquatable<ImportEventArgs<TEntity>>
public class ImportEventArgs<TEntity> : CancellableEnumerableObjectEventArgs<TEntity>, IEquatable<ImportEventArgs<TEntity>>
{
/// <summary>
/// Constructor accepting an XElement with the xml being imported

View File

@@ -4,7 +4,7 @@ using Umbraco.Core.Models.Packaging;
namespace Umbraco.Core.Events
{
internal class ImportPackageEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>, IEquatable<ImportPackageEventArgs<TEntity>>
internal class ImportPackageEventArgs<TEntity> : CancellableEnumerableObjectEventArgs<TEntity>, IEquatable<ImportPackageEventArgs<TEntity>>
{
private readonly MetaData _packageMetaData;
@@ -33,6 +33,7 @@ namespace Umbraco.Core.Events
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
//TODO: MetaData for package metadata has no equality operators :/
return base.Equals(other) && _packageMetaData.Equals(other._packageMetaData);
}

View File

@@ -5,8 +5,10 @@ using System.Linq;
namespace Umbraco.Core.Events
{
/// <summary>
/// This event manager supports event cancellation and will raise the events as soon as they are tracked, it does not store tracked events
/// An IEventDispatcher that immediately raise all events.
/// </summary>
/// <remarks>This means that events will be raised during the scope transaction,
/// whatever happens, and the transaction could roll back in the end.</remarks>
internal class PassThroughEventDispatcher : IEventDispatcher
{
public bool DispatchCancelable(EventHandler eventHandler, object sender, CancellableEventArgs args, string eventName = null)

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace Umbraco.Core.Events
{
public class PublishEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>, IEquatable<PublishEventArgs<TEntity>>
public class PublishEventArgs<TEntity> : CancellableEnumerableObjectEventArgs<TEntity>, IEquatable<PublishEventArgs<TEntity>>
{
/// <summary>
/// Constructor accepting multiple entities that are used in the publish operation

View File

@@ -4,11 +4,9 @@ using Umbraco.Core.IO;
namespace Umbraco.Core.Events
{
/// <summary>
/// This event manager is created for each scope and is aware of if it is nested in an outer scope
/// An IEventDispatcher that queues events, and raise them when the scope
/// exits and has been completed.
/// </summary>
/// <remarks>
/// The outer scope is the only scope that can raise events, the inner scope's will defer to the outer scope
/// </remarks>
internal class QueuingEventDispatcher : QueuingEventDispatcherBase
{
public QueuingEventDispatcher()

View File

@@ -1,11 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Plugins;
namespace Umbraco.Core.Events
{
/// <summary>
/// An IEventDispatcher that queues events.
/// </summary>
/// <remarks>
/// <para>Can raise, or ignore, cancelable events, depending on option.</para>
/// <para>Implementations must override ScopeExitCompleted to define what
/// to do with the events when the scope exits and has been completed.</para>
/// <para>If the scope exits without being completed, events are ignored.</para>
/// </remarks>
public abstract class QueuingEventDispatcherBase : IEventDispatcher
{
//events will be enlisted in the order they are raised
private List<IEventDefinition> _events;
private readonly bool _raiseCancelable;
@@ -68,26 +80,256 @@ namespace Umbraco.Core.Events
switch (filter)
{
case EventDefinitionFilter.All:
return _events;
return FilterSupersededAndUpdateToLatestEntity(_events);
case EventDefinitionFilter.FirstIn:
var l1 = new OrderedHashSet<IEventDefinition>();
foreach (var e in _events)
{
l1.Add(e);
}
return l1;
return FilterSupersededAndUpdateToLatestEntity(l1);
case EventDefinitionFilter.LastIn:
var l2 = new OrderedHashSet<IEventDefinition>(keepOldest: false);
foreach (var e in _events)
{
l2.Add(e);
}
return l2;
return FilterSupersededAndUpdateToLatestEntity(l2);
default:
throw new ArgumentOutOfRangeException(nameof(filter), filter, null);
}
}
private class EventDefinitionTypeData
{
public IEventDefinition EventDefinition { get; set; }
public Type EventArgType { get; set; }
public SupersedeEventAttribute[] SupersedeAttributes { get; set; }
}
/// <summary>
/// This will iterate over the events (latest first) and filter out any events or entities in event args that are included
/// in more recent events that Supersede previous ones. For example, If an Entity has been Saved and then Deleted, we don't want
/// to raise the Saved event (well actually we just don't want to include it in the args for that saved event)
/// </summary>
/// <param name="events"></param>
/// <returns></returns>
private static IEnumerable<IEventDefinition> FilterSupersededAndUpdateToLatestEntity(IReadOnlyList<IEventDefinition> events)
{
//used to keep the 'latest' entity and associated event definition data
var allEntities = new List<Tuple<IEntity, EventDefinitionTypeData>>();
//tracks all CancellableObjectEventArgs instances in the events which is the only type of args we can work with
var cancelableArgs = new List<CancellableObjectEventArgs>();
var result = new List<IEventDefinition>();
//This will eagerly load all of the event arg types and their attributes so we don't have to continuously look this data up
var allArgTypesWithAttributes = events.Select(x => x.Args.GetType())
.Distinct()
.ToDictionary(x => x, x => x.GetCustomAttributes<SupersedeEventAttribute>(false).ToArray());
//Iterate all events and collect the actual entities in them and relates them to their corresponding EventDefinitionTypeData
//we'll process the list in reverse because events are added in the order they are raised and we want to filter out
//any entities from event args that are not longer relevant
//(i.e. if an item is Deleted after it's Saved, we won't include the item in the Saved args)
for (var index = events.Count - 1; index >= 0; index--)
{
var eventDefinition = events[index];
var argType = eventDefinition.Args.GetType();
var attributes = allArgTypesWithAttributes[eventDefinition.Args.GetType()];
var meta = new EventDefinitionTypeData
{
EventDefinition = eventDefinition,
EventArgType = argType,
SupersedeAttributes = attributes
};
var args = eventDefinition.Args as CancellableObjectEventArgs;
if (args != null)
{
var list = TypeHelper.CreateGenericEnumerableFromObject(args.EventObject);
if (list == null)
{
//extract the event object
var obj = args.EventObject as IEntity;
if (obj != null)
{
//Now check if this entity already exists in other event args that supersede this current event arg type
if (IsFiltered(obj, meta, allEntities) == false)
{
//if it's not filtered we can adde these args to the response
cancelableArgs.Add(args);
result.Add(eventDefinition);
//track the entity
allEntities.Add(Tuple.Create(obj, meta));
}
}
else
{
//Can't retrieve the entity so cant' filter or inspect, just add to the output
result.Add(eventDefinition);
}
}
else
{
var toRemove = new List<IEntity>();
foreach (var entity in list)
{
//extract the event object
var obj = entity as IEntity;
if (obj != null)
{
//Now check if this entity already exists in other event args that supersede this current event arg type
if (IsFiltered(obj, meta, allEntities))
{
//track it to be removed
toRemove.Add(obj);
}
else
{
//track the entity, it's not filtered
allEntities.Add(Tuple.Create(obj, meta));
}
}
else
{
//we don't need to do anything here, we can't cast to IEntity so we cannot filter, so it will just remain in the list
}
}
//remove anything that has been filtered
foreach (var entity in toRemove)
{
list.Remove(entity);
}
//track the event and include in the response if there's still entities remaining in the list
if (list.Count > 0)
{
if (toRemove.Count > 0)
{
//re-assign if the items have changed
args.EventObject = list;
}
cancelableArgs.Add(args);
result.Add(eventDefinition);
}
}
}
else
{
//it's not a cancelable event arg so we just include it in the result
result.Add(eventDefinition);
}
}
//Now we'll deal with ensuring that only the latest(non stale) entities are used throughout all event args
UpdateToLatestEntities(allEntities, cancelableArgs);
//we need to reverse the result since we've been adding by latest added events first!
result.Reverse();
return result;
}
private static void UpdateToLatestEntities(IEnumerable<Tuple<IEntity, EventDefinitionTypeData>> allEntities, IEnumerable<CancellableObjectEventArgs> cancelableArgs)
{
//Now we'll deal with ensuring that only the latest(non stale) entities are used throughout all event args
var latestEntities = new OrderedHashSet<IEntity>(keepOldest: true);
foreach (var entity in allEntities.OrderByDescending(entity => entity.Item1.UpdateDate))
{
latestEntities.Add(entity.Item1);
}
foreach (var args in cancelableArgs)
{
var list = TypeHelper.CreateGenericEnumerableFromObject(args.EventObject);
if (list == null)
{
//try to find the args entity in the latest entity - based on the equality operators, this will
//match by Id since that is the default equality checker for IEntity. If one is found, than it is
//the most recent entity instance so update the args with that instance so we don't emit a stale instance.
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, args.EventObject));
if (foundEntity != null)
{
args.EventObject = foundEntity;
}
}
else
{
var updated = false;
for (int i = 0; i < list.Count; i++)
{
//try to find the args entity in the latest entity - based on the equality operators, this will
//match by Id since that is the default equality checker for IEntity. If one is found, than it is
//the most recent entity instance so update the args with that instance so we don't emit a stale instance.
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, list[i]));
if (foundEntity != null)
{
list[i] = foundEntity;
updated = true;
}
}
if (updated)
{
args.EventObject = list;
}
}
}
}
/// <summary>
/// This will check against all of the processed entity/events (allEntities) to see if this entity already exists in
/// event args that supersede the event args being passed in and if so returns true.
/// </summary>
/// <param name="entity"></param>
/// <param name="eventDef"></param>
/// <param name="allEntities"></param>
/// <returns></returns>
private static bool IsFiltered(
IEntity entity,
EventDefinitionTypeData eventDef,
List<Tuple<IEntity, EventDefinitionTypeData>> allEntities)
{
var argType = eventDef.EventDefinition.Args.GetType();
//check if the entity is found in any processed event data that could possible supersede this one
var foundByEntity = allEntities
.Where(x => x.Item2.SupersedeAttributes.Length > 0
//if it's the same arg type than it cannot supersede
&& x.Item2.EventArgType != argType
&& Equals(x.Item1, entity))
.ToArray();
//no args have been processed with this entity so it should not be filtered
if (foundByEntity.Length == 0)
return false;
if (argType.IsGenericType)
{
var supercededBy = foundByEntity
.FirstOrDefault(x =>
x.Item2.SupersedeAttributes.Any(y =>
//if the attribute type is a generic type def then compare with the generic type def of the event arg
(y.SupersededEventArgsType.IsGenericTypeDefinition && y.SupersededEventArgsType == argType.GetGenericTypeDefinition())
//if the attribute type is not a generic type def then compare with the normal type of the event arg
|| (y.SupersededEventArgsType.IsGenericTypeDefinition == false && y.SupersededEventArgsType == argType)));
return supercededBy != null;
}
else
{
var supercededBy = foundByEntity
.FirstOrDefault(x =>
x.Item2.SupersedeAttributes.Any(y =>
//since the event arg type is not a generic type, then we just compare type 1:1
y.SupersededEventArgsType == argType));
return supercededBy != null;
}
}
public void ScopeExit(bool completed)
{
if (_events == null) return;

View File

@@ -1,8 +1,9 @@
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Events
{
public class SaveEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
public class SaveEventArgs<TEntity> : CancellableEnumerableObjectEventArgs<TEntity>
{
/// <summary>
/// Constructor accepting multiple entities that are used in the saving operation

View File

@@ -0,0 +1,20 @@
using System;
namespace Umbraco.Core.Events
{
/// <summary>
/// This is used to know if the event arg attributed should supersede another event arg type when
/// tracking events for the same entity. If one event args supercedes another then the event args that have been superseded
/// will mean that the event will not be dispatched or the args will be filtered to exclude the entity.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
internal class SupersedeEventAttribute : Attribute
{
public Type SupersededEventArgsType { get; private set; }
public SupersedeEventAttribute(Type supersededEventArgsType)
{
SupersededEventArgsType = supersededEventArgsType;
}
}
}

View File

@@ -0,0 +1,12 @@
using System;
namespace Umbraco.Core.Exceptions
{
internal class ConnectionException : Exception
{
public ConnectionException(string message, Exception innerException) : base(message, innerException)
{
}
}
}

View File

@@ -7,7 +7,7 @@ namespace Umbraco.Core.Exceptions
public T Operation { get; private set; }
public DataOperationException(T operation, string message)
:base(message)
: base(message)
{
Operation = operation;
}

View File

@@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
namespace Umbraco.Core
{

View File

@@ -0,0 +1,104 @@
using System.Collections.Generic;
namespace Umbraco.Core
{
/// <summary>
/// Borrowed from http://stackoverflow.com/a/2575444/694494
/// </summary>
internal static class HashCodeHelper
{
public static int GetHashCode<T1, T2>(T1 arg1, T2 arg2)
{
unchecked
{
return 31 * arg1.GetHashCode() + arg2.GetHashCode();
}
}
public static int GetHashCode<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3)
{
unchecked
{
int hash = arg1.GetHashCode();
hash = 31 * hash + arg2.GetHashCode();
return 31 * hash + arg3.GetHashCode();
}
}
public static int GetHashCode<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3,
T4 arg4)
{
unchecked
{
int hash = arg1.GetHashCode();
hash = 31 * hash + arg2.GetHashCode();
hash = 31 * hash + arg3.GetHashCode();
return 31 * hash + arg4.GetHashCode();
}
}
public static int GetHashCode<T>(T[] list)
{
unchecked
{
int hash = 0;
foreach (var item in list)
{
if (item == null) continue;
hash = 31 * hash + item.GetHashCode();
}
return hash;
}
}
public static int GetHashCode<T>(IEnumerable<T> list)
{
unchecked
{
int hash = 0;
foreach (var item in list)
{
if (item == null) continue;
hash = 31 * hash + item.GetHashCode();
}
return hash;
}
}
/// <summary>
/// Gets a hashcode for a collection for that the order of items
/// does not matter.
/// So {1, 2, 3} and {3, 2, 1} will get same hash code.
/// </summary>
public static int GetHashCodeForOrderNoMatterCollection<T>(
IEnumerable<T> list)
{
unchecked
{
int hash = 0;
int count = 0;
foreach (var item in list)
{
if (item == null) continue;
hash += item.GetHashCode();
count++;
}
return 31 * hash + count.GetHashCode();
}
}
/// <summary>
/// Alternative way to get a hashcode is to use a fluent
/// interface like this:<br />
/// return 0.CombineHashCode(field1).CombineHashCode(field2).
/// CombineHashCode(field3);
/// </summary>
public static int CombineHashCode<T>(this int hashCode, T arg)
{
unchecked
{
return 31 * hashCode + arg.GetHashCode();
}
}
}
}

View File

@@ -177,7 +177,7 @@ namespace Umbraco.Core.IO
}
var filepath = UmbracoConfig.For.UmbracoSettings().Content.UploadAllowDirectories
? Path.Combine(folder, filename)
? Path.Combine(folder, filename).Replace('\\', '/')
: folder + "-" + filename;
return filepath;

View File

@@ -52,9 +52,20 @@ namespace Umbraco.Core.IO
try
{
Directory.Delete(dir, true);
dir = dir.Substring(0, dir.Length - _shadowPath.Length - 1);
// shadowPath make be path/to/dir, remove each
dir = dir.Replace("/", "\\");
var min = IOHelper.MapPath("~/App_Data/TEMP/ShadowFs").Length;
var pos = dir.LastIndexOf("\\", StringComparison.OrdinalIgnoreCase);
while (pos > min)
{
dir = dir.Substring(0, pos);
if (Directory.EnumerateFileSystemEntries(dir).Any() == false)
Directory.Delete(dir, true);
else
break;
pos = dir.LastIndexOf("\\", StringComparison.OrdinalIgnoreCase);
}
}
catch
{

View File

@@ -8,7 +8,7 @@ namespace Umbraco.Core.Models
/// Used in content/media/member repositories in order to add this type of entity to the persisted collection to be saved
/// in a single transaction during saving an entity
/// </summary>
internal class ContentXmlEntity<TContent> : IAggregateRoot
internal class ContentXmlEntity<TContent> : IAggregateRoot // fixme kill?
where TContent : IContentBase
{
private readonly Func<TContent, XElement> _xml;
@@ -42,6 +42,7 @@ namespace Umbraco.Core.Models
public Guid Key { get; set; }
public DateTime CreateDate { get; set; }
public DateTime UpdateDate { get; set; }
public DateTime? DeletedDate { get; set; }
/// <summary>
/// Special case, always return false, this will cause the repositories managing

View File

@@ -1,10 +1,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
namespace Umbraco.Core.Models.EntityBase
{
@@ -13,8 +10,8 @@ namespace Umbraco.Core.Models.EntityBase
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
[DebuggerDisplay("Id: {Id}")]
public abstract class Entity : TracksChangesEntityBase, IEntity, IRememberBeingDirty, ICanBeDirty
[DebuggerDisplay("Id: {" + nameof(Id) + "}")]
public abstract class Entity : TracksChangesEntityBase, IEntity //, IRememberBeingDirty, ICanBeDirty
{
private bool _hasIdentity;
private int _id;
@@ -25,6 +22,7 @@ namespace Umbraco.Core.Models.EntityBase
private static readonly Lazy<PropertySelectors> Ps = new Lazy<PropertySelectors>();
// ReSharper disable once ClassNeverInstantiated.Local
private class PropertySelectors
{
public readonly PropertyInfo IdSelector = ExpressionHelper.GetPropertyInfo<Entity, int>(x => x.Id);
@@ -41,7 +39,7 @@ namespace Umbraco.Core.Models.EntityBase
[DataMember]
public int Id
{
get { return _id; }
get => _id;
set
{
SetPropertyValueAndDetectChanges(value, ref _id, Ps.Value.IdSelector);
@@ -64,7 +62,7 @@ namespace Umbraco.Core.Models.EntityBase
_key = Guid.NewGuid();
return _key;
}
set { SetPropertyValueAndDetectChanges(value, ref _key, Ps.Value.KeySelector); }
set => SetPropertyValueAndDetectChanges(value, ref _key, Ps.Value.KeySelector);
}
/// <summary>
@@ -73,8 +71,8 @@ namespace Umbraco.Core.Models.EntityBase
[DataMember]
public DateTime CreateDate
{
get { return _createDate; }
set { SetPropertyValueAndDetectChanges(value, ref _createDate, Ps.Value.CreateDateSelector); }
get => _createDate;
set => SetPropertyValueAndDetectChanges(value, ref _createDate, Ps.Value.CreateDateSelector);
}
/// <summary>
@@ -87,8 +85,8 @@ namespace Umbraco.Core.Models.EntityBase
[Obsolete("Anytime there's a cancellable method it needs to return an Attempt so we know the outcome instead of this hack, not all services have been updated to use this though yet.")]
internal bool WasCancelled
{
get { return _wasCancelled; }
set { SetPropertyValueAndDetectChanges(value, ref _wasCancelled, Ps.Value.WasCancelledSelector); }
get => _wasCancelled;
set => SetPropertyValueAndDetectChanges(value, ref _wasCancelled, Ps.Value.WasCancelledSelector);
}
/// <summary>
@@ -97,10 +95,13 @@ namespace Umbraco.Core.Models.EntityBase
[DataMember]
public DateTime UpdateDate
{
get { return _updateDate; }
set { SetPropertyValueAndDetectChanges(value, ref _updateDate, Ps.Value.UpdateDateSelector); }
get => _updateDate;
set => SetPropertyValueAndDetectChanges(value, ref _updateDate, Ps.Value.UpdateDateSelector);
}
[IgnoreDataMember]
public DateTime? DeletedDate { get; set; }
internal virtual void ResetIdentity()
{
_hasIdentity = false;
@@ -134,32 +135,19 @@ namespace Umbraco.Core.Models.EntityBase
[DataMember]
public virtual bool HasIdentity
{
get
{
return _hasIdentity;
}
protected set { SetPropertyValueAndDetectChanges(value, ref _hasIdentity, Ps.Value.HasIdentitySelector); }
get => _hasIdentity;
protected set => SetPropertyValueAndDetectChanges(value, ref _hasIdentity, Ps.Value.HasIdentitySelector);
}
//TODO: Make this NOT virtual or even exist really!
public virtual bool SameIdentityAs(IEntity other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return SameIdentityAs(other as Entity);
return other != null && (ReferenceEquals(this, other) || SameIdentityAs(other as Entity));
}
public virtual bool Equals(Entity other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return SameIdentityAs(other);
return other != null && (ReferenceEquals(this, other) || SameIdentityAs(other));
}
//TODO: Make this NOT virtual or even exist really!
@@ -185,12 +173,7 @@ namespace Umbraco.Core.Models.EntityBase
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
return SameIdentityAs(obj as IEntity);
return obj != null && (ReferenceEquals(this, obj) || SameIdentityAs(obj as IEntity));
}
public override int GetHashCode()
@@ -208,7 +191,7 @@ namespace Umbraco.Core.Models.EntityBase
{
//Memberwise clone on Entity will work since it doesn't have any deep elements
// for any sub class this will work for standard properties as well that aren't complex object's themselves.
var ignored = this.Key; // ensure that 'this' has a key, before cloning
var unused = Key; // ensure that 'this' has a key, before cloning
var clone = (Entity)MemberwiseClone();
//ensure the clone has it's own dictionaries
clone.ResetChangeTrackingCollections();

View File

@@ -3,8 +3,6 @@
/// <summary>
/// Marker interface for aggregate roots
/// </summary>
public interface IAggregateRoot : IEntity
{
}
public interface IAggregateRoot : IDeletableEntity
{ }
}

View File

@@ -0,0 +1,11 @@
using System;
using System.Runtime.Serialization;
namespace Umbraco.Core.Models.EntityBase
{
public interface IDeletableEntity : IEntity
{
[DataMember]
DateTime? DeletedDate { get; set; }
}
}

View File

@@ -2,6 +2,6 @@
{
public interface IPartialView : IFile
{
PartialViewType ViewType { get; }
}
}

View File

@@ -1,10 +1,8 @@
using System;
using System.Runtime.Serialization;
using Umbraco.Core.Services;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents a Partial View file
/// </summary>
@@ -12,14 +10,21 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class PartialView : File, IPartialView
{
[Obsolete("Use the ctor that explicitely sets the view type.")]
public PartialView(string path)
: this(path, null)
: this(PartialViewType.PartialView, path, null)
{ }
internal PartialView(string path, Func<File, string> getFileContent)
public PartialView(PartialViewType viewType, string path)
: this(viewType, path, null)
{ }
internal PartialView(PartialViewType viewType, string path, Func<File, string> getFileContent)
: base(path, getFileContent)
{ }
{
ViewType = viewType;
}
internal PartialViewType ViewType { get; set; }
public PartialViewType ViewType { get; set; }
}
}

View File

@@ -1,6 +1,6 @@
namespace Umbraco.Core.Models
{
internal enum PartialViewType : byte
public enum PartialViewType : byte
{
Unknown = 0, // default
PartialView = 1,

View File

@@ -1,4 +1,5 @@
using NPoco;
using System;
using NPoco;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.Migrations.Syntax.Alter;
using Umbraco.Core.Persistence.Migrations.Syntax.Create;
@@ -27,8 +28,15 @@ namespace Umbraco.Core.Persistence.Migrations
Context = context;
}
public abstract void Up();
public abstract void Down();
public virtual void Up()
{
throw new NotSupportedException("This migration does not implement the \"up\" operation.");
}
public virtual void Down()
{
throw new NotSupportedException("This migration does not implement the \"down\" operation.");
}
public IAlterSyntaxBuilder Alter => new AlterSyntaxBuilder(Context);

View File

@@ -1,4 +1,5 @@
using NPoco;
using System;
using NPoco;
using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column;
using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions;
using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table;
@@ -23,6 +24,15 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter
return new AlterTableBuilder(_context, _supportedDatabaseTypes, expression);
}
/// <summary>
/// The problem with this is that only under particular circumstances is the expression added to the context
/// so you wouldn't actually know if you are using it correctly or not and chances are you are not and therefore
/// the statement won't even execute whereas using the IAlterTableSyntax to modify a column is guaranteed to add
/// the expression to the context.
/// </summary>
/// <param name="columnName"></param>
/// <returns></returns>
[Obsolete("Use the IAlterTableSyntax to modify a column instead, this will be removed in future versions")]
public IAlterColumnSyntax Column(string columnName)
{
var expression = new AlterColumnExpression(_context, _supportedDatabaseTypes) {Column = {Name = columnName}};

View File

@@ -1,4 +1,5 @@
using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column;
using System;
using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Column;
using Umbraco.Core.Persistence.Migrations.Syntax.Alter.Table;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter
@@ -6,6 +7,16 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter
public interface IAlterSyntaxBuilder : IFluentSyntax
{
IAlterTableSyntax Table(string tableName);
/// <summary>
/// The problem with this is that only under particular circumstances is the expression added to the context
/// so you wouldn't actually know if you are using it correctly or not and chances are you are not and therefore
/// the statement won't even execute whereas using the IAlterTableSyntax to modify a column is guaranteed to add
/// the expression to the context.
/// </summary>
/// <param name="columnName"></param>
/// <returns></returns>
[Obsolete("Use the IAlterTableSyntax to modify a column instead, this will be removed in future versions")]
IAlterColumnSyntax Column(string columnName);
}
}

View File

@@ -4,7 +4,7 @@ using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
{
[Migration("7.6.0", 0, Constants.System.UmbracoMigrationName)]
[Migration("7.6.0", 3, Constants.System.UmbracoMigrationName)]
public class AddIndexToCmsMemberLoginName : MigrationBase
{
public AddIndexToCmsMemberLoginName(IMigrationContext context)
@@ -13,17 +13,40 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
public override void Up()
{
Execute.Code(database =>
{
//Now we need to check if we can actually d6 this because we won't be able to if there's data in there that is too long
//http://issues.umbraco.org/issue/U4-9758
var colLen = SqlSyntax is MySqlSyntaxProvider
? database.ExecuteScalar<int?>("select max(LENGTH(LoginName)) from cmsMember")
: database.ExecuteScalar<int?>("select max(datalength(LoginName)) from cmsMember");
if (colLen < 900 == false && colLen != null)
{
return null;
}
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
//make sure it doesn't already exist
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsMember_LoginName")) == false)
{
Create.Index("IX_cmsMember_LoginName").OnTable("cmsMember")
var local = Context.GetLocalMigration();
//we can apply the index
local.Create.Index("IX_cmsMember_LoginName").OnTable("cmsMember")
.OnColumn("LoginName")
.Ascending()
.WithOptions()
.NonClustered();
return local.GetSql();
}
return null;
});
}
public override void Down()

View File

@@ -0,0 +1,49 @@
using System;
using System.Linq;
using Umbraco.Core.Exceptions;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
{
[Migration("7.6.0", 0, Constants.System.UmbracoMigrationName)]
public class NormalizeTemplateGuids : MigrationBase
{
public NormalizeTemplateGuids(IMigrationContext context)
: base(context)
{ }
public override void Up()
{
Execute.Code(UpdateTemplateGuids);
}
private static string UpdateTemplateGuids(IUmbracoDatabase database)
{
// we need this migration because ppl running pre-7.6 on Cloud and Courier have templates in different
// environments having different GUIDs (Courier does not sync template GUIDs) and we need to normalize
// these GUIDs so templates with the same alias on different environments have the same GUID.
// however, if already running a prerelease version of 7.6, we do NOT want to normalize the GUIDs as quite
// probably, we are already running Deploy and the GUIDs are OK. assuming noone is running a prerelease
// of 7.6 on Courier.
// so... testing if we already have a 7.6.0 version installed. not pretty but...?
//
var version = database.FirstOrDefault<string>("SELECT version FROM umbracoMigration WHERE name=@name ORDER BY version DESC", new { name = Constants.System.UmbracoMigrationName });
if (version != null && version.StartsWith("7.6.0")) return string.Empty;
var updates = database.Query<dynamic>(@"SELECT umbracoNode.id, cmsTemplate.alias FROM umbracoNode
JOIN cmsTemplate ON umbracoNode.id=cmsTemplate.nodeId
WHERE nodeObjectType = @guid", new { guid = Constants.ObjectTypes.TemplateTypeGuid})
.Select(template => Tuple.Create((int) template.id, ("template____" + (string) template.alias).ToGuid()))
.ToList();
foreach (var update in updates)
database.Execute("UPDATE umbracoNode set uniqueId=@guid WHERE id=@id", new { guid = update.Item2, id = update.Item1 });
return string.Empty;
}
public override void Down()
{
throw new WontImplementException();
}
}
}

View File

@@ -0,0 +1,48 @@
using System.Linq;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
{
[Migration("7.6.0", 2, Constants.System.UmbracoMigrationName)]
public class ReduceLoginNameColumnsSize : MigrationBase
{
public ReduceLoginNameColumnsSize(IMigrationContext context)
: base(context)
{ }
public override void Up()
{
//Now we need to check if we can actually d6 this because we won't be able to if there's data in there that is too long
//http://issues.umbraco.org/issue/U4-9758
Execute.Code(database =>
{
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(database);
var colLen = (SqlSyntax is MySqlSyntaxProvider)
? database.ExecuteScalar<int?>("select max(LENGTH(LoginName)) from cmsMember")
: database.ExecuteScalar<int?>("select max(datalength(LoginName)) from cmsMember");
if (colLen < 900 == false) return null;
var local = Context.GetLocalMigration();
//if it exists we need to drop it first
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsMember_LoginName")))
{
local.Delete.Index("IX_cmsMember_LoginName").OnTable("cmsMember");
}
//we can apply the col length change
local.Alter.Table("cmsMember")
.AlterColumn("LoginName")
.AsString(225)
.NotNullable();
return local.GetSql();
});
}
}
}

View File

@@ -29,7 +29,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe
}).ToArray();
//must be non-nullable
Alter.Column("uniqueID").OnTable("umbracoNode").AsGuid().NotNullable();
Alter.Table("umbracoNode").AlterColumn("uniqueID").AsGuid().NotNullable();
//make sure it already exists
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNodeUniqueID")))

View File

@@ -285,6 +285,8 @@ AND umbracoNode.id <> @id",
//Delete (base) node data
Database.Delete<NodeDto>("WHERE uniqueID = @Id", new { Id = entity.Key });
entity.DeletedDate = DateTime.Now;
}
#endregion
@@ -551,6 +553,8 @@ AND umbracoNode.id <> @id",
protected override void PersistDeletedItem(PreValueEntity entity)
{
Database.Execute("DELETE FROM cmsDataTypePreValues WHERE id=@Id", new { Id = entity.Id });
entity.DeletedDate = DateTime.Now;
}
protected override void PersistNewItem(PreValueEntity entity)

View File

@@ -195,6 +195,8 @@ namespace Umbraco.Core.Persistence.Repositories
//Clear the cache entries that exist by uniqueid/item key
IsolatedCache.ClearCacheItem(GetCacheIdKey<IDictionaryItem>(entity.ItemKey));
IsolatedCache.ClearCacheItem(GetCacheIdKey<IDictionaryItem>(entity.Key));
entity.DeletedDate = DateTime.Now;
}
private void RecursiveDelete(Guid parentId)

View File

@@ -157,6 +157,8 @@ namespace Umbraco.Core.Persistence.Repositories
// delete
Database.Delete(nodeDto);
entity.DeletedDate = DateTime.Now;
}
protected override void PersistNewItem(EntityContainer entity)

View File

@@ -89,6 +89,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
Database.Execute(delete, new { Id = GetEntityId(entity) });
}
entity.DeletedDate = DateTime.Now;
}
}
}

View File

@@ -30,7 +30,7 @@ namespace Umbraco.Core.Persistence.Repositories
var updated = FileSystem.GetLastModified(path).UtcDateTime;
//var content = GetFileContent(path);
var view = new PartialView(path, file => GetFileContent(file.OriginalPath))
var view = new PartialView(ViewType, path, file => GetFileContent(file.OriginalPath))
{
//id can be the hash
Id = path.GetHashCode(),
@@ -38,8 +38,7 @@ namespace Umbraco.Core.Persistence.Repositories
//Content = content,
CreateDate = created,
UpdateDate = updated,
VirtualPath = FileSystem.GetUrl(id),
ViewType = ViewType
VirtualPath = FileSystem.GetUrl(id)
};
//on initial construction we don't want to have dirty properties tracked

View File

@@ -120,6 +120,11 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Update(dto);
foreach (var removedRule in entity.RemovedRules)
{
Database.Delete<AccessRuleDto>("WHERE id=@Id", new { Id = removedRule });
}
foreach (var rule in entity.Rules)
{
if (rule.HasIdentity)
@@ -145,10 +150,6 @@ namespace Umbraco.Core.Persistence.Repositories
rule.Id = rule.Key.GetHashCode();
}
}
foreach (var removedRule in entity.RemovedRules)
{
Database.Delete<AccessRuleDto>("WHERE id=@Id", new {Id = removedRule});
}
entity.ResetDirtyProperties();
}

View File

@@ -318,6 +318,8 @@ namespace Umbraco.Core.Persistence.Repositories
var masterpageName = string.Concat(entity.Alias, ".master");
_masterpagesFileSystem.DeleteFile(masterpageName);
}
entity.DeletedDate = DateTime.Now;
}
#endregion

View File

@@ -1,11 +1,8 @@
using System;
using System.Collections.Generic;
using System.Data;
using NPoco;
using Umbraco.Core.Events;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Scoping;

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
@@ -19,6 +21,47 @@ namespace Umbraco.Core.Plugins
private static readonly Assembly[] EmptyAssemblies = new Assembly[0];
/// <summary>
/// Based on a type we'll check if it is IEnumerable{T} (or similar) and if so we'll return a List{T}, this will also deal with array types and return List{T} for those too.
/// If it cannot be done, null is returned.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
// fixme wtf is this and do we need it in v8?
internal static IList CreateGenericEnumerableFromObject(object obj)
{
var type = obj.GetType();
if (type.IsGenericType)
{
var genericTypeDef = type.GetGenericTypeDefinition();
if (genericTypeDef == typeof(IEnumerable<>)
|| genericTypeDef == typeof(ICollection<>)
|| genericTypeDef == typeof(Collection<>)
|| genericTypeDef == typeof(IList<>)
|| genericTypeDef == typeof(List<>)
//this will occur when Linq is used and we get the odd WhereIterator or DistinctIterators since those are special iterator types
|| obj is IEnumerable)
{
//if it is a IEnumerable<>, IList<T> or ICollection<> we'll use a List<>
var genericType = typeof(List<>).MakeGenericType(type.GetGenericArguments());
//pass in obj to fill the list
return (IList)Activator.CreateInstance(genericType, obj);
}
}
if (type.IsArray)
{
//if its an array, we'll use a List<>
var genericType = typeof(List<>).MakeGenericType(type.GetElementType());
//pass in obj to fill the list
return (IList)Activator.CreateInstance(genericType, obj);
}
return null;
}
/// <summary>
/// Checks if the method is actually overriding a base method
/// </summary>

View File

@@ -23,7 +23,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview)
{
return source.ToString();
return source?.ToString() ?? string.Empty;
}
}
}

View File

@@ -433,6 +433,7 @@ namespace Umbraco.Core.Scoping
}
finally
{
// removes the ambient context (ambient scope already gone)
_scopeProvider.SetAmbient(null);
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Scoping
{
@@ -9,11 +10,17 @@ namespace Umbraco.Core.Scoping
public class ScopeContext : IInstanceIdentifiable
{
private Dictionary<string, IEnlistedObject> _enlisted;
private bool _exiting;
public void ScopeExit(bool completed)
{
if (_enlisted == null)
return;
_exiting = true;
List<Exception> exceptions = null;
foreach (var enlisted in Enlisted.Values)
foreach (var enlisted in _enlisted.Values.OrderBy(x => x.Priority))
{
try
{
@@ -26,6 +33,7 @@ namespace Umbraco.Core.Scoping
exceptions.Add(e);
}
}
if (exceptions != null)
throw new AggregateException("Exceptions were thrown by listed actions.", exceptions);
}
@@ -38,73 +46,71 @@ namespace Umbraco.Core.Scoping
private interface IEnlistedObject
{
void Execute(bool completed);
int Priority { get; }
}
private class EnlistedObject<T> : IEnlistedObject
{
private readonly Action<bool, T> _action;
public EnlistedObject(T item)
{
Item = item;
}
public EnlistedObject(T item, Action<bool, T> action)
public EnlistedObject(T item, Action<bool, T> action, int priority)
{
Item = item;
Priority = priority;
_action = action;
}
public T Item { get; }
public int Priority { get; private set; }
public void Execute(bool completed)
{
_action(completed, Item);
}
}
/// <inheritdoc />
// todo: replace with optional parameters when we can break things
public T Enlist<T>(string key, Func<T> creator)
{
IEnlistedObject enlisted;
if (Enlisted.TryGetValue(key, out enlisted))
{
var enlistedAs = enlisted as EnlistedObject<T>;
if (enlistedAs == null) throw new Exception("An item with a different type has already been enlisted with the same key.");
return enlistedAs.Item;
}
var enlistedOfT = new EnlistedObject<T>(creator());
Enlisted[key] = enlistedOfT;
return enlistedOfT.Item;
return Enlist(key, creator, null, 100);
}
/// <inheritdoc />
// todo: replace with optional parameters when we can break things
public T Enlist<T>(string key, Func<T> creator, Action<bool, T> action)
{
IEnlistedObject enlisted;
if (Enlisted.TryGetValue(key, out enlisted))
{
var enlistedAs = enlisted as EnlistedObject<T>;
if (enlistedAs == null) throw new Exception("An item with a different type has already been enlisted with the same key.");
return enlistedAs.Item;
}
var enlistedOfT = new EnlistedObject<T>(creator(), action);
Enlisted[key] = enlistedOfT;
return enlistedOfT.Item;
return Enlist(key, creator, action, 100);
}
/// <inheritdoc />
// todo: replace with optional parameters when we can break things
public void Enlist(string key, Action<bool> action)
{
IEnlistedObject enlisted;
if (Enlisted.TryGetValue(key, out enlisted))
{
var enlistedAs = enlisted as EnlistedObject<object>;
if (enlistedAs == null) throw new Exception("An item with a different type has already been enlisted with the same key.");
return;
Enlist<object>(key, null, (completed, item) => action(completed), 100);
}
var enlistedOfT = new EnlistedObject<object>(null, (completed, item) => action(completed));
public void Enlist(string key, Action<bool> action, int priority)
{
Enlist<object>(key, null, (completed, item) => action(completed), priority);
}
public T Enlist<T>(string key, Func<T> creator, Action<bool, T> action, int priority)
{
if (_exiting)
throw new InvalidOperationException("Cannot enlist now, context is exiting.");
var enlistedObjects = _enlisted ?? (_enlisted = new Dictionary<string, IEnlistedObject>());
IEnlistedObject enlisted;
if (enlistedObjects.TryGetValue(key, out enlisted))
{
var enlistedAs = enlisted as EnlistedObject<T>;
if (enlistedAs == null) throw new InvalidOperationException("An item with the key already exists, but with a different type.");
if (enlistedAs.Priority != priority) throw new InvalidOperationException("An item with the key already exits, but with a different priority.");
return enlistedAs.Item;
}
var enlistedOfT = new EnlistedObject<T>(creator == null ? default(T) : creator(), action, priority);
Enlisted[key] = enlistedOfT;
return enlistedOfT.Item;
}
}
}

View File

@@ -191,6 +191,7 @@ namespace Umbraco.Core.Security
//track the last login date
user.LastLoginDateUtc = DateTime.UtcNow;
user.AccessFailedCount = 0;
await UserManager.UpdateAsync(user);
_logger.WriteCore(TraceEventType.Information, 0,

View File

@@ -126,35 +126,11 @@ namespace Umbraco.Core.Services
private static Guid GetNodeObjectTypeGuid(UmbracoObjectTypes umbracoObjectType)
{
switch (umbracoObjectType)
{
case UmbracoObjectTypes.Document:
return Constants.ObjectTypes.DocumentGuid;
case UmbracoObjectTypes.MemberType:
return Constants.ObjectTypes.MemberTypeGuid;
case UmbracoObjectTypes.Media:
return Constants.ObjectTypes.MediaGuid;
case UmbracoObjectTypes.Template:
return Constants.ObjectTypes.TemplateTypeGuid;
case UmbracoObjectTypes.MediaType:
return Constants.ObjectTypes.MediaTypeGuid;
case UmbracoObjectTypes.DocumentType:
return Constants.ObjectTypes.DocumentTypeGuid;
case UmbracoObjectTypes.Member:
return Constants.ObjectTypes.MemberGuid;
case UmbracoObjectTypes.DataType:
return Constants.ObjectTypes.DataTypeGuid;
case UmbracoObjectTypes.MemberGroup:
return Constants.ObjectTypes.MemberGroupGuid;
case UmbracoObjectTypes.RecycleBin:
case UmbracoObjectTypes.Stylesheet:
case UmbracoObjectTypes.ContentItem:
case UmbracoObjectTypes.ContentItemType:
case UmbracoObjectTypes.ROOT:
case UmbracoObjectTypes.Unknown:
default:
var guid = umbracoObjectType.GetGuid();
if (guid == Guid.Empty)
throw new NotSupportedException("Unsupported object type (" + umbracoObjectType + ").");
}
return guid;
}
public IUmbracoEntity GetByKey(Guid key, bool loadBaseType = true)

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Identity;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
@@ -24,7 +25,9 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repo = uow.CreateRepository<IExternalLoginRepository>();
return repo.GetByQuery(repo.QueryT.Where(x => x.UserId == userId));
return repo
.GetByQuery(repo.QueryT.Where(x => x.UserId == userId))
.ToList(); // ToList is important here, must evaluate within uow!
}
}
@@ -39,8 +42,9 @@ namespace Umbraco.Core.Services
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repo = uow.CreateRepository<IExternalLoginRepository>();
return repo.GetByQuery(repo.QueryT
.Where(x => x.ProviderKey == login.ProviderKey && x.LoginProvider == login.LoginProvider));
return repo
.GetByQuery(repo.QueryT.Where(x => x.ProviderKey == login.ProviderKey && x.LoginProvider == login.LoginProvider))
.ToList(); // ToList is important here, must evaluate within uow!
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using Umbraco.Core.Models;
@@ -186,5 +187,14 @@ namespace Umbraco.Core.Services
/// <param name="raiseEvents">Optional parameter indicating whether or not to raise events</param>
/// <returns><see cref="XElement"/> containing the xml representation of the IMacro object</returns>
XElement Export(IMacro macro, bool raiseEvents = true);
/// <summary>
/// This will fetch an Umbraco package file from the package repository and return the relative file path to the downloaded package file
/// </summary>
/// <param name="packageId"></param>
/// <param name="umbracoVersion"></param>
/// <param name="userId">The current user id performing the operation</param>
/// <returns></returns>
string FetchPackageFile(Guid packageId, Version umbracoVersion, int userId);
}
}

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI.WebControls;
@@ -9,8 +11,10 @@ using System.Xml.Linq;
using System.Xml.XPath;
using Newtonsoft.Json;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.DI;
using Umbraco.Core.Events;
using Umbraco.Core.Exceptions;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
@@ -49,7 +53,6 @@ namespace Umbraco.Core.Services
private IPackageInstallation _packageInstallation;
private readonly IUserService _userService;
public PackagingService(
ILogger logger,
IContentService contentService,
@@ -1458,6 +1461,65 @@ namespace Umbraco.Core.Services
#region Package Manifest
#endregion
#region Package Files
/// <summary>
/// This will fetch an Umbraco package file from the package repository and return the relative file path to the downloaded package file
/// </summary>
/// <param name="packageId"></param>
/// <param name="umbracoVersion"></param>
/// /// <param name="userId">The current user id performing the operation</param>
/// <returns></returns>
public string FetchPackageFile(Guid packageId, Version umbracoVersion, int userId)
{
var packageRepo = UmbracoConfig.For.UmbracoSettings().PackageRepositories.GetDefault();
using (var httpClient = new HttpClient())
using (var uow = _uowProvider.CreateUnitOfWork())
{
//includeHidden = true because we don't care if it's hidden we want to get the file regardless
var url = $"{packageRepo.RestApiUrl}/{packageId}?version={umbracoVersion.ToString(3)}&includeHidden=true&asFile=true";
byte[] bytes;
try
{
bytes = httpClient.GetByteArrayAsync(url).GetAwaiter().GetResult();
}
catch (HttpRequestException ex)
{
throw new ConnectionException("An error occuring downloading the package from " + url, ex);
}
//successfull
if (bytes.Length > 0)
{
var packagePath = IOHelper.MapPath(SystemDirectories.Packages);
// Check for package directory
if (Directory.Exists(packagePath) == false)
Directory.CreateDirectory(packagePath);
var packageFilePath = Path.Combine(packagePath, packageId + ".umb");
using (var fs1 = new FileStream(packageFilePath, FileMode.Create))
{
fs1.Write(bytes, 0, bytes.Length);
return "packages\\" + packageId + ".umb";
}
}
Audit(uow, AuditType.PackagerInstall, $"Package {packageId} fetched from {packageRepo.Id}", userId, -1);
return null;
}
}
private static void Audit(IUnitOfWork uow, AuditType type, string message, int userId, int objectId)
{
var auditRepo = uow.CreateRepository<IAuditRepository>();
auditRepo.AddOrUpdate(new AuditItem(objectId, message, type, userId));
}
#endregion
#region Templates
/// <summary>

View File

@@ -20,7 +20,7 @@ namespace Umbraco.Core
/// <param name="entityType">The entity type part of the udi.</param>
/// <param name="id">The string id part of the udi.</param>
public StringUdi(string entityType, string id)
: base(entityType, "umb://" + entityType + "/" + id)
: base(entityType, "umb://" + entityType + "/" + Uri.EscapeUriString(id))
{
Id = id;
}
@@ -32,7 +32,7 @@ namespace Umbraco.Core
public StringUdi(Uri uriValue)
: base(uriValue)
{
Id = uriValue.AbsolutePath.TrimStart('/');
Id = Uri.UnescapeDataString(uriValue.AbsolutePath.TrimStart('/'));
}
/// <summary>

View File

@@ -1,9 +1,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Sync
{
@@ -17,12 +17,12 @@ namespace Umbraco.Core.Sync
private readonly ServerRole _serverRole;
private readonly string _umbracoApplicationUrl;
public ConfigServerRegistrar(IUmbracoSettingsSection settings)
: this(settings.DistributedCall)
public ConfigServerRegistrar(IUmbracoSettingsSection settings, ILogger logger)
: this(settings.DistributedCall, logger)
{ }
// for tests
internal ConfigServerRegistrar(IDistributedCallSection settings)
internal ConfigServerRegistrar(IDistributedCallSection settings, ILogger logger)
{
if (settings.Enabled == false)
{
@@ -42,6 +42,7 @@ namespace Umbraco.Core.Sync
if (serversA.Length == 0)
{
_serverRole = ServerRole.Unknown; // config error, actually
logger.Debug<ConfigServerRegistrar>("Server Role Unknown: DistributedCalls are enabled but no servers are listed.");
}
else
{
@@ -50,17 +51,23 @@ namespace Umbraco.Core.Sync
var serverName = master.ServerName;
if (appId.IsNullOrWhiteSpace() && serverName.IsNullOrWhiteSpace())
{
_serverRole = ServerRole.Unknown; // config error, actually
logger.Debug<ConfigServerRegistrar>("Server Role Unknown: Server Name or AppId missing from Server configuration in DistributedCalls settings.");
}
else
{
_serverRole = IsCurrentServer(appId, serverName)
? ServerRole.Master
: ServerRole.Slave;
}
}
var currentServer = serversA.FirstOrDefault(x => IsCurrentServer(x.AppId, x.ServerName));
if (currentServer != null)
{
// match, use the configured url
// ReSharper disable once UseStringInterpolation
_umbracoApplicationUrl = string.Format("{0}://{1}:{2}/{3}",
currentServer.ForceProtocol.IsNullOrWhiteSpace() ? "http" : currentServer.ForceProtocol,
currentServer.ServerAddress,
@@ -76,19 +83,10 @@ namespace Umbraco.Core.Sync
|| (serverName.IsNullOrWhiteSpace() == false && serverName.Trim().InvariantEquals(NetworkHelper.MachineName));
}
public IEnumerable<IServerAddress> Registrations
{
get { return _addresses; }
}
public IEnumerable<IServerAddress> Registrations => _addresses;
public ServerRole GetCurrentServerRole()
{
return _serverRole;
}
public ServerRole GetCurrentServerRole() => _serverRole;
public string GetCurrentServerUmbracoApplicationUrl()
{
return _umbracoApplicationUrl;
}
public string GetCurrentServerUmbracoApplicationUrl() => _umbracoApplicationUrl;
}
}

View File

@@ -103,7 +103,8 @@ namespace Umbraco.Core
public override string ToString()
{
// UriValue is created in the ctor and is never null
return UriValue.ToString();
// use AbsoluteUri here and not ToString else it's not encoded!
return UriValue.AbsoluteUri;
}
/// <summary>
@@ -161,7 +162,7 @@ namespace Umbraco.Core
}
if (udiType == UdiType.StringUdi)
{
udi = path == string.Empty ? GetRootUdi(uri.Host) : new StringUdi(uri.Host, path);
udi = path == string.Empty ? GetRootUdi(uri.Host) : new StringUdi(uri.Host, Uri.UnescapeDataString(path));
return true;
}
if (tryParse) return false;

View File

@@ -198,7 +198,13 @@ namespace Umbraco.Core
public static StringUdi GetUdi(this IPartialView entity)
{
if (entity == null) throw new ArgumentNullException("entity");
return new StringUdi(Constants.UdiEntityType.PartialView, entity.Path.TrimStart('/')).EnsureClosed();
// we should throw on Unknown but for the time being, assume it means PartialView
var entityType = entity.ViewType == PartialViewType.PartialViewMacro
? Constants.UdiEntityType.PartialViewMacro
: Constants.UdiEntityType.PartialView;
return new StringUdi(entityType, entity.Path.TrimStart('/')).EnsureClosed();
}
/// <summary>

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
@@ -33,70 +34,70 @@ namespace Umbraco.Tests.Cache
new EventDefinition<ISectionService, EventArgs>(null, serviceContext.SectionService, new EventArgs(), "Deleted"),
new EventDefinition<ISectionService, EventArgs>(null, serviceContext.SectionService, new EventArgs(), "New"),
new EventDefinition<IUserService, SaveEventArgs<IUserType>>(null, serviceContext.UserService, new SaveEventArgs<IUserType>((IUserType) null)),
new EventDefinition<IUserService, DeleteEventArgs<IUserType>>(null, serviceContext.UserService, new DeleteEventArgs<IUserType>((IUserType) null)),
new EventDefinition<IUserService, SaveEventArgs<IUserType>>(null, serviceContext.UserService, new SaveEventArgs<IUserType>(Enumerable.Empty<IUserType>())),
new EventDefinition<IUserService, DeleteEventArgs<IUserType>>(null, serviceContext.UserService, new DeleteEventArgs<IUserType>(Enumerable.Empty<IUserType>())),
new EventDefinition<IUserService, SaveEventArgs<IUser>>(null, serviceContext.UserService, new SaveEventArgs<IUser>((IUser) null)),
new EventDefinition<IUserService, DeleteEventArgs<IUser>>(null, serviceContext.UserService, new DeleteEventArgs<IUser>((IUser) null)),
new EventDefinition<IUserService, DeleteEventArgs<IUser>>(null, serviceContext.UserService, new DeleteEventArgs<IUser>((IUser) null)),
new EventDefinition<IUserService, SaveEventArgs<IUser>>(null, serviceContext.UserService, new SaveEventArgs<IUser>(Enumerable.Empty<IUser>())),
new EventDefinition<IUserService, DeleteEventArgs<IUser>>(null, serviceContext.UserService, new DeleteEventArgs<IUser>(Enumerable.Empty<IUser>())),
new EventDefinition<IUserService, DeleteEventArgs<IUser>>(null, serviceContext.UserService, new DeleteEventArgs<IUser>(Enumerable.Empty<IUser>())),
new EventDefinition<ILocalizationService, SaveEventArgs<IDictionaryItem>>(null, serviceContext.LocalizationService, new SaveEventArgs<IDictionaryItem>((IDictionaryItem) null)),
new EventDefinition<ILocalizationService, DeleteEventArgs<IDictionaryItem>>(null, serviceContext.LocalizationService, new DeleteEventArgs<IDictionaryItem>((IDictionaryItem) null)),
new EventDefinition<ILocalizationService, SaveEventArgs<IDictionaryItem>>(null, serviceContext.LocalizationService, new SaveEventArgs<IDictionaryItem>(Enumerable.Empty<IDictionaryItem>())),
new EventDefinition<ILocalizationService, DeleteEventArgs<IDictionaryItem>>(null, serviceContext.LocalizationService, new DeleteEventArgs<IDictionaryItem>(Enumerable.Empty<IDictionaryItem>())),
new EventDefinition<IDataTypeService, SaveEventArgs<IDataTypeDefinition>>(null, serviceContext.DataTypeService, new SaveEventArgs<IDataTypeDefinition>((IDataTypeDefinition) null)),
new EventDefinition<IDataTypeService, DeleteEventArgs<IDataTypeDefinition>>(null, serviceContext.DataTypeService, new DeleteEventArgs<IDataTypeDefinition>((IDataTypeDefinition) null)),
new EventDefinition<IDataTypeService, SaveEventArgs<IDataTypeDefinition>>(null, serviceContext.DataTypeService, new SaveEventArgs<IDataTypeDefinition>(Enumerable.Empty<IDataTypeDefinition>())),
new EventDefinition<IDataTypeService, DeleteEventArgs<IDataTypeDefinition>>(null, serviceContext.DataTypeService, new DeleteEventArgs<IDataTypeDefinition>(Enumerable.Empty<IDataTypeDefinition>())),
new EventDefinition<IFileService, SaveEventArgs<Stylesheet>>(null, serviceContext.FileService, new SaveEventArgs<Stylesheet>((Stylesheet) null)),
new EventDefinition<IFileService, DeleteEventArgs<Stylesheet>>(null, serviceContext.FileService, new DeleteEventArgs<Stylesheet>((Stylesheet) null)),
new EventDefinition<IFileService, SaveEventArgs<Stylesheet>>(null, serviceContext.FileService, new SaveEventArgs<Stylesheet>(Enumerable.Empty<Stylesheet>())),
new EventDefinition<IFileService, DeleteEventArgs<Stylesheet>>(null, serviceContext.FileService, new DeleteEventArgs<Stylesheet>(Enumerable.Empty<Stylesheet>())),
new EventDefinition<IDomainService, SaveEventArgs<IDomain>>(null, serviceContext.DomainService, new SaveEventArgs<IDomain>((IDomain) null)),
new EventDefinition<IDomainService, DeleteEventArgs<IDomain>>(null, serviceContext.DomainService, new DeleteEventArgs<IDomain>((IDomain) null)),
new EventDefinition<IDomainService, SaveEventArgs<IDomain>>(null, serviceContext.DomainService, new SaveEventArgs<IDomain>(Enumerable.Empty<IDomain>())),
new EventDefinition<IDomainService, DeleteEventArgs<IDomain>>(null, serviceContext.DomainService, new DeleteEventArgs<IDomain>(Enumerable.Empty<IDomain>())),
new EventDefinition<ILocalizationService, SaveEventArgs<ILanguage>>(null, serviceContext.LocalizationService, new SaveEventArgs<ILanguage>((ILanguage) null)),
new EventDefinition<ILocalizationService, DeleteEventArgs<ILanguage>>(null, serviceContext.LocalizationService, new DeleteEventArgs<ILanguage>((ILanguage) null)),
new EventDefinition<ILocalizationService, SaveEventArgs<ILanguage>>(null, serviceContext.LocalizationService, new SaveEventArgs<ILanguage>(Enumerable.Empty<ILanguage>())),
new EventDefinition<ILocalizationService, DeleteEventArgs<ILanguage>>(null, serviceContext.LocalizationService, new DeleteEventArgs<ILanguage>(Enumerable.Empty<ILanguage>())),
new EventDefinition<IContentTypeService, SaveEventArgs<IContentType>>(null, serviceContext.ContentTypeService, new SaveEventArgs<IContentType>((IContentType) null)),
new EventDefinition<IContentTypeService, DeleteEventArgs<IContentType>>(null, serviceContext.ContentTypeService, new DeleteEventArgs<IContentType>((IContentType) null)),
new EventDefinition<IContentTypeService, SaveEventArgs<IMediaType>>(null, serviceContext.ContentTypeService, new SaveEventArgs<IMediaType>((IMediaType) null)),
new EventDefinition<IContentTypeService, DeleteEventArgs<IMediaType>>(null, serviceContext.ContentTypeService, new DeleteEventArgs<IMediaType>((IMediaType) null)),
new EventDefinition<IContentTypeService, SaveEventArgs<IContentType>>(null, serviceContext.ContentTypeService, new SaveEventArgs<IContentType>(Enumerable.Empty<IContentType>())),
new EventDefinition<IContentTypeService, DeleteEventArgs<IContentType>>(null, serviceContext.ContentTypeService, new DeleteEventArgs<IContentType>(Enumerable.Empty<IContentType>())),
new EventDefinition<IContentTypeService, SaveEventArgs<IMediaType>>(null, serviceContext.ContentTypeService, new SaveEventArgs<IMediaType>(Enumerable.Empty<IMediaType>())),
new EventDefinition<IContentTypeService, DeleteEventArgs<IMediaType>>(null, serviceContext.ContentTypeService, new DeleteEventArgs<IMediaType>(Enumerable.Empty<IMediaType>())),
new EventDefinition<IMemberTypeService, SaveEventArgs<IMemberType>>(null, serviceContext.MemberTypeService, new SaveEventArgs<IMemberType>((IMemberType) null)),
new EventDefinition<IMemberTypeService, DeleteEventArgs<IMemberType>>(null, serviceContext.MemberTypeService, new DeleteEventArgs<IMemberType>((IMemberType) null)),
new EventDefinition<IMemberTypeService, SaveEventArgs<IMemberType>>(null, serviceContext.MemberTypeService, new SaveEventArgs<IMemberType>(Enumerable.Empty<IMemberType>())),
new EventDefinition<IMemberTypeService, DeleteEventArgs<IMemberType>>(null, serviceContext.MemberTypeService, new DeleteEventArgs<IMemberType>(Enumerable.Empty<IMemberType>())),
new EventDefinition<IFileService, SaveEventArgs<ITemplate>>(null, serviceContext.FileService, new SaveEventArgs<ITemplate>((ITemplate) null)),
new EventDefinition<IFileService, DeleteEventArgs<ITemplate>>(null, serviceContext.FileService, new DeleteEventArgs<ITemplate>((ITemplate) null)),
new EventDefinition<IFileService, SaveEventArgs<ITemplate>>(null, serviceContext.FileService, new SaveEventArgs<ITemplate>(Enumerable.Empty<ITemplate>())),
new EventDefinition<IFileService, DeleteEventArgs<ITemplate>>(null, serviceContext.FileService, new DeleteEventArgs<ITemplate>(Enumerable.Empty<ITemplate>())),
new EventDefinition<IMacroService, SaveEventArgs<IMacro>>(null, serviceContext.MacroService, new SaveEventArgs<IMacro>((IMacro) null)),
new EventDefinition<IMacroService, DeleteEventArgs<IMacro>>(null, serviceContext.MacroService, new DeleteEventArgs<IMacro>((IMacro) null)),
new EventDefinition<IMacroService, SaveEventArgs<IMacro>>(null, serviceContext.MacroService, new SaveEventArgs<IMacro>(Enumerable.Empty<IMacro>())),
new EventDefinition<IMacroService, DeleteEventArgs<IMacro>>(null, serviceContext.MacroService, new DeleteEventArgs<IMacro>(Enumerable.Empty<IMacro>())),
new EventDefinition<IMemberService, SaveEventArgs<IMember>>(null, serviceContext.MemberService, new SaveEventArgs<IMember>((IMember) null)),
new EventDefinition<IMemberService, DeleteEventArgs<IMember>>(null, serviceContext.MemberService, new DeleteEventArgs<IMember>((IMember) null)),
new EventDefinition<IMemberService, SaveEventArgs<IMember>>(null, serviceContext.MemberService, new SaveEventArgs<IMember>(Enumerable.Empty<IMember>())),
new EventDefinition<IMemberService, DeleteEventArgs<IMember>>(null, serviceContext.MemberService, new DeleteEventArgs<IMember>(Enumerable.Empty<IMember>())),
new EventDefinition<IMemberGroupService, SaveEventArgs<IMemberGroup>>(null, serviceContext.MemberGroupService, new SaveEventArgs<IMemberGroup>((IMemberGroup) null)),
new EventDefinition<IMemberGroupService, DeleteEventArgs<IMemberGroup>>(null, serviceContext.MemberGroupService, new DeleteEventArgs<IMemberGroup>((IMemberGroup) null)),
new EventDefinition<IMemberGroupService, SaveEventArgs<IMemberGroup>>(null, serviceContext.MemberGroupService, new SaveEventArgs<IMemberGroup>(Enumerable.Empty<IMemberGroup>())),
new EventDefinition<IMemberGroupService, DeleteEventArgs<IMemberGroup>>(null, serviceContext.MemberGroupService, new DeleteEventArgs<IMemberGroup>(Enumerable.Empty<IMemberGroup>())),
new EventDefinition<IMediaService, SaveEventArgs<IMedia>>(null, serviceContext.MediaService, new SaveEventArgs<IMedia>((IMedia) null)),
new EventDefinition<IMediaService, DeleteEventArgs<IMedia>>(null, serviceContext.MediaService, new DeleteEventArgs<IMedia>((IMedia) null)),
new EventDefinition<IMediaService, SaveEventArgs<IMedia>>(null, serviceContext.MediaService, new SaveEventArgs<IMedia>(Enumerable.Empty<IMedia>())),
new EventDefinition<IMediaService, DeleteEventArgs<IMedia>>(null, serviceContext.MediaService, new DeleteEventArgs<IMedia>(Enumerable.Empty<IMedia>())),
new EventDefinition<IMediaService, MoveEventArgs<IMedia>>(null, serviceContext.MediaService, new MoveEventArgs<IMedia>(new MoveEventInfo<IMedia>(null, "", -1)), "Moved"),
new EventDefinition<IMediaService, MoveEventArgs<IMedia>>(null, serviceContext.MediaService, new MoveEventArgs<IMedia>(new MoveEventInfo<IMedia>(null, "", -1)), "Trashed"),
new EventDefinition<IMediaService, RecycleBinEventArgs>(null, serviceContext.MediaService, new RecycleBinEventArgs(Guid.NewGuid(), new Dictionary<int, IEnumerable<Property>>(), true)),
new EventDefinition<IContentService, SaveEventArgs<IContent>>(null, serviceContext.ContentService, new SaveEventArgs<IContent>((IContent) null)),
new EventDefinition<IContentService, DeleteEventArgs<IContent>>(null, serviceContext.ContentService, new DeleteEventArgs<IContent>((IContent) null)),
new EventDefinition<IContentService, SaveEventArgs<IContent>>(null, serviceContext.ContentService, new SaveEventArgs<IContent>(Enumerable.Empty<IContent>())),
new EventDefinition<IContentService, DeleteEventArgs<IContent>>(null, serviceContext.ContentService, new DeleteEventArgs<IContent>(Enumerable.Empty<IContent>())),
new EventDefinition<IContentService, CopyEventArgs<IContent>>(null, serviceContext.ContentService, new CopyEventArgs<IContent>(null, null, -1)),
new EventDefinition<IContentService, MoveEventArgs<IContent>>(null, serviceContext.ContentService, new MoveEventArgs<IContent>(new MoveEventInfo<IContent>(null, "", -1)), "Trashed"),
new EventDefinition<IContentService, RecycleBinEventArgs>(null, serviceContext.ContentService, new RecycleBinEventArgs(Guid.NewGuid(), new Dictionary<int, IEnumerable<Property>>(), true)),
new EventDefinition<IContentService, PublishEventArgs<IContent>>(null, serviceContext.ContentService, new PublishEventArgs<IContent>((IContent) null), "Published"),
new EventDefinition<IContentService, PublishEventArgs<IContent>>(null, serviceContext.ContentService, new PublishEventArgs<IContent>((IContent) null), "UnPublished"),
new EventDefinition<IContentService, PublishEventArgs<IContent>>(null, serviceContext.ContentService, new PublishEventArgs<IContent>(Enumerable.Empty<IContent>()), "Published"),
new EventDefinition<IContentService, PublishEventArgs<IContent>>(null, serviceContext.ContentService, new PublishEventArgs<IContent>(Enumerable.Empty<IContent>()), "UnPublished"),
new EventDefinition<IPublicAccessService, SaveEventArgs<PublicAccessEntry>>(null, serviceContext.PublicAccessService, new SaveEventArgs<PublicAccessEntry>((PublicAccessEntry) null)),
new EventDefinition<IPublicAccessService, DeleteEventArgs<PublicAccessEntry>>(null, serviceContext.PublicAccessService, new DeleteEventArgs<PublicAccessEntry>((PublicAccessEntry) null)),
new EventDefinition<IPublicAccessService, SaveEventArgs<PublicAccessEntry>>(null, serviceContext.PublicAccessService, new SaveEventArgs<PublicAccessEntry>(Enumerable.Empty<PublicAccessEntry>())),
new EventDefinition<IPublicAccessService, DeleteEventArgs<PublicAccessEntry>>(null, serviceContext.PublicAccessService, new DeleteEventArgs<PublicAccessEntry>(Enumerable.Empty<PublicAccessEntry>())),
new EventDefinition<IRelationService, SaveEventArgs<IRelationType>>(null, serviceContext.RelationService, new SaveEventArgs<IRelationType>((IRelationType) null)),
new EventDefinition<IRelationService, DeleteEventArgs<IRelationType>>(null, serviceContext.RelationService, new DeleteEventArgs<IRelationType>((IRelationType) null)),
new EventDefinition<IRelationService, SaveEventArgs<IRelationType>>(null, serviceContext.RelationService, new SaveEventArgs<IRelationType>(Enumerable.Empty<IRelationType>())),
new EventDefinition<IRelationService, DeleteEventArgs<IRelationType>>(null, serviceContext.RelationService, new DeleteEventArgs<IRelationType>(Enumerable.Empty<IRelationType>())),
new EventDefinition<IRelationService, SaveEventArgs<IRelationType>>(null, serviceContext.RelationService, new SaveEventArgs<IRelationType>((IRelationType) null)),
new EventDefinition<IRelationService, DeleteEventArgs<IRelationType>>(null, serviceContext.RelationService, new DeleteEventArgs<IRelationType>((IRelationType) null)),
new EventDefinition<IRelationService, SaveEventArgs<IRelationType>>(null, serviceContext.RelationService, new SaveEventArgs<IRelationType>(Enumerable.Empty<IRelationType>())),
new EventDefinition<IRelationService, DeleteEventArgs<IRelationType>>(null, serviceContext.RelationService, new DeleteEventArgs<IRelationType>(Enumerable.Empty<IRelationType>())),
};
foreach (var definition in definitions)

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
@@ -166,5 +167,38 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
{
Assert.IsTrue(SettingsSection.Content.DisallowedUploadFiles.All(x => "ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd".Split(',').Contains(x)));
}
[Test]
public void AllowedUploadFiles()
{
Assert.IsTrue(SettingsSection.Content.AllowedUploadFiles.All(x => "jpg,gif,png".Split(',').Contains(x)));
}
[Test]
[TestCase("png", true)]
[TestCase("jpg", true)]
[TestCase("gif", true)]
// TODO: Why does it flip to TestingDefaults=true for these two tests on AppVeyor. WHY?
//[TestCase("bmp", false)]
//[TestCase("php", false)]
[TestCase("ashx", false)]
[TestCase("config", false)]
public void IsFileAllowedForUpload_WithWhitelist(string extension, bool expected)
{
// Make really sure that defaults are NOT used
TestingDefaults = false;
Debug.WriteLine("Extension being tested", extension);
Debug.WriteLine("AllowedUploadFiles: {0}", SettingsSection.Content.AllowedUploadFiles);
Debug.WriteLine("DisallowedUploadFiles: {0}", SettingsSection.Content.DisallowedUploadFiles);
var allowedContainsExtension = SettingsSection.Content.AllowedUploadFiles.Any(x => x.InvariantEquals(extension));
var disallowedContainsExtension = SettingsSection.Content.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension));
Debug.WriteLine("AllowedContainsExtension: {0}", allowedContainsExtension);
Debug.WriteLine("DisallowedContainsExtension: {0}", disallowedContainsExtension);
Assert.AreEqual(SettingsSection.Content.IsFileAllowedForUpload(extension), expected);
}
}
}

View File

@@ -1,7 +1,7 @@
using System.Configuration;
using System.Diagnostics;
using System.IO;
using NUnit.Framework;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Tests.TestHelpers;
@@ -9,11 +9,7 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
{
public abstract class UmbracoSettingsTests
{
protected virtual bool TestingDefaults
{
get { return false; }
}
protected virtual bool TestingDefaults { get; set; }
[SetUp]
public void Init()
@@ -23,6 +19,7 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
var fileMap = new ExeConfigurationFileMap() { ExeConfigFilename = config.FullName };
var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
Debug.WriteLine("Testing defaults? {0}", TestingDefaults);
if (TestingDefaults)
{
SettingsSection = configuration.GetSection("umbracoConfiguration/defaultSettings") as UmbracoSettingsSection;
@@ -32,8 +29,6 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
SettingsSection = configuration.GetSection("umbracoConfiguration/settings") as UmbracoSettingsSection;
}
Assert.IsNotNull(SettingsSection);
}

View File

@@ -92,6 +92,9 @@
<!-- These file types will not be allowed to be uploaded via the upload control for media and content -->
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd</disallowedUploadFiles>
<!-- If completed, only the file extensions listed below will be allowed to be uploaded. If empty, disallowedUploadFiles will apply to prevent upload of specific file extensions. -->
<allowedUploadFiles>jpg,png,gif</allowedUploadFiles>
<!-- Defines the default document type property used when adding properties in the back-office (if missing or empty, defaults to Textstring -->
<defaultDocumentTypeProperty>Textstring</defaultDocumentTypeProperty>
</content>

View File

@@ -22,7 +22,7 @@ namespace Umbraco.Tests.Misc
private void Initialize(IUmbracoSettingsSection settings)
{
_registrar = new ConfigServerRegistrar(settings.DistributedCall);
_registrar = new ConfigServerRegistrar(settings.DistributedCall, Mock.Of<ILogger>());
var container = new ServiceContainer();
container.ConfigureUmbracoCore();
container.Register(_ => _registrar);

View File

@@ -40,14 +40,14 @@ namespace Umbraco.Tests.Persistence.Repositories
{
var repository = new PartialViewRepository(unitOfWork, _fileSystem);
var partialView = new PartialView("test-path-1.cshtml") { Content = "// partialView" };
var partialView = new PartialView(PartialViewType.PartialView, "test-path-1.cshtml") { Content = "// partialView" };
repository.AddOrUpdate(partialView);
unitOfWork.Flush();
Assert.IsTrue(_fileSystem.FileExists("test-path-1.cshtml"));
Assert.AreEqual("test-path-1.cshtml", partialView.Path);
Assert.AreEqual("/Views/Partials/test-path-1.cshtml", partialView.VirtualPath);
partialView = new PartialView("path-2/test-path-2.cshtml") { Content = "// partialView" };
partialView = new PartialView(PartialViewType.PartialView, "path-2/test-path-2.cshtml") { Content = "// partialView" };
repository.AddOrUpdate(partialView);
unitOfWork.Flush();
Assert.IsTrue(_fileSystem.FileExists("path-2/test-path-2.cshtml"));
@@ -59,7 +59,7 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.AreEqual("path-2\\test-path-2.cshtml", partialView.Path);
Assert.AreEqual("/Views/Partials/path-2/test-path-2.cshtml", partialView.VirtualPath);
partialView = new PartialView("path-2\\test-path-3.cshtml") { Content = "// partialView" };
partialView = new PartialView(PartialViewType.PartialView, "path-2\\test-path-3.cshtml") { Content = "// partialView" };
repository.AddOrUpdate(partialView);
unitOfWork.Flush();
Assert.IsTrue(_fileSystem.FileExists("path-2/test-path-3.cshtml"));
@@ -76,7 +76,7 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.AreEqual("path-2\\test-path-3.cshtml", partialView.Path);
Assert.AreEqual("/Views/Partials/path-2/test-path-3.cshtml", partialView.VirtualPath);
partialView = new PartialView("\\test-path-4.cshtml") { Content = "// partialView" };
partialView = new PartialView(PartialViewType.PartialView, "\\test-path-4.cshtml") { Content = "// partialView" };
Assert.Throws<FileSecurityException>(() => // fixed in 7.3 - 7.2.8 used to strip the \
{
repository.AddOrUpdate(partialView);

View File

@@ -4,15 +4,18 @@ using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Scoping;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
namespace Umbraco.Tests.Scoping
{
[TestFixture]
public class ScopeEventDispatcherTests
public class ScopeEventDispatcherTests //: BaseUmbracoConfigurationTest
{
[SetUp]
public void Setup()
@@ -81,7 +84,7 @@ namespace Umbraco.Tests.Scoping
var events = scope.Events.GetEvents(EventDefinitionFilter.All).ToArray();
var knownNames = new[] { "DoThing1", "DoThing2", "DoThing3" };
var knownArgTypes = new[] { typeof (SaveEventArgs<string>), typeof (SaveEventArgs<int>), typeof (SaveEventArgs<decimal>) };
var knownArgTypes = new[] { typeof(SaveEventArgs<string>), typeof(SaveEventArgs<int>), typeof(SaveEventArgs<decimal>) };
for (var i = 0; i < events.Length; i++)
{
@@ -91,6 +94,166 @@ namespace Umbraco.Tests.Scoping
}
}
[Test]
public void SupersededEvents()
{
DoSaveForContent += OnDoThingFail;
DoDeleteForContent += OnDoThingFail;
DoForTestArgs += OnDoThingFail;
DoForTestArgs2 += OnDoThingFail;
var contentType = MockedContentTypes.CreateBasicContentType();
var content1 = MockedContent.CreateBasicContent(contentType);
content1.Id = 123;
var content2 = MockedContent.CreateBasicContent(contentType);
content2.Id = 456;
var content3 = MockedContent.CreateBasicContent(contentType);
content3.Id = 789;
var scopeProvider = new ScopeProvider(Mock.Of<IUmbracoDatabaseFactory>(), new Lazy<FileSystems>(() => Mock.Of<FileSystems>()), Mock.Of<ILogger>());
using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher()))
{
//content1 will be filtered from the args
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(new[]{ content1 , content3}));
scope.Events.Dispatch(DoDeleteForContent, this, new DeleteEventArgs<IContent>(content1));
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content2));
//this entire event will be filtered
scope.Events.Dispatch(DoForTestArgs, this, new TestEventArgs(content1));
scope.Events.Dispatch(DoForTestArgs2, this, new TestEventArgs2(content1));
// events have been queued
var events = scope.Events.GetEvents(EventDefinitionFilter.All).ToArray();
Assert.AreEqual(4, events.Length);
Assert.AreEqual(typeof(SaveEventArgs<IContent>), events[0].Args.GetType());
Assert.AreEqual(1, ((SaveEventArgs<IContent>)events[0].Args).SavedEntities.Count());
Assert.AreEqual(content3.Id, ((SaveEventArgs<IContent>)events[0].Args).SavedEntities.First().Id);
Assert.AreEqual(typeof(DeleteEventArgs<IContent>), events[1].Args.GetType());
Assert.AreEqual(content1.Id, ((DeleteEventArgs<IContent>) events[1].Args).DeletedEntities.First().Id);
Assert.AreEqual(typeof(SaveEventArgs<IContent>), events[2].Args.GetType());
Assert.AreEqual(content2.Id, ((SaveEventArgs<IContent>)events[2].Args).SavedEntities.First().Id);
Assert.AreEqual(typeof(TestEventArgs2), events[3].Args.GetType());
}
}
/// <summary>
/// This will test that when we track events that before we Get the events we normalize all of the
/// event entities to be the latest one (most current) found amongst the event so that there is
/// no 'stale' entities in any of the args
/// </summary>
[Test]
public void LatestEntities()
{
DoSaveForContent += OnDoThingFail;
var now = DateTime.Now;
var contentType = MockedContentTypes.CreateBasicContentType();
var content1 = MockedContent.CreateBasicContent(contentType);
content1.Id = 123;
content1.UpdateDate = now.AddMinutes(1);
var content2 = MockedContent.CreateBasicContent(contentType);
content2.Id = 123;
content2.UpdateDate = now.AddMinutes(2);
var content3 = MockedContent.CreateBasicContent(contentType);
content3.Id = 123;
content3.UpdateDate = now.AddMinutes(3);
var scopeProvider = new ScopeProvider(Mock.Of<IUmbracoDatabaseFactory>(), new Lazy<FileSystems>(() => Mock.Of<FileSystems>()), Mock.Of<ILogger>());
using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher()))
{
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content1));
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content2));
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content3));
// events have been queued
var events = scope.Events.GetEvents(EventDefinitionFilter.All).ToArray();
Assert.AreEqual(3, events.Length);
foreach (var t in events)
{
var args = (SaveEventArgs<IContent>)t.Args;
foreach (var entity in args.SavedEntities)
{
Assert.AreEqual(content3, entity);
Assert.IsTrue(object.ReferenceEquals(content3, entity));
}
}
}
}
[Test]
public void FirstIn()
{
DoSaveForContent += OnDoThingFail;
var now = DateTime.Now;
var contentType = MockedContentTypes.CreateBasicContentType();
var content1 = MockedContent.CreateBasicContent(contentType);
content1.Id = 123;
content1.UpdateDate = now.AddMinutes(1);
var content2 = MockedContent.CreateBasicContent(contentType);
content2.Id = 123;
content1.UpdateDate = now.AddMinutes(2);
var content3 = MockedContent.CreateBasicContent(contentType);
content3.Id = 123;
content1.UpdateDate = now.AddMinutes(3);
var scopeProvider = new ScopeProvider(Mock.Of<IUmbracoDatabaseFactory>(), new Lazy<FileSystems>(() => Mock.Of<FileSystems>()), Mock.Of<ILogger>());
using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher()))
{
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content1));
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content2));
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content3));
// events have been queued
var events = scope.Events.GetEvents(EventDefinitionFilter.FirstIn).ToArray();
Assert.AreEqual(1, events.Length);
Assert.AreEqual(content1, ((SaveEventArgs<IContent>) events[0].Args).SavedEntities.First());
Assert.IsTrue(object.ReferenceEquals(content1, ((SaveEventArgs<IContent>)events[0].Args).SavedEntities.First()));
Assert.AreEqual(content1.UpdateDate, ((SaveEventArgs<IContent>) events[0].Args).SavedEntities.First().UpdateDate);
}
}
[Test]
public void LastIn()
{
DoSaveForContent += OnDoThingFail;
var now = DateTime.Now;
var contentType = MockedContentTypes.CreateBasicContentType();
var content1 = MockedContent.CreateBasicContent(contentType);
content1.Id = 123;
content1.UpdateDate = now.AddMinutes(1);
var content2 = MockedContent.CreateBasicContent(contentType);
content2.Id = 123;
content2.UpdateDate = now.AddMinutes(2);
var content3 = MockedContent.CreateBasicContent(contentType);
content3.Id = 123;
content3.UpdateDate = now.AddMinutes(3);
var scopeProvider = new ScopeProvider(Mock.Of<IUmbracoDatabaseFactory>(), new Lazy<FileSystems>(() => Mock.Of<FileSystems>()), Mock.Of<ILogger>());
using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher()))
{
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content1));
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content2));
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content3));
// events have been queued
var events = scope.Events.GetEvents(EventDefinitionFilter.LastIn).ToArray();
Assert.AreEqual(1, events.Length);
Assert.AreEqual(content3, ((SaveEventArgs<IContent>)events[0].Args).SavedEntities.First());
Assert.IsTrue(object.ReferenceEquals(content3, ((SaveEventArgs<IContent>)events[0].Args).SavedEntities.First()));
Assert.AreEqual(content3.UpdateDate, ((SaveEventArgs<IContent>)events[0].Args).SavedEntities.First().UpdateDate);
}
}
[TestCase(true)]
[TestCase(false)]
public void EventsDispatching_Passive(bool complete)
@@ -179,12 +342,40 @@ namespace Umbraco.Tests.Scoping
Assert.Fail();
}
public static event EventHandler<SaveEventArgs<IContent>> DoSaveForContent;
public static event EventHandler<DeleteEventArgs<IContent>> DoDeleteForContent;
public static event EventHandler<TestEventArgs> DoForTestArgs;
public static event EventHandler<TestEventArgs2> DoForTestArgs2;
public static event EventHandler<SaveEventArgs<string>> DoThing1;
public static event EventHandler<SaveEventArgs<int>> DoThing2;
public static event TypedEventHandler<ScopeEventDispatcherTests, SaveEventArgs<decimal>> DoThing3;
public class TestEventArgs : CancellableObjectEventArgs
{
public TestEventArgs(object eventObject) : base(eventObject)
{
}
public object MyEventObject
{
get { return EventObject; }
}
}
[SupersedeEvent(typeof(TestEventArgs))]
public class TestEventArgs2 : CancellableObjectEventArgs
{
public TestEventArgs2(object eventObject) : base(eventObject)
{
}
public object MyEventObject
{
get { return EventObject; }
}
}
public class PassiveEventDispatcher : QueuingEventDispatcherBase
{
public PassiveEventDispatcher()

View File

@@ -533,6 +533,44 @@ namespace Umbraco.Tests.Scoping
Assert.IsNotNull(ambientContext); // the context is still there
}
[TestCase(true)]
[TestCase(false)]
public void ScopeContextEnlistAgain(bool complete)
{
var scopeProvider = ScopeProvider as IScopeProviderInternal;
bool? completed = null;
Exception exception = null;
Assert.IsNull(scopeProvider.AmbientScope);
using (var scope = scopeProvider.CreateScope())
{
scopeProvider.Context.Enlist("name", c =>
{
completed = c;
// at that point the scope is gone, but the context is still there
var ambientContext = scopeProvider.AmbientContext;
try
{
ambientContext.Enlist("another", c2 => { });
}
catch (Exception e)
{
exception = e;
}
});
if (complete)
scope.Complete();
}
Assert.IsNull(scopeProvider.AmbientScope);
Assert.IsNull(scopeProvider.AmbientContext);
Assert.IsNotNull(completed);
Assert.IsNotNull(exception);
Assert.IsInstanceOf<InvalidOperationException>(exception);
}
[Test]
public void ScopeContextException()
{

View File

@@ -154,7 +154,9 @@ namespace Umbraco.Tests.Scoping
// scope.Complete();
// }
// Assert.AreEqual(complete ? 2 : 0, evented);
//The reason why there is only 1 event occuring is because we are publishing twice for the same event for the same
//object and the scope deduplicates the events (uses the latest)
// Assert.AreEqual(complete ? 1 : 0, evented);
// // this should never change
// Assert.AreEqual(beforeOuterXml, beforeXml.OuterXml);

View File

@@ -31,6 +31,34 @@ namespace Umbraco.Tests
Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyString + "/test-id", udi.ToString());
}
[Test]
public void StringEncodingTest()
{
// absolute path is unescaped
var uri = new Uri("umb://" + Constants.UdiEntityType.AnyString + "/this%20is%20a%20test");
Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyString + "/this is a test", uri.ToString());
Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyString + "/this%20is%20a%20test", uri.AbsoluteUri);
Assert.AreEqual("/this%20is%20a%20test", uri.AbsolutePath);
Assert.AreEqual("/this is a test", Uri.UnescapeDataString(uri.AbsolutePath));
Assert.AreEqual("%2Fthis%20is%20a%20test", Uri.EscapeDataString("/this is a test"));
Assert.AreEqual("/this%20is%20a%20test", Uri.EscapeUriString("/this is a test"));
var udi = Udi.Parse("umb://" + Constants.UdiEntityType.AnyString + "/this%20is%20a%20test");
Assert.AreEqual(Constants.UdiEntityType.AnyString, udi.EntityType);
Assert.IsInstanceOf<StringUdi>(udi);
var stringEntityId = udi as StringUdi;
Assert.IsNotNull(stringEntityId);
Assert.AreEqual("this is a test", stringEntityId.Id);
Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyString + "/this%20is%20a%20test", udi.ToString());
var udi2 = new StringUdi(Constants.UdiEntityType.AnyString, "this is a test");
Assert.AreEqual(udi, udi2);
var udi3 = new StringUdi(Constants.UdiEntityType.AnyString, "path to/this is a test.xyz");
Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyString + "/path%20to/this%20is%20a%20test.xyz", udi3.ToString());
}
[Test]
public void GuidEntityCtorTest()
{

View File

@@ -105,11 +105,11 @@ angular.module("umbraco.directives")
});
//// INIT /////
$image.load(function(){
$timeout(function(){
$image.load(function() {
$timeout(function() {
setDimensions();
scope.loaded = true;
if (scope.onImageLoaded) {
if (angular.isFunction(scope.onImageLoaded)) {
scope.onImageLoaded();
}
});

View File

@@ -5,15 +5,14 @@
**/
function ourPackageRepositoryResource($q, $http, umbDataFormatter, umbRequestHelper) {
//var baseurl = "http://localhost:24292/webapi/packages/v1";
var baseurl = "https://our.umbraco.org/webapi/packages/v1";
var baseurl = Umbraco.Sys.ServerVariables.umbracoUrls.packagesRestApiBaseUrl;
return {
getDetails: function (packageId) {
return umbRequestHelper.resourcePromise(
$http.get(baseurl + "/" + packageId),
$http.get(baseurl + "/" + packageId + "?version=" + Umbraco.Sys.ServerVariables.application.version),
'Failed to get package details');
},

View File

@@ -5,7 +5,7 @@
</p>
<p>
To read a report of changes between your current version <strong>{{installer.current.model.currentVersion}}</strong> and this version your upgrading to <strong>{{installer.current.model.newVersion}}</strong>
To read a report of changes between your current version <strong>{{installer.current.model.currentVersion}}</strong> and this version you're upgrading to <strong>{{installer.current.model.newVersion}}</strong>
</p>
<p>
<a ng-href="{{installer.current.model.reportUrl}}" target="_blank" class="btn btn-info">View Report</a>

View File

@@ -49,7 +49,7 @@
.umb-tree li.current > div i.icon,
.umb-tree li.current > div ins {
color: @white !important;
background: @turquoise-d1;
background-color: @turquoise-d1;
border-color: @turquoise-d1;
}

View File

@@ -50,7 +50,7 @@
<div class="control-group" ng-class="{error: loginForm.username.$invalid}">
<label><localize key="general_username">Username</localize></label>
<input type="text" ng-model="login" name="username" class="-full-width-input" localize="placeholder" placeholder="@placeholders_username" />
<input type="text" ng-model="login" name="username" class="-full-width-input" localize="placeholder" placeholder="@placeholders_usernameHint" />
</div>
<div class="control-group" ng-class="{error: loginForm.password.$invalid}">

View File

@@ -6,7 +6,8 @@
placeholder="@general_url"
class="umb-editor umb-textstring"
ng-model="model.target.url"
ng-disabled="model.target.id"/>
ng-disabled="model.target.id"
focus-when="{{true}} "/>
</umb-control-group>
<umb-control-group label="@content_nodeName">

View File

@@ -16,14 +16,22 @@ angular.module("umbraco")
$scope.startNodeId = dialogOptions.startNodeId ? dialogOptions.startNodeId : -1;
$scope.cropSize = dialogOptions.cropSize;
$scope.lastOpenedNode = localStorageService.get("umbLastOpenedMediaNodeId");
var umbracoSettings = Umbraco.Sys.ServerVariables.umbracoSettings;
var allowedUploadFiles = mediaHelper.formatFileTypes(umbracoSettings.allowedUploadFiles);
if ($scope.onlyImages) {
$scope.acceptedFileTypes = mediaHelper
.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes);
$scope.acceptedFileTypes = mediaHelper.formatFileTypes(umbracoSettings.imageFileTypes);
} else {
$scope.acceptedFileTypes = !mediaHelper
.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.disallowedUploadFiles);
// Use whitelist of allowed file types if provided
if (allowedUploadFiles !== '') {
$scope.acceptedFileTypes = allowedUploadFiles;
} else {
// If no whitelist, we pass in a blacklist by adding ! to the file extensions, allowing everything EXCEPT for disallowedUploadFiles
$scope.acceptedFileTypes = !mediaHelper.formatFileTypes(umbracoSettings.disallowedUploadFiles);
}
$scope.maxFileSize = Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB";
}
$scope.maxFileSize = umbracoSettings.maxFileSize + "KB";
$scope.model.selectedImages = [];

View File

@@ -1,13 +1,12 @@
(function () {
(function() {
"use strict";
function QueryBuilderOverlayController($scope, templateQueryResource, localizationService) {
var everything = localizationService.localize("template_allContent");
var myWebsite = localizationService.localize("template_websiteRoot");
var ascendingTranslation = localizationService.localize("template_ascending");
var descendingTranslation = localizationService.localize("template_descending");
var everything = "";
var myWebsite = "";
var ascendingTranslation = "";
var descendingTranslation = "";
var vm = this;
@@ -21,6 +20,20 @@
format: "YYYY-MM-DD"
};
vm.chooseSource = chooseSource;
vm.getPropertyOperators = getPropertyOperators;
vm.addFilter = addFilter;
vm.trashFilter = trashFilter;
vm.changeSortOrder = changeSortOrder;
vm.setSortProperty = setSortProperty;
vm.setContentType = setContentType;
vm.setFilterProperty = setFilterProperty;
vm.setFilterTerm = setFilterTerm;
vm.changeConstraintValue = changeConstraintValue;
vm.datePickerChange = datePickerChange;
function onInit() {
vm.query = {
contentType: {
name: everything
@@ -45,36 +58,21 @@
ascending: ascendingTranslation,
descending: descendingTranslation
}
}
};
vm.chooseSource = chooseSource;
vm.getPropertyOperators = getPropertyOperators;
vm.addFilter = addFilter;
vm.trashFilter = trashFilter;
vm.changeSortOrder = changeSortOrder;
vm.setSortProperty = setSortProperty;
vm.setContentType = setContentType;
vm.setFilterProperty = setFilterProperty;
vm.setFilterTerm = setFilterTerm;
vm.changeConstraintValue = changeConstraintValue;
vm.datePickerChange = datePickerChange;
function onInit() {
templateQueryResource.getAllowedProperties()
.then(function (properties) {
.then(function(properties) {
vm.properties = properties;
});
templateQueryResource.getContentTypes()
.then(function (contentTypes) {
.then(function(contentTypes) {
vm.contentTypes = contentTypes;
});
templateQueryResource.getFilterConditions()
.then(function (conditions) {
.then(function(conditions) {
vm.conditions = conditions;
});
@@ -111,7 +109,8 @@
}
function getPropertyOperators(property) {
var conditions = _.filter(vm.conditions, function (condition) {
var conditions = _.filter(vm.conditions,
function(condition) {
var index = condition.appliesTo.indexOf(property.type);
return index >= 0;
});
@@ -123,10 +122,8 @@
}
function trashFilter(query, filter) {
for (var i = 0; i < query.filters.length; i++)
{
if (query.filters[i] == filter)
{
for (var i = 0; i < query.filters.length; i++) {
if (query.filters[i] == filter) {
query.filters.splice(i, 1);
}
}
@@ -173,7 +170,7 @@
function setFilterTerm(filter, term) {
filter.term = term;
if(filter.constraintValue) {
if (filter.constraintValue) {
throttledFunc();
}
}
@@ -183,22 +180,32 @@
}
function datePickerChange(event, filter) {
if(event.date && event.date.isValid()) {
if (event.date && event.date.isValid()) {
filter.constraintValue = event.date.format(vm.datePickerConfig.format);
throttledFunc();
}
}
var throttledFunc = _.throttle(function () {
var throttledFunc = _.throttle(function() {
templateQueryResource.postTemplateQuery(vm.query)
.then(function (response) {
.then(function(response) {
$scope.model.result = response;
});
}, 200);
},
200);
localizationService.localizeMany([
"template_allContent", "template_websiteRoot", "template_ascending", "template_descending"
])
.then(function(res) {
everything = res[0];
myWebsite = res[1];
ascendingTranslation = res[2];
descendingTranslation = res[3];
onInit();
});
}
angular.module("umbraco").controller("Umbraco.Overlays.QueryBuilderController", QueryBuilderOverlayController);

View File

@@ -1,5 +1,5 @@
<div class="umb-media-grid">
<div class="umb-media-grid__item" ng-click="clickItem(item, $event, $index)" ng-repeat="item in items | filter:filterBy" ng-style="item.flexStyle" ng-class="{'-selected': item.selected, '-file': !item.thumbnail, '-svg': item.extension == 'svg'}">
<div class="umb-media-grid__item" title="{{item.name}}" ng-click="clickItem(item, $event, $index)" ng-repeat="item in items | filter:filterBy" ng-style="item.flexStyle" ng-class="{'-selected': item.selected, '-file': !item.thumbnail, '-svg': item.extension == 'svg'}">
<div>
<i ng-show="item.selected" class="icon-check umb-media-grid__checkmark"></i>
@@ -12,10 +12,10 @@
<div class="umb-media-grid__image-background" ng-if="item.thumbnail || item.extension == 'svg'"></div>
<!-- Image thumbnail -->
<img class="umb-media-grid__item-image" width="{{item.width}}" height="{{item.height}}" ng-if="item.thumbnail" ng-src="{{item.thumbnail}}" alt="{{item.name}}" title="{{item.name}}" draggable="false" />
<img class="umb-media-grid__item-image" width="{{item.width}}" height="{{item.height}}" ng-if="item.thumbnail" ng-src="{{item.thumbnail}}" alt="{{item.name}}" draggable="false" />
<!-- SVG -->
<img class="umb-media-grid__item-image" width="{{item.width}}" height="{{item.height}}" ng-if="!item.thumbnail && item.extension == 'svg'" ng-src="{{item.file}}" alt="{{item.name}}" title="{{item.name}}" draggable="false" />
<img class="umb-media-grid__item-image" width="{{item.width}}" height="{{item.height}}" ng-if="!item.thumbnail && item.extension == 'svg'" ng-src="{{item.file}}" alt="{{item.name}}" draggable="false" />
<!-- Transparent image - fallback - used to keep image proportions on wrapper-->
<img class="umb-media-grid__item-image-placeholder" ng-if="!item.thumbnail && item.extension != 'svg'" src="assets/img/transparent.png" alt="{{item.name}}" draggable="false" />

View File

@@ -138,15 +138,15 @@ function fileUploadController($scope, $element, $compile, imageHelper, fileManag
//cannot just check for !newVal because it might be an empty string which we
//want to look for.
if (newVal !== null && newVal !== undefined && newVal !== oldVal) {
//now we need to check if we need to re-initialize our structure which is kind of tricky
// since we only want to do that if the server has changed the value, not if this controller
// has changed the value. There's only 2 scenarios where we change the value internall so
// we know what those values can be, if they are not either of them, then we'll re-initialize.
if (newVal.clearFiles !== true && newVal !== $scope.originalValue && !newVal.selectedFiles) {
// here we need to check if the value change needs to trigger an update in the UI.
// if the value is only changed in the controller and not in the server values, we do not
// want to trigger an update yet.
// we can however no longer rely on checking values in the controller vs. values from the server
// to determine whether to update or not, since you could potentially be uploading a file with
// the exact same name - in that case we need to reinitialize to show the newly uploaded file.
if (newVal.clearFiles !== true && !newVal.selectedFiles) {
initialize($scope.rebuildInput.index + 1);
}
}
});
};

View File

@@ -1,10 +1,17 @@
angular.module("umbraco")
.controller("Umbraco.PropertyEditors.Grid.MediaController",
function ($scope, $rootScope, $timeout) {
function ($scope, $rootScope, $timeout, userService) {
if (!$scope.model.config.startNodeId) {
userService.getCurrentUser().then(function (userData) {
$scope.model.config.startNodeId = userData.startMediaId;
});
}
$scope.setImage = function(){
$scope.mediaPickerOverlay = {};
$scope.mediaPickerOverlay.view = "mediapicker";
$scope.mediaPickerOverlay.startNodeId = $scope.model.config && $scope.model.config.startNodeId ? $scope.model.config.startNodeId : undefined;
$scope.mediaPickerOverlay.cropSize = $scope.control.editor.config && $scope.control.editor.config.size ? $scope.control.editor.config.size : undefined;
$scope.mediaPickerOverlay.showDetails = true;
$scope.mediaPickerOverlay.disableFolderSelect = true;

View File

@@ -6,17 +6,23 @@
* @description
* The controller for the content type editor
*/
(function() {
(function () {
"use strict";
function ListViewGridLayoutController($scope, $routeParams, mediaHelper, mediaResource, $location, listViewHelper, mediaTypeHelper) {
var vm = this;
var umbracoSettings = Umbraco.Sys.ServerVariables.umbracoSettings;
vm.nodeId = $scope.contentId;
//we pass in a blacklist by adding ! to the file extensions, allowing everything EXCEPT for disallowedUploadFiles
vm.acceptedFileTypes = !mediaHelper.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.disallowedUploadFiles);
vm.maxFileSize = Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB";
// Use whitelist of allowed file types if provided
vm.acceptedFileTypes = mediaHelper.formatFileTypes(umbracoSettings.allowedUploadFiles);
if (vm.acceptedFileTypes === '') {
// If not provided, we pass in a blacklist by adding ! to the file extensions, allowing everything EXCEPT for disallowedUploadFiles
vm.acceptedFileTypes = !mediaHelper.formatFileTypes(umbracoSettings.disallowedUploadFiles);
}
vm.maxFileSize = umbracoSettings.maxFileSize + "KB";
vm.activeDrag = false;
vm.mediaDetailsTooltip = {};
vm.itemsWithoutFolders = [];
@@ -50,7 +56,7 @@
var newArray = [];
if(items && items.length ) {
if (items && items.length) {
for (var i = 0; items.length > i; i++) {
var item = items[i];

View File

@@ -4,11 +4,18 @@
function ListViewListLayoutController($scope, listViewHelper, $location, mediaHelper, mediaTypeHelper) {
var vm = this;
var umbracoSettings = Umbraco.Sys.ServerVariables.umbracoSettings;
vm.nodeId = $scope.contentId;
//we pass in a blacklist by adding ! to the file extensions, allowing everything EXCEPT for disallowedUploadFiles
vm.acceptedFileTypes = !mediaHelper.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.disallowedUploadFiles);
vm.maxFileSize = Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB";
// Use whitelist of allowed file types if provided
vm.acceptedFileTypes = mediaHelper.formatFileTypes(umbracoSettings.allowedUploadFiles);
if (vm.acceptedFileTypes === '') {
// If not provided, we pass in a blacklist by adding ! to the file extensions, allowing everything EXCEPT for disallowedUploadFiles
vm.acceptedFileTypes = !mediaHelper.formatFileTypes(umbracoSettings.disallowedUploadFiles);
}
vm.maxFileSize = umbracoSettings.maxFileSize + "KB";
vm.activeDrag = false;
vm.isRecycleBin = $scope.contentId === '-21' || $scope.contentId === '-20';
vm.acceptedMediatypes = [];
@@ -48,7 +55,7 @@
function clickItem(item) {
// if item.id is 2147483647 (int.MaxValue) use item.key
$location.path($scope.entityType + '/' +$scope.entityType + '/edit/' + (item.id === 2147483647 ? item.key : item.id));
$location.path($scope.entityType + '/' + $scope.entityType + '/edit/' + (item.id === 2147483647 ? item.key : item.id));
}
function isSortDirection(col, direction) {
@@ -84,6 +91,6 @@
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.ListView.ListLayoutController", ListViewListLayoutController);
angular.module("umbraco").controller("Umbraco.PropertyEditors.ListView.ListLayoutController", ListViewListLayoutController);
}) ();
})();

View File

@@ -112,10 +112,9 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
// content picker. THen we don't have to worry about setting ids, render models, models, we just set one and let the
// watch do all the rest.
$timeout(function(){
angular.forEach($scope.images, function(value, key){
r.push(value.id);
angular.forEach($scope.images, function(value, key) {
r.push($scope.model.config.idType === "udi" ? value.udi : value.id);
});
$scope.ids = r;
$scope.sync();
}, 500, false);

View File

@@ -61,9 +61,12 @@
// if master template alias has changed move the node to it's new location
if(oldMasterTemplateAlias !== vm.template.masterTemplateAlias) {
// When creating a new template the id is -1. Make sure We don't remove the root node.
if (vm.page.menu.currentNode.id !== "-1") {
// move node to new location in tree
//first we need to remove the node that we're working on
treeService.removeNode(vm.page.menu.currentNode);
}
// update stored alias to the new one so the node won't move again unless the alias is changed again
oldMasterTemplateAlias = vm.template.masterTemplateAlias;

View File

@@ -15,7 +15,7 @@
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<UseIISExpress>true</UseIISExpress>
<IISExpressSSLPort>44319</IISExpressSSLPort>
<IISExpressSSLPort></IISExpressSSLPort>
<IISExpressAnonymousAuthentication>enabled</IISExpressAnonymousAuthentication>
<IISExpressWindowsAuthentication>disabled</IISExpressWindowsAuthentication>
<IISExpressUseClassicPipelineMode>false</IISExpressUseClassicPipelineMode>
@@ -482,13 +482,6 @@
<Compile Include="..\SolutionInfo.cs">
<Link>Properties\SolutionInfo.cs</Link>
</Compile>
<Compile Include="Umbraco\Install\Legacy\LoadStarterKits.ascx.cs">
<DependentUpon>loadStarterKits.ascx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="Umbraco\Install\Legacy\LoadStarterKits.ascx.designer.cs">
<DependentUpon>loadStarterKits.ascx</DependentUpon>
</Compile>
<Compile Include="Config\splashes\NoNodes.aspx.cs">
<DependentUpon>noNodes.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
@@ -566,13 +559,6 @@
<Compile Include="Umbraco\Developer\Packages\DirectoryBrowser.aspx.designer.cs">
<DependentUpon>directoryBrowser.aspx</DependentUpon>
</Compile>
<Compile Include="Umbraco\Developer\Packages\StarterKits.aspx.cs">
<DependentUpon>StarterKits.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="Umbraco\Developer\Packages\StarterKits.aspx.designer.cs">
<DependentUpon>StarterKits.aspx</DependentUpon>
</Compile>
<Compile Include="Umbraco\Dialogs\ChangeDocType.aspx.cs">
<DependentUpon>ChangeDocType.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
@@ -668,7 +654,6 @@
<Content Include="Scripts\jquery-1.6.4.js" />
<Content Include="Scripts\jquery-1.6.4.min.js" />
<Content Include="Umbraco\Config\Lang\cs.xml" />
<Content Include="Umbraco\Install\Legacy\loadStarterKits.ascx" />
<Content Include="Umbraco\ClientRedirect.aspx" />
<Content Include="Umbraco\create.aspx" />
<Content Include="Umbraco\Logout.aspx" />
@@ -816,7 +801,6 @@
<Content Include="Umbraco_Client\Modal\jquery.simplemodal.1.4.1.custom.js" />
<Content Include="Umbraco\Config\Lang\ko.xml" />
<Content Include="Umbraco\Dashboard\FeedProxy.aspx" />
<Content Include="Umbraco\Developer\Packages\StarterKits.aspx" />
<Content Include="Umbraco_Client\Ui\base2.js" />
<Content Include="Umbraco_Client\Ui\json2.js" />
<Content Include="Umbraco_Client\Ui\knockout.js" />
@@ -859,7 +843,6 @@
<Content Include="Umbraco\Dialogs\mediaPicker.aspx" />
<Content Include="Umbraco_Client\Application\JQuery\jquery.cookie.js" />
<Content Include="Umbraco_Client\Tablesorting\Img\bg.gif" />
<Content Include="Umbraco\Developer\Packages\proxy.htm" />
<Content Include="Umbraco\Developer\Xslt\xsltVisualize.aspx" />
<Content Include="Umbraco\Dialogs\empty.htm" />
<Content Include="Umbraco\Dialogs\insertMasterpageContent.aspx" />
@@ -878,12 +861,8 @@
<Content Include="Umbraco\Translation\details.aspx" />
<Content Include="Umbraco_Client\Modal\modalBackground.gif" />
<Content Include="Umbraco_Client\Modal\modalGradiant.gif" />
<Content Include="Umbraco\Developer\Packages\BrowseRepository.aspx" />
<Content Include="Umbraco\Developer\Packages\directoryBrowser.aspx" />
<Content Include="Umbraco\Developer\Packages\editPackage.aspx" />
<Content Include="Umbraco\Developer\Packages\installedPackage.aspx" />
<Content Include="Umbraco\Developer\Packages\LoadNitros.ascx" />
<Content Include="Umbraco\Developer\Packages\SubmitPackage.aspx" />
<Content Include="Umbraco\Dialogs\about.aspx" />
<Content Include="Umbraco\Dialogs\create.aspx" />
<Content Include="Umbraco\Dialogs\cruds.aspx" />
@@ -1131,7 +1110,26 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
</ProjectExtensions>
<Import Project="$(MSBuildProjectDirectory)\..\umbraco.presentation.targets" Condition="$(BuildingInsideVisualStudio) != true" />
<Import Project="$(SolutionDir)umbraco.presentation.targets" Condition="$(BuildingInsideVisualStudio) == true" />
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll')">
<WebPublishingTasks>$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll</WebPublishingTasks>
</PropertyGroup>
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.Tasks.dll')">
<WebPublishingTasks>$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.Tasks.dll</WebPublishingTasks>
</PropertyGroup>
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.Tasks.dll')">
<WebPublishingTasks>$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.Tasks.dll</WebPublishingTasks>
</PropertyGroup>
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.Publishing.Tasks.dll')">
<WebPublishingTasks>$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.Publishing.Tasks.dll</WebPublishingTasks>
</PropertyGroup>
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v15.0\Web\Microsoft.Web.Publishing.Tasks.dll')">
<WebPublishingTasks>$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v15.0\Web\Microsoft.Web.Publishing.Tasks.dll</WebPublishingTasks>
</PropertyGroup>
<UsingTask TaskName="TransformXml" AssemblyFile="$(WebPublishingTasks)" Condition="'$(WebPublishingTasks)' != ''" />
<UsingTask TaskName="TransformXml" AssemblyFile="$(VSWherePath)\Microsoft\VisualStudio\v15.0\Web\Microsoft.Web.Publishing.Tasks.dll" Condition="'$(VSWherePath)' != ''" />
<Target Name="BeforeBuild">
<Message Text="WebPublishingTasks: $(WebPublishingTasks)" Importance="high" />
<Message Text="VSWherePath: $(VSWherePath)" Importance="high" />
<!-- Create web.config file from Template if it doesn't exist -->
<Copy SourceFiles="$(ProjectDir)web.Template.config" DestinationFiles="$(ProjectDir)Web.config" OverwriteReadOnlyFiles="true" SkipUnchangedFiles="false" Condition="!Exists('$(ProjectDir)Web.config')" />
<!-- Transform the local Web.config file in Visual Studio -->

View File

@@ -93,6 +93,9 @@
<!-- These file types will not be allowed to be uploaded via the upload control for media and content -->
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,xhtml,html,htm,svg,php,htaccess</disallowedUploadFiles>
<!-- If completed, only the file extensions listed below will be allowed to be uploaded. If empty, disallowedUploadFiles will apply to prevent upload of specific file extensions. -->
<allowedUploadFiles></allowedUploadFiles>
<!-- Defines the default document type property used when adding properties in the back-office (if missing or empty, defaults to Textstring -->
<defaultDocumentTypeProperty>Textstring</defaultDocumentTypeProperty>

View File

@@ -1,106 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.UI;
using Umbraco.Core.Logging;
using Umbraco.Web.Install;
namespace Umbraco.Web.UI.Install.Steps.Skinning
{
public delegate void StarterKitInstalledEventHandler();
public partial class LoadStarterKits : UserControl
{
/// <summary>
/// Returns the string for the package installer web service base url
/// </summary>
protected string PackageInstallServiceBaseUrl { get; private set; }
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
//Get the URL for the package install service base url
var umbracoPath = Core.Configuration.GlobalSettings.UmbracoMvcArea;
var urlHelper = new UrlHelper(Context.Request.RequestContext);
//PackageInstallServiceBaseUrl = urlHelper.Action("Index", "InstallPackage", new { area = "UmbracoInstall" });
PackageInstallServiceBaseUrl = urlHelper.GetUmbracoApiService("Index", "InstallPackage", "UmbracoInstall");
}
/// <summary>
/// Flag to show if we can connect to the repo or not
/// </summary>
protected bool CannotConnect { get; private set; }
public event StarterKitInstalledEventHandler StarterKitInstalled;
protected virtual void OnStarterKitInstalled()
{
StarterKitInstalled();
}
private readonly global::umbraco.cms.businesslogic.packager.repositories.Repository _repo;
private const string RepoGuid = "65194810-1f85-11dd-bd0b-0800200c9a66";
public LoadStarterKits()
{
_repo = global::umbraco.cms.businesslogic.packager.repositories.Repository.getByGuid(RepoGuid);
}
protected void Page_Load(object sender, EventArgs e)
{
}
//protected void NextStep(object sender, EventArgs e)
//{
// var p = (Default)this.Page;
// //InstallHelper.RedirectToNextStep(Page, Request.GetItemAsString("installStep"));
//}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (_repo == null)
{
throw new InvalidOperationException("Could not find repository with id " + RepoGuid);
}
//clear progressbar cache
//InstallHelper.ClearProgress();
if (_repo.HasConnection())
{
try
{
var r = new org.umbraco.our.Repository();
rep_starterKits.DataSource = r.Modules();
rep_starterKits.DataBind();
}
catch (Exception ex)
{
Current.Logger.Error<LoadStarterKits>("Cannot connect to package repository", ex);
CannotConnect = true;
}
}
else
{
CannotConnect = true;
}
}
protected void GotoLastStep(object sender, EventArgs e)
{
//InstallHelper.RedirectToLastStep(Page);
}
}
}

View File

@@ -1,60 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Umbraco.Web.UI.Install.Steps.Skinning {
public partial class LoadStarterKits {
/// <summary>
/// pl_loadStarterKits control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.PlaceHolder pl_loadStarterKits;
/// <summary>
/// JsInclude1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::ClientDependency.Core.Controls.JsInclude JsInclude1;
/// <summary>
/// rep_starterKits control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Repeater rep_starterKits;
/// <summary>
/// LinkButton1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.LinkButton LinkButton1;
/// <summary>
/// LinkButton2 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.LinkButton LinkButton2;
}
}

View File

@@ -1,98 +0,0 @@
<%@ Control Language="C#" AutoEventWireup="True" CodeBehind="LoadStarterKits.ascx.cs" Inherits="Umbraco.Web.UI.Install.Steps.Skinning.LoadStarterKits" %>
<%@ Import Namespace="Umbraco.Web.org.umbraco.our" %>
<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %>
<asp:PlaceHolder ID="pl_loadStarterKits" runat="server">
<umb:JsInclude ID="JsInclude1" runat="server" FilePath="installer/js/PackageInstaller.js" PathNameAlias="UmbracoClient" />
<% if (!CannotConnect) { %>
<script type="text/javascript">
(function ($) {
$(document).ready(function () {
var installer = new Umbraco.Installer.PackageInstaller({
starterKits: $("a.selectStarterKit"),
baseUrl: "<%= PackageInstallServiceBaseUrl %>",
serverError: $("#serverError"),
connectionError: $("#connectionError"),
setProgress: updateProgressBar,
setStatusMessage: updateStatusMessage
});
installer.init();
});
})(jQuery);
</script>
<% } %>
<div id="starter-kit-progress" style="display: none;">
<h2>Installation in progress...</h2>
<div class="loader">
<div class="hold">
<div class="progress-bar">
</div>
<span class="progress-bar-value">0%</span>
</div>
<strong></strong>
</div>
</div>
<asp:Repeater ID="rep_starterKits" runat="server">
<headertemplate>
<ul class="thumbnails">
</headertemplate>
<itemtemplate>
<li class="span4 add-<%# ((Package)Container.DataItem).Text.Replace(" ","").ToLower() %>">
<div class="thumbnail" style="margin-right: 10px; height: 260px">
<img src="http://our.umbraco.org<%# ((Package)Container.DataItem).Thumbnail %>?width=170" alt="<%# ((Package)Container.DataItem).Text %>">
<h4><%# ((Package)Container.DataItem).Text %></h4>
<%# ((Package)Container.DataItem).Description %>
<a href="#" class="btn btn-success single-tab selectStarterKit" data-name="<%# ((Package)Container.DataItem).Text %>" title="Install <%# ((Package)Container.DataItem).Text %>" data-repoid="<%# ((Package)Container.DataItem).RepoGuid %>">
Install
</a>
</div>
</li>
</itemtemplate>
<footertemplate>
</ul>
<%--<asp:LinkButton runat="server" ID="declineStarterKits" CssClass="declineKit" OnClientClick="return confirm('Are you sure you do not want to install a starter kit?');" OnClick="NextStep">
No thanks, do not install a starterkit!
</asp:LinkButton>--%>
</footertemplate>
</asp:Repeater>
</asp:PlaceHolder>
<div id="connectionError" style="<%= CannotConnect ? "" : "display:none;" %>">
<div style="padding: 0 100px 13px 5px;">
<h2>Oops...the installer can't connect to the repository</h2>
Starter Kits could not be fetched from the repository as there was no connection - which can occur if you are using a proxy server or firewall with certain configurations,
or if you are not currently connected to the internet.
<br />
Click <strong>Continue</strong> to complete the installation then navigate to the Developer section of your Umbraco installation
where you will find the Starter Kits listed in the Packages tree.
</div>
<!-- btn box -->
<footer class="btn-box">
<div class="t">&nbsp;</div>
<asp:LinkButton ID="LinkButton1" class="btn-step btn btn-continue" runat="server" OnClick="GotoLastStep"><span>Continue</span></asp:LinkButton>
</footer>
</div>
<div id="serverError" style="display:none;">
<div style="padding: 0 100px 13px 5px;">
<h2>Oops...the installer encountered an error</h2>
<div class="error-message"></div>
</div>
<!-- btn box -->
<footer class="btn-box">
<div class="t">&nbsp;</div>
<asp:LinkButton ID="LinkButton2" class="btn-step btn btn-continue" runat="server" OnClick="GotoLastStep"><span>Continue</span></asp:LinkButton>
</footer>
</div>

View File

@@ -150,7 +150,7 @@
<key alias="releaseDate">Udgivelsesdato</key>
<key alias="unpublishDate">Dato for Fortryd udgivelse</key>
<key alias="removeDate">Fjern dato</key>
<key alias="sortDone">Sorteringrækkefølgen er opdateret</key>
<key alias="sortDone">Sorteringsrækkefølgen er opdateret</key>
<key alias="sortHelp">For at sortere, træk siderne eller klik på en af kolonnehovederne. Du kan vælge flere sider ved at holde "shift" eller "control" nede mens du vælger.</key>
<key alias="statistics">Statistik</key>
<key alias="titleOptional">Titel (valgfri)</key>
@@ -184,7 +184,7 @@
<key alias="updateData">Vælg en type og skriv en titel</key>
<key alias="noDocumentTypes" version="7.0"><![CDATA[Der kunne ikke findes nogen tilladte dokument typer. Du skal tillade disse i indstillinger under <strong>"dokument typer"</strong>.]]></key>
<key alias="noMediaTypes" version="7.0"><![CDATA[Der kunne ikke findes nogen tilladte media typer. Du skal tillade disse i indstillinger under <strong>"media typer"</strong>.]]></key>
<key alias="documentTypeWithoutTemplate">Dokument type uden skabelon</key>
<key alias="documentTypeWithoutTemplate">Dokumenttype uden skabelon</key>
<key alias="newFolder">Ny mappe</key>
<key alias="newDataType">Ny datatype</key>
</area>
@@ -320,6 +320,7 @@
<key alias="search">Søg...</key>
<key alias="filter">Filtrer...</key>
<key alias="enterTags">Indtast nøgleord (tryk på Enter efter hvert nøgleord)...</key>
<key alias="usernameHint">Dit brugernavn er typisk din e-mail adresse</key>
</area>
<area alias="editcontenttype">
<key alias="allowAtRoot" version="7.2">Tillad på rodniveau</key>
@@ -568,13 +569,13 @@
<key alias="permissionsAffectedFolders">Berørte filer og foldere</key>
<key alias="permissionsAffectedFoldersMoreInfo">Flere informationer om at opsætte rettigheder for Umbraco her</key>
<key alias="permissionsAffectedFoldersText">Du er nødt til at give ASP.NET 'modify' rettigheder på følgende filer/foldere</key>
<key alias="permissionsAlmostPerfect"><![CDATA[<strong>Dine rettighedsinstillinger er næsten perfekte!</strong><br/><br/>Du kan køre Umbraco uden problemer, men du vil ikke være i stand til at installere pakker, som er anbefalet for at få fuldt udbytte af Umbraco.]]></key>
<key alias="permissionsAlmostPerfect"><![CDATA[<strong>Dine rettighedsindstillinger er næsten perfekte!</strong><br/><br/>Du kan køre Umbraco uden problemer, men du vil ikke være i stand til at installere pakker, som er anbefalet for at få fuldt udbytte af Umbraco.]]></key>
<key alias="permissionsHowtoResolve">Hvorledes besluttes</key>
<key alias="permissionsHowtoResolveLink">Klik her for at læse tekstversionen</key>
<key alias="permissionsHowtoResolveText"><![CDATA[Se vores <strong>video tutorials</strong> om at opsætte folderrettigheder for Umbraco eller læs tekstversionen.]]></key>
<key alias="permissionsMaybeAnIssue"><![CDATA[<strong>Dine rettighedsinstillinger kan være et problem!</strong><br/><br/>Du kan afvikle Umbraco uden problemer, men du vil ikke være i stand til at oprette foldere eller installere pakker, hvilket er anbefalet for at få fuldt udbytte af Umbraco.]]></key>
<key alias="permissionsNotReady"><![CDATA[<strong>Dine rettighedsinstillinger er ikke klar til Umbraco!</strong><br/><br/>For at afvikle Umbraco er du nødt til at opdatere dine rettighedsinstillinger.]]></key>
<key alias="permissionsPerfect"><![CDATA[<strong>Dine rettighedsinstillinger er perfekte!</strong><br/><br/>Du er nu parat til at afvikle Umbraco og installere pakker!]]></key>
<key alias="permissionsMaybeAnIssue"><![CDATA[<strong>Dine rettighedsindstillinger kan være et problem!</strong><br/><br/>Du kan afvikle Umbraco uden problemer, men du vil ikke være i stand til at oprette foldere eller installere pakker, hvilket er anbefalet for at få fuldt udbytte af Umbraco.]]></key>
<key alias="permissionsNotReady"><![CDATA[<strong>Dine rettighedsindstillinger er ikke klar til Umbraco!</strong><br/><br/>For at afvikle Umbraco er du nødt til at opdatere dine rettighedsindstillinger.]]></key>
<key alias="permissionsPerfect"><![CDATA[<strong>Dine rettighedsindstillinger er perfekte!</strong><br/><br/>Du er nu parat til at afvikle Umbraco og installere pakker!]]></key>
<key alias="permissionsResolveFolderIssues">Løser folder problem</key>
<key alias="permissionsResolveFolderIssuesLink">Følg dette link for mere information om udfordringer med ASP.NET og oprettelse af foldere</key>
<key alias="permissionsSettingUpPermissions">Sætter folderrettigheder op</key>
@@ -586,7 +587,7 @@
<key alias="runwayInstalledText"><![CDATA[Du har fundamentet på plads. Vælg hvilke moduler du ønsker at installere ovenpå det.<br/>Dette er vores liste over anbefalede moduler. Kryds dem af du ønsker at installere eller se den <a href="#" onclick="toggleModules(); return false;" id="toggleModuleList">fulde liste af moduler</a> ]]></key>
<key alias="runwayOnlyProUsers">Kun anbefalet for erfarne brugere</key>
<key alias="runwaySimpleSite">Jeg ønsker at begynder med et simpelt website</key>
<key alias="runwaySimpleSiteText"><![CDATA[<p>"Runway" er et simpelt website som stiller nogle basale dokumenttyper og skabeloner til rådighed. Instaleringsprogrammet kan automatisk opsætte Runway for dig, men du kan nemt redigere, udvide eller fjerne det. Det er ikke nødvendigt og du kan sagtens bruge Umbraco uden. Men Runway tilbyder et fundament, som er baseret på 'Best Practices', som får dig igang hurtigere end nogensinde før. Hvis du vælger at installere Runway, kan du efter eget valg vælge de grundlæggende byggesten kaldet 'Runway Modules' til at forbedre dine Runway-sider.</p><p><small><em>Inkluderet med Runway:</em>Home Page, Getting Started page, Installing Modules page.<br /> <em>Valgfri Moduler:</em> Top Navigation, Sitemap, Contact, Gallery. </small></p>]]></key>
<key alias="runwaySimpleSiteText"><![CDATA[<p>"Runway" er et simpelt website som stiller nogle basale dokumenttyper og skabeloner til rådighed. Installeringsprogrammet kan automatisk opsætte Runway for dig, men du kan nemt redigere, udvide eller fjerne det. Det er ikke nødvendigt og du kan sagtens bruge Umbraco uden. Men Runway tilbyder et fundament, som er baseret på 'Best Practices', som får dig igang hurtigere end nogensinde før. Hvis du vælger at installere Runway, kan du efter eget valg vælge de grundlæggende byggesten kaldet 'Runway Modules' til at forbedre dine Runway-sider.</p><p><small><em>Inkluderet med Runway:</em>Home Page, Getting Started page, Installing Modules page.<br /> <em>Valgfri Moduler:</em> Top Navigation, Sitemap, Contact, Gallery. </small></p>]]></key>
<key alias="runwayWhatIsRunway">Hvad er Runway</key>
<key alias="step1">Skridt 1/5: Acceptér licens</key>
<key alias="step2">Skridt 2/5: Database-konfiguration</key>
@@ -703,7 +704,7 @@ Mange hilsner fra Umbraco robotten
<key alias="packageRepository">Pakke opbevaringsbase</key>
<key alias="packageUninstallConfirm">Bekræft af-installering</key>
<key alias="packageUninstalledHeader">Pakken blev fjernet</key>
<key alias="packageUninstalledText">Pakken er på succefuld vis blevet fjernet</key>
<key alias="packageUninstalledText">Pakken er på succesfuld vis blevet fjernet</key>
<key alias="packageUninstallHeader">Afinstallér pakke</key>
<key alias="packageUninstallText">
<![CDATA[Du kan fjerne markeringen på elementer du ikke ønsker at fjerne, på dette tidspunkt, nedenfor. Når du klikker 'bekræft' vil alle afkrydsede elemenet blive fjernet <br/>
@@ -784,7 +785,7 @@ Mange hilsner fra Umbraco robotten
<key alias="addRows">Tilføj række</key>
<key alias="addElement">Tilføj indhold</key>
<key alias="dropElement">Slip indhold</key>
<key alias="settingsApplied">Instillinger tilføjet</key>
<key alias="settingsApplied">Indstillinger tilføjet</key>
<key alias="contentNotAllowed">Indholdet er ikke tilladt her</key>
<key alias="contentAllowed">Indholdet er tilladt her</key>
@@ -929,7 +930,7 @@ Mange hilsner fra Umbraco robotten
<key alias="tab">Faneblad</key>
<key alias="tabname">Titel på faneblad</key>
<key alias="tabs">Faneblade</key>
<key alias="masterDocumentType">Master Dokument Type</key>
<key alias="masterDocumentType">Master Dokumenttype</key>
<key alias="createMatchingTemplate">Opret matchende skabelon</key>
</area>
<area alias="sort">

View File

@@ -278,6 +278,7 @@
<key alias="search">Durchsuchen ...</key>
<key alias="filter">Filtern ...</key>
<key alias="enterTags">Tippen, um Tags hinzuzufügen (nach jedem Tag die Eingabetaste drücken) ...</key>
<key alias="usernameHint">Der Benutzername ist normalerweise Ihre E-Mail-Adresse</key>
</area>
<area alias="editcontenttype">
<key alias="allowAtRoot" version="7.2">Auf oberster Ebene erlauben</key>

View File

@@ -339,6 +339,7 @@
<key alias="filter">Type to filter...</key>
<key alias="enterTags">Type to add tags (press enter after each tag)...</key>
<key alias="email">Enter your email</key>
<key alias="usernameHint">Your username is usually your email</key>
</area>
<area alias="editcontenttype">
<key alias="allowAtRoot" version="7.2">Allow at root</key>
@@ -1257,6 +1258,8 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="userPermissions">User Permissions</key>
<key alias="userTypes">User Types</key>
<key alias="users">Users</key>
<key alias="partialViews">Partial Views</key>
<key alias="partialViewMacros">Partial View Macro Files</key>
</area>
<area alias="update">
<key alias="updateAvailable">New update ready</key>

View File

@@ -1443,4 +1443,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="enabledConfirm">URL tracker has now been enabled.</key>
<key alias="enableError">Error enabling the URL tracker, more information can be found in your log file.</key>
</area>
<area alias="emptyStates">
<key alias="emptyDictionaryTree">No Dictionary items to choose from</key>
</area>
</language>

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