This commit is contained in:
Ross Poulton 2015-04-28 09:13:54 +10:00
parent ffb6243af0
commit 70c57f9096
10 changed files with 198 additions and 171 deletions

View File

@ -6,8 +6,10 @@ django-helpdesk - A Django powered ticket tracker for small enterprise.
forms.py - Definitions of newforms-based forms for creating and maintaining forms.py - Definitions of newforms-based forms for creating and maintaining
tickets. tickets.
""" """
try:
from StringIO import StringIO from StringIO import StringIO
except ImportError:
from io import StringIO
from django import forms from django import forms
from django.forms import extras from django.forms import extras

View File

@ -17,232 +17,235 @@ class Migration(migrations.Migration):
migrations.CreateModel( migrations.CreateModel(
name='Attachment', name='Attachment',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('file', models.FileField(upload_to=helpdesk.models.attachment_path, max_length=1000, verbose_name='File')), ('file', models.FileField(upload_to=helpdesk.models.attachment_path, verbose_name='File', max_length=1000)),
('filename', models.CharField(max_length=1000, verbose_name='Filename')), ('filename', models.CharField(verbose_name='Filename', max_length=1000)),
('mime_type', models.CharField(max_length=255, verbose_name='MIME Type')), ('mime_type', models.CharField(verbose_name='MIME Type', max_length=255)),
('size', models.IntegerField(help_text='Size of this file in bytes', verbose_name='Size')), ('size', models.IntegerField(verbose_name='Size', help_text='Size of this file in bytes')),
], ],
options={ options={
'ordering': ['filename'],
'verbose_name': 'Attachment',
'verbose_name_plural': 'Attachments', 'verbose_name_plural': 'Attachments',
'verbose_name': 'Attachment',
'ordering': ['filename'],
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='CustomField', name='CustomField',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('name', models.SlugField(help_text='As used in the database and behind the scenes. Must be unique and consist of only lowercase letters with no punctuation.', unique=True, verbose_name='Field Name')), ('name', models.SlugField(help_text='As used in the database and behind the scenes. Must be unique and consist of only lowercase letters with no punctuation.', verbose_name='Field Name', unique=True)),
('label', models.CharField(help_text='The display label for this field', max_length=b'30', verbose_name='Label')), ('label', models.CharField(verbose_name='Label', help_text='The display label for this field', max_length='30')),
('help_text', models.TextField(help_text='Shown to the user when editing the ticket', null=True, verbose_name='Help Text', blank=True)), ('help_text', models.TextField(null=True, verbose_name='Help Text', blank=True, help_text='Shown to the user when editing the ticket')),
('data_type', models.CharField(help_text='Allows you to restrict the data entered into this field', max_length=100, verbose_name='Data Type', choices=[(b'varchar', 'Character (single line)'), (b'text', 'Text (multi-line)'), (b'integer', 'Integer'), (b'decimal', 'Decimal'), (b'list', 'List'), (b'boolean', 'Boolean (checkbox yes/no)'), (b'date', 'Date'), (b'time', 'Time'), (b'datetime', 'Date & Time'), (b'email', 'E-Mail Address'), (b'url', 'URL'), (b'ipaddress', 'IP Address'), (b'slug', 'Slug')])), ('data_type', models.CharField(choices=[('varchar', 'Character (single line)'), ('text', 'Text (multi-line)'), ('integer', 'Integer'), ('decimal', 'Decimal'), ('list', 'List'), ('boolean', 'Boolean (checkbox yes/no)'), ('date', 'Date'), ('time', 'Time'), ('datetime', 'Date & Time'), ('email', 'E-Mail Address'), ('url', 'URL'), ('ipaddress', 'IP Address'), ('slug', 'Slug')], verbose_name='Data Type', help_text='Allows you to restrict the data entered into this field', max_length=100)),
('max_length', models.IntegerField(null=True, verbose_name='Maximum Length (characters)', blank=True)), ('max_length', models.IntegerField(null=True, verbose_name='Maximum Length (characters)', blank=True)),
('decimal_places', models.IntegerField(help_text='Only used for decimal fields', null=True, verbose_name='Decimal Places', blank=True)), ('decimal_places', models.IntegerField(null=True, verbose_name='Decimal Places', blank=True, help_text='Only used for decimal fields')),
('empty_selection_list', models.BooleanField(default=False, help_text='Only for List: adds an empty first entry to the choices list, which enforces that the user makes an active choice.', verbose_name='Add empty first choice to List?')), ('empty_selection_list', models.BooleanField(verbose_name='Add empty first choice to List?', default=False, help_text='Only for List: adds an empty first entry to the choices list, which enforces that the user makes an active choice.')),
('list_values', models.TextField(help_text='For list fields only. Enter one option per line.', null=True, verbose_name='List Values', blank=True)), ('list_values', models.TextField(null=True, verbose_name='List Values', blank=True, help_text='For list fields only. Enter one option per line.')),
('ordering', models.IntegerField(help_text='Lower numbers are displayed first; higher numbers are listed later', null=True, verbose_name='Ordering', blank=True)), ('ordering', models.IntegerField(null=True, verbose_name='Ordering', blank=True, help_text='Lower numbers are displayed first; higher numbers are listed later')),
('required', models.BooleanField(default=False, help_text='Does the user have to enter a value for this field?', verbose_name='Required?')), ('required', models.BooleanField(verbose_name='Required?', default=False, help_text='Does the user have to enter a value for this field?')),
('staff_only', models.BooleanField(default=False, help_text='If this is ticked, then the public submission form will NOT show this field', verbose_name='Staff Only?')), ('staff_only', models.BooleanField(verbose_name='Staff Only?', default=False, help_text='If this is ticked, then the public submission form will NOT show this field')),
], ],
options={ options={
'verbose_name': 'Custom field',
'verbose_name_plural': 'Custom fields', 'verbose_name_plural': 'Custom fields',
'verbose_name': 'Custom field',
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='EmailTemplate', name='EmailTemplate',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('template_name', models.CharField(max_length=100, verbose_name='Template Name')), ('template_name', models.CharField(verbose_name='Template Name', max_length=100)),
('subject', models.CharField(help_text='This will be prefixed with "[ticket.ticket] ticket.title". We recommend something simple such as "(Updated") or "(Closed)" - the same context is available as in plain_text, below.', max_length=100, verbose_name='Subject')), ('subject', models.CharField(verbose_name='Subject', help_text='This will be prefixed with "[ticket.ticket] ticket.title". We recommend something simple such as "(Updated") or "(Closed)" - the same context is available as in plain_text, below.', max_length=100)),
('heading', models.CharField(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, below.', max_length=100, verbose_name='Heading')), ('heading', models.CharField(verbose_name='Heading', 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, below.', max_length=100)),
('plain_text', models.TextField(help_text='The context available to you includes {{ ticket }}, {{ queue }}, and depending on the time of the call: {{ resolution }} or {{ comment }}.', verbose_name='Plain Text')), ('plain_text', models.TextField(verbose_name='Plain Text', help_text='The context available to you includes {{ ticket }}, {{ queue }}, and depending on the time of the call: {{ resolution }} or {{ comment }}.')),
('html', models.TextField(help_text='The same context is available here as in plain_text, above.', verbose_name='HTML')), ('html', models.TextField(verbose_name='HTML', help_text='The same context is available here as in plain_text, above.')),
('locale', models.CharField(help_text='Locale of this template.', max_length=10, null=True, verbose_name='Locale', blank=True)), ('locale', models.CharField(null=True, verbose_name='Locale', help_text='Locale of this template.', blank=True, max_length=10)),
], ],
options={ options={
'ordering': ['template_name', 'locale'],
'verbose_name': 'e-mail template',
'verbose_name_plural': 'e-mail templates', 'verbose_name_plural': 'e-mail templates',
'verbose_name': 'e-mail template',
'ordering': ['template_name', 'locale'],
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='EscalationExclusion', name='EscalationExclusion',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('name', models.CharField(max_length=100, verbose_name='Name')), ('name', models.CharField(verbose_name='Name', max_length=100)),
('date', models.DateField(help_text='Date on which escalation should not happen', verbose_name='Date')), ('date', models.DateField(verbose_name='Date', help_text='Date on which escalation should not happen')),
], ],
options={ options={
'verbose_name': 'Escalation exclusion',
'verbose_name_plural': 'Escalation exclusions', 'verbose_name_plural': 'Escalation exclusions',
'verbose_name': 'Escalation exclusion',
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='FollowUp', name='FollowUp',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('date', models.DateTimeField(default=django.utils.timezone.now, verbose_name='Date')), ('date', models.DateTimeField(verbose_name='Date', default=django.utils.timezone.now)),
('title', models.CharField(max_length=200, null=True, verbose_name='Title', blank=True)), ('title', models.CharField(null=True, verbose_name='Title', blank=True, max_length=200)),
('comment', models.TextField(null=True, verbose_name='Comment', blank=True)), ('comment', models.TextField(null=True, verbose_name='Comment', blank=True)),
('public', models.BooleanField(default=False, help_text='Public tickets are viewable by the submitter and all staff, but non-public tickets can only be seen by staff.', verbose_name='Public')), ('public', models.BooleanField(verbose_name='Public', default=False, help_text='Public tickets are viewable by the submitter and all staff, but non-public tickets can only be seen by staff.')),
('new_status', models.IntegerField(blank=True, help_text='If the status was changed, what was it changed to?', null=True, verbose_name='New Status', choices=[(1, 'Open'), (2, 'Reopened'), (3, 'Resolved'), (4, 'Closed'), (5, 'Duplicate')])), ('new_status', models.IntegerField(null=True, verbose_name='New Status', help_text='If the status was changed, what was it changed to?', blank=True, choices=[(1, 'Open'), (2, 'Reopened'), (3, 'Resolved'), (4, 'Closed'), (5, 'Duplicate')])),
], ],
options={ options={
'ordering': ['date'],
'verbose_name': 'Follow-up',
'verbose_name_plural': 'Follow-ups', 'verbose_name_plural': 'Follow-ups',
'verbose_name': 'Follow-up',
'ordering': ['date'],
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='IgnoreEmail', name='IgnoreEmail',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('name', models.CharField(max_length=100, verbose_name='Name')), ('name', models.CharField(verbose_name='Name', max_length=100)),
('date', models.DateField(help_text='Date on which this e-mail address was added', verbose_name='Date', editable=False, blank=True)), ('date', models.DateField(editable=False, verbose_name='Date', blank=True, help_text='Date on which this e-mail address was added')),
('email_address', models.CharField(help_text='Enter a full e-mail address, or portions with wildcards, eg *@domain.com or postmaster@*.', max_length=150, verbose_name='E-Mail Address')), ('email_address', models.CharField(verbose_name='E-Mail Address', help_text='Enter a full e-mail address, or portions with wildcards, eg *@domain.com or postmaster@*.', max_length=150)),
('keep_in_mailbox', models.BooleanField(default=False, 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.', verbose_name='Save Emails in Mailbox?')), ('keep_in_mailbox', models.BooleanField(verbose_name='Save Emails in Mailbox?', default=False, 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.')),
], ],
options={ options={
'verbose_name': 'Ignored e-mail address',
'verbose_name_plural': 'Ignored e-mail addresses', 'verbose_name_plural': 'Ignored e-mail addresses',
'verbose_name': 'Ignored e-mail address',
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='KBCategory', name='KBCategory',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('title', models.CharField(max_length=100, verbose_name='Title')), ('title', models.CharField(verbose_name='Title', max_length=100)),
('slug', models.SlugField(verbose_name='Slug')), ('slug', models.SlugField(verbose_name='Slug')),
('description', models.TextField(verbose_name='Description')), ('description', models.TextField(verbose_name='Description')),
], ],
options={ options={
'ordering': ['title'],
'verbose_name': 'Knowledge base category',
'verbose_name_plural': 'Knowledge base categories', 'verbose_name_plural': 'Knowledge base categories',
'verbose_name': 'Knowledge base category',
'ordering': ['title'],
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='KBItem', name='KBItem',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('title', models.CharField(max_length=100, verbose_name='Title')), ('title', models.CharField(verbose_name='Title', max_length=100)),
('question', models.TextField(verbose_name='Question')), ('question', models.TextField(verbose_name='Question')),
('answer', models.TextField(verbose_name='Answer')), ('answer', models.TextField(verbose_name='Answer')),
('votes', models.IntegerField(default=0, help_text='Total number of votes cast for this item', verbose_name='Votes')), ('votes', models.IntegerField(verbose_name='Votes', default=0, help_text='Total number of votes cast for this item')),
('recommendations', models.IntegerField(default=0, help_text='Number of votes for this item which were POSITIVE.', verbose_name='Positive Votes')), ('recommendations', models.IntegerField(verbose_name='Positive Votes', default=0, help_text='Number of votes for this item which were POSITIVE.')),
('last_updated', models.DateTimeField(help_text='The date on which this question was most recently changed.', verbose_name='Last Updated', blank=True)), ('last_updated', models.DateTimeField(verbose_name='Last Updated', blank=True, help_text='The date on which this question was most recently changed.')),
('category', models.ForeignKey(verbose_name='Category', to='helpdesk.KBCategory')), ('category', models.ForeignKey(verbose_name='Category', to='helpdesk.KBCategory')),
], ],
options={ options={
'ordering': ['title'],
'verbose_name': 'Knowledge base item',
'verbose_name_plural': 'Knowledge base items', 'verbose_name_plural': 'Knowledge base items',
'verbose_name': 'Knowledge base item',
'ordering': ['title'],
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='PreSetReply', name='PreSetReply',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('name', models.CharField(help_text='Only used to assist users with selecting a reply - not shown to the user.', max_length=100, verbose_name='Name')), ('name', models.CharField(verbose_name='Name', help_text='Only used to assist users with selecting a reply - not shown to the user.', max_length=100)),
('body', models.TextField(help_text='Context available: {{ ticket }} - ticket object (eg {{ ticket.title }}); {{ queue }} - The queue; and {{ user }} - the current user.', verbose_name='Body')), ('body', models.TextField(verbose_name='Body', help_text='Context available: {{ ticket }} - ticket object (eg {{ ticket.title }}); {{ queue }} - The queue; and {{ user }} - the current user.')),
], ],
options={ options={
'ordering': ['name'],
'verbose_name': 'Pre-set reply',
'verbose_name_plural': 'Pre-set replies', 'verbose_name_plural': 'Pre-set replies',
'verbose_name': 'Pre-set reply',
'ordering': ['name'],
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='Queue', name='Queue',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('title', models.CharField(max_length=100, verbose_name='Title')), ('title', models.CharField(verbose_name='Title', max_length=100)),
('slug', models.SlugField(help_text="This slug is used when building ticket ID's. Once set, try not to change it or e-mailing may get messy.", verbose_name='Slug')), ('slug', models.SlugField(verbose_name='Slug', help_text="This slug is used when building ticket ID's. Once set, try not to change it or e-mailing may get messy.")),
('email_address', models.EmailField(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 for that mailbox.', max_length=75, null=True, verbose_name='E-Mail Address', blank=True)), ('email_address', models.EmailField(null=True, verbose_name='E-Mail Address', 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 for that mailbox.', blank=True, max_length=75)),
('locale', models.CharField(help_text='Locale of this queue. All correspondence in this queue will be in this language.', max_length=10, null=True, verbose_name='Locale', blank=True)), ('locale', models.CharField(null=True, verbose_name='Locale', help_text='Locale of this queue. All correspondence in this queue will be in this language.', blank=True, max_length=10)),
('allow_public_submission', models.BooleanField(default=False, help_text='Should this queue be listed on the public submission form?', verbose_name='Allow Public Submission?')), ('allow_public_submission', models.BooleanField(verbose_name='Allow Public Submission?', default=False, help_text='Should this queue be listed on the public submission form?')),
('allow_email_submission', models.BooleanField(default=False, help_text='Do you want to poll the e-mail box below for new tickets?', verbose_name='Allow E-Mail Submission?')), ('allow_email_submission', models.BooleanField(verbose_name='Allow E-Mail Submission?', default=False, help_text='Do you want to poll the e-mail box below for new tickets?')),
('escalate_days', models.IntegerField(help_text='For tickets which are not held, how often do you wish to increase their priority? Set to 0 for no escalation.', null=True, verbose_name='Escalation Days', blank=True)), ('escalate_days', models.IntegerField(null=True, verbose_name='Escalation Days', blank=True, help_text='For tickets which are not held, how often do you wish to increase their priority? Set to 0 for no escalation.')),
('new_ticket_cc', models.CharField(help_text='If an e-mail address is entered here, then it will receive notification of all new tickets created for this queue. Enter a comma between multiple e-mail addresses.', max_length=200, null=True, verbose_name='New Ticket CC Address', blank=True)), ('new_ticket_cc', models.CharField(null=True, verbose_name='New Ticket CC Address', help_text='If an e-mail address is entered here, then it will receive notification of all new tickets created for this queue. Enter a comma between multiple e-mail addresses.', blank=True, max_length=200)),
('updated_ticket_cc', models.CharField(help_text='If an e-mail address is entered here, then it will receive notification of all activity (new tickets, closed tickets, updates, reassignments, etc) for this queue. Separate multiple addresses with a comma.', max_length=200, null=True, verbose_name='Updated Ticket CC Address', blank=True)), ('updated_ticket_cc', models.CharField(null=True, verbose_name='Updated Ticket CC Address', help_text='If an e-mail address is entered here, then it will receive notification of all activity (new tickets, closed tickets, updates, reassignments, etc) for this queue. Separate multiple addresses with a comma.', blank=True, max_length=200)),
('email_box_type', models.CharField(choices=[(b'pop3', 'POP 3'), (b'imap', 'IMAP')], max_length=5, blank=True, help_text='E-Mail server type for creating tickets automatically from a mailbox - both POP3 and IMAP are supported.', null=True, verbose_name='E-Mail Box Type')), ('email_box_type', models.CharField(null=True, verbose_name='E-Mail Box Type', help_text='E-Mail server type for creating tickets automatically from a mailbox - both POP3 and IMAP are supported.', blank=True, max_length=5, choices=[('pop3', 'POP 3'), ('imap', 'IMAP')])),
('email_box_host', models.CharField(help_text='Your e-mail server address - either the domain name or IP address. May be "localhost".', max_length=200, null=True, verbose_name='E-Mail Hostname', blank=True)), ('email_box_host', models.CharField(null=True, verbose_name='E-Mail Hostname', help_text='Your e-mail server address - either the domain name or IP address. May be "localhost".', blank=True, max_length=200)),
('email_box_port', models.IntegerField(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 servers. Leave it blank to use the defaults.', null=True, verbose_name='E-Mail Port', blank=True)), ('email_box_port', models.IntegerField(null=True, verbose_name='E-Mail Port', blank=True, 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 servers. Leave it blank to use the defaults.')),
('email_box_ssl', models.BooleanField(default=False, help_text='Whether to use SSL for IMAP or POP3 - the default ports when using SSL are 993 for IMAP and 995 for POP3.', verbose_name='Use SSL for E-Mail?')), ('email_box_ssl', models.BooleanField(verbose_name='Use SSL for E-Mail?', default=False, help_text='Whether to use SSL for IMAP or POP3 - the default ports when using SSL are 993 for IMAP and 995 for POP3.')),
('email_box_user', models.CharField(help_text='Username for accessing this mailbox.', max_length=200, null=True, verbose_name='E-Mail Username', blank=True)), ('email_box_user', models.CharField(null=True, verbose_name='E-Mail Username', help_text='Username for accessing this mailbox.', blank=True, max_length=200)),
('email_box_pass', models.CharField(help_text='Password for the above username', max_length=200, null=True, verbose_name='E-Mail Password', blank=True)), ('email_box_pass', models.CharField(null=True, verbose_name='E-Mail Password', help_text='Password for the above username', blank=True, max_length=200)),
('email_box_imap_folder', models.CharField(help_text='If using IMAP, what folder do you wish to fetch messages from? This allows you to use one IMAP account for multiple queues, by filtering messages on your IMAP server into separate folders. Default: INBOX.', max_length=100, null=True, verbose_name='IMAP Folder', blank=True)), ('email_box_imap_folder', models.CharField(null=True, verbose_name='IMAP Folder', help_text='If using IMAP, what folder do you wish to fetch messages from? This allows you to use one IMAP account for multiple queues, by filtering messages on your IMAP server into separate folders. Default: INBOX.', blank=True, max_length=100)),
('email_box_interval', models.IntegerField(default=b'5', help_text='How often do you wish to check this mailbox? (in Minutes)', null=True, verbose_name='E-Mail Check Interval', blank=True)), ('email_box_interval', models.IntegerField(null=True, verbose_name='E-Mail Check Interval', blank=True, default='5', help_text='How often do you wish to check this mailbox? (in Minutes)')),
('email_box_last_check', models.DateTimeField(null=True, editable=False, blank=True)), ('email_box_last_check', models.DateTimeField(editable=False, null=True, blank=True)),
('socks_proxy_type', models.CharField(null=True, verbose_name='Socks Proxy Type', help_text='SOCKS4 or SOCKS5 allows you to proxy your connections through a SOCKS server.', blank=True, max_length=8, choices=[('socks4', 'SOCKS4'), ('socks5', 'SOCKS5')])),
('socks_proxy_host', models.GenericIPAddressField(null=True, verbose_name='Socks Proxy Host', help_text='Socks proxy IP address. Default: 127.0.0.1', blank=True)),
('socks_proxy_port', models.IntegerField(null=True, verbose_name='Socks Proxy Port', blank=True, help_text='Socks proxy port number. Default: 9150 (default TOR port)')),
], ],
options={ options={
'ordering': ('title',),
'verbose_name': 'Queue',
'verbose_name_plural': 'Queues', 'verbose_name_plural': 'Queues',
'verbose_name': 'Queue',
'ordering': ('title',),
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='SavedSearch', name='SavedSearch',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('title', models.CharField(help_text='User-provided name for this query', max_length=100, verbose_name='Query Name')), ('title', models.CharField(verbose_name='Query Name', help_text='User-provided name for this query', max_length=100)),
('shared', models.BooleanField(default=False, help_text='Should other users see this query?', verbose_name='Shared With Other Users?')), ('shared', models.BooleanField(verbose_name='Shared With Other Users?', default=False, help_text='Should other users see this query?')),
('query', models.TextField(help_text='Pickled query object. Be wary changing this.', verbose_name='Search Query')), ('query', models.TextField(verbose_name='Search Query', help_text='Pickled query object. Be wary changing this.')),
('user', models.ForeignKey(verbose_name='User', to=settings.AUTH_USER_MODEL)), ('user', models.ForeignKey(verbose_name='User', to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'verbose_name': 'Saved search',
'verbose_name_plural': 'Saved searches', 'verbose_name_plural': 'Saved searches',
'verbose_name': 'Saved search',
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='Ticket', name='Ticket',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('title', models.CharField(max_length=200, verbose_name='Title')), ('title', models.CharField(verbose_name='Title', max_length=200)),
('created', models.DateTimeField(help_text='Date this ticket was first created', verbose_name='Created', blank=True)), ('created', models.DateTimeField(verbose_name='Created', blank=True, help_text='Date this ticket was first created')),
('modified', models.DateTimeField(help_text='Date this ticket was most recently changed.', verbose_name='Modified', blank=True)), ('modified', models.DateTimeField(verbose_name='Modified', blank=True, help_text='Date this ticket was most recently changed.')),
('submitter_email', models.EmailField(help_text='The submitter will receive an email for all public follow-ups left for this task.', max_length=75, null=True, verbose_name='Submitter E-Mail', blank=True)), ('submitter_email', models.EmailField(null=True, verbose_name='Submitter E-Mail', help_text='The submitter will receive an email for all public follow-ups left for this task.', blank=True, max_length=75)),
('status', models.IntegerField(default=1, verbose_name='Status', choices=[(1, 'Open'), (2, 'Reopened'), (3, 'Resolved'), (4, 'Closed'), (5, 'Duplicate')])), ('status', models.IntegerField(verbose_name='Status', default=1, choices=[(1, 'Open'), (2, 'Reopened'), (3, 'Resolved'), (4, 'Closed'), (5, 'Duplicate')])),
('on_hold', models.BooleanField(default=False, help_text='If a ticket is on hold, it will not automatically be escalated.', verbose_name='On Hold')), ('on_hold', models.BooleanField(verbose_name='On Hold', default=False, help_text='If a ticket is on hold, it will not automatically be escalated.')),
('description', models.TextField(help_text='The content of the customers query.', null=True, verbose_name='Description', blank=True)), ('description', models.TextField(null=True, verbose_name='Description', blank=True, help_text='The content of the customers query.')),
('resolution', models.TextField(help_text='The resolution provided to the customer by our staff.', null=True, verbose_name='Resolution', blank=True)), ('resolution', models.TextField(null=True, verbose_name='Resolution', blank=True, help_text='The resolution provided to the customer by our staff.')),
('priority', models.IntegerField(default=3, help_text='1 = Highest Priority, 5 = Low Priority', blank=3, verbose_name='Priority', choices=[(1, '1. Critical'), (2, '2. High'), (3, '3. Normal'), (4, '4. Low'), (5, '5. Very Low')])), ('priority', models.IntegerField(verbose_name='Priority', help_text='1 = Highest Priority, 5 = Low Priority', blank=3, default=3, choices=[(1, '1. Critical'), (2, '2. High'), (3, '3. Normal'), (4, '4. Low'), (5, '5. Very Low')])),
('due_date', models.DateTimeField(null=True, verbose_name='Due on', blank=True)), ('due_date', models.DateTimeField(null=True, verbose_name='Due on', blank=True)),
('last_escalation', models.DateTimeField(help_text='The date this ticket was last escalated - updated automatically by management/commands/escalate_tickets.py.', null=True, editable=False, blank=True)), ('last_escalation', models.DateTimeField(editable=False, null=True, blank=True, help_text='The date this ticket was last escalated - updated automatically by management/commands/escalate_tickets.py.')),
('assigned_to', models.ForeignKey(related_name=b'assigned_to', verbose_name='Assigned to', blank=True, to=settings.AUTH_USER_MODEL, null=True)), ('assigned_to', models.ForeignKey(null=True, verbose_name='Assigned to', blank=True, related_name='assigned_to', to=settings.AUTH_USER_MODEL)),
('queue', models.ForeignKey(verbose_name='Queue', to='helpdesk.Queue')), ('queue', models.ForeignKey(verbose_name='Queue', to='helpdesk.Queue')),
], ],
options={ options={
'verbose_name_plural': 'Tickets',
'verbose_name': 'Ticket',
'ordering': ('id',), 'ordering': ('id',),
'get_latest_by': 'created', 'get_latest_by': 'created',
'verbose_name': 'Ticket',
'verbose_name_plural': 'Tickets',
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='TicketCC', name='TicketCC',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('email', models.EmailField(help_text='For non-user followers, enter their e-mail address', max_length=75, null=True, verbose_name='E-Mail Address', blank=True)), ('email', models.EmailField(null=True, verbose_name='E-Mail Address', help_text='For non-user followers, enter their e-mail address', blank=True, max_length=75)),
('can_view', models.BooleanField(default=False, help_text='Can this CC login to view the ticket details?', verbose_name='Can View Ticket?')), ('can_view', models.BooleanField(verbose_name='Can View Ticket?', default=False, help_text='Can this CC login to view the ticket details?')),
('can_update', models.BooleanField(default=False, help_text='Can this CC login and update the ticket?', verbose_name='Can Update Ticket?')), ('can_update', models.BooleanField(verbose_name='Can Update Ticket?', default=False, help_text='Can this CC login and update the ticket?')),
('ticket', models.ForeignKey(verbose_name='Ticket', to='helpdesk.Ticket')), ('ticket', models.ForeignKey(verbose_name='Ticket', to='helpdesk.Ticket')),
('user', models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, help_text='User who wishes to receive updates for this ticket.', null=True, verbose_name='User')), ('user', models.ForeignKey(null=True, verbose_name='User', blank=True, to=settings.AUTH_USER_MODEL, help_text='User who wishes to receive updates for this ticket.')),
], ],
options={ options={
}, },
@ -251,55 +254,55 @@ class Migration(migrations.Migration):
migrations.CreateModel( migrations.CreateModel(
name='TicketChange', name='TicketChange',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('field', models.CharField(max_length=100, verbose_name='Field')), ('field', models.CharField(verbose_name='Field', max_length=100)),
('old_value', models.TextField(null=True, verbose_name='Old Value', blank=True)), ('old_value', models.TextField(null=True, verbose_name='Old Value', blank=True)),
('new_value', models.TextField(null=True, verbose_name='New Value', blank=True)), ('new_value', models.TextField(null=True, verbose_name='New Value', blank=True)),
('followup', models.ForeignKey(verbose_name='Follow-up', to='helpdesk.FollowUp')), ('followup', models.ForeignKey(verbose_name='Follow-up', to='helpdesk.FollowUp')),
], ],
options={ options={
'verbose_name': 'Ticket change',
'verbose_name_plural': 'Ticket changes', 'verbose_name_plural': 'Ticket changes',
'verbose_name': 'Ticket change',
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='TicketCustomFieldValue', name='TicketCustomFieldValue',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('value', models.TextField(null=True, blank=True)), ('value', models.TextField(null=True, blank=True)),
('field', models.ForeignKey(verbose_name='Field', to='helpdesk.CustomField')), ('field', models.ForeignKey(verbose_name='Field', to='helpdesk.CustomField')),
('ticket', models.ForeignKey(verbose_name='Ticket', to='helpdesk.Ticket')), ('ticket', models.ForeignKey(verbose_name='Ticket', to='helpdesk.Ticket')),
], ],
options={ options={
'verbose_name': 'Ticket custom field value',
'verbose_name_plural': 'Ticket custom field values', 'verbose_name_plural': 'Ticket custom field values',
'verbose_name': 'Ticket custom field value',
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='TicketDependency', name='TicketDependency',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('depends_on', models.ForeignKey(related_name=b'depends_on', verbose_name='Depends On Ticket', to='helpdesk.Ticket')), ('depends_on', models.ForeignKey(related_name='depends_on', verbose_name='Depends On Ticket', to='helpdesk.Ticket')),
('ticket', models.ForeignKey(related_name=b'ticketdependency', verbose_name='Ticket', to='helpdesk.Ticket')), ('ticket', models.ForeignKey(related_name='ticketdependency', verbose_name='Ticket', to='helpdesk.Ticket')),
], ],
options={ options={
'verbose_name': 'Ticket dependency',
'verbose_name_plural': 'Ticket dependencies', 'verbose_name_plural': 'Ticket dependencies',
'verbose_name': 'Ticket dependency',
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
migrations.CreateModel( migrations.CreateModel(
name='UserSettings', name='UserSettings',
fields=[ fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
('settings_pickled', models.TextField(help_text='This is a base64-encoded representation of a pickled Python dictionary. Do not change this field via the admin.', null=True, verbose_name='Settings Dictionary', blank=True)), ('settings_pickled', models.TextField(null=True, verbose_name='Settings Dictionary', blank=True, help_text='This is a base64-encoded representation of a pickled Python dictionary. Do not change this field via the admin.')),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)), ('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'verbose_name': 'User Setting',
'verbose_name_plural': 'User Settings', 'verbose_name_plural': 'User Settings',
'verbose_name': 'User Setting',
}, },
bases=(models.Model,), bases=(models.Model,),
), ),
@ -310,13 +313,13 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='presetreply', model_name='presetreply',
name='queues', name='queues',
field=models.ManyToManyField(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.', to='helpdesk.Queue', null=True, blank=True), field=models.ManyToManyField(null=True, to='helpdesk.Queue', blank=True, 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.'),
preserve_default=True, preserve_default=True,
), ),
migrations.AddField( migrations.AddField(
model_name='ignoreemail', model_name='ignoreemail',
name='queues', name='queues',
field=models.ManyToManyField(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.', to='helpdesk.Queue', null=True, blank=True), field=models.ManyToManyField(null=True, to='helpdesk.Queue', blank=True, 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.'),
preserve_default=True, preserve_default=True,
), ),
migrations.AddField( migrations.AddField(
@ -328,13 +331,13 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='followup', model_name='followup',
name='user', name='user',
field=models.ForeignKey(verbose_name='User', blank=True, to=settings.AUTH_USER_MODEL, null=True), field=models.ForeignKey(null=True, verbose_name='User', blank=True, to=settings.AUTH_USER_MODEL),
preserve_default=True, preserve_default=True,
), ),
migrations.AddField( migrations.AddField(
model_name='escalationexclusion', model_name='escalationexclusion',
name='queues', name='queues',
field=models.ManyToManyField(help_text='Leave blank for this exclusion to be applied to all queues, or select those queues you wish to exclude with this entry.', to='helpdesk.Queue', null=True, blank=True), field=models.ManyToManyField(null=True, to='helpdesk.Queue', blank=True, help_text='Leave blank for this exclusion to be applied to all queues, or select those queues you wish to exclude with this entry.'),
preserve_default=True, preserve_default=True,
), ),
migrations.AddField( migrations.AddField(

View File

@ -9,9 +9,12 @@ from helpdesk.settings import DEFAULT_USER_SETTINGS
def picke_settings(data): def picke_settings(data):
"""Pickling as defined at migration's creation time""" """Pickling as defined at migration's creation time"""
import cPickle try:
import pickle
except ImportError:
import cPickle as pickle
from helpdesk.lib import b64encode from helpdesk.lib import b64encode
return b64encode(cPickle.dumps(data)) return b64encode(pickle.dumps(data))
# https://docs.djangoproject.com/en/1.7/topics/migrations/#data-migrations # https://docs.djangoproject.com/en/1.7/topics/migrations/#data-migrations

View File

@ -646,7 +646,7 @@ def attachment_path(instance, filename):
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):
os.makedirs(att_path, 0777) os.makedirs(att_path, 0o777)
return os.path.join(path, filename) return os.path.join(path, filename)
@ -1003,17 +1003,23 @@ class UserSettings(models.Model):
def _set_settings(self, data): def _set_settings(self, data):
# data should always be a Python dictionary. # data should always be a Python dictionary.
import cPickle try:
import pickle
except ImportError:
import cPickle as pickle
from helpdesk.lib import b64encode from helpdesk.lib import b64encode
self.settings_pickled = b64encode(cPickle.dumps(data)) self.settings_pickled = b64encode(pickle.dumps(data))
def _get_settings(self): def _get_settings(self):
# return a python dictionary representing the pickled data. # return a python dictionary representing the pickled data.
import cPickle try:
import pickle
except ImportError:
import cPickle as pickle
from helpdesk.lib import b64decode from helpdesk.lib import b64decode
try: try:
return cPickle.loads(b64decode(str(self.settings_pickled))) return pickle.loads(b64decode(str(self.settings_pickled)))
except cPickle.UnpicklingError: except pickle.UnpicklingError:
return {} return {}
settings = property(_get_settings, _set_settings) settings = property(_get_settings, _set_settings)

View File

@ -1,4 +1,5 @@
{% load i18n %} {% load i18n %}
{% load url from future %}
{% load load_helpdesk_settings %} {% load load_helpdesk_settings %}
{% with request|load_helpdesk_settings as helpdesk_settings %} {% with request|load_helpdesk_settings as helpdesk_settings %}
<html> <html>

View File

@ -1,4 +1,6 @@
{% extends "helpdesk/public_base.html" %}{% load i18n bootstrap %} {% extends "helpdesk/public_base.html" %}
{% load i18n bootstrap %}
{% load url from future %}
{% block helpdesk_body %} {% block helpdesk_body %}

View File

@ -9,13 +9,13 @@ from django.template import Library
from helpdesk import settings as helpdesk_settings_config from helpdesk import settings as helpdesk_settings_config
def load_helpdesk_settings(request): def load_helpdesk_settings(request):
try: # try:
return helpdesk_settings_config return helpdesk_settings_config
except Exception, e: # except Exception, e:
import sys # import sys
print >> sys.stderr, "'load_helpdesk_settings' template tag (django-helpdesk) crashed with following error:" # print >> sys.stderr, "'load_helpdesk_settings' template tag (django-helpdesk) crashed with following error:"
print >> sys.stderr, e # print >> sys.stderr, e
return '' # return ''
register = Library() register = Library()
register.filter('load_helpdesk_settings', load_helpdesk_settings) register.filter('load_helpdesk_settings', load_helpdesk_settings)

View File

@ -12,14 +12,14 @@ from helpdesk.models import SavedSearch
def saved_queries(user): def saved_queries(user):
try: # try:
user_saved_queries = SavedSearch.objects.filter(Q(user=user) | Q(shared__exact=True)) user_saved_queries = SavedSearch.objects.filter(Q(user=user) | Q(shared__exact=True))
return user_saved_queries return user_saved_queries
except Exception, e: # except Exception, 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()
register.filter('saved_queries', saved_queries) register.filter('saved_queries', saved_queries)

View File

@ -92,11 +92,11 @@ def view_ticket(request):
if request.user.is_staff: if request.user.is_staff:
redirect_url = reverse('helpdesk_view', args=[ticket_id]) redirect_url = reverse('helpdesk_view', args=[ticket_id])
if request.GET.has_key('close'): if 'close' in request.GET:
redirect_url += '?close' redirect_url += '?close'
return HttpResponseRedirect(redirect_url) return HttpResponseRedirect(redirect_url)
if request.GET.has_key('close') and ticket.status == Ticket.RESOLVED_STATUS: if 'close' in request.GET and ticket.status == Ticket.RESOLVED_STATUS:
from helpdesk.views.staff import update_ticket from helpdesk.views.staff import update_ticket
# Trick the update_ticket() view into thinking it's being called with # Trick the update_ticket() view into thinking it's being called with
# a valid POST. # a valid POST.
@ -134,7 +134,7 @@ def view_ticket(request):
def change_language(request): def change_language(request):
return_to = '' return_to = ''
if request.GET.has_key('return_to'): if 'return_to' in request.GET:
return_to = request.GET['return_to'] return_to = request.GET['return_to']
return render_to_response('helpdesk/public_change_language.html', return render_to_response('helpdesk/public_change_language.html',

View File

@ -6,7 +6,8 @@ django-helpdesk - A Django powered ticket tracker for small enterprise.
views/staff.py - The bulk of the application - provides most business logic and views/staff.py - The bulk of the application - provides most business logic and
renders all staff-facing views. renders all staff-facing views.
""" """
from __future__ import unicode_literals
from django.utils.encoding import python_2_unicode_compatible
from datetime import datetime, timedelta from datetime import datetime, timedelta
import sys import sys
@ -196,7 +197,7 @@ followup_delete = staff_member_required(followup_delete)
def view_ticket(request, ticket_id): def view_ticket(request, ticket_id):
ticket = get_object_or_404(Ticket, id=ticket_id) ticket = get_object_or_404(Ticket, id=ticket_id)
if request.GET.has_key('take'): if 'take' in request.GET:
# Allow the user to assign the ticket to themselves whilst viewing it. # Allow the user to assign the ticket to themselves whilst viewing it.
# Trick the update_ticket() view into thinking it's being called with # Trick the update_ticket() view into thinking it's being called with
@ -209,14 +210,14 @@ def view_ticket(request, ticket_id):
} }
return update_ticket(request, ticket_id) return update_ticket(request, ticket_id)
if request.GET.has_key('subscribe'): if 'subscribe' in request.GET:
# Allow the user to subscribe him/herself to the ticket whilst viewing it. # Allow the user to subscribe him/herself to the ticket whilst viewing it.
ticketcc_string, SHOW_SUBSCRIBE = return_ticketccstring_and_show_subscribe(request.user, ticket) ticketcc_string, SHOW_SUBSCRIBE = return_ticketccstring_and_show_subscribe(request.user, ticket)
if SHOW_SUBSCRIBE: if SHOW_SUBSCRIBE:
subscribe_staff_member_to_ticket(ticket, request.user) subscribe_staff_member_to_ticket(ticket, request.user)
return HttpResponseRedirect(reverse('helpdesk_view', args=[ticket.id])) return HttpResponseRedirect(reverse('helpdesk_view', args=[ticket.id]))
if request.GET.has_key('close') and ticket.status == Ticket.RESOLVED_STATUS: if 'close' in request.GET and ticket.status == Ticket.RESOLVED_STATUS:
if not ticket.assigned_to: if not ticket.assigned_to:
owner = 0 owner = 0
else: else:
@ -702,15 +703,18 @@ def ticket_list(request):
if not (saved_query.shared or saved_query.user == request.user): if not (saved_query.shared or saved_query.user == request.user):
return HttpResponseRedirect(reverse('helpdesk_list')) return HttpResponseRedirect(reverse('helpdesk_list'))
import cPickle try:
import pickle
except ImportError:
import cPickle as pickle
from helpdesk.lib import b64decode from helpdesk.lib import b64decode
query_params = cPickle.loads(b64decode(str(saved_query.query))) query_params = pickle.loads(b64decode(str(saved_query.query)))
elif not ( request.GET.has_key('queue') elif not ( 'queue' in request.GET
or request.GET.has_key('assigned_to') or 'assigned_to' in request.GET
or request.GET.has_key('status') or 'status' in request.GET
or request.GET.has_key('q') or 'q' in request.GET
or request.GET.has_key('sort') or 'sort' in request.GET
or request.GET.has_key('sortreverse') or 'sortreverse' in request.GET
): ):
# Fall-back if no querying is being done, force the list to only # Fall-back if no querying is being done, force the list to only
@ -799,13 +803,16 @@ def ticket_list(request):
tickets = ticket_paginator.page(ticket_paginator.num_pages) tickets = ticket_paginator.page(ticket_paginator.num_pages)
search_message = '' search_message = ''
if context.has_key('query') and settings.DATABASES['default']['ENGINE'].endswith('sqlite'): if 'query' in context and settings.DATABASES['default']['ENGINE'].endswith('sqlite'):
search_message = _('<p><strong>Note:</strong> Your keyword search is case sensitive because of your database. This means the search will <strong>not</strong> be accurate. By switching to a different database system you will gain better searching! For more information, read the <a href="http://docs.djangoproject.com/en/dev/ref/databases/#sqlite-string-matching">Django Documentation on string matching in SQLite</a>.') search_message = _('<p><strong>Note:</strong> Your keyword search is case sensitive because of your database. This means the search will <strong>not</strong> be accurate. By switching to a different database system you will gain better searching! For more information, read the <a href="http://docs.djangoproject.com/en/dev/ref/databases/#sqlite-string-matching">Django Documentation on string matching in SQLite</a>.')
import cPickle try:
import pickle
except ImportError:
import cPickle as pickle
from helpdesk.lib import b64encode from helpdesk.lib import b64encode
urlsafe_query = b64encode(cPickle.dumps(query_params)) urlsafe_query = b64encode(pickle.dumps(query_params))
user_saved_queries = SavedSearch.objects.filter(Q(user=request.user) | Q(shared__exact=True)) user_saved_queries = SavedSearch.objects.filter(Q(user=request.user) | Q(shared__exact=True))
@ -864,7 +871,7 @@ def create_ticket(request):
initial_data = {} initial_data = {}
if request.user.usersettings.settings.get('use_email_as_submitter', False) and request.user.email: if request.user.usersettings.settings.get('use_email_as_submitter', False) and request.user.email:
initial_data['submitter_email'] = request.user.email initial_data['submitter_email'] = request.user.email
if request.GET.has_key('queue'): if 'queue' in request.GET:
initial_data['queue'] = request.GET['queue'] initial_data['queue'] = request.GET['queue']
form = TicketForm(initial=initial_data) form = TicketForm(initial=initial_data)
@ -966,9 +973,12 @@ def run_report(request, report):
if not (saved_query.shared or saved_query.user == request.user): if not (saved_query.shared or saved_query.user == request.user):
return HttpResponseRedirect(reverse('helpdesk_report_index')) return HttpResponseRedirect(reverse('helpdesk_report_index'))
import cPickle try:
import pickle
except ImportError:
import cPickle as pickle
from helpdesk.lib import b64decode from helpdesk.lib import b64decode
query_params = cPickle.loads(b64decode(str(saved_query.query))) query_params = pickle.loads(b64decode(str(saved_query.query)))
report_queryset = apply_query(report_queryset, query_params) report_queryset = apply_query(report_queryset, query_params)
from collections import defaultdict from collections import defaultdict
@ -1003,7 +1013,7 @@ def run_report(request, report):
if report == 'userpriority': if report == 'userpriority':
title = _('User by Priority') title = _('User by Priority')
col1heading = _('User') col1heading = _('User')
possible_options = [t[1].__unicode__() for t in Ticket.PRIORITY_CHOICES] possible_options = [t[1].__str__() for t in Ticket.PRIORITY_CHOICES]
charttype = 'bar' charttype = 'bar'
elif report == 'userqueue': elif report == 'userqueue':
@ -1015,7 +1025,7 @@ def run_report(request, report):
elif report == 'userstatus': elif report == 'userstatus':
title = _('User by Status') title = _('User by Status')
col1heading = _('User') col1heading = _('User')
possible_options = [s[1].__unicode__() for s in Ticket.STATUS_CHOICES] possible_options = [s[1].__str__() for s in Ticket.STATUS_CHOICES]
charttype = 'bar' charttype = 'bar'
elif report == 'usermonth': elif report == 'usermonth':
@ -1027,13 +1037,13 @@ def run_report(request, report):
elif report == 'queuepriority': elif report == 'queuepriority':
title = _('Queue by Priority') title = _('Queue by Priority')
col1heading = _('Queue') col1heading = _('Queue')
possible_options = [t[1].__unicode__() for t in Ticket.PRIORITY_CHOICES] possible_options = [t[1].__str__() for t in Ticket.PRIORITY_CHOICES]
charttype = 'bar' charttype = 'bar'
elif report == 'queuestatus': elif report == 'queuestatus':
title = _('Queue by Status') title = _('Queue by Status')
col1heading = _('Queue') col1heading = _('Queue')
possible_options = [s[1].__unicode__() for s in Ticket.STATUS_CHOICES] possible_options = [s[1].__str__() for s in Ticket.STATUS_CHOICES]
charttype = 'bar' charttype = 'bar'
elif report == 'queuemonth': elif report == 'queuemonth':
@ -1249,7 +1259,7 @@ def ticket_dependency_add(request, ticket_id):
if form.is_valid(): if form.is_valid():
ticketdependency = form.save(commit=False) ticketdependency = form.save(commit=False)
ticketdependency.ticket = ticket ticketdependency.ticket = ticket
if ticketdependency.ticket <> ticketdependency.depends_on: if ticketdependency.ticket != ticketdependency.depends_on:
ticketdependency.save() ticketdependency.save()
return HttpResponseRedirect(reverse('helpdesk_view', args=[ticket.id])) return HttpResponseRedirect(reverse('helpdesk_view', args=[ticket.id]))
else: else: