Backported changes from 6.1 to fix how RePublishAll behaves in the content service to ensure its the same as what was done with

Document.RePublishAll
This commit is contained in:
Shannon Deminick
2013-03-20 00:19:36 +06:00
parent ee9f91b5cf
commit a76ffe8daf
8 changed files with 705 additions and 607 deletions

View File

@@ -120,7 +120,17 @@ namespace Umbraco.Core.Persistence
public static void DropTable(this Database db, string tableName)
{
var sql = new Sql(string.Format("DROP TABLE {0}", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName)));
var sql = new Sql(string.Format(
SqlSyntaxContext.SqlSyntaxProvider.DropTable,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName)));
db.Execute(sql);
}
public static void TruncateTable(this Database db, string tableName)
{
var sql = new Sql(string.Format(
SqlSyntaxContext.SqlSyntaxProvider.TruncateTable,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName)));
db.Execute(sql);
}

View File

@@ -31,6 +31,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
string InsertData { get; }
string UpdateData { get; }
string DeleteData { get; }
string TruncateTable { get; }
string CreateConstraint { get; }
string DeleteConstraint { get; }
string CreateForeignKeyConstraint { get; }

View File

@@ -42,6 +42,14 @@ namespace Umbraco.Core.Persistence.SqlSyntax
return false;
}
/// <summary>
/// SqlCe doesn't support the Truncate Table syntax, so we just have to do a DELETE FROM which is slower but we have no choice.
/// </summary>
public override string TruncateTable
{
get { return "DELETE FROM {0}"; }
}
public override string GetIndexType(IndexTypes indexTypes)
{
string indexType;

View File

@@ -436,6 +436,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
public virtual string InsertData { get { return "INSERT INTO {0} ({1}) VALUES ({2})"; } }
public virtual string UpdateData { get { return "UPDATE {0} SET {1} WHERE {2}"; } }
public virtual string DeleteData { get { return "DELETE FROM {0} WHERE {1}"; } }
public virtual string TruncateTable { get { return "TRUNCATE TABLE {0}"; } }
public virtual string CreateConstraint { get { return "ALTER TABLE {0} ADD CONSTRAINT {1} {2} ({3})"; } }
public virtual string DeleteConstraint { get { return "ALTER TABLE {0} DROP CONSTRAINT {1}"; } }

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Umbraco.Core.Auditing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
@@ -22,6 +23,9 @@ namespace Umbraco.Core.Services
private readonly IContentService _contentService;
private readonly IMediaService _mediaService;
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
//Support recursive locks because some of the methods that require locking call other methods that require locking.
//for example, the Move method needs to be locked but this calls the Save method which also needs to be locked.
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
public ContentTypeService(IContentService contentService, IMediaService mediaService)
: this(new PetaPocoUnitOfWorkProvider(), new RepositoryFactory(), contentService, mediaService)
@@ -173,19 +177,22 @@ namespace Umbraco.Core.Services
{
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(contentType), this))
return;
_contentService.DeleteContentOfType(contentType.Id);
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentTypeRepository(uow))
{
repository.Delete(contentType);
uow.Commit();
using (new WriteLock(Locker))
{
_contentService.DeleteContentOfType(contentType.Id);
DeletedContentType.RaiseEvent(new DeleteEventArgs<IContentType>(contentType, false), this);
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentTypeRepository(uow))
{
repository.Delete(contentType);
uow.Commit();
Audit.Add(AuditTypes.Delete, string.Format("Delete ContentType performed by user"), userId, contentType.Id);
DeletedContentType.RaiseEvent(new DeleteEventArgs<IContentType>(contentType, false), this);
}
Audit.Add(AuditTypes.Delete, string.Format("Delete ContentType performed by user"), userId, contentType.Id);
}
}
/// <summary>
@@ -200,27 +207,30 @@ namespace Umbraco.Core.Services
{
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(contentTypes), this))
return;
var contentTypeList = contentTypes.ToList();
foreach (var contentType in contentTypeList)
{
_contentService.DeleteContentOfType(contentType.Id);
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentTypeRepository(uow))
{
foreach (var contentType in contentTypeList)
{
repository.Delete(contentType);
}
using (new WriteLock(Locker))
{
var contentTypeList = contentTypes.ToList();
foreach (var contentType in contentTypeList)
{
_contentService.DeleteContentOfType(contentType.Id);
}
uow.Commit();
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentTypeRepository(uow))
{
foreach (var contentType in contentTypeList)
{
repository.Delete(contentType);
}
DeletedContentType.RaiseEvent(new DeleteEventArgs<IContentType>(contentTypes, false), this);
}
uow.Commit();
Audit.Add(AuditTypes.Delete, string.Format("Delete ContentTypes performed by user"), userId, -1);
DeletedContentType.RaiseEvent(new DeleteEventArgs<IContentType>(contentTypes, false), this);
}
Audit.Add(AuditTypes.Delete, string.Format("Delete ContentTypes performed by user"), userId, -1);
}
}
/// <summary>
@@ -357,20 +367,22 @@ namespace Umbraco.Core.Services
{
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(mediaType), this))
return;
_mediaService.DeleteMediaOfType(mediaType.Id, userId);
using (new WriteLock(Locker))
{
_mediaService.DeleteMediaOfType(mediaType.Id, userId);
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow))
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow))
{
repository.Delete(mediaType);
uow.Commit();
repository.Delete(mediaType);
uow.Commit();
DeletedMediaType.RaiseEvent(new DeleteEventArgs<IMediaType>(mediaType, false), this);
}
DeletedMediaType.RaiseEvent(new DeleteEventArgs<IMediaType>(mediaType, false), this);
}
Audit.Add(AuditTypes.Delete, string.Format("Delete MediaType performed by user"), userId, mediaType.Id);
Audit.Add(AuditTypes.Delete, string.Format("Delete MediaType performed by user"), userId, mediaType.Id);
}
}
/// <summary>
@@ -383,26 +395,28 @@ namespace Umbraco.Core.Services
{
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(mediaTypes), this))
return;
var mediaTypeList = mediaTypes.ToList();
foreach (var mediaType in mediaTypeList)
{
_mediaService.DeleteMediaOfType(mediaType.Id);
}
using (new WriteLock(Locker))
{
var mediaTypeList = mediaTypes.ToList();
foreach (var mediaType in mediaTypeList)
{
_mediaService.DeleteMediaOfType(mediaType.Id);
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow))
{
foreach (var mediaType in mediaTypeList)
{
repository.Delete(mediaType);
}
uow.Commit();
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow))
{
foreach (var mediaType in mediaTypeList)
{
repository.Delete(mediaType);
}
uow.Commit();
DeletedMediaType.RaiseEvent(new DeleteEventArgs<IMediaType>(mediaTypes, false), this);
}
DeletedMediaType.RaiseEvent(new DeleteEventArgs<IMediaType>(mediaTypes, false), this);
}
Audit.Add(AuditTypes.Delete, string.Format("Delete MediaTypes performed by user"), userId, -1);
Audit.Add(AuditTypes.Delete, string.Format("Delete MediaTypes performed by user"), userId, -1);
}
}
/// <summary>

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Xml.Linq;
using Umbraco.Core.Auditing;
using Umbraco.Core.Events;
@@ -19,6 +20,9 @@ namespace Umbraco.Core.Services
{
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
private readonly RepositoryFactory _repositoryFactory;
//Support recursive locks because some of the methods that require locking call other methods that require locking.
//for example, the Move method needs to be locked but this calls the Save method which also needs to be locked.
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
public MediaService(RepositoryFactory repositoryFactory)
: this(new PetaPocoUnitOfWorkProvider(), repositoryFactory)
@@ -306,32 +310,35 @@ namespace Umbraco.Core.Services
/// <param name="userId">Id of the User moving the Media</param>
public void Move(IMedia media, int parentId, int userId = 0)
{
//This ensures that the correct method is called if this method is used to Move to recycle bin.
if (parentId == -21)
{
MoveToRecycleBin(media, userId);
return;
}
using (new WriteLock(Locker))
{
//This ensures that the correct method is called if this method is used to Move to recycle bin.
if (parentId == -21)
{
MoveToRecycleBin(media, userId);
return;
}
if (Moving.IsRaisedEventCancelled(new MoveEventArgs<IMedia>(media, parentId), this))
return;
if (Moving.IsRaisedEventCancelled(new MoveEventArgs<IMedia>(media, parentId), this))
return;
media.ParentId = parentId;
Save(media, userId);
media.ParentId = parentId;
Save(media, userId);
//Ensure that Path and Level is updated on children
var children = GetChildren(media.Id);
if (children.Any())
{
var parentPath = media.Path;
var parentLevel = media.Level;
var updatedDescendents = UpdatePathAndLevelOnChildren(children, parentPath, parentLevel);
Save(updatedDescendents, userId);
}
//Ensure that Path and Level is updated on children
var children = GetChildren(media.Id);
if (children.Any())
{
var parentPath = media.Path;
var parentLevel = media.Level;
var updatedDescendents = UpdatePathAndLevelOnChildren(children, parentPath, parentLevel);
Save(updatedDescendents, userId);
}
Moved.RaiseEvent(new MoveEventArgs<IMedia>(media, false, parentId), this);
Moved.RaiseEvent(new MoveEventArgs<IMedia>(media, false, parentId), this);
Audit.Add(AuditTypes.Move, "Move Media performed by user", userId, media.Id);
Audit.Add(AuditTypes.Move, "Move Media performed by user", userId, media.Id);
}
}
/// <summary>
@@ -403,32 +410,42 @@ namespace Umbraco.Core.Services
/// <param name="mediaTypeId">Id of the <see cref="IMediaType"/></param>
/// <param name="userId">Optional id of the user deleting the media</param>
public void DeleteMediaOfType(int mediaTypeId, int userId = 0)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMediaRepository(uow))
{
using (new WriteLock(Locker))
{
//NOTE What about media that has the contenttype as part of its composition?
//The ContentType has to be removed from the composition somehow as it would otherwise break
//Dbl.check+test that the ContentType's Id is removed from the ContentType2ContentType table
var query = Query<IMedia>.Builder.Where(x => x.ContentTypeId == mediaTypeId);
var contents = repository.GetByQuery(query);
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMediaRepository(uow))
{
//NOTE What about media that has the contenttype as part of its composition?
//The ContentType has to be removed from the composition somehow as it would otherwise break
//Dbl.check+test that the ContentType's Id is removed from the ContentType2ContentType table
var query = Query<IMedia>.Builder.Where(x => x.ContentTypeId == mediaTypeId);
var contents = repository.GetByQuery(query);
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMedia>(contents), this))
return;
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMedia>(contents), this))
return;
foreach (var content in contents)
{
((Core.Models.Media)content).ChangeTrashedState(true);
repository.AddOrUpdate(content);
}
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<IMedia>.Builder.Where(x => x.Path.StartsWith(c.Path));
var children = repository.GetByQuery(childQuery);
uow.Commit();
foreach (var child in children)
{
if (child.ContentType.Id != mediaTypeId)
MoveToRecycleBin(child, userId);
}
Deleted.RaiseEvent(new DeleteEventArgs<IMedia>(contents, false), this);
}
//Permantly delete the content
Delete(content, userId);
}
}
Audit.Add(AuditTypes.Delete, "Delete Media items by Type performed by user", userId, -1);
}
Audit.Add(AuditTypes.Delete, "Delete Media items by Type performed by user", userId, -1);
}
}
/// <summary>
/// Permanently deletes an <see cref="IMedia"/> object
@@ -523,25 +540,28 @@ namespace Umbraco.Core.Services
return;
}
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMediaRepository(uow))
{
media.CreatorId = userId;
repository.AddOrUpdate(media);
uow.Commit();
using (new WriteLock(Locker))
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMediaRepository(uow))
{
media.CreatorId = userId;
repository.AddOrUpdate(media);
uow.Commit();
var xml = media.ToXml();
var poco = new ContentXmlDto { NodeId = media.Id, Xml = xml.ToString(SaveOptions.None) };
var exists = uow.Database.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new { Id = media.Id }) != null;
int result = exists
? uow.Database.Update(poco)
: Convert.ToInt32(uow.Database.Insert(poco));
}
var xml = media.ToXml();
var poco = new ContentXmlDto {NodeId = media.Id, Xml = xml.ToString(SaveOptions.None)};
var exists = uow.Database.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new {Id = media.Id}) != null;
int result = exists
? uow.Database.Update(poco)
: Convert.ToInt32(uow.Database.Insert(poco));
}
if(raiseEvents)
Saved.RaiseEvent(new SaveEventArgs<IMedia>(media, false), this);
if (raiseEvents)
Saved.RaiseEvent(new SaveEventArgs<IMedia>(media, false), this);
Audit.Add(AuditTypes.Save, "Save Media performed by user", media.CreatorId, media.Id);
Audit.Add(AuditTypes.Save, "Save Media performed by user", media.CreatorId, media.Id);
}
}
/// <summary>

View File

@@ -298,18 +298,30 @@ namespace Umbraco.Tests.Services
{
// Arrange
var contentService = ServiceContext.ContentService;
var contentTypeService = ServiceContext.ContentTypeService;
var contentType = contentTypeService.GetContentType("umbTextpage");
var rootContent = contentService.GetRootContent();
foreach (var c in rootContent)
{
contentService.PublishWithChildren(c);
}
//for testing we need to clear out the contentXml table so we can see if it worked
var provider = new PetaPocoUnitOfWorkProvider();
var uow = provider.GetUnitOfWork();
using (RepositoryResolver.Current.ResolveByType<IContentRepository>(uow))
{
uow.Database.TruncateTable("cmsContentXml");
}
// Act
var published = contentService.RePublishAll(0);
var contents = contentService.GetContentOfContentType(contentType.Id);
// Assert
Assert.That(published, Is.True);
Assert.That(contents.First(x => x.Id == 1046).Published, Is.True);//No restrictions, so should be published
Assert.That(contents.First(x => x.Id == 1047).Published, Is.True);//Released 5 mins ago, so should be published
Assert.That(contents.First(x => x.Id == 1049).Published, Is.False);//Trashed content, so shouldn't be published
Assert.IsTrue(published);
var allContent = rootContent.Concat(rootContent.SelectMany(x => contentService.GetDescendants(x.Id)));
uow = provider.GetUnitOfWork();
using (var repo = RepositoryResolver.Current.ResolveByType<IContentRepository>(uow))
{
Assert.AreEqual(allContent.Count(), uow.Database.ExecuteScalar<int>("select count(*) from cmsContentXml"));
}
}
[Test]