Merge pull request #1189 from jorge-leon/attachment-enable-setting

Attachment enable setting
This commit is contained in:
Christopher Broderick 2024-06-15 14:32:51 +01:00 committed by GitHub
commit f883868361
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 204 additions and 115 deletions

View File

@ -39,8 +39,8 @@ If you want to override the default settings for your users, create ``HELPDESK_D
} }
Access controll & Security Access control & Security
--------------- -------------------------
These settings can be used to change who can access the helpdesk. These settings can be used to change who can access the helpdesk.
- **HELPDESK_PUBLIC_VIEW_PROTECTOR** This is a function that takes a request and can either return `None` granting access to to a public view or a redirect denying access. - **HELPDESK_PUBLIC_VIEW_PROTECTOR** This is a function that takes a request and can either return `None` granting access to to a public view or a redirect denying access.
@ -51,16 +51,30 @@ These settings can be used to change who can access the helpdesk.
**Default:** ``HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT = False`` **Default:** ``HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT = False``
- **HELPDESK_VALID_EXTENSIONS** Valid extensions for file types that can be attached to tickets. Note: This used to be calle **VALID_EXTENSIONS** which is now deprecated.
**Default:** ``HELPDESK_VALID_EXTENSIONS = ['.txt', '.asc', '.htm', '.html', '.pdf', '.doc', '.docx', '.odt', '.jpg', '.png', '.eml']
- **HELPDESK_VALIDATE_ATTACHMENT_TYPES** If you'd like to turn of filtering of helpdesk extension types you can set this to False.
- **HELPDESK_ANON_ACCESS_RAISES_404** If True, redirects user to a 404 page when attempting to reach ticket pages while not logged in, rather than redirecting to a login screen. - **HELPDESK_ANON_ACCESS_RAISES_404** If True, redirects user to a 404 page when attempting to reach ticket pages while not logged in, rather than redirecting to a login screen.
**Default:** ``HELPDESK_ANON_ACCESS_RAISES_404 = False`` **Default:** ``HELPDESK_ANON_ACCESS_RAISES_404 = False``
Settings related to attachments:
- **HELPDESK_ENABLE_ATTACHMENTS** If set to ``True``, files can be
attached to tickets and followups, and emails are searched for
attachments which are then attached to the ticket. Also enables the
``HELPDESK_ALWAYS_SAVE_INCOMING_EMAIL_MESSAGE`` setting.
**Caution**: Set this to False, unless you have secured access to
the uploaded files. Otherwise anyone on the Internet will be able
to download your ticket attachments.
Attachments are enabled by default for backwards compatibility.
- **HELPDESK_VALID_EXTENSIONS** Valid extensions for file types that can be attached to tickets. Note: This used to be called **VALID_EXTENSIONS** which is now deprecated.
**Default:** ``HELPDESK_VALID_EXTENSIONS = ['.txt', '.asc', '.htm', '.html', '.pdf', '.doc', '.docx', '.odt', '.jpg', '.png', '.eml']``
- **HELPDESK_VALIDATE_ATTACHMENT_TYPES** If you'd like to turn of filtering of helpdesk extension types you can set this to False.
Generic Options Generic Options
--------------- ---------------
These changes are visible throughout django-helpdesk These changes are visible throughout django-helpdesk
@ -422,4 +436,9 @@ The following settings were defined in previous versions and are no longer suppo
- **HELPDESK_FULL_FIRST_MESSAGE_FROM_EMAIL** Do not ignore fowarded and replied text from the email messages which create a new ticket; useful for cases when customer forwards some email (error from service or something) and wants support to see that - **HELPDESK_FULL_FIRST_MESSAGE_FROM_EMAIL** Do not ignore fowarded and replied text from the email messages which create a new ticket; useful for cases when customer forwards some email (error from service or something) and wants support to see that
- **HELPDESK_ALWAYS_SAVE_INCOMING_EMAIL_MESSAGE** Any incoming .eml message is saved and available, helps when customer spent some time doing fancy markup which has been corrupted during the email-to-ticket-comment translate process - **HELPDESK_ALWAYS_SAVE_INCOMING_EMAIL_MESSAGE** Any incoming .eml
message is saved and available, helps when customer spent some time
doing fancy markup which has been corrupted during the
email-to-ticket-comment translate process.
Requires ``HELPDESK_ENABLE_ATTACHMENTS`` to be set to `True`

View File

@ -595,16 +595,17 @@ def create_object_from_email_message(message, ticket_id, payload, files, logger)
logger.info("[%s-%s] %s" % (ticket.queue.slug, ticket.id, ticket.title,)) logger.info("[%s-%s] %s" % (ticket.queue.slug, ticket.id, ticket.title,))
try: if settings.HELPDESK_ENABLE_ATTACHMENTS:
attached = process_attachments(f, files) try:
except ValidationError as e: attached = process_attachments(f, files)
logger.error(str(e)) except ValidationError as e:
else: logger.error(str(e))
for att_file in attached: else:
logger.info( for att_file in attached:
"Attachment '%s' (with size %s) successfully added to ticket from email.", logger.info(
att_file[0], att_file[1].size "Attachment '%s' (with size %s) successfully added to ticket from email.",
) att_file[0], att_file[1].size
)
context = safe_template_context(ticket) context = safe_template_context(ticket)
@ -984,7 +985,7 @@ def extract_email_metadata(message: str,
filtered_body, full_body = extract_email_message_content(message_obj, files, include_chained_msgs) filtered_body, full_body = extract_email_message_content(message_obj, files, include_chained_msgs)
# If the base part is not a multipart then it will have already been processed as the vbody content so # If the base part is not a multipart then it will have already been processed as the vbody content so
# no need to process attachments # no need to process attachments
if "multipart" == message_obj.get_content_maintype(): if "multipart" == message_obj.get_content_maintype() and settings.HELPDESK_ENABLE_ATTACHMENTS:
# Find and attach all other parts or part contents as attachments # Find and attach all other parts or part contents as attachments
counter, content_parts_excluded = extract_attachments(message_obj, files, logger) counter, content_parts_excluded = extract_attachments(message_obj, files, logger)
if not content_parts_excluded: if not content_parts_excluded:
@ -994,7 +995,8 @@ def extract_email_metadata(message: str,
Verify that there were no text/* parts containing message content.") Verify that there were no text/* parts containing message content.")
if logger.isEnabledFor(logging.DEBUG): if logger.isEnabledFor(logging.DEBUG):
logger.debug("Email parsed and %s attachments were found and attached.", counter) logger.debug("Email parsed and %s attachments were found and attached.", counter)
add_file_if_always_save_incoming_email_message(files, message) if settings.HELPDESK_ENABLE_ATTACHMENTS:
add_file_if_always_save_incoming_email_message(files, message)
smtp_priority = message_obj.get('priority', '') smtp_priority = message_obj.get('priority', '')
smtp_importance = message_obj.get('importance', '') smtp_importance = message_obj.get('importance', '')

View File

@ -239,17 +239,18 @@ class AbstractTicketForm(CustomFieldMixin, forms.Form):
label=_('Due on'), label=_('Due on'),
) )
attachment = forms.FileField( if helpdesk_settings.HELPDESK_ENABLE_ATTACHMENTS:
widget=forms.FileInput(attrs={'class': 'form-control-file'}), attachment = forms.FileField(
required=False, widget=forms.FileInput(attrs={'class': 'form-control-file'}),
label=_('Attach File'), required=False,
help_text=_('You can attach a file to this ticket. ' label=_('Attach File'),
'Only file types such as plain text (.txt), ' help_text=_('You can attach a file to this ticket. '
'a document (.pdf, .docx, or .odt), ' 'Only file types such as plain text (.txt), '
'or screenshot (.png or .jpg) may be uploaded.'), 'a document (.pdf, .docx, or .odt), '
validators=[validate_file_extension] 'or screenshot (.png or .jpg) may be uploaded.'),
) validators=[validate_file_extension]
)
class Media: class Media:
js = ('helpdesk/js/init_due_date.js', js = ('helpdesk/js/init_due_date.js',
'helpdesk/js/init_datetime_classes.js') 'helpdesk/js/init_datetime_classes.js')
@ -326,7 +327,7 @@ class AbstractTicketForm(CustomFieldMixin, forms.Form):
return followup return followup
def _attach_files_to_follow_up(self, followup): def _attach_files_to_follow_up(self, followup):
files = self.cleaned_data['attachment'] files = self.cleaned_data.get('attachment')
if files: if files:
files = process_attachments(followup, [files]) files = process_attachments(followup, [files])
return files return files
@ -418,7 +419,10 @@ class TicketForm(AbstractTicketForm):
followup = self._create_follow_up(ticket, title=title, user=user) followup = self._create_follow_up(ticket, title=title, user=user)
followup.save() followup.save()
files = self._attach_files_to_follow_up(followup) if helpdesk_settings.HELPDESK_ENABLE_ATTACHMENTS:
files = self._attach_files_to_follow_up(followup)
else:
files = None
# emit signal when the TicketForm.save is done # emit signal when the TicketForm.save is done
new_ticket_done.send(sender="TicketForm", ticket=ticket) new_ticket_done.send(sender="TicketForm", ticket=ticket)

View File

@ -56,6 +56,15 @@ HELPDESK_STAFF_VIEW_PROTECTOR = getattr(settings,
'HELPDESK_STAFF_VIEW_PROTECTOR', 'HELPDESK_STAFF_VIEW_PROTECTOR',
lambda _: None) lambda _: None)
# Enable ticket and Email attachments
#
# Caution! Set this to False, unless you have secured access to
# the uploaded files. Otherwise anyone on the Internet will be
# able to download your ticket attachments.
HELPDESK_ENABLE_ATTACHMENTS = getattr(settings,
'HELPDESK_ENABLE_ATTACHMENTS',
True)
# Enable the Dependencies field on ticket view # Enable the Dependencies field on ticket view
HELPDESK_ENABLE_DEPENDENCIES_ON_TICKET = getattr(settings, HELPDESK_ENABLE_DEPENDENCIES_ON_TICKET = getattr(settings,
'HELPDESK_ENABLE_DEPENDENCIES_ON_TICKET', 'HELPDESK_ENABLE_DEPENDENCIES_ON_TICKET',

View File

@ -9,6 +9,7 @@
{% include 'helpdesk/base-head.html' %} {% include 'helpdesk/base-head.html' %}
{% block helpdesk_head %}{% endblock %} {% block helpdesk_head %}{% endblock %}
{% include 'helpdesk/base_js.html' %}
</head> </head>

View File

@ -75,16 +75,19 @@
{% for followup in ticket.followup_set.public_followups %} {% for followup in ticket.followup_set.public_followups %}
<div class='followup well card'> <div class='followup well card'>
<p><b>{{ followup.title }} <span class='byline text-info'>{% if followup.user %}by {{ followup.user }}{% endif %} <span title='{{ followup.date|date:"DATETIME_FORMAT" }}'>{{ followup.date|naturaltime }}</span></span></b></p> <p><b>{{ followup.title }} <span class='byline text-info'>{% if followup.user %}by {{ followup.user }}{% endif %} <span title='{{ followup.date|date:"DATETIME_FORMAT" }}'>{{ followup.date|naturaltime }}</span></span></b></p>
{{ followup.comment|force_escape|urlizetrunc:50|num_to_link|linebreaksbr }} {{ followup.comment|force_escape|urlizetrunc:50|num_to_link|linebreaksbr }}
{% if followup.ticketchange_set.all %}<div class='changes'><ul> {% if followup.ticketchange_set.all %}<div class='changes'><ul>
{% for change in followup.ticketchange_set.all %} {% for change in followup.ticketchange_set.all %}
<li>{% blocktrans with change.field as field and change.old_value as old_value and change.new_value as new_value %}Changed {{ field }} from {{ old_value }} to {{ new_value }}.{% endblocktrans %}</li> <li>{% blocktrans with change.field as field and change.old_value as old_value and change.new_value as new_value %}Changed {{ field }} from {{ old_value }} to {{ new_value }}.{% endblocktrans %}</li>
{% endfor %} {% endfor %}
</ul></div>{% endif %} </ul></div>{% endif %}
{% for attachment in followup.followupattachment_set.all %}{% if forloop.first %}<div class='attachments'><ul>{% endif %}
<li><a href='{{ attachment.file.url }}'>{{ attachment.filename }}</a> ({{ attachment.mime_type }}, {{ attachment.size|filesizeformat }})</li> {% if helpdesk_settings.HELPDESK_ENABLE_ATTACHMENTS %}
{% if forloop.last %}</ul></div>{% endif %} {% for attachment in followup.followupattachment_set.all %}{% if forloop.first %}<div class='attachments'><ul>{% endif %}
{% endfor %} <li><a href='{{ attachment.file.url }}'>{{ attachment.filename }}</a> ({{ attachment.mime_type }}, {{ attachment.size|filesizeformat }})</li>
{% if forloop.last %}</ul></div>{% endif %}
{% endfor %}
{% endif %}
</div> </div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
@ -122,7 +125,8 @@
<input type='hidden' name='public' value='1'> <input type='hidden' name='public' value='1'>
</dl> </dl>
{% if helpdesk_settings.HELPDESK_ENABLE_ATTACHMENTS %}
<p id='ShowFileUploadPara'><button class="btn btn-warning btn-sm" <p id='ShowFileUploadPara'><button class="btn btn-warning btn-sm"
id='ShowFileUpload' onclick="$('#FileUpload')[0].style.display='block';return false;" >{% trans "Attach File(s) &raquo;" %}</button></p> id='ShowFileUpload' onclick="$('#FileUpload')[0].style.display='block';return false;" >{% trans "Attach File(s) &raquo;" %}</button></p>
@ -132,6 +136,7 @@
<dt><label for='id_file'>{% trans "Attach a File" %}</label></dt> <dt><label for='id_file'>{% trans "Attach a File" %}</label></dt>
<dd> <dd>
<div class="add_file_fields_wrap"> <div class="add_file_fields_wrap">
<button class="add_file_field_button btn btn-success btn-xs">{% trans "Add Another File" %}</button>
<div><label class='btn btn-primary btn-sm btn-file'> <div><label class='btn btn-primary btn-sm btn-file'>
Browse... <input type="file" name='attachment' id='file0' style='display: none;'/> Browse... <input type="file" name='attachment' id='file0' style='display: none;'/>
</label><span>&nbsp;</span><span id='selectedfilename0'>{% trans 'No files selected.' %}</span></div> </label><span>&nbsp;</span><span id='selectedfilename0'>{% trans 'No files selected.' %}</span></div>
@ -140,12 +145,52 @@
</dl> </dl>
</div> </div>
{% endif %}
</fieldset> </fieldset>
<button class="btn btn-primary btn-lg" style="margin-bottom:10px" type='submit'>{% trans "Update This Ticket" %}</button> <button class="btn btn-primary btn-lg" style="margin-bottom:10px" type='submit'>{% trans "Update This Ticket" %}</button>
{% csrf_token %}</form> {% csrf_token %}
</form>
{% if helpdesk_settings.HELPDESK_ENABLE_ATTACHMENTS %}
<script type='text/javascript' language='javascript'>
$(document).ready(function() {
$("#ShowFileUpload").click(function() {
$("#FileUpload").fadeIn();
$("#ShowFileUploadPara").hide();
});
// lists for file input change events, then updates the associated text label
// with the file name selected
$('.add_file_fields_wrap').on('fileselect', ':file', function(event, numFiles, label, browseButtonNum) {
$("#selectedfilename"+browseButtonNum).html(label);
});
var x = 0;
var wrapper = $(".add_file_fields_wrap"); //Fields wrapper
var add_button = $(".add_file_field_button"); //Add button ID
$(add_button).click(function(e){ //on add input button click
x++;
e.preventDefault();
$(wrapper).append("<div><label class='btn btn-primary btn-sm btn-file'>Browse... <input type='file' name='attachment' id='file" + x + "' multiple style='display: none;'/></label><span>&nbsp;</span><span id='selectedfilename" + x + "'>{% trans 'No files selected.' %}</span></div>"); //add input box
});
});
// this function listens for changes on any file input, and
// emits the appropriate event to update the input's text.
// Needed to have properly styled file input buttons! (this really shouldn't be this hard...)
$(document).on('change', ':file', function() {
var input = $(this),
inputWidgetNum = $(this).attr('id').split("file")[1],
numFiles = input.get(0).files ? input.get(0).files.length : 1,
label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
input.trigger('fileselect', [numFiles, label, inputWidgetNum]);
});
</script>
{% endif %}
{% endblock %} {% endblock %}

View File

@ -54,14 +54,16 @@
<li>{% blocktrans with change.field as field and change.old_value as old_value and change.new_value as new_value %}Changed {{ field }} from {{ old_value }} to {{ new_value }}.{% endblocktrans %}</li> <li>{% blocktrans with change.field as field and change.old_value as old_value and change.new_value as new_value %}Changed {{ field }} from {{ old_value }} to {{ new_value }}.{% endblocktrans %}</li>
{% if forloop.last %}</ul></div>{% endif %} {% if forloop.last %}</ul></div>{% endif %}
{% endfor %} {% endfor %}
{% for attachment in followup.followupattachment_set.all %}{% if forloop.first %}{% trans "Attachments" %}:<div class='attachments'><ul>{% endif %} {% if helpdesk_settings.HELPDESK_ENABLE_ATTACHMENTS %}
{% for attachment in followup.followupattachment_set.all %}{% if forloop.first %}{% trans "Attachments" %}:<div class='attachments'><ul>{% endif %}
<li><a href='{{ attachment.file.url }}'>{{ attachment.filename }}</a> ({{ attachment.mime_type }}, {{ attachment.size|filesizeformat }}) <li><a href='{{ attachment.file.url }}'>{{ attachment.filename }}</a> ({{ attachment.mime_type }}, {{ attachment.size|filesizeformat }})
{% if followup.user and request.user == followup.user %} {% if followup.user and request.user == followup.user %}
<a href='{% url 'helpdesk:attachment_del' ticket.id attachment.id %}'><button class="btn btn-danger btn-sm"><i class="fas fa-trash"></i></button></a> <a href='{% url 'helpdesk:attachment_del' ticket.id attachment.id %}'><button class="btn btn-danger btn-sm"><i class="fas fa-trash"></i></button></a>
{% endif %} {% endif %}
</li> </li>
{% if forloop.last %}</ul></div>{% endif %} {% if forloop.last %}</ul></div>{% endif %}
{% endfor %} {% endfor %}
{% endif %}
</p> </p>
<!--- ugly long test to suppress the following if it will be empty, to save vertical space --> <!--- ugly long test to suppress the following if it will be empty, to save vertical space -->
{% with possible=helpdesk_settings.HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP %} {% with possible=helpdesk_settings.HELPDESK_SHOW_EDIT_BUTTON_FOLLOW_UP %}
@ -105,10 +107,10 @@
<dt><label for='commentBox'>{% trans "Comment / Resolution" %}</label></dt> <dt><label for='commentBox'>{% trans "Comment / Resolution" %}</label></dt>
<dd><textarea rows='8' cols='70' name='comment' id='commentBox'></textarea></dd> <dd><textarea rows='8' cols='70' name='comment' id='commentBox'></textarea></dd>
{% url "helpdesk:help_context" as context_help_url %} {% url "helpdesk:help_context" as context_help_url %}
{% blocktrans %} {% blocktrans %}
<dd class='form_help_text'>You can insert ticket and queue details in your message. For more information, see the <a href='{{ context_help_url }}'>context help page</a>.</dd> <dd class='form_help_text'>You can insert ticket and queue details in your message. For more information, see the <a href='{{ context_help_url }}'>context help page</a>.</dd>
{% endblocktrans %} {% endblocktrans %}
<dt><label>{% trans "New Status" %}</label></dt> <dt><label>{% trans "New Status" %}</label></dt>
{% if not ticket.can_be_resolved %}<dd>{% trans "This ticket cannot be resolved or closed until the tickets it depends on are resolved." %}</dd>{% endif %} {% if not ticket.can_be_resolved %}<dd>{% trans "This ticket cannot be resolved or closed until the tickets it depends on are resolved." %}</dd>{% endif %}
@ -197,7 +199,9 @@
</div> </div>
{% endif %} {% endif %}
{% if helpdesk_settings.HELPDESK_ENABLE_ATTACHMENTS %}
<p id='ShowFileUploadPara'><button type="button" class="btn btn-warning btn-sm" id='ShowFileUpload'>{% trans "Attach File(s) &raquo;" %}</button></p> <p id='ShowFileUploadPara'><button type="button" class="btn btn-warning btn-sm" id='ShowFileUpload'>{% trans "Attach File(s) &raquo;" %}</button></p>
{% endif %}
<div id='FileUpload' style='display: none;'> <div id='FileUpload' style='display: none;'>
@ -257,76 +261,79 @@
{% block helpdesk_js %} {% block helpdesk_js %}
<script type='text/javascript' language='javascript'> <script type='text/javascript' language='javascript'>
$( function() { $( function() {
$( "#id_due_date" ).datepicker({dateFormat: 'yy-mm-dd'}); $( "#id_due_date" ).datepicker({dateFormat: 'yy-mm-dd'});
} ); } );
</script> </script>
<script type='text/javascript' language='javascript'> <script type='text/javascript' language='javascript'>
$(document).ready(function() { $(document).ready(function() {
$("#ShowFurtherEditOptions").click(function() { $("#ShowFurtherEditOptions").click(function() {
$("#FurtherEditOptions").toggle(); $("#FurtherEditOptions").toggle();
}); });
$("#ShowChecklistEditOptions").click(function() { $("#ShowChecklistEditOptions").click(function() {
$("#checklistEdit").toggle(); $("#checklistEdit").toggle();
}); });
$("#ShowFileUpload").click(function() { $('#id_preset').change(function() {
$("#FileUpload").fadeIn(); preset = $('#id_preset').val();
$("#ShowFileUploadPara").hide(); if (preset != '') {
}); $.get("{% url 'helpdesk:raw' 'preset' %}?id=" + preset, function(data) {
$("#commentBox").val(data)
});
}
});
$('#id_preset').change(function() { // Preset name of checklist when a template is selected
preset = $('#id_preset').val(); $('#id_checklist_template').on('change', function() {
if (preset != '') { const nameField = $('#id_name')
$.get("{% url 'helpdesk:raw' 'preset' %}?id=" + preset, function(data) { const selectedTemplate = $(this).children(':selected')
$("#commentBox").val(data) if (nameField.val() === '' && selectedTemplate.val()) {
}); nameField.val(selectedTemplate.text())
} }
}); })
// Preset name of checklist when a template is selected $('.disabledTask').on('click', () => {
$('#id_checklist_template').on('change', function() { alert('{% trans 'If you want to update state of checklist tasks, please do a Follow-Up response and click on "Update checklists"' %}')
const nameField = $('#id_name') })
const selectedTemplate = $(this).children(':selected')
if (nameField.val() === '' && selectedTemplate.val()) {
nameField.val(selectedTemplate.text())
}
})
$('.disabledTask').on('click', () => { $("[data-toggle=tooltip]").tooltip();
alert('{% trans 'If you want to update state of checklist tasks, please do a Follow-Up response and click on "Update checklists"' %}')
})
$("[data-toggle=tooltip]").tooltip(); {% if helpdesk_settings.HELPDESK_ENABLE_ATTACHMENTS %}
$("#ShowFileUpload").click(function() {
$("#FileUpload").fadeIn();
$("#ShowFileUploadPara").hide();
});
// lists for file input change events, then updates the associated text label // lists for file input change events, then updates the associated text label
// with the file name selected // with the file name selected
$('.add_file_fields_wrap').on('fileselect', ':file', function(event, numFiles, label, browseButtonNum) { $('.add_file_fields_wrap').on('fileselect', ':file', function(event, numFiles, label, browseButtonNum) {
$("#selectedfilename"+browseButtonNum).html(label); $("#selectedfilename"+browseButtonNum).html(label);
}); });
var x = 0; var x = 0;
var wrapper = $(".add_file_fields_wrap"); //Fields wrapper var wrapper = $(".add_file_fields_wrap"); //Fields wrapper
var add_button = $(".add_file_field_button"); //Add button ID var add_button = $(".add_file_field_button"); //Add button ID
$(add_button).click(function(e){ //on add input button click $(add_button).click(function(e){ //on add input button click
x++; x++;
e.preventDefault(); e.preventDefault();
$(wrapper).append("<div><label class='btn btn-primary btn-sm btn-file'>Browse... <input type='file' name='attachment' id='file" + x + "' multiple style='display: none;'/></label><span>&nbsp;</span><span id='selectedfilename" + x + "'>{% trans 'No files selected.' %}</span></div>"); //add input box $(wrapper).append("<div><label class='btn btn-primary btn-sm btn-file'>Browse... <input type='file' name='attachment' id='file" + x + "' multiple style='display: none;'/></label><span>&nbsp;</span><span id='selectedfilename" + x + "'>{% trans 'No files selected.' %}</span></div>"); //add input box
}); });
{% endif %}
});
}); {% if helpdesk_settings.HELPDESK_ENABLE_ATTACHMENTS %}
// this function listens for changes on any file input, and
// this function listens for changes on any file input, and // emits the appropriate event to update the input's text.
// emits the appropriate event to update the input's text. // Needed to have properly styled file input buttons! (this really shouldn't be this hard...)
// Needed to have properly styled file input buttons! (this really shouldn't be this hard...) $(document).on('change', ':file', function() {
$(document).on('change', ':file', function() { var input = $(this),
var input = $(this), inputWidgetNum = $(this).attr('id').split("file")[1],
inputWidgetNum = $(this).attr('id').split("file")[1], numFiles = input.get(0).files ? input.get(0).files.length : 1,
numFiles = input.get(0).files ? input.get(0).files.length : 1, label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
label = input.val().replace(/\\/g, '/').replace(/.*\//, ''); input.trigger('fileselect', [numFiles, label, inputWidgetNum]);
input.trigger('fileselect', [numFiles, label, inputWidgetNum]); });
}); {% endif %}
</script> </script>
{% endblock %} {% endblock %}

View File

@ -190,7 +190,8 @@
<th class="table-active">{% trans "Knowlegebase item" %}</th> <th class="table-active">{% trans "Knowlegebase item" %}</th>
<td> <a href ="{{ticket.kbitem.query_url}}"> {{ticket.kbitem}} </a> </td> <td> <a href ="{{ticket.kbitem.query_url}}"> {{ticket.kbitem}} </a> </td>
</tr> </tr>
{% endif %} {% endif %}
{% if helpdesk_settings.HELPDESK_ENABLE_ATTACHMENTS %}
<tr> <tr>
<th class="table-active">{% trans "Attachments" %}</th> <th class="table-active">{% trans "Attachments" %}</th>
<td colspan="3"> <td colspan="3">
@ -212,6 +213,7 @@
</ul> </ul>
</td> </td>
</tr> </tr>
{% endif %}
<tr> <tr>
<th class="table-active">{% trans "Checklists" %}</th> <th class="table-active">{% trans "Checklists" %}</th>
<td colspan="3"> <td colspan="3">