We love designing and developing websites, but what really drives us is solving problems and cultivating strong relationships with our clients
Reactions
9th March, 2012, pingback from http://gluten-free-guide.net/848/your...
31st Jan., 2012, pingback from http://www.onesecretlife.com/archives...
25th Dec., 2011, pingback from http://greenegardner.allergiesaid.com...
Posts
- Test Driven Development in Python
- Deploying Django apps on Heroku
- Developing android applications from command line
- Deploy Django App in 5 Easy Steps
- Project Management Tools for Start-Ups
- Generating a pdf from an image using PIL and django
- Dynamically attaching SITE_ID to Django Caching
- Screencast: How to deploy Django on Heroku
- Deploying Django apps on Heroku
- How to use pep8.py to write better Django code
Topics
- rails
- django
- linkroundup
- django opinion
- opinion
- business
- API
- appengine
- python
- satire
- startup
- Uncategorized
- marketing
- personal
- rambling
- search
- interviews
- seo-interviews
- 5startupideas
- ideas
- seo
- tips
- forms
- paypal
- utilities
- datetime
- web2.0
- Amazon
- algorithms
- presentations
- products
- pinax
- satchmo
- ecommerce
- microsoft
- yahoo
- book
- tutorial
- models
- aggreagtion
- meta
- India
- apps
- about
- CSS
- Design
- wordpress
- test slug
- vim
- urls
- reviews
- javascript
- xmpp
- emacs
- Typography
- Grid Theory
- Color Theory
- iphone
- android
- titanium
- mobile applications
- CSS3
- Browser Compatibility
- mobile
- jobs
- lamson
- django setup
- files
- upload
- jsTree
- hierarchical view
- web page
- Treeview
- coffeescript
- request
- response
- South
- django south
- django migration
- --fake
- screencasts
- django caching
- SITE_ID prefix
- review
- code hosting
- comparison
- unfuddle
- fogbugz
- assembla
- github
- project management
- ticketing system
- gunicorn
- deploy
- nginx
- ubuntu
- vps
- android terminal
- terminal
- programming
- TDD
- Test Driven
- Development
Archives
- May 2012
- April 2012
- March 2012
- February 2012
- January 2012
- December 2011
- October 2011
- September 2011
- July 2011
- June 2011
- April 2011
- February 2011
- January 2011
- December 2010
- November 2010
- October 2010
- September 2010
- June 2010
- April 2010
- March 2010
- January 2010
- December 2009
- November 2009
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- April 2009
- March 2009
- February 2009
- November 2008
- October 2008
- June 2008
- May 2008
- April 2008
Writing an e-mail application with Lamson - II
By : thejaswi
In the last post, we saw how to create the skeleton of a basic email application using Lamson. In this part, we'll see how to write a handler (in the controller) to open a ticket in Unfuddle, the project management tool we use at Agiliq.
If you look at the config/settings.py file, you'll see a handlers attribute that should be updated to match the file that contains the rules for mail routing. In this case, let us create a unfuddle.py under the app/handlers directory and update the config/settings.py:
In the app/handlers/unfuddle.py, the handler code would be as below:
from lamson.routing import route, route_like, stateless from config.settings import UNFUDDLE_USERNAME, UNFUDDLE_PASSWORD import httplib2, json UNFUDDLE_API_ENDPOINT = "https://%(subdomain)s.unfuddle.com/api/v1" @route("(subdomain)\+(project)@(host)", subdomain="\w+", project="\w+", host=".+") def START(message, subdomain=None, project=None, host=None): UNFUDDLE_API_URL = UNFUDDLE_API_ENDPOINT %({"subdomain": subdomain}) h = httplib2.Http() h.add_credentials(UNFUDDLE_USERNAME, UNFUDDLE_PASSWORD) _, content = h.request("%(url)s/projects.json" %({"url": UNFUDDLE_API_URL}), method="GET") json_content = json.loads(content) proj = None for proj_iter in json_content: if proj_iter["short_name"] == project: proj = proj_iter if not proj: return START _, tickets = h.request("%(url)s/projects/%(id)s/ticket_reports/dynamic.json?conditions_string=status-neq-closed" %({"url": UNFUDDLE_API_URL, "id": proj["id"]})) ticket_json = json.loads(tickets) tickets = [] if ticket_json["groups"]: tickets = ticket_json["groups"][0]["tickets"] for ticket in tickets: if ticket["summary"] == message.base["Subject"]: _, content = h.request("%(url)s/projects/%(id)s/tickets/%(ticket_id)s/comments.json" %({"url": UNFUDDLE_API_URL, "id": proj["id"], "ticket_id": ticket["id"]}), method="POST", body="""{"comment": {"body": "%(body)s" } }""" %{"body": message.body().replace('"','\"')}, headers={"Accept": "application/json", "Content-Type": "application/json"}) return START _, content = h.request("%(url)s/projects/%(id)s/tickets.json" %({"url": UNFUDDLE_API_URL, "id": proj["id"]}), method="POST", body="""{"ticket": {"summary": "", "description": "", "priority": "3"} }""" %({"summary": message.base["Subject"].replace('"', '\"'), "description": message.body().replace('"', '\"') }), headers={"Accept": "application/json", "Content-Type": "application/json"}) return START @route_like(START) @stateless def ERROR(message, subdomain=None, project=None, host=None): return STARTFor a conventional application, e-mail is routed on the basis of rules mentioned in configuration files (aliases, macros etc) and then dropped off to a separate process (like fetchmail or procmail) which finally delivers the e-mail to it's destination. In lamson, all this routing is implemented through 'State Machines'. This makes for cleaner code (unified at one place and process) and easy to develop and debug. Each function generally represents a state and returns the next state (could be the same state itself) where the application should proceed. Lamson uses data stores to store the state. By default, it uses the MemoryStorage but it's very easy to write a custom data storage to say store the mails in a database etc.
In our example app, there are two states to the state machine. They are 'START' and 'ERROR'. The ERROR state is a special state in which the application finds itself when there's any error. The 'START' state accepts all mails with the from address in the regexp format (?P<subdomain>\w+)\+(?P<project>\w+)@(?P<host>.+). These captured regular expression groups are passed as keyword arguments to the 'START' function. Based on these keyword arguments, we use the Unfuddle API (which uses HTTP Basic Auth) to create a ticket if it doesn't exist else attach a comment to the ticket.
We'll have to restart the lamson server to be able to reflect the new changes. You can then use the local mutt config file to be able to send mails to the server and try out your changes (for example, send a mail to test+abc@localhost):
Keep a watch at the logs/lamson.log files while developing because this information may be invaluable.
In the next part, we'll see how to setup and deploy this application.
Note
The code for this e-mail application is available at https://github.com/agiliq/unfuddle/tree/master/email2ticket