mirror of
https://gitea.mueller.network/extern/django-helpdesk.git
synced 2025-01-14 01:48:40 +01:00
Merge remote-tracking branch 'upstream/develop' into develop
This commit is contained in:
commit
9ca7f9fb46
@ -471,9 +471,12 @@ def object_from_message(message, queue, logger):
|
||||
|
||||
if part.get_content_maintype() == 'text' and name is None:
|
||||
if part.get_content_subtype() == 'plain':
|
||||
body = EmailReplyParser.parse_reply(
|
||||
decodeUnknown(part.get_content_charset(), part.get_payload(decode=True))
|
||||
)
|
||||
body = part.get_payload(decode=True)
|
||||
# https://github.com/django-helpdesk/django-helpdesk/issues/732
|
||||
if part['Content-Transfer-Encoding'] == '8bit' and part.get_content_charset() == 'utf-8':
|
||||
body = body.decode('unicode_escape')
|
||||
body = decodeUnknown(part.get_content_charset(), body)
|
||||
body = EmailReplyParser.parse_reply(body)
|
||||
# workaround to get unicode text out rather than escaped text
|
||||
try:
|
||||
body = body.encode('ascii').decode('unicode_escape')
|
||||
@ -481,9 +484,15 @@ def object_from_message(message, queue, logger):
|
||||
body.encode('utf-8')
|
||||
logger.debug("Discovered plain text MIME part")
|
||||
else:
|
||||
payload = encoding.smart_bytes(part.get_payload(decode=True))
|
||||
payload = """
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
</head>
|
||||
%s
|
||||
</html>""" % encoding.smart_text(part.get_payload(decode=True))
|
||||
files.append(
|
||||
SimpleUploadedFile(_("email_html_body.html"), payload, 'text/html')
|
||||
SimpleUploadedFile(_("email_html_body.html"), payload.encode("utf-8"), 'text/html')
|
||||
)
|
||||
logger.debug("Discovered HTML MIME part")
|
||||
else:
|
||||
|
@ -748,6 +748,10 @@ class Ticket(models.Model):
|
||||
def get_markdown(self):
|
||||
return get_markdown(self.description)
|
||||
|
||||
@property
|
||||
def get_resolution_markdown(self):
|
||||
return get_markdown(self.resolution)
|
||||
|
||||
|
||||
class FollowUpManager(models.Manager):
|
||||
|
||||
|
@ -19,6 +19,7 @@ class TicketSerializer(serializers.ModelSerializer):
|
||||
status = serializers.SerializerMethodField()
|
||||
row_class = serializers.SerializerMethodField()
|
||||
time_spent = serializers.SerializerMethodField()
|
||||
queue = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Ticket
|
||||
@ -27,6 +28,9 @@ class TicketSerializer(serializers.ModelSerializer):
|
||||
'created', 'due_date', 'assigned_to', 'row_class',
|
||||
'time_spent')
|
||||
|
||||
def get_queue(self, obj):
|
||||
return ({"title": obj.queue.title, "id": obj.queue.id})
|
||||
|
||||
def get_ticket(self, obj):
|
||||
return (str(obj.id) + " " + obj.ticket)
|
||||
|
||||
|
@ -87,3 +87,11 @@ pre {
|
||||
padding: 1em;
|
||||
border: 1pt solid white;
|
||||
}
|
||||
|
||||
table .tickettitle {
|
||||
max-width: 250px;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
@ -8,12 +8,11 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
|
||||
<thead>
|
||||
<table class="table table-bordered table-sm table-striped" id="dataTable" width="100%" cellspacing="0">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>{% trans "Pr" %}</th>
|
||||
<th>{% trans "Title" %}</th>
|
||||
<th>{% trans "Ticket" %}</th>
|
||||
<th>{% trans "Priority" %}</th>
|
||||
<th>{% trans "Queue" %}</th>
|
||||
<th>{% trans "Status" %}</th>
|
||||
<th>{% trans "Last Update" %}</th>
|
||||
@ -22,9 +21,8 @@
|
||||
<tbody>
|
||||
{% for ticket in ticket_list %}
|
||||
<tr class="{{ ticket.get_priority_css_class }}">
|
||||
<td><a href='{{ ticket.get_absolute_url }}'>{{ ticket.ticket }}</a></td>
|
||||
<td class="tickettitle"><a href="{{ ticket.get_absolute_url }}">{{ ticket.id }}. {{ ticket.title }}</a></td>
|
||||
<td>{{ ticket.priority }}</td>
|
||||
<td><a href='{{ ticket.get_absolute_url }}'>{{ ticket.title }}</a></td>
|
||||
<td>{{ ticket.queue }}</td>
|
||||
<td>{{ ticket.get_status }}</td>
|
||||
<td><span title='{{ ticket.modified|date:"r" }}'>{{ ticket.modified|naturaltime }}</span></td>
|
||||
|
@ -8,28 +8,26 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
|
||||
<thead>
|
||||
<table class="table table-bordered table-sm table-striped" id="dataTable" width="100%" cellspacing="0">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>{% trans "Pr" %}</th>
|
||||
<th>{% trans "Title" %}</th>
|
||||
<th>{% trans "Ticket" %}</th>
|
||||
<th>{% trans "Prority" %}</th>
|
||||
<th>{% trans "Queue" %}</th>
|
||||
<th>{% trans "Status" %}</th>
|
||||
<th> </th>
|
||||
<th>{% trans "Created" %}</th>
|
||||
<th>{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for ticket in unassigned_tickets %}
|
||||
<tr class="{{ ticket.get_priority_css_class }}">
|
||||
<td><a href='{{ ticket.get_absolute_url }}'>{{ ticket.ticket }}</a></td>
|
||||
<td class="tickettitle"><a href='{{ ticket.get_absolute_url }}'>{{ ticket.id }}. {{ ticket.title }} </a></td>
|
||||
<td>{{ ticket.priority }}</td>
|
||||
<td><a href='{{ ticket.get_absolute_url }}'>{{ ticket.title }}</a></td>
|
||||
<td>{{ ticket.queue }}</td>
|
||||
<td><span title='{{ ticket.created|date:"r" }}'>{{ ticket.created|naturaltime }}</span></td>
|
||||
<td>
|
||||
<a href='{{ ticket.get_absolute_url }}?take'><button class='btn btn-primary btn-xs'><i class="fas fa-hand-paper"></i> {% trans "Take" %}</button></a> |
|
||||
<a href='{% url 'helpdesk:delete' ticket.id %}'><button class='btn btn-danger btn-xs'><i class="fas fa-trash"></i> {% trans "Delete" %}</button></a>
|
||||
<td class="text-center">
|
||||
<a href='{{ ticket.get_absolute_url }}?take'><button class='btn btn-primary btn-sm'><i class="fas fa-hand-paper"></i> {% trans "Take" %}</button></a>
|
||||
<a href='{% url 'helpdesk:delete' ticket.id %}'><button class='btn btn-danger btn-sm'><i class="fas fa-trash"></i> {% trans "Delete" %}</button></a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
|
@ -24,12 +24,13 @@
|
||||
{% cycle 'one' 'two' 'three' as itemnumperrow silent %}
|
||||
{% ifequal itemnumperrow 'one' %}<div class="card-deck">{% endifequal %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">{{ item.title }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text">{{ item.question }}</p>
|
||||
<p class="card-text">
|
||||
<p>
|
||||
{% blocktrans with item.get_absolute_url as url %}View <a href='{{ url }}'>Answer <i class="fa fa-arrow-right"></i></a>{% endblocktrans %}
|
||||
{% blocktrans with item.get_absolute_url as url %}<a href='{{ url }}' class="btn btn-primary"> Go to answer <i class="fa fa-share"></i></a>{% endblocktrans %}
|
||||
</p>
|
||||
<div class="well well-sm">
|
||||
<p>{% trans 'Rating' %}: {{ item.score }}</p>
|
||||
|
@ -18,10 +18,12 @@
|
||||
{% cycle 'one' 'two' 'three' as catnumperrow silent %}
|
||||
{% if catnumperrow == 'one' %}<div class="card-deck">{% endif %}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>{{ category.title }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ category.title }}</h5>
|
||||
<p class="card-text">{{ category.description }}</p>
|
||||
<p class="card-text"><small class="text-muted"><a href='{{ category.get_absolute_url }}'>{% trans 'View articles' %}<i class="fa fa-arrow-right"></i></a></small></p>
|
||||
<p class="card-text"><small class="text-muted"><a class="btn btn-primary" href='{{ category.get_absolute_url }}'>{% trans 'View articles' %} <i class="fa fa-share"></i></a></small></p>
|
||||
</div>
|
||||
</div>
|
||||
{% if catnumperrow == 'three' %}</div>{% endif %}
|
||||
|
@ -11,7 +11,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block helpdesk_body %}
|
||||
<h2>{% trans 'Knowledgebase' %}:{% blocktrans with item.title as item %}{{ item }}{% endblocktrans %}</h2>
|
||||
<h2>{% trans 'Knowledgebase' %}: {% blocktrans with item.title as item %}{{ item }}{% endblocktrans %}</h2>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
|
@ -33,7 +33,7 @@
|
||||
<th colspan='2'>{% trans "Resolution" %}{% ifequal ticket.get_status_display "Resolved" %} <a href='?close'><button type="button" class="btn btn-warning btn-sm">{% trans "Accept and Close" %}</button></a>{% endifequal %}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2'>{{ ticket.resolution|force_escape|urlizetrunc:50|linebreaksbr }}</td>
|
||||
<td colspan='2'>{{ ticket.get_resolution_markdown|urlizetrunc:50|linebreaksbr }}</td>
|
||||
</tr>{% endif %}
|
||||
<tr>
|
||||
<th>{% trans "Due Date" %}</th>
|
||||
|
@ -41,7 +41,7 @@
|
||||
<div class="card">
|
||||
<div class="card-header" id="headingOne">
|
||||
<h5 class="mb-0">
|
||||
<button class="btn btn-link" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
||||
<button class="btn btn-link btn-sm" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
||||
<i class="fas fa-question-circle"></i>
|
||||
<strong>{% trans "Change Query" %}</strong>
|
||||
</button>
|
||||
@ -51,7 +51,9 @@
|
||||
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#queryAccordion">
|
||||
<div class="card-body">
|
||||
<form>
|
||||
<select name='select' id='filterBuilderSelect'>
|
||||
<div class="form-group">
|
||||
<label for="filterBuilderSelect">{% trans "Select filter" %}:</label>
|
||||
<select aria-describedby="select-description" name='select' id='filterBuilderSelect'>
|
||||
<option value='Sort'>{% trans "Sorting" %}</option>
|
||||
<option value='Owner'>{% trans "Owner" %}</option>
|
||||
<option value='Queue'>{% trans "Queue" %}</option>
|
||||
@ -59,10 +61,13 @@
|
||||
<option value='Keywords'>{% trans "Keywords" %}</option>
|
||||
<option value='Dates'>{% trans "Date Range" %}</option>
|
||||
</select>
|
||||
<button class='btn btn-success btn-sm' id='filterBuilderButton'><i class="fas fa-plus-circle"></i></button>
|
||||
<small id="select-description" class="form-text text-muted">{% trans "Add another filter to list of filers for finer selection of displayed tickets" %}</small>
|
||||
<button class='btn btn-success btn-sm' id='filterBuilderButton'>{% trans "Add selected filter" %} <i class="fas fa-plus-circle"></i></button>
|
||||
{% csrf_token %}</form>
|
||||
</div>
|
||||
|
||||
<form method='get' action='./'>
|
||||
<div class="d-flex align-items-stretch">
|
||||
<div class='thumbnail filterBox{% if query_params.sorting %} filterBoxShow{% endif %}' id='filterBoxSort'>
|
||||
<label for='id_sort'>{% trans "Sorting" %}</label>
|
||||
<select id='id_sort' name='sort'>
|
||||
@ -128,15 +133,17 @@
|
||||
<p class='filterHelp'>{% trans "Keywords are case-insensitive, and will be looked for in the title, body and submitter fields." %}</p>
|
||||
<button class='filterBuilderRemove btn btn-danger btn-sm'><i class="fas fa-trash-alt"></i></button>
|
||||
</div>
|
||||
</div> <!-- end div d-flex class -->
|
||||
<hr style='clear: both;' />
|
||||
<input class="btn btn-primary" type='submit' value='{% trans "Apply Filter" %}' />
|
||||
<input class="btn btn-primary btn-sm" type='submit' value='{% trans "Apply Filters" %}' />
|
||||
{% if from_saved_query and saved_query.user == user %}
|
||||
<p>{% blocktrans with saved_query.title as query_name %}You are currently viewing saved query <strong>"{{ query_name }}"</strong>.{% endblocktrans %} <a href='{% url 'helpdesk:delete_query' saved_query.id %}'>{% trans "Delete Saved Query" %}</a></p>
|
||||
{% endif %}
|
||||
{% if from_saved_query %}
|
||||
<p>{% blocktrans with saved_query.id as query_id %}<a href='../reports/?saved_query={{ query_id }}'>Run a report</a> on this query to see stats and charts for the data listed below.{% endblocktrans %}</p>
|
||||
{% endif %}
|
||||
{% csrf_token %}</form>
|
||||
{% csrf_token %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- end card -->
|
||||
@ -144,7 +151,7 @@
|
||||
<div class="card">
|
||||
<div class="card-header" id="headingTwo">
|
||||
<h5 class="mb-0">
|
||||
<button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
||||
<button class="btn btn-link collapsed btn-sm" type="button" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
||||
<i class="fas fa-save"></i>
|
||||
<strong>{% trans "Save Query" %}</strong>
|
||||
</button>
|
||||
@ -175,7 +182,7 @@
|
||||
<div class="card">
|
||||
<div class="card-header" id="headingThree">
|
||||
<h5 class="mb-0">
|
||||
<button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
|
||||
<button class="btn btn-link collapsed btn-sm" type="button" data-toggle="collapse" data-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
|
||||
<i class="fas fa-clipboard-check"></i>
|
||||
<strong>{% trans "Use Saved Query" %}</strong>
|
||||
</button>
|
||||
@ -210,13 +217,12 @@
|
||||
<div class="card-body">
|
||||
{{ search_message|safe }}
|
||||
<form method='post' action='{% url 'helpdesk:mass_update' %}' id="ticket_mass_update">
|
||||
<table width="100%" class="table table-striped table-bordered table-hover" id="ticketTable" data-page-length='{{ default_tickets_per_page }}'>
|
||||
<thead>
|
||||
<table width="100%" class="table table-sm table-striped table-bordered table-hover" id="ticketTable" data-page-length='{{ default_tickets_per_page }}'>
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th> </th>
|
||||
<th>{% trans "Pr" %}</th>
|
||||
<th>{% trans "Title" %}</th>
|
||||
<th>{% trans "Ticket" %}</th>
|
||||
<th>{% trans "Prority" %}</th>
|
||||
<th>{% trans "Queue" %}</th>
|
||||
<th>{% trans "Status" %}</th>
|
||||
<th>{% trans "Created" %}</th>
|
||||
@ -301,18 +307,6 @@
|
||||
},
|
||||
|
||||
"columns": [
|
||||
{"data": "ticket",
|
||||
"render": function (data, type, row, meta)
|
||||
{
|
||||
var id = data.split(" ")[0];
|
||||
var name = data.split(" ")[1];
|
||||
if (type === 'display')
|
||||
{
|
||||
data = '<b><a href="' + get_url(row) + '" >' + name + '</a></b>';
|
||||
}
|
||||
return data
|
||||
}
|
||||
},
|
||||
{"data": "id",
|
||||
"orderable": false,
|
||||
"render": function(data, type, row, meta)
|
||||
@ -324,22 +318,49 @@
|
||||
return data
|
||||
}
|
||||
},
|
||||
{"data": "priority"},
|
||||
{"data": "title",
|
||||
{"data": "ticket",
|
||||
"render": function (data, type, row, meta)
|
||||
{
|
||||
if (type === 'display')
|
||||
{
|
||||
data = '<b><a href="' + get_url(row) + '" >' + data + '</a></b>';
|
||||
}
|
||||
return data
|
||||
var id = data.split(" ")[0];
|
||||
var name = data.split(" ")[1];
|
||||
if (type === 'display')
|
||||
{
|
||||
data = '<div class="tickettitle"><a href="' + get_url(row) + '" >' +
|
||||
row.id + '. ' +
|
||||
row.title + '</a></div>';
|
||||
}
|
||||
return data
|
||||
}
|
||||
},
|
||||
{"data": "queue"},
|
||||
{"data": "priority",
|
||||
"render": function (data, type, row, meta) {
|
||||
var priority = "success";
|
||||
if (data == 4 ) {
|
||||
priority = "warning";
|
||||
} else if (data == 5) {
|
||||
priority = "danger";
|
||||
}
|
||||
return '<p class="text-'+priority+'">'+data+'</p>';
|
||||
}
|
||||
},
|
||||
{"data": "queue",
|
||||
"render": function(data, type, row, meta) {
|
||||
return data.title;
|
||||
}
|
||||
},
|
||||
{"data": "status"},
|
||||
{"data": "created"},
|
||||
{"data": "due_date"},
|
||||
{"data": "assigned_to"},
|
||||
{"data": "assigned_to",
|
||||
"render": function(data, type, row, meta) {
|
||||
if (data != "None") {
|
||||
return data;
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
},
|
||||
{"data": "time_spent"},
|
||||
]
|
||||
});
|
||||
|
@ -5,7 +5,7 @@
|
||||
<tr class="{{ ticket.get_priority_css_class }}">
|
||||
<th><a href='{{ ticket.get_absolute_url }}'>{{ ticket.ticket }}</a></th>
|
||||
<td><input type='checkbox' name='ticket_id' value='{{ ticket.id }}' class='ticket_multi_select' /></td>
|
||||
<td>{{ ticket.priority }}</td>
|
||||
<td>{{ ticket.priority }}|||||</td>
|
||||
<th><a href='{{ ticket.get_absolute_url }}'>{{ ticket.title }}</a></th>
|
||||
<td>{{ ticket.queue }}</td>
|
||||
<td>{{ ticket.get_status }}</td>
|
||||
|
@ -53,7 +53,7 @@ class GetEmailCommonTests(TestCase):
|
||||
with open(os.path.join(THIS_DIR, "test_files/blank-body-with-attachment.eml")) as fd:
|
||||
test_email = fd.read()
|
||||
ticket = helpdesk.email.object_from_message(test_email, self.queue_public, self.logger)
|
||||
self.assertEqual(ticket.title, "FollowUpAttachment without body")
|
||||
self.assertEqual(ticket.title, "Attachment without body")
|
||||
self.assertEqual(ticket.description, "")
|
||||
|
||||
def test_email_with_quoted_printable_body(self):
|
||||
@ -71,7 +71,7 @@ class GetEmailCommonTests(TestCase):
|
||||
attachments = FollowUpAttachment.objects.filter(followup=followup)
|
||||
self.assertEqual(len(attachments), 1)
|
||||
attachment = attachments[0]
|
||||
self.assertEqual(attachment.file.read().decode("utf-8"), '<div dir="ltr">Tohle je test českých písmen odeslaných z gmailu.</div>\n')
|
||||
self.assertIn('<div dir="ltr">Tohle je test českých písmen odeslaných z gmailu.</div>\n', attachment.file.read().decode("utf-8"))
|
||||
|
||||
def test_email_with_8bit_encoding_and_utf_8(self):
|
||||
"""
|
||||
|
@ -138,13 +138,15 @@ def dashboard(request):
|
||||
showing ticket counts by queue/status, and a list of unassigned tickets
|
||||
with options for them to 'Take' ownership of said tickets.
|
||||
"""
|
||||
# open & reopened tickets, assigned to current user
|
||||
tickets = Ticket.objects.select_related('queue').filter(
|
||||
assigned_to=request.user,
|
||||
).exclude(
|
||||
active_tickets = Ticket.objects.select_related('queue').exclude(
|
||||
status__in=[Ticket.CLOSED_STATUS, Ticket.RESOLVED_STATUS],
|
||||
)
|
||||
|
||||
# open & reopened tickets, assigned to current user
|
||||
tickets = active_tickets.filter(
|
||||
assigned_to=request.user,
|
||||
)
|
||||
|
||||
# closed & resolved tickets, assigned to current user
|
||||
tickets_closed_resolved = Ticket.objects.select_related('queue').filter(
|
||||
assigned_to=request.user,
|
||||
@ -152,11 +154,9 @@ def dashboard(request):
|
||||
|
||||
user_queues = _get_user_queues(request.user)
|
||||
|
||||
unassigned_tickets = Ticket.objects.select_related('queue').filter(
|
||||
unassigned_tickets = active_tickets.filter(
|
||||
assigned_to__isnull=True,
|
||||
queue__in=user_queues
|
||||
).exclude(
|
||||
status=Ticket.CLOSED_STATUS,
|
||||
)
|
||||
|
||||
# all tickets, reported by current user
|
||||
@ -269,7 +269,7 @@ def followup_edit(request, ticket_id, followup_id):
|
||||
new_followup.user = followup.user
|
||||
new_followup.save()
|
||||
# get list of old attachments & link them to new_followup
|
||||
attachments = FolllowUpAttachment.objects.filter(followup=followup)
|
||||
attachments = FollowUpAttachment.objects.filter(followup=followup)
|
||||
for attachment in attachments:
|
||||
attachment.followup = new_followup
|
||||
attachment.save()
|
||||
@ -1581,7 +1581,7 @@ def attachment_del(request, ticket_id, attachment_id):
|
||||
if not _is_my_ticket(request.user, ticket):
|
||||
raise PermissionDenied()
|
||||
|
||||
attachment = get_object_or_404(FolllowUpAttachment, id=attachment_id)
|
||||
attachment = get_object_or_404(FollowUpAttachment, id=attachment_id)
|
||||
if request.method == 'POST':
|
||||
attachment.delete()
|
||||
return HttpResponseRedirect(reverse('helpdesk:view', args=[ticket_id]))
|
||||
|
19
quicktest.py
19
quicktest.py
@ -27,7 +27,8 @@ class QuickDjangoTest(object):
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.staticfiles',
|
||||
'bootstrap4form'
|
||||
'bootstrap4form',
|
||||
'helpdesk',
|
||||
)
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
@ -62,7 +63,7 @@ class QuickDjangoTest(object):
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.apps = args
|
||||
self.tests = args
|
||||
self._tests()
|
||||
|
||||
def _tests(self):
|
||||
@ -79,7 +80,7 @@ class QuickDjangoTest(object):
|
||||
'PORT': '',
|
||||
}
|
||||
},
|
||||
INSTALLED_APPS=self.INSTALLED_APPS + self.apps,
|
||||
INSTALLED_APPS=self.INSTALLED_APPS,
|
||||
MIDDLEWARE=self.MIDDLEWARE,
|
||||
ROOT_URLCONF='helpdesk.tests.urls',
|
||||
STATIC_URL='/static/',
|
||||
@ -92,7 +93,7 @@ class QuickDjangoTest(object):
|
||||
test_runner = DiscoverRunner(verbosity=1)
|
||||
django.setup()
|
||||
|
||||
failures = test_runner.run_tests(self.apps)
|
||||
failures = test_runner.run_tests(self.tests)
|
||||
if failures:
|
||||
sys.exit(failures)
|
||||
|
||||
@ -102,13 +103,15 @@ if __name__ == '__main__':
|
||||
|
||||
Example usage:
|
||||
|
||||
$ python quicktest.py app1 app2
|
||||
$ python quicktest.py test1 test2
|
||||
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
usage="[args]",
|
||||
description="Run Django tests on the provided applications."
|
||||
description="Run Django tests."
|
||||
)
|
||||
parser.add_argument('apps', nargs='+', type=str)
|
||||
parser.add_argument('tests', nargs="*", type=str)
|
||||
args = parser.parse_args()
|
||||
QuickDjangoTest(*args.apps)
|
||||
if not args.tests:
|
||||
args.tests = ['helpdesk']
|
||||
QuickDjangoTest(*args.tests)
|
||||
|
Loading…
Reference in New Issue
Block a user