diff --git a/src/Umbraco.Core/EventArgs.cs b/src/Umbraco.Core/EventArgs.cs
index c6582a712d..af2ebd208d 100644
--- a/src/Umbraco.Core/EventArgs.cs
+++ b/src/Umbraco.Core/EventArgs.cs
@@ -1,12 +1,10 @@
-using Umbraco.Core.Models;
-using Umbraco.Core.Persistence.UnitOfWork;
-using Umbraco.Core.Services;
-
-namespace Umbraco.Core
+namespace Umbraco.Core
{
//Publishing Events
- public class PublishingEventArgs : System.ComponentModel.CancelEventArgs { }
+ public class PublishingEventArgs : System.ComponentModel.CancelEventArgs {
+ public bool IsAllRepublished { get; set; }
+ }
public class SendToPublishEventArgs : System.ComponentModel.CancelEventArgs { }
//Moving object Events
diff --git a/src/Umbraco.Core/Models/ContentExtensions.cs b/src/Umbraco.Core/Models/ContentExtensions.cs
index 71e5df37ea..9f83eaca5c 100644
--- a/src/Umbraco.Core/Models/ContentExtensions.cs
+++ b/src/Umbraco.Core/Models/ContentExtensions.cs
@@ -1,9 +1,8 @@
using System;
using System.Linq;
-using Umbraco.Core.Configuration;
+using System.Xml.Linq;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence;
-using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Models
@@ -69,5 +68,63 @@ namespace Umbraco.Core.Models
return repository.GetProfileById(content.WriterId);
}
}
+
+
+ ///
+ /// Creates the xml representation for the object
+ ///
+ /// to generate xml for
+ /// Xml representation of the passed in
+ public static XElement ToXml(this IContent content)
+ {
+ //nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias);
+ //var nodeName = content.ContentType.Alias.ToUmbracoAlias(StringAliasCaseType.CamelCase, true);
+ var nodeName = content.ContentType.Alias;
+ var niceUrl = content.Name.Replace(" ", "-").ToLower();
+
+ var xml = new XElement(nodeName,
+ new XAttribute("id", content.Id),
+ new XAttribute("parentID", content.Level > 1 ? content.ParentId : -1),
+ new XAttribute("level", content.Level),
+ new XAttribute("writerID", content.WriterId),
+ new XAttribute("creatorID", content.CreatorId),
+ new XAttribute("nodeType", content.ContentType.Id),
+ new XAttribute("template", content.Template == null ? "0" : content.Template.Id.ToString()),
+ new XAttribute("sortOrder", content.SortOrder),
+ new XAttribute("createDate", content.CreateDate.ToString("s")),
+ new XAttribute("updateDate", content.UpdateDate.ToString("s")),
+ new XAttribute("nodeName", content.Name),
+ new XAttribute("urlName", niceUrl),//Format Url ?
+ new XAttribute("writerName", content.GetWriterProfile().Name),
+ new XAttribute("creatorName", content.GetCreatorProfile().Name),
+ new XAttribute("path", content.Path),
+ new XAttribute("isDoc", ""));
+
+ foreach (var property in content.Properties)
+ {
+ if (property == null) continue;
+
+ xml.Add(property.ToXml());
+
+ //Check for umbracoUrlName convention
+ if (property.Alias == "umbracoUrlName" && property.Value.ToString().Trim() != string.Empty)
+ xml.SetAttributeValue("urlName", property.Value);
+ }
+
+ return xml;
+ }
+
+ ///
+ /// Creates the xml representation for the object
+ ///
+ /// to generate xml for
+ /// Boolean indicating whether the xml should be generated for preview
+ /// Xml representation of the passed in
+ public static XElement ToXml(this IContent content, bool isPreview)
+ {
+ //TODO Do a proper implementation of this
+ //If current IContent is published we should get latest unpublished version
+ return content.ToXml();
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/PropertyExtensions.cs b/src/Umbraco.Core/Models/PropertyExtensions.cs
index 460174e8c0..0f3a40fe07 100644
--- a/src/Umbraco.Core/Models/PropertyExtensions.cs
+++ b/src/Umbraco.Core/Models/PropertyExtensions.cs
@@ -18,14 +18,8 @@ namespace Umbraco.Core.Models
var xd = new XmlDocument();
XmlNode xmlNode = xd.CreateNode(XmlNodeType.Element, nodeName, "");
- XmlNode child = property.PropertyType.DataTypeDatabaseType == DataTypeDatabaseType.Ntext
- ? xd.CreateCDataSection(property.Value.ToString()) as XmlNode
- : xd.CreateTextNode(property.Value.ToString());
-
- xmlNode.AppendChild(child);
-
//This seems to fail during testing
- //xmlNode.AppendChild(property.PropertyType.DataType(property.Id).Data.ToXMl(xd));
+ xmlNode.AppendChild(property.PropertyType.DataType(property.Id).Data.ToXMl(xd));
var element = xmlNode.GetXElement();
return element;
diff --git a/src/Umbraco.Core/Models/PropertyTypeExtensions.cs b/src/Umbraco.Core/Models/PropertyTypeExtensions.cs
index 97c803deb7..9347760b41 100644
--- a/src/Umbraco.Core/Models/PropertyTypeExtensions.cs
+++ b/src/Umbraco.Core/Models/PropertyTypeExtensions.cs
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Models
internal static IDataType DataType(this PropertyType propertyType, int propertyId)
{
Mandate.ParameterNotNull(propertyType, "propertyType");
- var dataType = DataTypesResolver.Current.GetById(propertyType.DataTypeControlId);
+ var dataType = ApplicationContext.Current.Services.DataTypeService.GetDataTypeById(propertyType.DataTypeControlId);
dataType.DataTypeDefinitionId = propertyType.DataTypeId;
dataType.Data.PropertyId = propertyId;
return dataType;
diff --git a/src/Umbraco.Core/Models/Relation.cs b/src/Umbraco.Core/Models/Relation.cs
index a501a2e341..8193d529c9 100644
--- a/src/Umbraco.Core/Models/Relation.cs
+++ b/src/Umbraco.Core/Models/Relation.cs
@@ -18,10 +18,11 @@ namespace Umbraco.Core.Models
private RelationType _relationType;
private string _comment;
- public Relation(int parentId, int childId)
+ public Relation(int parentId, int childId, RelationType relationType)
{
_parentId = parentId;
_childId = childId;
+ _relationType = relationType;
}
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId);
diff --git a/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs b/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs
index 83ba2cf3e3..fe4574b4b0 100644
--- a/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs
@@ -30,47 +30,54 @@ namespace Umbraco.Core.Persistence.Factories
public IContent BuildEntity(DocumentDto dto)
{
return new Content(dto.ContentVersionDto.ContentDto.NodeDto.ParentId, _contentType)
- {
- Id = _id,
- Key =
- dto.ContentVersionDto.ContentDto.NodeDto.UniqueId.HasValue
- ? dto.ContentVersionDto.ContentDto.NodeDto.UniqueId.Value
- : _id.ToGuid(),
- Name = dto.Text,
- NodeName = dto.ContentVersionDto.ContentDto.NodeDto.Text,
- Language = dto.ContentVersionDto.Language,
- Path = dto.ContentVersionDto.ContentDto.NodeDto.Path,
- CreatorId = dto.ContentVersionDto.ContentDto.NodeDto.UserId.Value,
- WriterId = dto.WriterUserId,
- Level = dto.ContentVersionDto.ContentDto.NodeDto.Level,
- ParentId = dto.ContentVersionDto.ContentDto.NodeDto.ParentId,
- SortOrder = dto.ContentVersionDto.ContentDto.NodeDto.SortOrder,
- Trashed = dto.ContentVersionDto.ContentDto.NodeDto.Trashed,
- Published = dto.Published,
- CreateDate = dto.ContentVersionDto.ContentDto.NodeDto.CreateDate,
- UpdateDate = dto.ContentVersionDto.VersionDate,
- ExpireDate = dto.ExpiresDate,
- ReleaseDate = dto.ReleaseDate,
- Version = dto.ContentVersionDto.VersionId
- };
+ {
+ Id = _id,
+ Key =
+ dto.ContentVersionDto.ContentDto.NodeDto.UniqueId.HasValue
+ ? dto.ContentVersionDto.ContentDto.NodeDto.UniqueId.Value
+ : _id.ToGuid(),
+ Name = dto.Text,
+ NodeName = dto.ContentVersionDto.ContentDto.NodeDto.Text,
+ Language = dto.ContentVersionDto.Language,
+ Path = dto.ContentVersionDto.ContentDto.NodeDto.Path,
+ CreatorId = dto.ContentVersionDto.ContentDto.NodeDto.UserId.Value,
+ WriterId = dto.WriterUserId,
+ Level = dto.ContentVersionDto.ContentDto.NodeDto.Level,
+ ParentId = dto.ContentVersionDto.ContentDto.NodeDto.ParentId,
+ SortOrder = dto.ContentVersionDto.ContentDto.NodeDto.SortOrder,
+ Trashed = dto.ContentVersionDto.ContentDto.NodeDto.Trashed,
+ Published = dto.Published,
+ CreateDate = dto.ContentVersionDto.ContentDto.NodeDto.CreateDate,
+ UpdateDate = dto.ContentVersionDto.VersionDate,
+ ExpireDate = dto.ExpiresDate.HasValue ? dto.ExpiresDate.Value : (DateTime?)null,
+ ReleaseDate = dto.ReleaseDate.HasValue ? dto.ReleaseDate.Value : (DateTime?)null,
+ Version = dto.ContentVersionDto.VersionId
+ };
}
public DocumentDto BuildDto(IContent entity)
{
//NOTE Currently doesn't add Alias and templateId (legacy stuff that eventually will go away)
var documentDto = new DocumentDto
- {
- ExpiresDate = entity.ExpireDate,
- Newest = true,
- NodeId = entity.Id,
- Published = entity.Published,
- ReleaseDate = entity.ReleaseDate,
- Text = entity.Name,
- UpdateDate = entity.UpdateDate,
- WriterUserId = entity.WriterId,
- VersionId = entity.Version,
- ContentVersionDto = BuildContentVersionDto(entity)
- };
+ {
+ Newest = true,
+ NodeId = entity.Id,
+ Published = entity.Published,
+ Text = entity.Name,
+ UpdateDate = entity.UpdateDate,
+ WriterUserId = entity.WriterId,
+ VersionId = entity.Version,
+ ExpiresDate = null,
+ ReleaseDate = null,
+ ContentVersionDto = BuildContentVersionDto(entity)
+ };
+
+ if (entity.ExpireDate.HasValue)
+ documentDto.ExpiresDate = entity.ExpireDate.Value;
+
+ if (entity.ReleaseDate.HasValue)
+ documentDto.ReleaseDate = entity.ReleaseDate.Value;
+
return documentDto;
}
@@ -88,24 +95,24 @@ namespace Umbraco.Core.Persistence.Factories
var lang = content == null ? string.Empty : content.Language;
var contentVersionDto = new ContentVersionDto
- {
- NodeId = entity.Id,
- VersionDate = entity.UpdateDate,
- VersionId = entity.Version,
- Language = lang,
- ContentDto = BuildContentDto(entity)
- };
+ {
+ NodeId = entity.Id,
+ VersionDate = entity.UpdateDate,
+ VersionId = entity.Version,
+ Language = lang,
+ ContentDto = BuildContentDto(entity)
+ };
return contentVersionDto;
}
private ContentDto BuildContentDto(IContent entity)
{
var contentDto = new ContentDto
- {
- NodeId = entity.Id,
- ContentTypeId = entity.ContentTypeId,
- NodeDto = BuildNodeDto(entity)
- };
+ {
+ NodeId = entity.Id,
+ ContentTypeId = entity.ContentTypeId,
+ NodeDto = BuildNodeDto(entity)
+ };
if (_primaryKey > 0)
{
@@ -119,22 +126,22 @@ namespace Umbraco.Core.Persistence.Factories
{
//TODO: Change this once the Language property is public on IContent
var content = entity as Content;
- var nodeName = content == null ? entity.Name : content.NodeName;
+ var nodeName = content != null && string.IsNullOrEmpty(content.NodeName) == false ? content.NodeName : entity.Name;
var nodeDto = new NodeDto
- {
- CreateDate = entity.CreateDate,
- NodeId = entity.Id,
- Level = short.Parse(entity.Level.ToString(CultureInfo.InvariantCulture)),
- NodeObjectType = _nodeObjectTypeId,
- ParentId = entity.ParentId,
- Path = entity.Path,
- SortOrder = entity.SortOrder,
- Text = nodeName,
- Trashed = entity.Trashed,
- UniqueId = entity.Key,
- UserId = entity.CreatorId
- };
+ {
+ CreateDate = entity.CreateDate,
+ NodeId = entity.Id,
+ Level = short.Parse(entity.Level.ToString(CultureInfo.InvariantCulture)),
+ NodeObjectType = _nodeObjectTypeId,
+ ParentId = entity.ParentId,
+ Path = entity.Path,
+ SortOrder = entity.SortOrder,
+ Text = nodeName,
+ Trashed = entity.Trashed,
+ UniqueId = entity.Key,
+ UserId = entity.CreatorId
+ };
return nodeDto;
}
diff --git a/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs b/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs
index ccd2071b76..93d137d1b1 100644
--- a/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs
@@ -45,18 +45,15 @@ namespace Umbraco.Core.Persistence.Factories
public IEnumerable BuildDto(IEnumerable properties)
{
var propertyDataDtos = new List();
- /*var serviceStackSerializer = new ServiceStackXmlSerializer();
- var service = new SerializationService(serviceStackSerializer);*/
foreach (var property in properties)
{
var dto = new PropertyDataDto { NodeId = _id, PropertyTypeId = property.PropertyTypeId, VersionId = _version };
- //TODO Add complex (PropertyEditor) ValueModels to the Ntext/Nvarchar column as a serialized 'Object' (DataTypeDatabaseType.Object)
- /*if (property.Value is IEditorModel)
- {
- var result = service.ToStream(property.Value);
- dto.Text = result.ResultStream.ToJsonString();
- }*/
+
+ //Check if property has an Id and set it, so that it can be updated if it already exists
+ if (property.HasIdentity)
+ dto.Id = property.Id;
+
if (property.DataTypeDatabaseType == DataTypeDatabaseType.Integer && property.Value != null)
{
dto.Integer = int.Parse(property.Value.ToString());
diff --git a/src/Umbraco.Core/Persistence/Factories/RelationFactory.cs b/src/Umbraco.Core/Persistence/Factories/RelationFactory.cs
index 9c5d23682d..030cad9254 100644
--- a/src/Umbraco.Core/Persistence/Factories/RelationFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/RelationFactory.cs
@@ -16,13 +16,12 @@ namespace Umbraco.Core.Persistence.Factories
public Relation BuildEntity(RelationDto dto)
{
- var entity = new Relation(dto.ParentId, dto.ChildId)
+ var entity = new Relation(dto.ParentId, dto.ChildId, _relationType)
{
Comment = dto.Comment,
CreateDate = dto.Datetime,
Id = dto.Id,
- UpdateDate = dto.Datetime,
- RelationType = _relationType
+ UpdateDate = dto.Datetime
};
return entity;
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
index d0c087d9a2..9b0ebd8c62 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
@@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
@@ -101,7 +103,7 @@ namespace Umbraco.Core.Persistence.Repositories
yield return Get(dto.NodeId);
}
}
-
+
#endregion
#region Overrides of PetaPocoRepositoryBase
@@ -127,18 +129,19 @@ namespace Umbraco.Core.Persistence.Repositories
{
var list = new List
{
- string.Format("DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id"),
- string.Format("DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id"),
- string.Format("DELETE FROM umbracoRelation WHERE parentId = @Id"),
- string.Format("DELETE FROM umbracoRelation WHERE childId = @Id"),
- string.Format("DELETE FROM cmsTagRelationship WHERE nodeId = @Id"),
- string.Format("DELETE FROM cmsDocument WHERE NodeId = @Id"),
- string.Format("DELETE FROM cmsPropertyData WHERE contentNodeId = @Id"),
- string.Format("DELETE FROM cmsPreviewXml WHERE nodeId = @Id"),
- string.Format("DELETE FROM cmsContentVersion WHERE ContentId = @Id"),
- string.Format("DELETE FROM cmsContentXml WHERE nodeID = @Id"),
- string.Format("DELETE FROM cmsContent WHERE NodeId = @Id"),
- string.Format("DELETE FROM umbracoNode WHERE id = @Id")
+ "DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id",
+ "DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id",
+ "DELETE FROM umbracoRelation WHERE parentId = @Id",
+ "DELETE FROM umbracoRelation WHERE childId = @Id",
+ "DELETE FROM cmsTagRelationship WHERE nodeId = @Id",
+ "DELETE FROM umbracoDomains WHERE domainRootStructureID = @Id",
+ "DELETE FROM cmsDocument WHERE NodeId = @Id",
+ "DELETE FROM cmsPropertyData WHERE contentNodeId = @Id",
+ "DELETE FROM cmsPreviewXml WHERE nodeId = @Id",
+ "DELETE FROM cmsContentVersion WHERE ContentId = @Id",
+ "DELETE FROM cmsContentXml WHERE nodeID = @Id",
+ "DELETE FROM cmsContent WHERE NodeId = @Id",
+ "DELETE FROM umbracoNode WHERE id = @Id"
};
return list;
}
@@ -223,8 +226,24 @@ namespace Umbraco.Core.Persistence.Repositories
protected override void PersistUpdatedItem(IContent entity)
{
- //Updates Modified date and Version Guid
- ((Content)entity).UpdatingEntity();
+ //A new version should only be created if published state has changed
+ bool shouldCreateNewVersion = ((ICanBeDirty)entity).IsPropertyDirty("Published") || ((ICanBeDirty)entity).IsPropertyDirty("Language");
+ if (shouldCreateNewVersion)
+ {
+ //Updates Modified date and Version Guid
+ ((Content)entity).UpdatingEntity();
+ }
+ else
+ {
+ entity.UpdateDate = DateTime.UtcNow;
+ }
+
+ //Look up parent to get and set the correct Path if ParentId has changed
+ if (((ICanBeDirty)entity).IsPropertyDirty("ParentId"))
+ {
+ var parent = Database.First("WHERE id = @ParentId", new { ParentId = entity.ParentId });
+ entity.Path = string.Concat(parent.Path, ",", entity.Id);
+ }
var factory = new ContentFactory(NodeObjectTypeId, entity.Id);
//Look up Content entry to get Primary for updating the DTO
@@ -235,7 +254,7 @@ namespace Umbraco.Core.Persistence.Repositories
//Updates the (base) node data - umbracoNode
var nodeDto = dto.ContentVersionDto.ContentDto.NodeDto;
var o = Database.Update(nodeDto);
-
+
//Only update this DTO if the contentType has actually changed
if (contentDto.ContentTypeId != entity.ContentTypeId)
{
@@ -244,36 +263,97 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Update(newContentDto);
}
- //Look up (newest) entries by id in cmsDocument table to set newest = false
- var documentDtos = Database.Fetch("WHERE nodeId = @Id AND newest = @IsNewest", new { Id = entity.Id, IsNewest = true });
- foreach (var documentDto in documentDtos)
+ //If Published state has changed then previous versions should have their publish state reset
+ if (shouldCreateNewVersion && entity.Published)
{
- var docDto = documentDto;
- docDto.Newest = false;
- Database.Update(docDto);
+ var publishedDocs = Database.Fetch("WHERE nodeId = @Id AND published = @IsPublished", new { Id = entity.Id, IsPublished = true });
+ foreach (var doc in publishedDocs)
+ {
+ var docDto = doc;
+ docDto.Published = false;
+ Database.Update(docDto);
+ }
}
- //Create a new version - cmsContentVersion
- //Assumes a new Version guid and Version date (modified date) has been set
var contentVersionDto = dto.ContentVersionDto;
- Database.Insert(contentVersionDto);
+ if (shouldCreateNewVersion)
+ {
+ //Look up (newest) entries by id in cmsDocument table to set newest = false
+ //NOTE: This is only relevant when a new version is created, which is why its done inside this if-statement.
+ var documentDtos = Database.Fetch("WHERE nodeId = @Id AND newest = @IsNewest", new { Id = entity.Id, IsNewest = true });
+ foreach (var documentDto in documentDtos)
+ {
+ var docDto = documentDto;
+ docDto.Newest = false;
+ Database.Update(docDto);
+ }
- //Create the Document specific data for this version - cmsDocument
- //Assumes a new Version guid has been generated
- Database.Insert(dto);
+ //Create a new version - cmsContentVersion
+ //Assumes a new Version guid and Version date (modified date) has been set
+ Database.Insert(contentVersionDto);
+ //Create the Document specific data for this version - cmsDocument
+ //Assumes a new Version guid has been generated
+ Database.Insert(dto);
+ }
+ else
+ {
+ //In order to update the ContentVersion we need to retreive its primary key id
+ var contentVerDto = Database.SingleOrDefault("WHERE VersionId = @Version", new { Version = entity.Version });
+ contentVersionDto.Id = contentVerDto.Id;
+
+ Database.Update(contentVersionDto);
+ Database.Update(dto);
+ }
//Create the PropertyData for this version - cmsPropertyData
- var propertyFactory = new PropertyFactory(entity.ContentType, entity.Version, entity.Id);
+ var propertyFactory = new PropertyFactory(((Content)entity).ContentType, entity.Version, entity.Id);
var propertyDataDtos = propertyFactory.BuildDto(entity.Properties);
//Add Properties
foreach (var propertyDataDto in propertyDataDtos)
{
- Database.Insert(propertyDataDto);
+ if (shouldCreateNewVersion == false && propertyDataDto.Id > 0)
+ {
+ Database.Update(propertyDataDto);
+ }
+ else
+ {
+ Database.Insert(propertyDataDto);
+ }
}
((ICanBeDirty)entity).ResetDirtyProperties();
}
-
+
+ protected override void PersistDeletedItem(IContent entity)
+ {
+ var fs = FileSystemProviderManager.Current.GetFileSystemProvider();
+ var uploadFieldId = new Guid("5032a6e6-69e3-491d-bb28-cd31cd11086c");
+ //Loop through properties to check if the content contains media that should be deleted
+ foreach (var property in entity.Properties)
+ {
+ if (property.PropertyType.DataTypeControlId == uploadFieldId &&
+ string.IsNullOrEmpty(property.Value.ToString()) == false
+ && fs.FileExists(IOHelper.MapPath(property.Value.ToString())))
+ {
+ var relativeFilePath = fs.GetRelativePath(property.Value.ToString());
+ var parentDirectory = System.IO.Path.GetDirectoryName(relativeFilePath);
+
+ // don't want to delete the media folder if not using directories.
+ if (UmbracoSettings.UploadAllowDirectories && parentDirectory != fs.GetRelativePath("/"))
+ {
+ //issue U4-771: if there is a parent directory the recursive parameter should be true
+ fs.DeleteDirectory(parentDirectory, String.IsNullOrEmpty(parentDirectory) == false);
+ }
+ else
+ {
+ fs.DeleteFile(relativeFilePath, true);
+ }
+ }
+ }
+
+ base.PersistDeletedItem(entity);
+ }
+
#endregion
#region Implementation of IContentRepository
@@ -334,7 +414,7 @@ namespace Umbraco.Core.Persistence.Repositories
var documentDto = Database.FirstOrDefault("WHERE nodeId = @Id AND versionId = @VersionId AND newest = @Newest", new { Id = id, VersionId = versionId, Newest = false });
Mandate.That(documentDto != null);
- using(var transaction = Database.GetTransaction())
+ using (var transaction = Database.GetTransaction())
{
DeleteVersion(id, versionId);
@@ -344,7 +424,7 @@ namespace Umbraco.Core.Persistence.Repositories
public void Delete(int id, DateTime versionDate)
{
- var list = Database.Fetch("WHERE nodeId = @Id AND VersionDate < @VersionDate", new {Id = id, VersionDate = versionDate});
+ var list = Database.Fetch("WHERE nodeId = @Id AND VersionDate < @VersionDate", new { Id = id, VersionDate = versionDate });
Mandate.That(list.Any());
using (var transaction = Database.GetTransaction())
@@ -357,7 +437,7 @@ namespace Umbraco.Core.Persistence.Repositories
transaction.Complete();
}
}
-
+
///
/// Private method to execute the delete statements for removing a single version for a Content item.
///
diff --git a/src/Umbraco.Core/Publishing/BasePublishingStrategy.cs b/src/Umbraco.Core/Publishing/BasePublishingStrategy.cs
index 2673426ade..36656e5e27 100644
--- a/src/Umbraco.Core/Publishing/BasePublishingStrategy.cs
+++ b/src/Umbraco.Core/Publishing/BasePublishingStrategy.cs
@@ -99,5 +99,34 @@ namespace Umbraco.Core.Publishing
if (UnPublished != null)
UnPublished(content, e);
}
+
+ ///
+ /// Call to fire event that updating the published content has finalized.
+ ///
+ ///
+ /// This seperation of the OnPublished event is done to ensure that the Content
+ /// has been properly updated (committed unit of work) and xml saved in the db.
+ ///
+ /// thats being published
+ public abstract void PublishingFinalized(IContent content);
+
+ ///
+ /// Call to fire event that updating the published content has finalized.
+ ///
+ /// An enumerable list of thats being published
+ /// Boolean indicating whether its all content that is republished
+ public abstract void PublishingFinalized(IEnumerable content, bool isAllRepublished);
+
+ ///
+ /// Call to fire event that updating the unpublished content has finalized.
+ ///
+ /// thats being unpublished
+ public abstract void UnPublishingFinalized(IContent content);
+
+ ///
+ /// Call to fire event that updating the unpublished content has finalized.
+ ///
+ /// An enumerable list of thats being unpublished
+ public abstract void UnPublishingFinalized(IEnumerable content);
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Publishing/IPublishingStrategy.cs b/src/Umbraco.Core/Publishing/IPublishingStrategy.cs
index c2861eac8b..0408409488 100644
--- a/src/Umbraco.Core/Publishing/IPublishingStrategy.cs
+++ b/src/Umbraco.Core/Publishing/IPublishingStrategy.cs
@@ -39,5 +39,34 @@ namespace Umbraco.Core.Publishing
/// Id of the User issueing the unpublish operation
/// True if the unpublish operation was successfull and not cancelled, otherwise false
bool UnPublish(IEnumerable content, int userId);
+
+ ///
+ /// Call to fire event that updating the published content has finalized.
+ ///
+ ///
+ /// This seperation of the OnPublished event is done to ensure that the Content
+ /// has been properly updated (committed unit of work) and xml saved in the db.
+ ///
+ /// thats being published
+ void PublishingFinalized(IContent content);
+
+ ///
+ /// Call to fire event that updating the published content has finalized.
+ ///
+ /// An enumerable list of thats being published
+ /// Boolean indicating whether its all content that is republished
+ void PublishingFinalized(IEnumerable content, bool isAllRepublished);
+
+ ///
+ /// Call to fire event that updating the unpublished content has finalized.
+ ///
+ /// thats being unpublished
+ void UnPublishingFinalized(IContent content);
+
+ ///
+ /// Call to fire event that updating the unpublished content has finalized.
+ ///
+ /// An enumerable list of thats being unpublished
+ void UnPublishingFinalized(IEnumerable content);
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Publishing/PublishingStrategy.cs b/src/Umbraco.Core/Publishing/PublishingStrategy.cs
index ffd5077af4..618c731302 100644
--- a/src/Umbraco.Core/Publishing/PublishingStrategy.cs
+++ b/src/Umbraco.Core/Publishing/PublishingStrategy.cs
@@ -30,7 +30,7 @@ namespace Umbraco.Core.Publishing
if (!e.Cancel)
{
//Check if the Content is Expired to verify that it can in fact be published
- if(content.Status == ContentStatus.Expired)
+ if (content.Status == ContentStatus.Expired)
{
LogHelper.Info(
string.Format("Content '{0}' with Id '{1}' has expired and could not be published.",
@@ -62,11 +62,6 @@ namespace Umbraco.Core.Publishing
string.Format("Content '{0}' with Id '{1}' has been published.",
content.Name, content.Id));
- //Fire Published event
- OnPublished(content, e);
-
- //NOTE: Ideally the xml cache should be refreshed here - as part of the publishing
-
return true;
}
@@ -121,20 +116,12 @@ namespace Umbraco.Core.Publishing
}
item.ChangePublishedState(true);
-
+
LogHelper.Info(
string.Format("Content '{0}' with Id '{1}' has been published.",
item.Name, item.Id));
-
- //Fire Published event
- OnPublished(item, e);
}
- OnPublished(content, e);
-
- //NOTE: Ideally the xml cache should be refreshed here - as part of the publishing
- //OnCacheContentAfterPublish(content, e)
-
return true;
}
@@ -169,13 +156,6 @@ namespace Umbraco.Core.Publishing
LogHelper.Info(
string.Format("Content '{0}' with Id '{1}' has been unpublished.",
content.Name, content.Id));
-
- //Fire UnPublishing event
- OnUnPublished(content, e);
-
- //NOTE: Ideally the xml cache should be refreshed here - as part of the unpublishing
- //OnRemoveCacheContentAfterPublish(content, e)
-
return true;
}
@@ -216,16 +196,50 @@ namespace Umbraco.Core.Publishing
LogHelper.Info(
string.Format("Content '{0}' with Id '{1}' has been unpublished.",
item.Name, item.Id));
-
- //Fire AfterUnPublish event
- OnUnPublished(item, e);
}
- OnUnPublished(content, e);
-
- //NOTE: Ideally the xml cache should be refreshed here - as part of the publishing
-
return true;
}
+
+ ///
+ /// Call to fire event that updating the published content has finalized.
+ ///
+ ///
+ /// This seperation of the OnPublished event is done to ensure that the Content
+ /// has been properly updated (committed unit of work) and xml saved in the db.
+ ///
+ /// thats being published
+ public override void PublishingFinalized(IContent content)
+ {
+ OnPublished(content, new PublishingEventArgs());
+ }
+
+ ///
+ /// Call to fire event that updating the published content has finalized.
+ ///
+ /// An enumerable list of thats being published
+ /// Boolean indicating whether its all content that is republished
+ public override void PublishingFinalized(IEnumerable content, bool isAllRepublished)
+ {
+ OnPublished(content, new PublishingEventArgs { IsAllRepublished = isAllRepublished });
+ }
+
+ ///
+ /// Call to fire event that updating the unpublished content has finalized.
+ ///
+ /// thats being unpublished
+ public override void UnPublishingFinalized(IContent content)
+ {
+ OnUnPublished(content, new PublishingEventArgs());
+ }
+
+ ///
+ /// Call to fire event that updating the unpublished content has finalized.
+ ///
+ /// An enumerable list of thats being unpublished
+ public override void UnPublishingFinalized(IEnumerable content)
+ {
+ OnUnPublished(content, new PublishingEventArgs());
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs
index 13adfb2df7..d8f0f0e746 100644
--- a/src/Umbraco.Core/Services/ContentService.cs
+++ b/src/Umbraco.Core/Services/ContentService.cs
@@ -2,10 +2,13 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
+using System.Xml.Linq;
using Umbraco.Core.Auditing;
+using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
+using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
@@ -178,6 +181,65 @@ namespace Umbraco.Core.Services
}
}
+ ///
+ /// Gets a collection of objects by its name or partial name
+ ///
+ /// Id of the Parent to retrieve Children from
+ /// Full or partial name of the children
+ /// An Enumerable list of objects
+ public IEnumerable GetChildrenByName(int parentId, string name)
+ {
+ using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.ParentId == parentId && x.Name.Contains(name));
+ var contents = repository.GetByQuery(query);
+
+ return contents;
+ }
+ }
+
+ ///
+ /// Gets a collection of objects by Parent Id
+ ///
+ /// Id of the Parent to retrieve Descendants from
+ /// An Enumerable list of objects
+ public IEnumerable GetDescendants(int id)
+ {
+ var content = GetById(id);
+ return GetDescendants(content);
+ }
+
+ ///
+ /// Gets a collection of objects by Parent Id
+ ///
+ /// item to retrieve Descendants from
+ /// An Enumerable list of objects
+ public IEnumerable GetDescendants(IContent content)
+ {
+ using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.Path.StartsWith(content.Path));
+ var contents = repository.GetByQuery(query);
+
+ return contents;
+ }
+ }
+
+
+ ///
+ /// Gets a specific version of an item.
+ ///
+ /// Id of the to retrieve version from
+ /// Id of the version to retrieve
+ /// An item
+ public IContent GetByIdVersion(int id, Guid versionId)
+ {
+ using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ return repository.GetByVersion(id, versionId);
+ }
+ }
+
///
/// Gets a collection of an objects versions by Id
///
@@ -190,9 +252,22 @@ namespace Umbraco.Core.Services
var versions = repository.GetAllVersions(id);
return versions;
}
-
}
+ ///
+ /// Gets the published version of an item
+ ///
+ /// Id of the to retrieve version from
+ /// An item
+ public IContent GetPublishedVersion(int id)
+ {
+ using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var version = GetVersions(id);
+ return version.FirstOrDefault(x => x.Published == true);
+ }
+ }
+
///
/// Gets a collection of objects, which reside at the first level / root
///
@@ -253,17 +328,49 @@ namespace Umbraco.Core.Services
}
}
- ///
- /// Re-Publishes all Content
- ///
- /// Optional Id of the User issueing the publishing
- /// True if publishing succeeded, otherwise False
- public bool RePublishAll(int userId = -1)
+ ///
+ /// Checks whether an item has any children
+ ///
+ /// Id of the
+ /// True if the content has any children otherwise False
+ public bool HasChildren(int id)
+ {
+ using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.ParentId == id);
+ int count = repository.Count(query);
+ return count > 0;
+ }
+ }
+
+ ///
+ /// Checks whether an item has any published versions
+ ///
+ /// Id of the
+ /// True if the content has any published version otherwise False
+ public bool HasPublishedVersion(int id)
+ {
+ using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ var query = Query.Builder.Where(x => x.Published == true && x.Id == id);
+ int count = repository.Count(query);
+ return count > 0;
+ }
+ }
+
+ ///
+ /// Re-Publishes all Content
+ ///
+ /// Optional Id of the User issueing the publishing
+ /// Optional boolean to avoid having the cache refreshed when calling this RePublish method. By default this method will update the cache.
+ /// True if publishing succeeded, otherwise False
+ public bool RePublishAll(int userId = -1, bool omitCacheRefresh = false)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
var list = new List();
+ var updated = new List();
//Consider creating a Path query instead of recursive method:
//var query = Query.Builder.Where(x => x.Path.StartsWith("-1"));
@@ -287,12 +394,24 @@ namespace Umbraco.Core.Services
{
SetWriter(item, userId);
repository.AddOrUpdate(item);
+ updated.Add(item);
}
uow.Commit();
- //TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
- //global::umbraco.library.RefreshContent();
+ foreach (var c in updated)
+ {
+ var xml = c.ToXml();
+ var poco = new ContentXmlDto { NodeId = c.Id, Xml = xml.ToString(SaveOptions.None) };
+ var exists = uow.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = c.Id }) != null;
+ int result = exists
+ ? uow.Database.Update(poco)
+ : Convert.ToInt32(uow.Database.Insert(poco));
+ }
+
+ //Updating content to published state is finished, so we fire event through PublishingStrategy to have cache updated
+ if (omitCacheRefresh == false)
+ _publishingStrategy.PublishingFinalized(updated, true);
Audit.Add(AuditTypes.Publish, "RePublish All performed by user", userId == -1 ? 0 : userId, -1);
}
@@ -301,30 +420,32 @@ namespace Umbraco.Core.Services
}
}
- ///
- /// Publishes a single object
- ///
- /// The to publish
- /// Optional Id of the User issueing the publishing
- /// True if publishing succeeded, otherwise False
- public bool Publish(IContent content, int userId = -1)
- {
- return SaveAndPublish(content, userId);
- }
+ ///
+ /// Publishes a single object
+ ///
+ /// The to publish
+ /// Optional Id of the User issueing the publishing
+ /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.
+ /// True if publishing succeeded, otherwise False
+ public bool Publish(IContent content, int userId = -1, bool omitCacheRefresh = false)
+ {
+ return SaveAndPublish(content, userId, omitCacheRefresh);
+ }
- ///
- /// Publishes a object and all its children
- ///
- /// The to publish along with its children
- /// Optional Id of the User issueing the publishing
- /// True if publishing succeeded, otherwise False
- public bool PublishWithChildren(IContent content, int userId = -1)
+ ///
+ /// Publishes a object and all its children
+ ///
+ /// The to publish along with its children
+ /// Optional Id of the User issueing the publishing
+ /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.
+ /// True if publishing succeeded, otherwise False
+ public bool PublishWithChildren(IContent content, int userId = -1, bool omitCacheRefresh = false)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
//Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
- if (content.ParentId != -1 && content.ParentId != -20 && !GetById(content.ParentId).Published)
+ if (content.ParentId != -1 && content.ParentId != -20 && HasPublishedVersion(content.ParentId) == false)
{
LogHelper.Info(
string.Format("Content '{0}' with Id '{1}' could not be published because its parent is not published.",
@@ -344,6 +465,7 @@ namespace Umbraco.Core.Services
//Consider creating a Path query instead of recursive method:
//var query = Query.Builder.Where(x => x.Path.StartsWith(content.Path));
+ var updated = new List();
var list = new List();
list.Add(content);
list.AddRange(GetChildrenDeep(content.Id));
@@ -357,13 +479,24 @@ namespace Umbraco.Core.Services
{
SetWriter(item, userId);
repository.AddOrUpdate(item);
+ updated.Add(item);
}
uow.Commit();
- //TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
- //TODO Need to investigate if it will also update the cache for children of the Content object
- //global::umbraco.library.UpdateDocumentCache(content.Id);
+ foreach (var c in updated)
+ {
+ var xml = c.ToXml();
+ var poco = new ContentXmlDto { NodeId = c.Id, Xml = xml.ToString(SaveOptions.None) };
+ var exists = uow.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = c.Id }) != null;
+ int result = exists
+ ? uow.Database.Update(poco)
+ : Convert.ToInt32(uow.Database.Insert(poco));
+ }
+
+ //Save xml to db and call following method to fire event:
+ if (omitCacheRefresh == false)
+ _publishingStrategy.PublishingFinalized(updated, false);
Audit.Add(AuditTypes.Publish, "Publish with Children performed by user", userId == -1 ? 0 : userId, content.Id);
}
@@ -372,13 +505,14 @@ namespace Umbraco.Core.Services
}
}
- ///
- /// UnPublishes a single object
- ///
- /// The to publish
- /// Optional Id of the User issueing the publishing
- /// True if unpublishing succeeded, otherwise False
- public bool UnPublish(IContent content, int userId = -1)
+ ///
+ /// UnPublishes a single object
+ ///
+ /// The to publish
+ /// Optional Id of the User issueing the publishing
+ /// Optional boolean to avoid having the cache refreshed when calling this Unpublish method. By default this method will update the cache.
+ /// True if unpublishing succeeded, otherwise False
+ public bool UnPublish(IContent content, int userId = -1, bool omitCacheRefresh = false)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
@@ -409,10 +543,21 @@ namespace Umbraco.Core.Services
uow.Commit();
- //TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content class.
- //global::umbraco.library.UnPublishSingleNode(content.Id);
+ //Remove 'published' xml from the cmsContentXml table for the unpublished content and its (possible) children
+ uow.Database.Delete("WHERE nodeId = @Id", new { Id = content.Id });
+ if (hasChildren)
+ {
+ foreach (var child in children)
+ {
+ uow.Database.Delete("WHERE nodeId = @Id", new { Id = child.Id });
+ }
+ }
- Audit.Add(AuditTypes.Publish, "UnPublish performed by user", userId == -1 ? 0 : userId, content.Id);
+ //Delete xml from db? and call following method to fire event through PublishingStrategy to update cache
+ if (omitCacheRefresh == false)
+ _publishingStrategy.UnPublishingFinalized(content);
+
+ Audit.Add(AuditTypes.UnPublish, "UnPublish performed by user", userId == -1 ? 0 : userId, content.Id);
}
return unpublished;
@@ -445,13 +590,14 @@ namespace Umbraco.Core.Services
return list;
}
- ///
- /// Saves and Publishes a single object
- ///
- /// The to save and publish
- /// Optional Id of the User issueing the publishing
- /// True if publishing succeeded, otherwise False
- public bool SaveAndPublish(IContent content, int userId = -1)
+ ///
+ /// Saves and Publishes a single object
+ ///
+ /// The to save and publish
+ /// Optional Id of the User issueing the publishing
+ /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.
+ /// True if publishing succeeded, otherwise False
+ public bool SaveAndPublish(IContent content, int userId = -1, bool omitCacheRefresh = false)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
@@ -462,9 +608,8 @@ namespace Umbraco.Core.Services
if (!e.Cancel)
{
-
//Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
- if (content.ParentId != -1 && content.ParentId != -20 && GetById(content.ParentId).Published == false)
+ if (content.ParentId != -1 && content.ParentId != -20 && HasPublishedVersion(content.ParentId) == false)
{
LogHelper.Info(
string.Format(
@@ -485,15 +630,25 @@ namespace Umbraco.Core.Services
//Publish and then update the database with new status
bool published = _publishingStrategy.Publish(content, userId);
- if (published)
- {
- SetWriter(content, userId);
- repository.AddOrUpdate(content);
- uow.Commit();
- //TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
- //global::umbraco.library.UpdateDocumentCache(content.Id);
- }
+ //Since this is the Save and Publish method, the content should be saved even though the publish fails or isn't allowed
+ SetWriter(content, userId);
+ repository.AddOrUpdate(content);
+ uow.Commit();
+
+ if (published)
+ {
+ var xml = content.ToXml();
+ var poco = new ContentXmlDto { NodeId = content.Id, Xml = xml.ToString(SaveOptions.None) };
+ var exists = uow.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = content.Id }) != null;
+ int result = exists
+ ? uow.Database.Update(poco)
+ : Convert.ToInt32(uow.Database.Insert(poco));
+
+ //Save xml to db and call following method to fire event through PublishingStrategy to update cache
+ if (omitCacheRefresh == false)
+ _publishingStrategy.PublishingFinalized(content);
+ }
if (Saved != null)
Saved(content, e);
@@ -524,16 +679,19 @@ namespace Umbraco.Core.Services
if (!e.Cancel)
{
-
SetWriter(content, userId);
- content.ChangePublishedState(false);
+
+ //Only change the publish state if the "previous" version was actually published
+ if (content.Published)
+ content.ChangePublishedState(false);
+
repository.AddOrUpdate(content);
uow.Commit();
if (Saved != null)
Saved(content, e);
- //Audit.Add(AuditTypes.Save, "Save Content performed by user", userId == -1 ? 0 : userId, content.Id);
+ Audit.Add(AuditTypes.Save, "Save Content performed by user", userId == -1 ? 0 : userId, content.Id);
}
}
}
@@ -565,7 +723,11 @@ namespace Umbraco.Core.Services
foreach (var content in contents)
{
SetWriter(content, userId);
- content.ChangePublishedState(false);
+
+ //Only change the publish state if the "previous" version was actually published
+ if (content.Published)
+ content.ChangePublishedState(false);
+
repository.AddOrUpdate(content);
uow.Commit();
}
@@ -614,7 +776,11 @@ namespace Umbraco.Core.Services
foreach (var content in contents)
{
SetWriter(content.Value, userId);
- content.Value.ChangePublishedState(false);
+
+ //Only change the publish state if the "previous" version was actually published
+ if (content.Value.Published)
+ content.Value.ChangePublishedState(false);
+
repository.AddOrUpdate(content.Value);
uow.Commit();
}
@@ -627,55 +793,64 @@ namespace Umbraco.Core.Services
}
}
- ///
- /// Deletes all content of specified type. All children of deleted content is moved to Recycle Bin.
- ///
- /// This needs extra care and attention as its potentially a dangerous and extensive operation
- /// Id of the
- /// Optional Id of the user issueing the delete operation
- public void DeleteContentOfType(int contentTypeId, int userId = -1)
- {
- var uow = _uowProvider.GetUnitOfWork();
- using (var repository = _repositoryFactory.CreateContentRepository(uow))
- {
- //NOTE What about content that has the contenttype as part of its composition?
- var query = Query.Builder.Where(x => x.ContentTypeId == contentTypeId);
- var contents = repository.GetByQuery(query);
+ ///
+ /// Deletes all content of specified type. All children of deleted content is moved to Recycle Bin.
+ ///
+ /// This needs extra care and attention as its potentially a dangerous and extensive operation
+ /// Id of the
+ /// Optional Id of the user issueing the delete operation
+ public void DeleteContentOfType(int contentTypeId, int userId = -1)
+ {
+ using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
+ {
+ //NOTE What about content that has the contenttype as part of its composition?
+ var query = Query.Builder.Where(x => x.ContentTypeId == contentTypeId);
+ var contents = repository.GetByQuery(query);
- var e = new DeleteEventArgs { Id = contentTypeId };
- if (Deleting != null)
- Deleting(contents, e);
+ var e = new DeleteEventArgs {Id = contentTypeId};
+ if (Deleting != null)
+ Deleting(contents, e);
- if (!e.Cancel)
- {
- foreach (var content in contents)
- {
- ((Content)content).ChangeTrashedState(true);
- repository.AddOrUpdate(content);
- }
+ if (!e.Cancel)
+ {
+ foreach (var content in contents.OrderByDescending(x => x.ParentId))
+ {
+ //Look for children of current content and move that to trash before the current content is deleted
+ var c = content;
+ var childQuery = Query.Builder.Where(x => x.Path.StartsWith(c.Path));
+ var children = repository.GetByQuery(childQuery);
- uow.Commit();
+ foreach (var child in children)
+ {
+ if (child.ContentType.Id != contentTypeId)
+ MoveToRecycleBin(child, userId);
+ }
- if (Deleted != null)
- Deleted(contents, e);
+ //Permantly delete the content
+ Delete(content, userId);
+ }
- Audit.Add(AuditTypes.Delete, string.Format("Delete Content of Type {0} performed by user", contentTypeId), userId == -1 ? 0 : userId, -1);
- }
- }
- }
+ if (Deleted != null)
+ Deleted(contents, e);
- ///
- /// Permanently deletes an object
- ///
- /// Please note that this method will completely remove the Content from the database
- /// The to delete
- /// Optional Id of the User deleting the Content
+ Audit.Add(AuditTypes.Delete,
+ string.Format("Delete Content of Type {0} performed by user", contentTypeId),
+ userId == -1 ? 0 : userId, -1);
+ }
+ }
+ }
+
+ ///
+ /// Permanently deletes an object.
+ ///
+ ///
+ /// This method will also delete associated media files, child content and possibly associated domains.
+ ///
+ /// Please note that this method will completely remove the Content from the database
+ /// The to delete
+ /// Optional Id of the User deleting the Content
public void Delete(IContent content, int userId = -1)
{
- //TODO Ensure that content is unpublished when deleted
- //TODO This method should handle/react to errors when there is a constraint issue with the content being deleted
- //TODO Children should either be deleted or moved to the recycle bin
-
var e = new DeleteEventArgs { Id = content.Id };
if (Deleting != null)
Deleting(content, e);
@@ -685,8 +860,21 @@ namespace Umbraco.Core.Services
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
- SetWriter(content, userId);
- repository.Delete(content);
+ //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);
+ }
+
+ SetWriter(content, userId);
+ repository.Delete(content);
uow.Commit();
if (Deleted != null)
@@ -789,22 +977,32 @@ namespace Umbraco.Core.Services
/// Optional Id of the User deleting the Content
public void MoveToRecycleBin(IContent content, int userId = -1)
{
- //TODO If content item has children those should also be moved to the recycle bin
- //TODO Unpublish deleted content + children
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
-
var e = new MoveEventArgs { ParentId = -20 };
if (Trashing != null)
Trashing(content, e);
if (!e.Cancel)
{
- SetWriter(content, userId);
- content.ChangeTrashedState(true);
- repository.AddOrUpdate(content);
- uow.Commit();
+ //Make sure that published content is unpublished before being moved to the Recycle Bin
+ if (HasPublishedVersion(content.Id))
+ {
+ UnPublish(content, userId);
+ }
+
+ //Move children to Recycle Bin before the 'possible parent' is moved there
+ var children = GetChildren(content.Id);
+ foreach (var child in children)
+ {
+ MoveToRecycleBin(child, userId);
+ }
+
+ SetWriter(content, userId);
+ content.ChangeTrashedState(true);
+ repository.AddOrUpdate(content);
+ uow.Commit();
if (Trashed != null)
Trashed(content, e);
@@ -827,6 +1025,8 @@ namespace Umbraco.Core.Services
/// Optional Id of the User moving the Content
public void Move(IContent content, int parentId, int userId = -1)
{
+ //TODO Verify that SortOrder + Path is updated correctly
+ //TODO Add a check to see if parentId = -20 because then we should change the TrashState
var e = new MoveEventArgs { ParentId = parentId };
if (Moving != null)
Moving(content, e);
@@ -882,15 +1082,16 @@ namespace Umbraco.Core.Services
}
}
- ///
- /// Copies an object by creating a new Content object of the same type and copies all data from the current
- /// to the new copy which is returned.
- ///
- /// The to copy
- /// Id of the Content's new Parent
- /// Optional Id of the User copying the Content
- /// The newly created object
- public IContent Copy(IContent content, int parentId, int userId = -1)
+ ///
+ /// Copies an object by creating a new Content object of the same type and copies all data from the current
+ /// to the new copy which is returned.
+ ///
+ /// The to copy
+ /// Id of the Content's new Parent
+ /// Boolean indicating whether the copy should be related to the original
+ /// Optional Id of the User copying the Content
+ /// The newly created object
+ public IContent Copy(IContent content, int parentId, bool relateToOriginal, int userId = -1)
{
var e = new CopyEventArgs { ParentId = parentId };
if (Copying != null)
@@ -911,13 +1112,77 @@ namespace Umbraco.Core.Services
repository.AddOrUpdate(copy);
uow.Commit();
+
+ var uploadFieldId = new Guid("5032a6e6-69e3-491d-bb28-cd31cd11086c");
+ if (content.Properties.Any(x => x.PropertyType.DataTypeControlId == uploadFieldId))
+ {
+ bool isUpdated = false;
+ var fs = FileSystemProviderManager.Current.GetFileSystemProvider();
+
+ //Loop through properties to check if the content contains media that should be deleted
+ foreach (var property in content.Properties.Where(x => x.PropertyType.DataTypeControlId == uploadFieldId
+ && string.IsNullOrEmpty(x.Value.ToString()) == false))
+ {
+ if (fs.FileExists(IOHelper.MapPath(property.Value.ToString())))
+ {
+ var currentPath = fs.GetRelativePath(property.Value.ToString());
+ var propertyId = copy.Properties.First(x => x.Alias == property.Alias).Id;
+ var newPath = fs.GetRelativePath(propertyId, System.IO.Path.GetFileName(currentPath));
+
+ fs.CopyFile(currentPath, newPath);
+ copy.SetValue(property.Alias, fs.GetUrl(newPath));
+
+ //Copy thumbnails
+ foreach (var thumbPath in fs.GetThumbnails(currentPath))
+ {
+ var newThumbPath = fs.GetRelativePath(propertyId, System.IO.Path.GetFileName(thumbPath));
+ fs.CopyFile(thumbPath, newThumbPath);
+ }
+ isUpdated = true;
+ }
+ }
+
+ if (isUpdated)
+ {
+ repository.AddOrUpdate(copy);
+ uow.Commit();
+ }
+ }
}
+
+ //NOTE This 'Relation' part should eventually be delegated to a RelationService
+ if (relateToOriginal)
+ {
+ RelationType relationType = null;
+ using (var relationTypeRepository = _repositoryFactory.CreateRelationTypeRepository(uow))
+ {
+ relationType = relationTypeRepository.Get(1);
+ }
+
+ using (var relationRepository = _repositoryFactory.CreateRelationRepository(uow))
+ {
+ var relation = new Relation(content.Id, copy.Id, relationType);
+ relationRepository.AddOrUpdate(relation);
+ uow.Commit();
+ }
+
+ Audit.Add(AuditTypes.Copy,
+ string.Format("Copied content with Id: '{0}' related to original content with Id: '{1}'",
+ copy.Id, content.Id), copy.WriterId, copy.Id);
+ }
+
+ //Look for children and copy those as well
+ var children = GetChildren(content.Id);
+ foreach (var child in children)
+ {
+ Copy(child, copy.Id, relateToOriginal, userId);
+ }
}
if (Copied != null)
Copied(copy, e);
- Audit.Add(AuditTypes.Delete, "Copy Content performed by user", content.WriterId, content.Id);
+ Audit.Add(AuditTypes.Copy, "Copy Content performed by user", content.WriterId, content.Id);
return copy;
}
@@ -928,7 +1193,7 @@ namespace Umbraco.Core.Services
/// The to send to publication
/// Optional Id of the User issueing the send to publication
/// True if sending publication was succesfull otherwise false
- public bool SendToPublication(IContent content, int userId = -1)
+ internal bool SendToPublication(IContent content, int userId = -1)
{
//TODO Implement something similar to this
var e = new SendToPublishEventArgs();
diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs
index d27e4a467c..11a7336337 100644
--- a/src/Umbraco.Core/Services/IContentService.cs
+++ b/src/Umbraco.Core/Services/IContentService.cs
@@ -19,11 +19,6 @@ namespace Umbraco.Core.Services
///
IContent CreateContent(int parentId, string contentTypeAlias, int userId = -1);
- //TODO Add GetLatestUnpublishedVersions(int id){}
- //TODO Add CreateNewVersion method? Its currently used in the Document API when Publishing - latest version is published,
- //but then a new version is created so latest version is not published.
- //IContent CreateNewVersion(int id); -> should not be necessary as Version number is changed when updating
-
///
/// Gets an object by Id
///
@@ -90,45 +85,6 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
IEnumerable GetContentInRecycleBin();
- ///
- /// Re-Publishes all Content
- ///
- /// Optional Id of the User issueing the publishing
- /// True if publishing succeeded, otherwise False
- bool RePublishAll(int userId = -1);
-
- ///
- /// Publishes a single object
- ///
- /// The to publish
- /// Optional Id of the User issueing the publishing
- /// True if publishing succeeded, otherwise False
- bool Publish(IContent content, int userId = -1);
-
- ///
- /// Publishes a object and all its children
- ///
- /// The to publish along with its children
- /// Optional Id of the User issueing the publishing
- /// True if publishing succeeded, otherwise False
- bool PublishWithChildren(IContent content, int userId = -1);
-
- ///
- /// UnPublishes a single object
- ///
- /// The to publish
- /// Optional Id of the User issueing the publishing
- /// True if unpublishing succeeded, otherwise False
- bool UnPublish(IContent content, int userId = -1);
-
- ///
- /// Saves and Publishes a single object
- ///
- /// The to save and publish
- /// Optional Id of the User issueing the publishing
- /// True if publishing succeeded, otherwise False
- bool SaveAndPublish(IContent content, int userId = -1);
-
///
/// Saves a single object
///
@@ -166,14 +122,6 @@ namespace Umbraco.Core.Services
/// Optional Id of the user issueing the delete operation
void DeleteContentOfType(int contentTypeId, int userId = -1);
- ///
- /// Permanently deletes an object
- ///
- /// Please note that this method will completely remove the Content from the database
- /// The to delete
- /// Optional Id of the User deleting the Content
- void Delete(IContent content, int userId = -1);
-
///
/// Permanently deletes versions from an object prior to a specific date.
///
@@ -229,24 +177,6 @@ namespace Umbraco.Core.Services
///
void EmptyRecycleBin();
- ///
- /// Copies an object by creating a new Content object of the same type and copies all data from the current
- /// to the new copy which is returned.
- ///
- /// The to copy
- /// Id of the Content's new Parent
- /// Optional Id of the User copying the Content
- /// The newly created object
- IContent Copy(IContent content, int parentId, int userId = -1);
-
- ///
- /// Sends an to Publication, which executes handlers and events for the 'Send to Publication' action.
- ///
- /// The to send to publication
- /// Optional Id of the User issueing the send to publication
- /// True if sending publication was succesfull otherwise false
- bool SendToPublication(IContent content, int userId = -1);
-
///
/// Rollback an object to a previous version.
/// This will create a new version, which is a copy of all the old data.
@@ -256,5 +186,122 @@ namespace Umbraco.Core.Services
/// Optional Id of the User issueing the rollback of the Content
/// The newly created object
IContent Rollback(int id, Guid versionId, int userId = -1);
+
+ ///
+ /// Gets a collection of objects by its name or partial name
+ ///
+ /// Id of the Parent to retrieve Children from
+ /// Full or partial name of the children
+ /// An Enumerable list of objects
+ IEnumerable GetChildrenByName(int parentId, string name);
+
+ ///
+ /// Gets a collection of objects by Parent Id
+ ///
+ /// Id of the Parent to retrieve Descendants from
+ /// An Enumerable list of objects
+ IEnumerable GetDescendants(int id);
+
+ ///
+ /// Gets a collection of objects by Parent Id
+ ///
+ /// item to retrieve Descendants from
+ /// An Enumerable list of objects
+ IEnumerable GetDescendants(IContent content);
+
+ ///
+ /// Gets a specific version of an item.
+ ///
+ /// Id of the to retrieve version from
+ /// Id of the version to retrieve
+ /// An item
+ IContent GetByIdVersion(int id, Guid versionId);
+
+ ///
+ /// Gets the published version of an item
+ ///
+ /// Id of the to retrieve version from
+ /// An item
+ IContent GetPublishedVersion(int id);
+
+ ///
+ /// Checks whether an item has any children
+ ///
+ /// Id of the
+ /// True if the content has any children otherwise False
+ bool HasChildren(int id);
+
+ ///
+ /// Checks whether an item has any published versions
+ ///
+ /// Id of the
+ /// True if the content has any published version otherwise False
+ bool HasPublishedVersion(int id);
+
+ ///
+ /// Re-Publishes all Content
+ ///
+ /// Optional Id of the User issueing the publishing
+ /// Optional boolean to avoid having the cache refreshed when calling this RePublish method. By default this method will update the cache.
+ /// True if publishing succeeded, otherwise False
+ bool RePublishAll(int userId = -1, bool omitCacheRefresh = false);
+
+ ///
+ /// Publishes a single object
+ ///
+ /// The to publish
+ /// Optional Id of the User issueing the publishing
+ /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.
+ /// True if publishing succeeded, otherwise False
+ bool Publish(IContent content, int userId = -1, bool omitCacheRefresh = false);
+
+ ///
+ /// Publishes a object and all its children
+ ///
+ /// The to publish along with its children
+ /// Optional Id of the User issueing the publishing
+ /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.
+ /// True if publishing succeeded, otherwise False
+ bool PublishWithChildren(IContent content, int userId = -1, bool omitCacheRefresh = false);
+
+ ///
+ /// UnPublishes a single object
+ ///
+ /// The to publish
+ /// Optional Id of the User issueing the publishing
+ /// Optional boolean to avoid having the cache refreshed when calling this Unpublish method. By default this method will update the cache.
+ /// True if unpublishing succeeded, otherwise False
+ bool UnPublish(IContent content, int userId = -1, bool omitCacheRefresh = false);
+
+ ///
+ /// Saves and Publishes a single object
+ ///
+ /// The to save and publish
+ /// Optional Id of the User issueing the publishing
+ /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache.
+ /// True if publishing succeeded, otherwise False
+ bool SaveAndPublish(IContent content, int userId = -1, bool omitCacheRefresh = false);
+
+ ///
+ /// Permanently deletes an object.
+ ///
+ ///
+ /// This method will also delete associated media files, child content and possibly associated domains.
+ ///
+ /// Please note that this method will completely remove the Content from the database
+ /// The to delete
+ /// Optional Id of the User deleting the Content
+ void Delete(IContent content, int userId = -1);
+
+ ///
+ /// Copies an object by creating a new Content object of the same type and copies all data from the current
+ /// to the new copy which is returned.
+ ///
+ /// The to copy
+ /// Id of the Content's new Parent
+ /// Boolean indicating whether the copy should be related to the original
+ /// Optional Id of the User copying the Content
+ /// The newly created object
+ IContent Copy(IContent content, int parentId, bool relateToOriginal, int userId = -1);
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Persistence/Repositories/RelationRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/RelationRepositoryTest.cs
index 9fba87f316..8730dc3aad 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/RelationRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/RelationRepositoryTest.cs
@@ -48,7 +48,7 @@ namespace Umbraco.Tests.Persistence.Repositories
// Act
var relationType = repositoryType.Get(1);
- var relation = new Relation(1047, 1048) { RelationType = relationType };
+ var relation = new Relation(1047, 1048, relationType);
repository.AddOrUpdate(relation);
unitOfWork.Commit();
@@ -270,8 +270,8 @@ namespace Umbraco.Tests.Persistence.Repositories
Content subpage2 = MockedContent.CreateSimpleContent(contentType, "Text Page 2", textpage.Id);
ServiceContext.ContentService.Save(subpage2, 0);
- var relation = new Relation(textpage.Id, subpage.Id) {RelationType = relateContent, Comment = string.Empty};
- var relation2 = new Relation(textpage.Id, subpage2.Id) { RelationType = relateContent, Comment = string.Empty};
+ var relation = new Relation(textpage.Id, subpage.Id, relateContent) { Comment = string.Empty };
+ var relation2 = new Relation(textpage.Id, subpage2.Id, relateContent) { Comment = string.Empty };
relationRepository.AddOrUpdate(relation);
relationRepository.AddOrUpdate(relation2);
unitOfWork.Commit();
diff --git a/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs b/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs
index 17b9ad9130..822799e8d6 100644
--- a/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs
+++ b/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs
@@ -1,7 +1,5 @@
using System;
using System.IO;
-using System.Web;
-using System.Xml;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Configuration;
@@ -11,7 +9,6 @@ using Umbraco.Core.ObjectResolution;
using Umbraco.Core.Persistence;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
-using Umbraco.Web.Strategies;
using umbraco.editorControls.tinyMCE3;
using umbraco.interfaces;
@@ -66,25 +63,7 @@ namespace Umbraco.Tests.Publishing
[Test]
public void Can_Publish_And_Update_Xml_Cache()
{
- // Arrange
- var httpContext = base.GetUmbracoContext("/test", 1234).HttpContext;
- var updateContentCache = new UpdateContentCache(httpContext);
- var contentService = ServiceContext.ContentService;
- var content = contentService.GetById(1046);
-
- // Act
- bool published = contentService.Publish(content, 0);
-
- // Assert
- Assert.That(published, Is.True);
- Assert.That(content.Published, Is.True);
- Assert.IsTrue(httpContext.Items.Contains("UmbracoXmlContextContent"));
-
- var document = httpContext.Items["UmbracoXmlContextContent"] as XmlDocument;
- Console.Write(document.OuterXml);
- document.Save("umbraco.config");
-
- updateContentCache.Unsubscribe();
+ //TODO Create new test
}
public void CreateTestData()
diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs
index b1269c0596..d04cd84b26 100644
--- a/src/Umbraco.Tests/Services/ContentServiceTests.cs
+++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs
@@ -25,6 +25,19 @@ namespace Umbraco.Tests.Services
[SetUp]
public override void Initialize()
{
+ //this ensures its reset
+ //PluginManager.Current = new PluginManager();
+
+ //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
+ /*PluginManager.Current.AssembliesToScan = new[]
+ {
+ typeof(IDataType).Assembly,
+ typeof(tinyMCE3dataType).Assembly
+ };
+
+ DataTypesResolver.Current = new DataTypesResolver(
+ PluginManager.Current.ResolveDataTypes());*/
+
base.Initialize();
CreateTestData();
@@ -33,6 +46,10 @@ namespace Umbraco.Tests.Services
[TearDown]
public override void TearDown()
{
+ //reset the app context
+ //DataTypesResolver.Reset();
+ //PluginManager.Current = null;
+
base.TearDown();
}
@@ -207,10 +224,12 @@ namespace Umbraco.Tests.Services
{
// Arrange
var contentService = ServiceContext.ContentService;
+ var parent = ServiceContext.ContentService.GetById(1046);
+ ServiceContext.ContentService.Publish(parent);//Publishing root, so Text Page 2 can be updated.
var subpage2 = contentService.GetById(1048);
subpage2.Name = "Text Page 2 Updated";
subpage2.SetValue("author", "Jane Doe");
- contentService.Save(subpage2, 0);
+ contentService.SaveAndPublish(subpage2, 0);//NOTE New versions are only added between publish-state-changed, so publishing to ensure addition version.
// Act
var versions = contentService.GetVersions(1048);
@@ -636,7 +655,7 @@ namespace Umbraco.Tests.Services
var content = contentService.GetById(1048);
// Act
- var copy = contentService.Copy(content, content.ParentId, 0);
+ var copy = contentService.Copy(content, content.ParentId, false, 0);
// Assert
Assert.That(copy, Is.Not.Null);
@@ -654,19 +673,21 @@ namespace Umbraco.Tests.Services
{
// Arrange
var contentService = ServiceContext.ContentService;
+ var parent = ServiceContext.ContentService.GetById(1046);
+ ServiceContext.ContentService.Publish(parent);//Publishing root, so Text Page 2 can be updated.
var subpage2 = contentService.GetById(1048);
var version = subpage2.Version;
var nameBeforeRollback = subpage2.Name;
subpage2.Name = "Text Page 2 Updated";
subpage2.SetValue("author", "Jane Doe");
- contentService.Save(subpage2, 0);
+ contentService.SaveAndPublish(subpage2, 0);//Saving and publishing, so a new version is created
// Act
var rollback = contentService.Rollback(1048, version, 0);
// Assert
Assert.That(rollback, Is.Not.Null);
- Assert.AreNotEqual(rollback.Version, version);
+ Assert.AreNotEqual(rollback.Version, subpage2.Version);
Assert.That(rollback.GetValue("author"), Is.Not.EqualTo("Jane Doe"));
Assert.AreEqual(nameBeforeRollback, rollback.Name);
}
diff --git a/src/Umbraco.Web/ContentExtensions.cs b/src/Umbraco.Web/ContentExtensions.cs
deleted file mode 100644
index e135dcf24e..0000000000
--- a/src/Umbraco.Web/ContentExtensions.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using System.Xml.Linq;
-using Umbraco.Core;
-using Umbraco.Core.Models;
-
-namespace Umbraco.Web
-{
- public static class ContentExtensions
- {
- ///
- /// Creates the xml representation for the object
- ///
- /// to generate xml for
- /// Xml representation of the passed in
- public static XElement ToXml(this IContent content)
- {
- //nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias);
- var nodeName = content.ContentType.Alias.ToUmbracoAlias(StringAliasCaseType.CamelCase, true);
- var niceUrl = content.Name.Replace(" ", "-").ToLower();
-
- if (UmbracoContext.Current != null)
- {
- var niceUrlsProvider = UmbracoContext.Current.NiceUrlProvider;
- niceUrl = niceUrlsProvider.GetNiceUrl(content.Id);
- }
-
- var xml = new XElement(nodeName,
- new XAttribute("id", content.Id),
- new XAttribute("parentID", content.Level > 1 ? content.ParentId : -1),
- new XAttribute("level", content.Level),
- new XAttribute("writerID", content.WriterId),
- new XAttribute("creatorID", content.CreatorId),
- new XAttribute("nodeType", content.ContentType.Id),
- new XAttribute("template", content.Template == null ? string.Empty : content.Template.Id.ToString()),
- new XAttribute("sortOrder", content.SortOrder),
- new XAttribute("createDate", content.CreateDate),
- new XAttribute("updateDate", content.UpdateDate),
- new XAttribute("nodeName", content.Name),
- new XAttribute("urlName", niceUrl),//Format Url ?
- new XAttribute("writerName", content.GetWriterProfile().Name),
- new XAttribute("creatorName", content.GetCreatorProfile().Name),
- new XAttribute("path", content.Path));
-
- foreach (var property in content.Properties)
- {
- if (property == null) continue;
-
- xml.Add(property.ToXml());
-
- //Check for umbracoUrlName convention
- if (property.Alias == "umbracoUrlName" && property.Value.ToString().Trim() != string.Empty)
- xml.SetAttributeValue("urlName", property.Value);
- }
-
- return xml;
- }
-
- ///
- /// Creates the xml representation for the object
- ///
- /// to generate xml for
- /// Boolean indicating whether the xml should be generated for preview
- /// Xml representation of the passed in
- public static XElement ToXml(this IContent content, bool isPreview)
- {
- //TODO Do a proper implementation of this
- //If current IContent is published we should get latest unpublished version
- return content.ToXml();
- }
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Strategies/DeletedTemplate.cs b/src/Umbraco.Web/Strategies/DeletedTemplate.cs
deleted file mode 100644
index 2e2bcb27c1..0000000000
--- a/src/Umbraco.Web/Strategies/DeletedTemplate.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using umbraco.interfaces;
-
-namespace Umbraco.Web.Strategies
-{
- ///
- /// Subscribes to Template Deleted event in order to remove Foreign key reference
- /// from cmsDocument table (Template Id set explicitly on content), and from cmsDocumentType
- /// table where the ContentType references the Template Allowed/Default.
- ///
- internal class DeletedTemplate : IApplicationStartupHandler
- {
-
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Strategies/TrashedContent.cs b/src/Umbraco.Web/Strategies/TrashedContent.cs
deleted file mode 100644
index 731b995f6b..0000000000
--- a/src/Umbraco.Web/Strategies/TrashedContent.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using umbraco.interfaces;
-
-namespace Umbraco.Web.Strategies
-{
- internal class TrashedContent : IApplicationStartupHandler
- {
-
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Strategies/UpdateContentCache.cs b/src/Umbraco.Web/Strategies/UpdateContentCache.cs
deleted file mode 100644
index c9054391d0..0000000000
--- a/src/Umbraco.Web/Strategies/UpdateContentCache.cs
+++ /dev/null
@@ -1,238 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Web;
-using System.Web.Caching;
-using System.Xml;
-using Umbraco.Core;
-using Umbraco.Core.Configuration;
-using Umbraco.Core.Models;
-using Umbraco.Core.Publishing;
-using Umbraco.Core.Services;
-using umbraco.interfaces;
-using umbraco.presentation.nodeFactory;
-using Node = umbraco.NodeFactory.Node;
-
-namespace Umbraco.Web.Strategies
-{
- internal class UpdateContentCache : IApplicationStartupHandler
- {
- // Sync access to internal cache
- private static readonly object XmlContentInternalSyncLock = new object();
- private const string XmlContextContentItemKey = "UmbracoXmlContextContent";
- private readonly HttpContextBase _httpContext;
- private readonly ServiceContext _serviceContext;
-
- public UpdateContentCache()
- {
- _httpContext = new HttpContextWrapper(HttpContext.Current);
- _serviceContext = ApplicationContext.Current.Services;
-
- BasePublishingStrategy.Published += PublishingStrategy_Published;
- }
-
- public UpdateContentCache(HttpContextBase httpContext)
- {
- _httpContext = httpContext;
- _serviceContext = ApplicationContext.Current.Services;
-
- BasePublishingStrategy.Published += PublishingStrategy_Published;
- }
-
- void PublishingStrategy_Published(object sender, PublishingEventArgs e)
- {
- if((sender is IContent) == false) return;
-
- //var e = new DocumentCacheEventArgs();
- //FireBeforeUpdateDocumentCache(d, e);
-
- var content = sender as IContent;
-
- // lock the xml cache so no other thread can write to it at the same time
- // note that some threads could read from it while we hold the lock, though
- lock (XmlContentInternalSyncLock)
- {
- XmlDocument wip = XmlContent;
-
- ClearContextCache();
-
- XmlContent = UpdateXmlAndSitemap(content, wip, false);//Update sitemap is usually set to true
- }
-
- // clear cached field values
- if (_httpContext != null)
- {
- Cache httpCache = _httpContext.Cache;
- string cachedFieldKeyStart = String.Format("contentItem{0}_", content.Id);
- var foundKeys = new List();
- foreach (DictionaryEntry cacheItem in httpCache)
- {
- string key = cacheItem.Key.ToString();
- if (key.StartsWith(cachedFieldKeyStart))
- foundKeys.Add(key);
- }
- foreach (string foundKey in foundKeys)
- {
- httpCache.Remove(foundKey);
- }
- }
-
- //Action.RunActionHandlers(d, ActionPublish.Instance);
- //FireAfterUpdateDocumentCache(d, e);
- }
-
- private XmlDocument UpdateXmlAndSitemap(IContent content, XmlDocument xmlContentCopy, bool updateSitemapProvider)
- {
- // check if document *is* published, it could be unpublished by an event
- if (content.Published)
- {
- int parentId = content.Level == 1 ? -1 : content.ParentId;
- var contentXmlNode = content.ToXml(false).GetXmlNode();
- var xmlNode = xmlContentCopy.ImportNode(contentXmlNode, true);
- xmlContentCopy = AppendContentXml(content.Id, content.Level, parentId, xmlNode, xmlContentCopy);
-
- // update sitemapprovider
- if (updateSitemapProvider && SiteMap.Provider is UmbracoSiteMapProvider)
- {
- try
- {
- var prov = (UmbracoSiteMapProvider)SiteMap.Provider;
- var n = new Node(content.Id, true);
- if (!String.IsNullOrEmpty(n.Url) && n.Url != "/#")
- {
- prov.UpdateNode(n);
- }
- else
- {
- //Log.Add(LogTypes.Error, content.Id, "Can't update Sitemap Provider due to empty Url in node");
- }
- }
- catch (Exception ee)
- {
- //Log.Add(LogTypes.Error, content.Id, string.Format("Error adding node to Sitemap Provider in PublishNodeDo(): {0}", ee));
- }
- }
- }
-
- return xmlContentCopy;
- }
-
- private XmlDocument AppendContentXml(int id, int level, int parentId, XmlNode docNode, XmlDocument xmlContentCopy)
- {
- // Find the document in the xml cache
- XmlNode x = xmlContentCopy.GetElementById(id.ToString());
-
- // if the document is not there already then it's a new document
- // we must make sure that its document type exists in the schema
- var xmlContentCopy2 = xmlContentCopy;
- if (x == null && UmbracoSettings.UseLegacyXmlSchema == false)
- {
- //TODO Look into the validate schema method - seems a bit odd
- //Move to Contract ?
- xmlContentCopy = ValidateSchema(docNode.Name, xmlContentCopy);
- if (xmlContentCopy != xmlContentCopy2)
- docNode = xmlContentCopy.ImportNode(docNode, true);
- }
-
- // Find the parent (used for sortering and maybe creation of new node)
- XmlNode parentNode;
- if (level == 1)
- parentNode = xmlContentCopy.DocumentElement;
- else
- parentNode = xmlContentCopy.GetElementById(parentId.ToString());
-
- if (parentNode != null)
- {
- if (x == null)
- {
- x = docNode;
- parentNode.AppendChild(x);
- }
- else
- {
- //TODO
- //TransferValuesFromDocumentXmlToPublishedXml(docNode, x);
- }
-
- // TODO: Update with new schema!
- string xpath = UmbracoSettings.UseLegacyXmlSchema ? "./node" : "./* [@id]";
- XmlNodeList childNodes = parentNode.SelectNodes(xpath);
-
- // Maybe sort the nodes if the added node has a lower sortorder than the last
- if (childNodes.Count > 0)
- {
- int siblingSortOrder =
- int.Parse(childNodes[childNodes.Count - 1].Attributes.GetNamedItem("sortOrder").Value);
- int currentSortOrder = int.Parse(x.Attributes.GetNamedItem("sortOrder").Value);
- if (childNodes.Count > 1 && siblingSortOrder > currentSortOrder)
- {
- //SortNodes(ref parentNode);
- }
- }
- }
-
- return xmlContentCopy;
- }
-
- ///
- /// Clear HTTPContext cache if any
- ///
- private void ClearContextCache()
- {
- // If running in a context very important to reset context cache or else new nodes are missing
- if (_httpContext != null && _httpContext.Items.Contains(XmlContextContentItemKey))
- _httpContext.Items.Remove(XmlContextContentItemKey);
- }
-
- private XmlDocument ValidateSchema(string docTypeAlias, XmlDocument xmlDoc)
- {
- // check if doctype is defined in schema else add it
- // can't edit the doctype of an xml document, must create a new document
-
- var doctype = xmlDoc.DocumentType;
- var subset = doctype.InternalSubset;
- if (!subset.Contains(string.Format("", docTypeAlias)))
- {
- subset = string.Format("\r\n\r\n{1}", docTypeAlias, subset);
- var xmlDoc2 = new XmlDocument();
- doctype = xmlDoc2.CreateDocumentType("root", null, null, subset);
- xmlDoc2.AppendChild(doctype);
- var root = xmlDoc2.ImportNode(xmlDoc.DocumentElement, true);
- xmlDoc2.AppendChild(root);
-
- // apply
- xmlDoc = xmlDoc2;
- }
-
- return xmlDoc;
- }
-
- private XmlDocument XmlContent
- {
- get
- {
- var content = _httpContext.Items[XmlContextContentItemKey] as XmlDocument;
- if (content == null)
- {
- //content = global::umbraco.content.Instance.XmlContent;
- var dtd = _serviceContext.ContentTypeService.GetDtd();
-
- content = new XmlDocument();
- content.LoadXml(
- String.Format("{0}{1}{0}",
- Environment.NewLine,
- dtd));
-
- _httpContext.Items[XmlContextContentItemKey] = content;
- }
- return content;
- }
- set { _httpContext.Items[XmlContextContentItemKey] = value; }
- }
-
- internal void Unsubscribe()
- {
- BasePublishingStrategy.Published -= PublishingStrategy_Published;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Strategies/UpdateMultipleContentCache.cs b/src/Umbraco.Web/Strategies/UpdateMultipleContentCache.cs
deleted file mode 100644
index fa06e82927..0000000000
--- a/src/Umbraco.Web/Strategies/UpdateMultipleContentCache.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Collections.Generic;
-using Umbraco.Core.Models;
-using Umbraco.Core.Publishing;
-
-namespace Umbraco.Web.Strategies
-{
- public class UpdateMultipleContentCache
- {
- public UpdateMultipleContentCache()
- {
- PublishingStrategy.Published += PublishingStrategy_Published;
- }
-
- void PublishingStrategy_Published(object sender, Core.PublishingEventArgs e)
- {
- if ((sender is IEnumerable) == false) return;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index d53a84f417..bfc30126df 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -247,7 +247,6 @@
-
@@ -328,10 +327,6 @@
-
-
-
-
ASPXCodeBehind
@@ -2186,7 +2181,9 @@
umbraco_org_umbraco_update_CheckForUpgrade
-
+
+
+
10.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)