mirror of
https://gitea.mueller.network/extern/django-helpdesk.git
synced 2024-11-21 15:33:09 +01:00
Refactor custom commands with modern syntax
This commit is contained in:
parent
2686c46dbf
commit
0a1e73918d
@ -38,7 +38,7 @@ Before django-helpdesk will be much use, you need to do some basic configuration
|
||||
|
||||
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::
|
||||
|
||||
0 0 * * 0 /path/to/helpdesksite/manage.py create_escalation_exclusions --days saturday,sunday --escalate-verbosely
|
||||
0 0 * * 0 /path/to/helpdesksite/manage.py create_escalation_exclusions --days saturday sunday
|
||||
|
||||
This will, on a weekly basis, create exclusions for the coming weekend.
|
||||
|
||||
|
@ -11,63 +11,7 @@ scripts/create_escalation_exclusion.py - Easy way to routinely add particular
|
||||
|
||||
from datetime import date, timedelta
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
import getopt
|
||||
from helpdesk.models import EscalationExclusion, Queue
|
||||
from optparse import make_option
|
||||
import sys
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def __init__(self):
|
||||
BaseCommand.__init__(self)
|
||||
|
||||
self.option_list += (
|
||||
make_option(
|
||||
'--days', '-d',
|
||||
help='Days of week (monday, tuesday, etc)'),
|
||||
make_option(
|
||||
'--occurrences', '-o',
|
||||
type='int',
|
||||
default=1,
|
||||
help='Occurrences: How many weeks ahead to exclude this day'),
|
||||
make_option(
|
||||
'--queues', '-q',
|
||||
help='Queues to include (default: all). Use queue slugs'),
|
||||
make_option(
|
||||
'--escalate-verbosely', '-x',
|
||||
action='store_true',
|
||||
default=False,
|
||||
dest='escalate-verbosely',
|
||||
help='Display a list of dates excluded'),
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
days = options['days']
|
||||
# optparse should already handle the `or 1`
|
||||
occurrences = options['occurrences'] or 1
|
||||
verbose = False
|
||||
queue_slugs = options['queues']
|
||||
queues = []
|
||||
|
||||
if options['escalate-verbosely']:
|
||||
verbose = True
|
||||
|
||||
if not (days and occurrences):
|
||||
raise CommandError('One or more occurrences must be specified.')
|
||||
|
||||
if queue_slugs is not None:
|
||||
queue_set = queue_slugs.split(',')
|
||||
for queue in queue_set:
|
||||
try:
|
||||
q = Queue.objects.get(slug__exact=queue)
|
||||
except Queue.DoesNotExist:
|
||||
raise CommandError("Queue %s does not exist." % queue)
|
||||
queues.append(q)
|
||||
|
||||
create_exclusions(days=days, occurrences=occurrences,
|
||||
verbose=verbose, queues=queues)
|
||||
|
||||
|
||||
day_names = {
|
||||
'monday': 0,
|
||||
@ -80,79 +24,70 @@ day_names = {
|
||||
}
|
||||
|
||||
|
||||
def create_exclusions(days, occurrences, verbose, queues):
|
||||
days = days.split(',')
|
||||
for day in days:
|
||||
day_name = day
|
||||
day = day_names[day]
|
||||
workdate = date.today()
|
||||
i = 0
|
||||
while i < occurrences:
|
||||
if day == workdate.weekday():
|
||||
if EscalationExclusion.objects.filter(date=workdate).count() == 0:
|
||||
esc = EscalationExclusion(
|
||||
name='Auto Exclusion for %s' % day_name, date=workdate)
|
||||
esc.save()
|
||||
class Command(BaseCommand):
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'-d',
|
||||
'--days',
|
||||
nargs='*',
|
||||
choices=list(day_names.keys()),
|
||||
required=True,
|
||||
help='Days of week (monday, tuesday, etc)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-o',
|
||||
'--occurrences',
|
||||
default=1,
|
||||
type=int,
|
||||
help='Occurrences: How many weeks ahead to exclude this day'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-q',
|
||||
'--queues',
|
||||
nargs='*',
|
||||
choices=list(Queue.objects.values_list('slug', flat=True)),
|
||||
help='Queues to include (default: all). Use queue slugs'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-x',
|
||||
'--exclude-verbosely',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Display a list of dates excluded'
|
||||
)
|
||||
|
||||
if verbose:
|
||||
print("Created exclusion for %s %s" %
|
||||
(day_name, workdate))
|
||||
def handle(self, *args, **options):
|
||||
days = options['days']
|
||||
occurrences = options['occurrences']
|
||||
verbose = options['exclude_verbosely']
|
||||
queue_slugs = options['queues']
|
||||
|
||||
if not (days and occurrences):
|
||||
raise CommandError('One or more occurrences must be specified.')
|
||||
|
||||
queues = []
|
||||
if queue_slugs is not None:
|
||||
queues = Queue.objects.filter(slug__in=queue_slugs)
|
||||
|
||||
for day_name in days:
|
||||
day = day_names[day_name]
|
||||
workdate = date.today()
|
||||
i = 0
|
||||
while i < occurrences:
|
||||
if day == workdate.weekday():
|
||||
if EscalationExclusion.objects.filter(date=workdate).count() == 0:
|
||||
esc = EscalationExclusion.objects.create(
|
||||
name=f'Auto Exclusion for {day_name}',
|
||||
date=workdate
|
||||
)
|
||||
|
||||
for q in queues:
|
||||
esc.queues.add(q)
|
||||
if verbose:
|
||||
print(" - for queue %s" % q)
|
||||
self.stdout.write(f"Created exclusion for {day_name} {workdate}")
|
||||
|
||||
i += 1
|
||||
workdate += timedelta(days=1)
|
||||
for q in queues:
|
||||
esc.queues.add(q)
|
||||
if verbose:
|
||||
self.stdout.write(f" - for queue {q}")
|
||||
|
||||
|
||||
def usage():
|
||||
print("Options:")
|
||||
print(" --days, -d: Days of week (monday, tuesday, etc)")
|
||||
print(" --occurrences, -o: Occurrences: How many weeks ahead to exclude this day")
|
||||
print(" --queues, -q: Queues to include (default: all). Use queue slugs")
|
||||
print(" --verbose, -v: Display a list of dates excluded")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# This script can be run from the command-line or via Django's manage.py.
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], 'd:o:q:v', [
|
||||
'days=', 'occurrences=', 'verbose', 'queues='])
|
||||
except getopt.GetoptError:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
|
||||
days = None
|
||||
occurrences = 1
|
||||
verbose = False
|
||||
queue_slugs = None
|
||||
queues = []
|
||||
|
||||
for o, a in opts:
|
||||
if o in ('-x', '--escalate-verbosely'):
|
||||
verbose = True
|
||||
if o in ('-d', '--days'):
|
||||
days = a
|
||||
if o in ('-q', '--queues'):
|
||||
queue_slugs = a
|
||||
if o in ('-o', '--occurrences'):
|
||||
occurrences = int(a) or 1
|
||||
|
||||
if not (days and occurrences):
|
||||
usage()
|
||||
sys.exit(2)
|
||||
|
||||
if queue_slugs is not None:
|
||||
queue_set = queue_slugs.split(',')
|
||||
for queue in queue_set:
|
||||
try:
|
||||
q = Queue.objects.get(slug__exact=queue)
|
||||
except Queue.DoesNotExist:
|
||||
print("Queue %s does not exist." % queue)
|
||||
sys.exit(2)
|
||||
queues.append(q)
|
||||
|
||||
create_exclusions(days=days, occurrences=occurrences,
|
||||
verbose=verbose, queues=queues)
|
||||
i += 1
|
||||
workdate += timedelta(days=1)
|
||||
|
@ -15,55 +15,54 @@ scripts/create_queue_permissions.py -
|
||||
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db.utils import IntegrityError
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from helpdesk.models import Queue
|
||||
from optparse import make_option
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def __init__(self):
|
||||
BaseCommand.__init__(self)
|
||||
|
||||
self.option_list += (
|
||||
make_option(
|
||||
'--queues', '-q',
|
||||
help='Queues to include (default: all). Use queue slugs'),
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'-q',
|
||||
'--queues',
|
||||
nargs='*',
|
||||
choices=list(Queue.objects.values_list('slug', flat=True)),
|
||||
help='Queues to include (default: all). Use queue slugs'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-x',
|
||||
'--escalate-verbosely',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Display a list of dates excluded'
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
queue_slugs = options['queues']
|
||||
queues = []
|
||||
|
||||
if queue_slugs is not None:
|
||||
queue_set = queue_slugs.split(',')
|
||||
for queue in queue_set:
|
||||
try:
|
||||
q = Queue.objects.get(slug__exact=queue)
|
||||
except Queue.DoesNotExist:
|
||||
raise CommandError("Queue %s does not exist." % queue)
|
||||
queues.append(q)
|
||||
queues = Queue.objects.filter(slug__in=queue_slugs)
|
||||
else:
|
||||
queues = list(Queue.objects.all())
|
||||
queues = Queue.objects.all()
|
||||
|
||||
# Create permissions for the queues, which may be all or not
|
||||
for q in queues:
|
||||
self.stdout.write("Preparing Queue %s [%s]" % (q.title, q.slug))
|
||||
self.stdout.write(f"Preparing Queue {q} [{q.slug}]")
|
||||
|
||||
if q.permission_name:
|
||||
self.stdout.write(
|
||||
" .. already has `permission_name=%s`" % q.permission_name)
|
||||
f" .. already has `permission_name={q.permission_name}`")
|
||||
basename = q.permission_name[9:]
|
||||
else:
|
||||
basename = q.generate_permission_name()
|
||||
self.stdout.write(
|
||||
" .. generated `permission_name=%s`" % q.permission_name)
|
||||
f" .. generated `permission_name={q.permission_name}`")
|
||||
q.save()
|
||||
|
||||
self.stdout.write(
|
||||
" .. checking permission codename `%s`" % basename)
|
||||
f" .. checking permission codename `{basename}`")
|
||||
|
||||
try:
|
||||
Permission.objects.create(
|
||||
|
@ -8,168 +8,93 @@ scripts/escalate_tickets.py - Easy way to escalate tickets based on their age,
|
||||
designed to be run from Cron or similar.
|
||||
"""
|
||||
|
||||
|
||||
from datetime import date, timedelta
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db.models import Q
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
import getopt
|
||||
from helpdesk.lib import safe_template_context
|
||||
from helpdesk.models import EscalationExclusion, FollowUp, Queue, Ticket, TicketChange
|
||||
from optparse import make_option
|
||||
import sys
|
||||
from helpdesk.models import EscalationExclusion, Queue, Ticket
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def __init__(self):
|
||||
BaseCommand.__init__(self)
|
||||
|
||||
self.option_list = (
|
||||
make_option(
|
||||
'--queues',
|
||||
help='Queues to include (default: all). Use queue slugs'),
|
||||
make_option(
|
||||
'--verboseescalation',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Display a list of dates excluded'),
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'-q',
|
||||
'--queues',
|
||||
nargs='*',
|
||||
choices=list(Queue.objects.values_list('slug', flat=True)),
|
||||
help='Queues to include (default: all). Use queue slugs'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-x',
|
||||
'--escalate-verbosely',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Display escalated tickets'
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
verbose = False
|
||||
queue_slugs = None
|
||||
queues = []
|
||||
|
||||
if 'verboseescalation' in options:
|
||||
verbose = True
|
||||
if 'queues' in options:
|
||||
queue_slugs = options['queues']
|
||||
verbose = options['escalate_verbosely']
|
||||
|
||||
queue_slugs = options['queues']
|
||||
# Only include queues with escalation configured
|
||||
queues = Queue.objects.filter(escalate_days__isnull=False).exclude(escalate_days=0)
|
||||
if queue_slugs is not None:
|
||||
queue_set = queue_slugs.split(',')
|
||||
for queue in queue_set:
|
||||
try:
|
||||
Queue.objects.get(slug__exact=queue)
|
||||
except Queue.DoesNotExist:
|
||||
raise CommandError("Queue %s does not exist." % queue)
|
||||
queues.append(queue)
|
||||
|
||||
escalate_tickets(queues=queues, verbose=verbose)
|
||||
|
||||
|
||||
def escalate_tickets(queues, verbose):
|
||||
""" Only include queues with escalation configured """
|
||||
queryset = Queue.objects.filter(
|
||||
escalate_days__isnull=False).exclude(escalate_days=0)
|
||||
if queues:
|
||||
queryset = queryset.filter(slug__in=queues)
|
||||
|
||||
for q in queryset:
|
||||
last = date.today() - timedelta(days=q.escalate_days)
|
||||
today = date.today()
|
||||
workdate = last
|
||||
|
||||
days = 0
|
||||
|
||||
while workdate < today:
|
||||
if EscalationExclusion.objects.filter(date=workdate).count() == 0:
|
||||
days += 1
|
||||
workdate = workdate + timedelta(days=1)
|
||||
|
||||
req_last_escl_date = date.today() - timedelta(days=days)
|
||||
queues = queues.filter(slug__in=queue_slugs)
|
||||
|
||||
if verbose:
|
||||
print("Processing: %s" % q)
|
||||
self.stdout.write(f"Processing: {queues}")
|
||||
|
||||
Q_OPEN_STATUSES = Q()
|
||||
for open_status in Ticket.OPEN_STATUSES:
|
||||
Q_OPEN_STATUSES |= Q(status=open_status)
|
||||
|
||||
for t in q.ticket_set.filter(
|
||||
Q_OPEN_STATUSES
|
||||
).exclude(
|
||||
priority=1
|
||||
).filter(
|
||||
Q(on_hold__isnull=True) |
|
||||
Q(on_hold=False)
|
||||
).filter(
|
||||
Q(last_escalation__lte=req_last_escl_date) |
|
||||
for queue in queues:
|
||||
last = date.today() - timedelta(days=queue.escalate_days)
|
||||
today = date.today()
|
||||
workdate = last
|
||||
|
||||
days = 0
|
||||
|
||||
while workdate < today:
|
||||
if not EscalationExclusion.objects.filter(date=workdate).exists():
|
||||
days += 1
|
||||
workdate = workdate + timedelta(days=1)
|
||||
|
||||
req_last_escl_date = timezone.now() - timedelta(days=days)
|
||||
|
||||
for ticket in queue.ticket_set.filter(
|
||||
status__in=Ticket.OPEN_STATUSES
|
||||
).exclude(
|
||||
priority=1
|
||||
).filter(
|
||||
Q(on_hold__isnull=True) | Q(on_hold=False)
|
||||
).filter(
|
||||
Q(last_escalation__lte=req_last_escl_date) |
|
||||
Q(last_escalation__isnull=True, created__lte=req_last_escl_date)
|
||||
):
|
||||
):
|
||||
|
||||
t.last_escalation = timezone.now()
|
||||
t.priority -= 1
|
||||
t.save()
|
||||
ticket.last_escalation = timezone.now()
|
||||
ticket.priority -= 1
|
||||
ticket.save()
|
||||
|
||||
context = safe_template_context(t)
|
||||
context = safe_template_context(ticket)
|
||||
|
||||
t.send(
|
||||
{'submitter': ('escalated_submitter', context),
|
||||
'ticket_cc': ('escalated_cc', context),
|
||||
'assigned_to': ('escalated_owner', context)},
|
||||
fail_silently=True,
|
||||
)
|
||||
|
||||
if verbose:
|
||||
print(" - Esclating %s from %s>%s" % (
|
||||
t.ticket,
|
||||
t.priority + 1,
|
||||
t.priority
|
||||
)
|
||||
ticket.send(
|
||||
{'submitter': ('escalated_submitter', context),
|
||||
'ticket_cc': ('escalated_cc', context),
|
||||
'assigned_to': ('escalated_owner', context)},
|
||||
fail_silently=True,
|
||||
)
|
||||
|
||||
f = FollowUp(
|
||||
ticket=t,
|
||||
title='Ticket Escalated',
|
||||
date=timezone.now(),
|
||||
public=True,
|
||||
comment=_('Ticket escalated after %s days' % q.escalate_days),
|
||||
)
|
||||
f.save()
|
||||
if verbose:
|
||||
self.stdout.write(f" - Esclating {ticket.ticket} from {ticket.priority + 1}>{ticket.priority}")
|
||||
|
||||
tc = TicketChange(
|
||||
followup=f,
|
||||
field=_('Priority'),
|
||||
old_value=t.priority + 1,
|
||||
new_value=t.priority,
|
||||
)
|
||||
tc.save()
|
||||
followup = ticket.followup_set.create(
|
||||
title=_('Ticket Escalated'),
|
||||
public=True,
|
||||
comment=_('Ticket escalated after %(nb)s days') % {'nb': queue.escalate_days},
|
||||
)
|
||||
|
||||
|
||||
def usage():
|
||||
print("Options:")
|
||||
print(" --queues: Queues to include (default: all). Use queue slugs")
|
||||
print(" --verboseescalation: Display a list of dates excluded")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
opts, args = getopt.getopt(
|
||||
sys.argv[1:], ['queues=', 'verboseescalation'])
|
||||
except getopt.GetoptError:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
|
||||
verbose = False
|
||||
queue_slugs = None
|
||||
queues = []
|
||||
|
||||
for o, a in opts:
|
||||
if o == '--verboseescalation':
|
||||
verbose = True
|
||||
if o == '--queues':
|
||||
queue_slugs = a
|
||||
|
||||
if queue_slugs is not None:
|
||||
queue_set = queue_slugs.split(',')
|
||||
for queue in queue_set:
|
||||
try:
|
||||
q = Queue.objects.get(slug__exact=queue)
|
||||
except Queue.DoesNotExist:
|
||||
print("Queue %s does not exist." % queue)
|
||||
sys.exit(2)
|
||||
queues.append(queue)
|
||||
|
||||
escalate_tickets(queues=queues, verbose=verbose)
|
||||
followup.ticketchange_set.create(
|
||||
field=_('Priority'),
|
||||
old_value=ticket.priority + 1,
|
||||
new_value=ticket.priority,
|
||||
)
|
||||
|
@ -16,9 +16,6 @@ from helpdesk.email import process_email
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
def __init__(self):
|
||||
BaseCommand.__init__(self)
|
||||
|
||||
help = 'Process django-helpdesk queues and process e-mails via POP3/IMAP or ' \
|
||||
'from a local mailbox directory as required, feeding them into the helpdesk.'
|
||||
|
||||
@ -39,8 +36,8 @@ class Command(BaseCommand):
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
quiet = options.get('quiet', False)
|
||||
debug_to_stdout = options.get('debug_to_stdout', False)
|
||||
quiet = options.get('quiet')
|
||||
debug_to_stdout = options.get('debug_to_stdout')
|
||||
process_email(quiet=quiet, debug_to_stdout=debug_to_stdout)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user