2008-08-19 10:50:38 +02:00
"""
2011-01-26 00:08:41 +01:00
django - helpdesk - A Django powered ticket tracker for small enterprise .
2007-12-27 01:29:17 +01:00
2008-02-06 05:36:07 +01:00
( c ) Copyright 2008 Jutda . All Rights Reserved . See LICENSE for details .
2007-12-27 01:29:17 +01:00
2008-08-19 10:50:38 +02:00
forms . py - Definitions of newforms - based forms for creating and maintaining
2008-02-06 05:36:07 +01:00
tickets .
2007-12-27 01:29:17 +01:00
"""
2020-02-06 10:10:07 +01:00
import logging
2021-02-11 01:58:01 +01:00
from datetime import datetime , date , time
2008-08-19 10:50:38 +02:00
2020-10-29 23:32:02 +01:00
from django . core . exceptions import ObjectDoesNotExist , ValidationError
2008-08-12 01:24:18 +02:00
from django import forms
2009-01-22 09:08:22 +01:00
from django . conf import settings
2016-10-18 15:37:57 +02:00
from django . utils . translation import ugettext_lazy as _
2016-10-21 17:14:12 +02:00
from django . contrib . auth import get_user_model
2016-11-21 03:12:19 +01:00
from django . utils import timezone
2007-12-27 01:29:17 +01:00
2018-10-31 16:24:57 +01:00
from helpdesk . lib import safe_template_context , process_attachments
2019-03-07 21:58:04 +01:00
from helpdesk . models import ( Ticket , Queue , FollowUp , IgnoreEmail , TicketCC ,
2020-01-07 13:33:06 +01:00
CustomField , TicketCustomFieldValue , TicketDependency , UserSettings , KBItem )
2012-01-17 22:40:44 +01:00
from helpdesk import settings as helpdesk_settings
2008-08-19 10:50:38 +02:00
2020-02-06 10:10:07 +01:00
logger = logging . getLogger ( __name__ )
2016-10-21 17:14:12 +02:00
User = get_user_model ( )
2016-10-30 20:53:18 +01:00
CUSTOMFIELD_TO_FIELD_DICT = {
# Store the immediate equivalences here
' boolean ' : forms . BooleanField ,
' date ' : forms . DateField ,
' time ' : forms . TimeField ,
' datetime ' : forms . DateTimeField ,
' email ' : forms . EmailField ,
' url ' : forms . URLField ,
' ipaddress ' : forms . GenericIPAddressField ,
' slug ' : forms . SlugField ,
}
2021-02-11 01:58:01 +01:00
CUSTOMFIELD_DATE_FORMAT = " % Y- % m- %d "
CUSTOMFIELD_TIME_FORMAT = " % H: % M: % S "
CUSTOMFIELD_DATETIME_FORMAT = f " { CUSTOMFIELD_DATE_FORMAT } { CUSTOMFIELD_TIME_FORMAT } "
2016-10-21 17:14:12 +02:00
2014-06-05 01:45:07 +02:00
class CustomFieldMixin ( object ) :
"""
Mixin that provides a method to turn CustomFields into an actual field
"""
2016-10-23 22:09:17 +02:00
2014-06-05 01:45:07 +02:00
def customfield_to_field ( self , field , instanceargs ) :
2020-06-03 10:21:43 +02:00
# Use TextInput widget by default
instanceargs [ ' widget ' ] = forms . TextInput ( attrs = { ' class ' : ' form-control ' } )
2016-10-30 20:53:18 +01:00
# if-elif branches start with special cases
2014-06-05 01:45:07 +02:00
if field . data_type == ' varchar ' :
fieldclass = forms . CharField
instanceargs [ ' max_length ' ] = field . max_length
elif field . data_type == ' text ' :
fieldclass = forms . CharField
2020-06-03 10:21:43 +02:00
instanceargs [ ' widget ' ] = forms . Textarea ( attrs = { ' class ' : ' form-control ' } )
2014-06-05 01:45:07 +02:00
instanceargs [ ' max_length ' ] = field . max_length
elif field . data_type == ' integer ' :
fieldclass = forms . IntegerField
2020-06-03 10:21:43 +02:00
instanceargs [ ' widget ' ] = forms . NumberInput ( attrs = { ' class ' : ' form-control ' } )
2014-06-05 01:45:07 +02:00
elif field . data_type == ' decimal ' :
fieldclass = forms . DecimalField
instanceargs [ ' decimal_places ' ] = field . decimal_places
instanceargs [ ' max_digits ' ] = field . max_length
2020-06-03 10:21:43 +02:00
instanceargs [ ' widget ' ] = forms . NumberInput ( attrs = { ' class ' : ' form-control ' } )
2014-06-05 01:45:07 +02:00
elif field . data_type == ' list ' :
fieldclass = forms . ChoiceField
choices = field . choices_as_array
if field . empty_selection_list :
2016-10-21 17:14:12 +02:00
choices . insert ( 0 , ( ' ' , ' --------- ' ) )
2014-06-05 01:45:07 +02:00
instanceargs [ ' choices ' ] = choices
2020-06-03 10:21:43 +02:00
instanceargs [ ' widget ' ] = forms . Select ( attrs = { ' class ' : ' form-control ' } )
2016-10-30 08:38:49 +01:00
else :
2016-10-30 20:53:18 +01:00
# Try to use the immediate equivalences dictionary
try :
fieldclass = CUSTOMFIELD_TO_FIELD_DICT [ field . data_type ]
2021-02-11 01:58:01 +01:00
# Change widgets for the following classes
if fieldclass == forms . DateField :
instanceargs [ ' widget ' ] = forms . DateInput ( attrs = { ' class ' : ' form-control date-field ' } )
elif fieldclass == forms . DateTimeField :
instanceargs [ ' widget ' ] = forms . DateTimeInput ( attrs = { ' class ' : ' form-control datetime-field ' } )
elif fieldclass == forms . TimeField :
instanceargs [ ' widget ' ] = forms . TimeInput ( attrs = { ' class ' : ' form-control time-field ' } )
elif fieldclass == forms . BooleanField :
2020-06-03 10:21:43 +02:00
instanceargs [ ' widget ' ] = forms . CheckboxInput ( attrs = { ' class ' : ' form-control ' } )
2016-10-30 20:53:18 +01:00
except KeyError :
# The data_type was not found anywhere
raise NameError ( " Unrecognized data_type %s " % field . data_type )
2014-06-05 01:45:07 +02:00
self . fields [ ' custom_ %s ' % field . name ] = fieldclass ( * * instanceargs )
2016-10-21 17:14:12 +02:00
2014-06-05 01:45:07 +02:00
class EditTicketForm ( CustomFieldMixin , forms . ModelForm ) :
2016-10-23 22:09:17 +02:00
2009-06-03 13:43:46 +02:00
class Meta :
model = Ticket
exclude = ( ' created ' , ' modified ' , ' status ' , ' on_hold ' , ' resolution ' , ' last_escalation ' , ' assigned_to ' )
2016-09-12 08:11:55 +02:00
2021-02-11 01:58:01 +01:00
class Media :
js = ( ' helpdesk/js/init_due_date.js ' , ' helpdesk/js/init_datetime_classes.js ' )
2011-05-09 23:54:44 +02:00
def __init__ ( self , * args , * * kwargs ) :
"""
Add any custom fields that are defined to the form
"""
super ( EditTicketForm , self ) . __init__ ( * args , * * kwargs )
2021-02-09 21:08:27 +01:00
# Disable and add help_text to the merged_to field on this form
self . fields [ ' merged_to ' ] . disabled = True
self . fields [ ' merged_to ' ] . help_text = _ ( ' This ticket is merged into the selected ticket. ' )
2011-05-09 23:54:44 +02:00
for field in CustomField . objects . all ( ) :
2021-02-11 01:58:01 +01:00
initial_value = None
2011-05-09 23:54:44 +02:00
try :
current_value = TicketCustomFieldValue . objects . get ( ticket = self . instance , field = field )
initial_value = current_value . value
2021-02-11 01:58:01 +01:00
# Attempt to convert from fixed format string to date/time data type
if ' datetime ' == current_value . field . data_type :
initial_value = datetime . strptime ( initial_value , CUSTOMFIELD_DATETIME_FORMAT )
elif ' date ' == current_value . field . data_type :
initial_value = datetime . strptime ( initial_value , CUSTOMFIELD_DATE_FORMAT )
elif ' time ' == current_value . field . data_type :
initial_value = datetime . strptime ( initial_value , CUSTOMFIELD_TIME_FORMAT )
2021-01-16 23:28:30 +01:00
# If it is boolean field, transform the value to a real boolean instead of a string
2021-02-11 01:58:01 +01:00
elif ' boolean ' == current_value . field . data_type :
initial_value = ' True ' == initial_value
except ( TicketCustomFieldValue . DoesNotExist , ValueError , TypeError ) :
# ValueError error if parsing fails, using initial_value = current_value.value
# TypeError if parsing None type
pass
2011-05-09 23:54:44 +02:00
instanceargs = {
2016-10-23 22:09:17 +02:00
' label ' : field . label ,
' help_text ' : field . help_text ,
' required ' : field . required ,
' initial ' : initial_value ,
}
2014-06-05 01:45:07 +02:00
self . customfield_to_field ( field , instanceargs )
2011-05-09 23:54:44 +02:00
def save ( self , * args , * * kwargs ) :
2016-09-12 08:11:55 +02:00
2011-05-09 23:54:44 +02:00
for field , value in self . cleaned_data . items ( ) :
if field . startswith ( ' custom_ ' ) :
2014-10-25 21:53:56 +02:00
field_name = field . replace ( ' custom_ ' , ' ' , 1 )
2011-05-09 23:54:44 +02:00
customfield = CustomField . objects . get ( name = field_name )
try :
cfv = TicketCustomFieldValue . objects . get ( ticket = self . instance , field = customfield )
2016-10-21 17:14:12 +02:00
except ObjectDoesNotExist :
2011-05-09 23:54:44 +02:00
cfv = TicketCustomFieldValue ( ticket = self . instance , field = customfield )
2021-02-11 01:58:01 +01:00
# Convert date/time data type to known fixed format string.
if datetime is type ( value ) :
cfv . value = value . strftime ( CUSTOMFIELD_DATETIME_FORMAT )
elif date is type ( value ) :
cfv . value = value . strftime ( CUSTOMFIELD_DATE_FORMAT )
elif time is type ( value ) :
cfv . value = value . strftime ( CUSTOMFIELD_TIME_FORMAT )
else :
cfv . value = value
2011-05-09 23:54:44 +02:00
cfv . save ( )
2016-09-12 08:11:55 +02:00
2011-05-09 23:54:44 +02:00
return super ( EditTicketForm , self ) . save ( * args , * * kwargs )
2009-06-03 13:43:46 +02:00
2011-01-29 07:02:03 +01:00
class EditFollowUpForm ( forms . ModelForm ) :
2016-10-23 22:09:17 +02:00
2011-01-29 07:02:03 +01:00
class Meta :
model = FollowUp
exclude = ( ' date ' , ' user ' , )
2016-10-21 17:14:12 +02:00
def __init__ ( self , * args , * * kwargs ) :
""" Filter not openned tickets here. """
super ( EditFollowUpForm , self ) . __init__ ( * args , * * kwargs )
self . fields [ " ticket " ] . queryset = Ticket . objects . filter ( status__in = ( Ticket . OPEN_STATUS , Ticket . REOPENED_STATUS ) )
2016-10-30 08:39:06 +01:00
class AbstractTicketForm ( CustomFieldMixin , forms . Form ) :
"""
Contain all the common code and fields between " TicketForm " and
" PublicTicketForm " . This Form is not intended to be used directly .
"""
2008-08-19 10:50:38 +02:00
queue = forms . ChoiceField (
2016-10-29 10:08:57 +02:00
widget = forms . Select ( attrs = { ' class ' : ' form-control ' } ) ,
2008-08-19 10:50:38 +02:00
label = _ ( ' Queue ' ) ,
required = True ,
choices = ( )
2016-10-23 22:09:17 +02:00
)
2008-08-19 10:50:38 +02:00
title = forms . CharField (
max_length = 100 ,
required = True ,
2016-10-29 10:08:57 +02:00
widget = forms . TextInput ( attrs = { ' class ' : ' form-control ' } ) ,
2008-08-19 10:50:38 +02:00
label = _ ( ' Summary of the problem ' ) ,
2016-10-23 22:09:17 +02:00
)
2008-08-19 10:50:38 +02:00
body = forms . CharField (
2016-10-31 06:38:49 +01:00
widget = forms . Textarea ( attrs = { ' class ' : ' form-control ' } ) ,
2016-10-30 08:39:06 +01:00
label = _ ( ' Description of your issue ' ) ,
2008-08-19 10:50:38 +02:00
required = True ,
2016-10-30 08:39:06 +01:00
help_text = _ ( ' Please be as descriptive as possible and include all details ' ) ,
2016-10-23 22:09:17 +02:00
)
2008-08-19 10:50:38 +02:00
priority = forms . ChoiceField (
2016-10-29 10:08:57 +02:00
widget = forms . Select ( attrs = { ' class ' : ' form-control ' } ) ,
2008-08-19 10:50:38 +02:00
choices = Ticket . PRIORITY_CHOICES ,
2016-10-30 08:39:06 +01:00
required = True ,
2020-02-06 10:10:07 +01:00
initial = getattr ( settings , ' HELPDESK_PUBLIC_TICKET_PRIORITY ' , ' 3 ' ) ,
2008-08-19 10:50:38 +02:00
label = _ ( ' Priority ' ) ,
2016-10-30 08:39:06 +01:00
help_text = _ ( " Please select a priority carefully. If unsure, leave it as ' 3 ' . " ) ,
2016-10-23 22:09:17 +02:00
)
2008-08-19 10:50:38 +02:00
2012-01-20 21:48:38 +01:00
due_date = forms . DateTimeField (
2020-10-23 16:23:47 +02:00
widget = forms . TextInput ( attrs = { ' class ' : ' form-control ' , ' autocomplete ' : ' off ' } ) ,
2012-01-20 21:48:38 +01:00
required = False ,
2021-02-11 01:58:01 +01:00
input_formats = [ CUSTOMFIELD_DATE_FORMAT , CUSTOMFIELD_DATETIME_FORMAT , ' %d / % m/ % Y ' , ' % m/ %d / % Y ' , " %d . % m. % Y " ] ,
2012-01-20 21:48:38 +01:00
label = _ ( ' Due on ' ) ,
2016-10-23 22:09:17 +02:00
)
2012-01-20 21:48:38 +01:00
2009-01-22 09:08:22 +01:00
attachment = forms . FileField (
2018-09-02 10:36:16 +02:00
widget = forms . FileInput ( attrs = { ' class ' : ' form-control-file ' } ) ,
2009-01-22 09:08:22 +01:00
required = False ,
label = _ ( ' Attach File ' ) ,
2021-10-05 12:25:42 +02:00
help_text = _ ( ' You can attach a file to this ticket. Only file types such as plain text (.txt), a document (.pdf, .docx, or .odt), or screenshot (.png or .jpg) may be uploaded. ' ) ,
2016-10-23 22:09:17 +02:00
)
2009-01-22 09:08:22 +01:00
2020-10-23 16:23:47 +02:00
class Media :
2021-02-11 01:58:01 +01:00
js = ( ' helpdesk/js/init_due_date.js ' , ' helpdesk/js/init_datetime_classes.js ' )
2020-10-23 16:23:47 +02:00
2020-01-08 18:39:41 +01:00
def __init__ ( self , kbcategory = None , * args , * * kwargs ) :
super ( ) . __init__ ( * args , * * kwargs )
if kbcategory :
2020-01-08 20:38:08 +01:00
self . fields [ ' kbitem ' ] = forms . ChoiceField (
2020-01-08 18:39:41 +01:00
widget = forms . Select ( attrs = { ' class ' : ' form-control ' } ) ,
required = False ,
2020-02-25 14:25:52 +01:00
label = _ ( ' Knowledge Base Item ' ) ,
2020-02-27 11:54:04 +01:00
choices = [ ( kbi . pk , kbi . title ) for kbi in KBItem . objects . filter ( category = kbcategory . pk , enabled = True ) ] ,
2020-01-08 18:39:41 +01:00
)
2016-10-30 08:39:06 +01:00
def _add_form_custom_fields ( self , staff_only_filter = None ) :
if staff_only_filter is None :
queryset = CustomField . objects . all ( )
else :
queryset = CustomField . objects . filter ( staff_only = staff_only_filter )
for field in queryset :
2020-01-08 20:38:08 +01:00
instanceargs = {
' label ' : field . label ,
' help_text ' : field . help_text ,
' required ' : field . required ,
}
2014-06-05 01:45:07 +02:00
self . customfield_to_field ( field , instanceargs )
2011-02-02 12:22:46 +01:00
2020-01-07 13:47:36 +01:00
def _get_queue ( self ) :
2020-02-06 10:10:07 +01:00
# this procedure is re-defined for public submission form
2020-01-07 13:47:36 +01:00
return Queue . objects . get ( id = int ( self . cleaned_data [ ' queue ' ] ) )
2016-10-30 08:39:06 +01:00
def _create_ticket ( self ) :
2020-02-06 10:10:07 +01:00
queue = self . _get_queue ( )
2020-01-07 13:33:06 +01:00
kbitem = None
if ' kbitem ' in self . cleaned_data :
kbitem = KBItem . objects . get ( id = int ( self . cleaned_data [ ' kbitem ' ] ) )
2008-08-19 10:50:38 +02:00
2020-02-06 10:10:07 +01:00
ticket = Ticket (
title = self . cleaned_data [ ' title ' ] ,
submitter_email = self . cleaned_data [ ' submitter_email ' ] ,
created = timezone . now ( ) ,
status = Ticket . OPEN_STATUS ,
queue = queue ,
description = self . cleaned_data [ ' body ' ] ,
priority = self . cleaned_data . get (
' priority ' ,
getattr ( settings , " HELPDESK_PUBLIC_TICKET_PRIORITY " , " 3 " )
) ,
due_date = self . cleaned_data . get (
' due_date ' ,
getattr ( settings , " HELPDESK_PUBLIC_TICKET_DUE_DATE " , None )
) or None ,
kbitem = kbitem ,
)
2008-08-19 10:50:38 +02:00
2016-10-30 20:43:05 +01:00
return ticket , queue
2016-09-12 08:11:55 +02:00
2016-10-30 08:39:06 +01:00
def _create_custom_fields ( self , ticket ) :
2011-02-02 12:22:46 +01:00
for field , value in self . cleaned_data . items ( ) :
if field . startswith ( ' custom_ ' ) :
2014-10-25 21:53:56 +02:00
field_name = field . replace ( ' custom_ ' , ' ' , 1 )
2016-10-30 08:39:06 +01:00
custom_field = CustomField . objects . get ( name = field_name )
cfv = TicketCustomFieldValue ( ticket = ticket ,
field = custom_field ,
2016-10-21 17:14:12 +02:00
value = value )
2011-02-02 12:22:46 +01:00
cfv . save ( )
2007-12-27 01:29:17 +01:00
2016-10-30 08:39:06 +01:00
def _create_follow_up ( self , ticket , title , user = None ) :
2016-10-30 20:43:05 +01:00
followup = FollowUp ( ticket = ticket ,
title = title ,
date = timezone . now ( ) ,
public = True ,
comment = self . cleaned_data [ ' body ' ] ,
)
2016-10-30 08:39:06 +01:00
if user :
2016-10-30 20:43:05 +01:00
followup . user = user
return followup
2007-12-28 04:29:45 +01:00
2016-10-30 08:39:06 +01:00
def _attach_files_to_follow_up ( self , followup ) :
2016-11-10 17:23:16 +01:00
files = self . cleaned_data [ ' attachment ' ]
if files :
files = process_attachments ( followup , [ files ] )
return files
2008-08-19 10:50:38 +02:00
2016-10-30 08:39:06 +01:00
@staticmethod
def _send_messages ( ticket , queue , followup , files , user = None ) :
context = safe_template_context ( ticket )
context [ ' comment ' ] = followup . comment
2016-09-12 08:11:55 +02:00
2018-10-31 16:24:57 +01:00
roles = { ' submitter ' : ( ' newticket_submitter ' , context ) ,
' new_ticket_cc ' : ( ' newticket_cc ' , context ) ,
' ticket_cc ' : ( ' newticket_cc ' , context ) }
if ticket . assigned_to and ticket . assigned_to . usersettings_helpdesk . email_on_ticket_assign :
roles [ ' assigned_to ' ] = ( ' assigned_owner ' , context )
ticket . send (
roles ,
fail_silently = True ,
files = files ,
)
2008-01-21 02:02:12 +01:00
2008-08-19 10:50:38 +02:00
2016-10-30 08:39:06 +01:00
class TicketForm ( AbstractTicketForm ) :
"""
Ticket Form creation for registered users .
"""
2008-08-19 10:50:38 +02:00
submitter_email = forms . EmailField (
2012-01-20 21:48:38 +01:00
required = False ,
2016-10-30 08:39:06 +01:00
label = _ ( ' Submitter E-Mail Address ' ) ,
2018-09-02 10:36:16 +02:00
widget = forms . TextInput ( attrs = { ' class ' : ' form-control ' , ' type ' : ' email ' } ) ,
2016-10-30 08:39:06 +01:00
help_text = _ ( ' This e-mail address will receive copies of all public '
' updates to this ticket. ' ) ,
2016-10-23 22:09:17 +02:00
)
2016-10-30 08:39:06 +01:00
assigned_to = forms . ChoiceField (
2020-02-06 10:10:07 +01:00
widget = (
forms . Select ( attrs = { ' class ' : ' form-control ' } )
if not helpdesk_settings . HELPDESK_CREATE_TICKET_HIDE_ASSIGNED_TO
else forms . HiddenInput ( )
) ,
2009-01-22 09:08:22 +01:00
required = False ,
2016-10-30 08:39:06 +01:00
label = _ ( ' Case owner ' ) ,
help_text = _ ( ' If you select an owner other than yourself, they \' ll be '
' e-mailed details of this ticket immediately. ' ) ,
2018-09-07 19:05:16 +02:00
choices = ( )
2016-10-23 22:09:17 +02:00
)
2009-01-22 09:08:22 +01:00
2011-02-02 12:22:46 +01:00
def __init__ ( self , * args , * * kwargs ) :
"""
2016-10-30 08:39:06 +01:00
Add any custom fields that are defined to the form .
2011-02-02 12:22:46 +01:00
"""
2019-02-05 14:38:41 +01:00
queue_choices = kwargs . pop ( " queue_choices " )
2018-09-07 19:05:16 +02:00
super ( ) . __init__ ( * args , * * kwargs )
2019-02-05 14:38:41 +01:00
self . fields [ ' queue ' ] . choices = queue_choices
2018-09-07 19:05:16 +02:00
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 ]
2016-10-30 08:39:06 +01:00
self . _add_form_custom_fields ( )
2011-02-02 12:22:46 +01:00
2020-03-03 22:39:02 +01:00
def save ( self , user ) :
2008-01-16 01:26:24 +01:00
"""
Writes and returns a Ticket ( ) object
"""
2008-08-19 10:50:38 +02:00
2016-10-30 20:43:05 +01:00
ticket , queue = self . _create_ticket ( )
2016-10-30 08:39:06 +01:00
if self . cleaned_data [ ' assigned_to ' ] :
try :
u = User . objects . get ( id = self . cleaned_data [ ' assigned_to ' ] )
2016-10-30 20:43:05 +01:00
ticket . assigned_to = u
2016-10-30 08:39:06 +01:00
except User . DoesNotExist :
2016-10-30 20:43:05 +01:00
ticket . assigned_to = None
ticket . save ( )
2016-09-12 08:11:55 +02:00
2016-10-30 20:43:05 +01:00
self . _create_custom_fields ( ticket )
2009-01-22 09:08:22 +01:00
2016-10-30 08:39:06 +01:00
if self . cleaned_data [ ' assigned_to ' ] :
title = _ ( ' Ticket Opened & Assigned to %(name)s ' ) % {
2016-10-30 20:43:05 +01:00
' name ' : ticket . get_assigned_to or _ ( " <invalid user> " )
2016-10-30 08:39:06 +01:00
}
else :
title = _ ( ' Ticket Opened ' )
2016-10-30 20:43:05 +01:00
followup = self . _create_follow_up ( ticket , title = title , user = user )
followup . save ( )
2008-01-16 01:26:24 +01:00
2016-10-30 20:43:05 +01:00
files = self . _attach_files_to_follow_up ( followup )
self . _send_messages ( ticket = ticket ,
queue = queue ,
followup = followup ,
files = files ,
user = user )
return ticket
2009-08-11 11:02:48 +02:00
2016-02-17 09:40:08 +01:00
2016-10-30 08:39:06 +01:00
class PublicTicketForm ( AbstractTicketForm ) :
"""
Ticket Form creation for all users ( public - facing ) .
"""
submitter_email = forms . EmailField (
2018-09-02 10:36:16 +02:00
widget = forms . TextInput ( attrs = { ' class ' : ' form-control ' , ' type ' : ' email ' } ) ,
2016-10-30 08:39:06 +01:00
required = True ,
label = _ ( ' Your E-Mail Address ' ) ,
help_text = _ ( ' We will e-mail you when your ticket is updated. ' ) ,
)
2008-08-19 10:50:38 +02:00
2020-01-08 18:39:41 +01:00
def __init__ ( self , hidden_fields = ( ) , readonly_fields = ( ) , * args , * * kwargs ) :
2016-10-30 08:39:06 +01:00
"""
Add any ( non - staff ) custom fields that are defined to the form
"""
super ( PublicTicketForm , self ) . __init__ ( * args , * * kwargs )
2019-12-12 16:41:55 +01:00
self . _add_form_custom_fields ( False )
2021-08-19 22:00:18 +02:00
for field in self . fields . keys ( ) :
if field in hidden_fields :
self . fields [ field ] . widget = forms . HiddenInput ( )
if field in readonly_fields :
self . fields [ field ] . disabled = True
field_deletion_table = {
2019-12-06 15:44:20 +01:00
' queue ' : ' HELPDESK_PUBLIC_TICKET_QUEUE ' ,
' priority ' : ' HELPDESK_PUBLIC_TICKET_PRIORITY ' ,
' due_date ' : ' HELPDESK_PUBLIC_TICKET_DUE_DATE ' ,
}
2019-12-12 17:22:57 +01:00
2021-08-19 22:00:18 +02:00
for field_name , field_setting_key in field_deletion_table . items ( ) :
2020-02-06 10:10:07 +01:00
has_settings_default_value = getattr ( settings , field_setting_key , None )
if has_settings_default_value is not None :
2021-08-19 22:00:18 +02:00
del self . fields [ field_name ]
2019-12-06 15:44:20 +01:00
2020-02-06 10:10:07 +01:00
public_queues = Queue . objects . filter ( allow_public_submission = True )
if len ( public_queues ) == 0 :
logger . warning (
" There are no public queues defined - public ticket creation is impossible "
)
if ' queue ' in self . fields :
self . fields [ ' queue ' ] . choices = [ ( ' ' , ' -------- ' ) ] + [
( q . id , q . title ) for q in public_queues ]
def _get_queue ( self ) :
if getattr ( settings , ' HELPDESK_PUBLIC_TICKET_QUEUE ' , None ) is not None :
# force queue to be the pre-defined one
# (only for public submissions)
public_queue = Queue . objects . filter (
slug = settings . HELPDESK_PUBLIC_TICKET_QUEUE
) . first ( )
if not public_queue :
logger . fatal (
" Public queue ' %s ' is configured as default but can ' t be found " ,
settings . HELPDESK_PUBLIC_TICKET_QUEUE
)
return public_queue
else :
# get the queue user entered
return Queue . objects . get ( id = int ( self . cleaned_data [ ' queue ' ] ) )
2008-01-21 02:02:12 +01:00
2020-03-03 22:39:02 +01:00
def save ( self , user ) :
2016-10-30 08:39:06 +01:00
"""
Writes and returns a Ticket ( ) object
"""
2016-10-30 20:43:05 +01:00
ticket , queue = self . _create_ticket ( )
if queue . default_owner and not ticket . assigned_to :
ticket . assigned_to = queue . default_owner
ticket . save ( )
self . _create_custom_fields ( ticket )
2020-03-03 22:39:02 +01:00
followup = self . _create_follow_up (
ticket , title = _ ( ' Ticket Opened Via Web ' ) , user = user )
2016-10-30 20:43:05 +01:00
followup . save ( )
files = self . _attach_files_to_follow_up ( followup )
self . _send_messages ( ticket = ticket ,
queue = queue ,
followup = followup ,
files = files )
return ticket
2008-08-19 10:50:38 +02:00
2008-09-09 10:32:01 +02:00
2018-10-05 14:54:22 +02:00
class UserSettingsForm ( forms . ModelForm ) :
2009-07-22 10:19:46 +02:00
2018-10-05 14:54:22 +02:00
class Meta :
model = UserSettings
exclude = [ ' user ' , ' settings_pickled ' ]
2009-08-06 10:56:02 +02:00
2008-10-25 00:52:34 +02:00
class EmailIgnoreForm ( forms . ModelForm ) :
2016-10-23 22:09:17 +02:00
2008-10-25 00:52:34 +02:00
class Meta :
model = IgnoreEmail
2014-09-11 09:37:51 +02:00
exclude = [ ]
2009-09-09 10:47:48 +02:00
2016-10-21 17:14:12 +02:00
2009-09-09 10:47:48 +02:00
class TicketCCForm ( forms . ModelForm ) :
2016-09-12 08:11:55 +02:00
''' Adds either an email address or helpdesk user as a CC on a Ticket. Used for processing POST requests. '''
2016-10-23 22:09:17 +02:00
2016-10-21 17:14:12 +02:00
class Meta :
model = TicketCC
exclude = ( ' ticket ' , )
2011-02-06 18:49:07 +01:00
def __init__ ( self , * args , * * kwargs ) :
super ( TicketCCForm , self ) . __init__ ( * args , * * kwargs )
2012-01-17 22:40:44 +01:00
if helpdesk_settings . HELPDESK_STAFF_ONLY_TICKET_CC :
2014-10-22 07:18:04 +02:00
users = User . objects . filter ( is_active = True , is_staff = True ) . order_by ( User . USERNAME_FIELD )
2012-01-17 22:40:44 +01:00
else :
2014-10-22 07:18:04 +02:00
users = User . objects . filter ( is_active = True ) . order_by ( User . USERNAME_FIELD )
2016-09-12 08:11:55 +02:00
self . fields [ ' user ' ] . queryset = users
2011-02-06 18:49:07 +01:00
2016-10-29 10:27:29 +02:00
2016-09-12 08:11:55 +02:00
class TicketCCUserForm ( forms . ModelForm ) :
''' Adds a helpdesk user as a CC on a Ticket '''
2016-10-29 10:08:57 +02:00
2016-09-12 08:11:55 +02:00
def __init__ ( self , * args , * * kwargs ) :
super ( TicketCCUserForm , self ) . __init__ ( * args , * * kwargs )
if helpdesk_settings . HELPDESK_STAFF_ONLY_TICKET_CC :
users = User . objects . filter ( is_active = True , is_staff = True ) . order_by ( User . USERNAME_FIELD )
else :
users = User . objects . filter ( is_active = True ) . order_by ( User . USERNAME_FIELD )
self . fields [ ' user ' ] . queryset = users
2016-10-29 10:20:16 +02:00
2016-09-12 08:11:55 +02:00
class Meta :
model = TicketCC
2016-10-29 10:08:57 +02:00
exclude = ( ' ticket ' , ' email ' , )
2016-09-12 08:11:55 +02:00
2016-10-29 10:27:29 +02:00
2016-09-12 08:11:55 +02:00
class TicketCCEmailForm ( forms . ModelForm ) :
''' Adds an email address as a CC on a Ticket '''
2016-10-29 10:08:57 +02:00
2016-09-12 08:11:55 +02:00
def __init__ ( self , * args , * * kwargs ) :
super ( TicketCCEmailForm , self ) . __init__ ( * args , * * kwargs )
2016-10-29 10:20:16 +02:00
2016-09-12 08:11:55 +02:00
class Meta :
model = TicketCC
2016-10-29 10:08:57 +02:00
exclude = ( ' ticket ' , ' user ' , )
2016-09-12 08:11:55 +02:00
2016-10-29 10:27:29 +02:00
2011-05-10 11:27:11 +02:00
class TicketDependencyForm ( forms . ModelForm ) :
2016-10-29 10:08:57 +02:00
''' Adds a different ticket as a dependency for this Ticket '''
2016-10-23 22:09:17 +02:00
2011-05-10 11:27:11 +02:00
class Meta :
model = TicketDependency
exclude = ( ' ticket ' , )
2020-10-29 23:32:02 +01:00
class MultipleTicketSelectForm ( forms . Form ) :
tickets = forms . ModelMultipleChoiceField (
label = _ ( ' Tickets to merge ' ) ,
2020-10-30 20:19:50 +01:00
queryset = Ticket . objects . filter ( merged_to = None ) ,
2020-10-29 23:32:02 +01:00
widget = forms . SelectMultiple ( attrs = { ' class ' : ' form-control ' } )
)
def clean_tickets ( self ) :
tickets = self . cleaned_data . get ( ' tickets ' )
if len ( tickets ) < 2 :
2020-10-30 20:19:50 +01:00
raise ValidationError ( _ ( ' Please choose at least 2 tickets. ' ) )
2020-10-29 23:32:02 +01:00
if len ( tickets ) > 4 :
raise ValidationError ( _ ( ' Impossible to merge more than 4 tickets... ' ) )
2020-10-30 20:19:50 +01:00
queues = tickets . order_by ( ' queue ' ) . distinct ( ) . values_list ( ' queue ' , flat = True )
if len ( queues ) != 1 :
raise ValidationError ( _ ( ' All selected tickets must share the same queue in order to be merged. ' ) )
2020-10-29 23:32:02 +01:00
return tickets