Merge pull request #640 from auto-mat/public_ticket_security

Public ticket security improvements
This commit is contained in:
Garret Wassermann 2018-09-08 22:13:42 -04:00 committed by GitHub
commit a3bc6ed46b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 288 additions and 139 deletions

1
.gitignore vendored
View File

@ -10,6 +10,7 @@ docs/doctrees/*
.project .project
.pydevproject .pydevproject
.directory .directory
*.swp
# ignore demo attachments that user might have added # ignore demo attachments that user might have added
helpdesk/attachments/ helpdesk/attachments/

View File

@ -301,21 +301,27 @@ class TicketForm(AbstractTicketForm):
help_text=_('This e-mail address will receive copies of all public ' help_text=_('This e-mail address will receive copies of all public '
'updates to this ticket.'), 'updates to this ticket.'),
) )
assigned_to = forms.ChoiceField( assigned_to = forms.ChoiceField(
widget=forms.Select(attrs={'class': 'form-control'}), widget=forms.Select(attrs={'class': 'form-control'}) if not helpdesk_settings.HELPDESK_CREATE_TICKET_HIDE_ASSIGNED_TO else forms.HiddenInput(),
choices=(),
required=False, required=False,
label=_('Case owner'), label=_('Case owner'),
help_text=_('If you select an owner other than yourself, they\'ll be ' help_text=_('If you select an owner other than yourself, they\'ll be '
'e-mailed details of this ticket immediately.'), 'e-mailed details of this ticket immediately.'),
choices=()
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
""" """
Add any custom fields that are defined to the form. Add any custom fields that are defined to the form.
""" """
super(TicketForm, self).__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['queue'].choices = [('', '--------')] + [(q.id, q.title) for q in Queue.objects.all()]
if helpdesk_settings.HELPDESK_STAFF_ONLY_TICKET_OWNERS:
assignable_users = User.objects.filter(is_active=True, is_staff=True).order_by(User.USERNAME_FIELD)
else:
assignable_users = User.objects.filter(is_active=True).order_by(User.USERNAME_FIELD)
self.fields['assigned_to'].choices = [('', '--------')] + [(u.id, u.get_username()) for u in assignable_users]
self._add_form_custom_fields() self._add_form_custom_fields()
def save(self, user=None): def save(self, user=None):
@ -375,8 +381,8 @@ class PublicTicketForm(AbstractTicketForm):
self.fields['priority'].widget = forms.HiddenInput() self.fields['priority'].widget = forms.HiddenInput()
if hasattr(settings, 'HELPDESK_PUBLIC_TICKET_DUE_DATE'): if hasattr(settings, 'HELPDESK_PUBLIC_TICKET_DUE_DATE'):
self.fields['due_date'].widget = forms.HiddenInput() self.fields['due_date'].widget = forms.HiddenInput()
self.fields['queue'].choices = [('', '--------')] + [
self._add_form_custom_fields(False) (q.id, q.title) for q in Queue.objects.filter(allow_public_submission=True)]
def save(self): def save(self):
""" """

View File

@ -0,0 +1,28 @@
# Generated by Django 2.0.1 on 2018-09-07 21:22
from django.db import migrations, models
import helpdesk.models
def clear_secret_keys(apps, schema_editor):
Ticket = apps.get_model("helpdesk", "Ticket")
db_alias = schema_editor.connection.alias
for ticket in Ticket.objects.using(db_alias).all():
ticket.secret_key=''
ticket.save()
class Migration(migrations.Migration):
dependencies = [
('helpdesk', '0017_default_owner_on_delete_null'),
]
operations = [
migrations.AddField(
model_name='ticket',
name='secret_key',
field=models.CharField(default=helpdesk.models.mk_secret, max_length=36, null=True, verbose_name='Secret key needed for viewing/editing ticket by non-logged in users'),
),
migrations.RunPython(clear_secret_keys),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 2.0.1 on 2018-09-07 21:22
from django.db import migrations, models
import helpdesk.models
class Migration(migrations.Migration):
dependencies = [
('helpdesk', '0018_ticket_secret_key'),
]
operations = [
migrations.AlterField(
model_name='ticket',
name='secret_key',
field=models.CharField(default=helpdesk.models.mk_secret, max_length=36, verbose_name='Secret key needed for viewing/editing ticket by non-logged in users'),
),
]

View File

@ -21,6 +21,7 @@ from django.utils.encoding import python_2_unicode_compatible
import re import re
import six import six
import uuid
@python_2_unicode_compatible @python_2_unicode_compatible
@ -351,6 +352,10 @@ class Queue(models.Model):
pass pass
def mk_secret():
return str(uuid.uuid4())
@python_2_unicode_compatible @python_2_unicode_compatible
class Ticket(models.Model): class Ticket(models.Model):
""" """
@ -480,6 +485,12 @@ class Ticket(models.Model):
'automatically by management/commands/escalate_tickets.py.'), 'automatically by management/commands/escalate_tickets.py.'),
) )
secret_key = models.CharField(
_("Secret key needed for viewing/editing ticket by non-logged in users"),
max_length=36,
default=mk_secret,
)
def _get_assigned_to(self): def _get_assigned_to(self):
""" Custom property to allow us to easily print 'Unassigned' if a """ Custom property to allow us to easily print 'Unassigned' if a
ticket has no owner, or the users name if it's assigned. If the user ticket has no owner, or the users name if it's assigned. If the user
@ -544,11 +555,12 @@ class Ticket(models.Model):
site = Site.objects.get_current() site = Site.objects.get_current()
except ImproperlyConfigured: except ImproperlyConfigured:
site = Site(domain='configure-django-sites.com') site = Site(domain='configure-django-sites.com')
return u"http://%s%s?ticket=%s&email=%s" % ( return u"http://%s%s?ticket=%s&email=%s&key=%s" % (
site.domain, site.domain,
reverse('helpdesk:public_view'), reverse('helpdesk:public_view'),
self.ticket_for_url, self.ticket_for_url,
self.submitter_email self.submitter_email,
self.secret_key
) )
ticket_url = property(_get_ticket_url) ticket_url = property(_get_ticket_url)

View File

@ -0,0 +1,47 @@
{% extends "helpdesk/public_base.html" %}
{% load i18n bootstrap %}
{% block helpdesk_body %}
{% if helpdesk_settings.HELPDESK_SUBMIT_A_TICKET_PUBLIC %}
<div class="col-xs-6">
<div class="panel panel-default">
<div class="panel-body">
<h2 name='submit'>{% trans "Submit a Ticket" %}</h2>
<p>{% trans "Please provide as descriptive a title and description as possible." %}</p>
<form role="form" method='post' action='./#submit' enctype='multipart/form-data'>
<fieldset>
{{ form|bootstrap }}
{% comment %}
{% for field in form %}
{% if field.is_hidden %}
{{ field }}
{% else %}
<div class="form-group {% if field.errors %}has-error{% endif %}">
<label class="control-label" for='id_{{ field.name }}'>{{ field.label }}</label>{% if not field.field.required %} <span class='form_optional'>{% trans "(Optional)" %}</span>{% endif %}</dt>
<div class="input-group">{{ field }}</div>
{% if field.errors %}<div class="help-block">{{ field.errors }}</div>{% endif %}
{% if field.help_text %}<span class='fhelp-block'>{{ field.help_text }}</span>{% endif %}
</div>
{% endif %}
{% endfor %}
{% endcomment %}
<div class='buttons form-group'>
<input type='submit' class="btn btn-primary" value='{% trans "Submit Ticket" %}' />
</div>
</fieldset>
{% csrf_token %}</form>
</div>
</div>
</div>
{% endif %}
{% endblock %}

View File

@ -26,7 +26,7 @@
<div class="panel-body"> <div class="panel-body">
<h2 name='submit'>{% trans "Submit a Ticket" %}</h2> <h2 name='submit'>{% trans "Submit a Ticket" %}</h2>
<p>{% trans "All fields are required." %} {% trans "Please provide as descriptive a title and description as possible." %}</p> <p>{% trans "Please provide as descriptive a title and description as possible." %}</p>
<form role="form" method='post' action='./#submit' enctype='multipart/form-data'> <form role="form" method='post' action='./#submit' enctype='multipart/form-data'>
<fieldset> <fieldset>

View File

@ -29,12 +29,21 @@ class PublicActionsTestCase(TestCase):
self.client = Client() self.client = Client()
def test_public_view_ticket(self): def test_public_view_ticket(self):
# Without key, we get 403
response = self.client.get('%s?ticket=%s&email=%s' % ( response = self.client.get('%s?ticket=%s&email=%s' % (
reverse('helpdesk:public_view'), reverse('helpdesk:public_view'),
self.ticket.ticket_for_url, self.ticket.ticket_for_url,
'test.submitter@example.com')) 'test.submitter@example.com'))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 403)
self.assertTemplateNotUsed(response, 'helpdesk/public_view_form.html') self.assertTemplateNotUsed(response, 'helpdesk/public_view_form.html')
# With a key it works
response = self.client.get('%s?ticket=%s&email=%s&key=%s' % (
reverse('helpdesk:public_view'),
self.ticket.ticket_for_url,
'test.submitter@example.com',
self.ticket.secret_key))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'helpdesk/public_view_ticket.html')
def test_public_close(self): def test_public_close(self):
old_status = self.ticket.status old_status = self.ticket.status
@ -49,10 +58,11 @@ class PublicActionsTestCase(TestCase):
current_followups = ticket.followup_set.all().count() current_followups = ticket.followup_set.all().count()
response = self.client.get('%s?ticket=%s&email=%s&close' % ( response = self.client.get('%s?ticket=%s&email=%s&close&key=%s' % (
reverse('helpdesk:public_view'), reverse('helpdesk:public_view'),
ticket.ticket_for_url, ticket.ticket_for_url,
'test.submitter@example.com')) 'test.submitter@example.com',
ticket.secret_key))
ticket = Ticket.objects.get(id=self.ticket.id) ticket = Ticket.objects.get(id=self.ticket.id)

View File

@ -2,9 +2,13 @@
from django.urls import reverse from django.urls import reverse
from django.test import TestCase from django.test import TestCase
from helpdesk.models import Ticket, Queue from helpdesk.models import Ticket, Queue
from django.test.utils import override_settings
class TestKBDisabled(TestCase): @override_settings(
HELPDESK_VIEW_A_TICKET_PUBLIC=True
)
class TestTicketLookupPublicEnabled(TestCase):
def setUp(self): def setUp(self):
q = Queue(title='Q1', slug='q1') q = Queue(title='Q1', slug='q1')
q.save() q.save()

View File

@ -12,7 +12,7 @@ from django.contrib.auth.decorators import login_required
from django.contrib.auth import views as auth_views from django.contrib.auth import views as auth_views
from django.views.generic import TemplateView from django.views.generic import TemplateView
from helpdesk.decorators import helpdesk_staff_member_required from helpdesk.decorators import helpdesk_staff_member_required, protect_view
from helpdesk import settings as helpdesk_settings from helpdesk import settings as helpdesk_settings
from helpdesk.views import feeds, staff, public, kb from helpdesk.views import feeds, staff, public, kb
@ -46,10 +46,6 @@ urlpatterns = [
staff.mass_update, staff.mass_update,
name='mass_update'), name='mass_update'),
url(r'^tickets/submit/$',
staff.create_ticket,
name='submit'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/$',
staff.view_ticket, staff.view_ticket,
name='view'), name='view'),
@ -149,9 +145,13 @@ urlpatterns = [
urlpatterns += [ urlpatterns += [
url(r'^$', url(r'^$',
public.homepage, protect_view(public.Homepage.as_view()),
name='home'), name='home'),
url(r'^tickets/submit/$',
public.create_ticket,
name='submit'),
url(r'^view/$', url(r'^view/$',
public.view_ticket, public.view_ticket,
name='public_view'), name='public_view'),

View File

@ -0,0 +1,8 @@
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from helpdesk.decorators import is_helpdesk_staff
class MustBeStaffMixin(LoginRequiredMixin, UserPassesTestMixin):
def test_func(self):
return is_helpdesk_staff(self.request.user)

View File

@ -6,7 +6,7 @@ django-helpdesk - A Django powered ticket tracker for small enterprise.
views/public.py - All public facing views, eg non-staff (no authentication views/public.py - All public facing views, eg non-staff (no authentication
required) views. required) views.
""" """
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
try: try:
# Django 2.0+ # Django 2.0+
from django.urls import reverse from django.urls import reverse
@ -18,55 +18,59 @@ from django.shortcuts import render
from django.utils.http import urlquote from django.utils.http import urlquote
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.conf import settings from django.conf import settings
from django.views.generic.base import TemplateView
from django.views.generic.edit import FormView
from helpdesk import settings as helpdesk_settings from helpdesk import settings as helpdesk_settings
from helpdesk.decorators import protect_view, is_helpdesk_staff from helpdesk.decorators import protect_view, is_helpdesk_staff
import helpdesk.views.staff as staff
from helpdesk.forms import PublicTicketForm from helpdesk.forms import PublicTicketForm
from helpdesk.lib import text_is_spam from helpdesk.lib import text_is_spam
from helpdesk.models import Ticket, Queue, UserSettings, KBCategory from helpdesk.models import Ticket, Queue, UserSettings, KBCategory
@protect_view def create_ticket(request, *args, **kwargs):
def homepage(request): if is_helpdesk_staff(request.user):
if not request.user.is_authenticated and helpdesk_settings.HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT: return staff.CreateTicketView.as_view()(request, *args, **kwargs)
return HttpResponseRedirect(reverse('login'))
if is_helpdesk_staff(request.user) or \
(request.user.is_authenticated and
helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE):
try:
if request.user.usersettings_helpdesk.settings.get('login_view_ticketlist', False):
return HttpResponseRedirect(reverse('helpdesk:list'))
else:
return HttpResponseRedirect(reverse('helpdesk:dashboard'))
except UserSettings.DoesNotExist:
return HttpResponseRedirect(reverse('helpdesk:dashboard'))
if request.method == 'POST':
form = PublicTicketForm(request.POST, request.FILES)
form.fields['queue'].choices = [('', '--------')] + [
(q.id, q.title) for q in Queue.objects.filter(allow_public_submission=True)]
if form.is_valid():
if text_is_spam(form.cleaned_data['body'], request):
# This submission is spam. Let's not save it.
return render(request, template_name='helpdesk/public_spam.html')
else:
ticket = form.save()
try:
return HttpResponseRedirect('%s?ticket=%s&email=%s' % (
reverse('helpdesk:public_view'),
ticket.ticket_for_url,
urlquote(ticket.submitter_email))
)
except ValueError:
# if someone enters a non-int string for the ticket
return HttpResponseRedirect(reverse('helpdesk:home'))
else: else:
return CreateTicketView.as_view()(request, *args, **kwargs)
class CreateTicketView(FormView):
template_name = 'helpdesk/public_create_ticket.html'
form_class = PublicTicketForm
def dispatch(self, *args, **kwargs):
request = self.request
if not request.user.is_authenticated and helpdesk_settings.HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT:
return HttpResponseRedirect(reverse('login'))
if is_helpdesk_staff(request.user) or \
(request.user.is_authenticated and
helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE):
try:
if request.user.usersettings_helpdesk.settings.get('login_view_ticketlist', False):
return HttpResponseRedirect(reverse('helpdesk:list'))
else:
return HttpResponseRedirect(reverse('helpdesk:dashboard'))
except UserSettings.DoesNotExist:
return HttpResponseRedirect(reverse('helpdesk:dashboard'))
return super().dispatch(*args, **kwargs)
def get_context(self):
knowledgebase_categories = KBCategory.objects.all()
return {
'helpdesk_settings': helpdesk_settings,
'kb_categories': knowledgebase_categories
}
def get_initial(self):
request = self.request
initial_data = {}
try: try:
queue = Queue.objects.get(slug=request.GET.get('queue', None)) queue = Queue.objects.get(slug=request.GET.get('queue', None))
except Queue.DoesNotExist: except Queue.DoesNotExist:
queue = None queue = None
initial_data = {}
# add pre-defined data for public ticket # add pre-defined data for public ticket
if hasattr(settings, 'HELPDESK_PUBLIC_TICKET_QUEUE'): if hasattr(settings, 'HELPDESK_PUBLIC_TICKET_QUEUE'):
@ -85,76 +89,99 @@ def homepage(request):
if request.user.is_authenticated and request.user.email: if request.user.is_authenticated and request.user.email:
initial_data['submitter_email'] = request.user.email initial_data['submitter_email'] = request.user.email
return initial_data
form = PublicTicketForm(initial=initial_data) def form_valid(self, form):
form.fields['queue'].choices = [('', '--------')] + [ request = self.request
(q.id, q.title) for q in Queue.objects.filter(allow_public_submission=True)] if text_is_spam(form.cleaned_data['body'], request):
# This submission is spam. Let's not save it.
return render(request, template_name='helpdesk/public_spam.html')
else:
ticket = form.save()
try:
return HttpResponseRedirect('%s?ticket=%s&email=%s&key=%s' % (
reverse('helpdesk:public_view'),
ticket.ticket_for_url,
urlquote(ticket.submitter_email),
ticket.secret_key)
)
except ValueError:
# if someone enters a non-int string for the ticket
return HttpResponseRedirect(reverse('helpdesk:home'))
knowledgebase_categories = KBCategory.objects.all() def get_success_url(self):
request = self.request
return render(request, 'helpdesk/public_homepage.html', {
'form': form, class Homepage(CreateTicketView):
'helpdesk_settings': helpdesk_settings, template_name = 'helpdesk/public_homepage.html'
'kb_categories': knowledgebase_categories
})
def search_for_ticket(request, error_message=None):
if hasattr(settings, 'HELPDESK_VIEW_A_TICKET_PUBLIC') and settings.HELPDESK_VIEW_A_TICKET_PUBLIC:
email = request.GET.get('email', None)
return render(request, 'helpdesk/public_view_form.html', {
'ticket': False,
'email': email,
'error_message': error_message,
'helpdesk_settings': helpdesk_settings,
})
else:
raise PermissionDenied("Public viewing of tickets without a secret key is forbidden.")
@protect_view @protect_view
def view_ticket(request): def view_ticket(request):
ticket_req = request.GET.get('ticket', None) ticket_req = request.GET.get('ticket', None)
email = request.GET.get('email', None) email = request.GET.get('email', None)
key = request.GET.get('key', '')
if ticket_req and email: if not (ticket_req and email):
queue, ticket_id = Ticket.queue_and_id_from_query(ticket_req) if ticket_req is None and email is None:
try: return search_for_ticket(request)
ticket = Ticket.objects.get(id=ticket_id, submitter_email__iexact=email)
except ObjectDoesNotExist:
error_message = _('Invalid ticket ID or e-mail address. Please try again.')
except ValueError:
error_message = _('Invalid ticket ID or e-mail address. Please try again.')
else: else:
if is_helpdesk_staff(request.user): return search_for_ticket(request, _('Missing ticket ID or e-mail address. Please try again.'))
redirect_url = reverse('helpdesk:view', args=[ticket_id])
if 'close' in request.GET:
redirect_url += '?close'
return HttpResponseRedirect(redirect_url)
if 'close' in request.GET and ticket.status == Ticket.RESOLVED_STATUS: queue, ticket_id = Ticket.queue_and_id_from_query(ticket_req)
from helpdesk.views.staff import update_ticket try:
# Trick the update_ticket() view into thinking it's being called with if hasattr(settings, 'HELPDESK_VIEW_A_TICKET_PUBLIC') and settings.HELPDESK_VIEW_A_TICKET_PUBLIC:
# a valid POST. ticket = Ticket.objects.get(id=ticket_id, submitter_email__iexact=email)
request.POST = { else:
'new_status': Ticket.CLOSED_STATUS, ticket = Ticket.objects.get(id=ticket_id, submitter_email__iexact=email, secret_key__iexact=key)
'public': 1, except (ObjectDoesNotExist, ValueError):
'title': ticket.title, return search_for_ticket(request, _('Invalid ticket ID or e-mail address. Please try again.'))
'comment': _('Submitter accepted resolution and closed ticket'),
}
if ticket.assigned_to:
request.POST['owner'] = ticket.assigned_to.id
request.GET = {}
return update_ticket(request, ticket_id, public=True) if is_helpdesk_staff(request.user):
redirect_url = reverse('helpdesk:view', args=[ticket_id])
if 'close' in request.GET:
redirect_url += '?close'
return HttpResponseRedirect(redirect_url)
# redirect user back to this ticket if possible. if 'close' in request.GET and ticket.status == Ticket.RESOLVED_STATUS:
redirect_url = '' from helpdesk.views.staff import update_ticket
if helpdesk_settings.HELPDESK_NAVIGATION_ENABLED: # Trick the update_ticket() view into thinking it's being called with
redirect_url = reverse('helpdesk:view', args=[ticket_id]) # a valid POST.
request.POST = {
'new_status': Ticket.CLOSED_STATUS,
'public': 1,
'title': ticket.title,
'comment': _('Submitter accepted resolution and closed ticket'),
}
if ticket.assigned_to:
request.POST['owner'] = ticket.assigned_to.id
request.GET = {}
return render(request, 'helpdesk/public_view_ticket.html', { return update_ticket(request, ticket_id, public=True)
'ticket': ticket,
'helpdesk_settings': helpdesk_settings,
'next': redirect_url,
})
elif ticket_req is None and email is None:
error_message = None
else:
error_message = _('Missing ticket ID or e-mail address. Please try again.')
return render(request, 'helpdesk/public_view_form.html', { # redirect user back to this ticket if possible.
'ticket': False, redirect_url = ''
'email': email, if helpdesk_settings.HELPDESK_NAVIGATION_ENABLED:
'error_message': error_message, redirect_url = reverse('helpdesk:view', args=[ticket_id])
return render(request, 'helpdesk/public_view_ticket.html', {
'ticket': ticket,
'helpdesk_settings': helpdesk_settings, 'helpdesk_settings': helpdesk_settings,
'next': redirect_url,
}) })

View File

@ -26,6 +26,7 @@ from django.utils.translation import ugettext as _
from django.utils.html import escape from django.utils.html import escape
from django import forms from django import forms
from django.utils import timezone from django.utils import timezone
from django.views.generic.edit import FormView
from django.utils import six from django.utils import six
@ -46,6 +47,7 @@ from helpdesk.models import (
IgnoreEmail, TicketCC, TicketDependency, IgnoreEmail, TicketCC, TicketDependency,
) )
from helpdesk import settings as helpdesk_settings from helpdesk import settings as helpdesk_settings
from helpdesk.views.permissions import MustBeStaffMixin
User = get_user_model() User = get_user_model()
@ -1019,44 +1021,29 @@ def edit_ticket(request, ticket_id):
edit_ticket = staff_member_required(edit_ticket) edit_ticket = staff_member_required(edit_ticket)
@helpdesk_staff_member_required class CreateTicketView(MustBeStaffMixin, FormView):
def create_ticket(request): template_name = 'helpdesk/create_ticket.html'
if helpdesk_settings.HELPDESK_STAFF_ONLY_TICKET_OWNERS: form_class = TicketForm
assignable_users = User.objects.filter(is_active=True, is_staff=True).order_by(User.USERNAME_FIELD)
else:
assignable_users = User.objects.filter(is_active=True).order_by(User.USERNAME_FIELD)
if request.method == 'POST': def get_initial(self):
form = TicketForm(request.POST, request.FILES)
form.fields['queue'].choices = [('', '--------')] + [
(q.id, q.title) for q in Queue.objects.all()]
form.fields['assigned_to'].choices = [('', '--------')] + [
(u.id, u.get_username()) for u in assignable_users]
if form.is_valid():
ticket = form.save(user=request.user)
if _has_access_to_queue(request.user, ticket.queue):
return HttpResponseRedirect(ticket.get_absolute_url())
else:
return HttpResponseRedirect(reverse('helpdesk:dashboard'))
else:
initial_data = {} initial_data = {}
request = self.request
if request.user.usersettings_helpdesk.settings.get('use_email_as_submitter', False) and request.user.email: if request.user.usersettings_helpdesk.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 'queue' in request.GET: if 'queue' in request.GET:
initial_data['queue'] = request.GET['queue'] initial_data['queue'] = request.GET['queue']
return initial_data
form = TicketForm(initial=initial_data) def form_valid(self, form):
form.fields['queue'].choices = [('', '--------')] + [ self.ticket = form.save()
(q.id, q.title) for q in Queue.objects.all()] return super().form_valid(form)
form.fields['assigned_to'].choices = [('', '--------')] + [
(u.id, u.get_username()) for u in assignable_users]
if helpdesk_settings.HELPDESK_CREATE_TICKET_HIDE_ASSIGNED_TO:
form.fields['assigned_to'].widget = forms.HiddenInput()
return render(request, 'helpdesk/create_ticket.html', {'form': form}) def get_success_url(self):
request = self.request
if _has_access_to_queue(request.user, self.ticket.queue):
create_ticket = staff_member_required(create_ticket) return self.ticket.get_absolute_url()
else:
return reverse('helpdesk:dashboard')
@helpdesk_staff_member_required @helpdesk_staff_member_required