Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Davide Oliva 35 posts 199 karma points
    Feb 17, 2012 @ 12:58
    Davide Oliva
    0

    multiple DataFoldersDocType?

    Hi all, my friends!
    I'll try to explain myself as best as possible, due to my limited knowledge of english language. Thanks for your patience!

    First of all, I think that datefolders is a great package and I would like to thank kipusoep for developing it and all the contributors for their help.

    I think also that will be great if we could use more than one DateFolderDocType, like as permitted with ItemDocType property.

    Example:

    DateFolderDocType:  newsArea, eventArea, meetingsArea
    ItemDocType: news, meeting, event

    newsArea permits as child content created as "news" or "event"
    meetingsArea permits as child, instead, only content created as "meeting"

    Love this great community!
    Ciao,
    Davide

  • Stuart Nisbett 11 posts 57 karma points
    Jul 05, 2013 @ 13:51
    Stuart Nisbett
    0

    I would like to see this as well

  • Robert Tunna 2 posts 22 karma points
    Dec 14, 2013 @ 19:57
    Robert Tunna
    0

    Hi Stuart,

    I have managed to adapt the code to allow multiple types on this which maybe of interest to you.  I have tried to contact the developer directly to try and get this incorporated, but the message errored which is not great, but anyway enough waffling, here is the adapted version.  This hasnt been fully tested, so let me know if there are any bugs.

    Web.Config Appsettings Example:

        <add key="datefolders:ItemDocType" value="NewsItem,EventItem" />
        <add key="datefolders:DateFolderDocType" value="News,Events" />
        <add key="datefolders:CreateDayFolders" value="true" />

    /*
    DateFolders v2.1 for umbraco 6.1.0+
    Created by Stefan Kip (kipusoep), InfoCaster
    Contributed to by Matt, Enjoy Digital
    MIT license

    Copyright (c) 2011 InfoCaster

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
    */

    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using umbraco;
    using Umbraco.Core;
    using Umbraco.Core.Events;
    using Umbraco.Core.Logging;
    using Umbraco.Core.Models;
    using Umbraco.Core.Services;
    using Umbraco.Web;
    using Umbraco.Web.UI;
    using Umbraco.Web.UI.Pages;

    namespace InfoCaster.Umbraco.Common
    {
        /// <summary>
        /// This package creates Datefolders (year/month(/day)) for the specified doctype for Umbraco 6.1.x+. For older versions please use v1.4
        ///
        /// Behavior
        ///
        /// - When you create a document with doctype "itemDocType", this package will automatically create year/month/day folders for it
        /// - When you edit the "itemDateProperty", the document is automatically moved to the correct year/month/day folder
        /// - Automatically cleans up empty year, month and day folders
        /// - Orders the items in the year, month and dayfolders by "itemDateProperty" with every action
        ///
        /// Configuration
        ///
        /// Add these keys/values to your appSettings section in the web.config:
        /// - Key: "datefolders:ItemDocType" - the doctype alias to create datefolders for (e.g. "newsItem") - comma separated values are allowed for multiple doctype aliases
        /// - Key: "datefolders:ItemDateProperty" - the property of the itemDocType to read the date from (e.g. "startDate") (don't add this key if you just want to use the document's create date)
        /// - Key: "datefolders:DateFolderDocType" - the doctype to use for creating the year/month/day folders (e.g "DateFolder")
        /// - Key: "datefolders:CreateDayFolders" - boolean indicating whether or not day folders should be created
        /// - Key: "datefolders:OrderByDecending"  - boolean indicating sort order for date folders (default: false)
        ///
        /// Changelog
        ///
        /// Version 2.1.1
        /// - Fixed cast error when using Date picker with DB type date.
        ///
        /// Version 2.1
        /// - Removed legacy configuration settings
        /// - Added datefolders:OrderByDecending
        /// - Implomented fix for 'Publish At' given by - Wayne Godfrey
        /// - Refactored to reduce code complexity
        ///
        /// Version 2.0.1
        /// - Fix to order by child name
        ///
        /// Version 2.0
        /// - Updated to use umbraco v6 api.
        /// - Fixed ordering to handle non date folders.
        ///
        /// Version 1.4
        /// - Removed Threading (Threading can cause the back-end to be out-of-sync, therefore removed)
        /// - Changed configuration keys, added prefix (legacy still works)
        /// - Added day folders feature (configurable, off by default)
        /// - Fixed silly order by hard-coded propertyAlias bug
        ///
        /// Version 1.3
        /// - Better exception handling (speechbubble)
        /// - Exception get's handled when the datefoler document type doesn't exist
        /// - Month folders are now named with a leading zero if the month number is a single number (01, 02 etc.)
        /// - Exception get's handled when a date item is created under the 'Content' root node
        ///
        /// Version 1.2
        /// - Support for multiple itemDocTypes (comma separated)
        ///
        /// Version 1.1
        /// - Tree get's synced automatically
        /// </summary>
        public class DateFolders : UmbracoApplication, IApplicationEventHandler
        {
            private readonly string[] itemDocType;
            private readonly string itemDateProperty;
            private readonly string[] dateFolderDocType;
            private readonly bool createDayFolders;
            private readonly bool orderByDescending;
            static readonly object Syncer = new object();

            /* Configuration properties:
              *
              * datefolders:ItemDocType (string)
              * datefolders:ItemDateProperty (string, optional, default create date)
              * datefolders:DateFolderDocType (string)
              * datefolders:CreateDayFolders (bool, optional, default false)
              * datefolders:OrderByDecending (bool, optional, default false)
              */

            /// <summary>
            /// Constructor, reads configuration properties and sets private properties.
            /// </summary>
            public DateFolders()
            {
                if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["datefolders:ItemDocType"]) && !string.IsNullOrEmpty(ConfigurationManager.AppSettings["datefolders:DateFolderDocType"]))
                {
                    itemDocType = ConfigurationManager.AppSettings["datefolders:ItemDocType"].Split(',');
                    itemDateProperty = ConfigurationManager.AppSettings["datefolders:ItemDateProperty"];
                    dateFolderDocType = ConfigurationManager.AppSettings["datefolders:DateFolderDocType"].Split(',');
                    var createDayFoldersString = ConfigurationManager.AppSettings["datefolders:CreateDayFolders"];
                    var orderByDescendingString = ConfigurationManager.AppSettings["datefolders:OrderByDecending"];
                    if (!string.IsNullOrEmpty(createDayFoldersString))
                    {
                        if (!bool.TryParse(createDayFoldersString, out createDayFolders))
                        {
                            LogError(new ConfigurationErrorsException("datefolders:CreateDayFolders in not a valid boolean (true/false)"), "datefolders:CreateDayFolders configuration is not a valid boolean value", false);
                        }
                    }
                    if (!string.IsNullOrEmpty(orderByDescendingString))
                    {
                        if (!bool.TryParse(orderByDescendingString, out orderByDescending))
                        {
                            LogError(new ConfigurationErrorsException("datefolders:OrderByDecending in not a valid boolean (true/false)"), "datefolders:OrderByDecending configuration is not a valid boolean value", false);
                        }
                    }
                }
            }

            public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
            {
                if (itemDocType == null || itemDocType.Length <= 0 || dateFolderDocType.Length <= 0) return;
                ContentService.Created += Document_New;
                ContentService.Saved += Document_AfterSave;
                ContentService.Trashing += Document_BeforeMoveToTrash;
                ContentService.Trashed += Document_AfterMoveToTrash;
            }

            /// <summary>
            /// Returns the node under passed parent that matches the name passed or creates a node with that name and the dateFolderDocType.
            /// Saves and publishs created/found node.
            /// </summary>
            /// <returns></returns>
            IContent GetOrCreateAndPublishDateFolder(IContentService contentService, IContent parent, string nodeName, int currentUserId, string currentDateFolderDocType)
            {
                var node = parent.Children().FirstOrDefault(x => x.ContentType.Alias == currentDateFolderDocType && x.Name.Equals(nodeName)) ??
                           contentService.CreateContent(nodeName, parent, currentDateFolderDocType, currentUserId);
                if (!node.Published) contentService.SaveAndPublish(node, currentUserId);
                return node;
            }

            void Document_New(IContentService sender, NewEventArgs<IContent> newEventArgs)
            {
                try
                {
                    // Get position of the string in the array.
                    var index = Array.FindIndex(itemDocType, row => row.Contains(newEventArgs.Alias));

                    var contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
                    var folderDocType = contentTypeService.GetContentType(dateFolderDocType[index]);
                    if (folderDocType != null)
                    {
                        if (itemDocType.Contains(newEventArgs.Alias))
                        {
                            var parent = newEventArgs.Entity.Parent();
                            var currentUserId = newEventArgs.Entity.CreatorId;
                            var now = DateTime.Now;
                            var yearFolder = GetOrCreateAndPublishDateFolder(sender, parent, now.Year.ToString(), currentUserId, dateFolderDocType[index]);
                            var monthFolder = GetOrCreateAndPublishDateFolder(sender, yearFolder, now.Month.ToString("00"), currentUserId, dateFolderDocType[index]);

                            if (createDayFolders)
                            {
                                var dayFolder = GetOrCreateAndPublishDateFolder(sender, monthFolder, now.Day.ToString("00"), currentUserId, dateFolderDocType[index]);
                                sender.Move(newEventArgs.Entity, dayFolder.Id);
                            }
                            else
                            {
                                sender.Move(newEventArgs.Entity, monthFolder.Id);
                            }

                            sender.Save(newEventArgs.Entity, currentUserId);

                            OrderChildrenByName(parent, orderByDescending);
                            OrderChildrenByName(yearFolder, orderByDescending);
                            if (createDayFolders)
                            {
                                OrderChildrenByName(monthFolder, orderByDescending);
                            }
                        }
                    }
                    else
                    {
                        ShowErrorToUser("Date folder property", string.Format("The date folder document type does not exist ({0})", dateFolderDocType));
                    }
                }
                catch (Exception ex)
                {
                    LogError(ex, "DateFolders Document_New exception", true);
                }
            }

            void Document_AfterSave(IContentService sender, SaveEventArgs<IContent> saveEventArgs)
            {
                var contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
                foreach (var content in saveEventArgs.SavedEntities)
                {
                    //var getNode = ApplicationContext.Current.Services.ContentService.GetById(content.Children());

                    //if (getNode.Level == 3) return;
                   
                    var index = Array.FindIndex(itemDocType, row => row.Contains(content.ContentType.Alias));

                    if (!itemDocType.Contains(content.ContentType.Alias)) continue;
                    var folderDocType = contentTypeService.GetContentType(dateFolderDocType[index]);
                    if (folderDocType != null)
                    {
                        if (content.ParentId > 0)
                        {
                            var date = GetItemDate(content, itemDateProperty);

                            IContent monthFolder = null;
                            IContent yearFolder = null;
                            IContent dayFolder = null;
                            var parent = content.Parent();
                            var dayChanged = false;
                            bool monthChanged;
                            bool yearChanged;

                            if (parent.ContentType.Alias.Equals(dateFolderDocType[index]))
                            {
                                if (createDayFolders)
                                {
                                    dayFolder = parent;
                                    monthFolder = dayFolder.Parent();
                                    yearFolder = monthFolder.Parent();
                                    dayChanged = date.Day.ToString("00") != dayFolder.Name;
                                }
                                else
                                {
                                    monthFolder = parent;
                                    yearFolder = monthFolder.Parent();
                                }
                                parent = yearFolder.Parent();

                                yearChanged = date.Year.ToString() != yearFolder.Name;
                                monthChanged = date.Month.ToString("00") != monthFolder.Name;
                            }
                            else
                            {
                                dayChanged = true;
                                monthChanged = true;
                                yearChanged = true;
                            }

                            if (yearChanged || monthChanged || dayChanged)
                            {
                                IContent newDayFolder = null;

                                var newYearFolder = yearChanged ? GetOrCreateAndPublishDateFolder(sender, parent, date.Year.ToString(), content.CreatorId, dateFolderDocType[index]) : yearFolder;

                                var newMonthFolder = GetOrCreateAndPublishDateFolder(sender, newYearFolder, date.Month.ToString("00"), content.CreatorId, dateFolderDocType[index]);

                                if (createDayFolders)
                                {
                                    newDayFolder = GetOrCreateAndPublishDateFolder(sender, newMonthFolder, date.Day.ToString("00"), content.CreatorId, dateFolderDocType[index]);
                                    sender.Move(content, newDayFolder.Id);
                                }
                                else
                                {
                                    sender.Move(content, newMonthFolder.Id);
                                }

                                if (content.Published)
                                {
                                    sender.SaveAndPublish(content);
                                }

                                var orderParent = newMonthFolder;
                                if (createDayFolders)
                                {
                                    orderParent = newDayFolder;
                                }

                                if (!string.IsNullOrEmpty(itemDateProperty))
                                {
                                    OrderChildrenByDateProperty(orderParent, itemDateProperty, orderByDescending);
                                }
                                else
                                {
                                    OrderChildrenByCreateDate(orderParent, orderByDescending);
                                }

                                // Delete if empty
                                if (createDayFolders)
                                {
                                    if (dayFolder != null && !dayFolder.Children().Any())
                                    {
                                        sender.Delete(dayFolder);
                                    }
                                }

                                if (monthFolder != null && !monthFolder.Children().Any())
                                {
                                    sender.Delete(monthFolder);

                                    if (yearFolder != null && !yearFolder.Children().Any())
                                    {
                                        sender.Delete(yearFolder);
                                    }
                                }

                                // Order
                                OrderChildrenByName(parent, orderByDescending);
                                OrderChildrenByName(newYearFolder, orderByDescending);
                                if (createDayFolders)
                                {
                                    OrderChildrenByName(newMonthFolder, orderByDescending);
                                }

                                var clientTools = GetClientTools();
                                if (clientTools != null) clientTools.ChangeContentFrameUrl(string.Concat("editContent.aspx?id=", content.Id));
                            }
                        }
                        else
                        {
                            // Item is created under 'Content' root, which is unsupported
                            ShowErrorToUser("Unsupported", "Creating a date folder item under 'Content' root is unsupported");
                        }
                    }
                    else
                    {
                        // Date folder doctype is null
                        ShowErrorToUser("Configuration error", string.Format("The date folder document type ('{0}') does not exist", dateFolderDocType[index]));
                    }

                }
            }

            void Document_BeforeMoveToTrash(IContentService sender, MoveEventArgs<IContent> moveEventArgs)
            {
                if (!itemDocType.Contains(moveEventArgs.Entity.ContentType.Alias)) return;
                try
                {
                    var parent = moveEventArgs.Entity.Parent();
                    if (parent == null || !parent.ContentType.Alias.Equals(dateFolderDocType)) return;
                    if (createDayFolders)
                    {
                        HttpContext.Current.Items.Add("dayId", parent.Id);
                        HttpContext.Current.Items.Add("monthId", parent.ParentId);
                        HttpContext.Current.Items.Add("yearId", parent.Parent().ParentId);
                    }
                    else
                    {
                        HttpContext.Current.Items.Add("monthId", parent.Id);
                        HttpContext.Current.Items.Add("yearId", parent.ParentId);
                    }
                }
                catch (Exception ex)
                {
                    LogError(ex, "DateFolders Document_BeforeMoveToTrash exception", false);
                }
            }

            void Document_AfterMoveToTrash(IContentService sender, MoveEventArgs<IContent> moveEventArgs)
            {
                if (!itemDocType.Contains(moveEventArgs.Entity.ContentType.Alias)) return;
                if (!HttpContext.Current.Items.Contains("yearId")) return;
                try
                {
                    var dayId = -100;
                    int monthId;
                    int yearId;

                    if (createDayFolders)
                    {
                        dayId = int.Parse(HttpContext.Current.Items["dayId"].ToString());
                        HttpContext.Current.Items.Remove("dayId");
                        monthId = int.Parse(HttpContext.Current.Items["monthId"].ToString());
                        yearId = int.Parse(HttpContext.Current.Items["yearId"].ToString());
                    }
                    else
                    {
                        monthId = int.Parse(HttpContext.Current.Items["monthId"].ToString());
                        yearId = int.Parse(HttpContext.Current.Items["yearId"].ToString());
                    }

                    HttpContext.Current.Items.Remove("monthId");
                    HttpContext.Current.Items.Remove("yearId");

                    if (createDayFolders)
                    {
                        var day = sender.GetById(dayId);
                        if (!day.Children().Any())
                        {
                            sender.Delete(day);
                        }
                    }

                    var month = sender.GetById(monthId);
                    if (!month.Children().Any())
                    {
                        sender.Delete(month);
                    }

                    var year = sender.GetById(yearId);
                    if (!year.Children().Any())
                    {
                        sender.Delete(year);
                    }
                }
                catch (Exception ex)
                {
                    LogError(ex, "DateFolders Document_AfterMoveToTrash exception", false);
                }
            }

            /// <summary>
            /// Order the children by propertyAlias, appends any node without alias.
            /// </summary>
            /// <param name="parent">The parent document</param>
            /// <param name="propertyAlias">The property alias</param>
            /// <param name="orderByDesc">order by descending or not</param>
            static void OrderChildrenByDateProperty(IContent parent, string propertyAlias, bool orderByDesc)
            {
                lock (Syncer)
                {
                    try
                    {
                        var orderedChildren = (orderByDesc ? parent.Children().Where(c => c.HasProperty(propertyAlias)).OrderByDescending(c => GetItemDate(c, propertyAlias))
                            : parent.Children().Where(c => c.HasProperty(propertyAlias)).OrderBy(c => GetItemDate(c, propertyAlias))).ToList();
                        orderedChildren.AddRange(parent.Children().Where(c => !c.HasProperty(propertyAlias)));
                        DoOrder(orderedChildren);
                    }
                    catch (Exception ex)
                    {
                        LogError(ex, "DateFolders OrderChildrenByDateProperty exception", true);
                    }
                }
            }

            /// <summary>
            /// Order the children by createDate
            /// </summary>
            /// <param name="parent">The parent cotent</param>
            /// <param name="orderByDesc">order by descending or not</param>
            static void OrderChildrenByCreateDate(IContent parent, bool orderByDesc)
            {
                lock (Syncer)
                {
                    try
                    {
                        DoOrder(orderByDesc ? parent.Children().OrderByDescending(x => x.CreateDate) : parent.Children().OrderBy(x => x.CreateDate));
                    }
                    catch (Exception ex)
                    {
                        LogError(ex, "DateFolders OrderChildrenByCreateDate exception", true);
                    }
                }
            }

            /// <summary>
            /// Order the children by name, converts Name to int any non int Names are pushed to the bottom of the ordering.
            /// </summary>
            /// <param name="parent">The parent content</param>
            /// <param name="orderByDesc">order by descending or not</param>
            static void OrderChildrenByName(IContent parent, bool orderByDesc)
            {
                lock (Syncer)
                {
                    try
                    {
                        int i;
                        var orderedChildren = (orderByDesc ? parent.Children().Where(c => int.TryParse(c.Name, out i)).OrderByDescending(x => int.Parse(x.Name))
                                                   : parent.Children().Where(c => int.TryParse(c.Name, out i)).OrderBy(x => int.Parse(x.Name))).ToList();

                        orderedChildren.AddRange(parent.Children().Where(c => !int.TryParse(c.Name, out i)));
                        DoOrder(orderedChildren);
                    }
                    catch (Exception ex)
                    {
                        LogError(ex, "DateFolders OrderChildrenByName exception", true);
                    }
                }
            }

            /// <summary>
            /// Order documents
            /// </summary>
            /// <param name="contents">content to order</param>
            static void DoOrder(IEnumerable<IContent> contents)
            {
                var sortOrder = 0;
                foreach (var objChild in contents)
                {
                    objChild.SortOrder = sortOrder;
                    sortOrder++;
                }
            }

            /// <summary>
            /// Returns itemDataProperty or Creation Date of passed content.
            /// </summary>
            /// <param name="content"></param>
            /// <param name="propertyAlias"></param>
            /// <returns></returns>
            private static DateTime GetItemDate(IContentBase content, string propertyAlias)
            {
                if (string.IsNullOrEmpty(propertyAlias)) return content.CreateDate;
                var dateValue = content.GetValue(propertyAlias) as DateTime?;
                return dateValue.HasValue ? dateValue.Value : content.CreateDate;
            }

            /// <summary>
            /// Logs passed error to umbraco Log.
            /// </summary>
            /// <param name="ex"></param>
            /// <param name="header"></param>
            /// <param name="pushToFrontEnd">If true calls ShowErrorToUser</param>
            static void LogError(Exception ex, string header, bool pushToFrontEnd)
            {
                if (pushToFrontEnd)
                {
                    ShowErrorToUser(header, ex.Message);
                }
                LogHelper.Error(typeof(DateFolders), header, ex);
            }

            /// <summary>
            /// Passes error to Umbraco's client error display
            /// </summary>
            /// <param name="header"></param>
            /// <param name="message"></param>
            static void ShowErrorToUser(string header, string message)
            {
                var clientTools = GetClientTools();
                if (clientTools == null) return;
                clientTools.ShowSpeechBubble(SpeechBubbleIcon.Error, header, message);
            }

            /// <summary>
            /// If HttpContext is not null return CurrentHandler as Page. Else null.
            /// </summary>
            /// <returns></returns>
            static ClientTools GetClientTools()
            {
                Page page = null;
                if (HttpContext.Current != null) page = HttpContext.Current.CurrentHandler as Page;
                return page != null ? new ClientTools(page) : null;
            }

            public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
            {
            }

            public void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
            {
            }
        }
    }

    Enjoy!,

    Rob

Please Sign in or register to post replies

Write your reply to:

Draft