Here's a URLTrigger script that will do this.
If the Subject: line starts with //, the line will be parsed for these parameters:
- -p project-name
- -a area-name
- -c category-name
- -P assignee-name
The remainder of the line is the case title.
You can download the code here:
http://markharrison.net/fogbugz/fogbugz_EmailReceived.py.txt
Setup
- create a Fogbugz inbox
- install the URLTrigger plugin
- Configure the URLTrigger like this:
http://myweb/fogbugz_EmailReceived?case={CaseNumber}&subj={EmailSubject}
- set the admin_login information as specified.
Code
#!/usr/bin/python
"""
This is a fogbugz URLTrigger script.
If the subject line begins with "//" these parameters will be extracted:
-p project
-a area
-c category
-t assigned-to
example:
// -p myproject -a myarea -c mycategory -t myperson this is the title
bugs:
currently your project, area, etc can't have spaces.
it should also accept an appreviated project, area, etc name.
configure it like this on the url-trigger plugin:
http://myweb/fogbugz_EmailReceived?case={CaseNumber}&subj={EmailSubject}
"""
# set this to your fogbugz url, admin login, and password
admin_login=['http://spolsky','mh','']
import sys
import cgi
import urllib
import optparse
import xml.dom.minidom
def P(s):
sys.stderr.write('%s\n'%(s))
sys.stderr.flush()
#-----------------------------------------------------------------------
# fog bugz xml helpers
#-----------------------------------------------------------------------
class BabyFogBugzParser:
"""this is stripped down from the parser in fogbugz.py"""
def sendit(self,url):
P('url=:%s:'%(url))
f = urllib.urlopen(url)
resp=f.read()
return resp
def pp(self,s):
doc=xml.dom.minidom.parseString(s)
return doc.toprettyxml(indent=' ')
def raiseerror(self,s):
xdom = xml.dom.minidom.parseString(s)
xresponse=xdom.getElementsByTagName("response")[0]
xerror=xresponse.getElementsByTagName("error")
if xerror == []:
return False
else:
xerror=xerror[0]
code=xerror.getAttribute('code')
errtext=self.getText(xerror.childNodes)
sys.stderr.write('error %s %s\n'%(code,errtext))
sys.exit(1)
def generic_2level(self,s):
xdom = xml.dom.minidom.parseString(s)
xresponse=xdom.getElementsByTagName("response")[0]
qq={}
for nn in xresponse.childNodes:
if nn.nodeType == nn.ELEMENT_NODE:
qq[str(nn.nodeName)]=str(nn.childNodes[0].nodeValue.strip())
return qq
def api(self,s): return self.generic_2level(s)
def login2(self,s): return self.generic_2level(s)
#-----------------------------------------------------------------------
# cgi-code
#-----------------------------------------------------------------------
form = cgi.FieldStorage()
case=form.getvalue('case','0')
subj=form.getvalue('subj','--no-subj--')
# case='167'
# subj='// -p proj -a area -c category -T who this has opts'
P('----------------------------------')
P('subj=%s'%(subj))
if subj.startswith('//'):
a=subj[2:].split()
import optparse
p=optparse.OptionParser()
p.add_option("-p")
p.add_option("-a")
p.add_option("-c")
p.add_option("-P")
(opts,args) = p.parse_args(a)
title=' '.join(args)
if opts.p or opts.a or opts.c or opts.P:
if opts.p is None: opts.p=''
if opts.a is None: opts.a=''
if opts.c is None: opts.c=''
if opts.P is None: opts.P=''
P('opts=%s'%(opts))
P('title=%s'%(title))
fb=BabyFogBugzParser()
#-------------------------------------------------- api info
resp=fb.sendit('%s/api.xml'%(admin_login[0]))
fb.raiseerror(resp)
api_info=fb.api(resp)
api_url=api_info['url']
#-------------------------------------------------- login
resp=fb.sendit('%s/%s%s'%(admin_login[0],api_url,urllib.urlencode({
'cmd' : 'logon',
'email' : admin_login[1],
'password' : admin_login[2],
})))
fb.raiseerror(resp)
login_info=fb.login2(resp)
tok=login_info['token']
#-------------------------------------------------- edit item
resp=fb.sendit('%s/%s%s'%(admin_login[0],api_url,urllib.urlencode({
'token' : tok,
'cmd' : 'edit',
'ixBug' : case,
'sProject' : opts.p,
'sArea' : opts.a,
'sCategory' : opts.c,
'sPersonAssignedTo' : opts.P,
'sTitle' : title,
})))
P(resp)
fb.raiseerror(resp)
sys.stdout.write("\n<body>thanks</body>\n")
sys.stdout.flush()