<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Nicole Drath</title><link href="http://world.optimizely.com" /><updated>2024-09-25T14:34:05.0000000Z</updated><id>https://world.optimizely.com/blogs/nicole-drath/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>How to write a bespoke notification management system</title><link href="https://world.optimizely.com/blogs/nicole-drath/dates/2024/9/how-to-write-a-bespoke-notification-management-system/" /><id>&lt;p&gt;Websites can be the perfect vehicle for notifying customers of important information quickly, whether it&amp;rsquo;s the latest offer, an operational message, or an informative alert.&lt;/p&gt;
&lt;p&gt;Customers are used to seeing these messages at the top of web pages and companies find it an invaluable way to communicate with website visitors.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/6981845f0df04148a7d3a95622af5d47.aspx&quot; width=&quot;1104&quot; alt=&quot;Header&quot; height=&quot;323&quot; /&gt;&lt;/p&gt;
&lt;p&gt;At Animal Friends Insurance, the company I work for, we already had rudimentary notification capability on our site. We wanted to take it a step further by classifying these messages red, amber or green and managing them in the CMS by building a bespoke notification management page. &amp;nbsp;Here editors could manage the editing and expiring of notifications, and additionally see their publication status.&lt;/p&gt;
&lt;p&gt;When deciding how to tackle this requirement, I made the decision early on that the most efficient way would be to create a notification block that used the inbuilt scheduling, publishing, and expiring of blocks and pages already provided by the CMS.&lt;/p&gt;
&lt;p&gt;These blocks can be viewed, in their correct state, on the management page to give editors a simple overview.&lt;/p&gt;
&lt;p&gt;First, I created a notification block, with all the attributes needed. &amp;nbsp;Simple enough!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/7429dd7b7d5545eba2ed658bc84913ca.aspx&quot; width=&quot;556&quot; alt=&quot;Notification Block&quot; height=&quot;809&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Next, I created a custom page that would be accessible from the Settings tab in the CMS backend. &amp;nbsp;This page was divided into the following sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Published&lt;/li&gt;
&lt;li&gt;Not Published Yet&lt;/li&gt;
&lt;li&gt;Scheduled&lt;/li&gt;
&lt;li&gt;Expired&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/link/9a6ba25e70e74b0a872e89c77c812626.aspx&quot; width=&quot;1104&quot; alt=&quot;Notification Management Page&quot; height=&quot;570&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I made use of Optimizely&amp;rsquo;s publishing flow to display the notifications in the correct place on the page.&lt;/p&gt;
&lt;h2&gt;Published&lt;/h2&gt;
&lt;p&gt;Once my test notification was created and published, I used IVersionable to get the published date, which also helped to decide where this notification should sit within the sections on the notification management page.&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public DateTime? GetStartPublishDateTime(ContentReference content)
{
	var notificationBlock = _contentRepository.Get&amp;lt;NotificationBlock&amp;gt;(content);
	var startPublishDate = (notificationBlock as IVersionable).StartPublish;
	return startPublishDate;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/link/991de5607b1543e5a93c6f38ede846fe.aspx&quot; width=&quot;1104&quot; alt=&quot;Notification Management Page&quot; height=&quot;496&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As it appears at the top of the website.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/06a59f8f73784f42b7382a9f17a12a78.aspx&quot; width=&quot;1104&quot; alt=&quot;&quot; height=&quot;64&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Not Published Yet&lt;/h2&gt;
&lt;p&gt;Whilst there is no specific attribute to be able to determine if content is scheduled to be published, it can be deduced by what it is not. &amp;nbsp;My logic went something like this&amp;hellip;&lt;/p&gt;
&lt;p&gt;If the notification is not:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deleted&lt;/li&gt;
&lt;li&gt;Published&lt;/li&gt;
&lt;li&gt;Previously Published&lt;/li&gt;
&lt;li&gt;Scheduled to be published&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;then it must be unpublished.&lt;/p&gt;
&lt;p&gt;With the exception of the &amp;lsquo;deleted&amp;rsquo; state, I used the version status to find this information. So, for example, for &amp;lsquo;previously published&amp;rsquo; the code looked like this:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public static bool HasBeenPreviouslyPublished(ContentReference content)
{
    if (content != null)
    {
        var contentVersion = ContentVersionRep.Load(content);
        if (contentVersion != null)
        {
	        if (contentVersion.Status == VersionStatus.PreviouslyPublished)
	        {
		        return true;
	        }
        };
    }
    return false;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/link/102e192f561c4b658693b68c02e26c1d.aspx&quot; width=&quot;1104&quot; alt=&quot;Notification Management Page&quot; height=&quot;419&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Scheduled&lt;/h2&gt;
&lt;p&gt;To find out if a notification is scheduled to be published, I used the DelayPublishUntil attribute.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public static DateTime? GetDelayPublishUntil(ContentReference content)
{
    DateTime? delayPublishUntil = null;
    if (content != null)
    {
        var contentVersion = ContentVersionRep.Load(content);
        if (contentVersion != null)
        {
	        delayPublishUntil = contentVersion.DelayPublishUntil;
        }
    }
    return delayPublishUntil;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/link/7fdf303a11a54e61aac472886f51ad52.aspx&quot; width=&quot;1104&quot; alt=&quot;Notification Management Page&quot; height=&quot;547&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Expired/Removed&lt;/h2&gt;
&lt;p&gt;To expire a notification, I first had to create a clone of the notification and then used the IVersionable class stopPublish function to expire the clone.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s important to note, you cannot expire the original block from the content repository, you must create a clone and then save and publish the cloned version with the new expired state.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public void ExpireNotification(string contentRef)
{
	var notificationBlock = _contentRepository.Get&amp;lt;NotificationBlock&amp;gt;(ContentReference.Parse(contentRef));
	var notificationToExpire = notificationBlock.CreateWritableClone() as NotificationBlock;
	(notificationToExpire as IVersionable).StopPublish = DateTime.Now;
	_contentRepository.Save(notificationToExpire as IContent, SaveAction.Publish, AccessLevel.NoAccess);
} &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/link/a8509d88e443486885ef598e7395708e.aspx&quot; width=&quot;1104&quot; alt=&quot;Notification Management Page&quot; height=&quot;704&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The final task was to add the notification management page to the CMS menu structure. &amp;nbsp;This was done by extending the menu section using the [MenuProvider] decorator. Details of how to do this can be found here - &lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/docs/adding-and-configuring-menu-items&quot;&gt;Add and configure menu items (optimizely.com)&lt;/a&gt; and would look something like the code below.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public IEnumerable&amp;lt;MenuItem&amp;gt; GetMenuItems()
   {
      var notificationManagement = new UrlMenuItem(
           &quot;Notification Management&quot;,
           MenuPaths.Global + &quot;/cms/admin/notificationmanagementplugin&quot;,
           $&quot;/{ConfigurationConstants.BaseAdminUrl}/{ConfigurationConstants.CmsPath}/notificationmanagementplugin/index&quot;)
       {
           IsAvailable = _ =&amp;gt; true,
           SortIndex = 80,
          AuthorizationPolicy = CmsPolicyNames.CmsAdmin
      };
  
      return new List&amp;lt;MenuItem&amp;gt;(1)
      {
          notificationManagement
      };
  }&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;/h2&gt;
&lt;h2&gt;Any Gotchas?&lt;/h2&gt;
&lt;p&gt;Daylight savings! This work was completed before the clocks went forward in spring consequently, timestamps on the &amp;lsquo;published&amp;rsquo; and &amp;lsquo;expired&amp;rsquo; fields were showing the correct time. &amp;nbsp;One of our eagle-eyed CMS admins noticed, however, in the summer that the timestamps on new notifications were out by an hour because the servers that host the website use UTC.&lt;/p&gt;
&lt;p&gt;Of course, on my local version of the CMS the notification page showed the correct time because I run on Windows which uses &amp;lsquo;GMT Standard Time&amp;rsquo;, a Microsoft invention that works with daylight savings. &amp;nbsp;However, since upgrading the CMS to version 12, the DXP servers are running on Linux which have no awareness of &amp;lsquo;GMT Standard Time&amp;rsquo;. &amp;nbsp;So, to show the correct time, I added the following check:&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var timeZone = TimeZoneInfo.FindSystemTimeZoneById(&quot;Europe/London&quot;);

DateTime dt = dateTime.Value;

var isDaylightSaving = timeZone.IsDaylightSavingTime(dt);
if (isDaylightSaving)
{
    dateTime = dt.AddHours(1);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And there you have it, a fully working notification management system powered by the CMS. &amp;nbsp;&lt;/p&gt;</id><updated>2024-09-25T14:34:05.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>