Content editor And Core Editor open at the same time

6. juli 2010 by Thomas Stern

For thoose of you that where attending the dreamcore in Copenhagen, know about this nice little easy piece of code, Actually it is One line of code that can help you a lot in sitecore backend. I have for while been doing a lot of work in the core content editor and offen had to switch back and forth between the Core content editor and Master database content editor. So after seen Raul Jimenz Presentation af Dreamcore aI thought wow cool I what the same functionality just with a minor twist, I would like my shortcut to be placed in Tray of the Desktop of the sitecore backend. I know this is easy to do, but sometimes easy to do things get overlooked I now I did for this. Okay here we go, lets start with adding the an icon with an click action in the tray let's start by going to the core editor go to:


/sitecore/content/Applications/Desktop/Tray/CoreContentEditor

and insert an item as shown

coredb1

 

 

tray3
Okay now open the command.config file for you sitecore solution and add the with reference to to command you wrote in core editor of sitecore. Remenber that syntax is FullClassName,NameSpace.

<command name="Tray:CoreContentEditor" type="CoreContentEditor.TrayCommandCoreContentEditor,CoreContentEditor" />


Now tho the code it is simple one line of code.

namespace PT.CoreContentEditor
{
  public class TrayCommandCoreContentEditor : Command
  {
  
    public override void Execute(CommandContext context)
    {
      Sitecore.Shell.Framework.Windows.RunApplication("Content Editor", "sc_content=core");
    }
  }
 
}


And now let's see it in action


openatthesametime


Again I know it is easy to do, but i think it is so nice to could switch back and forth without having to open the content editor everytime. Note you could also make a shortcut for the webdatabase. Changing sc_content=core to sc_content=web.

Usersessions in sitecore (logout users from backend)

7. juni 2010 by Thomas Stern

 

The number of usersession that is possible to have open in sitecore depend onj the licens, which is fair enough. But the task for an administrator to end hanging usersession seems somewhat headless. The administrator have to logout, to get a list of active user sessions, and then choose to end hanging or not used sessions. This might be fine in minor solutions but I think this might pose a problem in solutions where a user with the "Is Adminstrator" flag is set to true can be hard to find. He might be working in different office or just generally be hard to get a hold of. It doesn't require you have the "Is administrator" flag to end session but it is required to get the list of active sessions. You don't even have to be logged in to sitecore to end active session, if presented with the option to end active session anonymous users could do so. My idea is to help local administrators with functionality to end session with out leaving the backend, or having to log out or anything like that. Since sitecore is one big tool box I will build it as shortcut in the tray of sitecore.
Okay so we start, all our work is done in the core database and it only contains minimal coding. We start with making the tray icon. In the core database we go to content/applications/Desktop/tray and add a item I will call it UserSessions the Data section of the item find the click attribute and add the command name, this will also have to go in the command file we get back to that. I also and icon for the tray I have choosen the standard user icon.


userhelper1


Now with the tray icon shortcut in place you should be able to see it in th start bar just save the item and hit F5

 

userhelper2

Now we will add the command to the App_Config/Commands.config add the following line

<command name="Tray:UserSessionViewer" type="UserHelper.UserhelperTrayCommand,UserHelper" />


I will add this little user feature helper as an application so we need to add an application and layout for the application in the core database. We start with adding the layout "core database" go to sitecore/layout/applications and add a new layout in the data section in path write the physical path to layout you will create in the next step.

 

suerhelper3


Next we will add the application again this is done in the core database go to sitecore/content/Applications/ and add a new application pull on the the layout we just created make sure you can see it in the layout section for the item. Also note the Id for your application, we will have to use it in the code part.


userhelper4


Okay now we are done with the configuration in sitecore now to code part.
First we will start we the Tray click command which is pretty simple note that is hardcode the id for our application and the database I getting the item from.

 

Now we have something that handle the click on the Tray command no we will code the popup or application window. First the frontend code for the application. The frontend code shows when the user session started and when the last request was made info need to take into account which user sessions you should end

<div class="taskInfoWindow">
  <div class="SystemTime>
  <span class="Literal">System Time</span>
  <span class="Time"><%# SystemTime %></span>
  </div>
    <div class="tasks">
      <asp:Repeater ID="taskRepeater" runat="server" DataSource="<%# ScheduleItems %>"
        OnItemCommand="taskRepeater_ItemCommand">
        <HeaderTemplate>
          <table>
            <thead>
              <tr class="informationHeader">
                <td class="Icon">
                  *
                </td>
                <td class="Literal">
                  Task name
                </td>
                <td class="Literal">
                  Is Due
                </td>
                <td class="Time">
                  Last run
                </td>
                <td class="Time">
                  Next run
                </td>
                <td class="Button">
                  Execute Task
                </td>
              </tr>
            </thead>
            <tbody>
        </HeaderTemplate>
        <ItemTemplate>
          <tr class="scheduledItem <%# Container.ItemIndex == 0 || Container.ItemIndex % 2 == 0 ? "even" : "odd"   %>">
            <td class="Icon">
              <img src="/sitecore/shell/Themes/Standard/<%#((ScheduleItem)Container.DataItem).Icon%>"
                alt="<%# ((ScheduleItem)Container.DataItem).DisplayName %>" />
            </td>
            <td class="Literal">
              <%# ((ScheduleItem)Container.DataItem).DisplayName%>
            </td>
            <td class="Literal">
              <%# ((ScheduleItem)Container.DataItem).IsDue%>
            </td>
            <td class="Time">
              <%# ((ScheduleItem)Container.DataItem).LastRun.ToString("HH:mm dd/MM-yyyy")%>
            </td>
            <td class="Time">
              <%# ((ScheduleItem)Container.DataItem).NextRun.ToString("HH:mm dd/MM-yyyy")%>
            </td>
            <td class="Button">
              <asp:LinkButton ID="LinkButton1" Text="Execute" CssClass="SortButton" runat="server"
                CommandName="Execute" CommandArgument="<%# ((ScheduleItem)Container.DataItem).ID %>" />
            </td>
          </tr>
          </tbody>
        </ItemTemplate>
        <FooterTemplate>
          </tbody> </table>
        </FooterTemplate>
      </asp:Repeater>
    </div>
  </div>

Now to the code behind, I am only using standard sitecore functionality nothing fancy here other then the click event for the repeater that end the selected user session.

using Sitecore.Data;
using Sitecore.Security.Accounts;
using Sitecore.Web.Authentication;

namespace Userhelper.Presentation
{
  public partial class UserSessionsView : System.Web.UI.Page
  {
    protected void Page_Load(object sender, EventArgs e)
    {
      DataBind();
    }

    public IEnumerable UserSessions
    {
      get
      {
        return DomainAccessGuard.Sessions;
      }
    }


    protected void userRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
    {
      string id = e.CommandArgument.ToString();
      switch (e.CommandName)
      {
        case "Execute":
          EndSession(id);
          break;
      }
    }

    private void EndSession(string sessionID)
    {
      DomainAccessGuard.Kick(sessionID);
    }

  }
}


This is how I looks when we done

userhelperlast

The styling part is left for you. With this little userhelper you can set security on the tray icon so local administrator can see the tray icon and all other users have denied read access so only users with elevate security settings can end user sessions.

 

System Alert in sitecore

27. april 2010 by Thomas Stern

When working with large Sitecore implementation and customers that have a lot of editors maintaining the content of their website, often makes updating the system becomes a hurdle. Because editors may or may not work in on the same floor or even the same building, so even if you have an contact person who's responsibility is to notify editor about the downtime, it is possible that one or more editors haven't heart about the downtime and haven't save the what they where doing the second the system is taken offline, a valuable work may have been lost.
So I thought what would be more smart the implementing a System alert/ notifier system that alert the users about the forthcoming downtime. This Alert could as in this example be a simple javascript alert.
My solution is build around simple Javascript calling a webservice which looks for alert placed inside sitecore and display them as a simple javascript alert. Yes some may argue that I have some hardcoded path string and what have we not, but it is left to you to move these to fx. The web.config. Even more this solution I maybe a little over the edge when looking at the implementation, but I se so many usages for this so I went ALL-IN as implemented with interface and using a provider model. The solution is build and tested against a Sitecore 6.2, but nothing wrong with using on other Sitecore versions.
But here goes first the javascript since Sitecore editors have three different editors Page Edit, Content Editor and the Desktop. So we need to include the javascript in three different files, and because of the we need to ensure that the file is only loaded once so logged into the Desktop and opening the content editor doesn't give two warnings, hence the cookie check. Now to javascript, it's all simple stuff.
The javascript should be include in these three files
Webedit:
sitecore\shell\Applications\WebEdit\WebEditRibbon.aspx
Content Editor:
sitecore\shell\Applications\Content Manager\Default.aspx
Desktop:
sitecore\shell\Applications\Startbar\Startbar.xml

/* Function for calling the webservice                             */
function callWebservice() {
  var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  xmlhttp.open("GET", "/Components/SystemNotifier/AjaxWebservice/SystemNotifier.asmx/GetAlerts", false);
  xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  xmlhttp.send();

  if (xmlhttp.status == 200) {
    var str = xmlhttp.responseXml.getElementsByTagName("string").item(0).text;
    return str;
  }
}

/* function that Get system alerts */
/* update timer by calling the webservice    */
function GetSystemAlerts() {
  var alertString = callWebservice();
  if (alertString != "") {
     alert(alertString);
     //increase time to next call so we dont get same alert twice
     setTimeout("GetSystemAlerts()", 125000);
  }
  else {
    setTimeout("GetSystemAlerts()", 60000);
  } 
}

var cookieName = "SitecoreSystemNotifier";

function writeCookie() {
 document.cookie = cookieName;
}

function cookieExists()
{

 if (document.cookie.length >0 )
 {
   var offset = document.cookie.indexOf(cookieName);
   if (offset != -1)
     return true;
   return false;
 }
 return false;
}


function init(){
 if(!cookieExists()){
  writeCookie();
  //SetTimeout in ms
  setTimeout("GetSystemAlerts()", 60000);
 }
}

init();

 

Okay now that we have the javascript we need the webservice to be called. It's fairly simple when using the Provider.

 

namespace SystemNotifier.AjaxWebservice
{
  /// 
  /// Summary description for SystemNotifier
  /// 
  [WebService(Namespace = "http://pentia.dk/")]
  [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
  [System.ComponentModel.ToolboxItem(false)]
  // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
  [System.Web.Script.Services.ScriptService]
  public class SystemNotifier : WebService
  {

    [WebMethod]
    public string GetAlerts()
    {
      ISystemAlert alert = AlertProvider.NextAlert;
      if (alert != null)
        return alert.Text;
      return "";
    }

    private SystemAlertProvider _provider;
    private SystemAlertProvider AlertProvider
    {
      get
      {
        if (_provider == null)
          _provider = new SystemAlertProvider();
        return _provider;
      }
    }
    
  }
}

And now to the provider implementation

 public class SystemAlertProvider
  {
    private IEnumerable _alerts;
    public IEnumerable Alerts
    {
      get {
      if(_alerts == null)
       _alerts = GetAlertsFromSitecore();
       return _alerts;
      }
    }

    private TimeSpan timespan = new TimeSpan(0, 1, 0);
    private IEnumerable GetAlertsFromSitecore()
    {
      ChildList childList = AlertRootItem.Children;
      foreach(Item child in childList)
      {
        ISystemAlert alertItem = new SystemAlert(child);
        if(alertItem.AlertTime > DateTime.Now.Subtract(timespan))
          yield return alertItem;
      }
    }

    private const string sitecoreRootPath = "/sitecore/system/SystemAlertNotifier";
    private Item _rootItem;
    private Item AlertRootItem
    {
      get
      {
        if(_rootItem == null)
         _rootItem = Database.GetItem(sitecoreRootPath);
        return _rootItem;
      }
    }

    private const string _databaseName = "master";
    private Database Database
    {
      get
      {
        return Database.GetDatabase(_databaseName);
      }
    }
    public ISystemAlert NextAlert
    {
      get
      {
        if(Alerts.Count() > 0)
          return Alerts.OrderBy(w => w.AlertTime).First();
        return null;
      }
    }
  }

And finally the Alert interface and implementation of the same.

Inteface

public interface ISystemAlert
  {
    DateTime AlertTime { get; }
    String Text { get; }
  }

Implementaion

public class SystemAlert : ISystemAlert
  {
    public SystemAlert(Item item)
    {
      Item = item;
    }

    private Item Item
    {
      get;
      set;
    }

    private const string _alertTimeField = "SystemAlert_AlertTime";
    public DateTime AlertTime
    {
      get
      {

        DateField dateField = Item.Fields[_alertTimeField];
        return dateField.DateTime;
      }
    }

    private const string _textField = "SystemAlert_Text";
    public string Text
    {
      get { return Item[_textField]; }
    }
  }

Now we got all the code working so now we need to have someway to get the info, let's use a sitecore item. So here is a snapshot of the how my sitecore item looks.

sys2

So this is pretty much everything you need to have a system alert system up and running inside sitecore. Remember to edit hardcode root path to system alert root folder.
You can download the project in the download section link here.

And hope you can see the posiblities in this solution or implementaion, you could scheduled downtown and have email alert, downtime calendar and much much more hope you enjoy,