forked from extern/django-helpdesk
Merge upstream changes
This commit is contained in:
commit
11e4f1a7bd
@ -2,6 +2,7 @@ include README
|
|||||||
include UPGRADE
|
include UPGRADE
|
||||||
include LICENSE*
|
include LICENSE*
|
||||||
include CHANGELOG
|
include CHANGELOG
|
||||||
|
include requirements.txt
|
||||||
|
|
||||||
recursive-include helpdesk/static/helpdesk *
|
recursive-include helpdesk/static/helpdesk *
|
||||||
recursive-include helpdesk/locale *.po *.mo
|
recursive-include helpdesk/locale *.po *.mo
|
||||||
|
@ -23,7 +23,7 @@ Before django-helpdesk will be much use, you need to do some basic configuration
|
|||||||
|
|
||||||
0 * * * * /path/to/helpdesksite/manage.py escalate_tickets
|
0 * * * * /path/to/helpdesksite/manage.py escalate_tickets
|
||||||
|
|
||||||
This will run the escalation process hourly, using the 'Escalation Hours' setting for each queue to determine which tickets to escalate.
|
This will run the escalation process hourly, using the 'Escalation Days' setting for each queue to determine which tickets to escalate.
|
||||||
|
|
||||||
5. If you wish to exclude some days (eg, weekends) from escalation calculations, enter the dates manually via the Admin, or setup a cronjob to run a management command on a regular basis::
|
5. If you wish to exclude some days (eg, weekends) from escalation calculations, enter the dates manually via the Admin, or setup a cronjob to run a management command on a regular basis::
|
||||||
|
|
||||||
@ -39,4 +39,6 @@ Before django-helpdesk will be much use, you need to do some basic configuration
|
|||||||
EMAIL_HOST_USER = 'YYYYYY@ZZZZ.PPP'
|
EMAIL_HOST_USER = 'YYYYYY@ZZZZ.PPP'
|
||||||
EMAIL_HOST_PASSWORD = '123456'
|
EMAIL_HOST_PASSWORD = '123456'
|
||||||
|
|
||||||
|
8. If you wish to use SOCKS4/5 proxy with Helpdesk Queue email operations, install PySocks manually.
|
||||||
|
|
||||||
You're now up and running! Happy ticketing.
|
You're now up and running! Happy ticketing.
|
||||||
|
@ -29,7 +29,7 @@ Download, extract, and drop ``helpdesk`` into your ``PYTHONPATH``
|
|||||||
Adding To Your Django Project
|
Adding To Your Django Project
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
1. Edit your ``settings.py`` file and add ``helpdesk`` to the ``INSTALLED_APPS`` setting. You also need ``django.contrib.admin`` and ``django.contrib.markup`` in ``INSTALLED_APPS`` if you haven't already added it. eg::
|
1. Edit your ``settings.py`` file and add ``helpdesk`` to the ``INSTALLED_APPS`` setting. You also need ``django.contrib.admin`` in ``INSTALLED_APPS`` if you haven't already added it. eg::
|
||||||
|
|
||||||
INSTALLED_APPS = (
|
INSTALLED_APPS = (
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
@ -37,11 +37,11 @@ Adding To Your Django Project
|
|||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.sites',
|
'django.contrib.sites',
|
||||||
'django.contrib.admin', # Required for helpdesk admin/maintenance
|
'django.contrib.admin', # Required for helpdesk admin/maintenance
|
||||||
'django.contrib.markup', # Required for helpdesk text display
|
|
||||||
'django.contrib.humanize', # Required for elapsed time formatting
|
'django.contrib.humanize', # Required for elapsed time formatting
|
||||||
'south', # Highly recommended to make database migrations simpler.
|
'south', # Highly recommended to make database migrations simpler in Django < 1.7
|
||||||
'markdown_deux', # Required for Knowledgebase item formatting
|
'markdown_deux', # Required for Knowledgebase item formatting
|
||||||
'helpdesk', # This is new!
|
'bootstrapform', # Required for nicer formatting of forms with the default templates
|
||||||
|
'helpdesk', # This is us!
|
||||||
)
|
)
|
||||||
|
|
||||||
2. Make sure django-helpdesk is accessible via ``urls.py``. Add the following line to ``urls.py``::
|
2. Make sure django-helpdesk is accessible via ``urls.py``. Add the following line to ``urls.py``::
|
||||||
@ -58,7 +58,7 @@ Adding To Your Django Project
|
|||||||
|
|
||||||
./manage.py syncdb
|
./manage.py syncdb
|
||||||
|
|
||||||
Then migrate using South
|
Then migrate using South / Django 1.7+ migrations::
|
||||||
|
|
||||||
./manage.py migrate helpdesk
|
./manage.py migrate helpdesk
|
||||||
|
|
||||||
@ -98,3 +98,7 @@ Adding To Your Django Project
|
|||||||
LOGIN_URL = '/helpdesk/login/'
|
LOGIN_URL = '/helpdesk/login/'
|
||||||
|
|
||||||
Alter the URL to suit your installation path.
|
Alter the URL to suit your installation path.
|
||||||
|
|
||||||
|
9. Load initial e-mail templates, otherwise you will not be able to setnd e-mail::
|
||||||
|
|
||||||
|
python manage.py loaddata emailtemplate.json
|
||||||
|
@ -102,7 +102,7 @@ class EditTicketForm(CustomFieldMixin, forms.ModelForm):
|
|||||||
|
|
||||||
for field, value in self.cleaned_data.items():
|
for field, value in self.cleaned_data.items():
|
||||||
if field.startswith('custom_'):
|
if field.startswith('custom_'):
|
||||||
field_name = field.replace('custom_', '')
|
field_name = field.replace('custom_', '', 1)
|
||||||
customfield = CustomField.objects.get(name=field_name)
|
customfield = CustomField.objects.get(name=field_name)
|
||||||
try:
|
try:
|
||||||
cfv = TicketCustomFieldValue.objects.get(ticket=self.instance, field=customfield)
|
cfv = TicketCustomFieldValue.objects.get(ticket=self.instance, field=customfield)
|
||||||
@ -229,7 +229,7 @@ class TicketForm(CustomFieldMixin, forms.Form):
|
|||||||
|
|
||||||
for field, value in self.cleaned_data.items():
|
for field, value in self.cleaned_data.items():
|
||||||
if field.startswith('custom_'):
|
if field.startswith('custom_'):
|
||||||
field_name = field.replace('custom_', '')
|
field_name = field.replace('custom_', '', 1)
|
||||||
customfield = CustomField.objects.get(name=field_name)
|
customfield = CustomField.objects.get(name=field_name)
|
||||||
cfv = TicketCustomFieldValue(ticket=t,
|
cfv = TicketCustomFieldValue(ticket=t,
|
||||||
field=customfield,
|
field=customfield,
|
||||||
@ -369,6 +369,7 @@ class PublicTicketForm(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.'),
|
||||||
|
max_length=1000,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -407,7 +408,7 @@ class PublicTicketForm(CustomFieldMixin, forms.Form):
|
|||||||
|
|
||||||
for field, value in self.cleaned_data.items():
|
for field, value in self.cleaned_data.items():
|
||||||
if field.startswith('custom_'):
|
if field.startswith('custom_'):
|
||||||
field_name = field.replace('custom_', '')
|
field_name = field.replace('custom_', '', 1)
|
||||||
customfield = CustomField.objects.get(name=field_name)
|
customfield = CustomField.objects.get(name=field_name)
|
||||||
cfv = TicketCustomFieldValue(ticket=t,
|
cfv = TicketCustomFieldValue(ticket=t,
|
||||||
field=customfield,
|
field=customfield,
|
||||||
@ -529,9 +530,9 @@ class TicketCCForm(forms.ModelForm):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(TicketCCForm, self).__init__(*args, **kwargs)
|
super(TicketCCForm, self).__init__(*args, **kwargs)
|
||||||
if helpdesk_settings.HELPDESK_STAFF_ONLY_TICKET_CC:
|
if helpdesk_settings.HELPDESK_STAFF_ONLY_TICKET_CC:
|
||||||
users = User.objects.filter(is_active=True, is_staff=True).order_by('username')
|
users = User.objects.filter(is_active=True, is_staff=True).order_by(User.USERNAME_FIELD)
|
||||||
else:
|
else:
|
||||||
users = User.objects.filter(is_active=True).order_by('username')
|
users = User.objects.filter(is_active=True).order_by(User.USERNAME_FIELD)
|
||||||
self.fields['user'].queryset = users
|
self.fields['user'].queryset = users
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TicketCC
|
model = TicketCC
|
||||||
|
@ -115,7 +115,7 @@ def send_templated_mail(template_name, email_context, recipients, sender=None, b
|
|||||||
elif type(recipients) != list:
|
elif type(recipients) != list:
|
||||||
recipients = [recipients,]
|
recipients = [recipients,]
|
||||||
|
|
||||||
msg = EmailMultiAlternatives( subject_part.replace('\n', ''),
|
msg = EmailMultiAlternatives( subject_part.replace('\n', '').replace('\r', ''),
|
||||||
text_part,
|
text_part,
|
||||||
sender,
|
sender,
|
||||||
recipients,
|
recipients,
|
||||||
|
@ -15,6 +15,7 @@ import imaplib
|
|||||||
import mimetypes
|
import mimetypes
|
||||||
import poplib
|
import poplib
|
||||||
import re
|
import re
|
||||||
|
import socket
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from email.header import decode_header
|
from email.header import decode_header
|
||||||
@ -84,6 +85,22 @@ def process_queue(q, quiet=False):
|
|||||||
if not quiet:
|
if not quiet:
|
||||||
print "Processing: %s" % q
|
print "Processing: %s" % q
|
||||||
|
|
||||||
|
if q.socks_proxy_type and q.socks_proxy_host and q.socks_proxy_port:
|
||||||
|
try:
|
||||||
|
import socks
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError("Queue has been configured with proxy settings, but no socks library was installed. Try to install PySocks via pypi.")
|
||||||
|
|
||||||
|
proxy_type = {
|
||||||
|
'socks4': socks.SOCKS4,
|
||||||
|
'socks5': socks.SOCKS5,
|
||||||
|
}.get(q.socks_proxy_type)
|
||||||
|
|
||||||
|
socks.set_default_proxy(proxy_type=proxy_type, addr=q.socks_proxy_host, port=q.socks_proxy_port)
|
||||||
|
socket.socket = socks.socksocket
|
||||||
|
else:
|
||||||
|
socket.socket = socket._socketobject
|
||||||
|
|
||||||
email_box_type = settings.QUEUE_EMAIL_BOX_TYPE if settings.QUEUE_EMAIL_BOX_TYPE else q.email_box_type
|
email_box_type = settings.QUEUE_EMAIL_BOX_TYPE if settings.QUEUE_EMAIL_BOX_TYPE else q.email_box_type
|
||||||
|
|
||||||
if email_box_type == 'pop3':
|
if email_box_type == 'pop3':
|
||||||
|
32
helpdesk/migrations/0002_socks_proxy.py
Normal file
32
helpdesk/migrations/0002_socks_proxy.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('helpdesk', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='queue',
|
||||||
|
name='socks_proxy_host',
|
||||||
|
field=models.GenericIPAddressField(help_text='Socks proxy IP address. Default: 127.0.0.1', null=True, verbose_name='Socks Proxy Host', blank=True),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='queue',
|
||||||
|
name='socks_proxy_port',
|
||||||
|
field=models.IntegerField(help_text='Socks proxy port number. Default: 9150 (default TOR port)', null=True, verbose_name='Socks Proxy Port', blank=True),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='queue',
|
||||||
|
name='socks_proxy_type',
|
||||||
|
field=models.CharField(choices=[(b'socks4', 'SOCKS4'), (b'socks5', 'SOCKS5')], max_length=8, blank=True, help_text='SOCKS4 or SOCKS5 allows you to proxy your connections through a SOCKS server.', null=True, verbose_name='Socks Proxy Type'),
|
||||||
|
preserve_default=True,
|
||||||
|
),
|
||||||
|
]
|
50
helpdesk/migrations/0003_populate_usersettings.py
Normal file
50
helpdesk/migrations/0003_populate_usersettings.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
from helpdesk.settings import DEFAULT_USER_SETTINGS
|
||||||
|
|
||||||
|
|
||||||
|
def picke_settings(data):
|
||||||
|
"""Pickling as defined at migration's creation time"""
|
||||||
|
import cPickle
|
||||||
|
from helpdesk.lib import b64encode
|
||||||
|
return b64encode(cPickle.dumps(data))
|
||||||
|
|
||||||
|
|
||||||
|
# https://docs.djangoproject.com/en/1.7/topics/migrations/#data-migrations
|
||||||
|
def populate_usersettings(apps, schema_editor):
|
||||||
|
"""Create a UserSettings entry for each existing user.
|
||||||
|
This will only happen once (at install time, or at upgrade)
|
||||||
|
when the UserSettings model doesn't already exist."""
|
||||||
|
|
||||||
|
_User = get_user_model()
|
||||||
|
User = apps.get_model(_User._meta.app_label, _User._meta.model_name)
|
||||||
|
|
||||||
|
# Import historical version of models
|
||||||
|
UserSettings = apps.get_model("helpdesk", "UserSettings")
|
||||||
|
|
||||||
|
settings_pickled = picke_settings(DEFAULT_USER_SETTINGS)
|
||||||
|
|
||||||
|
for u in User.objects.all():
|
||||||
|
try:
|
||||||
|
UserSettings.objects.get(user=u)
|
||||||
|
except UserSettings.DoesNotExist:
|
||||||
|
UserSettings.objects.create(user=u, settings_pickled=settings_pickled)
|
||||||
|
|
||||||
|
|
||||||
|
noop = lambda *args, **kwargs: None
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('helpdesk', '0002_socks_proxy'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(populate_usersettings, reverse_code=noop),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
44
helpdesk/migrations/0004_initial_data_import.py
Normal file
44
helpdesk/migrations/0004_initial_data_import.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import os
|
||||||
|
from sys import path
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
from django.core import serializers
|
||||||
|
|
||||||
|
fixture_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '../fixtures'))
|
||||||
|
fixture_filename = 'emailtemplate.json'
|
||||||
|
|
||||||
|
def deserialize_fixture():
|
||||||
|
fixture_file = os.path.join(fixture_dir, fixture_filename)
|
||||||
|
|
||||||
|
with open(fixture_file, 'rb') as fixture:
|
||||||
|
return list(serializers.deserialize('json', fixture, ignorenonexistent=True))
|
||||||
|
|
||||||
|
|
||||||
|
def load_fixture(apps, schema_editor):
|
||||||
|
objects = deserialize_fixture()
|
||||||
|
|
||||||
|
for obj in objects:
|
||||||
|
obj.save()
|
||||||
|
|
||||||
|
|
||||||
|
def unload_fixture(apps, schema_editor):
|
||||||
|
"Delete all EmailTemplate objects"
|
||||||
|
|
||||||
|
objects = deserialize_fixture()
|
||||||
|
|
||||||
|
EmailTemplate = apps.get_model("helpdesk", "emailtemplate")
|
||||||
|
EmailTemplate.objects.filter(pk__in=[ obj.object.pk for obj in objects ]).delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('helpdesk', '0003_populate_usersettings'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(load_fixture, reverse_code=unload_fixture),
|
||||||
|
]
|
@ -11,6 +11,7 @@ from django.db import models
|
|||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext_lazy as _, ugettext
|
from django.utils.translation import ugettext_lazy as _, ugettext
|
||||||
|
from django import VERSION
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
@ -178,6 +179,29 @@ class Queue(models.Model):
|
|||||||
# 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'),
|
||||||
|
max_length=8,
|
||||||
|
choices=(('socks4', _('SOCKS4')), ('socks5', _('SOCKS5'))),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
help_text=_('SOCKS4 or SOCKS5 allows you to proxy your connections through a SOCKS server.'),
|
||||||
|
)
|
||||||
|
|
||||||
|
socks_proxy_host = models.GenericIPAddressField(
|
||||||
|
_('Socks Proxy Host'),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
help_text=_('Socks proxy IP address. Default: 127.0.0.1'),
|
||||||
|
)
|
||||||
|
|
||||||
|
socks_proxy_port = models.IntegerField(
|
||||||
|
_('Socks Proxy Port'),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
help_text=_('Socks proxy port number. Default: 9150 (default TOR port)'),
|
||||||
|
)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"%s" % self.title
|
return u"%s" % self.title
|
||||||
|
|
||||||
@ -202,6 +226,15 @@ class Queue(models.Model):
|
|||||||
if self.email_box_type == 'imap' and not self.email_box_imap_folder:
|
if self.email_box_type == 'imap' and not self.email_box_imap_folder:
|
||||||
self.email_box_imap_folder = 'INBOX'
|
self.email_box_imap_folder = 'INBOX'
|
||||||
|
|
||||||
|
if self.socks_proxy_type:
|
||||||
|
if not self.socks_proxy_host:
|
||||||
|
self.socks_proxy_host = '127.0.0.1'
|
||||||
|
if not self.socks_proxy_port:
|
||||||
|
self.socks_proxy_port = 9150
|
||||||
|
else:
|
||||||
|
self.socks_proxy_host = None
|
||||||
|
self.socks_proxy_port = None
|
||||||
|
|
||||||
if not self.email_box_port:
|
if not self.email_box_port:
|
||||||
if self.email_box_type == 'imap' and self.email_box_ssl:
|
if self.email_box_type == 'imap' and self.email_box_ssl:
|
||||||
self.email_box_port = 993
|
self.email_box_port = 993
|
||||||
@ -351,7 +384,7 @@ class Ticket(models.Model):
|
|||||||
if self.assigned_to.get_full_name():
|
if self.assigned_to.get_full_name():
|
||||||
return self.assigned_to.get_full_name()
|
return self.assigned_to.get_full_name()
|
||||||
else:
|
else:
|
||||||
return self.assigned_to.username
|
return self.assigned_to.get_username()
|
||||||
get_assigned_to = property(_get_assigned_to)
|
get_assigned_to = property(_get_assigned_to)
|
||||||
|
|
||||||
def _get_ticket(self):
|
def _get_ticket(self):
|
||||||
@ -995,7 +1028,7 @@ class UserSettings(models.Model):
|
|||||||
verbose_name_plural = _('User Settings')
|
verbose_name_plural = _('User Settings')
|
||||||
|
|
||||||
|
|
||||||
def create_usersettings(sender, created_models=[], instance=None, created=False, **kwargs):
|
def create_usersettings(sender, instance, created, **kwargs):
|
||||||
"""
|
"""
|
||||||
Helper function to create UserSettings instances as
|
Helper function to create UserSettings instances as
|
||||||
required, eg when we first create the UserSettings database
|
required, eg when we first create the UserSettings database
|
||||||
@ -1005,30 +1038,20 @@ def create_usersettings(sender, created_models=[], instance=None, created=False,
|
|||||||
'DoesNotExist: UserSettings matching query does not exist.' errors.
|
'DoesNotExist: UserSettings matching query does not exist.' errors.
|
||||||
"""
|
"""
|
||||||
from helpdesk.settings import DEFAULT_USER_SETTINGS
|
from helpdesk.settings import DEFAULT_USER_SETTINGS
|
||||||
if sender == settings.AUTH_USER_MODEL and created:
|
if created:
|
||||||
# This is a new user, so lets create their settings entry.
|
UserSettings.objects.create(user=instance, settings=DEFAULT_USER_SETTINGS)
|
||||||
s, created = UserSettings.objects.get_or_create(user=instance, defaults={'settings': DEFAULT_USER_SETTINGS})
|
|
||||||
s.save()
|
|
||||||
elif UserSettings in created_models:
|
|
||||||
User = get_user_model()
|
|
||||||
# We just created the UserSettings model, lets create a UserSettings
|
|
||||||
# entry for each existing user. This will only happen once (at install
|
|
||||||
# time, or at upgrade) when the UserSettings model doesn't already
|
|
||||||
# exist.
|
|
||||||
for u in User.objects.all():
|
|
||||||
try:
|
|
||||||
s = UserSettings.objects.get(user=u)
|
|
||||||
except UserSettings.DoesNotExist:
|
|
||||||
s = UserSettings(user=u, settings=DEFAULT_USER_SETTINGS)
|
|
||||||
s.save()
|
|
||||||
|
|
||||||
models.signals.post_syncdb.connect(create_usersettings)
|
|
||||||
try:
|
try:
|
||||||
|
# Connecting via settings.AUTH_USER_MODEL (string) fails in Django < 1.7. We need the actual model there.
|
||||||
|
# https://docs.djangoproject.com/en/1.7/topics/auth/customizing/#referencing-the-user-model
|
||||||
|
if VERSION < (1, 7):
|
||||||
|
raise ValueError
|
||||||
models.signals.post_save.connect(create_usersettings, sender=settings.AUTH_USER_MODEL)
|
models.signals.post_save.connect(create_usersettings, sender=settings.AUTH_USER_MODEL)
|
||||||
except:
|
except:
|
||||||
signal_user = get_user_model()
|
signal_user = get_user_model()
|
||||||
models.signals.post_save.connect(create_usersettings, sender=signal_user)
|
models.signals.post_save.connect(create_usersettings, sender=signal_user)
|
||||||
|
|
||||||
|
|
||||||
class IgnoreEmail(models.Model):
|
class IgnoreEmail(models.Model):
|
||||||
"""
|
"""
|
||||||
This model lets us easily ignore e-mails from certain senders when
|
This model lets us easily ignore e-mails from certain senders when
|
||||||
|
@ -0,0 +1,249 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from south.utils import datetime_utils as datetime
|
||||||
|
from south.db import db
|
||||||
|
from south.v2 import SchemaMigration
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(SchemaMigration):
|
||||||
|
|
||||||
|
def forwards(self, orm):
|
||||||
|
# Adding field 'Queue.socks_proxy_type'
|
||||||
|
db.add_column(u'helpdesk_queue', 'socks_proxy_type',
|
||||||
|
self.gf('django.db.models.fields.CharField')(max_length=8, null=True, blank=True),
|
||||||
|
keep_default=False)
|
||||||
|
|
||||||
|
# Adding field 'Queue.socks_proxy_host'
|
||||||
|
db.add_column(u'helpdesk_queue', 'socks_proxy_host',
|
||||||
|
self.gf('django.db.models.fields.GenericIPAddressField')(max_length=39, null=True, blank=True),
|
||||||
|
keep_default=False)
|
||||||
|
|
||||||
|
# Adding field 'Queue.socks_proxy_port'
|
||||||
|
db.add_column(u'helpdesk_queue', 'socks_proxy_port',
|
||||||
|
self.gf('django.db.models.fields.IntegerField')(null=True, blank=True),
|
||||||
|
keep_default=False)
|
||||||
|
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
# Deleting field 'Queue.socks_proxy_type'
|
||||||
|
db.delete_column(u'helpdesk_queue', 'socks_proxy_type')
|
||||||
|
|
||||||
|
# Deleting field 'Queue.socks_proxy_host'
|
||||||
|
db.delete_column(u'helpdesk_queue', 'socks_proxy_host')
|
||||||
|
|
||||||
|
# Deleting field 'Queue.socks_proxy_port'
|
||||||
|
db.delete_column(u'helpdesk_queue', 'socks_proxy_port')
|
||||||
|
|
||||||
|
|
||||||
|
models = {
|
||||||
|
u'auth.group': {
|
||||||
|
'Meta': {'object_name': 'Group'},
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||||
|
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
u'auth.permission': {
|
||||||
|
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||||
|
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||||
|
},
|
||||||
|
u'auth.user': {
|
||||||
|
'Meta': {'object_name': 'User'},
|
||||||
|
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||||
|
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||||
|
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
|
||||||
|
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||||
|
},
|
||||||
|
u'contenttypes.contenttype': {
|
||||||
|
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||||
|
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||||
|
},
|
||||||
|
u'helpdesk.attachment': {
|
||||||
|
'Meta': {'ordering': "['filename']", 'object_name': 'Attachment'},
|
||||||
|
'file': ('django.db.models.fields.files.FileField', [], {'max_length': '1000'}),
|
||||||
|
'filename': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
|
||||||
|
'followup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['helpdesk.FollowUp']"}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'size': ('django.db.models.fields.IntegerField', [], {})
|
||||||
|
},
|
||||||
|
u'helpdesk.customfield': {
|
||||||
|
'Meta': {'object_name': 'CustomField'},
|
||||||
|
'data_type': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'decimal_places': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'empty_selection_list': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'help_text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'label': ('django.db.models.fields.CharField', [], {'max_length': "'30'"}),
|
||||||
|
'list_values': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'max_length': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}),
|
||||||
|
'ordering': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'required': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'staff_only': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
|
||||||
|
},
|
||||||
|
u'helpdesk.emailtemplate': {
|
||||||
|
'Meta': {'ordering': "['template_name', 'locale']", 'object_name': 'EmailTemplate'},
|
||||||
|
'heading': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'html': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'locale': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'plain_text': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
'subject': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'template_name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||||
|
},
|
||||||
|
u'helpdesk.escalationexclusion': {
|
||||||
|
'Meta': {'object_name': 'EscalationExclusion'},
|
||||||
|
'date': ('django.db.models.fields.DateField', [], {}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'queues': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['helpdesk.Queue']", 'null': 'True', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
u'helpdesk.followup': {
|
||||||
|
'Meta': {'ordering': "['date']", 'object_name': 'FollowUp'},
|
||||||
|
'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'new_status': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['helpdesk.Ticket']"}),
|
||||||
|
'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
u'helpdesk.ignoreemail': {
|
||||||
|
'Meta': {'object_name': 'IgnoreEmail'},
|
||||||
|
'date': ('django.db.models.fields.DateField', [], {'blank': 'True'}),
|
||||||
|
'email_address': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'keep_in_mailbox': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'queues': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['helpdesk.Queue']", 'null': 'True', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
u'helpdesk.kbcategory': {
|
||||||
|
'Meta': {'ordering': "['title']", 'object_name': 'KBCategory'},
|
||||||
|
'description': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
|
||||||
|
'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||||
|
},
|
||||||
|
u'helpdesk.kbitem': {
|
||||||
|
'Meta': {'ordering': "['title']", 'object_name': 'KBItem'},
|
||||||
|
'answer': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
'category': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['helpdesk.KBCategory']"}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'last_updated': ('django.db.models.fields.DateTimeField', [], {'blank': 'True'}),
|
||||||
|
'question': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
'recommendations': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||||
|
'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'votes': ('django.db.models.fields.IntegerField', [], {'default': '0'})
|
||||||
|
},
|
||||||
|
u'helpdesk.presetreply': {
|
||||||
|
'Meta': {'ordering': "['name']", 'object_name': 'PreSetReply'},
|
||||||
|
'body': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'queues': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['helpdesk.Queue']", 'null': 'True', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
u'helpdesk.queue': {
|
||||||
|
'Meta': {'ordering': "('title',)", 'object_name': 'Queue'},
|
||||||
|
'allow_email_submission': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'allow_public_submission': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'email_box_host': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'email_box_imap_folder': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'email_box_interval': ('django.db.models.fields.IntegerField', [], {'default': "'5'", 'null': 'True', 'blank': 'True'}),
|
||||||
|
'email_box_last_check': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'email_box_pass': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'email_box_port': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'email_box_ssl': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'email_box_type': ('django.db.models.fields.CharField', [], {'max_length': '5', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'email_box_user': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'escalate_days': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'locale': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'new_ticket_cc': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
|
||||||
|
'socks_proxy_host': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'socks_proxy_port': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'socks_proxy_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'updated_ticket_cc': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
u'helpdesk.savedsearch': {
|
||||||
|
'Meta': {'object_name': 'SavedSearch'},
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'query': ('django.db.models.fields.TextField', [], {}),
|
||||||
|
'shared': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
|
||||||
|
},
|
||||||
|
u'helpdesk.ticket': {
|
||||||
|
'Meta': {'ordering': "('id',)", 'object_name': 'Ticket'},
|
||||||
|
'assigned_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'assigned_to'", 'null': 'True', 'to': u"orm['auth.User']"}),
|
||||||
|
'created': ('django.db.models.fields.DateTimeField', [], {'blank': 'True'}),
|
||||||
|
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'due_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'last_escalation': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'modified': ('django.db.models.fields.DateTimeField', [], {'blank': 'True'}),
|
||||||
|
'on_hold': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'priority': ('django.db.models.fields.IntegerField', [], {'default': '3', 'blank': '3'}),
|
||||||
|
'queue': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['helpdesk.Queue']"}),
|
||||||
|
'resolution': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
|
||||||
|
'submitter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'title': ('django.db.models.fields.CharField', [], {'max_length': '200'})
|
||||||
|
},
|
||||||
|
u'helpdesk.ticketcc': {
|
||||||
|
'Meta': {'object_name': 'TicketCC'},
|
||||||
|
'can_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'can_view': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['helpdesk.Ticket']"}),
|
||||||
|
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
u'helpdesk.ticketchange': {
|
||||||
|
'Meta': {'object_name': 'TicketChange'},
|
||||||
|
'field': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'followup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['helpdesk.FollowUp']"}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'new_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'old_value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
u'helpdesk.ticketcustomfieldvalue': {
|
||||||
|
'Meta': {'object_name': 'TicketCustomFieldValue'},
|
||||||
|
'field': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['helpdesk.CustomField']"}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['helpdesk.Ticket']"}),
|
||||||
|
'value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
u'helpdesk.ticketdependency': {
|
||||||
|
'Meta': {'unique_together': "(('ticket', 'depends_on'),)", 'object_name': 'TicketDependency'},
|
||||||
|
'depends_on': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'depends_on'", 'to': u"orm['helpdesk.Ticket']"}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'ticket': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ticketdependency'", 'to': u"orm['helpdesk.Ticket']"})
|
||||||
|
},
|
||||||
|
u'helpdesk.usersettings': {
|
||||||
|
'Meta': {'object_name': 'UserSettings'},
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'settings_pickled': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_apps = ['helpdesk']
|
90
helpdesk/south_migrations/0011_populate_usersettings.py
Normal file
90
helpdesk/south_migrations/0011_populate_usersettings.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from south.utils import datetime_utils as datetime
|
||||||
|
from south.db import db
|
||||||
|
from south.v2 import DataMigration
|
||||||
|
from django.db import models
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from helpdesk.settings import DEFAULT_USER_SETTINGS
|
||||||
|
|
||||||
|
|
||||||
|
def pickle_settings(data):
|
||||||
|
"""Pickling as defined at migration's creation time"""
|
||||||
|
import cPickle
|
||||||
|
from helpdesk.lib import b64encode
|
||||||
|
return b64encode(cPickle.dumps(data))
|
||||||
|
|
||||||
|
|
||||||
|
# https://docs.djangoproject.com/en/1.7/topics/migrations/#data-migrations
|
||||||
|
def populate_usersettings(orm):
|
||||||
|
"""Create a UserSettings entry for each existing user.
|
||||||
|
This will only happen once (at install time, or at upgrade)
|
||||||
|
when the UserSettings model doesn't already exist."""
|
||||||
|
|
||||||
|
_User = get_user_model()
|
||||||
|
|
||||||
|
# Import historical version of models
|
||||||
|
User = orm[_User._meta.app_label+'.'+_User._meta.model_name]
|
||||||
|
UserSettings = orm["helpdesk"+'.'+"UserSettings"]
|
||||||
|
settings_pickled = pickle_settings(DEFAULT_USER_SETTINGS)
|
||||||
|
|
||||||
|
for u in User.objects.all():
|
||||||
|
try:
|
||||||
|
UserSettings.objects.get(user=u)
|
||||||
|
except UserSettings.DoesNotExist:
|
||||||
|
UserSettings.objects.create(user=u, settings_pickled=settings_pickled)
|
||||||
|
|
||||||
|
class Migration(DataMigration):
|
||||||
|
|
||||||
|
def forwards(self, orm):
|
||||||
|
populate_usersettings(orm)
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
pass
|
||||||
|
|
||||||
|
models = {
|
||||||
|
u'auth.group': {
|
||||||
|
'Meta': {'object_name': 'Group'},
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||||
|
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
u'auth.permission': {
|
||||||
|
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||||
|
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||||
|
},
|
||||||
|
u'auth.user': {
|
||||||
|
'Meta': {'object_name': 'User'},
|
||||||
|
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||||
|
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||||
|
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
|
||||||
|
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||||
|
},
|
||||||
|
u'contenttypes.contenttype': {
|
||||||
|
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||||
|
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||||
|
},
|
||||||
|
u'helpdesk.usersettings': {
|
||||||
|
'Meta': {'object_name': 'UserSettings'},
|
||||||
|
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'settings_pickled': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||||
|
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['auth.User']", 'unique': 'True'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_apps = ['helpdesk']
|
||||||
|
symmetrical = True
|
@ -17,7 +17,7 @@
|
|||||||
<!--link rel='stylesheet' href='{{ STATIC_URL }}helpdesk/jquery-smoothness-theme/jquery-ui-1.8.9.custom.css' type='text/css' /-->
|
<!--link rel='stylesheet' href='{{ STATIC_URL }}helpdesk/jquery-smoothness-theme/jquery-ui-1.8.9.custom.css' type='text/css' /-->
|
||||||
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.2/js/bootstrap.min.js"></script>
|
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.2/js/bootstrap.min.js"></script>
|
||||||
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css" rel="stylesheet">
|
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link rel='alternate' href='{% url 'helpdesk_rss_user' user.username %}' type='application/rss+xml' title='{% trans "My Open Tickets" %}' />
|
<link rel='alternate' href='{% url 'helpdesk_rss_user' user.get_username %}' type='application/rss+xml' title='{% trans "My Open Tickets" %}' />
|
||||||
<link rel='alternate' href='{% url 'helpdesk_rss_activity' %}' type='application/rss+xml' title='{% trans "All Recent Activity" %}' />
|
<link rel='alternate' href='{% url 'helpdesk_rss_activity' %}' type='application/rss+xml' title='{% trans "All Recent Activity" %}' />
|
||||||
<link rel='alternate' href='{% url 'helpdesk_rss_unassigned' %}' type='application/rss+xml' title='{% trans "Unassigned Tickets" %}' />
|
<link rel='alternate' href='{% url 'helpdesk_rss_unassigned' %}' type='application/rss+xml' title='{% trans "Unassigned Tickets" %}' />
|
||||||
|
|
||||||
|
@ -26,13 +26,13 @@
|
|||||||
{% for q in user_saved_queries_ %}
|
{% for q in user_saved_queries_ %}
|
||||||
<li><a href="{% url 'helpdesk_list' %}?saved_query={{ q.id }}">{{ q.title }}
|
<li><a href="{% url 'helpdesk_list' %}?saved_query={{ q.id }}">{{ q.title }}
|
||||||
{% if q.shared %}
|
{% if q.shared %}
|
||||||
(Shared{% ifnotequal user q.user %} by {{ q.user.username }}{% endifnotequal %})
|
(Shared{% ifnotequal user q.user %} by {{ q.user.get_username }}{% endifnotequal %})
|
||||||
{% endif %}</a></li>
|
{% endif %}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class="headerlink dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#"><span class="glyphicon glyphicon-user"></span> <span class="nav-text">{{ user.get_full_name|default:user.username }} <b class="caret"></b></span></a>
|
<li class="headerlink dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#"><span class="glyphicon glyphicon-user"></span> <span class="nav-text">{{ user.get_full_name|default:user.get_username }} <b class="caret"></b></span></a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a href='{% url 'helpdesk_user_settings' %}'>{% trans "User Settings" %}</a></li>
|
<li><a href='{% url 'helpdesk_user_settings' %}'>{% trans "User Settings" %}</a></li>
|
||||||
{% if helpdesk_settings.HELPDESK_SHOW_CHANGE_PASSWORD and user.has_usable_password %}
|
{% if helpdesk_settings.HELPDESK_SHOW_CHANGE_PASSWORD and user.has_usable_password %}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<p>{% trans "The following RSS feeds are available for you to monitor using your preferred RSS software. With the exception of the 'Latest Activity' feed, all feeds provide information only on Open and Reopened cases. This ensures your RSS reader isn't full of information about closed or historical tasks." %}</p>
|
<p>{% trans "The following RSS feeds are available for you to monitor using your preferred RSS software. With the exception of the 'Latest Activity' feed, all feeds provide information only on Open and Reopened cases. This ensures your RSS reader isn't full of information about closed or historical tasks." %}</p>
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt><a href='{% url 'helpdesk_rss_user' user.username %}'><img src='{{ STATIC_URL }}helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "My Open Tickets" %}' border='0' />{% trans "My Open Tickets" %}</a></dt>
|
<dt><a href='{% url 'helpdesk_rss_user' user.get_username %}'><img src='{{ STATIC_URL }}helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "My Open Tickets" %}' border='0' />{% trans "My Open Tickets" %}</a></dt>
|
||||||
<dd>{% trans "A summary of your open tickets - useful for getting alerted to new tickets opened for you" %}</dd>
|
<dd>{% trans "A summary of your open tickets - useful for getting alerted to new tickets opened for you" %}</dd>
|
||||||
|
|
||||||
<dt><a href='{% url 'helpdesk_rss_activity' %}'><img src='{{ STATIC_URL }}helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "Latest Activity" %}' border='0' />{% trans "Latest Activity" %}</a></dt>
|
<dt><a href='{% url 'helpdesk_rss_activity' %}'><img src='{{ STATIC_URL }}helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "Latest Activity" %}' border='0' />{% trans "Latest Activity" %}</a></dt>
|
||||||
@ -28,7 +28,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{{ queue.title }}</td>
|
<td>{{ queue.title }}</td>
|
||||||
<td align='center'><a href='{% url 'helpdesk_rss_queue' queue.slug %}'><img src='{{ STATIC_URL }}helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "Open Tickets" %}' border='0' /></a></td>
|
<td align='center'><a href='{% url 'helpdesk_rss_queue' queue.slug %}'><img src='{{ STATIC_URL }}helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "Open Tickets" %}' border='0' /></a></td>
|
||||||
<td align='center'><a href='{% url 'helpdesk_rss_user_queue' user.username queue.slug %}'><img src='{{ STATIC_URL }}helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "My Open Tickets" %}' border='0' /></a></td>
|
<td align='center'><a href='{% url 'helpdesk_rss_user_queue' user.get_username queue.slug %}'><img src='{{ STATIC_URL }}helpdesk/rss_icon.png' width='14' height='14' alt='{% trans "RSS Icon" %}' title='{% trans "My Open Tickets" %}' border='0' /></a></td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% extends "helpdesk/base.html" %}{% load i18n %}{% load url from future %}
|
{% extends "helpdesk/base.html" %}{% load i18n %}{% load url from future %}{% load user_admin_url %}
|
||||||
|
|
||||||
{% block helpdesk_title %}{% trans "Change System Settings" %}{% endblock %}
|
{% block helpdesk_title %}{% trans "Change System Settings" %}{% endblock %}
|
||||||
|
|
||||||
@ -14,6 +14,6 @@
|
|||||||
<li><a href='{% url 'admin:helpdesk_kbcategory_changelist' %}'>{% trans "Maintain Knowledgebase Categories" %}</a></li>
|
<li><a href='{% url 'admin:helpdesk_kbcategory_changelist' %}'>{% trans "Maintain Knowledgebase Categories" %}</a></li>
|
||||||
<li><a href='{% url 'admin:helpdesk_kbitem_changelist' %}'>{% trans "Maintain Knowledgebase Items" %}</a></li>
|
<li><a href='{% url 'admin:helpdesk_kbitem_changelist' %}'>{% trans "Maintain Knowledgebase Items" %}</a></li>
|
||||||
<li><a href='{% url 'admin:helpdesk_emailtemplate_changelist' %}'>{% trans "Maintain E-Mail Templates" %}</a></li>
|
<li><a href='{% url 'admin:helpdesk_emailtemplate_changelist' %}'>{% trans "Maintain E-Mail Templates" %}</a></li>
|
||||||
<li><a href='{% url 'admin:auth_user_changelist' %}'>{% trans "Maintain Users" %}</a></li>
|
<li><a href='{% url 'changelist'|user_admin_url %}'>{% trans "Maintain Users" %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<tr class='row_tablehead'><td colspan='2'><h3>{{ ticket.id }}. {{ ticket.title }} [{{ ticket.get_status }}]</h3> <span class='ticket_toolbar'>
|
<tr class='row_tablehead'><td colspan='2'><h3>{{ ticket.id }}. {{ ticket.title }} [{{ ticket.get_status }}]</h3> <span class='ticket_toolbar'>
|
||||||
<a href='{% url 'helpdesk_edit' ticket.id %}' class="ticket-edit"><span class="glyphicon glyphicon-pencil"></span> Edit</a>
|
<a href='{% url 'helpdesk_edit' ticket.id %}' class="ticket-edit"><span class="glyphicon glyphicon-pencil"></span> Edit</a>
|
||||||
| <a href='{% url 'helpdesk_delete' ticket.id %}' class="ticket-delete"><span class="glyphicon glyphicon-remove"></span> Delete</a>
|
| <a href='{% url 'helpdesk_delete' ticket.id %}' class="ticket-delete"><span class="glyphicon glyphicon-remove"></span> Delete</a>
|
||||||
{% if ticket.on_hold %} | <a href='unhold/' class="ticket-hold">{% trans "Unhold" %}</a>{% else %} | <a href='hold/' class="ticket-hold">{% trans "Hold" %}</a>{% endif %}
|
{% if ticket.on_hold %} | <a href='{% url 'helpdesk_unhold' ticket.id %}' class="ticket-hold">{% trans "Unhold" %}</a>{% else %} | <a href='{% url 'helpdesk_hold' ticket.id %}' class="ticket-hold">{% trans "Hold" %}</a>{% endif %}
|
||||||
</span></td></tr>
|
</span></td></tr>
|
||||||
<tr><th colspan='2'>{% blocktrans with ticket.queue as queue %}Queue: {{ queue }}{% endblocktrans %}</th></tr>
|
<tr><th colspan='2'>{% blocktrans with ticket.queue as queue %}Queue: {{ queue }}{% endblocktrans %}</th></tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -106,7 +106,7 @@ $(document).ready(function() {
|
|||||||
<select id='id_owners' name='assigned_to' multiple='selected' size='5'>
|
<select id='id_owners' name='assigned_to' multiple='selected' size='5'>
|
||||||
{% for u in user_choices %}
|
{% for u in user_choices %}
|
||||||
<option value='{{ u.id }}'{% if u.id|in_list:query_params.filtering.assigned_to__id__in %} selected='selected'{% endif %}>
|
<option value='{{ u.id }}'{% if u.id|in_list:query_params.filtering.assigned_to__id__in %} selected='selected'{% endif %}>
|
||||||
{{ u.username }}{% ifequal u user %} {% trans "(ME)" %}{% endifequal %}
|
{{ u.get_username }}{% ifequal u user %} {% trans "(ME)" %}{% endifequal %}
|
||||||
</option>
|
</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
@ -199,7 +199,7 @@ $(document).ready(function() {
|
|||||||
<form method='get' action='{% url 'helpdesk_list' %}'>
|
<form method='get' action='{% url 'helpdesk_list' %}'>
|
||||||
<p><label for='id_query_selector'>{% trans "Query" %}</label> <select name='saved_query' id='id_query_selector'>
|
<p><label for='id_query_selector'>{% trans "Query" %}</label> <select name='saved_query' id='id_query_selector'>
|
||||||
{% for q in user_saved_queries %}
|
{% for q in user_saved_queries %}
|
||||||
<option value='{{ q.id }}'>{{ q.title }}{% if q.shared %} (Shared{% ifnotequal user q.user %} by {{ q.user.username }}{% endifnotequal %}){% endif %}</option>
|
<option value='{{ q.id }}'>{{ q.title }}{% if q.shared %} (Shared{% ifnotequal user q.user %} by {{ q.user.get_username }}{% endifnotequal %}){% endif %}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select></p>
|
</select></p>
|
||||||
<input class="btn btn-primary" type='submit' value='{% trans "Run Query" %}'>
|
<input class="btn btn-primary" type='submit' value='{% trans "Run Query" %}'>
|
||||||
@ -257,7 +257,7 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
<p><label>{% trans "Select:" %} </label> <a href='#select_all' id='select_all'>{% trans "All" %}</a> <a href='#select_none' id='select_none'>{% trans "None" %}</a> <a href='#select_inverse' id='select_inverse'>{% trans "Inverse" %}</a></p>
|
<p><label>{% trans "Select:" %} </label> <a href='#select_all' id='select_all'>{% trans "All" %}</a> <a href='#select_none' id='select_none'>{% trans "None" %}</a> <a href='#select_inverse' id='select_inverse'>{% trans "Inverse" %}</a></p>
|
||||||
|
|
||||||
<p><label for='id_mass_action'>{% trans "With Selected Tickets:" %}</label> <select name='action' id='id_mass_action'><option value='take'>{% trans "Take (Assign to me)" %}</option><option value='delete'>{% trans "Delete" %}</option><optgroup label='{% trans "Close" %}'><option value='close'>{% trans "Close (Don't Send E-Mail)" %}</option><option value='close_public'>{% trans "Close (Send E-Mail)" %}</option></optgroup><optgroup label='{% trans "Assign To" %}'><option value='unassign'>{% trans "Nobody (Unassign)" %}</option>{% for u in user_choices %}<option value='assign_{{ u.id }}'>{{ u.username }}</option>{% endfor %}</optgroup></select> <input type='submit' value='Go' /></p>
|
<p><label for='id_mass_action'>{% trans "With Selected Tickets:" %}</label> <select name='action' id='id_mass_action'><option value='take'>{% trans "Take (Assign to me)" %}</option><option value='delete'>{% trans "Delete" %}</option><optgroup label='{% trans "Close" %}'><option value='close'>{% trans "Close (Don't Send E-Mail)" %}</option><option value='close_public'>{% trans "Close (Send E-Mail)" %}</option></optgroup><optgroup label='{% trans "Assign To" %}'><option value='unassign'>{% trans "Nobody (Unassign)" %}</option>{% for u in user_choices %}<option value='assign_{{ u.id }}'>{{ u.get_username }}</option>{% endfor %}</optgroup></select> <input type='submit' value='Go' /></p>
|
||||||
{% csrf_token %}</form>
|
{% csrf_token %}</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
22
helpdesk/templatetags/user_admin_url.py
Normal file
22
helpdesk/templatetags/user_admin_url.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"""
|
||||||
|
django-helpdesk - A Django powered ticket tracker for small enterprise.
|
||||||
|
|
||||||
|
(c) Copyright 2008 Jutda. All Rights Reserved. See LICENSE for details.
|
||||||
|
|
||||||
|
templatetags/admin_url.py - Very simple template tag allow linking to the
|
||||||
|
right auth user model urls.
|
||||||
|
|
||||||
|
{% url 'changelist'|user_admin_url %}
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django import template
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
|
def user_admin_url(action):
|
||||||
|
user = get_user_model()
|
||||||
|
return 'admin:%s_%s_%s' % (
|
||||||
|
user._meta.app_label, user._meta.module_name.lower(),
|
||||||
|
action)
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
register.filter(user_admin_url)
|
@ -25,7 +25,7 @@ class TestKBDisabled(TestCase):
|
|||||||
"""Test proper rendering of navigation.html by accessing the dashboard"""
|
"""Test proper rendering of navigation.html by accessing the dashboard"""
|
||||||
from django.core.urlresolvers import NoReverseMatch
|
from django.core.urlresolvers import NoReverseMatch
|
||||||
|
|
||||||
self.client.login(username=get_staff_user().username, password='password')
|
self.client.login(username=get_staff_user().get_username(), password='password')
|
||||||
self.assertRaises(NoReverseMatch, reverse, 'helpdesk_kb_index')
|
self.assertRaises(NoReverseMatch, reverse, 'helpdesk_kb_index')
|
||||||
try:
|
try:
|
||||||
response = self.client.get(reverse('helpdesk_dashboard'))
|
response = self.client.get(reverse('helpdesk_dashboard'))
|
||||||
|
@ -5,6 +5,8 @@ from django.test.client import Client
|
|||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
class TicketBasicsTestCase(TestCase):
|
class TicketBasicsTestCase(TestCase):
|
||||||
|
fixtures = ['emailtemplate.json']
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.queue_public = Queue.objects.create(title='Queue 1', slug='q1', allow_public_submission=True, new_ticket_cc='new.public@example.com', updated_ticket_cc='update.public@example.com')
|
self.queue_public = Queue.objects.create(title='Queue 1', slug='q1', allow_public_submission=True, new_ticket_cc='new.public@example.com', updated_ticket_cc='update.public@example.com')
|
||||||
self.queue_private = Queue.objects.create(title='Queue 2', slug='q2', allow_public_submission=False, new_ticket_cc='new.private@example.com', updated_ticket_cc='update.private@example.com')
|
self.queue_private = Queue.objects.create(title='Queue 2', slug='q2', allow_public_submission=False, new_ticket_cc='new.private@example.com', updated_ticket_cc='update.private@example.com')
|
||||||
|
@ -110,7 +110,7 @@ class API:
|
|||||||
def api_public_create_ticket(self):
|
def api_public_create_ticket(self):
|
||||||
form = TicketForm(self.request.POST)
|
form = TicketForm(self.request.POST)
|
||||||
form.fields['queue'].choices = [[q.id, q.title] for q in Queue.objects.all()]
|
form.fields['queue'].choices = [[q.id, q.title] for q in Queue.objects.all()]
|
||||||
form.fields['assigned_to'].choices = [[u.id, u.username] for u in User.objects.filter(is_active=True)]
|
form.fields['assigned_to'].choices = [[u.id, u.get_username()] for u in User.objects.filter(is_active=True)]
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
ticket = form.save(user=self.request.user)
|
ticket = form.save(user=self.request.user)
|
||||||
|
@ -38,22 +38,22 @@ class OpenTicketsByUser(Feed):
|
|||||||
if obj['queue']:
|
if obj['queue']:
|
||||||
return _("Helpdesk: Open Tickets in queue %(queue)s for %(username)s") % {
|
return _("Helpdesk: Open Tickets in queue %(queue)s for %(username)s") % {
|
||||||
'queue': obj['queue'].title,
|
'queue': obj['queue'].title,
|
||||||
'username': obj['user'].username,
|
'username': obj['user'].get_username(),
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
return _("Helpdesk: Open Tickets for %(username)s") % {
|
return _("Helpdesk: Open Tickets for %(username)s") % {
|
||||||
'username': obj['user'].username,
|
'username': obj['user'].get_username(),
|
||||||
}
|
}
|
||||||
|
|
||||||
def description(self, obj):
|
def description(self, obj):
|
||||||
if obj['queue']:
|
if obj['queue']:
|
||||||
return _("Open and Reopened Tickets in queue %(queue)s for %(username)s") % {
|
return _("Open and Reopened Tickets in queue %(queue)s for %(username)s") % {
|
||||||
'queue': obj['queue'].title,
|
'queue': obj['queue'].title,
|
||||||
'username': obj['user'].username,
|
'username': obj['user'].get_username(),
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
return _("Open and Reopened Tickets for %(username)s") % {
|
return _("Open and Reopened Tickets for %(username)s") % {
|
||||||
'username': obj['user'].username,
|
'username': obj['user'].get_username(),
|
||||||
}
|
}
|
||||||
|
|
||||||
def link(self, obj):
|
def link(self, obj):
|
||||||
@ -90,7 +90,7 @@ class OpenTicketsByUser(Feed):
|
|||||||
|
|
||||||
def item_author_name(self, item):
|
def item_author_name(self, item):
|
||||||
if item.assigned_to:
|
if item.assigned_to:
|
||||||
return item.assigned_to.username
|
return item.assigned_to.get_username()
|
||||||
else:
|
else:
|
||||||
return _('Unassigned')
|
return _('Unassigned')
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ class UnassignedTickets(Feed):
|
|||||||
|
|
||||||
def item_author_name(self, item):
|
def item_author_name(self, item):
|
||||||
if item.assigned_to:
|
if item.assigned_to:
|
||||||
return item.assigned_to.username
|
return item.assigned_to.get_username()
|
||||||
else:
|
else:
|
||||||
return _('Unassigned')
|
return _('Unassigned')
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ class OpenTicketsByQueue(Feed):
|
|||||||
|
|
||||||
def item_author_name(self, item):
|
def item_author_name(self, item):
|
||||||
if item.assigned_to:
|
if item.assigned_to:
|
||||||
return item.assigned_to.username
|
return item.assigned_to.get_username()
|
||||||
else:
|
else:
|
||||||
return _('Unassigned')
|
return _('Unassigned')
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ def return_ticketccstring_and_show_subscribe(user, ticket):
|
|||||||
''' used in view_ticket() and followup_edit()'''
|
''' used in view_ticket() and followup_edit()'''
|
||||||
# create the ticketcc_string and check whether current user is already
|
# create the ticketcc_string and check whether current user is already
|
||||||
# subscribed
|
# subscribed
|
||||||
username = user.username.upper()
|
username = user.get_username().upper()
|
||||||
useremail = user.email.upper()
|
useremail = user.email.upper()
|
||||||
strings_to_check = list()
|
strings_to_check = list()
|
||||||
strings_to_check.append(username)
|
strings_to_check.append(username)
|
||||||
@ -364,7 +364,7 @@ def update_ticket(request, ticket_id, public=False):
|
|||||||
if owner != 0 and ((ticket.assigned_to and owner != ticket.assigned_to.id) or not ticket.assigned_to):
|
if owner != 0 and ((ticket.assigned_to and owner != ticket.assigned_to.id) or not ticket.assigned_to):
|
||||||
new_user = User.objects.get(id=owner)
|
new_user = User.objects.get(id=owner)
|
||||||
f.title = _('Assigned to %(username)s') % {
|
f.title = _('Assigned to %(username)s') % {
|
||||||
'username': new_user.username,
|
'username': new_user.get_username(),
|
||||||
}
|
}
|
||||||
ticket.assigned_to = new_user
|
ticket.assigned_to = new_user
|
||||||
reassigned = True
|
reassigned = True
|
||||||
@ -571,7 +571,7 @@ def mass_update(request):
|
|||||||
if action == 'assign' and t.assigned_to != user:
|
if action == 'assign' and t.assigned_to != user:
|
||||||
t.assigned_to = user
|
t.assigned_to = user
|
||||||
t.save()
|
t.save()
|
||||||
f = FollowUp(ticket=t, date=timezone.now(), title=_('Assigned to %(username)s in bulk update' % {'username': user.username}), public=True, user=request.user)
|
f = FollowUp(ticket=t, date=timezone.now(), title=_('Assigned to %(username)s in bulk update' % {'username': user.get_username()}), public=True, user=request.user)
|
||||||
f.save()
|
f.save()
|
||||||
elif action == 'unassign' and t.assigned_to is not None:
|
elif action == 'unassign' and t.assigned_to is not None:
|
||||||
t.assigned_to = None
|
t.assigned_to = None
|
||||||
@ -849,14 +849,14 @@ edit_ticket = staff_member_required(edit_ticket)
|
|||||||
|
|
||||||
def create_ticket(request):
|
def create_ticket(request):
|
||||||
if helpdesk_settings.HELPDESK_STAFF_ONLY_TICKET_OWNERS:
|
if helpdesk_settings.HELPDESK_STAFF_ONLY_TICKET_OWNERS:
|
||||||
assignable_users = User.objects.filter(is_active=True, is_staff=True).order_by('username')
|
assignable_users = User.objects.filter(is_active=True, is_staff=True).order_by(User.USERNAME_FIELD)
|
||||||
else:
|
else:
|
||||||
assignable_users = User.objects.filter(is_active=True).order_by('username')
|
assignable_users = User.objects.filter(is_active=True).order_by(User.USERNAME_FIELD)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = TicketForm(request.POST, request.FILES)
|
form = TicketForm(request.POST, request.FILES)
|
||||||
form.fields['queue'].choices = [('', '--------')] + [[q.id, q.title] for q in Queue.objects.all()]
|
form.fields['queue'].choices = [('', '--------')] + [[q.id, q.title] for q in Queue.objects.all()]
|
||||||
form.fields['assigned_to'].choices = [('', '--------')] + [[u.id, u.username] for u in assignable_users]
|
form.fields['assigned_to'].choices = [('', '--------')] + [[u.id, u.get_username()] for u in assignable_users]
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
ticket = form.save(user=request.user)
|
ticket = form.save(user=request.user)
|
||||||
return HttpResponseRedirect(ticket.get_absolute_url())
|
return HttpResponseRedirect(ticket.get_absolute_url())
|
||||||
@ -869,7 +869,7 @@ def create_ticket(request):
|
|||||||
|
|
||||||
form = TicketForm(initial=initial_data)
|
form = TicketForm(initial=initial_data)
|
||||||
form.fields['queue'].choices = [('', '--------')] + [[q.id, q.title] for q in Queue.objects.all()]
|
form.fields['queue'].choices = [('', '--------')] + [[q.id, q.title] for q in Queue.objects.all()]
|
||||||
form.fields['assigned_to'].choices = [('', '--------')] + [[u.id, u.username] for u in assignable_users]
|
form.fields['assigned_to'].choices = [('', '--------')] + [[u.id, u.get_username()] for u in assignable_users]
|
||||||
if helpdesk_settings.HELPDESK_CREATE_TICKET_HIDE_ASSIGNED_TO:
|
if helpdesk_settings.HELPDESK_CREATE_TICKET_HIDE_ASSIGNED_TO:
|
||||||
form.fields['assigned_to'].widget = forms.HiddenInput()
|
form.fields['assigned_to'].widget = forms.HiddenInput()
|
||||||
|
|
||||||
|
20
quicktest.py
20
quicktest.py
@ -1,8 +1,11 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
import django
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
class QuickDjangoTest(object):
|
class QuickDjangoTest(object):
|
||||||
"""
|
"""
|
||||||
A quick way to run the Django test suite without a fully-configured project.
|
A quick way to run the Django test suite without a fully-configured project.
|
||||||
@ -25,6 +28,14 @@ class QuickDjangoTest(object):
|
|||||||
'django.contrib.humanize',
|
'django.contrib.humanize',
|
||||||
'bootstrapform',
|
'bootstrapform',
|
||||||
)
|
)
|
||||||
|
MIDDLEWARE_CLASSES = [
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.apps = args
|
self.apps = args
|
||||||
@ -40,8 +51,7 @@ class QuickDjangoTest(object):
|
|||||||
"""
|
"""
|
||||||
Figure out which version of Django's test suite we have to play with.
|
Figure out which version of Django's test suite we have to play with.
|
||||||
"""
|
"""
|
||||||
from django import VERSION
|
if django.VERSION >= (1, 2):
|
||||||
if VERSION[0] == 1 and VERSION[1] >= 2:
|
|
||||||
return 'new'
|
return 'new'
|
||||||
else:
|
else:
|
||||||
return 'old'
|
return 'old'
|
||||||
@ -64,6 +74,7 @@ class QuickDjangoTest(object):
|
|||||||
"""
|
"""
|
||||||
Fire up the Django test suite developed for version 1.2
|
Fire up the Django test suite developed for version 1.2
|
||||||
"""
|
"""
|
||||||
|
|
||||||
settings.configure(
|
settings.configure(
|
||||||
DEBUG = True,
|
DEBUG = True,
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
@ -77,8 +88,13 @@ class QuickDjangoTest(object):
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
INSTALLED_APPS = self.INSTALLED_APPS + self.apps,
|
INSTALLED_APPS = self.INSTALLED_APPS + self.apps,
|
||||||
|
MIDDLEWARE_CLASSES = self.MIDDLEWARE_CLASSES,
|
||||||
ROOT_URLCONF = self.apps[0] + '.urls',
|
ROOT_URLCONF = self.apps[0] + '.urls',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if django.VERSION >= (1, 7):
|
||||||
|
django.setup()
|
||||||
|
|
||||||
from django.test.simple import DjangoTestSuiteRunner
|
from django.test.simple import DjangoTestSuiteRunner
|
||||||
failures = DjangoTestSuiteRunner().run_tests(self.apps, verbosity=1)
|
failures = DjangoTestSuiteRunner().run_tests(self.apps, verbosity=1)
|
||||||
if failures:
|
if failures:
|
||||||
|
2
setup.py
2
setup.py
@ -4,7 +4,7 @@ from distutils.util import convert_path
|
|||||||
from fnmatch import fnmatchcase
|
from fnmatch import fnmatchcase
|
||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
version = '0.1.12'
|
version = '0.1.16'
|
||||||
|
|
||||||
# Provided as an attribute, so you can append to these instead
|
# Provided as an attribute, so you can append to these instead
|
||||||
# of replicating them:
|
# of replicating them:
|
||||||
|
Loading…
Reference in New Issue
Block a user