Using IronPython in Umbraco – pyForum part 2

Continuing with our pyForum. In this post we will create a possibility for our users to add threads with a standard Html form.

More Html templates for our form

First we add four more Html template strings,

  • a link that the user clicks to show the form,
  • the actual form,
  • a thank you messsage to show after the form has been submitted and
  • a error message to show if the form data is not valid.

For now we target all users, with or without Javascript enabled browsers. For that reason we use a simple querystring ?new=1 to activate our form. Later on we will spice up our forum with Javascript and Ajax.

forumShowNewThreadFormTemplate ="<p><a href='?new=1'>Add a new thread</a></p>

forumNewThreadFormTemplate ="""
<h2>Add a new thread</h2>
<form action="#" method="post" id="forumpost">
<label for="forumpost-subject">Subject</label><br/>
<input type="text" id="forumpost-subject" name="forumpost-subject"/><br/>
<label for="forumpost-text">Text</label><br/>
<textarea cols=80 rows=4 id="forumpost-text" name="forumpost-text"></textarea><br/>
<label for="forumpost-user">User (name)</label><br/>
<input type="text" id="forumpost-user" name="forumpost-user"/><br/>
<input type="submit" id="forumpost-submit" name="forumpost-submit" value="Submit"/>
</forum>
"""
forumNewThreadPostMessageTemplate = "<p>Thank you for creating a new thread!</p>"
forumNewThreadPostErrorMessageTemplate = "<p>Not valid!</p>"

These new Html strings should also have a place in our original full view, so we add a place holder for them in our forumStartTemplate:

forumStartTemplate = """
 <div  class="forumstart">
 <h1>{forumname}</h1>
 </div>
 <ul>
 {forumThreads}
 </ul>
 {forumNewThreadForm}

 """

Handle user interaction

We have three states of our page. First the regular GET request shall show the page with the Add new thread link. Second, we show our form when the user clicks that link, and the request querystring becomes new=1. And third, we handle the form post and show a confirmation after the user submits the form data.

Current HttpContext

To get the RequestType and some other Context information we need the current httpcontext object, since System.Web is not referenced to from start we need to reference it and then import the System.Web.HttpContext:

import clr
clr.AddReference('System.Web')
from System.Web.HttpContext import Current
requestType = Current.Request.RequestType

Here’s what our handling code looks like, if the requestType is GET we just return the appropriate template string, on POST however we call a function that will handle the form data:

def HandleForumForm():
    if requestType=="GET":
        requestNew = library.RequestQueryString("new")
        if requestNew:
            return forumNewThreadFormTemplate
        else:
            return forumShowNewThreadFormTemplate
    if requestType=="POST":
        return HandleFormPost(currentPage.Id)

The HandleFormPost function contains the following code:

def HandleFormPost(id):
    retval = ""
    requestForm = Current.Request.Form
    subject = requestForm["forumpost-subject"]
    text = requestForm["forumpost-text"]
    user = requestForm["forumpost-user"]
    properties = {}
    properties["richtext"]=text
    properties["user"]=user
    # a very simple form validation:
    isValid = True
    if not subject: isValid=False
    if not user: isValid=False
    if not text: isValid=False
    if isValid:
        create = DocumentCreate("pyForumThread",id,subject,properties)
        retval = forumNewThreadPostMessageTemplate
    else:
        retval = forumNewThreadPostErrorMessageTemplate
    return retval

Note the standard calls to get data from Request Form fields. After those we construct a dictionary (much like a hashtable) which we will send to a DocumentCreate function. The DocumentCreate function uses Umbraco Api functions to create a new document using the parameters, nodetypealias, parent node id, name of the document and a list of property values. The Umbraco Api is well documented in other places.

Here are DocumentCreate:

def DocumentCreate(nodeTypeAlias, pageId, name, properties):
    dt = DocumentType.GetByAlias(nodeTypeAlias)
    author = User(0)
    documentId = int(pageId)
    documentName = name
    doc = Document.MakeNew(documentName, dt, author, documentId)
    #
    # Loop through document properties matching items in the properties dictionary.
    #
    if properties:
        for prop in doc.getProperties:
            alias = prop.PropertyType.Alias
            if alias in properties:
                doc.getProperty(alias).Value = properties[alias]
    doc.Publish(author)
    library.UpdateDocumentCache(doc.Id)
    return doc.Id

The “if properties” statement evaluates to True if properties != null, we could use the more explicit “if not properties is None”. See also http://boodebr.org/main/python/tourist/none-empty-nothing

The pyForumHelpers module

DocumentCreate is a function that we will use from other Python macro scripts aswell. For that reason we create another file for it, pyForumHelpers.py, and we import all functions from it into our scripts with the statement:

from pyForumHelpers import *

A workaround for current version of Umbraco (4.5.2)

Well – we should be able to do import that if we had the /Python folder in our Python engine list of paths. That’s an issue in the current Umbraco version, we need to write some lines to add that path first:

import clr
clr.AddReference('System.Web')
from System.Web.HttpContext import Current
#  Add python path
import sys
sys.path.append(Current.Server.MapPath('~/python'))
# now we are able to import our module:
from pyForumHelpers import *

We’ll include another helper function in FormHelpers as well – one that gives us a property value from a Node, or a empty string if the property does not exist. Also we need a list of imports to be able to use the code in DocumentCreate. So the complete ForumHelpers.py will look like this:

#
# Imports
#
import clr
clr.AddReference('cms')
clr.AddReference('umbraco')
clr.AddReference('businesslogic')
from umbraco import library
from umbraco.BusinessLogic import User
from umbraco.cms import businesslogic
from umbraco.cms.businesslogic.web  import DocumentType
from umbraco.cms.businesslogic.web import Document
clr.AddReference('System.Web')
from System.Web.HttpContext import Current

def NodePropertyValue(node, propertyname):
    prop = node.GetProperty(propertyname)
    if prop : return prop.Value
    else : return ""
def DocumentCreate(nodeTypeAlias, pageId, name, properties):
    dt = DocumentType.GetByAlias(nodeTypeAlias)
    author = User(0)
    documentId = int(pageId)
    documentName = name
    doc = Document.MakeNew(documentName, dt, author, documentId)
    #
    # Loop through document properties matching items in the properties dictionary.
    #
    if properties:
        for prop in doc.getProperties:
            alias = prop.PropertyType.Alias
            if alias in properties:
                doc.getProperty(alias).Value = properties[alias]
    doc.Publish(author)
    library.UpdateDocumentCache(doc.Id)
    return doc.Id

End of current session

Now we have almost all code we need to lists our threads and give the users a possibility to add new ones. In the next part I will finish up stuff, including listing and handling the threads with comments(posts). It will also include a full package with the (very) basic but working forum. Part 3.

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s