using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using NPoco; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Persistence.UnitOfWork; using Umbraco.Core.Serialization; using Umbraco.Web.Composing; namespace Umbraco.Web.PublishedCache.NuCache.DataSource { // provides efficient database access for NuCache internal class Database { public ContentNodeKit GetContentSource(IScopeUnitOfWork uow, int id) { // fixme - missing things // // new: documentDto.publishDate // new: documentDto.publishUserId // new: documentDto.templateId - the published one // fixme still, we have an issue with names // // node.text == contentVersion.text (and we use contentVersion.text to keep track of things) // !! when creating a new version, the old version versionDate = publishDate, what else? // // new: documentDto.publishName === THE ONE WE USE FOR URLS !! // var dto = uow.Database.Fetch(new Sql(@"SELECT n.id Id, n.uniqueId Uid, uContent.contentTypeId ContentTypeId, n.level Level, n.path Path, n.sortOrder SortOrder, n.parentId ParentId, cver.versionId Version, n.createDate CreateDate, n.nodeUser CreatorId, cver.text DraftName, c.updateDate DraftVersionDate, c.writerUserId DraftWriterId, dver.templateId DraftTemplateId, doc.edited Edited, nuDraft.data DraftData, docPub.text PubName, doc.publishDate PubVersionDate, doc.publishUserId PubWriterId, doc.templateId PubTemplateId, doc.published Published, nuPub.data PubData FROM umbracoNode n JOIN uContent c ON (c.nodeId=n.id) LEFT JOIN uDocument doc ON (doc.nodeId=n.id) LEFT JOIN uContentVersion cver ON (n.id=cver.nodeId AND cver.current=1) LEFT JOIN uDocumentVersion dver ON (cver.id=dver.id) LEFT JOIN cmsContentNu nuDraft ON (nuDraft.nodeId=n.id AND nuDraft.published=0) LEFT JOIN cmsContentNu nuPub ON (nuPub.nodeId=n.id AND nuPub.published=1) WHERE n.nodeObjectType=@objType AND n.id=@id ", new { objType = Constants.ObjectTypes.Document, /*id =*/ id })).FirstOrDefault(); return dto == null ? new ContentNodeKit() : CreateContentNodeKit(dto); } public ContentNodeKit GetMediaSource(IScopeUnitOfWork uow, int id) { // should be only 1 version for medias var dto = uow.Database.Fetch(new Sql(@"SELECT n.id Id, n.uniqueId Uid, uContent.contentTypeId ContentTypeId, n.level Level, n.path Path, n.sortOrder SortOrder, n.parentId ParentId, n.createDate CreateDate, n.nodeUser CreatorId, n.text PubName, ver.versionId PubVersion, ver.versionDate PubVersionDate, nuPub.data PubData FROM umbracoNode n JOIN uContent ON (uContent.nodeId=n.id) JOIN uContentVersion ver ON (ver.contentId=n.id) LEFT JOIN cmsContentNu nuPub ON (nuPub.nodeId=n.id AND nuPub.published=1) WHERE n.nodeObjectType=@objType AND n.id=@id ", new { objType = Constants.ObjectTypes.Media, /*id =*/ id })).FirstOrDefault(); return dto == null ? new ContentNodeKit() : CreateMediaNodeKit(dto); } // we want arrays, we want them all loaded, not an enumerable public IEnumerable GetAllContentSources(IScopeUnitOfWork uow) { return uow.Database.Query(new Sql(@"SELECT n.id Id, n.uniqueId Uid, uContent.contentTypeId ContentTypeId, n.level Level, n.path Path, n.sortOrder SortOrder, n.parentId ParentId, n.createDate CreateDate, n.nodeUser CreatorId, docDraft.text DraftName, docDraft.versionId DraftVersion, docDraft.updateDate DraftVersionDate, docDraft.writerUserId DraftWriterId, docDraft.templateId DraftTemplateId, nuDraft.data DraftData, docPub.text PubName, docPub.versionId PubVersion, docPub.updateDate PubVersionDate, docPub.writerUserId PubWriterId, docPub.templateId PubTemplateId, nuPub.data PubData FROM umbracoNode n JOIN uContent ON (uContent.nodeId=n.id) LEFT JOIN cmsDocument docDraft ON (docDraft.nodeId=n.id AND docDraft.newest=1 AND docDraft.published=0) LEFT JOIN cmsDocument docPub ON (docPub.nodeId=n.id AND docPub.published=1) LEFT JOIN cmsContentNu nuDraft ON (nuDraft.nodeId=n.id AND nuDraft.published=0) LEFT JOIN cmsContentNu nuPub ON (nuPub.nodeId=n.id AND nuPub.published=1) WHERE n.nodeObjectType=@objType ORDER BY n.level, n.sortOrder ", new { objType = Constants.ObjectTypes.Document })).Select(CreateContentNodeKit); } public IEnumerable GetAllMediaSources(IScopeUnitOfWork uow) { // should be only 1 version for medias return uow.Database.Query(new Sql(@"SELECT n.id Id, n.uniqueId Uid, uContent.contentTypeId ContentTypeId, n.level Level, n.path Path, n.sortOrder SortOrder, n.parentId ParentId, n.createDate CreateDate, n.nodeUser CreatorId, n.text PubName, ver.versionId PubVersion, ver.versionDate PubVersionDate, nuPub.data PubData FROM umbracoNode n JOIN uContent ON (uContent.nodeId=n.id) JOIN uContentVersion ver ON (ver.contentId=n.id) LEFT JOIN cmsContentNu nuPub ON (nuPub.nodeId=n.id AND nuPub.published=1) WHERE n.nodeObjectType=@objType ORDER BY n.level, n.sortOrder ", new { objType = Constants.ObjectTypes.Media })).Select(CreateMediaNodeKit); } public IEnumerable GetBranchContentSources(IScopeUnitOfWork uow, int id) { return uow.Database.Query(new Sql(@"SELECT n.id Id, n.uniqueId Uid, uContent.contentTypeId ContentTypeId, n.level Level, n.path Path, n.sortOrder SortOrder, n.parentId ParentId, n.createDate CreateDate, n.nodeUser CreatorId, docDraft.text DraftName, docDraft.versionId DraftVersion, docDraft.updateDate DraftVersionDate, docDraft.writerUserId DraftWriterId, docDraft.templateId DraftTemplateId, nuDraft.data DraftData, docPub.text PubName, docPub.versionId PubVersion, docPub.updateDate PubVersionDate, docPub.writerUserId PubWriterId, docPub.templateId PubTemplateId, nuPub.data PubData FROM umbracoNode n JOIN umbracoNode x ON (n.id=x.id OR n.path LIKE " + uow.SqlContext.SqlSyntax.GetConcat("x.path", "',%'") + @") JOIN uContent ON (uContent.nodeId=n.id) LEFT JOIN cmsDocument docDraft ON (docDraft.nodeId=n.id AND docDraft.newest=1 AND docDraft.published=0) LEFT JOIN cmsDocument docPub ON (docPub.nodeId=n.id AND docPub.published=1) LEFT JOIN cmsContentNu nuDraft ON (nuDraft.nodeId=n.id AND nuDraft.published=0) LEFT JOIN cmsContentNu nuPub ON (nuPub.nodeId=n.id AND nuPub.published=1) WHERE n.nodeObjectType=@objType AND x.id=@id ORDER BY n.level, n.sortOrder ", new { objType = Constants.ObjectTypes.Document, /*id =*/ id })).Select(CreateContentNodeKit); } public IEnumerable GetBranchMediaSources(IScopeUnitOfWork uow, int id) { // should be only 1 version for medias return uow.Database.Query(new Sql(@"SELECT n.id Id, n.uniqueId Uid, uContent.contentTypeId ContentTypeId, n.level Level, n.path Path, n.sortOrder SortOrder, n.parentId ParentId, n.createDate CreateDate, n.nodeUser CreatorId, n.text PubName, ver.versionId PubVersion, ver.versionDate PubVersionDate, nuPub.data PubData FROM umbracoNode n JOIN umbracoNode x ON (n.id=x.id OR n.path LIKE " + uow.SqlContext.SqlSyntax.GetConcat("x.path", "',%'") + @") JOIN uContent ON (uContent.nodeId=n.id) JOIN uContentVersion ver ON (ver.contentId=n.id) LEFT JOIN cmsContentNu nuPub ON (nuPub.nodeId=n.id AND nuPub.published=1) WHERE n.nodeObjectType=@objType AND x.id=@id ORDER BY n.level, n.sortOrder ", new { objType = Constants.ObjectTypes.Media, /*id =*/ id })).Select(CreateMediaNodeKit); } public IEnumerable GetTypeContentSources(IScopeUnitOfWork uow, IEnumerable ids) { return uow.Database.Query(new Sql(@"SELECT n.id Id, n.uniqueId Uid, uContent.contentTypeId ContentTypeId, n.level Level, n.path Path, n.sortOrder SortOrder, n.parentId ParentId, n.createDate CreateDate, n.nodeUser CreatorId, docDraft.text DraftName, docDraft.versionId DraftVersion, docDraft.updateDate DraftVersionDate, docDraft.writerUserId DraftWriterId, docDraft.templateId DraftTemplateId, nuDraft.data DraftData, docPub.text PubName, docPub.versionId PubVersion, docPub.updateDate PubVersionDate, docPub.writerUserId PubWriterId, docPub.templateId PubTemplateId, nuPub.data PubData FROM umbracoNode n JOIN uContent ON (uContent.nodeId=n.id) LEFT JOIN cmsDocument docDraft ON (docDraft.nodeId=n.id AND docDraft.newest=1 AND docDraft.published=0) LEFT JOIN cmsDocument docPub ON (docPub.nodeId=n.id AND docPub.published=1) LEFT JOIN cmsContentNu nuDraft ON (nuDraft.nodeId=n.id AND nuDraft.published=0) LEFT JOIN cmsContentNu nuPub ON (nuPub.nodeId=n.id AND nuPub.published=1) WHERE n.nodeObjectType=@objType AND uContent.contentTypeId IN (@ids) ORDER BY n.level, n.sortOrder ", new { objType = Constants.ObjectTypes.Document, /*id =*/ ids })).Select(CreateContentNodeKit); } public IEnumerable GetTypeMediaSources(IScopeUnitOfWork uow, IEnumerable ids) { // should be only 1 version for medias return uow.Database.Query(new Sql(@"SELECT n.id Id, n.uniqueId Uid, uContent.contentTypeId ContentTypeId, n.level Level, n.path Path, n.sortOrder SortOrder, n.parentId ParentId, n.createDate CreateDate, n.nodeUser CreatorId, n.text PubName, ver.versionId PubVersion, ver.versionDate PubVersionDate, nuPub.data PubData FROM umbracoNode n JOIN uContent ON (uContent.nodeId=n.id) JOIN uContentVersion ver ON (ver.contentId=n.id) LEFT JOIN cmsContentNu nuPub ON (nuPub.nodeId=n.id AND nuPub.published=1) WHERE n.nodeObjectType=@objType AND uContent.contentTypeId IN (@ids) ORDER BY n.level, n.sortOrder ", new { objType = Constants.ObjectTypes.Media, /*id =*/ ids })).Select(CreateMediaNodeKit); } private static ContentNodeKit CreateContentNodeKit(ContentSourceDto dto) { ContentData d = null; ContentData p = null; if (dto.Edited) { if (dto.DraftData == null) { //throw new Exception("Missing cmsContentNu content for node " + dto.Id + ", consider rebuilding."); Current.Logger.Warn("Missing cmsContentNu content for node " + dto.Id + ", consider rebuilding."); } else { d = new ContentData { Name = dto.DraftName, Published = false, TemplateId = dto.DraftTemplateId, Version = dto.Version, VersionDate = dto.DraftVersionDate, WriterId = dto.DraftWriterId, Properties = DeserializeData(dto.DraftData) }; } } if (dto.Published) { if (dto.PubData == null) { //throw new Exception("Missing cmsContentNu content for node " + dto.Id + ", consider rebuilding."); Current.Logger.Warn("Missing cmsContentNu content for node " + dto.Id + ", consider rebuilding."); } else { p = new ContentData { Name = dto.PubName, Published = true, TemplateId = dto.PubTemplateId, Version = dto.Version, VersionDate = dto.PubVersionDate, WriterId = dto.PubWriterId, Properties = DeserializeData(dto.PubData) }; } } var n = new ContentNode(dto.Id, dto.Uid, dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); var s = new ContentNodeKit { Node = n, ContentTypeId = dto.ContentTypeId, DraftData = d, PublishedData = p }; return s; } private static ContentNodeKit CreateMediaNodeKit(ContentSourceDto dto) { if (dto.PubData == null) throw new Exception("No data for media " + dto.Id); var p = new ContentData { Name = dto.PubName, Published = true, TemplateId = -1, Version = dto.Version, VersionDate = dto.PubVersionDate, WriterId = dto.CreatorId, // what-else? Properties = DeserializeData(dto.PubData) }; var n = new ContentNode(dto.Id, dto.Uid, dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId); var s = new ContentNodeKit { Node = n, ContentTypeId = dto.ContentTypeId, PublishedData = p }; return s; } private static Dictionary DeserializeData(string data) { // by default JsonConvert will deserialize our numeric values as Int64 // which is bad, because they were Int32 in the database - take care var settings = new JsonSerializerSettings { Converters = new List { new ForceInt32Converter() } }; return JsonConvert.DeserializeObject>(data, settings); } } }