View from inside the viper

Exposing Trac Feeds in DotNetNuke

  August 20, 2010 10:40
by Mark

On our site we list a road map of features for Cart Viper, this comes straight out of Trac in this post I’m going to explain how we do this.


On the Trac server we’ve created a custom query for each version Cart Viper we want to publish the road map for.


The query in affect limits the tickets to a given version of Cart Viper.


Once you’ve created the feeds you can then access the tickets via the RSS feed for each query.
So over in DotNetNuke simple add the News Feed Module to the page and configure it with the URL for the Trac feed and the correct credentials.

Then using our custom XSLT file and a bit of jQuery we get the finished result.

   1: <?xml version="1.0"?>
   2: <xsl:stylesheet version="1.0" xmlns:xsl="">
   3:  <xsl:output method="html" indent="yes"/>
   4:  <xsl:param name="ItemsToShow"/>
   5:  <xsl:param name="ShowItemDetails"/>
   6:  <xsl:param name="ShowItemDate"/>
   7:  <xsl:param name="Locale"/>
   8:  <xsl:template match="rss">
   9:   <xsl:for-each select="channel/item[position()&lt;=$ItemsToShow or $ItemsToShow&lt;1]">
  10:    <div class="cvRoadMapItem Normal">
  11:          <p class="cvRoadMapTitle">
  12:             <a href="#" class="cvRoadMapLink">
  13:              <xsl:value-of select="title"/>
  14:             </a>
  15:          </p>
  16:          <xsl:if test="$ShowItemDate='true'">
  17:             <div class="cvRoadMainDate">
  18:              <xsl:value-of select="pubDate"/>
  19:             </div>
  20:          </xsl:if>
  21:          <xsl:if test="$ShowItemDetails='true'">
  22:             <div class="cvRoadMainDesc" style="display:none;">
  23:              <xsl:value-of select="description" disable-output-escaping="yes"/>
  24:             </div>
  25:    </xsl:if>
  26:    </div>
  27:   </xsl:for-each>
  28:  </xsl:template>
  29: </xsl:stylesheet>


   1: jQuery(document).ready(function(){
   3:     jQuery(".cvRoadMapLink").toggle(function(){
   4:         jQuery(this).parents().siblings(".cvRoadMainDesc").show('fast');
   5:     }, 
   6:     function(){
   7:         jQuery(this).parents().siblings(".cvRoadMainDesc").hide('fast');
   8:     });
  10: });

Getting PortalSettings Instance outside HttpContext in DotNetNuke

  August 13, 2010 15:59
by Nigel

One of the ideas we had for this blog was to post the lessons we had learnt during the development of Cart Viper. Although we feel as a CMS DotNetNuke is really good, as a platform to develop on the documentation is somewhat lacking. So the aim of this and future posts is to try and save you some time and hours of pulling your hair out if you are developing modules for the DotNetNuke platform by recounting the issues with the framework we have encountered.

In Cart Viper we have made extensive use of jQuery Ajax calls to provide a rich user experience. In order to achieve this we call a HttpHandler which in turn delegated the request to the appropriate class that would then process the request and return the correctly formatted JSON result. It was whilst in this class we ran into an issue.

Whilst in the HttpContext whenever you required the current PortalSettings object you could simple call:

   1: PortalSettings portalSettings = Globals.GetPortalSettings();

However as we were not in the HttpContext, PortalSettings was always null. This left us with the problem of how to instantiate the PortalSettings object.

One solution would be to pass in the PortalID as a parameter into the jQuery Ajax request, however a user could easily see the JSON request using firebug and then attempt to pass in a different PortalID into your HttpHandler, which in turn could then lead to cross portal updates. We did not like the security risks in this method so we thought how could we securely pass the current PortalID to the required class?

The solution we devised involved creating a base class that all .ascx controls we use within Cart Viper would implement:

   1: public class StoreControlBase : PortalModuleBase
   2: {
   3:     public StoreControlBase()
   4:     {
   5:     }
   6: }

In this base class we inserted the following method:

   1: /// <summary>
   2: /// Writes the portalId to an encrypted cookie
   3: /// </summary>
   4: /// <remarks>this is the used by ajax to determine the correct portalId</remarks>
   5: protected void WritePortalIdCookie()
   6: {
   7:     HttpCookie cookie = HttpContext.Current.Request.Cookies["YOUR PORTAL COOKIE"];
   8:     if (cookie == null)
   9:     {
  10:         cookie = new HttpCookie("YOUR PORTAL COOKIE");
  11:     }
  13:     string cookieValue;
  15:     if (SymmetricHelper.CanSafelyEncrypt)
  16:         cookieValue = SymmetricHelper.Encrypt(this.PortalId.ToString());
  17:     else
  18:         cookieValue = PortalId.ToString();
  20:     cookie["PortalId"] = cookieValue;
  22:     HttpContext.Current.Response.Cookies.Add(cookie);
  23: }

Then in each of the .ascx controls that make a jQuery AJAX request we simple add the following line to the page load event:

   1: protected void Page_Load(object sender, System.EventArgs e)
   2: {
   3:    //write out the portal cookie so we have it for the ajax
   4:    base.WritePortalIdCookie();
   6:    //page load as normal
   7: }

Then in the class it is just a case of getting the PortalID that is stored securely in the cookie and populating the associated PortalSettings object:

   1: /// <summary>
   2: /// Readonly access to the PortalSettings object for the
   3: /// current portal context
   4: /// </summary>
   5: protected PortalSettings PortalSettings
   6: {
   7:     get
   8:     {
   9:         HttpCookie cartCookie = HttpContext.Current.Request.Cookies["YOUR COOKIE NAME"];
  10:         if (cartCookie != null)
  11:         {
  12:             string pid = cartCookie["PortalId"];
  13:             if (SymmetricHelper.CanSafelyEncrypt &&
  14:                 !string.IsNullOrEmpty(pid))
  15:             {
  16:                 try
  17:                 {
  18:                     pid = SymmetricHelper.Decrypt(pid);
  19:                     return new PortalSettings(Int32.Parse(pid));
  20:                 }
  21:                 catch (Exception ex)
  22:                 {
  23:                     //the portal cookie is correct, rethrow
  24:                     throw ex;
  25:                 }
  26:             }
  27:         }
  29:         throw new ApplicationException("Portal cookie is not valid");
  30:     }
  31: }

This property should then return a fully populated PortalSettings object.which you can then query to get specific information relating to the Portal the request has originated from.

The Start of the Viper

  August 6, 2010 20:54
by Mark

After what seems like weeks and weeks of coding we appear to be closing in on our first release of Cart Viper.

What is Cart Viper?

Cart Viper is an advanced ecommerce module for DotNetNuke. Its allows you create a shop and start selling goods and digital downloads in minutes.
We’ve focused on making Cart Viper simple to start using but powerful for advanced users. We’ll be discussing more about the features in the future.

Why Cart Viper?

We are two developers from the UK that have already had success with creating DNN modules but where disappointed with the current ecommerce modules out there. So we decided to do something about it, hence the blog you’re reading now.

Stay tuned.