Unfuddle Summary Script
By : Shabda Raaj
Unfuddle is our preferred tool for private repos, project management and ticketing. We recently wrote a slick script to summarize our Unfuddle status. So here is it.
import getpass
import simplejson
import sys
import urllib2
from datetime import datetime, date
try:
from settings import *
except ImportError:
ACCOUNT_DETAILS = {
'account': '',
'username': '',
'password': '',
}
SEND_MAIL = False
if not ACCOUNT_DETAILS['account']:
ACCOUNT_DETAILS['account'] = raw_input('Enter unfuddle account name: ')
if not ACCOUNT_DETAILS['username']:
ACCOUNT_DETAILS['username'] = raw_input('Username: ')
if not ACCOUNT_DETAILS['password']:
ACCOUNT_DETAILS['password'] = getpass.getpass()
class Unfuddle(object):
def __init__(self):
self.base_url = 'https://%s.unfuddle.com' % (ACCOUNT_DETAILS['account'])
self.api_base_path = '/api/v1/'
def get_data(self, api_end_point):
# url = 'https://agiliq.unfuddle.com/api/v1/projects'
url = self.base_url + self.api_base_path + api_end_point
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(realm='Unfuddle API',
uri=url,
user=ACCOUNT_DETAILS['username'],
passwd=ACCOUNT_DETAILS['password'])
opener = urllib2.build_opener(auth_handler)
opener.addheaders = [('Content-Type', 'application/xml'), ('Accept', 'application/json')]
# print '\n', url, '\n'
try:
response = opener.open(url).read().strip()
# print 'response:', response
return simplejson.loads(response)
except IOError, e:
print IOError, e
def get_projects(self):
return self.get_data('projects')
def select_project(self):
projects = self.get_projects()
if len(projects) == 1:
print 'There is only one project "%s"' % (projects[0]['title'])
return projects[0]
for index, project in enumerate(projects):
print '%s. %s' % (index+1, project['title'])
project_index = int(raw_input('Enter the project number: ')) - 1
return projects[project_index]
def get_tickets(self, project=None):
if not project:
project = self.select_project()
api_end_point = 'projects/%s/tickets' % (project['id'])
tickets = self.get_data(api_end_point)
return project, tickets
def dynamic_report(self, project=None, query_string=None):
if project:
api_end_point = 'projects/%s/ticket_reports/dynamic' % (project['id'])
else:
api_end_point = 'ticket_reports/dynamic'
if query_string:
api_end_point += '?%s' % (query_string)
dynamic_report = self.get_data(api_end_point)
return dynamic_report
def get_ticket_report():
unfuddle = Unfuddle()
project, tickets = unfuddle.get_tickets()
print '\n'
print 'Total tickets in project:', len(tickets)
today_new_tickets = []
today_resolved_tickets = []
today_closed_tickets = []
total_closed_tickets = 0
total_resolved_tickets = 0
total_pending_tickets = 0
for ticket in tickets:
if datetime.strptime(ticket['created_at'], '%Y-%m-%dT%H:%M:%SZ').date() == datetime.utcnow().date():
today_new_tickets.append(ticket)
elif datetime.strptime(ticket['updated_at'], '%Y-%m-%dT%H:%M:%SZ').date() == datetime.utcnow().date() and ticket['status'] == 'resolved':
today_resolved_tickets.append(ticket)
elif datetime.strptime(ticket['updated_at'], '%Y-%m-%dT%H:%M:%SZ').date() == datetime.utcnow().date() and ticket['status'] == 'closed':
today_closed_tickets.append(ticket)
if ticket['status'] == 'closed':
total_closed_tickets += 1
elif ticket['status'] == 'resolved':
total_resolved_tickets += 1
else:
total_pending_tickets += 1
print '\n'
print 'Today new tickets:', len(today_new_tickets)
print 'Today resolved tickets:', len(today_resolved_tickets)
print 'Today closed tickets:', len(today_closed_tickets)
print '\n'
print 'Total closed tickets:', total_closed_tickets
print 'Total resolved tickets:', total_resolved_tickets
print 'Total pending tickets:', total_pending_tickets
query_string = 'group_by=assignee'
query_string += '&conditions_string=status-neq-closed,status-neq-resolved'
dynamic_report = unfuddle.dynamic_report(project, query_string=query_string)
print '\n'
print 'Number of tickets in each person queue'
for group in sorted(dynamic_report['groups'], cmp=lambda x, y: cmp(len(y['tickets']), len(x['tickets']))):
if not group:
continue
print '\t', group['title'], ' ' * (25 - len(group.get('title', ''))), '-', len(group['tickets'])
"""
query_string = 'group_by=assignee'
query_string += '&conditions_string=status-eq-closed|status-eq-resolved'
# query_string += '&updated_at=%s' % (date.today().strftime('%Y-%m-%dT%H:%M:%SZ'))
dynamic_report = unfuddle.dynamic_report(project, query_string=query_string)
dynamic_report['new_groups'] = []
for group in dynamic_report['groups']:
new_group = group.copy()
new_group['tickets'] = filter(lambda x: datetime.strptime(x['updated_at'], '%Y-%m-%dT%H:%M:%SZ').date() == datetime.utcnow().date(), group['tickets'])
if new_group['title'] == 'Javed K.':
print new_group
dynamic_report['new_groups'].append(new_group)
print '\n'
print 'Number of tickets closed/resolved by each person today'
for group in sorted(dynamic_report['new_groups'], cmp=lambda x, y: cmp(len(y['tickets']), len(x['tickets']))):
if not group:
continue
print '\t', group['title'], ' ' * (25 - len(group.get('title', ''))), '-', len(group['tickets'])
"""
if __name__ == '__main__':
get_ticket_report()
Here is an sample output from it.
Enter unfuddle account name: agiliq
Username: shabda
Password:
1. account
2. AgiliqSolutions
3. [Redacted]
....
Enter the project number: 3
Total tickets in project: 159
Today new tickets: 0
Today resolved tickets: 1
Today closed tickets: 0
Total closed tickets: 140
Total resolved tickets: 3
Total pending tickets: 16
Number of tickets in each person queue
[Redacted] - 6
Ashok R. - 3
[Redacted] - 3
Shabda R. - 3
- 1
Can we help you build amazing apps? Contact us today.
As the leading language-learning software in the world, Rosetta Stone makes learning a new language second nature. Millions of learners in more than 150 countries have already used our software to gain the confidence that comes with truly knowing a new language. We’re continually improving our software technology and adding new products. With Rosetta Stone at the helm, the future of language learning is very bright indeed.