almost auto-fix on misc files

This commit is contained in:
Alex Barcelo 2016-10-23 22:09:17 +02:00
parent 3c35473265
commit 30e3aa55aa
10 changed files with 230 additions and 219 deletions

View File

@ -35,6 +35,7 @@ class CustomFieldMixin(object):
""" """
Mixin that provides a method to turn CustomFields into an actual field Mixin that provides a method to turn CustomFields into an actual field
""" """
def customfield_to_field(self, field, instanceargs): def customfield_to_field(self, field, instanceargs):
if field.data_type == 'varchar': if field.data_type == 'varchar':
fieldclass = forms.CharField fieldclass = forms.CharField
@ -76,6 +77,7 @@ class CustomFieldMixin(object):
class EditTicketForm(CustomFieldMixin, forms.ModelForm): class EditTicketForm(CustomFieldMixin, forms.ModelForm):
class Meta: class Meta:
model = Ticket model = Ticket
exclude = ('created', 'modified', 'status', 'on_hold', 'resolution', 'last_escalation', 'assigned_to') exclude = ('created', 'modified', 'status', 'on_hold', 'resolution', 'last_escalation', 'assigned_to')
@ -93,11 +95,11 @@ class EditTicketForm(CustomFieldMixin, forms.ModelForm):
except TicketCustomFieldValue.DoesNotExist: except TicketCustomFieldValue.DoesNotExist:
initial_value = None initial_value = None
instanceargs = { instanceargs = {
'label': field.label, 'label': field.label,
'help_text': field.help_text, 'help_text': field.help_text,
'required': field.required, 'required': field.required,
'initial': initial_value, 'initial': initial_value,
} }
self.customfield_to_field(field, instanceargs) self.customfield_to_field(field, instanceargs)
@ -118,6 +120,7 @@ class EditTicketForm(CustomFieldMixin, forms.ModelForm):
class EditFollowUpForm(forms.ModelForm): class EditFollowUpForm(forms.ModelForm):
class Meta: class Meta:
model = FollowUp model = FollowUp
exclude = ('date', 'user',) exclude = ('date', 'user',)
@ -133,28 +136,28 @@ class TicketForm(CustomFieldMixin, forms.Form):
label=_('Queue'), label=_('Queue'),
required=True, required=True,
choices=() choices=()
) )
title = forms.CharField( title = forms.CharField(
max_length=100, max_length=100,
required=True, required=True,
widget=forms.TextInput(attrs={'size':'60'}), widget=forms.TextInput(attrs={'size': '60'}),
label=_('Summary of the problem'), label=_('Summary of the problem'),
) )
submitter_email = forms.EmailField( submitter_email = forms.EmailField(
required=False, required=False,
label=_('Submitter E-Mail Address'), label=_('Submitter E-Mail Address'),
widget=forms.TextInput(attrs={'size':'60'}), widget=forms.TextInput(attrs={'size': '60'}),
help_text=_('This e-mail address will receive copies of all public ' help_text=_('This e-mail address will receive copies of all public '
'updates to this ticket.'), 'updates to this ticket.'),
) )
body = forms.CharField( body = forms.CharField(
widget=forms.Textarea(attrs={'cols': 47, 'rows': 15}), widget=forms.Textarea(attrs={'cols': 47, 'rows': 15}),
label=_('Description of Issue'), label=_('Description of Issue'),
required=True, required=True,
) )
assigned_to = forms.ChoiceField( assigned_to = forms.ChoiceField(
choices=(), choices=(),
@ -162,7 +165,7 @@ class TicketForm(CustomFieldMixin, forms.Form):
label=_('Case owner'), label=_('Case owner'),
help_text=_('If you select an owner other than yourself, they\'ll be ' help_text=_('If you select an owner other than yourself, they\'ll be '
'e-mailed details of this ticket immediately.'), 'e-mailed details of this ticket immediately.'),
) )
priority = forms.ChoiceField( priority = forms.ChoiceField(
choices=Ticket.PRIORITY_CHOICES, choices=Ticket.PRIORITY_CHOICES,
@ -170,13 +173,13 @@ class TicketForm(CustomFieldMixin, forms.Form):
initial='3', initial='3',
label=_('Priority'), label=_('Priority'),
help_text=_('Please select a priority carefully. If unsure, leave it as \'3\'.'), help_text=_('Please select a priority carefully. If unsure, leave it as \'3\'.'),
) )
due_date = forms.DateTimeField( due_date = forms.DateTimeField(
widget=extras.SelectDateWidget, widget=extras.SelectDateWidget,
required=False, required=False,
label=_('Due on'), label=_('Due on'),
) )
def clean_due_date(self): def clean_due_date(self):
data = self.cleaned_data['due_date'] data = self.cleaned_data['due_date']
@ -189,7 +192,7 @@ class TicketForm(CustomFieldMixin, forms.Form):
required=False, required=False,
label=_('Attach File'), label=_('Attach File'),
help_text=_('You can attach a file such as a document or screenshot to this ticket.'), help_text=_('You can attach a file such as a document or screenshot to this ticket.'),
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
""" """
@ -198,10 +201,10 @@ class TicketForm(CustomFieldMixin, forms.Form):
super(TicketForm, self).__init__(*args, **kwargs) super(TicketForm, self).__init__(*args, **kwargs)
for field in CustomField.objects.all(): for field in CustomField.objects.all():
instanceargs = { instanceargs = {
'label': field.label, 'label': field.label,
'help_text': field.help_text, 'help_text': field.help_text,
'required': field.required, 'required': field.required,
} }
self.customfield_to_field(field, instanceargs) self.customfield_to_field(field, instanceargs)
@ -263,7 +266,7 @@ class TicketForm(CustomFieldMixin, forms.Form):
filename=filename, filename=filename,
mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream',
size=file.size, size=file.size,
) )
a.file.save(file.name, file, save=False) a.file.save(file.name, file, save=False)
a.save() a.save()
@ -288,7 +291,7 @@ class TicketForm(CustomFieldMixin, forms.Form):
sender=q.from_address, sender=q.from_address,
fail_silently=True, fail_silently=True,
files=files, files=files,
) )
messages_sent_to.append(t.submitter_email) messages_sent_to.append(t.submitter_email)
if t.assigned_to and \ if t.assigned_to and \
@ -303,7 +306,7 @@ class TicketForm(CustomFieldMixin, forms.Form):
sender=q.from_address, sender=q.from_address,
fail_silently=True, fail_silently=True,
files=files, files=files,
) )
messages_sent_to.append(t.assigned_to.email) messages_sent_to.append(t.assigned_to.email)
if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to: if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to:
@ -314,7 +317,7 @@ class TicketForm(CustomFieldMixin, forms.Form):
sender=q.from_address, sender=q.from_address,
fail_silently=True, fail_silently=True,
files=files, files=files,
) )
messages_sent_to.append(q.new_ticket_cc) messages_sent_to.append(q.new_ticket_cc)
if q.updated_ticket_cc and \ if q.updated_ticket_cc and \
@ -327,7 +330,7 @@ class TicketForm(CustomFieldMixin, forms.Form):
sender=q.from_address, sender=q.from_address,
fail_silently=True, fail_silently=True,
files=files, files=files,
) )
return t return t
@ -337,20 +340,20 @@ class PublicTicketForm(CustomFieldMixin, forms.Form):
label=_('Queue'), label=_('Queue'),
required=True, required=True,
choices=() choices=()
) )
title = forms.CharField( title = forms.CharField(
max_length=100, max_length=100,
required=True, required=True,
widget=forms.TextInput(), widget=forms.TextInput(),
label=_('Summary of your query'), label=_('Summary of your query'),
) )
submitter_email = forms.EmailField( submitter_email = forms.EmailField(
required=True, required=True,
label=_('Your E-Mail Address'), label=_('Your E-Mail Address'),
help_text=_('We will e-mail you when your ticket is updated.'), help_text=_('We will e-mail you when your ticket is updated.'),
) )
body = forms.CharField( body = forms.CharField(
widget=forms.Textarea(), widget=forms.Textarea(),
@ -358,7 +361,7 @@ class PublicTicketForm(CustomFieldMixin, forms.Form):
required=True, required=True,
help_text=_('Please be as descriptive as possible, including any ' help_text=_('Please be as descriptive as possible, including any '
'details we may need to address your query.'), 'details we may need to address your query.'),
) )
priority = forms.ChoiceField( priority = forms.ChoiceField(
choices=Ticket.PRIORITY_CHOICES, choices=Ticket.PRIORITY_CHOICES,
@ -366,20 +369,20 @@ class PublicTicketForm(CustomFieldMixin, forms.Form):
initial='3', initial='3',
label=_('Urgency'), label=_('Urgency'),
help_text=_('Please select a priority carefully.'), help_text=_('Please select a priority carefully.'),
) )
due_date = forms.DateTimeField( due_date = forms.DateTimeField(
widget=extras.SelectDateWidget, widget=extras.SelectDateWidget,
required=False, required=False,
label=_('Due on'), label=_('Due on'),
) )
attachment = forms.FileField( attachment = forms.FileField(
required=False, required=False,
label=_('Attach File'), label=_('Attach File'),
help_text=_('You can attach a file such as a document or screenshot to this ticket.'), help_text=_('You can attach a file such as a document or screenshot to this ticket.'),
max_length=1000, max_length=1000,
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
""" """
@ -388,10 +391,10 @@ class PublicTicketForm(CustomFieldMixin, forms.Form):
super(PublicTicketForm, self).__init__(*args, **kwargs) super(PublicTicketForm, self).__init__(*args, **kwargs)
for field in CustomField.objects.filter(staff_only=False): for field in CustomField.objects.filter(staff_only=False):
instanceargs = { instanceargs = {
'label': field.label, 'label': field.label,
'help_text': field.help_text, 'help_text': field.help_text,
'required': field.required, 'required': field.required,
} }
self.customfield_to_field(field, instanceargs) self.customfield_to_field(field, instanceargs)
@ -411,7 +414,7 @@ class PublicTicketForm(CustomFieldMixin, forms.Form):
description=self.cleaned_data['body'], description=self.cleaned_data['body'],
priority=self.cleaned_data['priority'], priority=self.cleaned_data['priority'],
due_date=self.cleaned_data['due_date'], due_date=self.cleaned_data['due_date'],
) )
if q.default_owner and not t.assigned_to: if q.default_owner and not t.assigned_to:
t.assigned_to = q.default_owner t.assigned_to = q.default_owner
@ -433,7 +436,7 @@ class PublicTicketForm(CustomFieldMixin, forms.Form):
date=timezone.now(), date=timezone.now(),
public=True, public=True,
comment=self.cleaned_data['body'], comment=self.cleaned_data['body'],
) )
f.save() f.save()
@ -447,7 +450,7 @@ class PublicTicketForm(CustomFieldMixin, forms.Form):
filename=filename, filename=filename,
mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream', mime_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream',
size=file.size, size=file.size,
) )
a.file.save(file.name, file, save=False) a.file.save(file.name, file, save=False)
a.save() a.save()
@ -467,7 +470,7 @@ class PublicTicketForm(CustomFieldMixin, forms.Form):
sender=q.from_address, sender=q.from_address,
fail_silently=True, fail_silently=True,
files=files, files=files,
) )
messages_sent_to.append(t.submitter_email) messages_sent_to.append(t.submitter_email)
if t.assigned_to and \ if t.assigned_to and \
@ -481,7 +484,7 @@ class PublicTicketForm(CustomFieldMixin, forms.Form):
sender=q.from_address, sender=q.from_address,
fail_silently=True, fail_silently=True,
files=files, files=files,
) )
messages_sent_to.append(t.assigned_to.email) messages_sent_to.append(t.assigned_to.email)
if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to: if q.new_ticket_cc and q.new_ticket_cc not in messages_sent_to:
@ -492,7 +495,7 @@ class PublicTicketForm(CustomFieldMixin, forms.Form):
sender=q.from_address, sender=q.from_address,
fail_silently=True, fail_silently=True,
files=files, files=files,
) )
messages_sent_to.append(q.new_ticket_cc) messages_sent_to.append(q.new_ticket_cc)
if q.updated_ticket_cc and \ if q.updated_ticket_cc and \
@ -505,7 +508,7 @@ class PublicTicketForm(CustomFieldMixin, forms.Form):
sender=q.from_address, sender=q.from_address,
fail_silently=True, fail_silently=True,
files=files, files=files,
) )
return t return t
@ -515,25 +518,25 @@ class UserSettingsForm(forms.Form):
label=_('Show Ticket List on Login?'), label=_('Show Ticket List on Login?'),
help_text=_('Display the ticket list upon login? Otherwise, the dashboard is shown.'), help_text=_('Display the ticket list upon login? Otherwise, the dashboard is shown.'),
required=False, required=False,
) )
email_on_ticket_change = forms.BooleanField( email_on_ticket_change = forms.BooleanField(
label=_('E-mail me on ticket change?'), label=_('E-mail me on ticket change?'),
help_text=_('If you\'re the ticket owner and the ticket is changed via the web by somebody else, do you want to receive an e-mail?'), help_text=_('If you\'re the ticket owner and the ticket is changed via the web by somebody else, do you want to receive an e-mail?'),
required=False, required=False,
) )
email_on_ticket_assign = forms.BooleanField( email_on_ticket_assign = forms.BooleanField(
label=_('E-mail me when assigned a ticket?'), label=_('E-mail me when assigned a ticket?'),
help_text=_('If you are assigned a ticket via the web, do you want to receive an e-mail?'), help_text=_('If you are assigned a ticket via the web, do you want to receive an e-mail?'),
required=False, required=False,
) )
email_on_ticket_apichange = forms.BooleanField( email_on_ticket_apichange = forms.BooleanField(
label=_('E-mail me when a ticket is changed via the API?'), label=_('E-mail me when a ticket is changed via the API?'),
help_text=_('If a ticket is altered by the API, do you want to receive an e-mail?'), help_text=_('If a ticket is altered by the API, do you want to receive an e-mail?'),
required=False, required=False,
) )
tickets_per_page = forms.IntegerField( tickets_per_page = forms.IntegerField(
label=_('Number of tickets to show per page'), label=_('Number of tickets to show per page'),
@ -541,22 +544,24 @@ class UserSettingsForm(forms.Form):
required=False, required=False,
min_value=1, min_value=1,
max_value=1000, max_value=1000,
) )
use_email_as_submitter = forms.BooleanField( use_email_as_submitter = forms.BooleanField(
label=_('Use my e-mail address when submitting tickets?'), label=_('Use my e-mail address when submitting tickets?'),
help_text=_('When you submit a ticket, do you want to automatically use your e-mail address as the submitter address? You can type a different e-mail address when entering the ticket if needed, this option only changes the default.'), help_text=_('When you submit a ticket, do you want to automatically use your e-mail address as the submitter address? You can type a different e-mail address when entering the ticket if needed, this option only changes the default.'),
required=False, required=False,
) )
class EmailIgnoreForm(forms.ModelForm): class EmailIgnoreForm(forms.ModelForm):
class Meta: class Meta:
model = IgnoreEmail model = IgnoreEmail
exclude = [] exclude = []
class TicketCCForm(forms.ModelForm): class TicketCCForm(forms.ModelForm):
class Meta: class Meta:
model = TicketCC model = TicketCC
exclude = ('ticket',) exclude = ('ticket',)
@ -571,6 +576,7 @@ class TicketCCForm(forms.ModelForm):
class TicketDependencyForm(forms.ModelForm): class TicketDependencyForm(forms.ModelForm):
class Meta: class Meta:
model = TicketDependency model = TicketDependency
exclude = ('ticket',) exclude = ('ticket',)

View File

@ -109,7 +109,7 @@ def send_templated_mail(template_name,
text_part = template_func( text_part = template_func(
"%s{%% include '%s' %%}" % (t.plain_text, footer_file) "%s{%% include '%s' %%}" % (t.plain_text, footer_file)
).render(context) ).render(context)
email_html_base_file = os.path.join('helpdesk', locale, 'email_html_base.html') email_html_base_file = os.path.join('helpdesk', locale, 'email_html_base.html')
@ -233,8 +233,8 @@ def safe_template_context(ticket):
context = { context = {
'queue': {}, 'queue': {},
'ticket': {}, 'ticket': {}
} }
queue = ticket.queue queue = ticket.queue
for field in ('title', 'slug', 'email_address', 'from_address', 'locale'): for field in ('title', 'slug', 'email_address', 'from_address', 'locale'):

View File

@ -21,6 +21,7 @@ from helpdesk.models import EscalationExclusion, Queue
class Command(BaseCommand): class Command(BaseCommand):
def __init__(self): def __init__(self):
BaseCommand.__init__(self) BaseCommand.__init__(self)
@ -42,7 +43,7 @@ class Command(BaseCommand):
default=False, default=False,
dest='escalate-verbosely', dest='escalate-verbosely',
help='Display a list of dates excluded'), help='Display a list of dates excluded'),
) )
def handle(self, *args, **options): def handle(self, *args, **options):
days = options['days'] days = options['days']

View File

@ -25,6 +25,7 @@ from helpdesk.models import Queue
class Command(BaseCommand): class Command(BaseCommand):
def __init__(self): def __init__(self):
BaseCommand.__init__(self) BaseCommand.__init__(self)
@ -32,7 +33,7 @@ class Command(BaseCommand):
make_option( make_option(
'--queues', '-q', '--queues', '-q',
help='Queues to include (default: all). Use queue slugs'), help='Queues to include (default: all). Use queue slugs'),
) )
def handle(self, *args, **options): def handle(self, *args, **options):
queue_slugs = options['queues'] queue_slugs = options['queues']
@ -71,4 +72,3 @@ class Command(BaseCommand):
) )
except IntegrityError: except IntegrityError:
self.stdout.write(" .. permission already existed, skipping") self.stdout.write(" .. permission already existed, skipping")

View File

@ -4,7 +4,7 @@ django-helpdesk - A Django powered ticket tracker for small enterprise.
See LICENSE for details. See LICENSE for details.
create_usersettings.py - Easy way to create helpdesk-specific settings for create_usersettings.py - Easy way to create helpdesk-specific settings for
users who don't yet have them. users who don't yet have them.
""" """

View File

@ -28,6 +28,7 @@ from helpdesk.lib import send_templated_mail, safe_template_context
class Command(BaseCommand): class Command(BaseCommand):
def __init__(self): def __init__(self):
BaseCommand.__init__(self) BaseCommand.__init__(self)
@ -40,7 +41,7 @@ class Command(BaseCommand):
action='store_true', action='store_true',
default=False, default=False,
help='Display a list of dates excluded'), help='Display a list of dates excluded'),
) )
def handle(self, *args, **options): def handle(self, *args, **options):
verbose = False verbose = False
@ -88,17 +89,17 @@ def escalate_tickets(queues, verbose):
print("Processing: %s" % q) print("Processing: %s" % q)
for t in q.ticket_set.filter( for t in q.ticket_set.filter(
Q(status=Ticket.OPEN_STATUS) Q(status=Ticket.OPEN_STATUS) |
| Q(status=Ticket.REOPENED_STATUS) Q(status=Ticket.REOPENED_STATUS)
).exclude( ).exclude(
priority=1 priority=1
).filter( ).filter(
Q(on_hold__isnull=True) Q(on_hold__isnull=True) |
| Q(on_hold=False) Q(on_hold=False)
).filter( ).filter(
Q(last_escalation__lte=req_last_escl_date) Q(last_escalation__lte=req_last_escl_date) |
| Q(last_escalation__isnull=True, created__lte=req_last_escl_date) Q(last_escalation__isnull=True, created__lte=req_last_escl_date)
): ):
t.last_escalation = timezone.now() t.last_escalation = timezone.now()
t.priority -= 1 t.priority -= 1
@ -113,7 +114,7 @@ def escalate_tickets(queues, verbose):
recipients=t.submitter_email, recipients=t.submitter_email,
sender=t.queue.from_address, sender=t.queue.from_address,
fail_silently=True, fail_silently=True,
) )
if t.queue.updated_ticket_cc: if t.queue.updated_ticket_cc:
send_templated_mail( send_templated_mail(
@ -122,7 +123,7 @@ def escalate_tickets(queues, verbose):
recipients=t.queue.updated_ticket_cc, recipients=t.queue.updated_ticket_cc,
sender=t.queue.from_address, sender=t.queue.from_address,
fail_silently=True, fail_silently=True,
) )
if t.assigned_to: if t.assigned_to:
send_templated_mail( send_templated_mail(
@ -131,14 +132,14 @@ def escalate_tickets(queues, verbose):
recipients=t.assigned_to.email, recipients=t.assigned_to.email,
sender=t.queue.from_address, sender=t.queue.from_address,
fail_silently=True, fail_silently=True,
) )
if verbose: if verbose:
print(" - Esclating %s from %s>%s" % ( print(" - Esclating %s from %s>%s" % (
t.ticket, t.ticket,
t.priority+1, t.priority + 1,
t.priority t.priority
) )
) )
f = FollowUp( f = FollowUp(

View File

@ -48,7 +48,9 @@ STRIPPED_SUBJECT_STRINGS = [
"Automatic reply: ", "Automatic reply: ",
] ]
class Command(BaseCommand): class Command(BaseCommand):
def __init__(self): def __init__(self):
BaseCommand.__init__(self) BaseCommand.__init__(self)
@ -58,7 +60,7 @@ class Command(BaseCommand):
default=False, default=False,
action='store_true', action='store_true',
help='Hide details about each queue/message as they are processed'), help='Hide details about each queue/message as they are processed'),
) )
help = 'Process Jutda Helpdesk queues and process e-mails via ' \ help = 'Process Jutda Helpdesk queues and process e-mails via ' \
'POP3/IMAP as required, feeding them into the helpdesk.' 'POP3/IMAP as required, feeding them into the helpdesk.'
@ -74,7 +76,7 @@ def process_email(quiet=False):
allow_email_submission=True): allow_email_submission=True):
if not q.email_box_last_check: if not q.email_box_last_check:
q.email_box_last_check = timezone.now()-timedelta(minutes=30) q.email_box_last_check = timezone.now() - timedelta(minutes=30)
if not q.email_box_interval: if not q.email_box_interval:
q.email_box_interval = 0 q.email_box_interval = 0
@ -176,7 +178,7 @@ def process_queue(q, quiet=False):
ticket = ticket_from_message(message=data[0][1], queue=q, quiet=quiet) ticket = ticket_from_message(message=data[0][1], queue=q, quiet=quiet)
if ticket: if ticket:
server.store(num, '+FLAGS', '\\Deleted') server.store(num, '+FLAGS', '\\Deleted')
server.expunge() server.expunge()
server.close() server.close()
server.logout() server.logout()
@ -221,7 +223,7 @@ def ticket_from_message(message, queue, quiet):
return False return False
return True return True
matchobj = re.match(r".*\["+queue.slug+"-(?P<id>\d+)\]", subject) matchobj = re.match(r".*\[" + queue.slug + "-(?P<id>\d+)\]", subject)
if matchobj: if matchobj:
# This is a reply or forward. # This is a reply or forward.
ticket = matchobj.group('id') ticket = matchobj.group('id')
@ -254,7 +256,7 @@ def ticket_from_message(message, queue, quiet):
'filename': name, 'filename': name,
'content': part.get_payload(decode=True), 'content': part.get_payload(decode=True),
'type': part.get_content_type()}, 'type': part.get_content_type()},
) )
counter += 1 counter += 1
@ -317,7 +319,7 @@ def ticket_from_message(message, queue, quiet):
if t.status == Ticket.REOPENED_STATUS: if t.status == Ticket.REOPENED_STATUS:
f.new_status = Ticket.REOPENED_STATUS f.new_status = Ticket.REOPENED_STATUS
f.title = _('Ticket Re-Opened by E-Mail Received from %(sender_email)s' % {'sender_email': sender_email}) f.title = _('Ticket Re-Opened by E-Mail Received from %(sender_email)s' % {'sender_email': sender_email})
f.save() f.save()
if not quiet: if not quiet:
@ -332,7 +334,7 @@ def ticket_from_message(message, queue, quiet):
filename=filename, filename=filename,
mime_type=file['type'], mime_type=file['type'],
size=len(file['content']), size=len(file['content']),
) )
a.file.save(filename, ContentFile(file['content']), save=False) a.file.save(filename, ContentFile(file['content']), save=False)
a.save() a.save()
if not quiet: if not quiet:
@ -349,7 +351,7 @@ def ticket_from_message(message, queue, quiet):
recipients=sender_email, recipients=sender_email,
sender=queue.from_address, sender=queue.from_address,
fail_silently=True, fail_silently=True,
) )
if queue.new_ticket_cc: if queue.new_ticket_cc:
send_templated_mail( send_templated_mail(
@ -358,7 +360,7 @@ def ticket_from_message(message, queue, quiet):
recipients=queue.new_ticket_cc, recipients=queue.new_ticket_cc,
sender=queue.from_address, sender=queue.from_address,
fail_silently=True, fail_silently=True,
) )
if queue.updated_ticket_cc and queue.updated_ticket_cc != queue.new_ticket_cc: if queue.updated_ticket_cc and queue.updated_ticket_cc != queue.new_ticket_cc:
send_templated_mail( send_templated_mail(
@ -367,7 +369,7 @@ def ticket_from_message(message, queue, quiet):
recipients=queue.updated_ticket_cc, recipients=queue.updated_ticket_cc,
sender=queue.from_address, sender=queue.from_address,
fail_silently=True, fail_silently=True,
) )
else: else:
context.update(comment=f.comment) context.update(comment=f.comment)
@ -384,7 +386,7 @@ def ticket_from_message(message, queue, quiet):
recipients=t.assigned_to.email, recipients=t.assigned_to.email,
sender=queue.from_address, sender=queue.from_address,
fail_silently=True, fail_silently=True,
) )
if queue.updated_ticket_cc: if queue.updated_ticket_cc:
send_templated_mail( send_templated_mail(
@ -393,11 +395,10 @@ def ticket_from_message(message, queue, quiet):
recipients=queue.updated_ticket_cc, recipients=queue.updated_ticket_cc,
sender=queue.from_address, sender=queue.from_address,
fail_silently=True, fail_silently=True,
) )
return t return t
if __name__ == '__main__': if __name__ == '__main__':
process_email() process_email()

View File

@ -36,7 +36,7 @@ class Queue(models.Model):
title = models.CharField( title = models.CharField(
_('Title'), _('Title'),
max_length=100, max_length=100,
) )
slug = models.SlugField( slug = models.SlugField(
_('Slug'), _('Slug'),
@ -44,7 +44,7 @@ class Queue(models.Model):
unique=True, unique=True,
help_text=_('This slug is used when building ticket ID\'s. Once set, ' help_text=_('This slug is used when building ticket ID\'s. Once set, '
'try not to change it or e-mailing may get messy.'), 'try not to change it or e-mailing may get messy.'),
) )
email_address = models.EmailField( email_address = models.EmailField(
_('E-Mail Address'), _('E-Mail Address'),
@ -53,7 +53,7 @@ class Queue(models.Model):
help_text=_('All outgoing e-mails for this queue will use this e-mail ' help_text=_('All outgoing e-mails for this queue will use this e-mail '
'address. If you use IMAP or POP3, this should be the e-mail ' 'address. If you use IMAP or POP3, this should be the e-mail '
'address for that mailbox.'), 'address for that mailbox.'),
) )
locale = models.CharField( locale = models.CharField(
_('Locale'), _('Locale'),
@ -62,14 +62,14 @@ class Queue(models.Model):
null=True, null=True,
help_text=_('Locale of this queue. All correspondence in this ' help_text=_('Locale of this queue. All correspondence in this '
'queue will be in this language.'), 'queue will be in this language.'),
) )
allow_public_submission = models.BooleanField( allow_public_submission = models.BooleanField(
_('Allow Public Submission?'), _('Allow Public Submission?'),
blank=True, blank=True,
default=False, default=False,
help_text=_('Should this queue be listed on the public submission form?'), help_text=_('Should this queue be listed on the public submission form?'),
) )
allow_email_submission = models.BooleanField( allow_email_submission = models.BooleanField(
_('Allow E-Mail Submission?'), _('Allow E-Mail Submission?'),
@ -77,7 +77,7 @@ class Queue(models.Model):
default=False, default=False,
help_text=_('Do you want to poll the e-mail box below for new ' help_text=_('Do you want to poll the e-mail box below for new '
'tickets?'), 'tickets?'),
) )
escalate_days = models.IntegerField( escalate_days = models.IntegerField(
_('Escalation Days'), _('Escalation Days'),
@ -85,7 +85,7 @@ class Queue(models.Model):
null=True, null=True,
help_text=_('For tickets which are not held, how often do you wish to ' help_text=_('For tickets which are not held, how often do you wish to '
'increase their priority? Set to 0 for no escalation.'), 'increase their priority? Set to 0 for no escalation.'),
) )
new_ticket_cc = models.CharField( new_ticket_cc = models.CharField(
_('New Ticket CC Address'), _('New Ticket CC Address'),
@ -95,7 +95,7 @@ class Queue(models.Model):
help_text=_('If an e-mail address is entered here, then it will ' help_text=_('If an e-mail address is entered here, then it will '
'receive notification of all new tickets created for this queue. ' 'receive notification of all new tickets created for this queue. '
'Enter a comma between multiple e-mail addresses.'), 'Enter a comma between multiple e-mail addresses.'),
) )
updated_ticket_cc = models.CharField( updated_ticket_cc = models.CharField(
_('Updated Ticket CC Address'), _('Updated Ticket CC Address'),
@ -106,7 +106,7 @@ class Queue(models.Model):
'receive notification of all activity (new tickets, closed ' 'receive notification of all activity (new tickets, closed '
'tickets, updates, reassignments, etc) for this queue. Separate ' 'tickets, updates, reassignments, etc) for this queue. Separate '
'multiple addresses with a comma.'), 'multiple addresses with a comma.'),
) )
email_box_type = models.CharField( email_box_type = models.CharField(
_('E-Mail Box Type'), _('E-Mail Box Type'),
@ -116,7 +116,7 @@ class Queue(models.Model):
null=True, null=True,
help_text=_('E-Mail server type for creating tickets automatically ' help_text=_('E-Mail server type for creating tickets automatically '
'from a mailbox - both POP3 and IMAP are supported.'), 'from a mailbox - both POP3 and IMAP are supported.'),
) )
email_box_host = models.CharField( email_box_host = models.CharField(
_('E-Mail Hostname'), _('E-Mail Hostname'),
@ -125,7 +125,7 @@ class Queue(models.Model):
null=True, null=True,
help_text=_('Your e-mail server address - either the domain name or ' help_text=_('Your e-mail server address - either the domain name or '
'IP address. May be "localhost".'), 'IP address. May be "localhost".'),
) )
email_box_port = models.IntegerField( email_box_port = models.IntegerField(
_('E-Mail Port'), _('E-Mail Port'),
@ -134,7 +134,7 @@ class Queue(models.Model):
help_text=_('Port number to use for accessing e-mail. Default for ' help_text=_('Port number to use for accessing e-mail. Default for '
'POP3 is "110", and for IMAP is "143". This may differ on some ' 'POP3 is "110", and for IMAP is "143". This may differ on some '
'servers. Leave it blank to use the defaults.'), 'servers. Leave it blank to use the defaults.'),
) )
email_box_ssl = models.BooleanField( email_box_ssl = models.BooleanField(
_('Use SSL for E-Mail?'), _('Use SSL for E-Mail?'),
@ -142,7 +142,7 @@ class Queue(models.Model):
default=False, default=False,
help_text=_('Whether to use SSL for IMAP or POP3 - the default ports ' help_text=_('Whether to use SSL for IMAP or POP3 - the default ports '
'when using SSL are 993 for IMAP and 995 for POP3.'), 'when using SSL are 993 for IMAP and 995 for POP3.'),
) )
email_box_user = models.CharField( email_box_user = models.CharField(
_('E-Mail Username'), _('E-Mail Username'),
@ -150,7 +150,7 @@ class Queue(models.Model):
blank=True, blank=True,
null=True, null=True,
help_text=_('Username for accessing this mailbox.'), help_text=_('Username for accessing this mailbox.'),
) )
email_box_pass = models.CharField( email_box_pass = models.CharField(
_('E-Mail Password'), _('E-Mail Password'),
@ -158,7 +158,7 @@ class Queue(models.Model):
blank=True, blank=True,
null=True, null=True,
help_text=_('Password for the above username'), help_text=_('Password for the above username'),
) )
email_box_imap_folder = models.CharField( email_box_imap_folder = models.CharField(
_('IMAP Folder'), _('IMAP Folder'),
@ -169,7 +169,7 @@ class Queue(models.Model):
'from? This allows you to use one IMAP account for multiple ' 'from? This allows you to use one IMAP account for multiple '
'queues, by filtering messages on your IMAP server into separate ' 'queues, by filtering messages on your IMAP server into separate '
'folders. Default: INBOX.'), 'folders. Default: INBOX.'),
) )
permission_name = models.CharField( permission_name = models.CharField(
_('Django auth permission name'), _('Django auth permission name'),
@ -178,8 +178,7 @@ class Queue(models.Model):
null=True, null=True,
editable=False, editable=False,
help_text=_('Name used in the django.contrib.auth permission system'), help_text=_('Name used in the django.contrib.auth permission system'),
) )
email_box_interval = models.IntegerField( email_box_interval = models.IntegerField(
_('E-Mail Check Interval'), _('E-Mail Check Interval'),
@ -187,14 +186,14 @@ class Queue(models.Model):
blank=True, blank=True,
null=True, null=True,
default='5', default='5',
) )
email_box_last_check = models.DateTimeField( email_box_last_check = models.DateTimeField(
blank=True, blank=True,
null=True, null=True,
editable=False, editable=False,
# This is updated by management/commands/get_mail.py. # This is updated by management/commands/get_mail.py.
) )
socks_proxy_type = models.CharField( socks_proxy_type = models.CharField(
_('Socks Proxy Type'), _('Socks Proxy Type'),
@ -347,24 +346,24 @@ class Ticket(models.Model):
title = models.CharField( title = models.CharField(
_('Title'), _('Title'),
max_length=200, max_length=200,
) )
queue = models.ForeignKey( queue = models.ForeignKey(
Queue, Queue,
verbose_name=_('Queue'), verbose_name=_('Queue'),
) )
created = models.DateTimeField( created = models.DateTimeField(
_('Created'), _('Created'),
blank=True, blank=True,
help_text=_('Date this ticket was first created'), help_text=_('Date this ticket was first created'),
) )
modified = models.DateTimeField( modified = models.DateTimeField(
_('Modified'), _('Modified'),
blank=True, blank=True,
help_text=_('Date this ticket was most recently changed.'), help_text=_('Date this ticket was most recently changed.'),
) )
submitter_email = models.EmailField( submitter_email = models.EmailField(
_('Submitter E-Mail'), _('Submitter E-Mail'),
@ -372,7 +371,7 @@ class Ticket(models.Model):
null=True, null=True,
help_text=_('The submitter will receive an email for all public ' help_text=_('The submitter will receive an email for all public '
'follow-ups left for this task.'), 'follow-ups left for this task.'),
) )
assigned_to = models.ForeignKey( assigned_to = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
@ -380,34 +379,34 @@ class Ticket(models.Model):
blank=True, blank=True,
null=True, null=True,
verbose_name=_('Assigned to'), verbose_name=_('Assigned to'),
) )
status = models.IntegerField( status = models.IntegerField(
_('Status'), _('Status'),
choices=STATUS_CHOICES, choices=STATUS_CHOICES,
default=OPEN_STATUS, default=OPEN_STATUS,
) )
on_hold = models.BooleanField( on_hold = models.BooleanField(
_('On Hold'), _('On Hold'),
blank=True, blank=True,
default=False, default=False,
help_text=_('If a ticket is on hold, it will not automatically be escalated.'), help_text=_('If a ticket is on hold, it will not automatically be escalated.'),
) )
description = models.TextField( description = models.TextField(
_('Description'), _('Description'),
blank=True, blank=True,
null=True, null=True,
help_text=_('The content of the customers query.'), help_text=_('The content of the customers query.'),
) )
resolution = models.TextField( resolution = models.TextField(
_('Resolution'), _('Resolution'),
blank=True, blank=True,
null=True, null=True,
help_text=_('The resolution provided to the customer by our staff.'), help_text=_('The resolution provided to the customer by our staff.'),
) )
priority = models.IntegerField( priority = models.IntegerField(
_('Priority'), _('Priority'),
@ -415,13 +414,13 @@ class Ticket(models.Model):
default=3, default=3,
blank=3, blank=3,
help_text=_('1 = Highest Priority, 5 = Low Priority'), help_text=_('1 = Highest Priority, 5 = Low Priority'),
) )
due_date = models.DateTimeField( due_date = models.DateTimeField(
_('Due on'), _('Due on'),
blank=True, blank=True,
null=True, null=True,
) )
last_escalation = models.DateTimeField( last_escalation = models.DateTimeField(
blank=True, blank=True,
@ -429,7 +428,7 @@ class Ticket(models.Model):
editable=False, editable=False,
help_text=_('The date this ticket was last escalated - updated ' help_text=_('The date this ticket was last escalated - updated '
'automatically by management/commands/escalate_tickets.py.'), 'automatically by management/commands/escalate_tickets.py.'),
) )
def _get_assigned_to(self): def _get_assigned_to(self):
""" Custom property to allow us to easily print 'Unassigned' if a """ Custom property to allow us to easily print 'Unassigned' if a
@ -479,7 +478,8 @@ class Ticket(models.Model):
Displays the ticket status, with an "On Hold" message if needed. Displays the ticket status, with an "On Hold" message if needed.
""" """
held_msg = '' held_msg = ''
if self.on_hold: held_msg = _(' - On Hold') if self.on_hold:
held_msg = _(' - On Hold')
dep_msg = '' dep_msg = ''
if not self.can_be_resolved: if not self.can_be_resolved:
dep_msg = _(' - Open dependencies') dep_msg = _(' - Open dependencies')
@ -502,7 +502,7 @@ class Ticket(models.Model):
reverse('helpdesk_public_view'), reverse('helpdesk_public_view'),
self.ticket_for_url, self.ticket_for_url,
self.submitter_email self.submitter_email
) )
ticket_url = property(_get_ticket_url) ticket_url = property(_get_ticket_url)
def _get_staff_url(self): def _get_staff_url(self):
@ -519,8 +519,8 @@ class Ticket(models.Model):
return u"http://%s%s" % ( return u"http://%s%s" % (
site.domain, site.domain,
reverse('helpdesk_view', reverse('helpdesk_view',
args=[self.id]) args=[self.id])
) )
staff_url = property(_get_staff_url) staff_url = property(_get_staff_url)
def _can_be_resolved(self): def _can_be_resolved(self):
@ -569,6 +569,7 @@ class Ticket(models.Model):
class FollowUpManager(models.Manager): class FollowUpManager(models.Manager):
def private_followups(self): def private_followups(self):
return self.filter(public=False) return self.filter(public=False)
@ -593,25 +594,25 @@ class FollowUp(models.Model):
ticket = models.ForeignKey( ticket = models.ForeignKey(
Ticket, Ticket,
verbose_name=_('Ticket'), verbose_name=_('Ticket'),
) )
date = models.DateTimeField( date = models.DateTimeField(
_('Date'), _('Date'),
default = timezone.now default=timezone.now
) )
title = models.CharField( title = models.CharField(
_('Title'), _('Title'),
max_length=200, max_length=200,
blank=True, blank=True,
null=True, null=True,
) )
comment = models.TextField( comment = models.TextField(
_('Comment'), _('Comment'),
blank=True, blank=True,
null=True, null=True,
) )
public = models.BooleanField( public = models.BooleanField(
_('Public'), _('Public'),
@ -619,14 +620,14 @@ class FollowUp(models.Model):
default=False, default=False,
help_text=_('Public tickets are viewable by the submitter and all ' help_text=_('Public tickets are viewable by the submitter and all '
'staff, but non-public tickets can only be seen by staff.'), 'staff, but non-public tickets can only be seen by staff.'),
) )
user = models.ForeignKey( user = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
blank=True, blank=True,
null=True, null=True,
verbose_name=_('User'), verbose_name=_('User'),
) )
new_status = models.IntegerField( new_status = models.IntegerField(
_('New Status'), _('New Status'),
@ -634,12 +635,12 @@ class FollowUp(models.Model):
blank=True, blank=True,
null=True, null=True,
help_text=_('If the status was changed, what was it changed to?'), help_text=_('If the status was changed, what was it changed to?'),
) )
objects = FollowUpManager() objects = FollowUpManager()
class Meta: class Meta:
ordering = ['date'] ordering = ('date',)
verbose_name = _('Follow-up') verbose_name = _('Follow-up')
verbose_name_plural = _('Follow-ups') verbose_name_plural = _('Follow-ups')
@ -666,24 +667,24 @@ class TicketChange(models.Model):
followup = models.ForeignKey( followup = models.ForeignKey(
FollowUp, FollowUp,
verbose_name=_('Follow-up'), verbose_name=_('Follow-up'),
) )
field = models.CharField( field = models.CharField(
_('Field'), _('Field'),
max_length=100, max_length=100,
) )
old_value = models.TextField( old_value = models.TextField(
_('Old Value'), _('Old Value'),
blank=True, blank=True,
null=True, null=True,
) )
new_value = models.TextField( new_value = models.TextField(
_('New Value'), _('New Value'),
blank=True, blank=True,
null=True, null=True,
) )
def __str__(self): def __str__(self):
out = '%s ' % self.field out = '%s ' % self.field
@ -695,7 +696,7 @@ class TicketChange(models.Model):
out += ugettext('changed from "%(old_value)s" to "%(new_value)s"') % { out += ugettext('changed from "%(old_value)s" to "%(new_value)s"') % {
'old_value': self.old_value, 'old_value': self.old_value,
'new_value': self.new_value 'new_value': self.new_value
} }
return out return out
class Meta: class Meta:
@ -711,7 +712,7 @@ def attachment_path(instance, filename):
import os import os
from django.conf import settings from django.conf import settings
os.umask(0) os.umask(0)
path = 'helpdesk/attachments/%s/%s' % (instance.followup.ticket.ticket_for_url, instance.followup.id ) path = 'helpdesk/attachments/%s/%s' % (instance.followup.ticket.ticket_for_url, instance.followup.id)
att_path = os.path.join(settings.MEDIA_ROOT, path) att_path = os.path.join(settings.MEDIA_ROOT, path)
if settings.DEFAULT_FILE_STORAGE == "django.core.files.storage.FileSystemStorage": if settings.DEFAULT_FILE_STORAGE == "django.core.files.storage.FileSystemStorage":
if not os.path.exists(att_path): if not os.path.exists(att_path):
@ -729,28 +730,28 @@ class Attachment(models.Model):
followup = models.ForeignKey( followup = models.ForeignKey(
FollowUp, FollowUp,
verbose_name=_('Follow-up'), verbose_name=_('Follow-up'),
) )
file = models.FileField( file = models.FileField(
_('File'), _('File'),
upload_to=attachment_path, upload_to=attachment_path,
max_length=1000, max_length=1000,
) )
filename = models.CharField( filename = models.CharField(
_('Filename'), _('Filename'),
max_length=1000, max_length=1000,
) )
mime_type = models.CharField( mime_type = models.CharField(
_('MIME Type'), _('MIME Type'),
max_length=255, max_length=255,
) )
size = models.IntegerField( size = models.IntegerField(
_('Size'), _('Size'),
help_text=_('Size of this file in bytes'), help_text=_('Size of this file in bytes'),
) )
def get_upload_to(self, field_attname): def get_upload_to(self, field_attname):
""" Get upload_to path specific to this item """ """ Get upload_to path specific to this item """
@ -759,13 +760,13 @@ class Attachment(models.Model):
return u'helpdesk/attachments/%s/%s' % ( return u'helpdesk/attachments/%s/%s' % (
self.followup.ticket.ticket_for_url, self.followup.ticket.ticket_for_url,
self.followup.id self.followup.id
) )
def __str__(self): def __str__(self):
return '%s' % self.filename return '%s' % self.filename
class Meta: class Meta:
ordering = ['filename',] ordering = ('filename',)
verbose_name = _('Attachment') verbose_name = _('Attachment')
verbose_name_plural = _('Attachments') verbose_name_plural = _('Attachments')
@ -783,7 +784,7 @@ class PreSetReply(models.Model):
queue, and the body text is fetched via AJAX. queue, and the body text is fetched via AJAX.
""" """
class Meta: class Meta:
ordering = ['name', ] ordering = ('name',)
verbose_name = _('Pre-set reply') verbose_name = _('Pre-set reply')
verbose_name_plural = _('Pre-set replies') verbose_name_plural = _('Pre-set replies')
@ -792,21 +793,21 @@ class PreSetReply(models.Model):
blank=True, blank=True,
help_text=_('Leave blank to allow this reply to be used for all ' help_text=_('Leave blank to allow this reply to be used for all '
'queues, or select those queues you wish to limit this reply to.'), 'queues, or select those queues you wish to limit this reply to.'),
) )
name = models.CharField( name = models.CharField(
_('Name'), _('Name'),
max_length=100, max_length=100,
help_text=_('Only used to assist users with selecting a reply - not ' help_text=_('Only used to assist users with selecting a reply - not '
'shown to the user.'), 'shown to the user.'),
) )
body = models.TextField( body = models.TextField(
_('Body'), _('Body'),
help_text=_('Context available: {{ ticket }} - ticket object (eg ' help_text=_('Context available: {{ ticket }} - ticket object (eg '
'{{ ticket.title }}); {{ queue }} - The queue; and {{ user }} ' '{{ ticket.title }}); {{ queue }} - The queue; and {{ user }} '
'- the current user.'), '- the current user.'),
) )
def __str__(self): def __str__(self):
return '%s' % self.name return '%s' % self.name
@ -829,17 +830,17 @@ class EscalationExclusion(models.Model):
blank=True, blank=True,
help_text=_('Leave blank for this exclusion to be applied to all queues, ' help_text=_('Leave blank for this exclusion to be applied to all queues, '
'or select those queues you wish to exclude with this entry.'), 'or select those queues you wish to exclude with this entry.'),
) )
name = models.CharField( name = models.CharField(
_('Name'), _('Name'),
max_length=100, max_length=100,
) )
date = models.DateField( date = models.DateField(
_('Date'), _('Date'),
help_text=_('Date on which escalation should not happen'), help_text=_('Date on which escalation should not happen'),
) )
def __str__(self): def __str__(self):
return '%s' % self.name return '%s' % self.name
@ -862,7 +863,7 @@ class EmailTemplate(models.Model):
template_name = models.CharField( template_name = models.CharField(
_('Template Name'), _('Template Name'),
max_length=100, max_length=100,
) )
subject = models.CharField( subject = models.CharField(
_('Subject'), _('Subject'),
@ -870,7 +871,7 @@ class EmailTemplate(models.Model):
help_text=_('This will be prefixed with "[ticket.ticket] ticket.title"' help_text=_('This will be prefixed with "[ticket.ticket] ticket.title"'
'. We recommend something simple such as "(Updated") or "(Closed)"' '. We recommend something simple such as "(Updated") or "(Closed)"'
' - the same context is available as in plain_text, below.'), ' - the same context is available as in plain_text, below.'),
) )
heading = models.CharField( heading = models.CharField(
_('Heading'), _('Heading'),
@ -878,19 +879,19 @@ class EmailTemplate(models.Model):
help_text=_('In HTML e-mails, this will be the heading at the top of ' help_text=_('In HTML e-mails, this will be the heading at the top of '
'the email - the same context is available as in plain_text, ' 'the email - the same context is available as in plain_text, '
'below.'), 'below.'),
) )
plain_text = models.TextField( plain_text = models.TextField(
_('Plain Text'), _('Plain Text'),
help_text=_('The context available to you includes {{ ticket }}, ' help_text=_('The context available to you includes {{ ticket }}, '
'{{ queue }}, and depending on the time of the call: ' '{{ queue }}, and depending on the time of the call: '
'{{ resolution }} or {{ comment }}.'), '{{ resolution }} or {{ comment }}.'),
) )
html = models.TextField( html = models.TextField(
_('HTML'), _('HTML'),
help_text=_('The same context is available here as in plain_text, above.'), help_text=_('The same context is available here as in plain_text, above.'),
) )
locale = models.CharField( locale = models.CharField(
_('Locale'), _('Locale'),
@ -898,13 +899,13 @@ class EmailTemplate(models.Model):
blank=True, blank=True,
null=True, null=True,
help_text=_('Locale of this template.'), help_text=_('Locale of this template.'),
) )
def __str__(self): def __str__(self):
return '%s' % self.template_name return '%s' % self.template_name
class Meta: class Meta:
ordering = ['template_name', 'locale'] ordering = ('template_name', 'locale')
verbose_name = _('e-mail template') verbose_name = _('e-mail template')
verbose_name_plural = _('e-mail templates') verbose_name_plural = _('e-mail templates')
@ -919,21 +920,21 @@ class KBCategory(models.Model):
title = models.CharField( title = models.CharField(
_('Title'), _('Title'),
max_length=100, max_length=100,
) )
slug = models.SlugField( slug = models.SlugField(
_('Slug'), _('Slug'),
) )
description = models.TextField( description = models.TextField(
_('Description'), _('Description'),
) )
def __str__(self): def __str__(self):
return '%s' % self.title return '%s' % self.title
class Meta: class Meta:
ordering = ['title',] ordering = ('title',)
verbose_name = _('Knowledge base category') verbose_name = _('Knowledge base category')
verbose_name_plural = _('Knowledge base categories') verbose_name_plural = _('Knowledge base categories')
@ -951,38 +952,38 @@ class KBItem(models.Model):
category = models.ForeignKey( category = models.ForeignKey(
KBCategory, KBCategory,
verbose_name=_('Category'), verbose_name=_('Category'),
) )
title = models.CharField( title = models.CharField(
_('Title'), _('Title'),
max_length=100, max_length=100,
) )
question = models.TextField( question = models.TextField(
_('Question'), _('Question'),
) )
answer = models.TextField( answer = models.TextField(
_('Answer'), _('Answer'),
) )
votes = models.IntegerField( votes = models.IntegerField(
_('Votes'), _('Votes'),
help_text=_('Total number of votes cast for this item'), help_text=_('Total number of votes cast for this item'),
default=0, default=0,
) )
recommendations = models.IntegerField( recommendations = models.IntegerField(
_('Positive Votes'), _('Positive Votes'),
help_text=_('Number of votes for this item which were POSITIVE.'), help_text=_('Number of votes for this item which were POSITIVE.'),
default=0, default=0,
) )
last_updated = models.DateTimeField( last_updated = models.DateTimeField(
_('Last Updated'), _('Last Updated'),
help_text=_('The date on which this question was most recently changed.'), help_text=_('The date on which this question was most recently changed.'),
blank=True, blank=True,
) )
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.last_updated: if not self.last_updated:
@ -1000,7 +1001,7 @@ class KBItem(models.Model):
return '%s' % self.title return '%s' % self.title
class Meta: class Meta:
ordering = ['title',] ordering = ('title',)
verbose_name = _('Knowledge base item') verbose_name = _('Knowledge base item')
verbose_name_plural = _('Knowledge base items') verbose_name_plural = _('Knowledge base items')
@ -1024,25 +1025,25 @@ class SavedSearch(models.Model):
user = models.ForeignKey( user = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
verbose_name=_('User'), verbose_name=_('User'),
) )
title = models.CharField( title = models.CharField(
_('Query Name'), _('Query Name'),
max_length=100, max_length=100,
help_text=_('User-provided name for this query'), help_text=_('User-provided name for this query'),
) )
shared = models.BooleanField( shared = models.BooleanField(
_('Shared With Other Users?'), _('Shared With Other Users?'),
blank=True, blank=True,
default=False, default=False,
help_text=_('Should other users see this query?'), help_text=_('Should other users see this query?'),
) )
query = models.TextField( query = models.TextField(
_('Search Query'), _('Search Query'),
help_text=_('Pickled query object. Be wary changing this.'), help_text=_('Pickled query object. Be wary changing this.'),
) )
def __str__(self): def __str__(self):
if self.shared: if self.shared:
@ -1073,7 +1074,7 @@ class UserSettings(models.Model):
'Do not change this field via the admin.'), 'Do not change this field via the admin.'),
blank=True, blank=True,
null=True, null=True,
) )
def _set_settings(self, data): def _set_settings(self, data):
# data should always be a Python dictionary. # data should always be a Python dictionary.
@ -1138,26 +1139,26 @@ class IgnoreEmail(models.Model):
blank=True, blank=True,
help_text=_('Leave blank for this e-mail to be ignored on all queues, ' help_text=_('Leave blank for this e-mail to be ignored on all queues, '
'or select those queues you wish to ignore this e-mail for.'), 'or select those queues you wish to ignore this e-mail for.'),
) )
name = models.CharField( name = models.CharField(
_('Name'), _('Name'),
max_length=100, max_length=100,
) )
date = models.DateField( date = models.DateField(
_('Date'), _('Date'),
help_text=_('Date on which this e-mail address was added'), help_text=_('Date on which this e-mail address was added'),
blank=True, blank=True,
editable=False editable=False
) )
email_address = models.CharField( email_address = models.CharField(
_('E-Mail Address'), _('E-Mail Address'),
max_length=150, max_length=150,
help_text=_('Enter a full e-mail address, or portions with ' help_text=_('Enter a full e-mail address, or portions with '
'wildcards, eg *@domain.com or postmaster@*.'), 'wildcards, eg *@domain.com or postmaster@*.'),
) )
keep_in_mailbox = models.BooleanField( keep_in_mailbox = models.BooleanField(
_('Save Emails in Mailbox?'), _('Save Emails in Mailbox?'),
@ -1165,7 +1166,7 @@ class IgnoreEmail(models.Model):
default=False, default=False,
help_text=_('Do you want to save emails from this address in the mailbox? ' help_text=_('Do you want to save emails from this address in the mailbox? '
'If this is unticked, emails from this address will be deleted.'), 'If this is unticked, emails from this address will be deleted.'),
) )
def __str__(self): def __str__(self):
return '%s' % self.name return '%s' % self.name
@ -1213,7 +1214,7 @@ class TicketCC(models.Model):
ticket = models.ForeignKey( ticket = models.ForeignKey(
Ticket, Ticket,
verbose_name=_('Ticket'), verbose_name=_('Ticket'),
) )
user = models.ForeignKey( user = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
@ -1221,28 +1222,28 @@ class TicketCC(models.Model):
null=True, null=True,
help_text=_('User who wishes to receive updates for this ticket.'), help_text=_('User who wishes to receive updates for this ticket.'),
verbose_name=_('User'), verbose_name=_('User'),
) )
email = models.EmailField( email = models.EmailField(
_('E-Mail Address'), _('E-Mail Address'),
blank=True, blank=True,
null=True, null=True,
help_text=_('For non-user followers, enter their e-mail address'), help_text=_('For non-user followers, enter their e-mail address'),
) )
can_view = models.BooleanField( can_view = models.BooleanField(
_('Can View Ticket?'), _('Can View Ticket?'),
blank=True, blank=True,
default=False, default=False,
help_text=_('Can this CC login to view the ticket details?'), help_text=_('Can this CC login to view the ticket details?'),
) )
can_update = models.BooleanField( can_update = models.BooleanField(
_('Can Update Ticket?'), _('Can Update Ticket?'),
blank=True, blank=True,
default=False, default=False,
help_text=_('Can this CC login and update the ticket?'), help_text=_('Can this CC login and update the ticket?'),
) )
def _email_address(self): def _email_address(self):
if self.user and self.user.email is not None: if self.user and self.user.email is not None:
@ -1263,6 +1264,7 @@ class TicketCC(models.Model):
class CustomFieldManager(models.Manager): class CustomFieldManager(models.Manager):
def get_queryset(self): def get_queryset(self):
return super(CustomFieldManager, self).get_queryset().order_by('ordering') return super(CustomFieldManager, self).get_queryset().order_by('ordering')
@ -1278,77 +1280,77 @@ class CustomField(models.Model):
help_text=_('As used in the database and behind the scenes. ' help_text=_('As used in the database and behind the scenes. '
'Must be unique and consist of only lowercase letters with no punctuation.'), 'Must be unique and consist of only lowercase letters with no punctuation.'),
unique=True, unique=True,
) )
label = models.CharField( label = models.CharField(
_('Label'), _('Label'),
max_length=30, max_length=30,
help_text=_('The display label for this field'), help_text=_('The display label for this field'),
) )
help_text = models.TextField( help_text = models.TextField(
_('Help Text'), _('Help Text'),
help_text=_('Shown to the user when editing the ticket'), help_text=_('Shown to the user when editing the ticket'),
blank=True, blank=True,
null=True null=True
) )
DATA_TYPE_CHOICES = ( DATA_TYPE_CHOICES = (
('varchar', _('Character (single line)')), ('varchar', _('Character (single line)')),
('text', _('Text (multi-line)')), ('text', _('Text (multi-line)')),
('integer', _('Integer')), ('integer', _('Integer')),
('decimal', _('Decimal')), ('decimal', _('Decimal')),
('list', _('List')), ('list', _('List')),
('boolean', _('Boolean (checkbox yes/no)')), ('boolean', _('Boolean (checkbox yes/no)')),
('date', _('Date')), ('date', _('Date')),
('time', _('Time')), ('time', _('Time')),
('datetime', _('Date & Time')), ('datetime', _('Date & Time')),
('email', _('E-Mail Address')), ('email', _('E-Mail Address')),
('url', _('URL')), ('url', _('URL')),
('ipaddress', _('IP Address')), ('ipaddress', _('IP Address')),
('slug', _('Slug')), ('slug', _('Slug')),
) )
data_type = models.CharField( data_type = models.CharField(
_('Data Type'), _('Data Type'),
max_length=100, max_length=100,
help_text=_('Allows you to restrict the data entered into this field'), help_text=_('Allows you to restrict the data entered into this field'),
choices=DATA_TYPE_CHOICES, choices=DATA_TYPE_CHOICES,
) )
max_length = models.IntegerField( max_length = models.IntegerField(
_('Maximum Length (characters)'), _('Maximum Length (characters)'),
blank=True, blank=True,
null=True, null=True,
) )
decimal_places = models.IntegerField( decimal_places = models.IntegerField(
_('Decimal Places'), _('Decimal Places'),
help_text=_('Only used for decimal fields'), help_text=_('Only used for decimal fields'),
blank=True, blank=True,
null=True, null=True,
) )
empty_selection_list = models.BooleanField( empty_selection_list = models.BooleanField(
_('Add empty first choice to List?'), _('Add empty first choice to List?'),
default=False, default=False,
help_text=_('Only for List: adds an empty first entry to the choices list, ' help_text=_('Only for List: adds an empty first entry to the choices list, '
'which enforces that the user makes an active choice.'), 'which enforces that the user makes an active choice.'),
) )
list_values = models.TextField( list_values = models.TextField(
_('List Values'), _('List Values'),
help_text=_('For list fields only. Enter one option per line.'), help_text=_('For list fields only. Enter one option per line.'),
blank=True, blank=True,
null=True, null=True,
) )
ordering = models.IntegerField( ordering = models.IntegerField(
_('Ordering'), _('Ordering'),
help_text=_('Lower numbers are displayed first; higher numbers are listed later'), help_text=_('Lower numbers are displayed first; higher numbers are listed later'),
blank=True, blank=True,
null=True, null=True,
) )
def _choices_as_array(self): def _choices_as_array(self):
from StringIO import StringIO from StringIO import StringIO
@ -1362,14 +1364,14 @@ class CustomField(models.Model):
_('Required?'), _('Required?'),
help_text=_('Does the user have to enter a value for this field?'), help_text=_('Does the user have to enter a value for this field?'),
default=False, default=False,
) )
staff_only = models.BooleanField( staff_only = models.BooleanField(
_('Staff Only?'), _('Staff Only?'),
help_text=_('If this is ticked, then the public submission form ' help_text=_('If this is ticked, then the public submission form '
'will NOT show this field'), 'will NOT show this field'),
default=False, default=False,
) )
objects = CustomFieldManager() objects = CustomFieldManager()
@ -1386,12 +1388,12 @@ class TicketCustomFieldValue(models.Model):
ticket = models.ForeignKey( ticket = models.ForeignKey(
Ticket, Ticket,
verbose_name=_('Ticket'), verbose_name=_('Ticket'),
) )
field = models.ForeignKey( field = models.ForeignKey(
CustomField, CustomField,
verbose_name=_('Field'), verbose_name=_('Field'),
) )
value = models.TextField(blank=True, null=True) value = models.TextField(blank=True, null=True)
@ -1420,13 +1422,13 @@ class TicketDependency(models.Model):
Ticket, Ticket,
verbose_name=_('Ticket'), verbose_name=_('Ticket'),
related_name='ticketdependency', related_name='ticketdependency',
) )
depends_on = models.ForeignKey( depends_on = models.ForeignKey(
Ticket, Ticket,
verbose_name=_('Depends On Ticket'), verbose_name=_('Depends On Ticket'),
related_name='depends_on', related_name='depends_on',
) )
def __str__(self): def __str__(self):
return '%s / %s' % (self.ticket, self.depends_on) return '%s / %s' % (self.ticket, self.depends_on)

View File

@ -1,7 +1,7 @@
""" """
django-helpdesk - A Django powered ticket tracker for small enterprise. django-helpdesk - A Django powered ticket tracker for small enterprise.
templatetags/load_helpdesk_settings.py - returns the settings as defined in templatetags/load_helpdesk_settings.py - returns the settings as defined in
django-helpdesk/helpdesk/settings.py django-helpdesk/helpdesk/settings.py
""" """
from __future__ import print_function from __future__ import print_function

View File

@ -1,7 +1,7 @@
""" """
django-helpdesk - A Django powered ticket tracker for small enterprise. django-helpdesk - A Django powered ticket tracker for small enterprise.
templatetags/saved_queries.py - This template tag returns previously saved templatetags/saved_queries.py - This template tag returns previously saved
queries. Therefore you don't need to modify queries. Therefore you don't need to modify
any views. any views.
""" """
@ -17,8 +17,8 @@ def saved_queries(user):
return user_saved_queries return user_saved_queries
except Exception as e: except Exception as e:
import sys import sys
print >> sys.stderr, "'saved_queries' template tag (django-helpdesk) crashed with following error:" print >> sys.stderr, "'saved_queries' template tag (django-helpdesk) crashed with following error:"
print >> sys.stderr, e print >> sys.stderr, e
return '' return ''
register = Library() register = Library()