diff --git a/src/Umbraco.Core/Models/ContentExtensions.cs b/src/Umbraco.Core/Models/ContentExtensions.cs index e2b81de74e..3e0f95d8a5 100644 --- a/src/Umbraco.Core/Models/ContentExtensions.cs +++ b/src/Umbraco.Core/Models/ContentExtensions.cs @@ -154,7 +154,7 @@ namespace Umbraco.Core.Models private static void SetFileOnContent(IContentBase content, string propertyTypeAlias, string name, Stream fileStream) { var property = content.Properties.FirstOrDefault(x => x.Alias == propertyTypeAlias); - if(property == null) + if (property == null) return; bool supportsResizing = false; @@ -204,7 +204,7 @@ namespace Umbraco.Core.Models XmlNode uploadFieldConfigNode = UmbracoSettings.ImageAutoFillImageProperties.SelectSingleNode( string.Format("uploadField [@alias = \"{0}\"]", propertyTypeAlias)); - + if (uploadFieldConfigNode != null) { //Only add dimensions to web images @@ -236,7 +236,7 @@ namespace Umbraco.Core.Models content.SetValue(propertyNode.FirstChild.Value, propertyValue); } } - + private static string Resize(MediaFileSystem fileSystem, string path, string extension, int maxWidthHeight, string fileNameAddition) { var fileNameThumb = DoResize(fileSystem, path, extension, GetDimensions(fileSystem, path).Item1, GetDimensions(fileSystem, path).Item2, maxWidthHeight, fileNameAddition); @@ -347,16 +347,28 @@ namespace Umbraco.Core.Models return new Tuple(widthTh, heightTh, newFileName); } + /// + /// Gets the for the Creator of this media item. + /// + internal static IProfile GetCreatorProfile(this IMedia media) + { + using (var repository = RepositoryResolver.Current.Factory.CreateUserRepository( + PetaPocoUnitOfWorkProvider.CreateUnitOfWork())) + { + return repository.GetProfileById(media.CreatorId); + } + } + /// /// Gets the for the Creator of this content. /// public static IProfile GetCreatorProfile(this IContent content) { - using (var repository = RepositoryResolver.Current.Factory.CreateUserRepository( - PetaPocoUnitOfWorkProvider.CreateUnitOfWork())) - { - return repository.GetProfileById(content.CreatorId); - } + using (var repository = RepositoryResolver.Current.Factory.CreateUserRepository( + PetaPocoUnitOfWorkProvider.CreateUnitOfWork())) + { + return repository.GetProfileById(content.CreatorId); + } } /// @@ -364,11 +376,11 @@ namespace Umbraco.Core.Models /// public static IProfile GetWriterProfile(this IContent content) { - using(var repository = RepositoryResolver.Current.Factory.CreateUserRepository( - PetaPocoUnitOfWorkProvider.CreateUnitOfWork())) - { - return repository.GetProfileById(content.WriterId); - } + using (var repository = RepositoryResolver.Current.Factory.CreateUserRepository( + PetaPocoUnitOfWorkProvider.CreateUnitOfWork())) + { + return repository.GetProfileById(content.WriterId); + } } /// @@ -391,30 +403,73 @@ namespace Umbraco.Core.Models /// Xml representation of the passed in public static XElement ToXml(this IContent content) { + //nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias); var nodeName = UmbracoSettings.UseLegacyXmlSchema ? "node" : content.ContentType.Alias.ToSafeAliasWithForcingCheck(); - var niceUrl = content.Name.FormatUrl().ToLower(); + + var x = content.ToXml(nodeName); + x.Add(new XAttribute("nodeType", content.ContentType.Id)); + x.Add(new XAttribute("creatorName", content.GetCreatorProfile().Name)); + x.Add(new XAttribute("writerName", content.GetWriterProfile().Name)); + x.Add(new XAttribute("writerID", content.WriterId)); + x.Add(new XAttribute("template", content.Template == null ? "0" : content.Template.Id.ToString())); + if (UmbracoSettings.UseLegacyXmlSchema) + { + x.Add(new XAttribute("nodeTypeAlias", content.ContentType.Alias)); + } + + return x; + + } + + /// + /// Creates the xml representation for the object + /// + /// to generate xml for + /// Xml representation of the passed in + internal static XElement ToXml(this IMedia media) + { + //nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias); + var nodeName = UmbracoSettings.UseLegacyXmlSchema ? "node" : media.ContentType.Alias.ToSafeAliasWithForcingCheck(); + + var x = media.ToXml(nodeName); + x.Add(new XAttribute("nodeType", media.ContentType.Id)); + x.Add(new XAttribute("writerName", media.GetCreatorProfile().Name)); + x.Add(new XAttribute("writerID", media.CreatorId)); + x.Add(new XAttribute("version", media.Version)); + x.Add(new XAttribute("template", 0)); + if (UmbracoSettings.UseLegacyXmlSchema) + { + x.Add(new XAttribute("nodeTypeAlias", media.ContentType.Alias)); + } + + return x; + } + + /// + /// Creates the xml representation for the object + /// + /// to generate xml for + /// + /// Xml representation of the passed in + private static XElement ToXml(this IContentBase contentBase, string nodeName) + { + var niceUrl = contentBase.Name.FormatUrl().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", ""), - UmbracoSettings.UseLegacyXmlSchema ? new XAttribute("nodeTypeAlias", content.ContentType.Alias) : null); + new XAttribute("id", contentBase.Id), + new XAttribute("parentID", contentBase.Level > 1 ? contentBase.ParentId : -1), + new XAttribute("level", contentBase.Level), + new XAttribute("creatorID", contentBase.CreatorId), + new XAttribute("sortOrder", contentBase.SortOrder), + new XAttribute("createDate", contentBase.CreateDate.ToString("s")), + new XAttribute("updateDate", contentBase.UpdateDate.ToString("s")), + new XAttribute("nodeName", contentBase.Name), + new XAttribute("urlName", niceUrl),//Format Url ? + new XAttribute("path", contentBase.Path), + new XAttribute("isDoc", "")); - foreach (var property in content.Properties) + foreach (var property in contentBase.Properties) { if (property == null) continue; diff --git a/src/Umbraco.Tests/Models/ContentXmlTest.cs b/src/Umbraco.Tests/Models/ContentXmlTest.cs index d080e037b6..f05230d191 100644 --- a/src/Umbraco.Tests/Models/ContentXmlTest.cs +++ b/src/Umbraco.Tests/Models/ContentXmlTest.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Xml.Linq; using NUnit.Framework; using Umbraco.Core; @@ -61,6 +62,27 @@ namespace Umbraco.Tests.Models // Assert Assert.That(element, Is.Not.Null); Assert.That(element.Name.LocalName, Is.EqualTo(nodeName)); + Assert.AreEqual(content.Id.ToString(), (string)element.Attribute("id")); + Assert.AreEqual(content.ParentId.ToString(), (string)element.Attribute("parentID")); + Assert.AreEqual(content.Level.ToString(), (string)element.Attribute("level")); + Assert.AreEqual(content.CreatorId.ToString(), (string)element.Attribute("creatorID")); + Assert.AreEqual(content.SortOrder.ToString(), (string)element.Attribute("sortOrder")); + Assert.AreEqual(content.CreateDate.ToString("s"), (string)element.Attribute("createDate")); + Assert.AreEqual(content.UpdateDate.ToString("s"), (string)element.Attribute("updateDate")); + Assert.AreEqual(content.Name, (string)element.Attribute("nodeName")); + Assert.AreEqual(content.Name.FormatUrl().ToLower(), (string)element.Attribute("urlName")); + Assert.AreEqual(content.Path, (string)element.Attribute("path")); + Assert.AreEqual("", (string)element.Attribute("isDoc")); + Assert.AreEqual(content.ContentType.Id.ToString(), (string)element.Attribute("nodeType")); + Assert.AreEqual(content.GetCreatorProfile().Name, (string)element.Attribute("creatorName")); + Assert.AreEqual(content.GetWriterProfile().Name, (string)element.Attribute("writerName")); + Assert.AreEqual(content.WriterId.ToString(), (string)element.Attribute("writerID")); + Assert.AreEqual(content.Template == null ? "0" : content.Template.Id.ToString(), (string)element.Attribute("template")); + + Assert.AreEqual(content.Properties["title"].Value.ToString(), element.Elements("title").Single().Value); + Assert.AreEqual(content.Properties["bodyText"].Value.ToString(), element.Elements("bodyText").Single().Value); + Assert.AreEqual(content.Properties["keywords"].Value.ToString(), element.Elements("keywords").Single().Value); + Assert.AreEqual(content.Properties["metaDescription"].Value.ToString(), element.Elements("metaDescription").Single().Value); } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs index b3a7f257c9..f0bf4c35c4 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs @@ -169,5 +169,31 @@ namespace Umbraco.Tests.TestHelpers.Entities return mediaType; } + + public static MediaType CreateImageMediaType() + { + var mediaType = new MediaType(-1) + { + Alias = "image", + Name = "Image", + Description = "ContentType used for images", + Icon = ".sprTreeDoc3", + Thumbnail = "doc.png", + SortOrder = 1, + CreatorId = 0, + Trashed = false + }; + + var contentCollection = new PropertyTypeCollection(); + contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Nvarchar) { Alias = "umbracoFile", Name = "File", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -90 }); + contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Integer) { Alias = "umbracoWidth", Name = "Width", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeDefinitionId = -90 }); + contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Integer) { Alias = "umbracoHeight", Name = "Height", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeDefinitionId = -90 }); + contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Integer) { Alias = "umbracoBytes", Name = "Bytes", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeDefinitionId = -90 }); + contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Integer) { Alias = "umbracoExtension", Name = "File Extension", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeDefinitionId = -90 }); + + mediaType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Media", SortOrder = 1 }); + + return mediaType; + } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index bf6540e963..27380cb453 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -175,6 +175,7 @@ + diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Search/ExamineEvents.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Search/ExamineEvents.cs index 1d30d3eb88..c0012a9e85 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Search/ExamineEvents.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Search/ExamineEvents.cs @@ -1,37 +1,124 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Web; +using Examine.Providers; +using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Core.Services; +using Umbraco.Web; using umbraco.BusinessLogic; using Examine; using UmbracoExamine; using Lucene.Net.Documents; using umbraco.businesslogic; +using umbraco.cms.businesslogic.media; using umbraco.interfaces; +using Content = umbraco.cms.businesslogic.Content; namespace umbraco.presentation.umbraco.Search { /// /// Used to wire up events for Examine /// - public class ExamineEvents : IApplicationStartupHandler + public class ExamineEvents : IApplicationEventHandler { - public ExamineEvents() - : base() + public void OnApplicationInitialized(UmbracoApplication httpApplication, ApplicationContext applicationContext) { + } + + public void OnApplicationStarting(UmbracoApplication httpApplication, ApplicationContext applicationContext) + { + } + + /// + /// Once the app has booted, then bind to the events + /// + /// + /// + public void OnApplicationStarted(UmbracoApplication httpApplication, ApplicationContext applicationContext) + { + //do not continue if the app context or database is not ready + if (!applicationContext.IsConfigured || !applicationContext.DatabaseContext.IsDatabaseConfigured) + return; + + //TODO: Remove this in 6.1!!! It will not be needed because we've changed the Examine Events entirely since UmbracoExamine is + // in the core. This is only temporary to get this task completed for 6.0: + // http://issues.umbraco.org/issue/U4-1530 + MediaService.Saved += MediaService_Saved; + MediaService.Deleted += MediaService_Deleted; + MediaService.Moved += MediaService_Moved; + ContentService.Saved += ContentService_Saved; + ContentService.Deleted += ContentService_Deleted; + ContentService.Moved += ContentService_Moved; + + //bind to examine events var contentIndexer = ExamineManager.Instance.IndexProviderCollection["InternalIndexer"] as UmbracoContentIndexer; if (contentIndexer != null) { - contentIndexer.DocumentWriting += new EventHandler(indexer_DocumentWriting); + contentIndexer.DocumentWriting += indexer_DocumentWriting; } var memberIndexer = ExamineManager.Instance.IndexProviderCollection["InternalMemberIndexer"] as UmbracoMemberIndexer; if (memberIndexer != null) { - memberIndexer.DocumentWriting += new EventHandler(indexer_DocumentWriting); + memberIndexer.DocumentWriting += indexer_DocumentWriting; } } + void ContentService_Moved(IContentService sender, Umbraco.Core.Events.MoveEventArgs e) + { + IndexConent(e.Entity); + } + + void ContentService_Deleted(IContentService sender, Umbraco.Core.Events.DeleteEventArgs e) + { + e.DeletedEntities.ForEach( + content => + ExamineManager.Instance.DeleteFromIndex( + content.Id.ToString(), + ExamineManager.Instance.IndexProviderCollection.OfType().Where(x => x.EnableDefaultEventHandler))); + } + + void ContentService_Saved(IContentService sender, Umbraco.Core.Events.SaveEventArgs e) + { + e.SavedEntities.ForEach(IndexConent); + } + + void MediaService_Moved(IMediaService sender, Umbraco.Core.Events.MoveEventArgs e) + { + IndexMedia(e.Entity); + } + + void MediaService_Deleted(IMediaService sender, Umbraco.Core.Events.DeleteEventArgs e) + { + e.DeletedEntities.ForEach( + media => + ExamineManager.Instance.DeleteFromIndex( + media.Id.ToString(), + ExamineManager.Instance.IndexProviderCollection.OfType().Where(x => x.EnableDefaultEventHandler))); + } + + void MediaService_Saved(IMediaService sender, Umbraco.Core.Events.SaveEventArgs e) + { + e.SavedEntities.ForEach(IndexMedia); + } + + private void IndexMedia(IMedia sender) + { + ExamineManager.Instance.ReIndexNode( + sender.ToXml(), "media", + ExamineManager.Instance.IndexProviderCollection.OfType().Where(x => x.EnableDefaultEventHandler)); + } + + private void IndexConent(IContent sender) + { + ExamineManager.Instance.ReIndexNode( + sender.ToXml(), "content", + ExamineManager.Instance.IndexProviderCollection.OfType().Where(x => x.EnableDefaultEventHandler)); + } + /// /// Event handler to create a lower cased version of the node name, this is so we can support case-insensitive searching and still /// use the Whitespace Analyzer @@ -52,5 +139,6 @@ namespace umbraco.presentation.umbraco.Search } } + } } \ No newline at end of file