2008-01-07 21:22:13 +01:00
|
|
|
""" ..
|
2008-02-06 05:36:07 +01:00
|
|
|
Jutda Helpdesk - A Django powered ticket tracker for small enterprise.
|
|
|
|
|
|
|
|
(c) Copyright 2008 Jutda. All Rights Reserved. See LICENSE for details.
|
|
|
|
|
|
|
|
lib.py - Common functions (eg multipart e-mail)
|
2008-01-07 21:22:13 +01:00
|
|
|
"""
|
2008-04-02 01:26:12 +02:00
|
|
|
def send_templated_mail(template_name, email_context, recipients, sender=None, bcc=None, fail_silently=False, files=None):
|
|
|
|
from helpdesk.models import EmailTemplate
|
|
|
|
from django.core.mail import EmailMultiAlternatives
|
|
|
|
from django.template import loader, Context
|
|
|
|
from django.conf import settings
|
|
|
|
|
|
|
|
t = EmailTemplate.objects.get(template_name__iexact=template_name)
|
|
|
|
|
|
|
|
if not sender:
|
|
|
|
sender = settings.DEFAULT_FROM_EMAIL
|
|
|
|
|
|
|
|
context = Context(email_context)
|
|
|
|
|
|
|
|
text_part = loader.get_template_from_string("%s{%% include 'helpdesk/email_text_footer.txt' %%}" % t.plain_text).render(context)
|
|
|
|
html_part = loader.get_template_from_string("{%% extends 'helpdesk/email_html_base.html' %%}{%% block title %%}%s{%% endblock %%}{%% block content %%}%s{%% endblock %%}" % (t.heading, t.html)).render(context)
|
|
|
|
subject_part = loader.get_template_from_string("{{ ticket.ticket }} {{ ticket.title }} %s" % t.subject).render(context)
|
|
|
|
|
|
|
|
if type(recipients) != list:
|
|
|
|
recipients = [recipients,]
|
|
|
|
|
|
|
|
msg = EmailMultiAlternatives(subject_part, text_part, sender, recipients, bcc=bcc)
|
|
|
|
msg.attach_alternative(html_part, "text/html")
|
|
|
|
|
|
|
|
if files:
|
|
|
|
if type(files) != list:
|
|
|
|
files = [files,]
|
|
|
|
|
|
|
|
for file in files:
|
|
|
|
msg.attach_file(file)
|
|
|
|
|
|
|
|
return msg.send(fail_silently)
|
|
|
|
|
|
|
|
|
2008-01-07 21:22:13 +01:00
|
|
|
|
|
|
|
def send_multipart_mail(template_name, email_context, subject, recipients, sender=None, bcc=None, fail_silently=False, files=None):
|
|
|
|
"""
|
|
|
|
This function will send a multi-part e-mail with both HTML and
|
|
|
|
Text parts.
|
|
|
|
|
|
|
|
template_name must NOT contain an extension. Both HTML (.html) and TEXT
|
|
|
|
(.txt) versions must exist, eg 'emails/public_submit' will use both
|
|
|
|
public_submit.html and public_submit.txt.
|
|
|
|
|
|
|
|
email_context should be a plain python dictionary. It is applied against
|
|
|
|
both the email messages (templates) & the subject.
|
|
|
|
|
|
|
|
subject can be plain text or a Django template string, eg:
|
|
|
|
New Job: {{ job.id }} {{ job.title }}
|
|
|
|
|
|
|
|
recipients can be either a string, eg 'a@b.com' or a list, eg:
|
|
|
|
['a@b.com', 'c@d.com']. Type conversion is done if needed.
|
|
|
|
|
|
|
|
sender can be an e-mail, 'Name <email>' or None. If unspecified, the
|
|
|
|
DEFAULT_FROM_EMAIL will be used.
|
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
Originally posted on my blog at http://www.rossp.org/
|
2008-01-07 21:22:13 +01:00
|
|
|
"""
|
|
|
|
from django.core.mail import EmailMultiAlternatives
|
|
|
|
from django.template import loader, Context
|
|
|
|
from django.conf import settings
|
|
|
|
|
|
|
|
if not sender:
|
|
|
|
sender = settings.DEFAULT_FROM_EMAIL
|
|
|
|
|
|
|
|
context = Context(email_context)
|
|
|
|
|
|
|
|
text_part = loader.get_template('%s.txt' % template_name).render(context)
|
|
|
|
html_part = loader.get_template('%s.html' % template_name).render(context)
|
|
|
|
subject_part = loader.get_template_from_string(subject).render(context)
|
|
|
|
|
|
|
|
if type(recipients) != list:
|
|
|
|
recipients = [recipients,]
|
|
|
|
|
|
|
|
msg = EmailMultiAlternatives(subject_part, text_part, sender, recipients, bcc=bcc)
|
|
|
|
msg.attach_alternative(html_part, "text/html")
|
|
|
|
|
|
|
|
if files:
|
|
|
|
if type(files) != list:
|
|
|
|
files = [files,]
|
|
|
|
|
|
|
|
for file in files:
|
|
|
|
msg.attach_file(file)
|
|
|
|
|
|
|
|
return msg.send(fail_silently)
|
|
|
|
|
2008-02-06 23:47:46 +01:00
|
|
|
|
2008-04-02 01:26:12 +02:00
|
|
|
def normalise_data(data, to=100):
|
2008-02-06 05:36:07 +01:00
|
|
|
"""
|
|
|
|
Used for normalising data prior to graphing with Google charting API
|
|
|
|
"""
|
2008-02-06 00:35:40 +01:00
|
|
|
max_value = max(data)
|
2008-04-02 01:26:12 +02:00
|
|
|
if max_value > to:
|
2008-02-06 00:35:40 +01:00
|
|
|
new_data = []
|
|
|
|
for d in data:
|
2008-04-02 01:26:12 +02:00
|
|
|
new_data.append(int(d/float(max_value)*to))
|
2008-02-06 00:35:40 +01:00
|
|
|
data = new_data
|
|
|
|
return data
|
2008-04-02 01:26:12 +02:00
|
|
|
|
|
|
|
chart_colours = ('80C65A', '990066', 'FF9900', '3399CC', 'BBCCED', '3399CC', 'FFCC33')
|
|
|
|
|
|
|
|
def line_chart(data):
|
|
|
|
"""
|
|
|
|
'data' is a list of lists making a table.
|
|
|
|
Row 1, columns 2-n are data headings (the time periods)
|
|
|
|
Rows 2-n are data, with column 1 being the line labels
|
|
|
|
"""
|
|
|
|
|
|
|
|
column_headings = data[0][1:]
|
|
|
|
max = 0
|
|
|
|
for row in data[1:]:
|
|
|
|
for field in row[1:]:
|
|
|
|
if field > max:
|
|
|
|
max = field
|
|
|
|
|
|
|
|
|
|
|
|
# Set width to '65px * number of months'.
|
|
|
|
chart_url = 'http://chart.apis.google.com/chart?cht=lc&chs=%sx90&chd=t:' % (len(column_headings)*65)
|
|
|
|
first_row = True
|
|
|
|
row_headings = []
|
|
|
|
for row in data[1:]:
|
|
|
|
# Add data to URL, normalised to the maximum for all lines on this chart
|
|
|
|
norm = normalise_data(row[1:], max)
|
|
|
|
if not first_row:
|
|
|
|
chart_url += '|'
|
|
|
|
chart_url += ','.join([str(num) for num in norm])
|
|
|
|
row_headings.append(row[0])
|
|
|
|
first_row = False
|
|
|
|
|
|
|
|
chart_url += '&chds='
|
|
|
|
rows = len(data)-1
|
|
|
|
first = True
|
|
|
|
for row in range(rows):
|
|
|
|
# Set maximum data ranges to '0:x' where 'x' is the maximum number in use.
|
|
|
|
if not first:
|
|
|
|
chart_url += ','
|
|
|
|
chart_url += '0,%s' % max
|
|
|
|
first = False
|
|
|
|
chart_url += '&chdl=%s' % '|'.join(row_headings) # Display legend/labels
|
|
|
|
chart_url += '&chco=%s' % ','.join(chart_colours) # Default colour set
|
|
|
|
chart_url += '&chxt=x,y' # Turn on axis labels
|
|
|
|
chart_url += '&chxl=0:|%s|1:|0|%s' % ('|'.join(column_headings), max) # Axis Label Text
|
|
|
|
|
|
|
|
return chart_url
|
|
|
|
|
|
|
|
def bar_chart(data):
|
|
|
|
"""
|
|
|
|
'data' is a list of lists making a table.
|
|
|
|
Row 1, columns 2-n are data headings
|
|
|
|
Rows 2-n are data, with column 1 being the line labels
|
|
|
|
"""
|
|
|
|
|
|
|
|
column_headings = data[0][1:]
|
|
|
|
max = 0
|
|
|
|
for row in data[1:]:
|
|
|
|
for field in row[1:]:
|
|
|
|
if field > max:
|
|
|
|
max = field
|
|
|
|
|
|
|
|
|
|
|
|
# Set width to '150px * number of months'.
|
|
|
|
chart_url = 'http://chart.apis.google.com/chart?cht=bvg&chs=%sx90&chd=t:' % (len(column_headings) * 150)
|
|
|
|
first_row = True
|
|
|
|
row_headings = []
|
|
|
|
for row in data[1:]:
|
|
|
|
# Add data to URL, normalised to the maximum for all lines on this chart
|
|
|
|
norm = normalise_data(row[1:], max)
|
|
|
|
if not first_row:
|
|
|
|
chart_url += '|'
|
|
|
|
chart_url += ','.join([str(num) for num in norm])
|
|
|
|
row_headings.append(row[0])
|
|
|
|
first_row = False
|
|
|
|
|
|
|
|
chart_url += '&chds=0,%s' % max
|
|
|
|
chart_url += '&chdl=%s' % '|'.join(row_headings) # Display legend/labels
|
|
|
|
chart_url += '&chco=%s' % ','.join(chart_colours) # Default colour set
|
|
|
|
chart_url += '&chxt=x,y' # Turn on axis labels
|
|
|
|
chart_url += '&chxl=0:|%s|1:|0|%s' % ('|'.join(column_headings), max) # Axis Label Text
|
|
|
|
|
|
|
|
return chart_url
|
2008-05-07 11:04:18 +02:00
|
|
|
|
|
|
|
def query_to_dict(results, descriptions):
|
|
|
|
""" Replacement method for cursor.dictfetchall() as that method no longer
|
|
|
|
exists in psycopg2, and I'm guessing in other backends too.
|
|
|
|
|
|
|
|
Converts the results of a raw SQL query into a list of dictionaries, suitable
|
|
|
|
for use in templates etc. """
|
|
|
|
output = []
|
|
|
|
for data in results:
|
|
|
|
row = {}
|
|
|
|
i = 0
|
|
|
|
for column in descriptions:
|
|
|
|
row[column[0]] = data[i]
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
output.append(row)
|
|
|
|
return output
|