mirror of
https://gitea.mueller.network/extern/django-helpdesk.git
synced 2024-11-22 16:03:19 +01:00
Merge custom staff filter, PR #239
This commit is contained in:
commit
3a1bd76e75
@ -108,8 +108,12 @@ These options only change display of items on public-facing pages, not staff pag
|
|||||||
Options that change ticket updates
|
Options that change ticket updates
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
- **HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE** Allow non-staff users to interact with tickets? This will also change how 'staff_member_required'
|
- **HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE** Allow non-staff users to interact with tickets?
|
||||||
in staff.py will be defined.
|
Set to True to allow any authenticated user to manage tickets.
|
||||||
|
You can also apply a custom authorisation logic for identifying helpdesk staff members, by setting this to a callable.
|
||||||
|
In that case, the value should be a function accepting the active user as a parameter and returning True if the user is considered helpdesk staff, e.g.
|
||||||
|
|
||||||
|
lambda u: u.is_authenticated() and u.is_active and u.groups.filter(name='helpdesk_staff').exists()))
|
||||||
|
|
||||||
**Default:** ``HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = False``
|
**Default:** ``HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = False``
|
||||||
|
|
||||||
|
@ -3,9 +3,21 @@ from functools import wraps
|
|||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.http import HttpResponseRedirect, Http404
|
from django.http import HttpResponseRedirect, Http404
|
||||||
from django.utils.decorators import available_attrs
|
from django.utils.decorators import available_attrs
|
||||||
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
|
|
||||||
from helpdesk import settings as helpdesk_settings
|
from helpdesk import settings as helpdesk_settings
|
||||||
|
|
||||||
|
if callable(helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE):
|
||||||
|
# apply a custom user validation condition
|
||||||
|
is_helpdesk_staff = helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE
|
||||||
|
elif helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE:
|
||||||
|
# treat 'normal' users like 'staff'
|
||||||
|
is_helpdesk_staff = lambda u: u.is_authenticated() and u.is_active
|
||||||
|
else:
|
||||||
|
is_helpdesk_staff = lambda u: u.is_authenticated() and u.is_active and u.is_staff
|
||||||
|
|
||||||
|
helpdesk_staff_member_required = user_passes_test(is_helpdesk_staff)
|
||||||
|
helpdesk_superuser_required = user_passes_test(lambda u: u.is_authenticated() and u.is_active and u.is_superuser)
|
||||||
|
|
||||||
def protect_view(view_func):
|
def protect_view(view_func):
|
||||||
"""
|
"""
|
||||||
@ -21,3 +33,4 @@ def protect_view(view_func):
|
|||||||
return view_func(request, *args, **kwargs)
|
return view_func(request, *args, **kwargs)
|
||||||
|
|
||||||
return _wrapped_view
|
return _wrapped_view
|
||||||
|
|
||||||
|
@ -312,6 +312,7 @@ def process_attachments(followup, attached_files):
|
|||||||
attachments = []
|
attachments = []
|
||||||
|
|
||||||
for attached in attached_files:
|
for attached in attached_files:
|
||||||
|
|
||||||
if attached.size:
|
if attached.size:
|
||||||
filename = smart_text(attached.name)
|
filename = smart_text(attached.name)
|
||||||
att = Attachment(
|
att = Attachment(
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
Default settings for django-helpdesk.
|
Default settings for django-helpdesk.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
import warnings
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -85,12 +86,12 @@ HELPDESK_SUBMIT_A_TICKET_PUBLIC = getattr(settings, 'HELPDESK_SUBMIT_A_TICKET_PU
|
|||||||
# options for update_ticket views #
|
# options for update_ticket views #
|
||||||
###################################
|
###################################
|
||||||
|
|
||||||
|
''' options for update_ticket views '''
|
||||||
# allow non-staff users to interact with tickets?
|
# allow non-staff users to interact with tickets?
|
||||||
# this will also change how 'staff_member_required'
|
# can be True/False or a callable accepting the active user and returning True if they must be considered helpdesk staff
|
||||||
# in staff.py will be defined.
|
HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = getattr(settings, 'HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE', False)
|
||||||
HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = getattr(settings,
|
if not (HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE in (True, False) or callable(HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE)):
|
||||||
'HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE',
|
warnings.warn("HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE should be set to either True/False or a callable.", RuntimeWarning)
|
||||||
False)
|
|
||||||
|
|
||||||
# show edit buttons in ticket follow ups.
|
# show edit buttons in ticket follow ups.
|
||||||
HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP = getattr(settings,
|
HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP = getattr(settings,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% load i18n %}
|
{% load i18n helpdesk_staff %}
|
||||||
|
|
||||||
<!-- Navigation -->
|
<!-- Navigation -->
|
||||||
<nav class="navbar navbar-default navbar-fixed-top" role="navigation" style="margin-bottom: 0">
|
<nav class="navbar navbar-default navbar-fixed-top" role="navigation" style="margin-bottom: 0">
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<!-- /.navbar-header -->
|
<!-- /.navbar-header -->
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" id="helpdesk-nav-collapse">
|
<div class="collapse navbar-collapse" id="helpdesk-nav-collapse">
|
||||||
{% if helpdesk_settings.HELPDESK_NAVIGATION_ENABLED and user.is_authenticated or user.is_staff %}
|
{% if helpdesk_settings.HELPDESK_NAVIGATION_ENABLED and user.is_authenticated or user|is_helpdesk_staff %}
|
||||||
<ul class="nav navbar-top-links navbar-right">
|
<ul class="nav navbar-top-links navbar-right">
|
||||||
<li>
|
<li>
|
||||||
<a href='{% url 'helpdesk:dashboard' %}'><i class="fa fa-dashboard fa-fw"></i> <span class="nav-text">{% trans "Dashboard" %}</span></a>
|
<a href='{% url 'helpdesk:dashboard' %}'><i class="fa fa-dashboard fa-fw"></i> <span class="nav-text">{% trans "Dashboard" %}</span></a>
|
||||||
@ -28,6 +28,7 @@
|
|||||||
<li>
|
<li>
|
||||||
<a href='{% url 'helpdesk:report_index' %}'><i class="fa fa-bar-chart-o fa-fw"></i> <span class="nav-text"> {% trans "Stats" %}</span></a>
|
<a href='{% url 'helpdesk:report_index' %}'><i class="fa fa-bar-chart-o fa-fw"></i> <span class="nav-text"> {% trans "Stats" %}</span></a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{% if helpdesk_settings.HELPDESK_KB_ENABLED %}
|
{% if helpdesk_settings.HELPDESK_KB_ENABLED %}
|
||||||
<li>
|
<li>
|
||||||
<a href='{% url 'helpdesk:kb_index' %}'><i class="fa fa-database fa-fw"></i> <span class="nav-text">{% trans "Knowledgebase" %}</span></a>
|
<a href='{% url 'helpdesk:kb_index' %}'><i class="fa fa-database fa-fw"></i> <span class="nav-text">{% trans "Knowledgebase" %}</span></a>
|
||||||
|
22
helpdesk/templatetags/helpdesk_staff.py
Normal file
22
helpdesk/templatetags/helpdesk_staff.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"""
|
||||||
|
django-helpdesk - A Django powered ticket tracker for small enterprise.
|
||||||
|
|
||||||
|
templatetags/helpdesk_staff.py - The is_helpdesk_staff template filter returns True if the user qualifies as Helpdesk staff.
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
from django.template import Library
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
from helpdesk.decorators import is_helpdesk_staff
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
register = Library()
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter(name='is_helpdesk_staff')
|
||||||
|
def helpdesk_staff(user):
|
||||||
|
try:
|
||||||
|
return is_helpdesk_staff(user)
|
||||||
|
except Exception, e:
|
||||||
|
logger.exception("'helpdesk_staff' template tag (django-helpdesk) crashed")
|
@ -4,6 +4,8 @@ from django.contrib.auth import get_user_model
|
|||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
from helpdesk.models import Ticket, Queue
|
||||||
|
|
||||||
|
|
||||||
def get_staff_user(username='helpdesk.staff', password='password'):
|
def get_staff_user(username='helpdesk.staff', password='password'):
|
||||||
try:
|
try:
|
||||||
@ -37,4 +39,37 @@ def reload_urlconf(urlconf=None):
|
|||||||
clear_url_caches()
|
clear_url_caches()
|
||||||
|
|
||||||
|
|
||||||
|
def update_user_settings(user, **kwargs):
|
||||||
|
usersettings = user.usersettings
|
||||||
|
settings = usersettings.settings
|
||||||
|
settings.update(kwargs)
|
||||||
|
usersettings.settings = settings
|
||||||
|
usersettings.save()
|
||||||
|
|
||||||
|
|
||||||
|
def delete_user_settings(user, *args):
|
||||||
|
usersettings = user.usersettings
|
||||||
|
settings = usersettings.settings
|
||||||
|
for setting in args:
|
||||||
|
if setting in settings:
|
||||||
|
del settings[setting]
|
||||||
|
usersettings.settings = settings
|
||||||
|
usersettings.save()
|
||||||
|
|
||||||
|
|
||||||
|
def create_ticket(**kwargs):
|
||||||
|
q = kwargs.get('queue', None)
|
||||||
|
if q is None:
|
||||||
|
try:
|
||||||
|
q = Queue.objects.all()[0]
|
||||||
|
except IndexError:
|
||||||
|
q = Queue.objects.create(title='Test Q', slug='test', )
|
||||||
|
data = {
|
||||||
|
'title': "I wish to register a complaint",
|
||||||
|
'queue': q,
|
||||||
|
}
|
||||||
|
data.update(kwargs)
|
||||||
|
return Ticket.objects.create(**data)
|
||||||
|
|
||||||
|
|
||||||
HELPDESK_URLCONF = 'helpdesk.urls'
|
HELPDESK_URLCONF = 'helpdesk.urls'
|
||||||
|
@ -1,22 +1,21 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import sys
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from helpdesk.tests.helpers import get_staff_user, reload_urlconf
|
|
||||||
|
|
||||||
|
|
||||||
class TestKBDisabled(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
from helpdesk import settings
|
from helpdesk import settings
|
||||||
|
from helpdesk.tests.helpers import (get_staff_user, reload_urlconf, User, update_user_settings, delete_user_settings,
|
||||||
|
create_ticket)
|
||||||
|
|
||||||
|
|
||||||
|
class KBDisabledTestCase(TestCase):
|
||||||
|
def setUp(self):
|
||||||
self.HELPDESK_KB_ENABLED = settings.HELPDESK_KB_ENABLED
|
self.HELPDESK_KB_ENABLED = settings.HELPDESK_KB_ENABLED
|
||||||
if self.HELPDESK_KB_ENABLED:
|
if self.HELPDESK_KB_ENABLED:
|
||||||
settings.HELPDESK_KB_ENABLED = False
|
settings.HELPDESK_KB_ENABLED = False
|
||||||
reload_urlconf()
|
reload_urlconf()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
from helpdesk import settings
|
|
||||||
|
|
||||||
if self.HELPDESK_KB_ENABLED:
|
if self.HELPDESK_KB_ENABLED:
|
||||||
settings.HELPDESK_KB_ENABLED = True
|
settings.HELPDESK_KB_ENABLED = True
|
||||||
reload_urlconf()
|
reload_urlconf()
|
||||||
@ -36,3 +35,193 @@ class TestKBDisabled(TestCase):
|
|||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
|
class StaffUserTestCaseMixin(object):
|
||||||
|
HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = False
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.original_setting = settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE
|
||||||
|
settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = self.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE
|
||||||
|
self.reload_views()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = self.original_setting
|
||||||
|
self.reload_views()
|
||||||
|
|
||||||
|
def reload_views(self):
|
||||||
|
try:
|
||||||
|
reload(sys.modules['helpdesk.decorators'])
|
||||||
|
reload(sys.modules['helpdesk.views.staff'])
|
||||||
|
reload_urlconf()
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_anonymous_user(self):
|
||||||
|
"""Access to the dashboard always requires a login"""
|
||||||
|
response = self.client.get(reverse('helpdesk_dashboard'), follow=True)
|
||||||
|
self.assertTemplateUsed(response, 'helpdesk/registration/login.html')
|
||||||
|
|
||||||
|
|
||||||
|
class NonStaffUsersAllowedTestCase(StaffUserTestCaseMixin, TestCase):
|
||||||
|
HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = True
|
||||||
|
|
||||||
|
def test_non_staff_allowed(self):
|
||||||
|
"""If HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE is True,
|
||||||
|
authenticated, non-staff users should be able to access
|
||||||
|
the dashboard.
|
||||||
|
"""
|
||||||
|
from helpdesk.decorators import is_helpdesk_staff
|
||||||
|
|
||||||
|
user = User.objects.create_user(username='henry.wensleydale', password='gouda', email='wensleydale@example.com')
|
||||||
|
|
||||||
|
self.assertTrue(is_helpdesk_staff(user))
|
||||||
|
|
||||||
|
self.client.login(username=user.username, password='gouda')
|
||||||
|
response = self.client.get(reverse('helpdesk_dashboard'), follow=True)
|
||||||
|
self.assertTemplateUsed(response, 'helpdesk/dashboard.html')
|
||||||
|
|
||||||
|
|
||||||
|
class StaffUsersOnlyTestCase(StaffUserTestCaseMixin, TestCase):
|
||||||
|
# Use default values
|
||||||
|
HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = False
|
||||||
|
|
||||||
|
def test_non_staff(self):
|
||||||
|
"""Non-staff users are correctly identified"""
|
||||||
|
from helpdesk.decorators import is_helpdesk_staff
|
||||||
|
|
||||||
|
user = User.objects.create_user(username='henry.wensleydale', password='gouda', email='wensleydale@example.com')
|
||||||
|
|
||||||
|
self.assertFalse(is_helpdesk_staff(user))
|
||||||
|
|
||||||
|
def test_staff_only(self):
|
||||||
|
"""If HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE is False,
|
||||||
|
only staff users should be able to access the dashboard.
|
||||||
|
"""
|
||||||
|
from helpdesk.decorators import is_helpdesk_staff
|
||||||
|
|
||||||
|
user = get_staff_user()
|
||||||
|
|
||||||
|
self.assertTrue(is_helpdesk_staff(user))
|
||||||
|
|
||||||
|
self.client.login(username=user.username, password='password')
|
||||||
|
response = self.client.get(reverse('helpdesk_dashboard'), follow=True)
|
||||||
|
self.assertTemplateUsed(response, 'helpdesk/dashboard.html')
|
||||||
|
|
||||||
|
|
||||||
|
class CustomStaffUserTestCase(StaffUserTestCaseMixin, TestCase):
|
||||||
|
@staticmethod
|
||||||
|
def custom_staff_filter(user):
|
||||||
|
"""Arbitrary user validation function"""
|
||||||
|
return user.is_authenticated() and user.is_active and user.username.lower().endswith('wensleydale')
|
||||||
|
|
||||||
|
HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = custom_staff_filter
|
||||||
|
|
||||||
|
def test_custom_staff_pass(self):
|
||||||
|
"""If HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE is callable,
|
||||||
|
a custom access rule is applied.
|
||||||
|
"""
|
||||||
|
from helpdesk.decorators import is_helpdesk_staff
|
||||||
|
|
||||||
|
user = User.objects.create_user(username='henry.wensleydale', password='gouda', email='wensleydale@example.com')
|
||||||
|
|
||||||
|
self.assertTrue(is_helpdesk_staff(user))
|
||||||
|
|
||||||
|
self.client.login(username=user.username, password='gouda')
|
||||||
|
response = self.client.get(reverse('helpdesk_dashboard'), follow=True)
|
||||||
|
self.assertTemplateUsed(response, 'helpdesk/dashboard.html')
|
||||||
|
|
||||||
|
def test_custom_staff_fail(self):
|
||||||
|
from helpdesk.decorators import is_helpdesk_staff
|
||||||
|
|
||||||
|
user = User.objects.create_user(username='terry.milton', password='frog', email='milton@example.com')
|
||||||
|
|
||||||
|
self.assertFalse(is_helpdesk_staff(user))
|
||||||
|
|
||||||
|
self.client.login(username=user.username, password='frog')
|
||||||
|
response = self.client.get(reverse('helpdesk_dashboard'), follow=True)
|
||||||
|
self.assertTemplateUsed(response, 'helpdesk/registration/login.html')
|
||||||
|
|
||||||
|
|
||||||
|
class HomePageAnonymousUserTestCase(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.redirect_to_login = settings.HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
settings.HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT = self.redirect_to_login
|
||||||
|
|
||||||
|
def test_homepage(self):
|
||||||
|
settings.HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT = True
|
||||||
|
response = self.client.get(reverse('helpdesk_home'))
|
||||||
|
self.assertTemplateUsed('helpdesk/public_homepage.html')
|
||||||
|
|
||||||
|
def test_redirect_to_login(self):
|
||||||
|
"""Unauthenticated users are redirected to the login page if HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT is True"""
|
||||||
|
settings.HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT = True
|
||||||
|
response = self.client.get(reverse('helpdesk_home'))
|
||||||
|
self.assertRedirects(response, reverse('login'))
|
||||||
|
|
||||||
|
|
||||||
|
class HomePageTestCase(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.original_setting = settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE
|
||||||
|
settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = False
|
||||||
|
try:
|
||||||
|
reload(sys.modules['helpdesk.views.public'])
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = self.original_setting
|
||||||
|
reload(sys.modules['helpdesk.views.public'])
|
||||||
|
|
||||||
|
def assertUserRedirectedToView(self, user, view_name):
|
||||||
|
self.client.login(username=user.username, password='password')
|
||||||
|
response = self.client.get(reverse('helpdesk_home'))
|
||||||
|
self.assertRedirects(response, reverse(view_name))
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_redirect_to_dashboard(self):
|
||||||
|
"""Authenticated users are redirected to the dashboard"""
|
||||||
|
user = get_staff_user()
|
||||||
|
|
||||||
|
# login_view_ticketlist is False...
|
||||||
|
update_user_settings(user, login_view_ticketlist=False)
|
||||||
|
self.assertUserRedirectedToView(user, 'helpdesk_dashboard')
|
||||||
|
|
||||||
|
# ... or missing
|
||||||
|
delete_user_settings(user, 'login_view_ticketlist')
|
||||||
|
self.assertUserRedirectedToView(user, 'helpdesk_dashboard')
|
||||||
|
|
||||||
|
def test_no_user_settings_redirect_to_dashboard(self):
|
||||||
|
"""Authenticated users are redirected to the dashboard if user settings are missing"""
|
||||||
|
from helpdesk.models import UserSettings
|
||||||
|
user = get_staff_user()
|
||||||
|
|
||||||
|
UserSettings.objects.filter(user=user).delete()
|
||||||
|
self.assertUserRedirectedToView(user, 'helpdesk_dashboard')
|
||||||
|
|
||||||
|
def test_redirect_to_ticket_list(self):
|
||||||
|
"""Authenticated users are redirected to the ticket list based on their user settings"""
|
||||||
|
user = get_staff_user()
|
||||||
|
update_user_settings(user, login_view_ticketlist=True)
|
||||||
|
|
||||||
|
self.assertUserRedirectedToView(user, 'helpdesk_list')
|
||||||
|
|
||||||
|
|
||||||
|
class ReturnToTicketTestCase(TestCase):
|
||||||
|
def test_staff_user(self):
|
||||||
|
from helpdesk.views.staff import return_to_ticket
|
||||||
|
|
||||||
|
user = get_staff_user()
|
||||||
|
ticket = create_ticket()
|
||||||
|
response = return_to_ticket(user, settings, ticket)
|
||||||
|
self.assertEqual(response['location'], ticket.get_absolute_url())
|
||||||
|
|
||||||
|
def test_non_staff_user(self):
|
||||||
|
from helpdesk.views.staff import return_to_ticket
|
||||||
|
|
||||||
|
user = User.objects.create_user(username='henry.wensleydale', password='gouda', email='wensleydale@example.com')
|
||||||
|
ticket = create_ticket()
|
||||||
|
response = return_to_ticket(user, settings, ticket)
|
||||||
|
self.assertEqual(response['location'], ticket.ticket_url)
|
||||||
|
@ -14,7 +14,7 @@ from django.utils.http import urlquote
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from helpdesk import settings as helpdesk_settings
|
from helpdesk import settings as helpdesk_settings
|
||||||
from helpdesk.decorators import protect_view
|
from helpdesk.decorators import protect_view, is_helpdesk_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
|
||||||
@ -22,7 +22,10 @@ from helpdesk.models import Ticket, Queue, UserSettings, KBCategory
|
|||||||
|
|
||||||
@protect_view
|
@protect_view
|
||||||
def homepage(request):
|
def homepage(request):
|
||||||
if request.user.is_staff or \
|
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
|
(request.user.is_authenticated() and
|
||||||
helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE):
|
helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE):
|
||||||
try:
|
try:
|
||||||
@ -85,7 +88,7 @@ def view_ticket(request):
|
|||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
error_message = _('Invalid ticket ID or e-mail address. Please try again.')
|
error_message = _('Invalid ticket ID or e-mail address. Please try again.')
|
||||||
else:
|
else:
|
||||||
if request.user.is_staff:
|
if is_helpdesk_staff(request.user):
|
||||||
redirect_url = reverse('helpdesk:view', args=[ticket_id])
|
redirect_url = reverse('helpdesk:view', args=[ticket_id])
|
||||||
if 'close' in request.GET:
|
if 'close' in request.GET:
|
||||||
redirect_url += '?close'
|
redirect_url += '?close'
|
||||||
|
@ -42,7 +42,6 @@ from helpdesk import settings as helpdesk_settings
|
|||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
if helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE:
|
if helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE:
|
||||||
# treat 'normal' users like 'staff'
|
# treat 'normal' users like 'staff'
|
||||||
staff_member_required = user_passes_test(
|
staff_member_required = user_passes_test(
|
||||||
@ -86,6 +85,7 @@ def _has_access_to_queue(user, queue):
|
|||||||
return user.has_perm(queue.permission_name)
|
return user.has_perm(queue.permission_name)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def dashboard(request):
|
def dashboard(request):
|
||||||
"""
|
"""
|
||||||
A quick summary overview for users: A list of their own tickets, a table
|
A quick summary overview for users: A list of their own tickets, a table
|
||||||
@ -166,7 +166,7 @@ def dashboard(request):
|
|||||||
})
|
})
|
||||||
dashboard = staff_member_required(dashboard)
|
dashboard = staff_member_required(dashboard)
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def delete_ticket(request, ticket_id):
|
def delete_ticket(request, ticket_id):
|
||||||
ticket = get_object_or_404(Ticket, id=ticket_id)
|
ticket = get_object_or_404(Ticket, id=ticket_id)
|
||||||
if not _has_access_to_queue(request.user, ticket.queue):
|
if not _has_access_to_queue(request.user, ticket.queue):
|
||||||
@ -178,10 +178,17 @@ def delete_ticket(request, ticket_id):
|
|||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
ticket.delete()
|
ticket.delete()
|
||||||
|
<<<<<<< HEAD
|
||||||
return HttpResponseRedirect(reverse('helpdesk:home'))
|
return HttpResponseRedirect(reverse('helpdesk:home'))
|
||||||
delete_ticket = staff_member_required(delete_ticket)
|
delete_ticket = staff_member_required(delete_ticket)
|
||||||
|
|
||||||
|
|
||||||
|
=======
|
||||||
|
return HttpResponseRedirect(reverse('helpdesk_home'))
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
|
>>>>>>> brente/custom-staff-filter
|
||||||
def followup_edit(request, ticket_id, followup_id):
|
def followup_edit(request, ticket_id, followup_id):
|
||||||
"""Edit followup options with an ability to change the ticket."""
|
"""Edit followup options with an ability to change the ticket."""
|
||||||
followup = get_object_or_404(FollowUp, id=followup_id)
|
followup = get_object_or_404(FollowUp, id=followup_id)
|
||||||
@ -232,6 +239,7 @@ def followup_edit(request, ticket_id, followup_id):
|
|||||||
followup_edit = staff_member_required(followup_edit)
|
followup_edit = staff_member_required(followup_edit)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def followup_delete(request, ticket_id, followup_id):
|
def followup_delete(request, ticket_id, followup_id):
|
||||||
"""followup delete for superuser"""
|
"""followup delete for superuser"""
|
||||||
|
|
||||||
@ -245,6 +253,7 @@ def followup_delete(request, ticket_id, followup_id):
|
|||||||
followup_delete = staff_member_required(followup_delete)
|
followup_delete = staff_member_required(followup_delete)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def view_ticket(request, ticket_id):
|
def view_ticket(request, ticket_id):
|
||||||
ticket = get_object_or_404(Ticket, id=ticket_id)
|
ticket = get_object_or_404(Ticket, id=ticket_id)
|
||||||
if not _has_access_to_queue(request.user, ticket.queue):
|
if not _has_access_to_queue(request.user, ticket.queue):
|
||||||
@ -363,7 +372,7 @@ def update_ticket(request, ticket_id, public=False):
|
|||||||
if not (public or (
|
if not (public or (
|
||||||
request.user.is_authenticated() and
|
request.user.is_authenticated() and
|
||||||
request.user.is_active and (
|
request.user.is_active and (
|
||||||
request.user.is_staff or
|
is_helpdesk_staff(request.user) or
|
||||||
helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE))):
|
helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE))):
|
||||||
return HttpResponseRedirect('%s?next=%s' %
|
return HttpResponseRedirect('%s?next=%s' %
|
||||||
(reverse('helpdesk:login'), request.path))
|
(reverse('helpdesk:login'), request.path))
|
||||||
@ -421,7 +430,7 @@ def update_ticket(request, ticket_id, public=False):
|
|||||||
|
|
||||||
f = FollowUp(ticket=ticket, date=timezone.now(), comment=comment)
|
f = FollowUp(ticket=ticket, date=timezone.now(), comment=comment)
|
||||||
|
|
||||||
if request.user.is_staff or helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE:
|
if is_helpdesk_staff(request.user):
|
||||||
f.user = request.user
|
f.user = request.user
|
||||||
|
|
||||||
f.public = public
|
f.public = public
|
||||||
@ -462,6 +471,8 @@ def update_ticket(request, ticket_id, public=False):
|
|||||||
|
|
||||||
f.save()
|
f.save()
|
||||||
|
|
||||||
|
files = []
|
||||||
|
if request.FILES:
|
||||||
files = process_attachments(f, request.FILES.getlist('attachment'))
|
files = process_attachments(f, request.FILES.getlist('attachment'))
|
||||||
|
|
||||||
if title and title != ticket.title:
|
if title and title != ticket.title:
|
||||||
@ -586,6 +597,7 @@ def update_ticket(request, ticket_id, public=False):
|
|||||||
(not reassigned and
|
(not reassigned and
|
||||||
ticket.assigned_to.usersettings_helpdesk.settings.get(
|
ticket.assigned_to.usersettings_helpdesk.settings.get(
|
||||||
'email_on_ticket_change', False)):
|
'email_on_ticket_change', False)):
|
||||||
|
|
||||||
send_templated_mail(
|
send_templated_mail(
|
||||||
template_staff,
|
template_staff,
|
||||||
context,
|
context,
|
||||||
@ -627,14 +639,19 @@ def update_ticket(request, ticket_id, public=False):
|
|||||||
|
|
||||||
|
|
||||||
def return_to_ticket(user, helpdesk_settings, ticket):
|
def return_to_ticket(user, helpdesk_settings, ticket):
|
||||||
|
<<<<<<< HEAD
|
||||||
"""Helper function for update_ticket"""
|
"""Helper function for update_ticket"""
|
||||||
|
=======
|
||||||
|
""" Helper function for update_ticket """
|
||||||
|
>>>>>>> brente/custom-staff-filter
|
||||||
|
|
||||||
if user.is_staff or helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE:
|
if is_helpdesk_staff(user):
|
||||||
return HttpResponseRedirect(ticket.get_absolute_url())
|
return HttpResponseRedirect(ticket.get_absolute_url())
|
||||||
else:
|
else:
|
||||||
return HttpResponseRedirect(ticket.ticket_url)
|
return HttpResponseRedirect(ticket.ticket_url)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def mass_update(request):
|
def mass_update(request):
|
||||||
tickets = request.POST.getlist('ticket_id')
|
tickets = request.POST.getlist('ticket_id')
|
||||||
action = request.POST.get('action', None)
|
action = request.POST.get('action', None)
|
||||||
@ -751,6 +768,7 @@ def mass_update(request):
|
|||||||
mass_update = staff_member_required(mass_update)
|
mass_update = staff_member_required(mass_update)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def ticket_list(request):
|
def ticket_list(request):
|
||||||
context = {}
|
context = {}
|
||||||
|
|
||||||
@ -934,6 +952,7 @@ def ticket_list(request):
|
|||||||
ticket_list = staff_member_required(ticket_list)
|
ticket_list = staff_member_required(ticket_list)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def edit_ticket(request, ticket_id):
|
def edit_ticket(request, ticket_id):
|
||||||
ticket = get_object_or_404(Ticket, id=ticket_id)
|
ticket = get_object_or_404(Ticket, id=ticket_id)
|
||||||
if not _has_access_to_queue(request.user, ticket.queue):
|
if not _has_access_to_queue(request.user, ticket.queue):
|
||||||
@ -951,6 +970,7 @@ def edit_ticket(request, ticket_id):
|
|||||||
edit_ticket = staff_member_required(edit_ticket)
|
edit_ticket = staff_member_required(edit_ticket)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
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(User.USERNAME_FIELD)
|
assignable_users = User.objects.filter(is_active=True, is_staff=True).order_by(User.USERNAME_FIELD)
|
||||||
@ -988,6 +1008,7 @@ def create_ticket(request):
|
|||||||
create_ticket = staff_member_required(create_ticket)
|
create_ticket = staff_member_required(create_ticket)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def raw_details(request, type):
|
def raw_details(request, type):
|
||||||
# TODO: This currently only supports spewing out 'PreSetReply' objects,
|
# TODO: This currently only supports spewing out 'PreSetReply' objects,
|
||||||
# in the future it needs to be expanded to include other items. All it
|
# in the future it needs to be expanded to include other items. All it
|
||||||
@ -1004,9 +1025,9 @@ def raw_details(request, type):
|
|||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
raise Http404
|
raise Http404
|
||||||
raw_details = staff_member_required(raw_details)
|
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def hold_ticket(request, ticket_id, unhold=False):
|
def hold_ticket(request, ticket_id, unhold=False):
|
||||||
ticket = get_object_or_404(Ticket, id=ticket_id)
|
ticket = get_object_or_404(Ticket, id=ticket_id)
|
||||||
if not _has_access_to_queue(request.user, ticket.queue):
|
if not _has_access_to_queue(request.user, ticket.queue):
|
||||||
@ -1031,19 +1052,20 @@ def hold_ticket(request, ticket_id, unhold=False):
|
|||||||
ticket.save()
|
ticket.save()
|
||||||
|
|
||||||
return HttpResponseRedirect(ticket.get_absolute_url())
|
return HttpResponseRedirect(ticket.get_absolute_url())
|
||||||
hold_ticket = staff_member_required(hold_ticket)
|
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def unhold_ticket(request, ticket_id):
|
def unhold_ticket(request, ticket_id):
|
||||||
return hold_ticket(request, ticket_id, unhold=True)
|
return hold_ticket(request, ticket_id, unhold=True)
|
||||||
unhold_ticket = staff_member_required(unhold_ticket)
|
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def rss_list(request):
|
def rss_list(request):
|
||||||
return render(request, 'helpdesk/rss_list.html', {'queues': Queue.objects.all()})
|
return render(request, 'helpdesk/rss_list.html', {'queues': Queue.objects.all()})
|
||||||
rss_list = staff_member_required(rss_list)
|
rss_list = staff_member_required(rss_list)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def report_index(request):
|
def report_index(request):
|
||||||
number_tickets = Ticket.objects.all().count()
|
number_tickets = Ticket.objects.all().count()
|
||||||
saved_query = request.GET.get('saved_query', None)
|
saved_query = request.GET.get('saved_query', None)
|
||||||
@ -1092,6 +1114,7 @@ def report_index(request):
|
|||||||
report_index = staff_member_required(report_index)
|
report_index = staff_member_required(report_index)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def run_report(request, report):
|
def run_report(request, report):
|
||||||
if Ticket.objects.all().count() == 0 or report not in (
|
if Ticket.objects.all().count() == 0 or report not in (
|
||||||
'queuemonth', 'usermonth', 'queuestatus', 'queuepriority', 'userstatus',
|
'queuemonth', 'usermonth', 'queuestatus', 'queuepriority', 'userstatus',
|
||||||
@ -1292,6 +1315,7 @@ def run_report(request, report):
|
|||||||
run_report = staff_member_required(run_report)
|
run_report = staff_member_required(run_report)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def save_query(request):
|
def save_query(request):
|
||||||
title = request.POST.get('title', None)
|
title = request.POST.get('title', None)
|
||||||
shared = request.POST.get('shared', False)
|
shared = request.POST.get('shared', False)
|
||||||
@ -1309,6 +1333,7 @@ def save_query(request):
|
|||||||
save_query = staff_member_required(save_query)
|
save_query = staff_member_required(save_query)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def delete_saved_query(request, id):
|
def delete_saved_query(request, id):
|
||||||
query = get_object_or_404(SavedSearch, id=id, user=request.user)
|
query = get_object_or_404(SavedSearch, id=id, user=request.user)
|
||||||
|
|
||||||
@ -1320,6 +1345,7 @@ def delete_saved_query(request, id):
|
|||||||
delete_saved_query = staff_member_required(delete_saved_query)
|
delete_saved_query = staff_member_required(delete_saved_query)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def user_settings(request):
|
def user_settings(request):
|
||||||
s = request.user.usersettings_helpdesk
|
s = request.user.usersettings_helpdesk
|
||||||
if request.POST:
|
if request.POST:
|
||||||
@ -1334,6 +1360,7 @@ def user_settings(request):
|
|||||||
user_settings = staff_member_required(user_settings)
|
user_settings = staff_member_required(user_settings)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_superuser_required
|
||||||
def email_ignore(request):
|
def email_ignore(request):
|
||||||
return render(request, 'helpdesk/email_ignore_list.html', {
|
return render(request, 'helpdesk/email_ignore_list.html', {
|
||||||
'ignore_list': IgnoreEmail.objects.all(),
|
'ignore_list': IgnoreEmail.objects.all(),
|
||||||
@ -1341,6 +1368,7 @@ def email_ignore(request):
|
|||||||
email_ignore = superuser_required(email_ignore)
|
email_ignore = superuser_required(email_ignore)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_superuser_required
|
||||||
def email_ignore_add(request):
|
def email_ignore_add(request):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = EmailIgnoreForm(request.POST)
|
form = EmailIgnoreForm(request.POST)
|
||||||
@ -1354,6 +1382,7 @@ def email_ignore_add(request):
|
|||||||
email_ignore_add = superuser_required(email_ignore_add)
|
email_ignore_add = superuser_required(email_ignore_add)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_superuser_required
|
||||||
def email_ignore_del(request, id):
|
def email_ignore_del(request, id):
|
||||||
ignore = get_object_or_404(IgnoreEmail, id=id)
|
ignore = get_object_or_404(IgnoreEmail, id=id)
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@ -1364,6 +1393,7 @@ def email_ignore_del(request, id):
|
|||||||
email_ignore_del = superuser_required(email_ignore_del)
|
email_ignore_del = superuser_required(email_ignore_del)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def ticket_cc(request, ticket_id):
|
def ticket_cc(request, ticket_id):
|
||||||
ticket = get_object_or_404(Ticket, id=ticket_id)
|
ticket = get_object_or_404(Ticket, id=ticket_id)
|
||||||
if not _has_access_to_queue(request.user, ticket.queue):
|
if not _has_access_to_queue(request.user, ticket.queue):
|
||||||
@ -1377,6 +1407,7 @@ def ticket_cc(request, ticket_id):
|
|||||||
ticket_cc = staff_member_required(ticket_cc)
|
ticket_cc = staff_member_required(ticket_cc)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def ticket_cc_add(request, ticket_id):
|
def ticket_cc_add(request, ticket_id):
|
||||||
ticket = get_object_or_404(Ticket, id=ticket_id)
|
ticket = get_object_or_404(Ticket, id=ticket_id)
|
||||||
if not _has_access_to_queue(request.user, ticket.queue):
|
if not _has_access_to_queue(request.user, ticket.queue):
|
||||||
@ -1401,6 +1432,7 @@ def ticket_cc_add(request, ticket_id):
|
|||||||
ticket_cc_add = staff_member_required(ticket_cc_add)
|
ticket_cc_add = staff_member_required(ticket_cc_add)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def ticket_cc_del(request, ticket_id, cc_id):
|
def ticket_cc_del(request, ticket_id, cc_id):
|
||||||
cc = get_object_or_404(TicketCC, ticket__id=ticket_id, id=cc_id)
|
cc = get_object_or_404(TicketCC, ticket__id=ticket_id, id=cc_id)
|
||||||
|
|
||||||
@ -1412,6 +1444,7 @@ def ticket_cc_del(request, ticket_id, cc_id):
|
|||||||
ticket_cc_del = staff_member_required(ticket_cc_del)
|
ticket_cc_del = staff_member_required(ticket_cc_del)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def ticket_dependency_add(request, ticket_id):
|
def ticket_dependency_add(request, ticket_id):
|
||||||
ticket = get_object_or_404(Ticket, id=ticket_id)
|
ticket = get_object_or_404(Ticket, id=ticket_id)
|
||||||
if not _has_access_to_queue(request.user, ticket.queue):
|
if not _has_access_to_queue(request.user, ticket.queue):
|
||||||
@ -1433,6 +1466,7 @@ def ticket_dependency_add(request, ticket_id):
|
|||||||
ticket_dependency_add = staff_member_required(ticket_dependency_add)
|
ticket_dependency_add = staff_member_required(ticket_dependency_add)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def ticket_dependency_del(request, ticket_id, dependency_id):
|
def ticket_dependency_del(request, ticket_id, dependency_id):
|
||||||
dependency = get_object_or_404(TicketDependency, ticket__id=ticket_id, id=dependency_id)
|
dependency = get_object_or_404(TicketDependency, ticket__id=ticket_id, id=dependency_id)
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@ -1442,6 +1476,7 @@ def ticket_dependency_del(request, ticket_id, dependency_id):
|
|||||||
ticket_dependency_del = staff_member_required(ticket_dependency_del)
|
ticket_dependency_del = staff_member_required(ticket_dependency_del)
|
||||||
|
|
||||||
|
|
||||||
|
@helpdesk_staff_member_required
|
||||||
def attachment_del(request, ticket_id, attachment_id):
|
def attachment_del(request, ticket_id, attachment_id):
|
||||||
ticket = get_object_or_404(Ticket, id=ticket_id)
|
ticket = get_object_or_404(Ticket, id=ticket_id)
|
||||||
if not _has_access_to_queue(request.user, ticket.queue):
|
if not _has_access_to_queue(request.user, ticket.queue):
|
||||||
|
Loading…
Reference in New Issue
Block a user