Custom logic for determining if the user is considered helpdesk staff.

This commit is contained in:
Stefano Brentegani 2014-07-20 10:36:24 +02:00
parent 3bd2d67193
commit 13830a84e5
3 changed files with 49 additions and 33 deletions

View File

@ -75,15 +75,15 @@ These changes are visible throughout django-helpdesk
**Default:** ``HELPDESK_SHOW_CHANGE_PASSWORD = False`` **Default:** ``HELPDESK_SHOW_CHANGE_PASSWORD = False``
- **HELPDESK_FOLLOWUP_MOD** Allow user to override default layout for 'followups' (work in progress) - **HELPDESK_FOLLOWUP_MOD** Allow user to override default layout for 'followups' (work in progress)
**Default:** ``HELPDESK_FOLLOWUP_MOD = False`` **Default:** ``HELPDESK_FOLLOWUP_MOD = False``
- **HELPDESK_CUSTOM_WELCOME** Show custom welcome message in dashboard? - **HELPDESK_CUSTOM_WELCOME** Show custom welcome message in dashboard?
**Default:** ``HELPDESK_CUSTOM_WELCOME = False`` **Default:** ``HELPDESK_CUSTOM_WELCOME = False``
- **HELPDESK_AUTO_SUBSCRIBE_ON_TICKET_RESPONSE ** Auto-subscribe user to ticket as a 'CC' if (s)he responds to a ticket? - **HELPDESK_AUTO_SUBSCRIBE_ON_TICKET_RESPONSE ** Auto-subscribe user to ticket as a 'CC' if (s)he responds to a ticket?
**Default:** ``HELPDESK_AUTO_SUBSCRIBE_ON_TICKET_RESPONSE = False`` **Default:** ``HELPDESK_AUTO_SUBSCRIBE_ON_TICKET_RESPONSE = False``
- **HELPDESK_EMAIL_SUBJECT_TEMPLATE ** Subject template for templated emails. ``%(subject)s`` represents the subject wording from the email template (e.g. "(Closed)"). - **HELPDESK_EMAIL_SUBJECT_TEMPLATE ** Subject template for templated emails. ``%(subject)s`` represents the subject wording from the email template (e.g. "(Closed)").
@ -97,28 +97,35 @@ Options shown on public pages
These options only change display of items on public-facing pages, not staff pages. These options only change display of items on public-facing pages, not staff pages.
- **HELPDESK_VIEW_A_TICKET_PUBLIC** Show 'View a Ticket' section on public page? - **HELPDESK_VIEW_A_TICKET_PUBLIC** Show 'View a Ticket' section on public page?
**Default:** ``HELPDESK_VIEW_A_TICKET_PUBLIC = True`` **Default:** ``HELPDESK_VIEW_A_TICKET_PUBLIC = True``
- **HELPDESK_SUBMIT_A_TICKET_PUBLIC** Show 'submit a ticket' section & form on public page? - **HELPDESK_SUBMIT_A_TICKET_PUBLIC** Show 'submit a ticket' section & form on public page?
**Default:** ``HELPDESK_SUBMIT_A_TICKET_PUBLIC = True`` **Default:** ``HELPDESK_SUBMIT_A_TICKET_PUBLIC = True``
- **HELPDESK_SHOW_KB_ON_HOMEPAGE** Should we should the KB categories on the homepage? - **HELPDESK_SHOW_KB_ON_HOMEPAGE** Should we should the KB categories on the homepage?
**Default:** ``HELPDESK_SHOW_KB_ON_HOMEPAGE = False`` **Default:** ``HELPDESK_SHOW_KB_ON_HOMEPAGE = False``
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? This will also change how 'staff_member_required'
in staff.py will be defined. in staff.py will be defined.
**Default:** ``HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = False`` **Default:** ``HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = False``
- **HELPDESK_CUSTOM_STAFF_FILTER_CALLBACK** Apply a custom authorisation logic when defining 'staff_member_required' in staff.py.
If set, `HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE` will be ignored when determining staff access.
The value should be a function accepting the active user as a parameter and returning True if the user is considered helpdesk
staff.
**Default:** ``HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE = None``
- **HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP** Show edit buttons in ticket follow ups? - **HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP** Show edit buttons in ticket follow ups?
**Default:** ``HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP = True`` **Default:** ``HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP = True``
- **HELPDESK_SHOW_DELETE_BUTTON_SUPERUSER_FOLLOW_UP** Show delete buttons in ticket follow ups if user is 'superuser'? - **HELPDESK_SHOW_DELETE_BUTTON_SUPERUSER_FOLLOW_UP** Show delete buttons in ticket follow ups if user is 'superuser'?

View File

@ -2,7 +2,7 @@
Default settings for django-helpdesk. Default settings for django-helpdesk.
""" """
import warnings
from django.conf import settings from django.conf import settings
@ -60,10 +60,17 @@ HELPDESK_SUBMIT_A_TICKET_PUBLIC = getattr(settings, 'HELPDESK_SUBMIT_A_TICKET_PU
''' options for update_ticket views ''' ''' options for update_ticket views '''
# allow non-staff users to interact with tickets? this will also change how 'staff_member_required' # allow non-staff users to interact with tickets? this will also change how 'staff_member_required'
# in staff.py will be defined. # 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, 'HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE', False)
# apply a custom authorisation logic when defining 'staff_member_required' in staff.py.
HELPDESK_CUSTOM_STAFF_FILTER_CALLBACK = getattr(settings, 'HELPDESK_CUSTOM_STAFF_FILTER_CALLBACK', None)
if HELPDESK_CUSTOM_STAFF_FILTER_CALLBACK and HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE:
warnings.warn(
"The HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE and HELPDESK_CUSTOM_STAFF_FILTER_CALLBACK settings cannot be both defined. "
"Only HELPDESK_CUSTOM_STAFF_FILTER_CALLBACK will be considered in determining staff access.", RuntimeWarning)
# 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', True) HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP = getattr(settings, 'HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP', True)
@ -73,10 +80,10 @@ HELPDESK_SHOW_DELETE_BUTTON_SUPERUSER_FOLLOW_UP = getattr(settings, 'HELPDESK_SH
# make all updates public by default? this will hide the 'is this update public' checkbox # make all updates public by default? this will hide the 'is this update public' checkbox
HELPDESK_UPDATE_PUBLIC_DEFAULT = getattr(settings, 'HELPDESK_UPDATE_PUBLIC_DEFAULT', False) HELPDESK_UPDATE_PUBLIC_DEFAULT = getattr(settings, 'HELPDESK_UPDATE_PUBLIC_DEFAULT', False)
# only show staff users in ticket owner drop-downs # only show staff users in ticket owner drop-downs
HELPDESK_STAFF_ONLY_TICKET_OWNERS = getattr(settings, 'HELPDESK_STAFF_ONLY_TICKET_OWNERS', False) HELPDESK_STAFF_ONLY_TICKET_OWNERS = getattr(settings, 'HELPDESK_STAFF_ONLY_TICKET_OWNERS', False)
# only show staff users in ticket cc drop-down # only show staff users in ticket cc drop-down
HELPDESK_STAFF_ONLY_TICKET_CC = getattr(settings, 'HELPDESK_STAFF_ONLY_TICKET_CC', False) HELPDESK_STAFF_ONLY_TICKET_CC = getattr(settings, 'HELPDESK_STAFF_ONLY_TICKET_CC', False)

View File

@ -39,8 +39,10 @@ from helpdesk.forms import TicketForm, UserSettingsForm, EmailIgnoreForm, EditTi
from helpdesk.lib import send_templated_mail, query_to_dict, apply_query, safe_template_context from helpdesk.lib import send_templated_mail, query_to_dict, apply_query, safe_template_context
from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch, IgnoreEmail, TicketCC, TicketDependency from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch, IgnoreEmail, TicketCC, TicketDependency
from helpdesk import settings as helpdesk_settings from helpdesk import settings as helpdesk_settings
if helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE: if helpdesk_settings.HELPDESK_CUSTOM_STAFF_FILTER_CALLBACK:
staff_member_required = user_passes_test(helpdesk_settings.HELPDESK_CUSTOM_STAFF_FILTER_CALLBACK)
elif helpdesk_settings.HELPDESK_ALLOW_NON_STAFF_TICKET_UPDATE:
# treat 'normal' users like 'staff' # treat 'normal' users like 'staff'
staff_member_required = user_passes_test(lambda u: u.is_authenticated() and u.is_active) staff_member_required = user_passes_test(lambda u: u.is_authenticated() and u.is_active)
else: else:
@ -69,7 +71,7 @@ def dashboard(request):
# closed & resolved tickets, assigned to current user # closed & resolved tickets, assigned to current user
tickets_closed_resolved = Ticket.objects.filter( tickets_closed_resolved = Ticket.objects.filter(
assigned_to=request.user, assigned_to=request.user,
status__in = [Ticket.CLOSED_STATUS, Ticket.RESOLVED_STATUS]) status__in = [Ticket.CLOSED_STATUS, Ticket.RESOLVED_STATUS])
unassigned_tickets = Ticket.objects.filter( unassigned_tickets = Ticket.objects.filter(
@ -107,7 +109,7 @@ def dashboard(request):
GROUP BY queue, name GROUP BY queue, name
ORDER BY q.id; ORDER BY q.id;
""") """)
dash_tickets = query_to_dict(cursor.fetchall(), cursor.description) dash_tickets = query_to_dict(cursor.fetchall(), cursor.description)
return render_to_response('helpdesk/dashboard.html', return render_to_response('helpdesk/dashboard.html',
@ -200,7 +202,7 @@ def view_ticket(request, ticket_id):
if request.GET.has_key('take'): if request.GET.has_key('take'):
# Allow the user to assign the ticket to themselves whilst viewing it. # Allow the user to assign the ticket to themselves whilst viewing it.
# Trick the update_ticket() view into thinking it's being called with # Trick the update_ticket() view into thinking it's being called with
# a valid POST. # a valid POST.
request.POST = { request.POST = {
@ -261,7 +263,7 @@ view_ticket = staff_member_required(view_ticket)
def return_ticketccstring_and_show_subscribe(user, ticket): 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.username.upper()
useremail = user.email.upper() useremail = user.email.upper()
@ -448,7 +450,7 @@ def update_ticket(request, ticket_id, public=False):
messages_sent_to = [] messages_sent_to = []
# ticket might have changed above, so we re-instantiate context with the # ticket might have changed above, so we re-instantiate context with the
# (possibly) updated ticket. # (possibly) updated ticket.
context = safe_template_context(ticket) context = safe_template_context(ticket)
context.update( context.update(
@ -457,7 +459,7 @@ def update_ticket(request, ticket_id, public=False):
) )
if public and (f.comment or (f.new_status in (Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS))): if public and (f.comment or (f.new_status in (Ticket.RESOLVED_STATUS, Ticket.CLOSED_STATUS))):
if f.new_status == Ticket.RESOLVED_STATUS: if f.new_status == Ticket.RESOLVED_STATUS:
template = 'resolved_' template = 'resolved_'
@ -712,7 +714,7 @@ def ticket_list(request):
or request.GET.has_key('status') or request.GET.has_key('status')
or request.GET.has_key('q') or request.GET.has_key('q')
or request.GET.has_key('sort') or request.GET.has_key('sort')
or request.GET.has_key('sortreverse') or request.GET.has_key('sortreverse')
): ):
# Fall-back if no querying is being done, force the list to only # Fall-back if no querying is being done, force the list to only
@ -751,7 +753,7 @@ def ticket_list(request):
date_from = request.GET.get('date_from') date_from = request.GET.get('date_from')
if date_from: if date_from:
query_params['filtering']['created__gte'] = date_from query_params['filtering']['created__gte'] = date_from
date_to = request.GET.get('date_to') date_to = request.GET.get('date_to')
if date_to: if date_to:
query_params['filtering']['created__lte'] = date_to query_params['filtering']['created__lte'] = date_to
@ -842,7 +844,7 @@ def edit_ticket(request, ticket_id):
return HttpResponseRedirect(ticket.get_absolute_url()) return HttpResponseRedirect(ticket.get_absolute_url())
else: else:
form = EditTicketForm(instance=ticket) form = EditTicketForm(instance=ticket)
return render_to_response('helpdesk/edit_ticket.html', return render_to_response('helpdesk/edit_ticket.html',
RequestContext(request, { RequestContext(request, {
'form': form, 'form': form,
@ -854,7 +856,7 @@ def create_ticket(request):
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('username')
else: else:
assignable_users = User.objects.filter(is_active=True).order_by('username') assignable_users = User.objects.filter(is_active=True).order_by('username')
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()]
@ -955,7 +957,7 @@ def run_report(request, report):
return HttpResponseRedirect(reverse("helpdesk_report_index")) return HttpResponseRedirect(reverse("helpdesk_report_index"))
report_queryset = Ticket.objects.all().select_related() report_queryset = Ticket.objects.all().select_related()
from_saved_query = False from_saved_query = False
saved_query = None saved_query = None
@ -993,7 +995,7 @@ def run_report(request, report):
_('Nov'), _('Nov'),
_('Dec'), _('Dec'),
) )
first_ticket = Ticket.objects.all().order_by('created')[0] first_ticket = Ticket.objects.all().order_by('created')[0]
first_month = first_ticket.created.month first_month = first_ticket.created.month
first_year = first_ticket.created.year first_year = first_ticket.created.year
@ -1106,15 +1108,15 @@ def run_report(request, report):
if report == 'daysuntilticketclosedbymonth': if report == 'daysuntilticketclosedbymonth':
summarytable2[metric1, metric2] += metric3 summarytable2[metric1, metric2] += metric3
table = [] table = []
if report == 'daysuntilticketclosedbymonth': if report == 'daysuntilticketclosedbymonth':
for key in summarytable2.keys(): for key in summarytable2.keys():
summarytable[key] = summarytable2[key] / summarytable[key] summarytable[key] = summarytable2[key] / summarytable[key]
header1 = sorted(set(list( i.encode('utf-8') for i,_ in summarytable.keys() ))) header1 = sorted(set(list( i.encode('utf-8') for i,_ in summarytable.keys() )))
column_headings = [col1heading] + possible_options column_headings = [col1heading] + possible_options
# Pivot the data so that 'header1' fields are always first column # Pivot the data so that 'header1' fields are always first column
@ -1330,11 +1332,11 @@ def calc_basic_ticket_stats(Ticket):
date_30_str = date_30.strftime('%Y-%m-%d') date_30_str = date_30.strftime('%Y-%m-%d')
date_60_str = date_60.strftime('%Y-%m-%d') date_60_str = date_60.strftime('%Y-%m-%d')
# > 0 & <= 30 # > 0 & <= 30
ota_le_30 = all_open_tickets.filter(created__gte = date_30_str) ota_le_30 = all_open_tickets.filter(created__gte = date_30_str)
N_ota_le_30 = len(ota_le_30) N_ota_le_30 = len(ota_le_30)
# >= 30 & <= 60 # >= 30 & <= 60
ota_le_60_ge_30 = all_open_tickets.filter(created__gte = date_60_str, created__lte = date_30_str) ota_le_60_ge_30 = all_open_tickets.filter(created__gte = date_60_str, created__lte = date_30_str)
N_ota_le_60_ge_30 = len(ota_le_60_ge_30) N_ota_le_60_ge_30 = len(ota_le_60_ge_30)
@ -1357,7 +1359,7 @@ def calc_basic_ticket_stats(Ticket):
average_nbr_days_until_ticket_closed_last_60_days = calc_average_nbr_days_until_ticket_resolved(all_closed_last_60_days) average_nbr_days_until_ticket_closed_last_60_days = calc_average_nbr_days_until_ticket_resolved(all_closed_last_60_days)
# put together basic stats # put together basic stats
basic_ticket_stats = { 'average_nbr_days_until_ticket_closed': average_nbr_days_until_ticket_closed, basic_ticket_stats = { 'average_nbr_days_until_ticket_closed': average_nbr_days_until_ticket_closed,
'average_nbr_days_until_ticket_closed_last_60_days': average_nbr_days_until_ticket_closed_last_60_days, 'average_nbr_days_until_ticket_closed_last_60_days': average_nbr_days_until_ticket_closed_last_60_days,
'open_ticket_stats': ots, } 'open_ticket_stats': ots, }