Merge #1009 Django 4 support into unstable

This commit is contained in:
Garret Wassermann 2022-04-23 02:24:17 -04:00
commit 224f1cb83e
27 changed files with 180 additions and 154 deletions

View File

@ -13,7 +13,7 @@ Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url, include
from django.urls import include, path
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
@ -26,7 +26,7 @@ from django.conf.urls.static import static
# https://docs.djangoproject.com/en/1.10/howto/static-files/
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include('helpdesk.urls', namespace='helpdesk')),
url(r'^api/auth/', include('rest_framework.urls', namespace='rest_framework'))
path('admin/', admin.site.urls),
path('', include('helpdesk.urls', namespace='helpdesk')),
path('api/auth/', include('rest_framework.urls', namespace='rest_framework'))
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@ -1,7 +1,7 @@
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
from helpdesk.models import Queue, Ticket, FollowUp, PreSetReply
from helpdesk.models import EscalationExclusion, EmailTemplate
from django.utils.translation import gettext_lazy as _
from helpdesk.models import Queue, Ticket, FollowUp, PreSetReply, KBCategory
from helpdesk.models import EscalationExclusion, EmailTemplate, KBItem
from helpdesk.models import TicketChange, KBIAttachment, FollowUpAttachment, IgnoreEmail
from helpdesk.models import CustomField
from helpdesk import settings as helpdesk_settings

View File

@ -27,7 +27,7 @@ from django.core.exceptions import ValidationError
from django.core.files.uploadedfile import SimpleUploadedFile
from django.db.models import Q
from django.utils import encoding, timezone
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
from email_reply_parser import EmailReplyParser
from helpdesk import settings
@ -129,7 +129,7 @@ def pop3_sync(q, logger, server):
if type(raw_content[0]) is bytes:
full_message = "\n".join([elm.decode('utf-8') for elm in raw_content])
else:
full_message = encoding.force_text("\n".join(raw_content), errors='replace')
full_message = encoding.force_str("\n".join(raw_content), errors='replace')
ticket = object_from_message(message=full_message, queue=q, logger=logger)
if ticket:
@ -175,7 +175,7 @@ def imap_sync(q, logger, server):
for num in msgnums:
logger.info("Processing message %s" % num)
status, data = server.fetch(num, '(RFC822)')
full_message = encoding.force_text(data[0][1], errors='replace')
full_message = encoding.force_str(data[0][1], errors='replace')
try:
ticket = object_from_message(message=full_message, queue=q, logger=logger)
except TypeError:
@ -268,7 +268,7 @@ def process_queue(q, logger):
for i, m in enumerate(mail, 1):
logger.info("Processing message %d" % i)
with open(m, 'r') as f:
full_message = encoding.force_text(f.read(), errors='replace')
full_message = encoding.force_str(f.read(), errors='replace')
ticket = object_from_message(message=full_message, queue=q, logger=logger)
if ticket:
logger.info("Successfully processed message %d, ticket/comment created.", i)
@ -579,9 +579,9 @@ def object_from_message(message, queue, logger):
logger.debug("Discovered plain text MIME part")
else:
try:
email_body = encoding.smart_text(part.get_payload(decode=True))
email_body = encoding.smart_str(part.get_payload(decode=True))
except UnicodeDecodeError:
email_body = encoding.smart_text(part.get_payload(decode=False))
email_body = encoding.smart_str(part.get_payload(decode=False))
if not body and not full_body:
# no text has been parsed so far - try such deep parsing for some messages

View File

@ -12,7 +12,7 @@ from datetime import datetime, date, time
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django import forms
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.contrib.auth import get_user_model
from django.utils import timezone

View File

@ -11,7 +11,7 @@ import mimetypes
from datetime import datetime, date, time
from django.conf import settings
from django.utils.encoding import smart_text
from django.utils.encoding import smart_str
from helpdesk.settings import CUSTOMFIELD_DATETIME_FORMAT, CUSTOMFIELD_DATE_FORMAT, CUSTOMFIELD_TIME_FORMAT
@ -117,13 +117,13 @@ def text_is_spam(text, request):
if ak.verify_key():
ak_data = {
'user_ip': request.META.get('REMOTE_ADDR', '127.0.0.1'),
'user_agent': request.META.get('HTTP_USER_AGENT', ''),
'referrer': request.META.get('HTTP_REFERER', ''),
'user_agent': request.headers.get('User-Agent', ''),
'referrer': request.headers.get('Referer', ''),
'comment_type': 'comment',
'comment_author': '',
}
return ak.comment_check(smart_text(text), data=ak_data)
return ak.comment_check(smart_str(text), data=ak_data)
return False
@ -135,8 +135,9 @@ def process_attachments(followup, attached_files):
for attached in attached_files:
if attached.size:
filename = smart_text(attached.name)
att = followup.followupattachment_set.create(
filename = smart_str(attached.name)
att = FollowUpAttachment(
followup=followup,
file=attached,
filename=filename,
mime_type=attached.content_type or

View File

@ -19,7 +19,7 @@ from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.core.management.base import BaseCommand, CommandError
from django.db.utils import IntegrityError
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from helpdesk.models import Queue

View File

@ -8,7 +8,7 @@ create_usersettings.py - Easy way to create helpdesk-specific settings for
users who don't yet have them.
"""
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model

View File

@ -15,7 +15,7 @@ import sys
from django.core.management.base import BaseCommand, CommandError
from django.db.models import Q
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
from django.utils import timezone
from helpdesk.models import Queue, Ticket, FollowUp, EscalationExclusion, TicketChange

View File

@ -2,7 +2,7 @@
from django.core.exceptions import ObjectDoesNotExist
from django.db import migrations
from django.db.utils import IntegrityError
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
def create_and_assign_permissions(apps, schema_editor):

View File

@ -14,7 +14,7 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models
from django.conf import settings
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _, ugettext
from django.utils.translation import gettext_lazy as _, gettext
from io import StringIO
import re
import os
@ -1031,11 +1031,11 @@ class TicketChange(models.Model):
def __str__(self):
out = '%s ' % self.field
if not self.new_value:
out += ugettext('removed')
out += gettext('removed')
elif not self.old_value:
out += ugettext('set to %s') % self.new_value
out += gettext('set to %s') % self.new_value
else:
out += ugettext('changed from "%(old_value)s" to "%(new_value)s"') % {
out += gettext('changed from "%(old_value)s" to "%(new_value)s"') % {
'old_value': self.old_value,
'new_value': self.new_value
}

View File

@ -1,7 +1,7 @@
from django.db.models import Q
from django.urls import reverse
from django.utils.html import escape
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
from base64 import b64encode
from base64 import b64decode

View File

@ -3,9 +3,9 @@
<h2>Queries</h2>
<p>
{{ sql_queries|length }} Quer{{ sql_queries|pluralize:"y,ies" }}
{% ifnotequal sql_queries|length 0 %}
{% if sql_queries|length != 0 %}
(<span style="cursor: pointer;" onclick="var s=document.getElementById('debugQueryTable').style;s.display=s.display=='none'?'':'none';this.innerHTML=this.innerHTML=='Show'?'Hide':'Show';">Show</span>)
{% endifnotequal %}
{% endif %}
</p>
<table id="debugQueryTable" style="display: none;">
<col width="1"></col>

View File

@ -14,7 +14,7 @@
{% endwith %}
{% for u in user_choices %}
<option value='{{ u.id }}'{% if u.id|in_list:query_params.filtering.assigned_to__id__in %} selected='selected'{% endif %}>
{{ u.get_username }}{% ifequal u user %} {% trans "(ME)" %}{% endifequal %}
{{ u.get_username }}
</option>
{% endfor %}
</select>

View File

@ -6,22 +6,22 @@
</div>
<div class="col col-sm-3">
<select id='id_sortx' name='sortx' class="">
<option value='created'{% ifequal query_params.sorting "created"%} selected='selected'{% endifequal %}>
<option value='created'{% if query_params.sorting == "created"%} selected='selected'{% endif %}>
{% trans "Created" %}
</option>
<option value='title'{% ifequal query_params.sorting "title"%} selected='selected'{% endifequal %}>
<option value='title'{% if query_params.sorting == "title"%} selected='selected'{% endif %}>
{% trans "Title" %}
</option>
<option value='queue'{% ifequal query_params.sorting "queue"%} selected='selected'{% endifequal %}>
<option value='queue'{% if query_params.sorting == "queue"%} selected='selected'{% endif %}>
{% trans "Queue" %}
</option>
<option value='status'{% ifequal query_params.sorting "status"%} selected='selected'{% endifequal %}>
<option value='status'{% if query_params.sorting == "status"%} selected='selected'{% endif %}>
{% trans "Status" %}
</option>
<option value='priority'{% ifequal query_params.sorting "priority"%} selected='selected'{% endifequal %}>
<option value='priority'{% if query_params.sorting == "priority"%} selected='selected'{% endif %}>
{% trans "Priority" %}
</option>
<option value='assigned_to'{% ifequal query_params.sorting "assigned_to"%} selected='selected'{% endifequal %}>
<option value='assigned_to'{% if query_params.sorting == "assigned_to"%} selected='selected'{% endif %}>
{% trans "Owner" %}
</option>
</select>

View File

@ -34,7 +34,7 @@
{% for q in user_saved_queries_ %}
<a class="dropdown-item" href="{% url 'helpdesk:list' %}?saved_query={{ q.id }}">{{ q.title }}
{% if q.shared %}
(Shared{% ifnotequal user q.user %} by {{ q.user.get_username }}{% endifnotequal %})
(Shared{% if user != q.user %} by {{ q.user.get_username }}{% endif %})
{% endif %}
</a>
{% endfor %}

View File

@ -25,7 +25,7 @@
{% for q in user_saved_queries_ %}
<a class="dropdown-item small" href="{% url 'helpdesk:list' %}?saved_query={{ q.id }}">{{ q.title }}
{% if q.shared %}
(Shared{% ifnotequal user q.user %} by {{ q.user.get_username }}{% endifnotequal %})
(Shared{% if user != q.user %} by {{ q.user.get_username }}{% endif %})
{% endif %}
</a>
{% endfor %}

View File

@ -99,34 +99,34 @@
<dd class='form_help_text'>{% trans "You can insert ticket and queue details in your message. For more information, see the <a href='../../help/context/'>context help page</a>." %}</dd>
{% 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 %}
{% ifequal ticket.status 1 %}
{% if ticket.status == 1 %}
<input type="hidden" name="new_status" value="{{ ticket.status }}" />
{% endifequal %}
{% ifequal ticket.status 2 %}
{% endif %}
{% if ticket.status == 2 %}
<dd><div class="form-group">
<label for='st_reopened' class='active radio-inline'><input type='radio' name='new_status' value='2' id='st_reopened' checked='checked'>{% trans "Reopened" %} &raquo;</label>
<label class="radio-inline" for='st_resolved'><input type='radio' name='new_status' value='3' id='st_resolved'{% if not ticket.can_be_resolved %} disabled='disabled'{% endif %}>{% trans "Resolved" %} &raquo;</label>
<label class="radio-inline" for='st_closed'><input type='radio' name='new_status' value='4' id='st_closed'{% if not ticket.can_be_resolved %} disabled='disabled'{% endif %}>{% trans "Closed" %} &raquo;</label>
<label class="radio-inline" for='st_duplicate'><input type='radio' name='new_status' value='5' id='st_duplicate'>{% trans "Duplicate" %}</label>
</div></dd>
{% endifequal %}
{% ifequal ticket.status 3 %}
{% endif %}
{% if ticket.status == 3 %}
<dd><div class="form-group">
<label for='st_reopened' class="radio-inline"><input type='radio' name='new_status' value='2' id='st_reopened'>{% trans "Reopened" %} &laquo;</label>
<label for='st_resolved' class='active radio-inline'><input type='radio' name='new_status' value='3' id='st_resolved' checked='checked'>{% trans "Resolved" %} &raquo;</label>
<label class="radio-inline" for='st_closed'><input type='radio' name='new_status' value='4' id='st_closed'>{% trans "Closed" %}</label>
</div></dd>
{% endifequal %}
{% ifequal ticket.status 4 %}
{% endif %}
{% if ticket.status == 4 %}
<dd><div class="form-group"><label for='st_reopened' class="radio-inline"><input type='radio' name='new_status' value='2' id='st_reopened'>{% trans "Reopened" %} &laquo;</label>
<label class="radio-inline" for='st_closed'><input type='radio' name='new_status' value='4' id='st_closed' checked='checked'>{% trans "Closed" %}</label></div></dd>
{% endifequal %}
{% ifequal ticket.status 5 %}
{% endif %}
{% if ticket.status == 5 %}
<dd><div class="form-group">
<label class="radio-inline" for='st_reopened'><input type='radio' name='new_status' value='2' id='st_reopened'>{% trans "Reopened" %} &laquo;</label>
<label class="radio-inline" for='st_duplicate'><input type='radio' name='new_status' value='5' id='st_duplicate' checked='checked'>{% trans "Duplicate" %}</label>
</div></dd>
{% endifequal %}
{% endif %}
<input type='hidden' name='public' value='1'>

View File

@ -29,7 +29,7 @@
<label for='saved_query'>{% trans "Select Query:" %}</label>
<select name='saved_query'>
<option value="">--------</option>{% for q in user_saved_queries_ %}
<option value="{{ q.id }}"{% ifequal saved_query q %} selected{% endifequal %}>{{ q.title }}</option>{% endfor %}
<option value="{{ q.id }}"{% if saved_query==q %} selected{% endif %}>{{ q.title }}</option>{% endfor %}
</select>
<input class="btn btn-primary" type='submit' value='{% trans "Filter Report" %}'>
</form>

View File

@ -112,39 +112,39 @@
<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 %}
{% ifequal ticket.status 1 %}
{% if ticket.status == 1 %}
<dd><div class="form-group">
<label for='st_open' class='active radio-inline'><input type='radio' name='new_status' value='1' id='st_open' checked='checked'>{% trans "Open" %} &raquo;</label>
<label for='st_resolved' class="radio-inline"><input type='radio' name='new_status' value='3' id='st_resolved'{% if not ticket.can_be_resolved %} disabled='disabled'{% endif %}>{% trans "Resolved" %} &raquo;</label>
<label for='st_closed' class="radio-inline"><input type='radio' name='new_status' value='4' id='st_closed'{% if not ticket.can_be_resolved %} disabled='disabled'{% endif %}>{% trans "Closed" %} &raquo;</label>
<label class="radio-inline" for='st_duplicate'><input type='radio' name='new_status' value='5' id='st_duplicate'>{% trans "Duplicate" %}</label>
</div></dd>
{% endifequal %}
{% ifequal ticket.status 2 %}
{% endif %}
{% if ticket.status == 2 %}
<dd><div class="form-group">
<label for='st_reopened' class='active radio-inline'><input type='radio' name='new_status' value='2' id='st_reopened' checked='checked'>{% trans "Reopened" %} &raquo;</label>
<label class="radio-inline" for='st_resolved'><input type='radio' name='new_status' value='3' id='st_resolved'{% if not ticket.can_be_resolved %} disabled='disabled'{% endif %}>{% trans "Resolved" %} &raquo;</label>
<label class="radio-inline" for='st_closed'><input type='radio' name='new_status' value='4' id='st_closed'{% if not ticket.can_be_resolved %} disabled='disabled'{% endif %}>{% trans "Closed" %} &raquo;</label>
<label class="radio-inline" for='st_duplicate'><input type='radio' name='new_status' value='5' id='st_duplicate'>{% trans "Duplicate" %}</label>
</div></dd>
{% endifequal %}
{% ifequal ticket.status 3 %}
{% endif %}
{% if ticket.status == 3 %}
<dd><div class="form-group">
<label for='st_reopened' class="radio-inline"><input type='radio' name='new_status' value='2' id='st_reopened'>{% trans "Reopened" %} &laquo;</label>
<label for='st_resolved' class='active radio-inline'><input type='radio' name='new_status' value='3' id='st_resolved' checked='checked'>{% trans "Resolved" %} &raquo;</label>
<label class="radio-inline" for='st_closed'><input type='radio' name='new_status' value='4' id='st_closed'>{% trans "Closed" %}</label>
</div></dd>
{% endifequal %}
{% ifequal ticket.status 4 %}
{% endif %}
{% if ticket.status == 4 %}
<dd><div class="form-group"><label for='st_reopened' class="radio-inline"><input type='radio' name='new_status' value='2' id='st_reopened'>{% trans "Reopened" %} &laquo;</label>
<label class="radio-inline" for='st_closed'><input type='radio' name='new_status' value='4' id='st_closed' checked='checked'>{% trans "Closed" %}</label></div></dd>
{% endifequal %}
{% ifequal ticket.status 5 %}
{% endif %}
{% if ticket.status == 5 %}
<dd><div class="form-group">
<label class="radio-inline" for='st_reopened'><input type='radio' name='new_status' value='2' id='st_reopened'>{% trans "Reopened" %} &laquo;</label>
<label class="radio-inline" for='st_duplicate'><input type='radio' name='new_status' value='5' id='st_duplicate' checked='checked'>{% trans "Duplicate" %}</label>
</div></dd>
{% endifequal %}
{% endif %}
{% if helpdesk_settings.HELPDESK_UPDATE_PUBLIC_DEFAULT %}
<input type='hidden' name='public' value='1'>
@ -176,10 +176,10 @@
<dd><input type='text' name='title' value='{{ ticket.title|escape }}' /></dd>
<dt><label for='id_owner'>{% trans "Owner" %}</label></dt>
<dd><select id='id_owner' name='owner'><option value='0'>{% trans "Unassign" %}</option>{% for u in active_users %}<option value='{{ u.id }}' {% ifequal u.id ticket.assigned_to.id %}selected{% endifequal %}>{{ u }}</option>{% endfor %}</select></dd>
<dd><select id='id_owner' name='owner'><option value='0'>{% trans "Unassign" %}</option>{% for u in active_users %}{% if u.id == ticket.assigned_to.id %}<option value='{{ u.id }}' selected>{{ u }}</option>{% else %}<option value='{{ u.id }}'>{{ u }}</option>{% endif %}{% endfor %}</select></dd>
<dt><label for='id_priority'>{% trans "Priority" %}</label></dt>
<dd><select id='id_priority' name='priority'>{% for p in priorities %}<option value='{{ p.0 }}'{% ifequal p.0 ticket.priority %} selected='selected'{% endifequal %}>{{ p.1 }}</option>{% endfor %}</select></dd>
<dd><select id='id_priority' name='priority'>{% for p in priorities %}{% if p.0 == ticket.priority %}<option value='{{ p.0 }}' selected='selected'>{{ p.1 }}</option>{% else %}<option value='{{ p.0 }}'>{{ p.1 }}</option>{% endif %}{% endfor %}</select></dd>
<dt><label for='id_due_date'>{% trans "Due on" %}</label></dt>
<dd>{{ form.due_date }}</dd>

View File

@ -2,7 +2,7 @@
from django.core.files.uploadedfile import SimpleUploadedFile
from django.urls import reverse
from django.test import override_settings, TestCase
from django.utils.encoding import smart_text
from django.utils.encoding import smart_str
from helpdesk import lib, models
@ -78,7 +78,7 @@ class AttachmentIntegrationTests(TestCase):
# Ensure attachment is available with correct content
att = models.FollowUpAttachment.objects.get(followup__ticket=response.context['ticket'])
with open(os.path.join(MEDIA_DIR, att.file.name)) as file_on_disk:
disk_content = smart_text(file_on_disk.read(), 'utf-8')
disk_content = smart_str(file_on_disk.read(), 'utf-8')
self.assertEqual(disk_content, 'โจ')

View File

@ -1,7 +1,7 @@
from django.conf.urls import include, url
from django.urls import include, path
from django.contrib import admin
urlpatterns = [
url(r'^helpdesk/', include('helpdesk.urls', namespace='helpdesk')),
url(r'^admin/', admin.site.urls),
path('helpdesk/', include('helpdesk.urls', namespace='helpdesk')),
path('admin/', admin.site.urls),
]

View File

@ -7,7 +7,7 @@ urls.py - Mapping of URL's to our various views. Note we always used NAMED
views for simplicity in linking later on.
"""
from django.conf.urls import url
from django.urls import path, re_path
from django.contrib.auth.decorators import login_required
from django.contrib.auth import views as auth_views
from django.urls import include
@ -48,115 +48,123 @@ app_name = 'helpdesk'
base64_pattern = r'(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$'
urlpatterns = [
url(r'^dashboard/$',
path('dashboard/',
staff.dashboard,
name='dashboard'),
url(r'^tickets/$',
path('tickets/',
staff.ticket_list,
name='list'),
url(r'^tickets/update/$',
path('tickets/update/',
staff.mass_update,
name='mass_update'),
url(r'^tickets/merge$',
path('tickets/merge',
staff.merge_tickets,
name='merge_tickets'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/$',
path('tickets/<int:ticket_id>/',
staff.view_ticket,
name='view'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/followup_edit/(?P<followup_id>[0-9]+)/$',
path('tickets/<int:ticket_id>/followup_edit/<int:followup_id>/',
staff.followup_edit,
name='followup_edit'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/followup_delete/(?P<followup_id>[0-9]+)/$',
path('tickets/<int:ticket_id>/followup_delete/<int:followup_id>/',
staff.followup_delete,
name='followup_delete'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/edit/$',
path('tickets/<int:ticket_id>/edit/',
staff.edit_ticket,
name='edit'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/update/$',
path('tickets/<int:ticket_id>/update/',
staff.update_ticket,
name='update'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/delete/$',
path('tickets/<int:ticket_id>/delete/',
staff.delete_ticket,
name='delete'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/hold/$',
path('tickets/<int:ticket_id>/hold/',
staff.hold_ticket,
name='hold'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/unhold/$',
path('tickets/<int:ticket_id>/unhold/',
staff.unhold_ticket,
name='unhold'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/cc/$',
path('tickets/<int:ticket_id>/cc/',
staff.ticket_cc,
name='ticket_cc'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/cc/add/$',
path('tickets/<int:ticket_id>/cc/add/',
staff.ticket_cc_add,
name='ticket_cc_add'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/cc/delete/(?P<cc_id>[0-9]+)/$',
path('tickets/<int:ticket_id>/cc/delete/<int:cc_id>/',
staff.ticket_cc_del,
name='ticket_cc_del'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/attachment_delete/(?P<attachment_id>[0-9]+)/$',
path('tickets/<int:ticket_id>/dependency/add/',
staff.ticket_dependency_add,
name='ticket_dependency_add'),
path('tickets/<int:ticket_id>/dependency/delete/<int:dependency_id>/',
staff.ticket_dependency_del,
name='ticket_dependency_del'),
path('tickets/<int:ticket_id>/attachment_delete/<int:attachment_id>/',
staff.attachment_del,
name='attachment_del'),
url(r'^raw/(?P<type>\w+)/$',
re_path(r'^raw/(?P<type>\w+)/$',
staff.raw_details,
name='raw'),
url(r'^rss/$',
path('rss/',
staff.rss_list,
name='rss_index'),
url(r'^reports/$',
path('reports/',
staff.report_index,
name='report_index'),
url(r'^reports/(?P<report>\w+)/$',
re_path(r'^reports/(?P<report>\w+)/$',
staff.run_report,
name='run_report'),
url(r'^save_query/$',
path('save_query/',
staff.save_query,
name='savequery'),
url(r'^delete_query/(?P<id>[0-9]+)/$',
path('delete_query/<int:id>/',
staff.delete_saved_query,
name='delete_query'),
url(r'^settings/$',
path('settings/',
staff.EditUserSettingsView.as_view(),
name='user_settings'),
url(r'^ignore/$',
path('ignore/',
staff.email_ignore,
name='email_ignore'),
url(r'^ignore/add/$',
path('ignore/add/',
staff.email_ignore_add,
name='email_ignore_add'),
url(r'^ignore/delete/(?P<id>[0-9]+)/$',
path('ignore/delete/<int:id>/',
staff.email_ignore_del,
name='email_ignore_del'),
url(r'^datatables_ticket_list/(?P<query>{})$'.format(base64_pattern),
re_path(r'^datatables_ticket_list/(?P<query>{})$'.format(base64_pattern),
staff.datatables_ticket_list,
name="datatables_ticket_list"),
url(r'^timeline_ticket_list/(?P<query>{})$'.format(base64_pattern),
re_path(r'^timeline_ticket_list/(?P<query>{})$'.format(base64_pattern),
staff.timeline_ticket_list,
name="timeline_ticket_list"),
@ -174,49 +182,49 @@ if helpdesk_settings.HELPDESK_ENABLE_DEPENDENCIES_ON_TICKET:
]
urlpatterns += [
url(r'^$',
path('',
protect_view(public.Homepage.as_view()),
name='home'),
url(r'^tickets/submit/$',
path('tickets/submit/',
public.create_ticket,
name='submit'),
url(r'^tickets/submit_iframe/$',
path('tickets/submit_iframe/',
public.CreateTicketIframeView.as_view(),
name='submit_iframe'),
url(r'^tickets/success_iframe/$', # Ticket was submitted successfully
path('tickets/success_iframe/', # Ticket was submitted successfully
public.SuccessIframeView.as_view(),
name='success_iframe'),
url(r'^view/$',
path('view/',
public.view_ticket,
name='public_view'),
url(r'^change_language/$',
path('change_language/',
public.change_language,
name='public_change_language'),
]
urlpatterns += [
url(r'^rss/user/(?P<user_name>[^/]+)/$',
path('rss/user/<str:user_name>/',
helpdesk_staff_member_required(feeds.OpenTicketsByUser()),
name='rss_user'),
url(r'^rss/user/(?P<user_name>[^/]+)/(?P<queue_slug>[A-Za-z0-9_-]+)/$',
re_path(r'^rss/user/(?P<user_name>[^/]+)/(?P<queue_slug>[A-Za-z0-9_-]+)/$',
helpdesk_staff_member_required(feeds.OpenTicketsByUser()),
name='rss_user_queue'),
url(r'^rss/queue/(?P<queue_slug>[A-Za-z0-9_-]+)/$',
re_path(r'^rss/queue/(?P<queue_slug>[A-Za-z0-9_-]+)/$',
helpdesk_staff_member_required(feeds.OpenTicketsByQueue()),
name='rss_queue'),
url(r'^rss/unassigned/$',
path('rss/unassigned/',
helpdesk_staff_member_required(feeds.UnassignedTickets()),
name='rss_unassigned'),
url(r'^rss/recent_activity/$',
path('rss/recent_activity/',
helpdesk_staff_member_required(feeds.RecentFollowUps()),
name='rss_activity'),
]
@ -232,23 +240,23 @@ if helpdesk_settings.HELPDESK_ACTIVATE_API_ENDPOINT:
urlpatterns += [
url(r'^login/$',
path('login/',
login.login,
name='login'),
url(r'^logout/$',
path('logout/',
auth_views.LogoutView.as_view(
template_name='helpdesk/registration/login.html',
next_page='../'),
name='logout'),
url(r'^password_change/$',
path('password_change/',
auth_views.PasswordChangeView.as_view(
template_name='helpdesk/registration/change_password.html',
success_url='./done'),
name='password_change'),
url(r'^password_change/done$',
path('password_change/done',
auth_views.PasswordChangeDoneView.as_view(
template_name='helpdesk/registration/change_password_done.html',),
name='password_change_done'),
@ -256,29 +264,29 @@ urlpatterns += [
if helpdesk_settings.HELPDESK_KB_ENABLED:
urlpatterns += [
url(r'^kb/$',
path('kb/',
kb.index,
name='kb_index'),
url(r'^kb/(?P<slug>[A-Za-z0-9_-]+)/$',
re_path(r'^kb/(?P<slug>[A-Za-z0-9_-]+)/$',
kb.category,
name='kb_category'),
url(r'^kb/(?P<item>[0-9]+)/vote/$',
path('kb/<int:item>/vote/',
kb.vote,
name='kb_vote'),
url(r'^kb_iframe/(?P<slug>[A-Za-z0-9_-]+)/$',
re_path(r'^kb_iframe/(?P<slug>[A-Za-z0-9_-]+)/$',
kb.category_iframe,
name='kb_category_iframe'),
]
urlpatterns += [
url(r'^help/context/$',
path('help/context/',
TemplateView.as_view(template_name='helpdesk/help_context.html'),
name='help_context'),
url(r'^system_settings/$',
path('system_settings/',
login_required(DirectTemplateView.as_view(template_name='helpdesk/system_settings.html')),
name='system_settings'),
]

View File

@ -11,7 +11,7 @@ from django.contrib.auth import get_user_model
from django.contrib.syndication.views import Feed
from django.urls import reverse
from django.db.models import Q
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
from django.shortcuts import get_object_or_404
from helpdesk.models import Ticket, FollowUp, Queue

View File

@ -15,8 +15,8 @@ from django.core.exceptions import (
from django.urls import reverse
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.utils.http import urlquote
from django.utils.translation import ugettext as _
from urllib.parse import quote
from django.utils.translation import gettext as _
from django.conf import settings
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.decorators.csrf import csrf_exempt
@ -112,7 +112,7 @@ class BaseCreateTicketView(abstract_views.AbstractCreateTicketMixin, FormView):
return HttpResponseRedirect('%s?ticket=%s&email=%s&key=%s' % (
reverse('helpdesk:public_view'),
ticket.ticket_for_url,
urlquote(ticket.submitter_email),
quote(ticket.submitter_email),
ticket.secret_key)
)
except ValueError:

View File

@ -19,7 +19,7 @@ from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.db.models import Q
from django.http import HttpResponseRedirect, Http404, HttpResponse, JsonResponse
from django.shortcuts import render, get_object_or_404, redirect
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
from django.utils.html import escape
from django.utils import timezone
from django.views.decorators.csrf import requires_csrf_token

View File

@ -1,7 +1,6 @@
Django>=2.2,<4
Django>=2.2
django-bootstrap4-form
celery
django-celery-beat
email-reply-parser
akismet
markdown

View File

@ -8,9 +8,16 @@ version = '0.4.0a1'
# Provided as an attribute, so you can append to these instead
# of replicating them:
standard_exclude = ('*.py', '*.pyc', '*$py.class', '*~', '.*', '*.bak')
standard_exclude_directories = ('.*', 'CVS', '_darcs', './build',
'./dist', 'EGG-INFO', '*.egg-info')
standard_exclude = ("*.py", "*.pyc", "*$py.class", "*~", ".*", "*.bak")
standard_exclude_directories = (
".*",
"CVS",
"_darcs",
"./build",
"./dist",
"EGG-INFO",
"*.egg-info",
)
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
@ -18,11 +25,13 @@ standard_exclude_directories = ('.*', 'CVS', '_darcs', './build',
# you can't import this from another package, when you don't know if
# that package is installed yet.
def find_package_data(
where='.', package='',
where=".",
package="",
exclude=standard_exclude,
exclude_directories=standard_exclude_directories,
only_in_packages=True,
show_ignored=False):
show_ignored=False,
):
"""
Return a dictionary suitable for use in ``package_data``
in a distutils ``setup.py`` file.
@ -51,7 +60,7 @@ def find_package_data(
"""
out = {}
stack = [(convert_path(where), '', package, only_in_packages)]
stack = [(convert_path(where), "", package, only_in_packages)]
while stack:
where, prefix, package, only_in_packages = stack.pop(0)
for name in os.listdir(where):
@ -59,43 +68,40 @@ def find_package_data(
if os.path.isdir(fn):
bad_name = False
for pattern in exclude_directories:
if (fnmatchcase(name, pattern)
or fn.lower() == pattern.lower()):
if fnmatchcase(name, pattern) or fn.lower() == pattern.lower():
bad_name = True
if show_ignored:
print(
"Directory %s ignored by pattern %s" % (fn, pattern),
file=sys.stderr
file=sys.stderr,
)
break
if bad_name:
continue
if (os.path.isfile(os.path.join(fn, '__init__.py'))
and not prefix):
if os.path.isfile(os.path.join(fn, "__init__.py")) and not prefix:
if not package:
new_package = name
else:
new_package = package + '.' + name
stack.append((fn, '', new_package, False))
new_package = package + "." + name
stack.append((fn, "", new_package, False))
else:
stack.append((fn, prefix + name + '/', package, only_in_packages))
stack.append((fn, prefix + name + "/", package, only_in_packages))
elif package or not only_in_packages:
# is a file
bad_name = False
for pattern in exclude:
if (fnmatchcase(name, pattern)
or fn.lower() == pattern.lower()):
if fnmatchcase(name, pattern) or fn.lower() == pattern.lower():
bad_name = True
if show_ignored:
print(
"File %s ignored by pattern %s" % (fn, pattern),
file=sys.stderr
)
file=sys.stderr,
)
break
if bad_name:
continue
out.setdefault(package, []).append(prefix+name)
out.setdefault(package, []).append(prefix + name)
return out
@ -116,7 +122,7 @@ def get_long_description():
setup(
name='django-helpdesk',
name="django-helpdesk",
version=version,
description="Django-powered ticket tracker for your helpdesk",
long_description=get_long_description(),
@ -128,6 +134,10 @@ setup(
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Framework :: Django",
<<<<<<< HEAD
=======
"Framework :: Django :: 2.2",
>>>>>>> 55c638aeef0b3032eab28bcdc8ee313da9cbf9c0
"Framework :: Django :: 3.2",
"Environment :: Web Environment",
"Operating System :: OS Independent",
@ -138,18 +148,26 @@ setup(
"Topic :: Office/Business",
"Natural Language :: English",
],
keywords=['django', 'helpdesk', 'django-helpdesk', 'tickets', 'incidents',
'cases', 'bugs', 'track', 'support'],
author='Ross Poulton',
author_email='ross@rossp.org',
maintainer='Garret Wassermann',
maintainer_email='gwasser@gmail.com',
url='https://github.com/django-helpdesk/django-helpdesk',
license='BSD',
keywords=[
"django",
"helpdesk",
"django-helpdesk",
"tickets",
"incidents",
"cases",
"bugs",
"track",
"support",
],
author="Ross Poulton",
author_email="ross@rossp.org",
maintainer="Garret Wassermann",
maintainer_email="gwasser@gmail.com",
url="https://github.com/django-helpdesk/django-helpdesk",
license="BSD",
packages=find_packages(),
package_data=find_package_data("helpdesk", only_in_packages=False),
include_package_data=True,
zip_safe=False,
install_requires=get_requirements(),
)