Compare commits
115 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| add2f57397 | |||
| cd3c17d73f | |||
| fe6d783222 | |||
| fc8b0f1822 | |||
| 6102c970c8 | |||
| 29903058a9 | |||
| b3940dea1b | |||
| 3dac630d05 | |||
| 10108d75b8 | |||
| 24cb64579b | |||
| 86239cc777 | |||
| 685aea1728 | |||
| eb4e041682 | |||
| 477aa754b3 | |||
| 48bff0aa6c | |||
| 4ea9fec9e2 | |||
| f3a965841b | |||
| 08ddb5f4c4 | |||
| 4ec63ffd0d | |||
| 4cb3e82972 | |||
| 0a20741f39 | |||
| 4575748f16 | |||
| 028ee831b8 | |||
| 54981cd57c | |||
| 0aab8cacaa | |||
| 15b4d33e00 | |||
| 367ba5cddf | |||
| ff64efbcdf | |||
| 5bc0c499d8 | |||
| f667318b58 | |||
| 87c9d15ad5 | |||
| 127736d188 | |||
| 139ab8d4df | |||
| 4abb8035b8 | |||
| 0ca1807d64 | |||
| 5ae90d201c | |||
| 6c416009d7 | |||
| 50da9bcb50 | |||
| 9e6a2d8a7c | |||
| cfb84cae44 | |||
| 4239833713 | |||
| 4fa1a3948e | |||
| 1b78e854f0 | |||
| c62a2362d2 | |||
| eb1855fcb7 | |||
| d4863239cd | |||
| 4b7ddb9c15 | |||
| e5bb35b335 | |||
| 7eabd09b3a | |||
| 087f0c0ede | |||
| db9d6d9109 | |||
| 700e180522 | |||
| 8584997f5f | |||
| 4710b3b641 | |||
| 227e2489c1 | |||
| 91a5b19378 | |||
| 4c20441c4e | |||
| edfe1e6d54 | |||
| 7869f77704 | |||
| 34fd405bca | |||
| f03ee9f908 | |||
| b053638204 | |||
| d790194682 | |||
| 3fec2b9756 | |||
| bc7a31d791 | |||
| 05d84c6673 | |||
| f6645e3928 | |||
| 50b00b12b0 | |||
| 569371ffff | |||
| f7b72b225a | |||
| d1bed54cf1 | |||
| ba868887d4 | |||
| 3a7853dcbe | |||
| 60af7deacd | |||
| 49bc3151b0 | |||
| d6b7bae38a | |||
| 715cc22722 | |||
| 88b23e09b6 | |||
| 612484c0b6 | |||
| 0e4974babe | |||
| 5fdd7d8bd6 | |||
| b5c87ccfb7 | |||
| 2efe6ae7a4 | |||
| 5775984730 | |||
| cbab70fd7c | |||
| cfa2a30006 | |||
| 09a3b0d155 | |||
| ca9cd77ded | |||
| 812601217a | |||
| 3a6ec5ef0c | |||
| 4197a7654f | |||
| 3133014650 | |||
| 4bce945946 | |||
| 2d15c9c01c | |||
| 58e648828b | |||
| d87b268a40 | |||
| 5174645059 | |||
| e4286bc35b | |||
| cf4d13da31 | |||
| a89b064e29 | |||
| 1e41973eb5 | |||
| b4e496fceb | |||
| bb94fc7d71 | |||
| 959378c456 | |||
| 787e128d5c | |||
| b7912a7be7 | |||
| 0bc7aa6ba7 | |||
| 367da39bbb | |||
| 6d8ffb903f | |||
| 0e992f897f | |||
| 3f19878c18 | |||
| 308f64a7e2 | |||
| 1eab92b299 | |||
| 7a8b8f138f | |||
| 926ea54c39 |
@@ -15,9 +15,8 @@
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[4.0.40804.0,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[5.2.3,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.3,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.1" />
|
||||
<dependency id="Microsoft.Net.Http" version="[2.2.29, 3.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.1, 3.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Security.Cookies" version="[3.0.1, 4.0.0)" />
|
||||
@@ -30,13 +29,15 @@
|
||||
<dependency id="MySql.Data" version="[6.9.7, 7.0.0)" />
|
||||
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.8.4, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc" version="[1.8.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.0.0, 3.1.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 7.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.66, 1.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.68, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[1.9.5, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[3.3.1, 5.0.0)" />
|
||||
<dependency id="semver" version="[1.1.2, 2.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebHelpers" version="[3.2.3, 4.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebPages.Data" version="[3.2.3, 4.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
<file src="tools\Dashboard.config.install.xdt" target="Content\config\Dashboard.config.install.xdt" />
|
||||
<file src="tools\trees.config.install.xdt" target="Content\config\trees.config.install.xdt" />
|
||||
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
|
||||
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" />
|
||||
<file src="build\**" target="build" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
|
||||
<configSections>
|
||||
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
xdt:Locator="Match(name)"
|
||||
xdt:Transform="SetAttributes(type)">
|
||||
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
xdt:Locator="Match(name)"
|
||||
xdt:Transform="SetAttributes(type)" />
|
||||
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
xdt:Locator="Match(name)"
|
||||
xdt:Transform="SetAttributes(type)" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
|
||||
<system.web.webPages.razor>
|
||||
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
xdt:Locator="Match(factoryType)"
|
||||
xdt:Transform="SetAttributes(factoryType)" />
|
||||
</system.web.webPages.razor>
|
||||
|
||||
<system.web>
|
||||
<pages
|
||||
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
xdt:Locator="Match(pageParserFilterType,pageBaseType,userControlBaseType)"
|
||||
xdt:Transform="SetAttributes(pageParserFilterType,pageBaseType,userControlBaseType)">
|
||||
<controls>
|
||||
<add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc"
|
||||
xdt:Locator="Match(namespace)"
|
||||
xdt:Transform="SetAttributes(assembly)" />
|
||||
</controls>
|
||||
</pages>
|
||||
</system.web>
|
||||
|
||||
</configuration>
|
||||
@@ -51,6 +51,8 @@
|
||||
<system.web xdt:Transform="InsertIfMissing" />
|
||||
<system.web>
|
||||
<siteMap xdt:Transform="Remove" />
|
||||
<httpRuntime xdt:Transform="InsertIfMissing" />
|
||||
<httpRuntime targetFramework="4.5" xdt:Transform="SetAttributes(targetFramework)" />
|
||||
<membership defaultProvider="DefaultMembershipProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove" />
|
||||
<roleManager defaultProvider="DefaultRoleProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>
|
||||
<profile defaultProvider="DefaultProfileProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>>
|
||||
|
||||
@@ -58,6 +58,7 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\ImageProcessor.Web.dll) { Remove-Item $umbracoBinFolder\ImageProcessor.Web.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Lucene.Net.dll) { Remove-Item $umbracoBinFolder\Lucene.Net.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Web.Infrastructure.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Infrastructure.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Web.Helpers.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Helpers.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Web.Mvc.FixedDisplayModes.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Mvc.FixedDisplayModes.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\MiniProfiler.dll) { Remove-Item $umbracoBinFolder\MiniProfiler.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\MySql.Data.dll) { Remove-Item $umbracoBinFolder\MySql.Data.dll -Force -Confirm:$false }
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.3.0
|
||||
beta2
|
||||
RC
|
||||
+1
-1
@@ -12,4 +12,4 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.3.0-beta2")]
|
||||
[assembly: AssemblyInformationalVersion("7.3.0-RC")]
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return "beta2"; } }
|
||||
public static string CurrentComment { get { return "RC"; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -159,15 +159,16 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
protected virtual ServiceContext CreateServiceContext(DatabaseContext dbContext, IDatabaseFactory dbFactory)
|
||||
{
|
||||
//default transient factory
|
||||
var msgFactory = new TransientMessagesFactory();
|
||||
return new ServiceContext(
|
||||
new RepositoryFactory(ApplicationCache, ProfilingLogger.Logger, dbContext.SqlSyntax, UmbracoConfig.For.UmbracoSettings()),
|
||||
new PetaPocoUnitOfWorkProvider(dbFactory),
|
||||
new FileUnitOfWorkProvider(),
|
||||
new PublishingStrategy(),
|
||||
new PublishingStrategy(msgFactory, ProfilingLogger.Logger),
|
||||
ApplicationCache,
|
||||
ProfilingLogger.Logger,
|
||||
//default transient factory
|
||||
new TransientMessagesFactory());
|
||||
msgFactory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -379,14 +380,19 @@ namespace Umbraco.Core
|
||||
if (ApplicationContext.IsConfigured == false) return;
|
||||
if (ApplicationContext.DatabaseContext.IsDatabaseConfigured == false) return;
|
||||
|
||||
//try now
|
||||
if (ApplicationContext.DatabaseContext.CanConnect)
|
||||
return;
|
||||
|
||||
var currentTry = 0;
|
||||
while (currentTry < 5)
|
||||
{
|
||||
//first wait, then retry
|
||||
Thread.Sleep(1000);
|
||||
|
||||
if (ApplicationContext.DatabaseContext.CanConnect)
|
||||
break;
|
||||
|
||||
//wait and retry
|
||||
Thread.Sleep(1000);
|
||||
currentTry++;
|
||||
}
|
||||
|
||||
@@ -394,7 +400,6 @@ namespace Umbraco.Core
|
||||
{
|
||||
throw new UmbracoStartupFailedException("Umbraco cannot start. A connection string is configured but the Umbraco cannot connect to the database.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static class DelegateExtensions
|
||||
{
|
||||
public static Attempt<T> RetryUntilSuccessOrTimeout<T>(this Func<Attempt<T>> task, TimeSpan timeout, TimeSpan pause)
|
||||
{
|
||||
if (pause.TotalMilliseconds < 0)
|
||||
{
|
||||
throw new ArgumentException("pause must be >= 0 milliseconds");
|
||||
}
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
do
|
||||
{
|
||||
var result = task();
|
||||
if (result) { return result; }
|
||||
Thread.Sleep((int)pause.TotalMilliseconds);
|
||||
}
|
||||
while (stopwatch.Elapsed < timeout);
|
||||
return Attempt<T>.Fail();
|
||||
}
|
||||
|
||||
public static Attempt<T> RetryUntilSuccessOrMaxAttempts<T>(this Func<int, Attempt<T>> task, int totalAttempts, TimeSpan pause)
|
||||
{
|
||||
if (pause.TotalMilliseconds < 0)
|
||||
{
|
||||
throw new ArgumentException("pause must be >= 0 milliseconds");
|
||||
}
|
||||
int attempts = 0;
|
||||
do
|
||||
{
|
||||
attempts++;
|
||||
var result = task(attempts);
|
||||
if (result) { return result; }
|
||||
Thread.Sleep((int)pause.TotalMilliseconds);
|
||||
}
|
||||
while (attempts < totalAttempts);
|
||||
return Attempt<T>.Fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,17 @@ namespace Umbraco.Core.Events
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// if this instance supports cancellation, this will set Cancel to true with an affiliated cancellation message
|
||||
/// </summary>
|
||||
/// <param name="cancelationMessage"></param>
|
||||
public void CancelOperation(EventMessage cancelationMessage)
|
||||
{
|
||||
Cancel = true;
|
||||
cancelationMessage.IsDefaultEventMessage = true;
|
||||
Messages.Add(cancelationMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the EventMessages object which is used to add messages to the message collection for this event
|
||||
/// </summary>
|
||||
|
||||
@@ -4,12 +4,56 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
public class DeleteEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the delete operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
public DeleteEventArgs(IEnumerable<TEntity> eventObject, bool canCancel) : base(eventObject, canCancel)
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the delete operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public DeleteEventArgs(IEnumerable<TEntity> eventObject, bool canCancel, EventMessages eventMessages) : base(eventObject, canCancel, eventMessages)
|
||||
{
|
||||
MediaFilesToDelete = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the delete operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public DeleteEventArgs(IEnumerable<TEntity> eventObject, EventMessages eventMessages) : base(eventObject, eventMessages)
|
||||
{
|
||||
MediaFilesToDelete = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a single entity instance
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public DeleteEventArgs(TEntity eventObject, EventMessages eventMessages)
|
||||
: base(new List<TEntity> { eventObject }, eventMessages)
|
||||
{
|
||||
MediaFilesToDelete = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a single entity instance
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public DeleteEventArgs(TEntity eventObject, bool canCancel, EventMessages eventMessages)
|
||||
: base(new List<TEntity> { eventObject }, canCancel, eventMessages)
|
||||
{
|
||||
MediaFilesToDelete = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the delete operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
public DeleteEventArgs(IEnumerable<TEntity> eventObject, bool canCancel) : base(eventObject, canCancel)
|
||||
{
|
||||
MediaFilesToDelete = new List<string>();
|
||||
}
|
||||
@@ -60,7 +104,13 @@ namespace Umbraco.Core.Events
|
||||
|
||||
public class DeleteEventArgs : CancellableEventArgs
|
||||
{
|
||||
public DeleteEventArgs(int id, bool canCancel)
|
||||
public DeleteEventArgs(int id, bool canCancel, EventMessages eventMessages)
|
||||
: base(canCancel, eventMessages)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public DeleteEventArgs(int id, bool canCancel)
|
||||
: base(canCancel)
|
||||
{
|
||||
Id = id;
|
||||
|
||||
@@ -8,34 +8,6 @@ namespace Umbraco.Core.Events
|
||||
/// </summary>
|
||||
public static class EventExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Raises the event and checks if a cancelation has occurred, if so it checks if any messages have been
|
||||
/// added to the event messages collection and if not it adds a default cancelation message
|
||||
/// </summary>
|
||||
/// <typeparam name="TSender"></typeparam>
|
||||
/// <typeparam name="TArgs"></typeparam>
|
||||
/// <param name="eventHandler"></param>
|
||||
/// <param name="evtMsgs"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <param name="sender"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsRaisedEventCancelled<TSender, TArgs>(
|
||||
this TypedEventHandler<TSender, TArgs> eventHandler,
|
||||
EventMessages evtMsgs,
|
||||
Func<EventMessages, TArgs> args,
|
||||
TSender sender)
|
||||
where TArgs : CancellableEventArgs
|
||||
{
|
||||
var evtArgs = args(evtMsgs);
|
||||
|
||||
if (eventHandler != null)
|
||||
{
|
||||
eventHandler(sender, evtArgs);
|
||||
}
|
||||
|
||||
return evtArgs.Cancel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the event and returns a boolean value indicating if the event was cancelled
|
||||
/// </summary>
|
||||
@@ -56,30 +28,7 @@ namespace Umbraco.Core.Events
|
||||
|
||||
return args.Cancel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the event with EventMessages
|
||||
/// </summary>
|
||||
/// <typeparam name="TSender"></typeparam>
|
||||
/// <typeparam name="TArgs"></typeparam>
|
||||
/// <param name="eventHandler"></param>
|
||||
/// <param name="evtMsgs"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <param name="sender"></param>
|
||||
public static void RaiseEvent<TSender, TArgs>(
|
||||
this TypedEventHandler<TSender, TArgs> eventHandler,
|
||||
EventMessages evtMsgs,
|
||||
Func<EventMessages, TArgs> args,
|
||||
TSender sender)
|
||||
where TArgs : EventArgs
|
||||
{
|
||||
if (eventHandler != null)
|
||||
{
|
||||
var evtArgs = args(evtMsgs);
|
||||
eventHandler(sender, evtArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Raises the event
|
||||
/// </summary>
|
||||
|
||||
@@ -18,5 +18,10 @@ namespace Umbraco.Core.Events
|
||||
public string Category { get; private set; }
|
||||
public string Message { get; private set; }
|
||||
public EventMessageType MessageType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is used to track if this message should be used as a default message so that Umbraco doesn't also append it's own default messages
|
||||
/// </summary>
|
||||
internal bool IsDefaultEventMessage { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,49 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
public class MoveEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor accepting a collection of MoveEventInfo objects
|
||||
/// </summary>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
/// <param name="moveInfo">
|
||||
/// A colleciton of MoveEventInfo objects that exposes all entities that have been moved during a single move operation
|
||||
/// </param>
|
||||
public MoveEventArgs(bool canCancel, EventMessages eventMessages, params MoveEventInfo<TEntity>[] moveInfo)
|
||||
: base(default(TEntity), canCancel, eventMessages)
|
||||
{
|
||||
if (moveInfo.FirstOrDefault() == null)
|
||||
{
|
||||
throw new ArgumentException("moveInfo argument must contain at least one item");
|
||||
}
|
||||
|
||||
MoveInfoCollection = moveInfo;
|
||||
//assign the legacy props
|
||||
EventObject = moveInfo.First().Entity;
|
||||
ParentId = moveInfo.First().NewParentId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a collection of MoveEventInfo objects
|
||||
/// </summary>
|
||||
/// <param name="eventMessages"></param>
|
||||
/// <param name="moveInfo">
|
||||
/// A colleciton of MoveEventInfo objects that exposes all entities that have been moved during a single move operation
|
||||
/// </param>
|
||||
public MoveEventArgs(EventMessages eventMessages, params MoveEventInfo<TEntity>[] moveInfo)
|
||||
: base(default(TEntity), eventMessages)
|
||||
{
|
||||
if (moveInfo.FirstOrDefault() == null)
|
||||
{
|
||||
throw new ArgumentException("moveInfo argument must contain at least one item");
|
||||
}
|
||||
|
||||
MoveInfoCollection = moveInfo;
|
||||
//assign the legacy props
|
||||
EventObject = moveInfo.First().Entity;
|
||||
ParentId = moveInfo.First().NewParentId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a collection of MoveEventInfo objects
|
||||
/// </summary>
|
||||
|
||||
@@ -4,6 +4,52 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
public class PublishEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the publish operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="isAllPublished"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public PublishEventArgs(IEnumerable<TEntity> eventObject, bool canCancel, bool isAllPublished, EventMessages eventMessages)
|
||||
: base(eventObject, canCancel, eventMessages)
|
||||
{
|
||||
IsAllRepublished = isAllPublished;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the publish operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public PublishEventArgs(IEnumerable<TEntity> eventObject, EventMessages eventMessages)
|
||||
: base(eventObject, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a single entity instance
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public PublishEventArgs(TEntity eventObject, EventMessages eventMessages)
|
||||
: base(new List<TEntity> { eventObject }, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a single entity instance
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="isAllPublished"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public PublishEventArgs(TEntity eventObject, bool canCancel, bool isAllPublished, EventMessages eventMessages)
|
||||
: base(new List<TEntity> { eventObject }, canCancel, eventMessages)
|
||||
{
|
||||
IsAllRepublished = isAllPublished;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the publish operation
|
||||
/// </summary>
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace Umbraco.Core.Logging
|
||||
private CancellationTokenSource _loggingCancelationTokenSource;
|
||||
private CancellationToken _loggingCancelationToken;
|
||||
private Task _loggingTask;
|
||||
private Double _shutdownFlushTimeout = 5;
|
||||
private TimeSpan _shutdownFlushTimespan = TimeSpan.FromSeconds(5);
|
||||
private Double _shutdownFlushTimeout = 1;
|
||||
private TimeSpan _shutdownFlushTimespan = TimeSpan.FromSeconds(1);
|
||||
private static readonly Type ThisType = typeof(ParallelForwardingAppender);
|
||||
private volatile bool _shutDownRequested;
|
||||
private int? _bufferSize = DefaultBufferSize;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -140,11 +141,22 @@ namespace Umbraco.Core.Manifest
|
||||
{
|
||||
var result = new List<PackageManifest>();
|
||||
foreach (var m in manifestFileContents)
|
||||
{
|
||||
if (m.IsNullOrWhiteSpace()) continue;
|
||||
{
|
||||
var manifestContent = m;
|
||||
|
||||
if (manifestContent.IsNullOrWhiteSpace()) continue;
|
||||
|
||||
// Strip byte object marker, JSON.NET does not like it
|
||||
var preamble = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
|
||||
|
||||
// Strangely StartsWith(preamble) would always return true
|
||||
if (manifestContent.Substring(0, 1) == preamble)
|
||||
manifestContent = manifestContent.Remove(0, preamble.Length);
|
||||
|
||||
if (manifestContent.IsNullOrWhiteSpace()) continue;
|
||||
|
||||
//remove any comments first
|
||||
var replaced = CommentsSurround.Replace(m, match => " ");
|
||||
var replaced = CommentsSurround.Replace(manifestContent, match => " ");
|
||||
replaced = CommentsLine.Replace(replaced, match => "");
|
||||
|
||||
JObject deserialized;
|
||||
@@ -154,7 +166,7 @@ namespace Umbraco.Core.Manifest
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<ManifestParser>("An error occurred parsing manifest with contents: " + m, ex);
|
||||
LogHelper.Error<ManifestParser>("An error occurred parsing manifest with contents: " + manifestContent, ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -95,13 +95,7 @@ namespace Umbraco.Core.Models
|
||||
[DataMember]
|
||||
public virtual ITemplate Template
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_template == null)
|
||||
return _contentType.DefaultTemplate;
|
||||
|
||||
return _template;
|
||||
}
|
||||
get { return _template; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
|
||||
@@ -8,5 +8,10 @@ namespace Umbraco.Core.Models
|
||||
string DomainName { get; set; }
|
||||
int? RootContentId { get; set; }
|
||||
bool IsWildcard { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Readonly value of the language ISO code for the domain
|
||||
/// </summary>
|
||||
string LanguageIsoCode { get; }
|
||||
}
|
||||
}
|
||||
@@ -23,5 +23,11 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
|
||||
[Column("domainName")]
|
||||
public string DomainName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used for a result on the query to get the associated language for a domain if there is one
|
||||
/// </summary>
|
||||
[ResultColumn("languageISOCode")]
|
||||
public string IsoCode { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Models
|
||||
public class Stylesheet : File
|
||||
{
|
||||
public Stylesheet(string path)
|
||||
: base(path)
|
||||
: base(path.EnsureEndsWith(".css"))
|
||||
{
|
||||
InitializeProperties();
|
||||
}
|
||||
|
||||
@@ -14,6 +14,12 @@ namespace Umbraco.Core.Models
|
||||
_domainName = domainName;
|
||||
}
|
||||
|
||||
public UmbracoDomain(string domainName, string languageIsoCode)
|
||||
: this(domainName)
|
||||
{
|
||||
LanguageIsoCode = languageIsoCode;
|
||||
}
|
||||
|
||||
private int? _contentId;
|
||||
private int? _languageId;
|
||||
private string _domainName;
|
||||
@@ -70,9 +76,9 @@ namespace Umbraco.Core.Models
|
||||
get { return string.IsNullOrWhiteSpace(DomainName) || DomainName.StartsWith("*"); }
|
||||
}
|
||||
|
||||
public string IsoCode
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// Readonly value of the language ISO code for the domain
|
||||
/// </summary>
|
||||
public string LanguageIsoCode { get; internal set; }
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
@@ -75,8 +76,10 @@ namespace Umbraco.Core.Persistence
|
||||
connection.Open();
|
||||
connection.Close();
|
||||
}
|
||||
catch (DbException)
|
||||
catch (DbException exc)
|
||||
{
|
||||
// Don't swallow this error, the exception is super handy for knowing "why" its not available
|
||||
LogHelper.WarnWithException<IDbConnection>("Configured database is reporting as not being available!", exc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,12 +43,8 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
Path = dto.NodeDto.Path
|
||||
};
|
||||
|
||||
if (childDefinitions.Any(x => x.ParentId == dto.NodeId))
|
||||
{
|
||||
template.IsMasterTemplate = true;
|
||||
}
|
||||
template.IsMasterTemplate = childDefinitions.Any(x => x.ParentId == dto.NodeId);
|
||||
|
||||
//TODO: Change this to ParentId: http://issues.umbraco.org/issue/U4-5846
|
||||
if(dto.NodeDto.ParentId > 0)
|
||||
template.MasterTemplateId = new Lazy<int>(() => dto.NodeDto.ParentId);
|
||||
|
||||
|
||||
+18
-1
@@ -30,9 +30,26 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe
|
||||
.NonClustered()
|
||||
.WithOptions()
|
||||
.Unique();
|
||||
|
||||
//now we need to fill in the data so that it is consistent, we can't have it generating random GUIDs for
|
||||
// the already existing data, see: http://issues.umbraco.org/issue/U4-6942
|
||||
|
||||
foreach (var data in Context.Database.Query<dynamic>(@"
|
||||
SELECT cmsPropertyType.id ptId, cmsPropertyType.Alias ptAlias, cmsContentType.alias ctAlias
|
||||
FROM cmsPropertyType
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsPropertyType.contentTypeId = cmsContentType.nodeId"))
|
||||
{
|
||||
//create a guid from the concatenation of the property type alias + the doc type alias
|
||||
string concatAlias = data.ptAlias + data.ctAlias;
|
||||
var ptGuid = concatAlias.ToGuid();
|
||||
|
||||
//set the Unique Id to the one we've generated
|
||||
Update.Table("cmsPropertyType").Set(new {uniqueID = ptGuid}).Where(new {id = data.ptId });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
|
||||
@@ -340,6 +340,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
((Content)entity).AddingEntity();
|
||||
|
||||
//ensure the default template is assigned
|
||||
if (entity.Template == null)
|
||||
{
|
||||
entity.Template = entity.ContentType.DefaultTemplate;
|
||||
}
|
||||
|
||||
//Ensure unique name on the same level
|
||||
entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name);
|
||||
|
||||
@@ -648,8 +654,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var translator = new SqlTranslator<IContent>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.Where<DocumentDto>(x => x.Published)
|
||||
.OrderBy<NodeDto>(x => x.Level)
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
.OrderBy<NodeDto>(x => x.Level, SqlSyntax)
|
||||
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
|
||||
|
||||
//NOTE: This doesn't allow properties to be part of the query
|
||||
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(sql);
|
||||
@@ -855,7 +861,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <summary>
|
||||
/// Private method to create a content object from a DocumentDto, which is used by Get and GetByVersion.
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="contentType"></param>
|
||||
/// <param name="template"></param>
|
||||
/// <param name="propCollection"></param>
|
||||
@@ -873,6 +879,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
content.Template = template ?? _templateRepository.Get(dto.TemplateId.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
//ensure there isn't one set.
|
||||
content.Template = null;
|
||||
}
|
||||
|
||||
content.Properties = propCollection;
|
||||
|
||||
@@ -885,7 +896,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <summary>
|
||||
/// Private method to create a content object from a DocumentDto, which is used by Get and GetByVersion.
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="versionId"></param>
|
||||
/// <param name="docSql"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
@@ -713,7 +713,7 @@ AND umbracoNode.id <> @id",
|
||||
var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
AllowedTypes.allowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
ParentTypes.parentContentTypeId as chtParentId,
|
||||
ParentTypes.parentContentTypeId as chtParentId, ParentTypes.parentContentTypeKey as chtParentKey,
|
||||
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
|
||||
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
|
||||
umbracoNode.uniqueID as nUniqueId
|
||||
@@ -727,7 +727,12 @@ AND umbracoNode.id <> @id",
|
||||
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
|
||||
) AllowedTypes
|
||||
ON AllowedTypes.Id = cmsContentType.nodeId
|
||||
LEFT JOIN cmsContentType2ContentType as ParentTypes
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentType2ContentType.parentContentTypeId, umbracoNode.uniqueID AS parentContentTypeKey, cmsContentType2ContentType.childContentTypeId
|
||||
FROM cmsContentType2ContentType
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)";
|
||||
|
||||
@@ -842,7 +847,7 @@ AND umbracoNode.id <> @id",
|
||||
cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
AllowedTypes.allowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
ParentTypes.parentContentTypeId as chtParentId,
|
||||
ParentTypes.parentContentTypeId as chtParentId,ParentTypes.parentContentTypeKey as chtParentKey,
|
||||
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
|
||||
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
|
||||
umbracoNode.uniqueID as nUniqueId,
|
||||
@@ -865,7 +870,12 @@ AND umbracoNode.id <> @id",
|
||||
ON cmsTemplate.nodeId = umbracoNode.id
|
||||
) as Template
|
||||
ON Template.nodeId = cmsDocumentType.templateNodeId
|
||||
LEFT JOIN cmsContentType2ContentType as ParentTypes
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentType2ContentType.parentContentTypeId, umbracoNode.uniqueID AS parentContentTypeKey, cmsContentType2ContentType.childContentTypeId
|
||||
FROM cmsContentType2ContentType
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)";
|
||||
|
||||
@@ -1043,7 +1053,14 @@ AND umbracoNode.id <> @id",
|
||||
? x.ctId == currentCtId
|
||||
: x.nUniqueId == currentCtId;
|
||||
})
|
||||
.Select(x => (TId?)x.chtParentId)
|
||||
.Select(x =>
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof(TId) == typeof(int))
|
||||
? (TId?)x.chtParentId
|
||||
: (TId?)x.chtParentKey;
|
||||
})
|
||||
.Where(x => x.HasValue)
|
||||
.Distinct()
|
||||
.Select(x => x.Value).ToList());
|
||||
|
||||
@@ -14,6 +14,8 @@ using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
//TODO: We need to get a readonly ISO code for the domain assigned
|
||||
|
||||
internal class DomainRepository : PetaPocoRepositoryBase<int, IDomain>, IDomainRepository
|
||||
{
|
||||
private readonly RepositoryCacheOptions _cacheOptions;
|
||||
@@ -62,7 +64,18 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
var sql = new Sql();
|
||||
sql.Select(isCount ? "COUNT(*)" : "*").From<DomainDto>(SqlSyntax);
|
||||
if (isCount)
|
||||
{
|
||||
sql.Select("COUNT(*)").From<DomainDto>(SqlSyntax);
|
||||
}
|
||||
else
|
||||
{
|
||||
sql.Select("umbracoDomains.*, umbracoLanguage.languageISOCode")
|
||||
.From<DomainDto>(SqlSyntax)
|
||||
.LeftJoin<LanguageDto>(SqlSyntax)
|
||||
.On<DomainDto, LanguageDto>(SqlSyntax, dto => dto.DefaultLanguage, dto => dto.Id);
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -110,6 +123,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var id = Convert.ToInt32(Database.Insert(dto));
|
||||
entity.Id = id;
|
||||
|
||||
//if the language changed, we need to resolve the ISO code!
|
||||
if (entity.LanguageId.HasValue)
|
||||
{
|
||||
((UmbracoDomain)entity).LanguageIsoCode = Database.ExecuteScalar<string>("SELECT languageISOCode FROM umbracoLanguage WHERE id=@langId", new { langId = entity.LanguageId });
|
||||
}
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
@@ -139,6 +158,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
Database.Update(dto);
|
||||
|
||||
//if the language changed, we need to resolve the ISO code!
|
||||
if (entity.WasPropertyDirty("LanguageId"))
|
||||
{
|
||||
((UmbracoDomain)entity).LanguageIsoCode = Database.ExecuteScalar<string>("SELECT languageISOCode FROM umbracoLanguage WHERE id=@langId", new {langId = entity.LanguageId});
|
||||
}
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
@@ -176,7 +201,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
public IDomain BuildEntity(DomainDto dto)
|
||||
{
|
||||
var domain = new UmbracoDomain(dto.DomainName) { Id = dto.Id, LanguageId = dto.DefaultLanguage, RootContentId = dto.RootStructureId };
|
||||
var domain = new UmbracoDomain(dto.DomainName, dto.IsoCode)
|
||||
{
|
||||
Id = dto.Id,
|
||||
LanguageId = dto.DefaultLanguage,
|
||||
RootContentId = dto.RootStructureId
|
||||
};
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
domain.ResetDirtyProperties(false);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
@@ -10,12 +11,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
IEnumerable<ITemplate> GetAll(params string[] aliases);
|
||||
|
||||
IEnumerable<ITemplate> GetChildren(int masterTemplateId);
|
||||
IEnumerable<ITemplate> GetChildren(string alias);
|
||||
|
||||
IEnumerable<ITemplate> GetDescendants(int masterTemplateId);
|
||||
IEnumerable<ITemplate> GetDescendants(string alias);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a template as a template node which can be traversed (parent, children)
|
||||
/// </summary>
|
||||
/// <param name="alias"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use GetDescendants instead")]
|
||||
TemplateNode GetTemplateNode(string alias);
|
||||
|
||||
/// <summary>
|
||||
@@ -24,6 +30,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <param name="anyNode"></param>
|
||||
/// <param name="alias"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use GetDescendants instead")]
|
||||
TemplateNode FindTemplateInTree(TemplateNode anyNode, string alias);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
public override Stylesheet Get(string id)
|
||||
{
|
||||
id = id.EnsureEndsWith(".css");
|
||||
|
||||
if (FileSystem.FileExists(id) == false)
|
||||
{
|
||||
return null;
|
||||
@@ -63,7 +65,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public override IEnumerable<Stylesheet> GetAll(params string[] ids)
|
||||
{
|
||||
//ensure they are de-duplicated, easy win if people don't do this as this can cause many excess queries
|
||||
ids = ids.Distinct().ToArray();
|
||||
ids = ids
|
||||
.Select(x => x.EnsureEndsWith(".css"))
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
if (ids.Any())
|
||||
{
|
||||
|
||||
@@ -477,7 +477,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
tagSetSql,
|
||||
" inner join cmsTags as NewTags on (TagSet.Tag = NewTags.Tag and TagSet.",
|
||||
SqlSyntax.GetQuotedColumnName("group"),
|
||||
" = TagSet.",
|
||||
" = NewTags.",
|
||||
SqlSyntax.GetQuotedColumnName("group"),
|
||||
") ",
|
||||
") as NewTagsSet ",
|
||||
|
||||
@@ -67,7 +67,15 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override ITemplate PerformGet(int id)
|
||||
{
|
||||
return GetAll(new[] { id }).FirstOrDefault();
|
||||
var sql = GetBaseQuery(false).Where<TemplateDto>(x => x.NodeId == id);
|
||||
var result = Database.Fetch<TemplateDto, NodeDto>(sql).FirstOrDefault();
|
||||
if (result == null) return null;
|
||||
|
||||
//look up the simple template definitions that have a master template assigned, this is used
|
||||
// later to populate the template item's properties
|
||||
var childIds = GetAxisDefinitions(result).ToArray();
|
||||
|
||||
return MapFromDto(result, childIds);
|
||||
}
|
||||
|
||||
protected override IEnumerable<ITemplate> PerformGetAll(params int[] ids)
|
||||
@@ -89,20 +97,15 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//look up the simple template definitions that have a master template assigned, this is used
|
||||
// later to populate the template item's properties
|
||||
var childIdsSql = new Sql()
|
||||
.Select("nodeId,alias,parentID")
|
||||
.From<TemplateDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<TemplateDto, NodeDto>(dto => dto.NodeId, dto => dto.NodeId)
|
||||
.Where<NodeDto>(t => t.ParentId > 0);
|
||||
var childIds = Database.Fetch<dynamic>(childIdsSql)
|
||||
.Select(x => new UmbracoEntity
|
||||
var childIds = (ids.Any()
|
||||
? GetAxisDefinitions(dtos.ToArray())
|
||||
: dtos.Select(x => new UmbracoEntity
|
||||
{
|
||||
Id = x.nodeId,
|
||||
ParentId = x.parentID,
|
||||
Name = x.alias
|
||||
});
|
||||
|
||||
Id = x.NodeId,
|
||||
ParentId = x.NodeDto.ParentId,
|
||||
Name = x.Alias
|
||||
})).ToArray();
|
||||
|
||||
return dtos.Select(d => MapFromDto(d, childIds));
|
||||
}
|
||||
|
||||
@@ -118,19 +121,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//look up the simple template definitions that have a master template assigned, this is used
|
||||
// later to populate the template item's properties
|
||||
var childIdsSql = new Sql()
|
||||
.Select("nodeId,alias,parentID")
|
||||
.From<TemplateDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<TemplateDto, NodeDto>(dto => dto.NodeId, dto => dto.NodeId)
|
||||
.Where<NodeDto>(t => t.ParentId > 0);
|
||||
var childIds = Database.Fetch<dynamic>(childIdsSql)
|
||||
.Select(x => new UmbracoEntity
|
||||
{
|
||||
Id = x.nodeId,
|
||||
ParentId = x.parentID,
|
||||
Name = x.alias
|
||||
});
|
||||
var childIds = GetAxisDefinitions(dtos.ToArray()).ToArray();
|
||||
|
||||
return dtos.Select(d => MapFromDto(d, childIds));
|
||||
}
|
||||
@@ -143,9 +134,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = new Sql();
|
||||
sql.Select(isCount ? "COUNT(*)" : "*")
|
||||
.From<TemplateDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<TemplateDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.From<TemplateDto>(SqlSyntax)
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<TemplateDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
|
||||
return sql;
|
||||
}
|
||||
@@ -273,7 +264,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
Database.Update(dto.NodeDto);
|
||||
Database.Update(dto);
|
||||
|
||||
|
||||
//re-update if this is a master template, since it could have changed!
|
||||
var axisDefs = GetAxisDefinitions(dto);
|
||||
template.IsMasterTemplate = axisDefs.Any(x => x.ParentId == dto.NodeId);
|
||||
|
||||
//now do the file work
|
||||
|
||||
if (DetermineTemplateRenderingEngine(entity) == RenderingEngine.Mvc)
|
||||
@@ -304,34 +299,27 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override void PersistDeletedItem(ITemplate entity)
|
||||
{
|
||||
var deletes = GetDeleteClauses().ToArray();
|
||||
|
||||
//TODO: This isn't the most ideal way to delete a template tree, because below it will actually end up
|
||||
// recursing back to this method for each descendant and re-looking up the template list causing an extrac
|
||||
// SQL call - not ideal but there shouldn't ever be a heaping list of descendant templates.
|
||||
//The easiest way to overcome this is to expose the underlying cache upwards so that the repository has access
|
||||
// to it, then in the PersistDeletedTemplate we wouldn't recurse the underlying function, we'd just call
|
||||
// PersistDeletedItem with a Template object and clear it's cache.
|
||||
var descendants = GetDescendants(entity.Id).ToList();
|
||||
|
||||
var sql = GetBaseQuery(false).Where<NodeDto>(dto => dto.ParentId > 0 || dto.NodeId == entity.Id);
|
||||
|
||||
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql);
|
||||
|
||||
var self = dtos.Single(x => x.NodeId == entity.Id);
|
||||
var allChildren = dtos.Except(new[] { self });
|
||||
var hierarchy = GenerateTemplateHierarchy(self, allChildren);
|
||||
//remove ourselves
|
||||
hierarchy.Remove(self);
|
||||
//change the order so it goes bottom up!
|
||||
hierarchy.Reverse();
|
||||
//change the order so it goes bottom up! (deepest level first)
|
||||
descendants.Reverse();
|
||||
|
||||
//delete the hierarchy
|
||||
foreach (var descendant in hierarchy)
|
||||
foreach (var descendant in descendants)
|
||||
{
|
||||
PersistDeletedTemplate(descendant);
|
||||
foreach (var delete in deletes)
|
||||
{
|
||||
Database.Execute(delete, new { Id = GetEntityId(descendant) });
|
||||
}
|
||||
}
|
||||
|
||||
//now we can delete this one
|
||||
base.PersistDeletedItem(entity);
|
||||
foreach (var delete in deletes)
|
||||
{
|
||||
Database.Execute(delete, new { Id = GetEntityId(entity) });
|
||||
}
|
||||
|
||||
if (DetermineTemplateRenderingEngine(entity) == RenderingEngine.Mvc)
|
||||
{
|
||||
@@ -342,28 +330,57 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var masterpageName = string.Concat(entity.Alias, ".master");
|
||||
_masterpagesFileSystem.DeleteFile(masterpageName);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private ITemplate MapFromDto(TemplateDto dto, IEnumerable<IUmbracoEntity> childDefinitions)
|
||||
private IEnumerable<IUmbracoEntity> GetAxisDefinitions(params TemplateDto[] templates)
|
||||
{
|
||||
//look up the simple template definitions that have a master template assigned, this is used
|
||||
// later to populate the template item's properties
|
||||
var childIdsSql = new Sql()
|
||||
.Select("nodeId,alias,parentID")
|
||||
.From<TemplateDto>(SqlSyntax)
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<TemplateDto, NodeDto>(SqlSyntax, dto => dto.NodeId, dto => dto.NodeId)
|
||||
//lookup axis's
|
||||
.Where("umbracoNode." + SqlSyntax.GetQuotedColumnName("id") + " IN (@parentIds) OR umbracoNode.parentID IN (@childIds)",
|
||||
new {parentIds = templates.Select(x => x.NodeDto.ParentId), childIds = templates.Select(x => x.NodeId)});
|
||||
|
||||
var childIds = Database.Fetch<dynamic>(childIdsSql)
|
||||
.Select(x => new UmbracoEntity
|
||||
{
|
||||
Id = x.nodeId,
|
||||
ParentId = x.parentID,
|
||||
Name = x.alias
|
||||
});
|
||||
return childIds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps from a dto to an ITemplate
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <param name="axisDefinitions">
|
||||
/// This is a collection of template definitions ... either all templates, or the collection of child templates and it's parent template
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
private ITemplate MapFromDto(TemplateDto dto, IUmbracoEntity[] axisDefinitions)
|
||||
{
|
||||
string csViewName = string.Concat(dto.Alias, ".cshtml");
|
||||
string vbViewName = string.Concat(dto.Alias, ".vbhtml");
|
||||
string masterpageName = string.Concat(dto.Alias, ".master");
|
||||
|
||||
var factory = new TemplateFactory();
|
||||
var template = factory.BuildEntity(dto, childDefinitions);
|
||||
var template = factory.BuildEntity(dto, axisDefinitions);
|
||||
|
||||
if (dto.NodeDto.ParentId > 0)
|
||||
{
|
||||
//TODO: Fix this n+1 query!
|
||||
var masterTemplate = Get(dto.NodeDto.ParentId);
|
||||
var masterTemplate = axisDefinitions.FirstOrDefault(x => x.Id == dto.NodeDto.ParentId);
|
||||
if (masterTemplate != null)
|
||||
{
|
||||
template.MasterTemplateAlias = masterTemplate.Alias;
|
||||
template.MasterTemplateAlias = masterTemplate.Name;
|
||||
template.MasterTemplateId = new Lazy<int>(() => dto.NodeDto.ParentId);
|
||||
}
|
||||
}
|
||||
@@ -390,36 +407,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
private void PersistDeletedTemplate(TemplateDto dto)
|
||||
{
|
||||
//we need to get the real template for this item unfortunately to remove it
|
||||
var template = Get(dto.NodeId);
|
||||
if (template != null)
|
||||
{
|
||||
//NOTE: We must cast here so that it goes to the outter method to
|
||||
// ensure the cache is updated.
|
||||
PersistDeletedItem((IEntity)template);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of templates in order of descendants from the parent
|
||||
/// </summary>
|
||||
/// <param name="template"></param>
|
||||
/// <param name="allChildTemplates"></param>
|
||||
/// <returns></returns>
|
||||
private static List<TemplateDto> GenerateTemplateHierarchy(TemplateDto template, IEnumerable<TemplateDto> allChildTemplates)
|
||||
{
|
||||
var hierarchy = new List<TemplateDto> { template };
|
||||
foreach (var t in allChildTemplates.Where(x => x.NodeDto.ParentId == template.NodeId))
|
||||
{
|
||||
hierarchy.AddRange(GenerateTemplateHierarchy(t, allChildTemplates));
|
||||
}
|
||||
return hierarchy;
|
||||
}
|
||||
|
||||
|
||||
private void PopulateViewTemplate(ITemplate template, string fileName)
|
||||
{
|
||||
string content;
|
||||
@@ -460,49 +448,119 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
return Get(dto.NodeId);
|
||||
return MapFromDto(dto, GetAxisDefinitions(dto).ToArray());
|
||||
}
|
||||
|
||||
public IEnumerable<ITemplate> GetAll(params string[] aliases)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
|
||||
if (aliases.Any())
|
||||
{
|
||||
foreach (var id in aliases)
|
||||
{
|
||||
yield return Get(id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var nodeDtos = Database.Fetch<NodeDto>("WHERE nodeObjectType = @NodeObjectType", new { NodeObjectType = NodeObjectTypeId });
|
||||
foreach (var nodeDto in nodeDtos)
|
||||
{
|
||||
yield return Get(nodeDto.NodeId);
|
||||
}
|
||||
sql.Where("cmsTemplate.alias IN (@aliases)", new {aliases = aliases});
|
||||
}
|
||||
|
||||
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
|
||||
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
|
||||
|
||||
var axisDefos = GetAxisDefinitions(dtos).ToArray();
|
||||
return dtos.Select(x => MapFromDto(x, axisDefos));
|
||||
}
|
||||
|
||||
public IEnumerable<ITemplate> GetChildren(int masterTemplateId)
|
||||
{
|
||||
//TODO: Fix this N+1!
|
||||
|
||||
List<TemplateDto> found;
|
||||
if (masterTemplateId == -1)
|
||||
var sql = GetBaseQuery(false);
|
||||
if (masterTemplateId <= 0)
|
||||
{
|
||||
var sql = GetBaseQuery(false).Where<NodeDto>(x => x.ParentId <= 0);
|
||||
found = Database.Fetch<TemplateDto, NodeDto>(sql);
|
||||
sql.Where<NodeDto>(x => x.ParentId <= 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sql = GetBaseQuery(false).Where<NodeDto>(x => x.ParentId == masterTemplateId);
|
||||
found = Database.Fetch<TemplateDto, NodeDto>(sql);
|
||||
sql.Where<NodeDto>(x => x.ParentId == masterTemplateId);
|
||||
}
|
||||
|
||||
foreach (var templateDto in found)
|
||||
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
|
||||
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
|
||||
|
||||
var axisDefos = GetAxisDefinitions(dtos).ToArray();
|
||||
return dtos.Select(x => MapFromDto(x, axisDefos));
|
||||
}
|
||||
|
||||
public IEnumerable<ITemplate> GetChildren(string alias)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
if (alias.IsNullOrWhiteSpace())
|
||||
{
|
||||
yield return Get(templateDto.NodeId);
|
||||
sql.Where<NodeDto>(x => x.ParentId <= 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
//unfortunately SQLCE doesn't support scalar subqueries in the where clause, otherwise we could have done this
|
||||
// in a single query, now we have to lookup the path to acheive the same thing
|
||||
var parent = Database.ExecuteScalar<int?>(new Sql().Select("nodeId").From<TemplateDto>(SqlSyntax).Where<TemplateDto>(dto => dto.Alias == alias));
|
||||
if (parent.HasValue == false) return Enumerable.Empty<ITemplate>();
|
||||
|
||||
sql.Where<NodeDto>(x => x.ParentId == parent.Value);
|
||||
}
|
||||
|
||||
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
|
||||
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
|
||||
|
||||
var axisDefos = GetAxisDefinitions(dtos).ToArray();
|
||||
return dtos.Select(x => MapFromDto(x, axisDefos));
|
||||
}
|
||||
|
||||
public IEnumerable<ITemplate> GetDescendants(int masterTemplateId)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
if (masterTemplateId > 0)
|
||||
{
|
||||
//unfortunately SQLCE doesn't support scalar subqueries in the where clause, otherwise we could have done this
|
||||
// in a single query, now we have to lookup the path to acheive the same thing
|
||||
var path = Database.ExecuteScalar<string>(
|
||||
new Sql().Select(SqlSyntax.GetQuotedColumnName("path"))
|
||||
.From<TemplateDto>(SqlSyntax)
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<TemplateDto, NodeDto>(SqlSyntax, dto => dto.NodeId, dto => dto.NodeId)
|
||||
.Where<NodeDto>(dto => dto.NodeId == masterTemplateId));
|
||||
|
||||
if (path.IsNullOrWhiteSpace()) return Enumerable.Empty<ITemplate>();
|
||||
|
||||
sql.Where(@"(umbracoNode." + SqlSyntax.GetQuotedColumnName("path") + @" LIKE @query)", new { query = path + ",%" });
|
||||
}
|
||||
|
||||
sql.OrderBy("umbracoNode." + SqlSyntax.GetQuotedColumnName("level"));
|
||||
|
||||
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
|
||||
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
|
||||
|
||||
var axisDefos = GetAxisDefinitions(dtos).ToArray();
|
||||
return dtos.Select(x => MapFromDto(x, axisDefos));
|
||||
|
||||
}
|
||||
|
||||
public IEnumerable<ITemplate> GetDescendants(string alias)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
if (alias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
//unfortunately SQLCE doesn't support scalar subqueries in the where clause, otherwise we could have done this
|
||||
// in a single query, now we have to lookup the path to acheive the same thing
|
||||
var path = Database.ExecuteScalar<string>(
|
||||
"SELECT umbracoNode.path FROM cmsTemplate INNER JOIN umbracoNode ON cmsTemplate.nodeId = umbracoNode.id WHERE cmsTemplate.alias = @alias", new { alias = alias });
|
||||
|
||||
if (path.IsNullOrWhiteSpace()) return Enumerable.Empty<ITemplate>();
|
||||
|
||||
sql.Where(@"(umbracoNode." + SqlSyntax.GetQuotedColumnName("path") + @" LIKE @query)", new {query = path + ",%" });
|
||||
}
|
||||
|
||||
sql.OrderBy("umbracoNode." + SqlSyntax.GetQuotedColumnName("level"));
|
||||
|
||||
var dtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
|
||||
if (dtos.Length == 0) return Enumerable.Empty<ITemplate>();
|
||||
|
||||
var axisDefos = GetAxisDefinitions(dtos).ToArray();
|
||||
return dtos.Select(x => MapFromDto(x, axisDefos));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -510,13 +568,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </summary>
|
||||
/// <param name="alias"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use GetDescendants instead")]
|
||||
public TemplateNode GetTemplateNode(string alias)
|
||||
{
|
||||
//in order to do this we need to get all of the templates and then organize,
|
||||
// TODO: unfortunately our db structure does not use the path correctly for templates so we cannot just look
|
||||
// up a template tree easily.
|
||||
//TODO: We do use the 'path' now, so this might be able to be fixed up
|
||||
|
||||
{
|
||||
//first get all template objects
|
||||
var allTemplates = GetAll().ToArray();
|
||||
|
||||
@@ -525,23 +579,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//then we need to get all template Dto's because those contain the master property
|
||||
var sql = GetBaseQuery(false);
|
||||
var allDtos = Database.Fetch<TemplateDto, NodeDto>(sql).ToArray();
|
||||
var selfDto = allDtos.Single(x => x.NodeId == selfTemplate.Id);
|
||||
|
||||
//need to get the top-most node of the current tree
|
||||
var top = selfDto;
|
||||
while (top.NodeDto.ParentId > 0)
|
||||
|
||||
var top = selfTemplate;
|
||||
while (top.MasterTemplateAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
top = allDtos.Single(x => x.NodeId == top.NodeDto.ParentId);
|
||||
top = allTemplates.Single(x => x.Alias == top.MasterTemplateAlias);
|
||||
}
|
||||
|
||||
var topNode = new TemplateNode(allTemplates.Single(x => x.Id == top.NodeId));
|
||||
var childIds = allDtos.Where(x => x.NodeDto.ParentId == top.NodeId).Select(x => x.NodeId);
|
||||
var topNode = new TemplateNode(allTemplates.Single(x => x.Id == top.Id));
|
||||
var childTemplates = allTemplates.Where(x => x.MasterTemplateAlias == top.Alias);
|
||||
//This now creates the hierarchy recursively
|
||||
topNode.Children = CreateChildren(topNode, childIds, allTemplates, allDtos);
|
||||
topNode.Children = CreateChildren(topNode, childTemplates, allTemplates);
|
||||
|
||||
//now we'll return the TemplateNode requested
|
||||
return FindTemplateInTree(topNode, alias);
|
||||
@@ -568,6 +616,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <param name="anyNode"></param>
|
||||
/// <param name="alias"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use GetDescendants instead")]
|
||||
public TemplateNode FindTemplateInTree(TemplateNode anyNode, string alias)
|
||||
{
|
||||
//first get the root
|
||||
@@ -658,12 +707,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return validFile && validExtension;
|
||||
}
|
||||
|
||||
private static IEnumerable<TemplateNode> CreateChildren(TemplateNode parent, IEnumerable<int> childIds, ITemplate[] allTemplates, TemplateDto[] allDtos)
|
||||
private static IEnumerable<TemplateNode> CreateChildren(TemplateNode parent, IEnumerable<ITemplate> childTemplates, ITemplate[] allTemplates)
|
||||
{
|
||||
var children = new List<TemplateNode>();
|
||||
foreach (var i in childIds)
|
||||
foreach (var childTemplate in childTemplates)
|
||||
{
|
||||
var template = allTemplates.Single(x => x.Id == i);
|
||||
var template = allTemplates.Single(x => x.Id == childTemplate.Id);
|
||||
var child = new TemplateNode(template)
|
||||
{
|
||||
Parent = parent
|
||||
@@ -673,10 +722,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
children.Add(child);
|
||||
|
||||
//get this node's children
|
||||
var kids = allDtos.Where(x => x.NodeDto.ParentId == i).Select(x => x.NodeId).ToArray();
|
||||
var local = childTemplate;
|
||||
var kids = allTemplates.Where(x => x.MasterTemplateAlias == local.Alias);
|
||||
|
||||
//recurse
|
||||
child.Children = CreateChildren(child, kids, allTemplates, allDtos);
|
||||
child.Children = CreateChildren(child, kids, allTemplates);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
@@ -41,14 +41,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
.From<ContentVersionDto>()
|
||||
.InnerJoin<ContentDto>()
|
||||
.On<ContentVersionDto, ContentDto>(left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.From<ContentVersionDto>(SqlSyntax)
|
||||
.InnerJoin<ContentDto>(SqlSyntax)
|
||||
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
|
||||
.Where<NodeDto>(x => x.NodeId == id)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
|
||||
var dtos = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sql);
|
||||
foreach (var dto in dtos)
|
||||
@@ -513,6 +513,8 @@ WHERE EXISTS(
|
||||
// of ContentItemBasic instances) to the database field names.
|
||||
switch (orderBy.ToUpperInvariant())
|
||||
{
|
||||
case "UPDATEDATE":
|
||||
return "cmsContentVersion.VersionDate";
|
||||
case "NAME":
|
||||
return "umbracoNode.text";
|
||||
case "OWNER":
|
||||
|
||||
@@ -38,9 +38,9 @@ using System.Security.Permissions;
|
||||
[assembly: InternalsVisibleTo("UmbracoExamine")]
|
||||
|
||||
[assembly: InternalsVisibleTo("Concorde.Sync")]
|
||||
[assembly: InternalsVisibleTo("Umbraco.Belle")]
|
||||
[assembly: InternalsVisibleTo("Umbraco.VisualStudio")]
|
||||
[assembly: InternalsVisibleTo("Umbraco.Courier.Core")]
|
||||
[assembly: InternalsVisibleTo("Umbraco.Courier.Persistence")]
|
||||
[assembly: InternalsVisibleTo("umbraco.providers")]
|
||||
|
||||
//allow this to be mocked in our unit tests
|
||||
|
||||
@@ -1,36 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Publishing
|
||||
{
|
||||
/// <summary>
|
||||
/// The result of publishing a content item
|
||||
/// </summary>
|
||||
public class PublishStatus
|
||||
public class PublishStatus : OperationStatus<IContent, PublishStatusType>
|
||||
{
|
||||
public PublishStatus()
|
||||
{
|
||||
//initialize
|
||||
InvalidProperties = new List<Property>();
|
||||
}
|
||||
|
||||
public PublishStatus(IContent content, PublishStatusType statusType)
|
||||
: this()
|
||||
{
|
||||
ContentItem = content;
|
||||
StatusType = statusType;
|
||||
public PublishStatus(IContent content, PublishStatusType statusType, EventMessages eventMessages)
|
||||
: base(content, statusType, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful publish status
|
||||
/// </summary>
|
||||
public PublishStatus(IContent content)
|
||||
: this(content, PublishStatusType.Success)
|
||||
public PublishStatus(IContent content, EventMessages eventMessages)
|
||||
: this(content, PublishStatusType.Success, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
public IContent ContentItem { get; private set; }
|
||||
public PublishStatusType StatusType { get; internal set; }
|
||||
public IContent ContentItem
|
||||
{
|
||||
get { return Entity; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets sets the invalid properties if the status failed due to validation.
|
||||
|
||||
@@ -5,6 +5,7 @@ using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Publishing
|
||||
{
|
||||
@@ -14,6 +15,16 @@ namespace Umbraco.Core.Publishing
|
||||
/// </summary>
|
||||
public class PublishingStrategy : BasePublishingStrategy
|
||||
{
|
||||
private readonly IEventMessagesFactory _eventMessagesFactory;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public PublishingStrategy(IEventMessagesFactory eventMessagesFactory, ILogger logger)
|
||||
{
|
||||
if (eventMessagesFactory == null) throw new ArgumentNullException("eventMessagesFactory");
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
_eventMessagesFactory = eventMessagesFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Publishes a single piece of Content
|
||||
@@ -22,48 +33,50 @@ namespace Umbraco.Core.Publishing
|
||||
/// <param name="userId">Id of the User issueing the publish operation</param>
|
||||
internal Attempt<PublishStatus> PublishInternal(IContent content, int userId)
|
||||
{
|
||||
if (Publishing.IsRaisedEventCancelled(new PublishEventArgs<IContent>(content), this))
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
|
||||
if (Publishing.IsRaisedEventCancelled(
|
||||
new PublishEventArgs<IContent>(content, evtMsgs), this))
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published, the event was cancelled.", content.Name, content.Id));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
|
||||
//Check if the Content is Expired to verify that it can in fact be published
|
||||
if (content.Status == ContentStatus.Expired)
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has expired and could not be published.",
|
||||
content.Name, content.Id));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedHasExpired));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedHasExpired, evtMsgs));
|
||||
}
|
||||
|
||||
//Check if the Content is Awaiting Release to verify that it can in fact be published
|
||||
if (content.Status == ContentStatus.AwaitingRelease)
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' is awaiting release and could not be published.",
|
||||
content.Name, content.Id));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedAwaitingRelease));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedAwaitingRelease, evtMsgs));
|
||||
}
|
||||
|
||||
//Check if the Content is Trashed to verify that it can in fact be published
|
||||
if (content.Status == ContentStatus.Trashed)
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' is trashed and could not be published.",
|
||||
content.Name, content.Id));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedIsTrashed));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedIsTrashed, evtMsgs));
|
||||
}
|
||||
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has been published.",
|
||||
content.Name, content.Id));
|
||||
|
||||
return Attempt.Succeed(new PublishStatus(content));
|
||||
return Attempt.Succeed(new PublishStatus(content, evtMsgs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -122,11 +135,13 @@ namespace Umbraco.Core.Publishing
|
||||
// much difference because we iterate over them all anyways?? Morten?
|
||||
// Because we're grouping I think this will execute all the queries anyways so need to fetch it all first.
|
||||
var fetchedContent = content.ToArray();
|
||||
|
||||
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
|
||||
//We're going to populate the statuses with all content that is already published because below we are only going to iterate over
|
||||
// content that is not published. We'll set the status to "AlreadyPublished"
|
||||
statuses.AddRange(fetchedContent.Where(x => x.Published)
|
||||
.Select(x => Attempt.Succeed(new PublishStatus(x, PublishStatusType.SuccessAlreadyPublished))));
|
||||
.Select(x => Attempt.Succeed(new PublishStatus(x, PublishStatusType.SuccessAlreadyPublished, evtMsgs))));
|
||||
|
||||
int? firstLevel = null;
|
||||
|
||||
@@ -138,7 +153,7 @@ namespace Umbraco.Core.Publishing
|
||||
//be published regardless of the rules mentioned in the remarks.
|
||||
if (!firstLevel.HasValue)
|
||||
{
|
||||
firstLevel = level.Key;
|
||||
firstLevel = level.Key;
|
||||
}
|
||||
|
||||
/* Only update content thats not already been published - we want to loop through
|
||||
@@ -149,7 +164,7 @@ namespace Umbraco.Core.Publishing
|
||||
//Check if this item should be excluded because it's parent's publishing has failed/cancelled
|
||||
if (parentsIdsCancelled.Contains(item.ParentId))
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published because it's parent's publishing action failed or was cancelled.", item.Name, item.Id));
|
||||
//if this cannot be published, ensure that it's children can definitely not either!
|
||||
parentsIdsCancelled.Add(item.Id);
|
||||
@@ -165,26 +180,27 @@ namespace Umbraco.Core.Publishing
|
||||
}
|
||||
|
||||
//Fire Publishing event
|
||||
if (Publishing.IsRaisedEventCancelled(new PublishEventArgs<IContent>(item), this))
|
||||
if (Publishing.IsRaisedEventCancelled(
|
||||
new PublishEventArgs<IContent>(item, evtMsgs), this))
|
||||
{
|
||||
//the publishing has been cancelled.
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published, the event was cancelled.", item.Name, item.Id));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedCancelledByEvent)));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedCancelledByEvent, evtMsgs)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//Check if the content is valid if the flag is set to check
|
||||
if (!item.IsValid())
|
||||
if (item.IsValid() == false)
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published because some of it's content is not passing validation rules.",
|
||||
item.Name, item.Id));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedContentInvalid)));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedContentInvalid, evtMsgs)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
@@ -195,24 +211,24 @@ namespace Umbraco.Core.Publishing
|
||||
//Check if the Content is Expired to verify that it can in fact be published
|
||||
if (item.Status == ContentStatus.Expired)
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has expired and could not be published.",
|
||||
item.Name, item.Id));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedHasExpired)));
|
||||
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedHasExpired, evtMsgs)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//Check if the Content is Awaiting Release to verify that it can in fact be published
|
||||
if (item.Status == ContentStatus.AwaitingRelease)
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' is awaiting release and could not be published.",
|
||||
item.Name, item.Id));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedAwaitingRelease)));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedAwaitingRelease, evtMsgs)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
@@ -223,10 +239,10 @@ namespace Umbraco.Core.Publishing
|
||||
//Check if the Content is Trashed to verify that it can in fact be published
|
||||
if (item.Status == ContentStatus.Trashed)
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' is trashed and could not be published.",
|
||||
item.Name, item.Id));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedIsTrashed)));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedIsTrashed, evtMsgs)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
@@ -236,13 +252,13 @@ namespace Umbraco.Core.Publishing
|
||||
|
||||
item.ChangePublishedState(PublishedState.Published);
|
||||
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has been published.",
|
||||
item.Name, item.Id));
|
||||
|
||||
statuses.Add(Attempt.Succeed(new PublishStatus(item)));
|
||||
statuses.Add(Attempt.Succeed(new PublishStatus(item, evtMsgs)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return statuses;
|
||||
@@ -263,7 +279,7 @@ namespace Umbraco.Core.Publishing
|
||||
//TODO: We're going back to the service layer here... not sure how to avoid this? And this will add extra overhead to
|
||||
// any document that fails to publish...
|
||||
var hasPublishedVersion = ApplicationContext.Current.Services.ContentService.HasPublishedVersion(content.Id);
|
||||
|
||||
|
||||
if (hasPublishedVersion && !includeUnpublishedDocuments)
|
||||
{
|
||||
//it has a published version but our flag tells us to not include un-published documents and therefore we should
|
||||
@@ -273,7 +289,7 @@ namespace Umbraco.Core.Publishing
|
||||
else if (!hasPublishedVersion)
|
||||
{
|
||||
//it doesn't have a published version so we certainly cannot publish it's children.
|
||||
parentsIdsCancelled.Add(content.Id);
|
||||
parentsIdsCancelled.Add(content.Id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,12 +342,15 @@ namespace Umbraco.Core.Publishing
|
||||
// if published != newest, then the published flags need to be reseted by whoever is calling that method
|
||||
// at the moment it's done by the content service
|
||||
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
|
||||
//Fire UnPublishing event
|
||||
if (UnPublishing.IsRaisedEventCancelled(new PublishEventArgs<IContent>(content), this))
|
||||
if (UnPublishing.IsRaisedEventCancelled(
|
||||
new PublishEventArgs<IContent>(content, evtMsgs), this))
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be unpublished, the event was cancelled.", content.Name, content.Id));
|
||||
return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent));
|
||||
return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
//If Content has a release date set to before now, it should be removed so it doesn't interrupt an unpublish
|
||||
@@ -340,7 +359,7 @@ namespace Umbraco.Core.Publishing
|
||||
{
|
||||
content.ReleaseDate = null;
|
||||
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' had its release date removed, because it was unpublished.",
|
||||
content.Name, content.Id));
|
||||
}
|
||||
@@ -349,11 +368,11 @@ namespace Umbraco.Core.Publishing
|
||||
if (content.Published)
|
||||
content.ChangePublishedState(PublishedState.Unpublished);
|
||||
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has been unpublished.",
|
||||
content.Name, content.Id));
|
||||
|
||||
return Attempt.Succeed(new PublishStatus(content));
|
||||
return Attempt.Succeed(new PublishStatus(content, evtMsgs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -385,7 +404,9 @@ namespace Umbraco.Core.Publishing
|
||||
/// <param name="content"><see cref="IContent"/> thats being published</param>
|
||||
public override void PublishingFinalized(IContent content)
|
||||
{
|
||||
Published.RaiseEvent(new PublishEventArgs<IContent>(content, false, false), this);
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
Published.RaiseEvent(
|
||||
new PublishEventArgs<IContent>(content, false, false, evtMsgs), this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -395,7 +416,9 @@ namespace Umbraco.Core.Publishing
|
||||
/// <param name="isAllRepublished">Boolean indicating whether its all content that is republished</param>
|
||||
public override void PublishingFinalized(IEnumerable<IContent> content, bool isAllRepublished)
|
||||
{
|
||||
Published.RaiseEvent(new PublishEventArgs<IContent>(content, false, isAllRepublished), this);
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
Published.RaiseEvent(
|
||||
new PublishEventArgs<IContent>(content, false, isAllRepublished, evtMsgs), this);
|
||||
|
||||
}
|
||||
|
||||
@@ -405,7 +428,9 @@ namespace Umbraco.Core.Publishing
|
||||
/// <param name="content"><see cref="IContent"/> thats being unpublished</param>
|
||||
public override void UnPublishingFinalized(IContent content)
|
||||
{
|
||||
UnPublished.RaiseEvent(new PublishEventArgs<IContent>(content, false, false), this);
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
UnPublished.RaiseEvent(
|
||||
new PublishEventArgs<IContent>(content, false, false, evtMsgs), this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -414,7 +439,9 @@ namespace Umbraco.Core.Publishing
|
||||
/// <param name="content">An enumerable list of <see cref="IContent"/> thats being unpublished</param>
|
||||
public override void UnPublishingFinalized(IEnumerable<IContent> content)
|
||||
{
|
||||
UnPublished.RaiseEvent(new PublishEventArgs<IContent>(content, false, false), this);
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
UnPublished.RaiseEvent(
|
||||
new PublishEventArgs<IContent>(content, false, false, evtMsgs), this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Publishing
|
||||
{
|
||||
/// <summary>
|
||||
/// The result of unpublishing a content item
|
||||
/// </summary>
|
||||
public class UnPublishStatus : OperationStatus<IContent, UnPublishedStatusType>
|
||||
{
|
||||
public UnPublishStatus(IContent content, UnPublishedStatusType statusType, EventMessages eventMessages)
|
||||
: base(content, statusType, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful unpublish status
|
||||
/// </summary>
|
||||
public UnPublishStatus(IContent content, EventMessages eventMessages)
|
||||
: this(content, UnPublishedStatusType.Success, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
public IContent ContentItem
|
||||
{
|
||||
get { return Entity; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace Umbraco.Core.Publishing
|
||||
{
|
||||
/// <summary>
|
||||
/// A status type of the result of unpublishing a content item
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Anything less than 10 = Success!
|
||||
/// </remarks>
|
||||
public enum UnPublishedStatusType
|
||||
{
|
||||
/// <summary>
|
||||
/// The unpublishing was successful.
|
||||
/// </summary>
|
||||
Success = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The item was already unpublished
|
||||
/// </summary>
|
||||
SuccessAlreadyUnPublished = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The publish action has been cancelled by an event handler
|
||||
/// </summary>
|
||||
FailedCancelledByEvent = 14,
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// Represents the Content Service, which is an easy access to operations involving <see cref="IContent"/>
|
||||
/// </summary>
|
||||
public class ContentService : RepositoryService, IContentService
|
||||
public class ContentService : RepositoryService, IContentService, IContentServiceOperations
|
||||
{
|
||||
private readonly IPublishingStrategy _publishingStrategy;
|
||||
private readonly EntityXmlSerializer _entitySerializer = new EntityXmlSerializer();
|
||||
@@ -38,18 +38,18 @@ namespace Umbraco.Core.Services
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
|
||||
|
||||
public ContentService(
|
||||
IDatabaseUnitOfWorkProvider provider,
|
||||
RepositoryFactory repositoryFactory,
|
||||
IDatabaseUnitOfWorkProvider provider,
|
||||
RepositoryFactory repositoryFactory,
|
||||
ILogger logger,
|
||||
IEventMessagesFactory eventMessagesFactory,
|
||||
IPublishingStrategy publishingStrategy,
|
||||
IDataTypeService dataTypeService,
|
||||
IPublishingStrategy publishingStrategy,
|
||||
IDataTypeService dataTypeService,
|
||||
IUserService userService)
|
||||
: base(provider, repositoryFactory, logger, eventMessagesFactory)
|
||||
{
|
||||
if (publishingStrategy == null) throw new ArgumentNullException("publishingStrategy");
|
||||
if (dataTypeService == null) throw new ArgumentNullException("dataTypeService");
|
||||
if (userService == null) throw new ArgumentNullException("userService");
|
||||
if (userService == null) throw new ArgumentNullException("userService");
|
||||
_publishingStrategy = publishingStrategy;
|
||||
_dataTypeService = dataTypeService;
|
||||
_userService = userService;
|
||||
@@ -747,7 +747,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether an <see cref="IContent"/> item has any children
|
||||
@@ -857,6 +857,110 @@ namespace Umbraco.Core.Services
|
||||
return result.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Publishes a <see cref="IContent"/> object and all its children
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to publish along with its children</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <param name="includeUnpublished"></param>
|
||||
/// <returns>The list of statuses for all published items</returns>
|
||||
IEnumerable<Attempt<PublishStatus>> IContentServiceOperations.PublishWithChildren(IContent content, int userId, bool includeUnpublished)
|
||||
{
|
||||
return PublishWithChildrenDo(content, userId, includeUnpublished);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves and Publishes a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to save and publish</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise save events.</param>
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
Attempt<PublishStatus> IContentServiceOperations.SaveAndPublish(IContent content, int userId, bool raiseEvents)
|
||||
{
|
||||
return SaveAndPublishDo(content, userId, raiseEvents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes an <see cref="IContent"/> object by moving it to the Recycle Bin
|
||||
/// </summary>
|
||||
/// <remarks>Move an item to the Recycle Bin will result in the item being unpublished</remarks>
|
||||
/// <param name="content">The <see cref="IContent"/> to delete</param>
|
||||
/// <param name="userId">Optional Id of the User deleting the Content</param>
|
||||
Attempt<OperationStatus> IContentServiceOperations.MoveToRecycleBin(IContent content, int userId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var originalPath = content.Path;
|
||||
|
||||
if (Trashing.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IContent>(evtMsgs, new MoveEventInfo<IContent>(content, originalPath, Constants.System.RecycleBinContent)),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
}
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IContent>>
|
||||
{
|
||||
new MoveEventInfo<IContent>(content, originalPath, Constants.System.RecycleBinContent)
|
||||
};
|
||||
|
||||
//Make sure that published content is unpublished before being moved to the Recycle Bin
|
||||
if (HasPublishedVersion(content.Id))
|
||||
{
|
||||
//TODO: this shouldn't be a 'sub operation', and if it needs to be it cannot raise events and cannot be cancelled!
|
||||
UnPublish(content, userId);
|
||||
}
|
||||
|
||||
//Unpublish descendents of the content item that is being moved to trash
|
||||
var descendants = GetDescendants(content).OrderBy(x => x.Level).ToList();
|
||||
foreach (var descendant in descendants)
|
||||
{
|
||||
//TODO: this shouldn't be a 'sub operation', and if it needs to be it cannot raise events and cannot be cancelled!
|
||||
UnPublish(descendant, userId);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(uow))
|
||||
{
|
||||
content.WriterId = userId;
|
||||
content.ChangeTrashedState(true);
|
||||
repository.AddOrUpdate(content);
|
||||
|
||||
//Loop through descendants to update their trash state, but ensuring structure by keeping the ParentId
|
||||
foreach (var descendant in descendants)
|
||||
{
|
||||
moveInfo.Add(new MoveEventInfo<IContent>(descendant, descendant.Path, descendant.ParentId));
|
||||
|
||||
descendant.WriterId = userId;
|
||||
descendant.ChangeTrashedState(true, descendant.ParentId);
|
||||
repository.AddOrUpdate(descendant);
|
||||
}
|
||||
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
Trashed.RaiseEvent(new MoveEventArgs<IContent>(false, evtMsgs, moveInfo.ToArray()), this);
|
||||
|
||||
Audit(AuditType.Move, "Move Content to Recycle Bin performed by user", userId, content.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UnPublishes a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to publish</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <returns>True if unpublishing succeeded, otherwise False</returns>
|
||||
Attempt<UnPublishStatus> IContentServiceOperations.UnPublish(IContent content, int userId)
|
||||
{
|
||||
return UnPublishDo(content, false, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Publishes a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
@@ -865,7 +969,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
public Attempt<PublishStatus> PublishWithStatus(IContent content, int userId = 0)
|
||||
{
|
||||
return SaveAndPublishDo(content, userId);
|
||||
return ((IContentServiceOperations)this).Publish(content, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -881,7 +985,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
//This used to just return false only when the parent content failed, otherwise would always return true so we'll
|
||||
// do the same thing for the moment
|
||||
if (!result.Any(x => x.Result.ContentItem.Id == content.Id))
|
||||
if (result.All(x => x.Result.ContentItem.Id != content.Id))
|
||||
return false;
|
||||
|
||||
return result.Single(x => x.Result.ContentItem.Id == content.Id).Success;
|
||||
@@ -896,7 +1000,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
public IEnumerable<Attempt<PublishStatus>> PublishWithChildrenWithStatus(IContent content, int userId = 0, bool includeUnpublished = false)
|
||||
{
|
||||
return PublishWithChildrenDo(content, userId, includeUnpublished);
|
||||
return ((IContentServiceOperations)this).PublishWithChildren(content, userId, includeUnpublished);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -907,7 +1011,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>True if unpublishing succeeded, otherwise False</returns>
|
||||
public bool UnPublish(IContent content, int userId = 0)
|
||||
{
|
||||
return UnPublishDo(content, false, userId);
|
||||
return ((IContentServiceOperations) this).UnPublish(content, userId).Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -933,7 +1037,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
public Attempt<PublishStatus> SaveAndPublishWithStatus(IContent content, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
return SaveAndPublishDo(content, userId, raiseEvents);
|
||||
return ((IContentServiceOperations)this).SaveAndPublish(content, userId, raiseEvents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -942,9 +1046,9 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="content">The <see cref="IContent"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the Content</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
public Attempt<OperationStatus> SaveWithStatus(IContent content, int userId = 0, bool raiseEvents = true)
|
||||
public void Save(IContent content, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
return Save(content, true, userId, raiseEvents);
|
||||
((IContentServiceOperations)this).Save(content, userId, raiseEvents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -953,18 +1057,19 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="contents">Collection of <see cref="IContent"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the Content</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
public Attempt<OperationStatus> SaveWithStatus(IEnumerable<IContent> contents, int userId = 0, bool raiseEvents = true)
|
||||
Attempt<OperationStatus> IContentServiceOperations.Save(IEnumerable<IContent> contents, int userId, bool raiseEvents)
|
||||
{
|
||||
var asArray = contents.ToArray();
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(
|
||||
EventMessagesFactory.Get(),
|
||||
messages => new SaveEventArgs<IContent>(asArray, messages),
|
||||
new SaveEventArgs<IContent>(asArray, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled);
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
}
|
||||
}
|
||||
using (new WriteLock(Locker))
|
||||
@@ -1004,23 +1109,88 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
Saved.RaiseEvent(EventMessagesFactory.Get(), messages => new SaveEventArgs<IContent>(asArray, false, messages), this);
|
||||
Saved.RaiseEvent(new SaveEventArgs<IContent>(asArray, false, evtMsgs), this);
|
||||
|
||||
Audit(AuditType.Save, "Bulk Save content performed by user", userId == -1 ? 0 : userId, Constants.System.Root);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success);
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Permanently deletes an <see cref="IContent"/> object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method will also delete associated media files, child content and possibly associated domains.
|
||||
/// </remarks>
|
||||
/// <remarks>Please note that this method will completely remove the Content from the database</remarks>
|
||||
/// <param name="content">The <see cref="IContent"/> to delete</param>
|
||||
/// <param name="userId">Optional Id of the User deleting the Content</param>
|
||||
Attempt<OperationStatus> IContentServiceOperations.Delete(IContent content, int userId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
if (Deleting.IsRaisedEventCancelled(
|
||||
new DeleteEventArgs<IContent>(content, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
}
|
||||
|
||||
//Make sure that published content is unpublished before being deleted
|
||||
if (HasPublishedVersion(content.Id))
|
||||
{
|
||||
UnPublish(content, userId);
|
||||
}
|
||||
|
||||
//Delete children before deleting the 'possible parent'
|
||||
var children = GetChildren(content.Id);
|
||||
foreach (var child in children)
|
||||
{
|
||||
Delete(child, userId);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(uow))
|
||||
{
|
||||
repository.Delete(content);
|
||||
uow.Commit();
|
||||
|
||||
var args = new DeleteEventArgs<IContent>(content, false, evtMsgs);
|
||||
Deleted.RaiseEvent(args, this);
|
||||
|
||||
//remove any flagged media files
|
||||
repository.DeleteMediaFiles(args.MediaFilesToDelete);
|
||||
}
|
||||
|
||||
Audit(AuditType.Delete, "Delete Content performed by user", userId, content.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Publishes a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to publish</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <returns>The published status attempt</returns>
|
||||
Attempt<PublishStatus> IContentServiceOperations.Publish(IContent content, int userId)
|
||||
{
|
||||
return SaveAndPublishDo(content, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the Content</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
public void Save(IContent content, int userId = 0, bool raiseEvents = true)
|
||||
Attempt<OperationStatus> IContentServiceOperations.Save(IContent content, int userId, bool raiseEvents)
|
||||
{
|
||||
SaveWithStatus(content, userId, raiseEvents);
|
||||
return Save(content, true, userId, raiseEvents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1035,7 +1205,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
public void Save(IEnumerable<IContent> contents, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
SaveWithStatus(contents, userId, raiseEvents);
|
||||
((IContentServiceOperations)this).Save(contents, userId, raiseEvents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1093,39 +1263,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional Id of the User deleting the Content</param>
|
||||
public void Delete(IContent content, int userId = 0)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IContent>(content), this))
|
||||
return;
|
||||
|
||||
//Make sure that published content is unpublished before being deleted
|
||||
if (HasPublishedVersion(content.Id))
|
||||
{
|
||||
UnPublish(content, userId);
|
||||
}
|
||||
|
||||
//Delete children before deleting the 'possible parent'
|
||||
var children = GetChildren(content.Id);
|
||||
foreach (var child in children)
|
||||
{
|
||||
Delete(child, userId);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(uow))
|
||||
{
|
||||
repository.Delete(content);
|
||||
uow.Commit();
|
||||
|
||||
var args = new DeleteEventArgs<IContent>(content, false);
|
||||
Deleted.RaiseEvent(args, this);
|
||||
|
||||
//remove any flagged media files
|
||||
repository.DeleteMediaFiles(args.MediaFilesToDelete);
|
||||
}
|
||||
|
||||
Audit(AuditType.Delete, "Delete Content performed by user", userId, content.Id);
|
||||
}
|
||||
((IContentServiceOperations)this).Delete(content, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1194,59 +1332,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional Id of the User deleting the Content</param>
|
||||
public void MoveToRecycleBin(IContent content, int userId = 0)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var originalPath = content.Path;
|
||||
|
||||
if (Trashing.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IContent>(
|
||||
new MoveEventInfo<IContent>(content, originalPath, Constants.System.RecycleBinContent)), this))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IContent>>
|
||||
{
|
||||
new MoveEventInfo<IContent>(content, originalPath, Constants.System.RecycleBinContent)
|
||||
};
|
||||
|
||||
//Make sure that published content is unpublished before being moved to the Recycle Bin
|
||||
if (HasPublishedVersion(content.Id))
|
||||
{
|
||||
UnPublish(content, userId);
|
||||
}
|
||||
|
||||
//Unpublish descendents of the content item that is being moved to trash
|
||||
var descendants = GetDescendants(content).OrderBy(x => x.Level).ToList();
|
||||
foreach (var descendant in descendants)
|
||||
{
|
||||
UnPublish(descendant, userId);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(uow))
|
||||
{
|
||||
content.WriterId = userId;
|
||||
content.ChangeTrashedState(true);
|
||||
repository.AddOrUpdate(content);
|
||||
|
||||
//Loop through descendants to update their trash state, but ensuring structure by keeping the ParentId
|
||||
foreach (var descendant in descendants)
|
||||
{
|
||||
moveInfo.Add(new MoveEventInfo<IContent>(descendant, descendant.Path, descendant.ParentId));
|
||||
|
||||
descendant.WriterId = userId;
|
||||
descendant.ChangeTrashedState(true, descendant.ParentId);
|
||||
repository.AddOrUpdate(descendant);
|
||||
}
|
||||
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
Trashed.RaiseEvent(new MoveEventArgs<IContent>(false, moveInfo.ToArray()), this);
|
||||
|
||||
Audit(AuditType.Move, "Move Content to Recycle Bin performed by user", userId, content.Id);
|
||||
}
|
||||
((IContentServiceOperations) this).MoveToRecycleBin(content, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1414,7 +1500,7 @@ namespace Umbraco.Core.Services
|
||||
SentToPublish.RaiseEvent(new SendToPublishEventArgs<IContent>(content, false), this);
|
||||
|
||||
Audit(AuditType.SendToPublish, "Send to Publish performed by user", content.WriterId, content.Id);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1504,6 +1590,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
if (content.Published)
|
||||
{
|
||||
//TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable!
|
||||
var published = _publishingStrategy.Publish(content, userId);
|
||||
shouldBePublished.Add(content);
|
||||
}
|
||||
@@ -1529,7 +1616,11 @@ namespace Umbraco.Core.Services
|
||||
Saved.RaiseEvent(new SaveEventArgs<IContent>(asArray, false), this);
|
||||
|
||||
if (shouldBePublished.Any())
|
||||
{
|
||||
//TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable!
|
||||
_publishingStrategy.PublishingFinalized(shouldBePublished, false);
|
||||
}
|
||||
|
||||
|
||||
Audit(AuditType.Sort, "Sorting content performed by user", userId, 0);
|
||||
|
||||
@@ -1683,6 +1774,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var result = new List<Attempt<PublishStatus>>();
|
||||
@@ -1694,7 +1787,7 @@ namespace Umbraco.Core.Services
|
||||
string.Format(
|
||||
"Content '{0}' with Id '{1}' could not be published because its parent or one of its ancestors is not published.",
|
||||
content.Name, content.Id));
|
||||
result.Add(Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedPathNotPublished)));
|
||||
result.Add(Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedPathNotPublished, evtMsgs)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1706,10 +1799,10 @@ namespace Umbraco.Core.Services
|
||||
content.Name, content.Id));
|
||||
result.Add(
|
||||
Attempt.Fail(
|
||||
new PublishStatus(content, PublishStatusType.FailedContentInvalid)
|
||||
{
|
||||
InvalidProperties = ((ContentBase)content).LastInvalidProperties
|
||||
}));
|
||||
new PublishStatus(content, PublishStatusType.FailedContentInvalid, evtMsgs)
|
||||
{
|
||||
InvalidProperties = ((ContentBase)content).LastInvalidProperties
|
||||
}));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1763,38 +1856,42 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="omitCacheRefresh">Optional boolean to avoid having the cache refreshed when calling this Unpublish method. By default this method will update the cache.</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <returns>True if unpublishing succeeded, otherwise False</returns>
|
||||
private bool UnPublishDo(IContent content, bool omitCacheRefresh = false, int userId = 0)
|
||||
private Attempt<UnPublishStatus> UnPublishDo(IContent content, bool omitCacheRefresh = false, int userId = 0)
|
||||
{
|
||||
var newest = GetById(content.Id); // ensure we have the newest version
|
||||
if (content.Version != newest.Version) // but use the original object if it's already the newest version
|
||||
content = newest;
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
var published = content.Published ? content : GetPublishedVersion(content.Id); // get the published version
|
||||
if (published == null)
|
||||
return false; // already unpublished
|
||||
|
||||
var unpublished = _publishingStrategy.UnPublish(content, userId);
|
||||
if (unpublished)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(uow))
|
||||
{
|
||||
content.WriterId = userId;
|
||||
repository.AddOrUpdate(content);
|
||||
// is published is not newest, reset the published flag on published version
|
||||
if (published.Version != content.Version)
|
||||
repository.ClearPublished(published);
|
||||
repository.DeleteContentXml(content);
|
||||
|
||||
uow.Commit();
|
||||
}
|
||||
//Delete xml from db? and call following method to fire event through PublishingStrategy to update cache
|
||||
if (omitCacheRefresh == false)
|
||||
_publishingStrategy.UnPublishingFinalized(content);
|
||||
|
||||
Audit(AuditType.UnPublish, "UnPublish performed by user", userId, content.Id);
|
||||
return Attempt.Succeed(new UnPublishStatus(content, UnPublishedStatusType.SuccessAlreadyUnPublished, evtMsgs)); // already unpublished
|
||||
}
|
||||
|
||||
var unpublished = _publishingStrategy.UnPublish(content, userId);
|
||||
if (unpublished == false) return Attempt.Fail(new UnPublishStatus(content, UnPublishedStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
|
||||
return unpublished;
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(uow))
|
||||
{
|
||||
content.WriterId = userId;
|
||||
repository.AddOrUpdate(content);
|
||||
// is published is not newest, reset the published flag on published version
|
||||
if (published.Version != content.Version)
|
||||
repository.ClearPublished(published);
|
||||
repository.DeleteContentXml(content);
|
||||
|
||||
uow.Commit();
|
||||
}
|
||||
//Delete xml from db? and call following method to fire event through PublishingStrategy to update cache
|
||||
if (omitCacheRefresh == false)
|
||||
_publishingStrategy.UnPublishingFinalized(content);
|
||||
|
||||
Audit(AuditType.UnPublish, "UnPublish performed by user", userId, content.Id);
|
||||
|
||||
return Attempt.Succeed(new UnPublishStatus(content, UnPublishedStatusType.Success, evtMsgs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1806,13 +1903,14 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
private Attempt<PublishStatus> SaveAndPublishDo(IContent content, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(
|
||||
EventMessagesFactory.Get(),
|
||||
messages => new SaveEventArgs<IContent>(content, messages), this))
|
||||
new SaveEventArgs<IContent>(content, evtMsgs), this))
|
||||
{
|
||||
return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent));
|
||||
return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1820,7 +1918,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
//Has this content item previously been published? If so, we don't need to refresh the children
|
||||
var previouslyPublished = content.HasIdentity && HasPublishedVersion(content.Id); //content might not have an id
|
||||
var publishStatus = new PublishStatus(content, PublishStatusType.Success); //initially set to success
|
||||
var publishStatus = new PublishStatus(content, PublishStatusType.Success, evtMsgs); //initially set to success
|
||||
|
||||
//Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
|
||||
publishStatus.StatusType = CheckAndLogIsPublishable(content);
|
||||
@@ -1870,7 +1968,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
Saved.RaiseEvent(EventMessagesFactory.Get(), messages => new SaveEventArgs<IContent>(content, false, messages), this);
|
||||
Saved.RaiseEvent(new SaveEventArgs<IContent>(content, false, evtMsgs), this);
|
||||
|
||||
//Save xml to db and call following method to fire event through PublishingStrategy to update cache
|
||||
if (published)
|
||||
@@ -1901,15 +1999,16 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
private Attempt<OperationStatus> Save(IContent content, bool changeState, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(
|
||||
EventMessagesFactory.Get(),
|
||||
messages => new SaveEventArgs<IContent>(content, messages),
|
||||
this))
|
||||
if (Saving.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<IContent>(content, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled);
|
||||
}
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
}
|
||||
}
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
@@ -1936,11 +2035,11 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
Saved.RaiseEvent(EventMessagesFactory.Get(), messages => new SaveEventArgs<IContent>(content, false, messages), this);
|
||||
Saved.RaiseEvent(new SaveEventArgs<IContent>(content, false, evtMsgs), this);
|
||||
|
||||
Audit(AuditType.Save, "Save Content performed by user", userId, content.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success);
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -319,6 +319,53 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<ITemplate> GetTemplateDescendants(string alias)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetDescendants(alias);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the template descendants
|
||||
/// </summary>
|
||||
/// <param name="masterTemplateId"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<ITemplate> GetTemplateDescendants(int masterTemplateId)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetDescendants(masterTemplateId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the template children
|
||||
/// </summary>
|
||||
/// <param name="alias"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<ITemplate> GetTemplateChildren(string alias)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetChildren(alias);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the template children
|
||||
/// </summary>
|
||||
/// <param name="masterTemplateId"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<ITemplate> GetTemplateChildren(int masterTemplateId)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetChildren(masterTemplateId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a template as a template node which can be traversed (parent, children)
|
||||
/// </summary>
|
||||
|
||||
@@ -8,6 +8,86 @@ using Umbraco.Core.Publishing;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// A temporary interface until we are in v8, this is used to return a different result for the same method and this interface gets implemented
|
||||
/// explicitly. These methods will replace the normal ones in IContentService in v8 and this will be removed.
|
||||
/// </summary>
|
||||
public interface IContentServiceOperations
|
||||
{
|
||||
//TODO: Remove this class in v8
|
||||
|
||||
//TODO: There's probably more that needs to be added like the EmptyRecycleBin, etc...
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the Content</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
Attempt<OperationStatus> Save(IContent content, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a collection of <see cref="IContent"/> objects.
|
||||
/// </summary>
|
||||
/// <param name="contents">Collection of <see cref="IContent"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the Content</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
Attempt<OperationStatus> Save(IEnumerable<IContent> contents, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
/// Permanently deletes an <see cref="IContent"/> object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method will also delete associated media files, child content and possibly associated domains.
|
||||
/// </remarks>
|
||||
/// <remarks>Please note that this method will completely remove the Content from the database</remarks>
|
||||
/// <param name="content">The <see cref="IContent"/> to delete</param>
|
||||
/// <param name="userId">Optional Id of the User deleting the Content</param>
|
||||
Attempt<OperationStatus> Delete(IContent content, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Publishes a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to publish</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <returns>The published status attempt</returns>
|
||||
Attempt<PublishStatus> Publish(IContent content, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Publishes a <see cref="IContent"/> object and all its children
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to publish along with its children</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <param name="includeUnpublished"></param>
|
||||
/// <returns>The list of statuses for all published items</returns>
|
||||
IEnumerable<Attempt<PublishStatus>> PublishWithChildren(IContent content, int userId = 0, bool includeUnpublished = false);
|
||||
|
||||
/// <summary>
|
||||
/// Saves and Publishes a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to save and publish</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise save events.</param>
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
Attempt<PublishStatus> SaveAndPublish(IContent content, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes an <see cref="IContent"/> object by moving it to the Recycle Bin
|
||||
/// </summary>
|
||||
/// <remarks>Move an item to the Recycle Bin will result in the item being unpublished</remarks>
|
||||
/// <param name="content">The <see cref="IContent"/> to delete</param>
|
||||
/// <param name="userId">Optional Id of the User deleting the Content</param>
|
||||
Attempt<OperationStatus> MoveToRecycleBin(IContent content, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// UnPublishes a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to publish</param>
|
||||
/// <param name="userId">Optional Id of the User issueing the publishing</param>
|
||||
/// <returns>True if unpublishing succeeded, otherwise False</returns>
|
||||
Attempt<UnPublishStatus> UnPublish(IContent content, int userId = 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the ContentService, which is an easy access to operations involving <see cref="IContent"/>
|
||||
/// </summary>
|
||||
@@ -188,31 +268,13 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
|
||||
IEnumerable<IContent> GetContentInRecycleBin();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the Content</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
Attempt<OperationStatus> SaveWithStatus(IContent content, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a collection of <see cref="IContent"/> objects.
|
||||
/// </summary>
|
||||
/// <param name="contents">Collection of <see cref="IContent"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the Content</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
Attempt<OperationStatus> SaveWithStatus(IEnumerable<IContent> contents, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
/// <param name="content">The <see cref="IContent"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the Content</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use SaveWithStatus instead, that method will provide more detailed information on the outcome")]
|
||||
void Save(IContent content, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
@@ -221,8 +283,6 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="contents">Collection of <see cref="IContent"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the Content</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use SaveWithStatus instead, that method will provide more detailed information on the outcome")]
|
||||
void Save(IEnumerable<IContent> contents, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
@@ -407,7 +467,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise save events.</param>
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
Attempt<PublishStatus> SaveAndPublishWithStatus(IContent content, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Permanently deletes an <see cref="IContent"/> object.
|
||||
/// </summary>
|
||||
@@ -416,7 +476,7 @@ namespace Umbraco.Core.Services
|
||||
/// </remarks>
|
||||
/// <remarks>Please note that this method will completely remove the Content from the database</remarks>
|
||||
/// <param name="content">The <see cref="IContent"/> to delete</param>
|
||||
/// <param name="userId">Optional Id of the User deleting the Content</param>
|
||||
/// <param name="userId">Optional Id of the User deleting the Content</param>
|
||||
void Delete(IContent content, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -130,10 +130,38 @@ namespace Umbraco.Core.Services
|
||||
ITemplate GetTemplate(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a template as a template node which can be traversed (parent, children)
|
||||
/// Gets the template descendants
|
||||
/// </summary>
|
||||
/// <param name="alias"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<ITemplate> GetTemplateDescendants(string alias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the template descendants
|
||||
/// </summary>
|
||||
/// <param name="masterTemplateId"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<ITemplate> GetTemplateDescendants(int masterTemplateId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the template children
|
||||
/// </summary>
|
||||
/// <param name="alias"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<ITemplate> GetTemplateChildren(string alias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the template children
|
||||
/// </summary>
|
||||
/// <param name="masterTemplateId"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<ITemplate> GetTemplateChildren(int masterTemplateId);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a template as a template node which can be traversed (parent, children)
|
||||
/// </summary>
|
||||
/// <param name="alias"></param>
|
||||
/// <returns></returns>
|
||||
TemplateNode GetTemplateNode(string alias);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -47,5 +47,13 @@ namespace Umbraco.Core.Services
|
||||
/// to resolve the full culture if possible.
|
||||
/// </remarks>
|
||||
CultureInfo ConvertToSupportedCultureWithRegionCode(CultureInfo currentCulture);
|
||||
|
||||
/// <summary>
|
||||
/// HAAAAAAAAAAACK! Used for backwards compat to convert a user's real culture code to a region code - normally this would be two letters
|
||||
/// TODO: REmove in v8
|
||||
/// </summary>
|
||||
/// <param name="currentCulture"></param>
|
||||
/// <returns></returns>
|
||||
string ConvertToRegionCodeFromSupportedCulture(CultureInfo currentCulture);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,51 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// A temporary interface until we are in v8, this is used to return a different result for the same method and this interface gets implemented
|
||||
/// explicitly. These methods will replace the normal ones in IContentService in v8 and this will be removed.
|
||||
/// </summary>
|
||||
public interface IMediaServiceOperations
|
||||
{
|
||||
//TODO: Remove this class in v8
|
||||
|
||||
//TODO: There's probably more that needs to be added like the EmptyRecycleBin, etc...
|
||||
|
||||
/// <summary>
|
||||
/// Deletes an <see cref="IMedia"/> object by moving it to the Recycle Bin
|
||||
/// </summary>
|
||||
/// <param name="media">The <see cref="IMedia"/> to delete</param>
|
||||
/// <param name="userId">Id of the User deleting the Media</param>
|
||||
Attempt<OperationStatus> MoveToRecycleBin(IMedia media, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Permanently deletes an <see cref="IMedia"/> object
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Please note that this method will completely remove the Media from the database,
|
||||
/// but current not from the file system.
|
||||
/// </remarks>
|
||||
/// <param name="media">The <see cref="IMedia"/> to delete</param>
|
||||
/// <param name="userId">Id of the User deleting the Media</param>
|
||||
Attempt<OperationStatus> Delete(IMedia media, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IMedia"/> object
|
||||
/// </summary>
|
||||
/// <param name="media">The <see cref="IMedia"/> to save</param>
|
||||
/// <param name="userId">Id of the User saving the Media</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
Attempt<OperationStatus> Save(IMedia media, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a collection of <see cref="IMedia"/> objects
|
||||
/// </summary>
|
||||
/// <param name="medias">Collection of <see cref="IMedia"/> to save</param>
|
||||
/// <param name="userId">Id of the User saving the Media</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
Attempt<OperationStatus> Save(IEnumerable<IMedia> medias, int userId = 0, bool raiseEvents = true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the Media Service, which is an easy access to operations involving <see cref="IMedia"/>
|
||||
/// </summary>
|
||||
@@ -174,31 +219,13 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="media">The <see cref="IMedia"/> to delete</param>
|
||||
/// <param name="userId">Id of the User deleting the Media</param>
|
||||
void Delete(IMedia media, int userId = 0);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IMedia"/> object
|
||||
/// </summary>
|
||||
/// <param name="media">The <see cref="IMedia"/> to save</param>
|
||||
/// <param name="userId">Id of the User saving the Media</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
Attempt<OperationStatus> SaveWithStatus(IMedia media, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a collection of <see cref="IMedia"/> objects
|
||||
/// </summary>
|
||||
/// <param name="medias">Collection of <see cref="IMedia"/> to save</param>
|
||||
/// <param name="userId">Id of the User saving the Media</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
Attempt<OperationStatus> SaveWithStatus(IEnumerable<IMedia> medias, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IMedia"/> object
|
||||
/// </summary>
|
||||
/// <param name="media">The <see cref="IMedia"/> to save</param>
|
||||
/// <param name="userId">Id of the User saving the Media</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use SaveWithStatus instead, that method will provide more detailed information on the outcome")]
|
||||
void Save(IMedia media, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
@@ -207,8 +234,6 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="medias">Collection of <see cref="IMedia"/> to save</param>
|
||||
/// <param name="userId">Id of the User saving the Media</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use SaveWithStatus instead, that method will provide more detailed information on the outcome")]
|
||||
void Save(IEnumerable<IMedia> medias, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -191,6 +191,23 @@ namespace Umbraco.Core.Services
|
||||
return attempt ? attempt.Result : currentCulture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HAAAAAAAAAAACK! Used for backwards compat to convert a user's real culture code to a region code - normally this would be two letters
|
||||
/// </summary>
|
||||
/// <param name="currentCulture"></param>
|
||||
/// <returns></returns>
|
||||
public string ConvertToRegionCodeFromSupportedCulture(CultureInfo currentCulture)
|
||||
{
|
||||
if (currentCulture == null) throw new ArgumentNullException("currentCulture");
|
||||
|
||||
if (_fileSources == null) return currentCulture.Name;
|
||||
|
||||
var attempt = _fileSources.Value.TryConvert4LetterCultureTo2Letter(currentCulture);
|
||||
return attempt
|
||||
? attempt.Result
|
||||
: currentCulture.Name;
|
||||
}
|
||||
|
||||
private string GetFromDictionarySource(CultureInfo culture, string area, string key, IDictionary<string, string> tokens)
|
||||
{
|
||||
if (_dictionarySource.ContainsKey(culture) == false)
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace Umbraco.Core.Services
|
||||
//TODO: See other notes in this class, this is purely a hack because we store 2 letter culture file names that contain 4 letter cultures :(
|
||||
public Attempt<CultureInfo> TryConvert2LetterCultureTo4Letter(string twoLetterCulture)
|
||||
{
|
||||
if (twoLetterCulture.Length != 2) Attempt<CultureInfo>.Fail();
|
||||
if (twoLetterCulture.Length != 2) return Attempt<CultureInfo>.Fail();
|
||||
|
||||
//This needs to be resolved before continuing so that the _twoLetterCultureConverter cache is initialized
|
||||
var resolved = _xmlSources.Value;
|
||||
@@ -168,6 +168,19 @@ namespace Umbraco.Core.Services
|
||||
: Attempt<CultureInfo>.Fail();
|
||||
}
|
||||
|
||||
//TODO: See other notes in this class, this is purely a hack because we store 2 letter culture file names that contain 4 letter cultures :(
|
||||
public Attempt<string> TryConvert4LetterCultureTo2Letter(CultureInfo culture)
|
||||
{
|
||||
if (culture == null) throw new ArgumentNullException("culture");
|
||||
|
||||
//This needs to be resolved before continuing so that the _twoLetterCultureConverter cache is initialized
|
||||
var resolved = _xmlSources.Value;
|
||||
|
||||
return _twoLetterCultureConverter.Values.Contains(culture)
|
||||
? Attempt.Succeed(culture.Name.Substring(0, 2))
|
||||
: Attempt<string>.Fail();
|
||||
}
|
||||
|
||||
private void MergeSupplementaryFiles(CultureInfo culture, XDocument xMasterDoc)
|
||||
{
|
||||
if (xMasterDoc.Root == null) return;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// Represents the Media Service, which is an easy access to operations involving <see cref="IMedia"/>
|
||||
/// </summary>
|
||||
public class MediaService : RepositoryService, IMediaService
|
||||
public class MediaService : RepositoryService, IMediaService, IMediaServiceOperations
|
||||
{
|
||||
|
||||
//Support recursive locks because some of the methods that require locking call other methods that require locking.
|
||||
@@ -726,54 +726,144 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Id of the User deleting the Media</param>
|
||||
public void MoveToRecycleBin(IMedia media, int userId = 0)
|
||||
{
|
||||
if (media == null) throw new ArgumentNullException("media");
|
||||
((IMediaServiceOperations) this).MoveToRecycleBin(media, userId);
|
||||
}
|
||||
|
||||
var originalPath = media.Path;
|
||||
/// <summary>
|
||||
/// Permanently deletes an <see cref="IMedia"/> object
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Please note that this method will completely remove the Media from the database,
|
||||
/// but current not from the file system.
|
||||
/// </remarks>
|
||||
/// <param name="media">The <see cref="IMedia"/> to delete</param>
|
||||
/// <param name="userId">Id of the User deleting the Media</param>
|
||||
Attempt<OperationStatus> IMediaServiceOperations.Delete(IMedia media, int userId)
|
||||
{
|
||||
//TODO: IT would be much nicer to mass delete all in one trans in the repo level!
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (Trashing.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IMedia>(
|
||||
new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)), this))
|
||||
if (Deleting.IsRaisedEventCancelled(
|
||||
new DeleteEventArgs<IMedia>(media, evtMsgs), this))
|
||||
{
|
||||
return;
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
}
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IMedia>>
|
||||
//Delete children before deleting the 'possible parent'
|
||||
var children = GetChildren(media.Id);
|
||||
foreach (var child in children)
|
||||
{
|
||||
new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)
|
||||
};
|
||||
|
||||
//Find Descendants, which will be moved to the recycle bin along with the parent/grandparent.
|
||||
var descendants = GetDescendants(media).OrderBy(x => x.Level).ToList();
|
||||
Delete(child, userId);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
//TODO: This should be part of the repo!
|
||||
repository.Delete(media);
|
||||
uow.Commit();
|
||||
|
||||
//Remove 'published' xml from the cmsContentXml table for the unpublished media
|
||||
uow.Database.Delete<ContentXmlDto>("WHERE nodeId = @Id", new { Id = media.Id });
|
||||
var args = new DeleteEventArgs<IMedia>(media, false, evtMsgs);
|
||||
Deleted.RaiseEvent(args, this);
|
||||
|
||||
media.ChangeTrashedState(true, Constants.System.RecycleBinMedia);
|
||||
repository.AddOrUpdate(media);
|
||||
//remove any flagged media files
|
||||
repository.DeleteMediaFiles(args.MediaFilesToDelete);
|
||||
}
|
||||
|
||||
//Loop through descendants to update their trash state, but ensuring structure by keeping the ParentId
|
||||
foreach (var descendant in descendants)
|
||||
Audit(AuditType.Delete, "Delete Media performed by user", userId, media.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IMedia"/> object
|
||||
/// </summary>
|
||||
/// <param name="media">The <see cref="IMedia"/> to save</param>
|
||||
/// <param name="userId">Id of the User saving the Media</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
Attempt<OperationStatus> IMediaServiceOperations.Save(IMedia media, int userId, bool raiseEvents)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<IMedia>(media, evtMsgs),
|
||||
this))
|
||||
{
|
||||
//Remove 'published' xml from the cmsContentXml table for the unpublished media
|
||||
uow.Database.Delete<ContentXmlDto>("WHERE nodeId = @Id", new { Id = descendant.Id });
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
}
|
||||
|
||||
descendant.ChangeTrashedState(true, descendant.ParentId);
|
||||
repository.AddOrUpdate(descendant);
|
||||
}
|
||||
|
||||
moveInfo.Add(new MoveEventInfo<IMedia>(descendant, descendant.Path, descendant.ParentId));
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
media.CreatorId = userId;
|
||||
repository.AddOrUpdate(media);
|
||||
repository.AddOrUpdateContentXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, _userService, m));
|
||||
// generate preview for blame history?
|
||||
if (UmbracoConfig.For.UmbracoSettings().Content.GlobalPreviewStorageEnabled)
|
||||
{
|
||||
repository.AddOrUpdatePreviewXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, _userService, m));
|
||||
}
|
||||
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
Trashed.RaiseEvent(new MoveEventArgs<IMedia>(false, moveInfo.ToArray()), this);
|
||||
if (raiseEvents)
|
||||
Saved.RaiseEvent(new SaveEventArgs<IMedia>(media, false, evtMsgs), this);
|
||||
|
||||
Audit(AuditType.Move, "Move Media to Recycle Bin performed by user", userId, media.Id);
|
||||
Audit(AuditType.Save, "Save Media performed by user", userId, media.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a collection of <see cref="IMedia"/> objects
|
||||
/// </summary>
|
||||
/// <param name="medias">Collection of <see cref="IMedia"/> to save</param>
|
||||
/// <param name="userId">Id of the User saving the Media</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
Attempt<OperationStatus> IMediaServiceOperations.Save(IEnumerable<IMedia> medias, int userId, bool raiseEvents)
|
||||
{
|
||||
var asArray = medias.ToArray();
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<IMedia>(asArray, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
}
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
foreach (var media in asArray)
|
||||
{
|
||||
media.CreatorId = userId;
|
||||
repository.AddOrUpdate(media);
|
||||
repository.AddOrUpdateContentXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, _userService, m));
|
||||
// generate preview for blame history?
|
||||
if (UmbracoConfig.For.UmbracoSettings().Content.GlobalPreviewStorageEnabled)
|
||||
{
|
||||
repository.AddOrUpdatePreviewXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, _userService, m));
|
||||
}
|
||||
}
|
||||
|
||||
//commit the whole lot in one go
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
Saved.RaiseEvent(new SaveEventArgs<IMedia>(asArray, false, evtMsgs), this);
|
||||
|
||||
Audit(AuditType.Save, "Save Media items performed by user", userId, -1);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -859,6 +949,67 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes an <see cref="IMedia"/> object by moving it to the Recycle Bin
|
||||
/// </summary>
|
||||
/// <param name="media">The <see cref="IMedia"/> to delete</param>
|
||||
/// <param name="userId">Id of the User deleting the Media</param>
|
||||
Attempt<OperationStatus> IMediaServiceOperations.MoveToRecycleBin(IMedia media, int userId)
|
||||
{
|
||||
if (media == null) throw new ArgumentNullException("media");
|
||||
|
||||
var originalPath = media.Path;
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (Trashing.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IMedia>(new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)), this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
}
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IMedia>>
|
||||
{
|
||||
new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)
|
||||
};
|
||||
|
||||
//Find Descendants, which will be moved to the recycle bin along with the parent/grandparent.
|
||||
var descendants = GetDescendants(media).OrderBy(x => x.Level).ToList();
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
//TODO: This should be part of the repo!
|
||||
|
||||
//Remove 'published' xml from the cmsContentXml table for the unpublished media
|
||||
uow.Database.Delete<ContentXmlDto>("WHERE nodeId = @Id", new { Id = media.Id });
|
||||
|
||||
media.ChangeTrashedState(true, Constants.System.RecycleBinMedia);
|
||||
repository.AddOrUpdate(media);
|
||||
|
||||
//Loop through descendants to update their trash state, but ensuring structure by keeping the ParentId
|
||||
foreach (var descendant in descendants)
|
||||
{
|
||||
//Remove 'published' xml from the cmsContentXml table for the unpublished media
|
||||
uow.Database.Delete<ContentXmlDto>("WHERE nodeId = @Id", new { Id = descendant.Id });
|
||||
|
||||
descendant.ChangeTrashedState(true, descendant.ParentId);
|
||||
repository.AddOrUpdate(descendant);
|
||||
|
||||
moveInfo.Add(new MoveEventInfo<IMedia>(descendant, descendant.Path, descendant.ParentId));
|
||||
}
|
||||
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
Trashed.RaiseEvent(
|
||||
new MoveEventArgs<IMedia>(false, evtMsgs, moveInfo.ToArray()), this);
|
||||
|
||||
Audit(AuditType.Move, "Move Media to Recycle Bin performed by user", userId, media.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Permanently deletes an <see cref="IMedia"/> object as well as all of its Children.
|
||||
/// </summary>
|
||||
@@ -870,32 +1021,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Id of the User deleting the Media</param>
|
||||
public void Delete(IMedia media, int userId = 0)
|
||||
{
|
||||
//TODO: IT would be much nicer to mass delete all in one trans in the repo level!
|
||||
|
||||
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMedia>(media), this))
|
||||
return;
|
||||
|
||||
//Delete children before deleting the 'possible parent'
|
||||
var children = GetChildren(media.Id);
|
||||
foreach (var child in children)
|
||||
{
|
||||
Delete(child, userId);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
repository.Delete(media);
|
||||
uow.Commit();
|
||||
|
||||
var args = new DeleteEventArgs<IMedia>(media, false);
|
||||
Deleted.RaiseEvent(args, this);
|
||||
|
||||
//remove any flagged media files
|
||||
repository.DeleteMediaFiles(args.MediaFilesToDelete);
|
||||
}
|
||||
|
||||
Audit(AuditType.Delete, "Delete Media performed by user", userId, media.Id);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -954,98 +1080,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Delete, "Delete Media by version performed by user", userId, -1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IMedia"/> object
|
||||
/// </summary>
|
||||
/// <param name="media">The <see cref="IMedia"/> to save</param>
|
||||
/// <param name="userId">Id of the User saving the Media</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
public Attempt<OperationStatus> SaveWithStatus(IMedia media, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
if (raiseEvents)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(
|
||||
EventMessagesFactory.Get(),
|
||||
messages => new SaveEventArgs<IMedia>(media, messages),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
media.CreatorId = userId;
|
||||
repository.AddOrUpdate(media);
|
||||
repository.AddOrUpdateContentXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, _userService, m));
|
||||
// generate preview for blame history?
|
||||
if (UmbracoConfig.For.UmbracoSettings().Content.GlobalPreviewStorageEnabled)
|
||||
{
|
||||
repository.AddOrUpdatePreviewXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, _userService, m));
|
||||
}
|
||||
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
Saved.RaiseEvent(EventMessagesFactory.Get(), messages => new SaveEventArgs<IMedia>(media, false, messages), this);
|
||||
|
||||
Audit(AuditType.Save, "Save Media performed by user", userId, media.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a collection of <see cref="IMedia"/> objects
|
||||
/// </summary>
|
||||
/// <param name="medias">Collection of <see cref="IMedia"/> to save</param>
|
||||
/// <param name="userId">Id of the User saving the Media</param>
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
public Attempt<OperationStatus> SaveWithStatus(IEnumerable<IMedia> medias, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
var asArray = medias.ToArray();
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(
|
||||
EventMessagesFactory.Get(),
|
||||
messages => new SaveEventArgs<IMedia>(asArray, messages),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled);
|
||||
}
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
foreach (var media in asArray)
|
||||
{
|
||||
media.CreatorId = userId;
|
||||
repository.AddOrUpdate(media);
|
||||
repository.AddOrUpdateContentXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, _userService, m));
|
||||
// generate preview for blame history?
|
||||
if (UmbracoConfig.For.UmbracoSettings().Content.GlobalPreviewStorageEnabled)
|
||||
{
|
||||
repository.AddOrUpdatePreviewXml(media, m => _entitySerializer.Serialize(this, _dataTypeService, _userService, m));
|
||||
}
|
||||
}
|
||||
|
||||
//commit the whole lot in one go
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
Saved.RaiseEvent(EventMessagesFactory.Get(), messages => new SaveEventArgs<IMedia>(asArray, false, messages), this);
|
||||
|
||||
Audit(AuditType.Save, "Save Media items performed by user", userId, -1);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IMedia"/> object
|
||||
/// </summary>
|
||||
@@ -1054,7 +1089,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
public void Save(IMedia media, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
SaveWithStatus(media, userId, raiseEvents);
|
||||
((IMediaServiceOperations)this).Save (media, userId, raiseEvents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1065,7 +1100,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="raiseEvents">Optional boolean indicating whether or not to raise events.</param>
|
||||
public void Save(IEnumerable<IMedia> medias, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
SaveWithStatus(medias, userId, raiseEvents);
|
||||
((IMediaServiceOperations)this).Save(medias, userId, raiseEvents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
var content = (IContent) entity;
|
||||
//we'll lazily get these if we need to send notifications
|
||||
IContent[] allVersions = null;
|
||||
IEnumerable<IContent> allVersions = null;
|
||||
|
||||
int totalUsers;
|
||||
var allUsers = _userService.GetAll(0, int.MaxValue, out totalUsers);
|
||||
@@ -75,12 +75,17 @@ namespace Umbraco.Core.Services
|
||||
//lazy load versions if notifications are required
|
||||
if (allVersions == null)
|
||||
{
|
||||
allVersions = _contentService.GetVersions(entity.Id).ToArray();
|
||||
allVersions = _contentService.GetVersions(entity.Id);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
SendNotification(operatingUser, u, content, allVersions, actionName, http, createSubject, createBody);
|
||||
SendNotification(
|
||||
operatingUser, u, content,
|
||||
allVersions,
|
||||
actionName, http, createSubject, createBody);
|
||||
|
||||
|
||||
_logger.Debug<NotificationService>(string.Format("Notification type: {0} sent to {1} ({2})", action, u.Name, u.Email));
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -192,7 +197,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="http"></param>
|
||||
/// <param name="createSubject">Callback to create the mail subject</param>
|
||||
/// <param name="createBody">Callback to create the mail body</param>
|
||||
private void SendNotification(IUser performingUser, IUser mailingUser, IContent content, IContent[] allVersions, string actionName, HttpContextBase http,
|
||||
private void SendNotification(IUser performingUser, IUser mailingUser, IContent content, IEnumerable<IContent> allVersions, string actionName, HttpContextBase http,
|
||||
Func<IUser, string[], string> createSubject,
|
||||
Func<IUser, string[], string> createBody)
|
||||
{
|
||||
@@ -204,8 +209,11 @@ namespace Umbraco.Core.Services
|
||||
if (createSubject == null) throw new ArgumentNullException("createSubject");
|
||||
if (createBody == null) throw new ArgumentNullException("createBody");
|
||||
|
||||
int versionCount = (allVersions.Length > 1) ? (allVersions.Length - 2) : (allVersions.Length - 1);
|
||||
var oldDoc = _contentService.GetByVersion(allVersions[versionCount].Version);
|
||||
//Ensure they are sorted: http://issues.umbraco.org/issue/U4-5180
|
||||
var allVersionsAsArray = allVersions.OrderBy(x => x.UpdateDate).ToArray();
|
||||
|
||||
int versionCount = (allVersionsAsArray.Length > 1) ? (allVersionsAsArray.Length - 2) : (allVersionsAsArray.Length - 1);
|
||||
var oldDoc = _contentService.GetByVersion(allVersionsAsArray[versionCount].Version);
|
||||
|
||||
// build summary
|
||||
var summary = new StringBuilder();
|
||||
|
||||
@@ -1,26 +1,61 @@
|
||||
using System;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// The status returned by many of the service methods
|
||||
/// </summary>
|
||||
public class OperationStatus
|
||||
public class OperationStatus<TEntity, TStatus> : OperationStatus<TStatus>
|
||||
where TStatus : struct
|
||||
{
|
||||
//TODO: This is a pretty simple class atm, but is 'future' proofed in case we need to add more detail here
|
||||
|
||||
internal static OperationStatus Cancelled
|
||||
public OperationStatus(TEntity entity, TStatus statusType, EventMessages eventMessages) : base(statusType, eventMessages)
|
||||
{
|
||||
get { return new OperationStatus(OperationStatusType.FailedCancelledByEvent);}
|
||||
Entity = entity;
|
||||
}
|
||||
|
||||
internal static OperationStatus Success
|
||||
{
|
||||
get { return new OperationStatus(OperationStatusType.Success); }
|
||||
}
|
||||
public TEntity Entity { get; private set; }
|
||||
|
||||
public OperationStatus(OperationStatusType statusType)
|
||||
{
|
||||
StatusType = statusType;
|
||||
}
|
||||
public OperationStatusType StatusType { get; internal set; }
|
||||
}
|
||||
|
||||
public class OperationStatus<TStatus>
|
||||
where TStatus : struct
|
||||
{
|
||||
public OperationStatus(TStatus statusType, EventMessages eventMessages)
|
||||
{
|
||||
if (eventMessages == null) throw new ArgumentNullException("eventMessages");
|
||||
StatusType = statusType;
|
||||
EventMessages = eventMessages;
|
||||
}
|
||||
|
||||
public TStatus StatusType { get; internal set; }
|
||||
public EventMessages EventMessages { get; private set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The default operation status
|
||||
/// </summary>
|
||||
public class OperationStatus : OperationStatus<OperationStatusType>
|
||||
{
|
||||
public OperationStatus(OperationStatusType statusType, EventMessages eventMessages) : base(statusType, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#region Static Helper methods
|
||||
|
||||
internal static OperationStatus Cancelled(EventMessages eventMessages)
|
||||
{
|
||||
return new OperationStatus(OperationStatusType.FailedCancelledByEvent, eventMessages);
|
||||
}
|
||||
|
||||
internal static OperationStatus Success(EventMessages eventMessages)
|
||||
{
|
||||
return new OperationStatus(OperationStatusType.Success, eventMessages);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,5 +17,7 @@ namespace Umbraco.Core.Services
|
||||
/// The saving has been cancelled by a 3rd party add-in
|
||||
/// </summary>
|
||||
FailedCancelledByEvent = 14
|
||||
|
||||
//TODO: In the future, we might need to add more operations statuses, potentially like 'FailedByPermissions', etc...
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,25 @@ using Umbraco.Core.Events;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// These are used currently to return the temporary 'operation' interfaces for services
|
||||
/// which are used to return a status from operational methods so we can determine if things are
|
||||
/// cancelled, etc...
|
||||
///
|
||||
/// These will be obsoleted in v8 since all real services methods will be changed to have the correct result.
|
||||
/// </summary>
|
||||
public static class ServiceWithResultExtensions
|
||||
{
|
||||
public static IContentServiceOperations WithResult(this IContentService contentService)
|
||||
{
|
||||
return (IContentServiceOperations)contentService;
|
||||
}
|
||||
public static IMediaServiceOperations WithResult(this IMediaService mediaService)
|
||||
{
|
||||
return (IMediaServiceOperations)mediaService;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Umbraco ServiceContext, which provides access to the following services:
|
||||
/// <see cref="IContentService"/>, <see cref="IContentTypeService"/>, <see cref="IDataTypeService"/>,
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Publishing;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Standalone
|
||||
{
|
||||
internal class ServiceContextManager : IDisposable
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
private readonly string _providerName;
|
||||
private readonly ILogger _logger;
|
||||
private readonly ISqlSyntaxProvider _syntaxProvider;
|
||||
private ServiceContext _serviceContext;
|
||||
private readonly StandaloneCoreApplication _application;
|
||||
|
||||
public ServiceContextManager(string connectionString, string providerName, string baseDirectory, ILogger logger, ISqlSyntaxProvider syntaxProvider)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
_providerName = providerName;
|
||||
_logger = logger;
|
||||
_syntaxProvider = syntaxProvider;
|
||||
|
||||
Trace.WriteLine("ServiceContextManager-Current AppDomain: " + AppDomain.CurrentDomain.FriendlyName);
|
||||
Trace.WriteLine("ServiceContextManager-Current AppDomain: " + AppDomain.CurrentDomain.BaseDirectory);
|
||||
|
||||
//var webAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.FullName.StartsWith("umbraco"));
|
||||
//if (webAssembly != null && examineEventHandlerToRemove == null)
|
||||
//{
|
||||
// var examineEventType = webAssembly.GetType("Umbraco.Web.Search.ExamineEvents");
|
||||
// examineEventHandlerToRemove = examineEventType;
|
||||
//}
|
||||
|
||||
_application = StandaloneCoreApplication.GetApplication(baseDirectory);
|
||||
|
||||
var examineEventHandlerToRemove = Type.GetType("Umbraco.Web.Search.ExamineEvents, umbraco");
|
||||
if (examineEventHandlerToRemove != null)
|
||||
_application.WithoutApplicationEventHandler(examineEventHandlerToRemove);
|
||||
|
||||
_application.Start();
|
||||
}
|
||||
|
||||
public ServiceContext Services
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_serviceContext == null)
|
||||
{
|
||||
var cacheHelper = new CacheHelper(
|
||||
new ObjectCacheRuntimeCacheProvider(),
|
||||
new StaticCacheProvider(),
|
||||
//we have no request based cache when running standalone
|
||||
new NullCacheProvider());
|
||||
|
||||
var dbFactory = new DefaultDatabaseFactory(_connectionString, _providerName, _logger);
|
||||
var dbContext = new DatabaseContext(dbFactory, _logger, _syntaxProvider, _providerName);
|
||||
Database.Mapper = new PetaPocoMapper();
|
||||
_serviceContext = new ServiceContext(
|
||||
new RepositoryFactory(cacheHelper, _logger, dbContext.SqlSyntax, UmbracoConfig.For.UmbracoSettings()),
|
||||
new PetaPocoUnitOfWorkProvider(dbFactory),
|
||||
new FileUnitOfWorkProvider(),
|
||||
new PublishingStrategy(),
|
||||
cacheHelper,
|
||||
new DebugDiagnosticsLogger(),
|
||||
new TransientMessagesFactory());
|
||||
|
||||
//initialize the DatabaseContext
|
||||
dbContext.Initialize(_providerName);
|
||||
}
|
||||
|
||||
return _serviceContext;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
((IDisposable)ApplicationContext.Current).Dispose();
|
||||
_application.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Standalone
|
||||
{
|
||||
internal class StandaloneCoreApplication : UmbracoApplicationBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StandaloneCoreApplication"/> class.
|
||||
/// </summary>
|
||||
protected StandaloneCoreApplication(string baseDirectory)
|
||||
{
|
||||
_baseDirectory = baseDirectory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides the application boot manager.
|
||||
/// </summary>
|
||||
/// <returns>An application boot manager.</returns>
|
||||
protected override IBootManager GetBootManager()
|
||||
{
|
||||
return new StandaloneCoreBootManager(this, _handlersToAdd, _handlersToRemove, _baseDirectory);
|
||||
}
|
||||
|
||||
#region Application
|
||||
|
||||
private readonly string _baseDirectory;
|
||||
private static StandaloneCoreApplication _application;
|
||||
private static bool _started;
|
||||
private static readonly object AppLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the instance of the standalone Umbraco application.
|
||||
/// </summary>
|
||||
public static StandaloneCoreApplication GetApplication(string baseDirectory)
|
||||
{
|
||||
lock (AppLock)
|
||||
{
|
||||
return _application ?? (_application = new StandaloneCoreApplication(baseDirectory));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the application.
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
lock (AppLock)
|
||||
{
|
||||
if (_started)
|
||||
throw new InvalidOperationException("Application has already started.");
|
||||
Application_Start(this, EventArgs.Empty);
|
||||
_started = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IApplicationEventHandler management
|
||||
|
||||
private readonly List<Type> _handlersToAdd = new List<Type>();
|
||||
private readonly List<Type> _handlersToRemove = new List<Type>();
|
||||
|
||||
/// <summary>
|
||||
/// Associates an <see cref="IApplicationEventHandler"/> type with the application.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to associate.</typeparam>
|
||||
/// <returns>The application.</returns>
|
||||
/// <remarks>Types implementing <see cref="IApplicationEventHandler"/> from within
|
||||
/// an executable are not automatically discovered by Umbraco and have to be
|
||||
/// explicitely associated with the application using this method.</remarks>
|
||||
public StandaloneCoreApplication WithApplicationEventHandler<T>()
|
||||
where T : IApplicationEventHandler
|
||||
{
|
||||
_handlersToAdd.Add(typeof(T));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dissociates an <see cref="IApplicationEventHandler"/> type from the application.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to dissociate.</typeparam>
|
||||
/// <returns>The application.</returns>
|
||||
public StandaloneCoreApplication WithoutApplicationEventHandler<T>()
|
||||
where T : IApplicationEventHandler
|
||||
{
|
||||
_handlersToRemove.Add(typeof(T));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Associates an <see cref="IApplicationEventHandler"/> type with the application.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to associate.</param>
|
||||
/// <returns>The application.</returns>
|
||||
/// <remarks>Types implementing <see cref="IApplicationEventHandler"/> from within
|
||||
/// an executable are not automatically discovered by Umbraco and have to be
|
||||
/// explicitely associated with the application using this method.</remarks>
|
||||
public StandaloneCoreApplication WithApplicationEventHandler(Type type)
|
||||
{
|
||||
if (type.Implements<IApplicationEventHandler>() == false)
|
||||
throw new ArgumentException("Type does not implement IApplicationEventHandler.", "type");
|
||||
_handlersToAdd.Add(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dissociates an <see cref="IApplicationEventHandler"/> type from the application.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to dissociate.</param>
|
||||
/// <returns>The application.</returns>
|
||||
public StandaloneCoreApplication WithoutApplicationEventHandler(Type type)
|
||||
{
|
||||
if (type.Implements<IApplicationEventHandler>() == false)
|
||||
throw new ArgumentException("Type does not implement IApplicationEventHandler.", "type");
|
||||
_handlersToRemove.Add(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Standalone
|
||||
{
|
||||
internal class StandaloneCoreBootManager : CoreBootManager
|
||||
{
|
||||
private readonly IEnumerable<Type> _handlersToAdd;
|
||||
private readonly IEnumerable<Type> _handlersToRemove;
|
||||
private readonly string _baseDirectory;
|
||||
|
||||
public StandaloneCoreBootManager(UmbracoApplicationBase umbracoApplication, IEnumerable<Type> handlersToAdd, IEnumerable<Type> handlersToRemove, string baseDirectory)
|
||||
: base(umbracoApplication)
|
||||
{
|
||||
_handlersToAdd = handlersToAdd;
|
||||
_handlersToRemove = handlersToRemove;
|
||||
_baseDirectory = baseDirectory;
|
||||
|
||||
base.InitializeApplicationRootPath(_baseDirectory);
|
||||
|
||||
// this is only here to ensure references to the assemblies needed for
|
||||
// the DataTypesResolver otherwise they won't be loaded into the AppDomain.
|
||||
var interfacesAssemblyName = typeof(IDataType).Assembly.FullName;
|
||||
}
|
||||
|
||||
protected override void InitializeApplicationEventsResolver()
|
||||
{
|
||||
base.InitializeApplicationEventsResolver();
|
||||
|
||||
foreach (var type in _handlersToAdd)
|
||||
ApplicationEventsResolver.Current.AddType(type);
|
||||
|
||||
foreach (var type in _handlersToRemove)
|
||||
ApplicationEventsResolver.Current.RemoveType(type);
|
||||
}
|
||||
|
||||
protected override void InitializeResolvers()
|
||||
{
|
||||
base.InitializeResolvers();
|
||||
|
||||
//Mappers are not resolved, which could be because of a known TypeMapper issue
|
||||
/*MappingResolver.Reset();
|
||||
MappingResolver.Current = new MappingResolver(
|
||||
() =>
|
||||
new List<Type>
|
||||
{
|
||||
typeof (ContentMapper),
|
||||
typeof (ContentTypeMapper),
|
||||
typeof (MediaMapper),
|
||||
typeof (MediaTypeMapper),
|
||||
typeof (DataTypeDefinitionMapper),
|
||||
typeof (UmbracoEntityMapper)
|
||||
});*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1409,5 +1409,18 @@ namespace Umbraco.Core
|
||||
{
|
||||
return string.IsNullOrEmpty(text) ? text : InvalidXmlChars.Replace(text, "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string to a Guid - WARNING, depending on the string, this may not be unique
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
internal static Guid ToGuid(this string text)
|
||||
{
|
||||
var md5 = MD5.Create();
|
||||
byte[] myStringBytes = Encoding.ASCII.GetBytes(text);
|
||||
byte[] hash = md5.ComputeHash(myStringBytes);
|
||||
return new Guid(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Umbraco.Core.Sync
|
||||
/// Thread safety: this is NOT thread safe. Because it is NOT meant to run multi-threaded.
|
||||
/// Callers MUST ensure thread-safety.
|
||||
/// </remarks>
|
||||
internal protected void Boot()
|
||||
protected void Boot()
|
||||
{
|
||||
// weight:10, must release *before* the facade service, because once released
|
||||
// the service will *not* be able to properly handle our notifications anymore
|
||||
|
||||
@@ -37,13 +37,13 @@
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
|
||||
<Reference Include="AutoMapper, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
<Reference Include="AutoMapper.Net4, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="HtmlAgilityPack, Version=1.4.9.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
@@ -302,6 +302,7 @@
|
||||
<Compile Include="DatabaseContext.cs" />
|
||||
<Compile Include="DataTableExtensions.cs" />
|
||||
<Compile Include="DateTimeExtensions.cs" />
|
||||
<Compile Include="DelegateExtensions.cs" />
|
||||
<Compile Include="DictionaryExtensions.cs" />
|
||||
<Compile Include="Dictionary\CultureDictionaryFactoryResolver.cs" />
|
||||
<Compile Include="Dictionary\ICultureDictionaryFactory.cs" />
|
||||
@@ -445,6 +446,8 @@
|
||||
<Compile Include="Persistence\Repositories\TaskRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\TaskTypeRepository.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\GridValueConverter.cs" />
|
||||
<Compile Include="Publishing\UnPublishedStatusType.cs" />
|
||||
<Compile Include="Publishing\UnPublishStatus.cs" />
|
||||
<Compile Include="Security\BackOfficeClaimsIdentityFactory.cs" />
|
||||
<Compile Include="Security\BackOfficeSignInManager.cs" />
|
||||
<Compile Include="Security\BackOfficeUserManager.cs" />
|
||||
@@ -1246,9 +1249,6 @@
|
||||
<Compile Include="Services\UserService.cs" />
|
||||
<Compile Include="Services\UserServiceExtensions.cs" />
|
||||
<Compile Include="IO\ViewHelper.cs" />
|
||||
<Compile Include="Standalone\ServiceContextManager.cs" />
|
||||
<Compile Include="Standalone\StandaloneCoreApplication.cs" />
|
||||
<Compile Include="Standalone\StandaloneCoreBootManager.cs" />
|
||||
<Compile Include="Strategies\RelateOnCopyHandler.cs" />
|
||||
<Compile Include="Strategies\RelateOnTrashHandler.cs" />
|
||||
<Compile Include="Strings\ContentBaseExtensions.cs" />
|
||||
@@ -1387,7 +1387,6 @@
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
|
||||
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
|
||||
</Target>
|
||||
<Import Project="..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets" Condition="Exists('..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
|
||||
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
|
||||
<package id="HtmlAgilityPack" version="1.4.9" targetFramework="net45" />
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net4" />
|
||||
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net45" />
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.1" newVersion="4.0.0.1" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
|
||||
</dependentAssembly>
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
|
||||
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
|
||||
|
||||
</dependentAssembly>
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Mvc;
|
||||
using Microsoft.Web.Mvc;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Profiling;
|
||||
using Umbraco.Web;
|
||||
@@ -16,46 +15,38 @@ namespace Umbraco.Tests.BootManagers
|
||||
{
|
||||
IList<IViewEngine> engines = new List<IViewEngine>
|
||||
{
|
||||
new FixedWebFormViewEngine(),
|
||||
new FixedRazorViewEngine(),
|
||||
new RenderViewEngine(),
|
||||
new PluginViewEngine()
|
||||
};
|
||||
|
||||
WebBootManager.WrapViewEngines(engines);
|
||||
|
||||
Assert.That(engines.Count, Is.EqualTo(4));
|
||||
Assert.That(engines.Count, Is.EqualTo(2));
|
||||
Assert.That(engines[0], Is.InstanceOf<ProfilingViewEngine>());
|
||||
Assert.That(engines[1], Is.InstanceOf<ProfilingViewEngine>());
|
||||
Assert.That(engines[2], Is.InstanceOf<ProfilingViewEngine>());
|
||||
Assert.That(engines[3], Is.InstanceOf<ProfilingViewEngine>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WrapViewEngines_HasEngines_KeepsSortOrder()
|
||||
{
|
||||
IList<IViewEngine> engines = new List<IViewEngine>
|
||||
IList<IViewEngine> engines = new List<IViewEngine>
|
||||
{
|
||||
new FixedWebFormViewEngine(),
|
||||
new FixedRazorViewEngine(),
|
||||
new RenderViewEngine(),
|
||||
new PluginViewEngine()
|
||||
};
|
||||
|
||||
WebBootManager.WrapViewEngines(engines);
|
||||
|
||||
Assert.That(engines.Count, Is.EqualTo(4));
|
||||
Assert.That(((ProfilingViewEngine)engines[0]).Inner, Is.InstanceOf<FixedWebFormViewEngine>());
|
||||
Assert.That(((ProfilingViewEngine)engines[1]).Inner, Is.InstanceOf<FixedRazorViewEngine>());
|
||||
Assert.That(((ProfilingViewEngine)engines[2]).Inner, Is.InstanceOf<RenderViewEngine>());
|
||||
Assert.That(((ProfilingViewEngine)engines[3]).Inner, Is.InstanceOf<PluginViewEngine>());
|
||||
Assert.That(engines.Count, Is.EqualTo(2));
|
||||
Assert.That(((ProfilingViewEngine)engines[0]).Inner, Is.InstanceOf<RenderViewEngine>());
|
||||
Assert.That(((ProfilingViewEngine)engines[1]).Inner, Is.InstanceOf<PluginViewEngine>());
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void WrapViewEngines_HasProfiledEngine_AddsSameInstance()
|
||||
{
|
||||
var profiledEngine = new ProfilingViewEngine(new FixedRazorViewEngine());
|
||||
var profiledEngine = new ProfilingViewEngine(new PluginViewEngine());
|
||||
IList<IViewEngine> engines = new List<IViewEngine>
|
||||
{
|
||||
profiledEngine
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using Lucene.Net.Index;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class DelegateExtensionsTests
|
||||
{
|
||||
|
||||
[Test]
|
||||
public void Only_Executes_Specific_Count()
|
||||
{
|
||||
var maxTries = 5;
|
||||
var totalTries = 0;
|
||||
DelegateExtensions.RetryUntilSuccessOrMaxAttempts((currentTry) =>
|
||||
{
|
||||
totalTries = currentTry;
|
||||
return Attempt<IndexWriter>.Fail();
|
||||
}, 5, TimeSpan.FromMilliseconds(10));
|
||||
|
||||
Assert.AreEqual(maxTries, totalTries);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Quits_On_Success_Count()
|
||||
{
|
||||
var maxTries = 5;
|
||||
var totalTries = 0;
|
||||
DelegateExtensions.RetryUntilSuccessOrMaxAttempts((currentTry) =>
|
||||
{
|
||||
totalTries = currentTry;
|
||||
if (totalTries == 2)
|
||||
{
|
||||
return Attempt<string>.Succeed();
|
||||
}
|
||||
return Attempt<string>.Fail();
|
||||
}, 5, TimeSpan.FromMilliseconds(10));
|
||||
|
||||
Assert.AreEqual(2, totalTries);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -119,6 +119,7 @@ namespace Umbraco.Tests.Logging
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore]
|
||||
public void CanLogAtleast1000MessagesASecond()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -460,13 +461,15 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2
|
||||
var content2 = "{javascript: []}";
|
||||
var content3 = "{javascript: ['~/test.js', '~/test2.js']}";
|
||||
var content4 = "{propertyEditors: [], javascript: ['~/test.js', '~/test2.js']}";
|
||||
var content5 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble()) + "{propertyEditors: [], javascript: ['~/test.js', '~/test2.js']}";
|
||||
|
||||
var result = ManifestParser.CreateManifests(null, content1, content2, content3, content4);
|
||||
var result = ManifestParser.CreateManifests(null, content1, content2, content3, content4, content5);
|
||||
|
||||
Assert.AreEqual(4, result.Count());
|
||||
Assert.AreEqual(5, result.Count());
|
||||
Assert.AreEqual(0, result.ElementAt(1).JavaScriptInitialize.Count);
|
||||
Assert.AreEqual(2, result.ElementAt(2).JavaScriptInitialize.Count);
|
||||
Assert.AreEqual(2, result.ElementAt(3).JavaScriptInitialize.Count);
|
||||
Assert.AreEqual(2, result.ElementAt(4).JavaScriptInitialize.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -56,11 +56,12 @@ namespace Umbraco.Tests.Persistence
|
||||
|
||||
var repositoryFactory = new RepositoryFactory(cacheHelper, _logger, SqlSyntaxProvider, SettingsForTests.GenerateMockSettings());
|
||||
|
||||
var evtMsgs = new TransientMessagesFactory();
|
||||
ApplicationContext.Current = new ApplicationContext(
|
||||
//assign the db context
|
||||
dbContext,
|
||||
//assign the service context
|
||||
new ServiceContext(repositoryFactory, new PetaPocoUnitOfWorkProvider(_logger), new FileUnitOfWorkProvider(), new PublishingStrategy(), cacheHelper, _logger, new TransientMessagesFactory()),
|
||||
new ServiceContext(repositoryFactory, new PetaPocoUnitOfWorkProvider(_logger), new FileUnitOfWorkProvider(), new PublishingStrategy(evtMsgs, _logger), cacheHelper, _logger, evtMsgs),
|
||||
cacheHelper,
|
||||
new ProfilingLogger(_logger, Mock.Of<IProfiler>()))
|
||||
{
|
||||
|
||||
@@ -44,7 +44,13 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
private ContentRepository CreateRepository(IDatabaseUnitOfWork unitOfWork, out ContentTypeRepository contentTypeRepository)
|
||||
{
|
||||
var templateRepository = new TemplateRepository(unitOfWork, CacheHelper, Logger, SqlSyntax, Mock.Of<IFileSystem>(), Mock.Of<IFileSystem>(), Mock.Of<ITemplatesSection>());
|
||||
TemplateRepository tr;
|
||||
return CreateRepository(unitOfWork, out contentTypeRepository, out tr);
|
||||
}
|
||||
|
||||
private ContentRepository CreateRepository(IDatabaseUnitOfWork unitOfWork, out ContentTypeRepository contentTypeRepository, out TemplateRepository templateRepository)
|
||||
{
|
||||
templateRepository = new TemplateRepository(unitOfWork, CacheHelper, Logger, SqlSyntax, Mock.Of<IFileSystem>(), Mock.Of<IFileSystem>(), Mock.Of<ITemplatesSection>());
|
||||
var tagRepository = new TagRepository(unitOfWork, CacheHelper, Logger, SqlSyntax);
|
||||
contentTypeRepository = new ContentTypeRepository(unitOfWork, CacheHelper, Logger, SqlSyntax, templateRepository);
|
||||
var repository = new ContentRepository(unitOfWork, CacheHelper, Logger, SqlSyntax, contentTypeRepository, templateRepository, tagRepository, Mock.Of<IContentSection>());
|
||||
@@ -217,6 +223,37 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
// Assert
|
||||
Assert.That(contentType.HasIdentity, Is.True);
|
||||
Assert.That(textpage.HasIdentity, Is.True);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Perform_Add_With_Default_Template()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
ContentTypeRepository contentTypeRepository;
|
||||
TemplateRepository templateRepository;
|
||||
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository, out templateRepository))
|
||||
{
|
||||
var template = new Template("hello", "hello");
|
||||
templateRepository.AddOrUpdate(template);
|
||||
unitOfWork.Commit();
|
||||
|
||||
ContentType contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage2", "Textpage");
|
||||
contentType.SetDefaultTemplate(template);
|
||||
Content textpage = MockedContent.CreateSimpleContent(contentType);
|
||||
|
||||
// Act
|
||||
|
||||
contentTypeRepository.AddOrUpdate(contentType);
|
||||
repository.AddOrUpdate(textpage);
|
||||
unitOfWork.Commit();
|
||||
|
||||
// Assert
|
||||
Assert.That(textpage.Template, Is.Not.Null);
|
||||
Assert.That(textpage.Template, Is.EqualTo(contentType.DefaultTemplate));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,6 +364,28 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Update_With_Null_Template()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
ContentTypeRepository contentTypeRepository;
|
||||
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
|
||||
{
|
||||
// Act
|
||||
var content = repository.Get(NodeDto.NodeIdSeed + 2);
|
||||
content.Template = null;
|
||||
repository.AddOrUpdate(content);
|
||||
unitOfWork.Commit();
|
||||
var updatedContent = repository.Get(NodeDto.NodeIdSeed + 2);
|
||||
|
||||
// Assert
|
||||
Assert.That(updatedContent.Template, Is.Null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Perform_Delete_On_ContentRepository()
|
||||
{
|
||||
|
||||
@@ -235,13 +235,16 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var contentType = repository.Get(NodeDto.NodeIdSeed + 1);
|
||||
var childContentType = MockedContentTypes.CreateSimpleContentType("blah", "Blah", contentType, randomizeAliases:true);
|
||||
repository.AddOrUpdate(childContentType);
|
||||
unitOfWork.Commit();
|
||||
|
||||
// Act
|
||||
contentType = repository.Get(contentType.Key);
|
||||
var result = repository.Get(childContentType.Key);
|
||||
|
||||
// Assert
|
||||
Assert.That(contentType, Is.Not.Null);
|
||||
Assert.That(contentType.Id, Is.EqualTo(NodeDto.NodeIdSeed + 1));
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result.Id, Is.EqualTo(childContentType.Id));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,9 +85,41 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
Assert.AreEqual("test.com", domain.DomainName);
|
||||
Assert.AreEqual(content.Id, domain.RootContentId);
|
||||
Assert.AreEqual(lang.Id, domain.LanguageId);
|
||||
Assert.AreEqual(lang.IsoCode, domain.LanguageIsoCode);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Create_And_Get_By_Id_Empty_lang()
|
||||
{
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
|
||||
ContentType ct;
|
||||
var contentId = CreateTestData("en-AU", out ct);
|
||||
|
||||
ContentRepository contentRepo;
|
||||
LanguageRepository langRepo;
|
||||
ContentTypeRepository contentTypeRepo;
|
||||
|
||||
using (var repo = CreateRepository(unitOfWork, out contentTypeRepo, out contentRepo, out langRepo))
|
||||
{
|
||||
var content = contentRepo.Get(contentId);
|
||||
|
||||
var domain = (IDomain)new UmbracoDomain("test.com") { RootContentId = content.Id };
|
||||
repo.AddOrUpdate(domain);
|
||||
unitOfWork.Commit();
|
||||
|
||||
//re-get
|
||||
domain = repo.Get(domain.Id);
|
||||
|
||||
Assert.NotNull(domain);
|
||||
Assert.IsTrue(domain.HasIdentity);
|
||||
Assert.Greater(domain.Id, 0);
|
||||
Assert.AreEqual("test.com", domain.DomainName);
|
||||
Assert.AreEqual(content.Id, domain.RootContentId);
|
||||
Assert.IsFalse(domain.LanguageId.HasValue);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -203,11 +235,13 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
Assert.AreEqual("blah.com", domain.DomainName);
|
||||
Assert.AreEqual(content2.Id, domain.RootContentId);
|
||||
Assert.AreEqual(lang2.Id, domain.LanguageId);
|
||||
Assert.AreEqual(lang2.IsoCode, domain.LanguageIsoCode);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Exists()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
@@ -63,7 +64,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
Assert.AreEqual(0, found.First().AssigneeUserId);
|
||||
Assert.AreEqual(false, found.First().Closed);
|
||||
Assert.AreEqual("hello world", found.First().Comment);
|
||||
Assert.GreaterOrEqual(found.First().CreateDate, created);
|
||||
Assert.GreaterOrEqual(found.First().CreateDate.TruncateTo(DateTimeExtensions.DateTruncate.Second), created.TruncateTo(DateTimeExtensions.DateTruncate.Second));
|
||||
Assert.AreEqual(-1, found.First().EntityId);
|
||||
Assert.AreEqual(0, found.First().OwnerUserId);
|
||||
Assert.AreEqual(true, found.First().HasIdentity);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -489,77 +490,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var parent = new Template("parent", "parent")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
|
||||
var child1 = new Template("child1", "child1")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
var toddler1 = new Template("toddler1", "toddler1")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
var toddler2 = new Template("toddler2", "toddler2")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
var baby1 = new Template("baby1", "baby1")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
|
||||
var child2 = new Template("child2", "child2")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
var toddler3 = new Template("toddler3", "toddler3")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
var toddler4 = new Template("toddler4", "toddler4")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
var baby2 = new Template("baby2", "baby2")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
|
||||
|
||||
child1.MasterTemplateAlias = parent.Alias;
|
||||
child1.MasterTemplateId = new Lazy<int>(() => parent.Id);
|
||||
child2.MasterTemplateAlias = parent.Alias;
|
||||
child2.MasterTemplateId = new Lazy<int>(() => parent.Id);
|
||||
|
||||
toddler1.MasterTemplateAlias = child1.Alias;
|
||||
toddler1.MasterTemplateId = new Lazy<int>(() => child1.Id);
|
||||
toddler2.MasterTemplateAlias = child1.Alias;
|
||||
toddler2.MasterTemplateId = new Lazy<int>(() => child1.Id);
|
||||
|
||||
toddler3.MasterTemplateAlias = child2.Alias;
|
||||
toddler3.MasterTemplateId = new Lazy<int>(() => child2.Id);
|
||||
toddler4.MasterTemplateAlias = child2.Alias;
|
||||
toddler4.MasterTemplateId = new Lazy<int>(() => child2.Id);
|
||||
|
||||
baby1.MasterTemplateAlias = toddler2.Alias;
|
||||
baby1.MasterTemplateId = new Lazy<int>(() => toddler2.Id);
|
||||
|
||||
baby2.MasterTemplateAlias = toddler4.Alias;
|
||||
baby2.MasterTemplateId = new Lazy<int>(() => toddler4.Id);
|
||||
|
||||
repository.AddOrUpdate(parent);
|
||||
repository.AddOrUpdate(child1);
|
||||
repository.AddOrUpdate(child2);
|
||||
repository.AddOrUpdate(toddler1);
|
||||
repository.AddOrUpdate(toddler2);
|
||||
repository.AddOrUpdate(toddler3);
|
||||
repository.AddOrUpdate(toddler4);
|
||||
repository.AddOrUpdate(baby1);
|
||||
repository.AddOrUpdate(baby2);
|
||||
unitOfWork.Commit();
|
||||
CreateHierarchy(repository, unitOfWork);
|
||||
|
||||
// Act
|
||||
var rootNode = repository.GetTemplateNode("parent");
|
||||
@@ -575,8 +506,102 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "baby1"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "baby2"));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_All()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var created = CreateHierarchy(repository, unitOfWork).ToArray();
|
||||
|
||||
// Act
|
||||
var all = repository.GetAll();
|
||||
var allByAlias = repository.GetAll("parent", "child2", "baby2", "notFound");
|
||||
var allById = repository.GetAll(created[0].Id, created[2].Id, created[4].Id, created[5].Id, 999999);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(9, all.Count());
|
||||
Assert.AreEqual(9, all.DistinctBy(x => x.Id).Count());
|
||||
|
||||
Assert.AreEqual(3, allByAlias.Count());
|
||||
Assert.AreEqual(3, allByAlias.DistinctBy(x => x.Id).Count());
|
||||
|
||||
Assert.AreEqual(4, allById.Count());
|
||||
Assert.AreEqual(4, allById.DistinctBy(x => x.Id).Count());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_Children()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var created = CreateHierarchy(repository, unitOfWork).ToArray();
|
||||
|
||||
// Act
|
||||
var childrenById = repository.GetChildren(created[1].Id);
|
||||
var childrenByAlias = repository.GetChildren(created[1].Alias);
|
||||
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(2, childrenById.Count());
|
||||
Assert.AreEqual(2, childrenById.DistinctBy(x => x.Id).Count());
|
||||
Assert.AreEqual(2, childrenByAlias.Count());
|
||||
Assert.AreEqual(2, childrenByAlias.DistinctBy(x => x.Id).Count());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_Children_At_Root()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
CreateHierarchy(repository, unitOfWork).ToArray();
|
||||
|
||||
// Act
|
||||
var children = repository.GetChildren(-1);
|
||||
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(1, children.Count());
|
||||
Assert.AreEqual(1, children.DistinctBy(x => x.Id).Count());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_Descendants()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = CreateRepository(unitOfWork))
|
||||
{
|
||||
var created = CreateHierarchy(repository, unitOfWork).ToArray();
|
||||
|
||||
// Act
|
||||
var descendantsById = repository.GetDescendants(created[1].Id);
|
||||
var descendantsByAlias = repository.GetDescendants(created[1].Alias);
|
||||
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(3, descendantsById.Count());
|
||||
Assert.AreEqual(3, descendantsById.DistinctBy(x => x.Id).Count());
|
||||
|
||||
Assert.AreEqual(3, descendantsByAlias.Count());
|
||||
Assert.AreEqual(3, descendantsByAlias.DistinctBy(x => x.Id).Count());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -717,5 +742,82 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
private IEnumerable<ITemplate> CreateHierarchy(ITemplateRepository repository, IDatabaseUnitOfWork unitOfWork)
|
||||
{
|
||||
var parent = new Template("parent", "parent")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
|
||||
var child1 = new Template("child1", "child1")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
var toddler1 = new Template("toddler1", "toddler1")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
var toddler2 = new Template("toddler2", "toddler2")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
var baby1 = new Template("baby1", "baby1")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
|
||||
var child2 = new Template("child2", "child2")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
var toddler3 = new Template("toddler3", "toddler3")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
var toddler4 = new Template("toddler4", "toddler4")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
var baby2 = new Template("baby2", "baby2")
|
||||
{
|
||||
Content = @"<%@ Master Language=""C#"" %>"
|
||||
};
|
||||
|
||||
|
||||
child1.MasterTemplateAlias = parent.Alias;
|
||||
child1.MasterTemplateId = new Lazy<int>(() => parent.Id);
|
||||
child2.MasterTemplateAlias = parent.Alias;
|
||||
child2.MasterTemplateId = new Lazy<int>(() => parent.Id);
|
||||
|
||||
toddler1.MasterTemplateAlias = child1.Alias;
|
||||
toddler1.MasterTemplateId = new Lazy<int>(() => child1.Id);
|
||||
toddler2.MasterTemplateAlias = child1.Alias;
|
||||
toddler2.MasterTemplateId = new Lazy<int>(() => child1.Id);
|
||||
|
||||
toddler3.MasterTemplateAlias = child2.Alias;
|
||||
toddler3.MasterTemplateId = new Lazy<int>(() => child2.Id);
|
||||
toddler4.MasterTemplateAlias = child2.Alias;
|
||||
toddler4.MasterTemplateId = new Lazy<int>(() => child2.Id);
|
||||
|
||||
baby1.MasterTemplateAlias = toddler2.Alias;
|
||||
baby1.MasterTemplateId = new Lazy<int>(() => toddler2.Id);
|
||||
|
||||
baby2.MasterTemplateAlias = toddler4.Alias;
|
||||
baby2.MasterTemplateId = new Lazy<int>(() => toddler4.Id);
|
||||
|
||||
repository.AddOrUpdate(parent);
|
||||
repository.AddOrUpdate(child1);
|
||||
repository.AddOrUpdate(child2);
|
||||
repository.AddOrUpdate(toddler1);
|
||||
repository.AddOrUpdate(toddler2);
|
||||
repository.AddOrUpdate(toddler3);
|
||||
repository.AddOrUpdate(toddler4);
|
||||
repository.AddOrUpdate(baby1);
|
||||
repository.AddOrUpdate(baby2);
|
||||
unitOfWork.Commit();
|
||||
|
||||
return new[] {parent, child1, child2, toddler1, toddler2, toddler3, toddler4, baby1, baby2};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -454,6 +454,20 @@ namespace Umbraco.Tests.PublishedContent
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FirstChild()
|
||||
{
|
||||
var doc = GetNode(1173); // has child nodes
|
||||
Assert.IsNotNull(doc.FirstChild());
|
||||
Assert.IsNotNull(doc.FirstChild(x => true));
|
||||
Assert.IsNotNull(doc.FirstChild<IPublishedContent>());
|
||||
|
||||
doc = GetNode(1175); // does not have child nodes
|
||||
Assert.IsNull(doc.FirstChild());
|
||||
Assert.IsNull(doc.FirstChild(x => true));
|
||||
Assert.IsNull(doc.FirstChild<IPublishedContent>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasProperty()
|
||||
{
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Umbraco.Tests.Publishing
|
||||
ServiceContext.ContentTypeService.GetContentType("umbTextpage"), "Sub Sub Sub", mandatorContent.Id);
|
||||
ServiceContext.ContentService.Save(subContent, 0);
|
||||
|
||||
var strategy = new PublishingStrategy();
|
||||
var strategy = new PublishingStrategy(new TransientMessagesFactory(), Logger);
|
||||
|
||||
//publish root and nodes at it's children level
|
||||
var listToPublish = ServiceContext.ContentService.GetDescendants(_homePage.Id).Concat(new[] { _homePage });
|
||||
@@ -91,8 +91,8 @@ namespace Umbraco.Tests.Publishing
|
||||
{
|
||||
CreateTestData();
|
||||
|
||||
var strategy = new PublishingStrategy();
|
||||
|
||||
var strategy = new PublishingStrategy(new TransientMessagesFactory(), Logger);
|
||||
|
||||
|
||||
PublishingStrategy.Publishing +=PublishingStrategyPublishing;
|
||||
|
||||
@@ -118,8 +118,8 @@ namespace Umbraco.Tests.Publishing
|
||||
{
|
||||
CreateTestData();
|
||||
|
||||
var strategy = new PublishingStrategy();
|
||||
|
||||
var strategy = new PublishingStrategy(new TransientMessagesFactory(), Logger);
|
||||
|
||||
//publish root and nodes at it's children level
|
||||
var result1 = strategy.Publish(_homePage, 0);
|
||||
Assert.IsTrue(result1);
|
||||
@@ -145,7 +145,7 @@ namespace Umbraco.Tests.Publishing
|
||||
{
|
||||
CreateTestData();
|
||||
|
||||
var strategy = new PublishingStrategy();
|
||||
var strategy = new PublishingStrategy(new TransientMessagesFactory(), Logger);
|
||||
|
||||
//publish root and nodes at it's children level
|
||||
var result1 = strategy.Publish(_homePage, 0);
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
SetupDomainServiceMock(new[]
|
||||
{
|
||||
new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangDeId, RootContentId = 1001}
|
||||
new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangDeId, RootContentId = 1001, LanguageIsoCode = "de-DE"}
|
||||
});
|
||||
|
||||
}
|
||||
@@ -22,12 +22,12 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
SetupDomainServiceMock(new[]
|
||||
{
|
||||
new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001},
|
||||
new UmbracoDomain("domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011},
|
||||
new UmbracoDomain("domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012},
|
||||
new UmbracoDomain("http://domain3.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1003},
|
||||
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031},
|
||||
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032}
|
||||
new UmbracoDomain("domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
|
||||
new UmbracoDomain("http://domain3.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1003, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -30,19 +30,22 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangDeId,
|
||||
RootContentId = 1001
|
||||
RootContentId = 1001,
|
||||
LanguageIsoCode = "de-DE"
|
||||
},
|
||||
new UmbracoDomain("domain1.com/en")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangEngId,
|
||||
RootContentId = 10011
|
||||
RootContentId = 10011,
|
||||
LanguageIsoCode = "en-US"
|
||||
},
|
||||
new UmbracoDomain("domain1.com/fr")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangFrId,
|
||||
RootContentId = 10012
|
||||
RootContentId = 10012,
|
||||
LanguageIsoCode = "fr-FR"
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -55,55 +58,64 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangDeId,
|
||||
RootContentId = 1001
|
||||
RootContentId = 1001,
|
||||
LanguageIsoCode = "de-DE"
|
||||
},
|
||||
new UmbracoDomain("domain1.com/en")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangEngId,
|
||||
RootContentId = 10011
|
||||
RootContentId = 10011,
|
||||
LanguageIsoCode = "en-US"
|
||||
},
|
||||
new UmbracoDomain("domain1.com/fr")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangFrId,
|
||||
RootContentId = 10012
|
||||
RootContentId = 10012,
|
||||
LanguageIsoCode = "fr-FR"
|
||||
},
|
||||
new UmbracoDomain("*1001")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangDeId,
|
||||
RootContentId = 1001
|
||||
RootContentId = 1001,
|
||||
LanguageIsoCode = "de-DE"
|
||||
},
|
||||
new UmbracoDomain("*10011")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangCzId,
|
||||
RootContentId = 10011
|
||||
RootContentId = 10011,
|
||||
LanguageIsoCode = "cs-CZ"
|
||||
},
|
||||
new UmbracoDomain("*100112")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangNlId,
|
||||
RootContentId = 100112
|
||||
RootContentId = 100112,
|
||||
LanguageIsoCode = "nl-NL"
|
||||
},
|
||||
new UmbracoDomain("*1001122")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangDkId,
|
||||
RootContentId = 1001122
|
||||
RootContentId = 1001122,
|
||||
LanguageIsoCode = "da-DK"
|
||||
},
|
||||
new UmbracoDomain("*10012")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangNlId,
|
||||
RootContentId = 10012
|
||||
RootContentId = 10012,
|
||||
LanguageIsoCode = "nl-NL"
|
||||
},
|
||||
new UmbracoDomain("*10031")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangNlId,
|
||||
RootContentId =10031
|
||||
RootContentId =10031,
|
||||
LanguageIsoCode = "nl-NL"
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -343,19 +355,22 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangEngId,
|
||||
RootContentId = 1001
|
||||
RootContentId = 1001,
|
||||
LanguageIsoCode = "en-US"
|
||||
},
|
||||
new UmbracoDomain("domain1.fr/")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangFrId,
|
||||
RootContentId = 1001
|
||||
RootContentId = 1001,
|
||||
LanguageIsoCode = "fr-FR"
|
||||
},
|
||||
new UmbracoDomain("*100112")
|
||||
{
|
||||
Id = 1,
|
||||
LanguageId = LangDeId,
|
||||
RootContentId = 100112
|
||||
RootContentId = 100112,
|
||||
LanguageIsoCode = "de-DE"
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Umbraco.Tests.Routing
|
||||
|
||||
SetupDomainServiceMock(new[]
|
||||
{
|
||||
new UmbracoDomain("domain1.com") {Id = 1, LanguageId = LangFrId, RootContentId = 1001}
|
||||
new UmbracoDomain("domain1.com") {Id = 1, LanguageId = LangFrId, RootContentId = 1001, LanguageIsoCode = "fr-FR"}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
SetupDomainServiceMock(new[]
|
||||
{
|
||||
new UmbracoDomain("http://domain1.com/foo") {Id = 1, LanguageId = LangFrId, RootContentId = 1001}
|
||||
new UmbracoDomain("http://domain1.com/foo") {Id = 1, LanguageId = LangFrId, RootContentId = 1001, LanguageIsoCode = "fr-FR"}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
SetupDomainServiceMock(new[]
|
||||
{
|
||||
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangFrId, RootContentId = 10011}
|
||||
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangFrId, RootContentId = 10011, LanguageIsoCode = "fr-FR"}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -52,12 +52,12 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
SetupDomainServiceMock(new[]
|
||||
{
|
||||
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001},
|
||||
new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011},
|
||||
new UmbracoDomain("http://domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012},
|
||||
new UmbracoDomain("http://domain3.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1003},
|
||||
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031},
|
||||
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032}
|
||||
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("http://domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
|
||||
new UmbracoDomain("http://domain3.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1003, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -65,14 +65,14 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
SetupDomainServiceMock(new[]
|
||||
{
|
||||
new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011},
|
||||
new UmbracoDomain("http://domain1a.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011},
|
||||
new UmbracoDomain("http://domain1b.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011},
|
||||
new UmbracoDomain("http://domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012},
|
||||
new UmbracoDomain("http://domain1a.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012},
|
||||
new UmbracoDomain("http://domain1b.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012},
|
||||
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031},
|
||||
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032}
|
||||
new UmbracoDomain("http://domain1.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("http://domain1a.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("http://domain1b.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("http://domain1.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
|
||||
new UmbracoDomain("http://domain1a.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
|
||||
new UmbracoDomain("http://domain1b.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"},
|
||||
new UmbracoDomain("http://domain3.com/en") {Id = 1, LanguageId = LangEngId, RootContentId = 10031, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("http://domain3.com/fr") {Id = 1, LanguageId = LangFrId, RootContentId = 10032, LanguageIsoCode = "fr-FR"}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -42,19 +42,10 @@ namespace Umbraco.Tests.Routing
|
||||
domainService.Setup(service => service.GetAll(It.IsAny<bool>()))
|
||||
.Returns((bool incWildcards) => new[]
|
||||
{
|
||||
new UmbracoDomain("domain1.com/"){Id = 1, LanguageId = 333, RootContentId = 1001},
|
||||
new UmbracoDomain("domain1.com/en"){Id = 1, LanguageId = 334, RootContentId = 10011},
|
||||
new UmbracoDomain("domain1.com/fr"){Id = 1, LanguageId = 335, RootContentId = 10012}
|
||||
});
|
||||
|
||||
var langService = Mock.Get(svcCtx.LocalizationService);
|
||||
//setup mock domain service
|
||||
langService.Setup(service => service.GetLanguageById(LangDeId)).Returns(new Language("de-DE") {Id = LangDeId });
|
||||
langService.Setup(service => service.GetLanguageById(LangEngId)).Returns(new Language("en-US") { Id = LangEngId });
|
||||
langService.Setup(service => service.GetLanguageById(LangFrId)).Returns(new Language("fr-FR") { Id = LangFrId });
|
||||
langService.Setup(service => service.GetLanguageById(LangCzId)).Returns(new Language("cs-CZ") { Id = LangCzId });
|
||||
langService.Setup(service => service.GetLanguageById(LangNlId)).Returns(new Language("nl-NL") { Id = LangNlId });
|
||||
langService.Setup(service => service.GetLanguageById(LangDkId)).Returns(new Language("da-DK") { Id = LangDkId });
|
||||
new UmbracoDomain("domain1.com/"){Id = 1, LanguageId = LangDeId, RootContentId = 1001, LanguageIsoCode = "de-DE"},
|
||||
new UmbracoDomain("domain1.com/en"){Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("domain1.com/fr"){Id = 1, LanguageId = LangFrId, RootContentId = 10012, LanguageIsoCode = "fr-FR"}
|
||||
});
|
||||
|
||||
return svcCtx;
|
||||
}
|
||||
|
||||
@@ -80,8 +80,8 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
SetupDomainServiceMock(new[]
|
||||
{
|
||||
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001},
|
||||
new UmbracoDomain("http://domain2.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 10011}
|
||||
new UmbracoDomain("http://domain1.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 1001, LanguageIsoCode = "en-US"},
|
||||
new UmbracoDomain("http://domain2.com/") {Id = 1, LanguageId = LangEngId, RootContentId = 10011, LanguageIsoCode = "en-US"}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -50,14 +50,15 @@ namespace Umbraco.Tests.Services
|
||||
//we need a new Database object for each thread.
|
||||
var repositoryFactory = new RepositoryFactory(cacheHelper, Logger, SqlSyntax, SettingsForTests.GenerateMockSettings());
|
||||
_uowProvider = new PerThreadPetaPocoUnitOfWorkProvider(_dbFactory);
|
||||
ApplicationContext.Services = new ServiceContext(
|
||||
var evtMsgs = new TransientMessagesFactory();
|
||||
ApplicationContext.Services = new ServiceContext(
|
||||
repositoryFactory,
|
||||
_uowProvider,
|
||||
new FileUnitOfWorkProvider(),
|
||||
new PublishingStrategy(),
|
||||
new PublishingStrategy(evtMsgs, Logger),
|
||||
cacheHelper,
|
||||
Logger,
|
||||
new TransientMessagesFactory());
|
||||
evtMsgs);
|
||||
|
||||
CreateTestData();
|
||||
}
|
||||
|
||||
@@ -24,6 +24,18 @@ namespace Umbraco.Tests.Strings
|
||||
ShortStringHelperResolver.Reset();
|
||||
}
|
||||
|
||||
[TestCase("hello", "world", false)]
|
||||
[TestCase("hello", "hello", true)]
|
||||
[TestCase("hellohellohellohellohellohellohello", "hellohellohellohellohellohellohelloo", false)]
|
||||
[TestCase("hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohelloo", false)]
|
||||
[TestCase("hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", true)]
|
||||
public void String_To_Guid(string first, string second, bool result)
|
||||
{
|
||||
Console.WriteLine("First: " + first.ToGuid());
|
||||
Console.WriteLine("Second: " + second.ToGuid());
|
||||
Assert.AreEqual(result, first.ToGuid() == second.ToGuid());
|
||||
}
|
||||
|
||||
[TestCase("alert('hello');", false)]
|
||||
[TestCase("~/Test.js", true)]
|
||||
[TestCase("../Test.js", true)]
|
||||
|
||||
@@ -76,11 +76,12 @@ namespace Umbraco.Tests.TestHelpers
|
||||
|
||||
var repositoryFactory = new RepositoryFactory(cacheHelper, Logger, SqlSyntax, SettingsForTests.GenerateMockSettings());
|
||||
|
||||
var evtMsgs = new TransientMessagesFactory();
|
||||
_appContext = new ApplicationContext(
|
||||
//assign the db context
|
||||
new DatabaseContext(dbFactory, Logger, SqlSyntax, "System.Data.SqlServerCe.4.0"),
|
||||
//assign the service context
|
||||
new ServiceContext(repositoryFactory, new PetaPocoUnitOfWorkProvider(dbFactory), new FileUnitOfWorkProvider(), new PublishingStrategy(), cacheHelper, Logger, new TransientMessagesFactory()),
|
||||
new ServiceContext(repositoryFactory, new PetaPocoUnitOfWorkProvider(dbFactory), new FileUnitOfWorkProvider(), new PublishingStrategy(evtMsgs, Logger), cacheHelper, Logger, evtMsgs),
|
||||
cacheHelper,
|
||||
ProfilingLogger)
|
||||
{
|
||||
|
||||
@@ -153,12 +153,13 @@ namespace Umbraco.Tests.TestHelpers
|
||||
var sqlSyntax = new SqlCeSyntaxProvider();
|
||||
var repoFactory = new RepositoryFactory(CacheHelper.CreateDisabledCacheHelper(), Logger, sqlSyntax, SettingsForTests.GenerateMockSettings());
|
||||
|
||||
var evtMsgs = new TransientMessagesFactory();
|
||||
ApplicationContext.Current = new ApplicationContext(
|
||||
//assign the db context
|
||||
new DatabaseContext(new DefaultDatabaseFactory(Core.Configuration.GlobalSettings.UmbracoConnectionName, Logger),
|
||||
Logger, sqlSyntax, "System.Data.SqlServerCe.4.0"),
|
||||
//assign the service context
|
||||
new ServiceContext(repoFactory, new PetaPocoUnitOfWorkProvider(Logger), new FileUnitOfWorkProvider(), new PublishingStrategy(), CacheHelper, Logger, new TransientMessagesFactory()),
|
||||
new ServiceContext(repoFactory, new PetaPocoUnitOfWorkProvider(Logger), new FileUnitOfWorkProvider(), new PublishingStrategy(evtMsgs, Logger), CacheHelper, Logger, evtMsgs),
|
||||
CacheHelper,
|
||||
ProfilingLogger)
|
||||
{
|
||||
|
||||
@@ -51,16 +51,16 @@
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
|
||||
<Reference Include="AutoMapper, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
<Reference Include="AutoMapper.Net4, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Examine, Version=0.1.66.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.66.0\lib\Examine.dll</HintPath>
|
||||
<Reference Include="Examine, Version=0.1.68.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.68.0\lib\Examine.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
@@ -79,9 +79,6 @@
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.Mvc.FixedDisplayModes">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Mvc.FixedDisplayModes.1.0.1\lib\net40\Microsoft.Web.Mvc.FixedDisplayModes.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MiniProfiler, Version=2.1.0.0, Culture=neutral, PublicKeyToken=b44f9351044011a3, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll</HintPath>
|
||||
@@ -124,9 +121,9 @@
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.ApplicationServices" />
|
||||
<Reference Include="System.Web.Helpers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Http, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
@@ -139,25 +136,26 @@
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Mvc, Version=4.0.0.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Reference Include="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.Mvc.4.0.40804.0\lib\net40\System.Web.Mvc.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Services" />
|
||||
<Reference Include="System.Web.WebPages, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages.Deployment, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
@@ -178,6 +176,7 @@
|
||||
<Compile Include="Cache\CacheRefresherTests.cs" />
|
||||
<Compile Include="Cache\DeepCloneRuntimeCacheProviderTests.cs" />
|
||||
<Compile Include="Controllers\BackOfficeControllerUnitTests.cs" />
|
||||
<Compile Include="DelegateExtensionsTests.cs" />
|
||||
<Compile Include="Logging\AsyncRollingFileAppenderTest.cs" />
|
||||
<Compile Include="Logging\DebugAppender.cs" />
|
||||
<Compile Include="Logging\ParallelForwarderTest.cs" />
|
||||
@@ -732,7 +731,6 @@
|
||||
xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\" /Y /F /E /D</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
<Import Project="..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets" Condition="Exists('..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="AspNetWebApi.SelfHost" version="4.0.20710.0" targetFramework="net45" />
|
||||
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.66.0" targetFramework="net45" />
|
||||
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.68.0" targetFramework="net45" />
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net45" />
|
||||
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Mvc" version="4.0.40804.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.1" />
|
||||
<package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.WebApi.SelfHost" version="4.0.30506.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.3" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.WebPages" version="2.0.30506.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net45" />
|
||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
|
||||
<package id="MiniProfiler" version="2.1.0" targetFramework="net45" />
|
||||
<package id="Moq" version="4.1.1309.0919" targetFramework="net45" />
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
"jquery-ui": "1.10.3",
|
||||
"angular-dynamic-locale": "~0.1.27",
|
||||
"tinymce": "~4.1.10",
|
||||
"bootstrap-tabdrop": "~1.0.0",
|
||||
"codemirror": "~5.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,7 +418,8 @@ module.exports = function (grunt) {
|
||||
ignorePackages: ['blueimp-canvas-to-blob', 'blueimp-tmpl', 'bootstrap'],
|
||||
packageSpecific: {
|
||||
'typeahead.js': {
|
||||
keepExpandedHierarchy: false
|
||||
keepExpandedHierarchy: false,
|
||||
files: ['dist/typeahead.bundle.min.js']
|
||||
},
|
||||
'underscore': {
|
||||
files: ['underscore-min.js', 'underscore-min.map']
|
||||
@@ -455,11 +456,7 @@ module.exports = function (grunt) {
|
||||
},
|
||||
'angular-dynamic-locale': {
|
||||
files: ['tmhDynamicLocale.min.js', 'tmhDynamicLocale.min.js.map']
|
||||
},
|
||||
'bootstrap-tabdrop': {
|
||||
keepExpandedHierarchy: false,
|
||||
files: ['build/js/bootstrap-tabdrop.min.js']
|
||||
},
|
||||
},
|
||||
'codemirror': {
|
||||
files: [
|
||||
'lib/codemirror.js',
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
bootstrap-tabdrop
|
||||
=================
|
||||
|
||||
*****************************************************************
|
||||
NOTE: THIS IS A CUSTOM FIXED VERSION!!!!!!!!!!!!!!!!!!!!!!
|
||||
- THE ORIGINAL HAS A MEMORY LEAK, SO WE'VE HAD TO EMBED THIS
|
||||
INTO THE CORE WITH THE FIX
|
||||
|
||||
--- UMBRACO CORE TEAM
|
||||
*****************************************************************
|
||||
|
||||
A dropdown tab tool for @twitter bootstrap forked from Stefan Petre's (of eyecon.ro),
|
||||
|
||||
The dropdown tab appears when your tabs do not all fit in the same row.
|
||||
|
||||
Original site and examples: http://www.eyecon.ro/bootstrap-tabdrop/
|
||||
|
||||
Added functionality: Displays the text of an active tab selected from the dropdown list instead of the text option on the dropdown tab.
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
* [Bootstrap](http://twitter.github.com/bootstrap/) 2.0.4+
|
||||
* [jQuery](http://jquery.com/) 1.7.1+
|
||||
|
||||
## Example
|
||||
|
||||
No additional HTML needed - the script adds it when the dropdown tab is needed.
|
||||
|
||||
Using bootstrap-tabdrop.js
|
||||
Call the tab drop via javascript on .nav-tabs and .nav-pills:
|
||||
```js
|
||||
$('.nav-pills, .nav-tabs').tabdrop()
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
#### text
|
||||
Type: string
|
||||
Default: icon
|
||||
```html
|
||||
<i class="icon-align-justify"></i>
|
||||
```
|
||||
To change the default value, call
|
||||
```javascript
|
||||
.tabdrop({text: "your text here"});
|
||||
```
|
||||
when initalizing the tabdrop. The displayed value will change when a tab is selected from the dropdown list.
|
||||
|
||||
### Methods
|
||||
|
||||
```js
|
||||
.tabdrop(options)
|
||||
```
|
||||
|
||||
Initializes an tab drop.
|
||||
|
||||
```js
|
||||
.tabdrop('layout')
|
||||
```
|
||||
|
||||
Checks if the tabs fit in one single row.
|
||||
@@ -0,0 +1,132 @@
|
||||
/* =========================================================
|
||||
* bootstrap-tabdrop.js
|
||||
* http://www.eyecon.ro/bootstrap-tabdrop
|
||||
* =========================================================
|
||||
* Copyright 2012 Stefan Petre
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ========================================================= */
|
||||
|
||||
/*****************************************************************
|
||||
* NOTE: THIS IS A CUSTOM FIXED VERSION!!!!!!!!!!!!!!!!!!!!!!
|
||||
* - THE ORIGINAL HAS A MEMORY LEAK, SO WE'VE HAD TO EMBED THIS
|
||||
* INTO THE CORE WITH THE FIX
|
||||
*
|
||||
* --- UMBRACO CORE TEAM
|
||||
*****************************************************************/
|
||||
|
||||
!function( $ ) {
|
||||
|
||||
var WinReszier = (function(){
|
||||
var registered = [];
|
||||
var inited = false;
|
||||
var timer;
|
||||
var resize = function(ev) {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(notify, 100);
|
||||
};
|
||||
var notify = function() {
|
||||
for(var i=0, cnt=registered.length; i<cnt; i++) {
|
||||
registered[i].apply();
|
||||
}
|
||||
};
|
||||
return {
|
||||
register: function(fn) {
|
||||
registered.push(fn);
|
||||
if (inited === false) {
|
||||
$(window).bind('resize', resize);
|
||||
inited = true;
|
||||
}
|
||||
},
|
||||
unregister: function(fn) {
|
||||
var index = registered.indexOf(fn);
|
||||
if (index > -1) {
|
||||
registered.splice(index, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
||||
var TabDrop = function(element, options) {
|
||||
this.element = $(element);
|
||||
this.dropdown = $('<li class="dropdown hide pull-right tabdrop">' +
|
||||
'<a class="dropdown-toggle" data-toggle="dropdown" href="#">' +
|
||||
options.text + ' <b class="caret"></b></a>' +
|
||||
'<ul class="dropdown-menu"></ul></li>').prependTo(this.element);
|
||||
if (this.element.parent().is('.tabs-below')) {
|
||||
this.dropdown.addClass('dropup');
|
||||
}
|
||||
this.resizeCallback = $.proxy(this.layout, this);
|
||||
WinReszier.register(this.resizeCallback);
|
||||
this.layout();
|
||||
};
|
||||
|
||||
TabDrop.prototype = {
|
||||
constructor: TabDrop,
|
||||
|
||||
layout: function() {
|
||||
var collection = [];
|
||||
this.dropdown.removeClass('hide');
|
||||
this.element
|
||||
.append(this.dropdown.find('li'))
|
||||
.find('>li')
|
||||
.not('.tabdrop')
|
||||
.each(function(){
|
||||
if(this.offsetTop > 0) {
|
||||
collection.push(this);
|
||||
}
|
||||
});
|
||||
if (collection.length > 0) {
|
||||
collection = $(collection);
|
||||
this.dropdown
|
||||
.find('ul')
|
||||
.empty()
|
||||
.append(collection);
|
||||
if (this.dropdown.find('.active').length == 1) {
|
||||
this.dropdown.addClass('active');
|
||||
} else {
|
||||
this.dropdown.removeClass('active');
|
||||
}
|
||||
} else {
|
||||
this.dropdown.addClass('hide');
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.dropdown.html();
|
||||
WinReszier.unregister(this.resizeCallback);
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.tabdrop = function ( option ) {
|
||||
return this.each(function () {
|
||||
var $this = $(this),
|
||||
data = $this.data('tabdrop'),
|
||||
options = typeof option === 'object' && option;
|
||||
if (!data) {
|
||||
$this.data('tabdrop', (data = new TabDrop(this, $.extend({},
|
||||
$.fn.tabdrop.defaults,options))));
|
||||
}
|
||||
if (typeof option == 'string') {
|
||||
data[option]();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.tabdrop.defaults = {
|
||||
text: '<i class="icon-align-justify"></i>'
|
||||
};
|
||||
|
||||
$.fn.tabdrop.Constructor = TabDrop;
|
||||
|
||||
}(window.jQuery);
|
||||
+35
-26
@@ -1,32 +1,41 @@
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbAutoResize', function($timeout) {
|
||||
return {
|
||||
require: "^?umbTabs",
|
||||
link: function(scope, element, attr, tabsCtrl) {
|
||||
var domEl = element[0];
|
||||
var update = function(force) {
|
||||
if (force === true) {
|
||||
element.height(0);
|
||||
}
|
||||
|
||||
return function(scope, element, attr){
|
||||
var domEl = element[0];
|
||||
var update = function(force) {
|
||||
if (domEl.scrollHeight !== domEl.clientHeight) {
|
||||
element.height(domEl.scrollHeight);
|
||||
}
|
||||
};
|
||||
var blur = function() {
|
||||
update(true);
|
||||
};
|
||||
|
||||
if(force === true){
|
||||
element.height(0);
|
||||
element.bind('keyup keydown keypress change', update);
|
||||
element.bind('blur', blur);
|
||||
|
||||
$timeout(function() {
|
||||
update(true);
|
||||
}, 200);
|
||||
|
||||
|
||||
//listen for tab changes
|
||||
if (tabsCtrl != null) {
|
||||
tabsCtrl.onTabShown(function(args) {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
if(domEl.scrollHeight !== domEl.clientHeight){
|
||||
element.height(domEl.scrollHeight);
|
||||
}
|
||||
};
|
||||
|
||||
element.bind('keyup keydown keypress change', update);
|
||||
element.bind('blur', function(){ update(true); });
|
||||
|
||||
$timeout(function() {
|
||||
update(true);
|
||||
}, 200);
|
||||
|
||||
|
||||
//I hate bootstrap tabs
|
||||
$('a[data-toggle="tab"]').on('shown', update);
|
||||
|
||||
scope.$on('$destroy', function() {
|
||||
$('a[data-toggle="tab"]').unbind("shown", update);
|
||||
});
|
||||
};
|
||||
});
|
||||
scope.$on('$destroy', function () {
|
||||
element.unbind('keyup keydown keypress change', update);
|
||||
element.unbind('blur', blur);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbHeader
|
||||
* @restrict E
|
||||
* @function
|
||||
* @description
|
||||
* The header on an editor that contains tabs using bootstrap tabs - THIS IS OBSOLETE, use umbTabHeader instead
|
||||
**/
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbHeader', function($parse, $timeout){
|
||||
.directive('umbHeader', function ($parse, $timeout) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
@@ -11,50 +19,13 @@ angular.module("umbraco.directives")
|
||||
tabs: "="
|
||||
},
|
||||
link: function (scope, iElement, iAttrs) {
|
||||
|
||||
var maxTabs = 4;
|
||||
|
||||
function collectFromDom(activeTab){
|
||||
var $panes = $('div.tab-content');
|
||||
|
||||
angular.forEach($panes.find('.tab-pane'), function (pane, index) {
|
||||
var $this = angular.element(pane);
|
||||
|
||||
var id = $this.attr("rel");
|
||||
var label = $this.attr("label");
|
||||
var tab = {id: id, label: label, active: false};
|
||||
if(!activeTab){
|
||||
tab.active = true;
|
||||
activeTab = tab;
|
||||
}
|
||||
|
||||
if ($this.attr("rel") === String(activeTab.id)) {
|
||||
$this.addClass('active');
|
||||
}
|
||||
else {
|
||||
$this.removeClass('active');
|
||||
}
|
||||
|
||||
if(label){
|
||||
scope.visibleTabs.push(tab);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$('.nav-pills, .nav-tabs').tabdrop();
|
||||
}
|
||||
|
||||
|
||||
scope.showTabs = iAttrs.tabs ? true : false;
|
||||
scope.visibleTabs = [];
|
||||
scope.overflownTabs = [];
|
||||
|
||||
$timeout(function () {
|
||||
collectFromDom(undefined);
|
||||
}, 500);
|
||||
|
||||
//when the tabs change, we need to hack the planet a bit and force the first tab content to be active,
|
||||
//unfortunately twitter bootstrap tabs is not playing perfectly with angular.
|
||||
scope.$watch("tabs", function (newValue, oldValue) {
|
||||
//since tabs are loaded async, we need to put a watch on them to determine
|
||||
// when they are loaded, then we can close the watch
|
||||
var tabWatch = scope.$watch("tabs", function (newValue, oldValue) {
|
||||
|
||||
angular.forEach(newValue, function(val, index){
|
||||
var tab = {id: val.id, label: val.label};
|
||||
@@ -64,16 +35,25 @@ angular.module("umbraco.directives")
|
||||
//don't process if we cannot or have already done so
|
||||
if (!newValue) {return;}
|
||||
if (!newValue.length || newValue.length === 0){return;}
|
||||
|
||||
var activeTab = _.find(newValue, function (item) {
|
||||
return item.active;
|
||||
});
|
||||
|
||||
|
||||
//we need to do a timeout here so that the current sync operation can complete
|
||||
// and update the UI, then this will fire and the UI elements will be available.
|
||||
$timeout(function () {
|
||||
collectFromDom(activeTab);
|
||||
}, 500);
|
||||
|
||||
//use bootstrap tabs API to show the first one
|
||||
iElement.find(".nav-tabs a:first").tab('show');
|
||||
|
||||
//enable the tab drop
|
||||
iElement.find('.nav-pills, .nav-tabs').tabdrop();
|
||||
|
||||
//ensure to destroy tabdrop (unbinds window resize listeners)
|
||||
scope.$on('$destroy', function () {
|
||||
iElement.find('.nav-pills, .nav-tabs').tabdrop("destroy");
|
||||
});
|
||||
|
||||
//stop watching now
|
||||
tabWatch();
|
||||
}, 200);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
* @restrict E
|
||||
**/
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbTab', function(){
|
||||
return {
|
||||
.directive('umbTab', function ($parse, $timeout) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
transclude: 'true',
|
||||
templateUrl: 'views/directives/umb-tab.html'
|
||||
};
|
||||
replace: true,
|
||||
transclude: 'true',
|
||||
templateUrl: 'views/directives/umb-tab.html'
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbTabs
|
||||
* @restrict A
|
||||
* @description Used to bind to bootstrap tab events so that sub directives can use this API to listen to tab changes
|
||||
**/
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbTabs', function () {
|
||||
return {
|
||||
restrict: 'A',
|
||||
controller: function ($scope, $element, $attrs) {
|
||||
|
||||
var callbacks = [];
|
||||
this.onTabShown = function(cb) {
|
||||
callbacks.push(cb);
|
||||
};
|
||||
|
||||
function tabShown(event) {
|
||||
|
||||
var curr = $(event.target); // active tab
|
||||
var prev = $(event.relatedTarget); // previous tab
|
||||
|
||||
for (var c in callbacks) {
|
||||
callbacks[c].apply(this, [{current: curr, previous: prev}]);
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: it MUST be done this way - binding to an ancestor element that exists
|
||||
// in the DOM to bind to the dynamic elements that will be created.
|
||||
// It would be nicer to create this event handler as a directive for which child
|
||||
// directives can attach to.
|
||||
$element.on('shown', '.nav-tabs a', tabShown);
|
||||
|
||||
//ensure to unregister
|
||||
$scope.$on('$destroy', function () {
|
||||
$element.off('shown', '.nav-tabs a', tabShown);
|
||||
|
||||
for (var c in callbacks) {
|
||||
delete callbacks[c];
|
||||
}
|
||||
callbacks = null;
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -64,6 +64,13 @@ function umbImageFolder($rootScope, assetsService, $timeout, $log, umbRequestHel
|
||||
found.completed = true;
|
||||
}
|
||||
|
||||
//Show notifications!!!!
|
||||
if (data.result && data.result.notifications && angular.isArray(data.result.notifications)) {
|
||||
for (var n = 0; n < data.result.notifications.length; n++) {
|
||||
notificationsService.showNotification(data.result.notifications[n]);
|
||||
}
|
||||
}
|
||||
|
||||
//when none are left resync everything
|
||||
var remaining = _.filter(scope.files, function (file) { return file.completed !== true; });
|
||||
if (remaining.length === 0) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Handles how the navigation responds to window resizing and controls how the draggable resize panel works
|
||||
**/
|
||||
angular.module("umbraco.directives")
|
||||
.directive('navResize', function (appState, eventsService) {
|
||||
.directive('navResize', function (appState, eventsService, windowResizeListener) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function (scope, element, attrs, ctrl) {
|
||||
@@ -22,22 +22,28 @@ angular.module("umbraco.directives")
|
||||
function enableResize() {
|
||||
//only enable when the size is correct and it's not already enabled
|
||||
if (!resizeEnabled && appState.getGlobalState("isTablet") === false) {
|
||||
element.find(".navigation-inner-container").resizable(
|
||||
element.resizable(
|
||||
{
|
||||
containment: $("#mainwrapper"),
|
||||
autoHide: true,
|
||||
handles: 'e',
|
||||
handles: "e",
|
||||
alsoResize: ".navigation-inner-container",
|
||||
resize: function(e, ui) {
|
||||
var wrapper = $("#mainwrapper");
|
||||
var contentPanel = $("#leftcolumn").next();
|
||||
var contentPanel = $("#contentwrapper");
|
||||
var apps = $("#applications");
|
||||
var navOffeset = ui.element.next();
|
||||
var bottomBar = contentPanel.find(".umb-bottom-bar");
|
||||
var navOffeset = $("#navOffset");
|
||||
|
||||
var leftPanelWidth = ui.element.width() + apps.width();
|
||||
|
||||
contentPanel.css({ left: leftPanelWidth });
|
||||
bottomBar.css({ left: leftPanelWidth });
|
||||
|
||||
navOffeset.css({ "margin-left": ui.element.outerWidth() });
|
||||
},
|
||||
stop: function(e, ui) {
|
||||
stop: function (e, ui) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -47,14 +53,14 @@ angular.module("umbraco.directives")
|
||||
|
||||
function resetResize() {
|
||||
if (resizeEnabled) {
|
||||
var navInnerContainer = element.find(".navigation-inner-container");
|
||||
|
||||
//kill the resize
|
||||
navInnerContainer.resizable("destroy");
|
||||
element.resizable("destroy");
|
||||
|
||||
element.css("width", "");
|
||||
var navInnerContainer = element.find(".navigation-inner-container");
|
||||
navInnerContainer.css("width", "");
|
||||
$("#leftcolumn").next().css("left", "");
|
||||
navInnerContainer.next().css("margin-left", "");
|
||||
$("#contentwrapper").css("left", "");
|
||||
$("#navOffset").css("margin-left", "");
|
||||
|
||||
resizeEnabled = false;
|
||||
}
|
||||
@@ -74,16 +80,17 @@ angular.module("umbraco.directives")
|
||||
}
|
||||
}));
|
||||
|
||||
$(window).bind("resize", function () {
|
||||
|
||||
var resizeCallback = function(size) {
|
||||
//set the global app state
|
||||
appState.setGlobalState("isTablet", ($(window).width() <= minScreenSize));
|
||||
|
||||
appState.setGlobalState("isTablet", (size.width <= minScreenSize));
|
||||
setTreeMode();
|
||||
});
|
||||
};
|
||||
|
||||
windowResizeListener.register(resizeCallback);
|
||||
|
||||
//ensure to unregister from all events and kill jquery plugins
|
||||
scope.$on('$destroy', function () {
|
||||
windowResizeListener.unregister(resizeCallback);
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
@@ -91,7 +98,6 @@ angular.module("umbraco.directives")
|
||||
navInnerContainer.resizable("destroy");
|
||||
});
|
||||
|
||||
|
||||
//init
|
||||
//set the global app state
|
||||
appState.setGlobalState("isTablet", ($(window).width() <= minScreenSize));
|
||||
|
||||
@@ -37,8 +37,7 @@ angular.module("umbraco.directives")
|
||||
template: '<li ng-class="{\'current\': (node == currentNode)}" on-right-click="altSelect(node, $event)">' +
|
||||
'<div ng-class="getNodeCssClass(node)" ng-swipe-right="options(node, $event)" >' +
|
||||
//NOTE: This ins element is used to display the search icon if the node is a container/listview and the tree is currently in dialog
|
||||
//'<ins ng-if="tree.enablelistviewsearch && node.metaData.isContainer" class="umb-tree-node-search icon-search" ng-click="searchNode(node, $event)" alt="searchAltText"></ins>' +
|
||||
'<ins style="width:18px;"></ins>' +
|
||||
//'<ins ng-if="tree.enablelistviewsearch && node.metaData.isContainer" class="umb-tree-node-search icon-search" ng-click="searchNode(node, $event)" alt="searchAltText"></ins>' +
|
||||
'<ins ng-class="{\'icon-navigation-right\': !node.expanded, \'icon-navigation-down\': node.expanded}" ng-click="load(node)"></ins>' +
|
||||
'<i class="icon umb-tree-icon sprTree"></i>' +
|
||||
'<a ng-click="select(node, $event)"></a>' +
|
||||
@@ -87,7 +86,7 @@ angular.module("umbraco.directives")
|
||||
icon.addClass(node.cssClass);
|
||||
icon.attr("title", node.routePath);
|
||||
|
||||
element.find("a:first").html(node.name);
|
||||
element.find("a:first").text(node.name);
|
||||
|
||||
if (!node.menuUrl) {
|
||||
element.find("a.umb-options").remove();
|
||||
|
||||
+17
-7
@@ -5,21 +5,31 @@ angular.module("umbraco.directives")
|
||||
link: function (scope, element, attrs, ctrl) {
|
||||
var active = false;
|
||||
var fn = $parse(attrs.delayedMouseleave);
|
||||
element.on("mouseleave", function(event) {
|
||||
var callback = function() {
|
||||
fn(scope, {$event:event});
|
||||
|
||||
function mouseLeave(event) {
|
||||
var callback = function () {
|
||||
fn(scope, { $event: event });
|
||||
};
|
||||
|
||||
active = false;
|
||||
$timeout(function(){
|
||||
if(active === false){
|
||||
$timeout(function () {
|
||||
if (active === false) {
|
||||
scope.$apply(callback);
|
||||
}
|
||||
}, 650);
|
||||
});
|
||||
}
|
||||
|
||||
element.on("mouseenter", function(event, args){
|
||||
function mouseEnter(event, args){
|
||||
active = true;
|
||||
}
|
||||
|
||||
element.on("mouseleave", mouseLeave);
|
||||
element.on("mouseenter", mouseEnter);
|
||||
|
||||
//unbind!!
|
||||
scope.$on('$destroy', function () {
|
||||
element.off("mouseleave", mouseLeave);
|
||||
element.off("mouseenter", mouseEnter);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,49 +1,80 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbPanel
|
||||
* @restrict E
|
||||
* @description This is used for the editor buttons to ensure they are displayed correctly if the horizontal overflow of the editor
|
||||
* exceeds the height of the window
|
||||
**/
|
||||
angular.module("umbraco.directives.html")
|
||||
.directive('detectFold', function($timeout, $log){
|
||||
return {
|
||||
.directive('detectFold', function ($timeout, $log, windowResizeListener) {
|
||||
return {
|
||||
require: "^?umbTabs",
|
||||
restrict: 'A',
|
||||
link: function (scope, el, attrs) {
|
||||
|
||||
var state = false,
|
||||
parent = $(".umb-panel-body"),
|
||||
winHeight = $(window).height(),
|
||||
calculate = _.throttle(function(){
|
||||
if(el && el.is(":visible") && !el.hasClass("umb-bottom-bar")){
|
||||
//var parent = el.parent();
|
||||
var hasOverflow = parent.innerHeight() < parent[0].scrollHeight;
|
||||
//var belowFold = (el.offset().top + el.height()) > winHeight;
|
||||
if(hasOverflow){
|
||||
el.addClass("umb-bottom-bar");
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}, 1000);
|
||||
link: function (scope, el, attrs, tabsCtrl) {
|
||||
|
||||
scope.$watch(calculate, function(newVal, oldVal) {
|
||||
if(newVal !== oldVal){
|
||||
if(newVal){
|
||||
el.addClass("umb-bottom-bar");
|
||||
}else{
|
||||
el.removeClass("umb-bottom-bar");
|
||||
}
|
||||
}
|
||||
});
|
||||
var firstRun = false;
|
||||
var parent = $(".umb-panel-body");
|
||||
var winHeight = $(window).height();
|
||||
var calculate = function () {
|
||||
if (el && el.is(":visible") && !el.hasClass("umb-bottom-bar")) {
|
||||
|
||||
$(window).bind("resize", function () {
|
||||
winHeight = $(window).height();
|
||||
el.removeClass("umb-bottom-bar");
|
||||
state = false;
|
||||
calculate();
|
||||
});
|
||||
//now that the element is visible, set the flag in a couple of seconds,
|
||||
// this will ensure that loading time of a current tab get's completed and that
|
||||
// we eventually stop watching to save on CPU time
|
||||
$timeout(function() {
|
||||
firstRun = true;
|
||||
}, 4000);
|
||||
|
||||
$('a[data-toggle="tab"]').on('shown', function (e) {
|
||||
calculate();
|
||||
});
|
||||
//var parent = el.parent();
|
||||
var hasOverflow = parent.innerHeight() < parent[0].scrollHeight;
|
||||
//var belowFold = (el.offset().top + el.height()) > winHeight;
|
||||
if (hasOverflow) {
|
||||
el.addClass("umb-bottom-bar");
|
||||
|
||||
//I wish we didn't have to put this logic here but unfortunately we
|
||||
// do. This needs to calculate the left offest to place the bottom bar
|
||||
// depending on if the left column splitter has been moved by the user
|
||||
// (based on the nav-resize directive)
|
||||
var wrapper = $("#mainwrapper");
|
||||
var contentPanel = $("#leftcolumn").next();
|
||||
var contentPanelLeftPx = contentPanel.css("left");
|
||||
|
||||
el.css({ left: contentPanelLeftPx });
|
||||
}
|
||||
}
|
||||
return firstRun;
|
||||
};
|
||||
|
||||
var resizeCallback = function(size) {
|
||||
winHeight = size.height;
|
||||
el.removeClass("umb-bottom-bar");
|
||||
calculate();
|
||||
};
|
||||
|
||||
windowResizeListener.register(resizeCallback);
|
||||
|
||||
//Only execute the watcher if this tab is the active (first) tab on load, otherwise there's no reason to execute
|
||||
// the watcher since it will be recalculated when the tab changes!
|
||||
if (el.closest(".umb-tab-pane").index() === 0) {
|
||||
//run a watcher to ensure that the calculation occurs until it's firstRun but ensure
|
||||
// the calculations are throttled to save a bit of CPU
|
||||
var listener = scope.$watch(_.throttle(calculate, 1000), function (newVal, oldVal) {
|
||||
if (newVal !== oldVal) {
|
||||
listener();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//listen for tab changes
|
||||
if (tabsCtrl != null) {
|
||||
tabsCtrl.onTabShown(function (args) {
|
||||
calculate();
|
||||
});
|
||||
}
|
||||
|
||||
//ensure to unregister
|
||||
scope.$on('$destroy', function() {
|
||||
windowResizeListener.unregister(resizeCallback);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -242,18 +242,19 @@ angular.module('umbraco.services')
|
||||
|
||||
_.each(assets, function (asset) {
|
||||
LazyLoad.js(appendRnd(asset.path), function () {
|
||||
asset.state = "loaded";
|
||||
if (!scope) {
|
||||
asset.state = "loaded";
|
||||
asset.deferred.resolve(true);
|
||||
} else {
|
||||
asset.state = "loaded";
|
||||
}
|
||||
else {
|
||||
angularHelper.safeApply(scope, function () {
|
||||
asset.deferred.resolve(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
//return and resolve
|
||||
var deferred = $q.defer();
|
||||
promise = deferred.promise;
|
||||
|
||||
@@ -55,6 +55,12 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
err: err,
|
||||
rebindCallback: self.reBindChangedProperties(args.content, err.data)
|
||||
});
|
||||
//show any notifications
|
||||
if (angular.isArray(err.data.notifications)) {
|
||||
for (var i = 0; i < err.data.notifications.length; i++) {
|
||||
notificationsService.showNotification(err.data.notifications[i]);
|
||||
}
|
||||
}
|
||||
args.scope.busy = false;
|
||||
deferred.reject(err);
|
||||
});
|
||||
@@ -466,13 +472,13 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
* @description
|
||||
* Changes the location to be editing the newly created content after create was successful.
|
||||
* We need to decide if we need to redirect to edito mode or if we will remain in create mode.
|
||||
* We will only need to maintain create mode if we have not fulfilled the basic requirements for creating an entity which is at least having a name.
|
||||
* We will only need to maintain create mode if we have not fulfilled the basic requirements for creating an entity which is at least having a name and ID
|
||||
*/
|
||||
redirectToCreatedContent: function (id, modelState) {
|
||||
|
||||
//only continue if we are currently in create mode and if there is no 'Name' modelstate errors
|
||||
// since we need at least a name to create content.
|
||||
if ($routeParams.create && (!modelState || !modelState["Name"])) {
|
||||
if ($routeParams.create && (id > 0 && (!modelState || !modelState["Name"]))) {
|
||||
|
||||
//need to change the location to not be in 'create' mode. Currently the route will be something like:
|
||||
// /belle/#/content/edit/1234?doctype=newsArticle&create=true
|
||||
|
||||
@@ -248,7 +248,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
|
||||
//This is a bit of a hack to check if the error is due to a file being uploaded that is too large,
|
||||
// we have to just check for the existence of a string value but currently that is the best way to
|
||||
// do this since it's very hacky/difficult to catch this on the server
|
||||
if (data.indexOf("Maximum request length exceeded") >= 0) {
|
||||
if (typeof data !== "undefined" && typeof data.indexOf === "function" && data.indexOf("Maximum request length exceeded") >= 0) {
|
||||
notificationsService.error("Server error", "The uploaded file was too large, check with your site administrator to adjust the maximum size allowed");
|
||||
}
|
||||
else if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name umbraco.services.windowResizeListener
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* A single window resize listener... we don't want to have more than one in theory to ensure that
|
||||
* there aren't too many events raised. This will debounce the event with 100 ms intervals and force
|
||||
* a $rootScope.$apply when changed and notify all listeners
|
||||
*
|
||||
*/
|
||||
function windowResizeListener($rootScope) {
|
||||
|
||||
var WinReszier = (function () {
|
||||
var registered = [];
|
||||
var inited = false;
|
||||
var resize = _.debounce(function(ev) {
|
||||
notify();
|
||||
}, 100);
|
||||
var notify = function () {
|
||||
var h = $(window).height();
|
||||
var w = $(window).width();
|
||||
//execute all registrations inside of a digest
|
||||
$rootScope.$apply(function() {
|
||||
for (var i = 0, cnt = registered.length; i < cnt; i++) {
|
||||
registered[i].apply($(window), [{ width: w, height: h }]);
|
||||
}
|
||||
});
|
||||
};
|
||||
return {
|
||||
register: function (fn) {
|
||||
registered.push(fn);
|
||||
if (inited === false) {
|
||||
$(window).bind('resize', resize);
|
||||
inited = true;
|
||||
}
|
||||
},
|
||||
unregister: function (fn) {
|
||||
var index = registered.indexOf(fn);
|
||||
if (index > -1) {
|
||||
registered.splice(index, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* Register a callback for resizing
|
||||
* @param {Function} cb
|
||||
*/
|
||||
register: function (cb) {
|
||||
WinReszier.register(cb);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a registered callback
|
||||
* @param {Function} cb
|
||||
*/
|
||||
unregister: function(cb) {
|
||||
WinReszier.unregister(cb);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.services').factory('windowResizeListener', windowResizeListener);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user