forked from extern/django-helpdesk
Merge pull request #1 from auto-mat/kb_forms
Vylepšení znalostní báze pro DPNK 2020
This commit is contained in:
commit
4acbb32ef5
@ -70,7 +70,7 @@ class FollowUpAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
@admin.register(KBItem)
|
@admin.register(KBItem)
|
||||||
class KBItemAdmin(admin.ModelAdmin):
|
class KBItemAdmin(admin.ModelAdmin):
|
||||||
list_display = ('category', 'title', 'last_updated', 'team', )
|
list_display = ('category', 'title', 'last_updated', 'team', 'order', 'enabled')
|
||||||
inlines = [KBIAttachmentInline]
|
inlines = [KBIAttachmentInline]
|
||||||
readonly_fields = ('voted_by', 'downvoted_by')
|
readonly_fields = ('voted_by', 'downvoted_by')
|
||||||
|
|
||||||
@ -93,6 +93,10 @@ class IgnoreEmailAdmin(admin.ModelAdmin):
|
|||||||
list_display = ('name', 'queue_list', 'email_address', 'keep_in_mailbox')
|
list_display = ('name', 'queue_list', 'email_address', 'keep_in_mailbox')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(KBCategory)
|
||||||
|
class KBCategoryAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('name', 'title', 'slug', 'public')
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(PreSetReply)
|
admin.site.register(PreSetReply)
|
||||||
admin.site.register(EscalationExclusion)
|
admin.site.register(EscalationExclusion)
|
||||||
admin.site.register(KBCategory)
|
|
||||||
|
@ -183,8 +183,8 @@ class AbstractTicketForm(CustomFieldMixin, forms.Form):
|
|||||||
self.fields['kbitem'] = forms.ChoiceField(
|
self.fields['kbitem'] = forms.ChoiceField(
|
||||||
widget=forms.Select(attrs={'class': 'form-control'}),
|
widget=forms.Select(attrs={'class': 'form-control'}),
|
||||||
required=False,
|
required=False,
|
||||||
label=_('Knowedge Base Item'),
|
label=_('Knowledge Base Item'),
|
||||||
choices=[(kbi.pk, kbi.title) for kbi in KBItem.objects.filter(category=kbcategory.pk)],
|
choices=[(kbi.pk, kbi.title) for kbi in KBItem.objects.filter(category=kbcategory.pk, enabled=True)],
|
||||||
)
|
)
|
||||||
|
|
||||||
def _add_form_custom_fields(self, staff_only_filter=None):
|
def _add_form_custom_fields(self, staff_only_filter=None):
|
||||||
|
33
helpdesk/migrations/0030_add_kbcategory_name.py
Normal file
33
helpdesk/migrations/0030_add_kbcategory_name.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Generated by Django 2.2.10 on 2020-02-25 11:21
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
def copy_title(apps, schema_editor):
|
||||||
|
KBCategory = apps.get_model("helpdesk", "KBCategory")
|
||||||
|
KBCategory.objects.update(name=models.F('title'))
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('helpdesk', '0029_kbcategory_public'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='kbcategory',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Name of the category'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='kbcategory',
|
||||||
|
name='title',
|
||||||
|
field=models.CharField(max_length=100, verbose_name='Title on knowledgebase page'),
|
||||||
|
),
|
||||||
|
migrations.RunPython(copy_title, migrations.RunPython.noop),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='kbcategory',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(blank=False, max_length=100, null=False, verbose_name='Name of the category'),
|
||||||
|
),
|
||||||
|
]
|
22
helpdesk/migrations/0031_auto_20200225_1440.py
Normal file
22
helpdesk/migrations/0031_auto_20200225_1440.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 2.2.10 on 2020-02-25 13:40
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('helpdesk', '0030_add_kbcategory_name'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='kbitem',
|
||||||
|
options={'ordering': ('order', 'title'), 'verbose_name': 'Knowledge base item', 'verbose_name_plural': 'Knowledge base items'},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='kbitem',
|
||||||
|
name='order',
|
||||||
|
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Order'),
|
||||||
|
),
|
||||||
|
]
|
18
helpdesk/migrations/0032_kbitem_enabled.py
Normal file
18
helpdesk/migrations/0032_kbitem_enabled.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 2.2.10 on 2020-02-25 13:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('helpdesk', '0031_auto_20200225_1440'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='kbitem',
|
||||||
|
name='enabled',
|
||||||
|
field=models.BooleanField(default=True, verbose_name='Enabled to display to users'),
|
||||||
|
),
|
||||||
|
]
|
@ -1215,8 +1215,13 @@ class KBCategory(models.Model):
|
|||||||
listing of questions & answers.
|
listing of questions & answers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
name = models.CharField(
|
||||||
|
_('Name of the category'),
|
||||||
|
max_length=100,
|
||||||
|
)
|
||||||
|
|
||||||
title = models.CharField(
|
title = models.CharField(
|
||||||
_('Title'),
|
_('Title on knowledgebase page'),
|
||||||
max_length=100,
|
max_length=100,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1242,7 +1247,7 @@ class KBCategory(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '%s' % self.title
|
return '%s' % self.name
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('title',)
|
ordering = ('title',)
|
||||||
@ -1312,6 +1317,17 @@ class KBItem(models.Model):
|
|||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
order = models.PositiveIntegerField(
|
||||||
|
_('Order'),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
enabled = models.BooleanField(
|
||||||
|
_('Enabled to display to users'),
|
||||||
|
default=True,
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.last_updated:
|
if not self.last_updated:
|
||||||
self.last_updated = timezone.now()
|
self.last_updated = timezone.now()
|
||||||
@ -1328,7 +1344,7 @@ class KBItem(models.Model):
|
|||||||
return '%s: %s' % (self.category.title, self.title)
|
return '%s: %s' % (self.category.title, self.title)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('title',)
|
ordering = ('order', 'title',)
|
||||||
verbose_name = _('Knowledge base item')
|
verbose_name = _('Knowledge base item')
|
||||||
verbose_name_plural = _('Knowledge base items')
|
verbose_name_plural = _('Knowledge base items')
|
||||||
|
|
||||||
|
@ -242,6 +242,10 @@ body.fixed-nav.sidebar-toggled #content-wrapper {
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-text {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.card-body-icon {
|
.card-body-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
|
@ -27,3 +27,6 @@
|
|||||||
|
|
||||||
<!-- Custom Theme JavaScript -->
|
<!-- Custom Theme JavaScript -->
|
||||||
<script src="{% static 'helpdesk/js/sb-admin.js' %}"></script>
|
<script src="{% static 'helpdesk/js/sb-admin.js' %}"></script>
|
||||||
|
|
||||||
|
{% block js_bottom %}
|
||||||
|
{% endblock %}
|
||||||
|
@ -1,35 +1,42 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<h2>{% trans 'Knowledgebase Category' %}:{% blocktrans with category.title as kbcat %}{{ kbcat }}{% endblocktrans %}</h2>
|
{% block header %}
|
||||||
<p>{{ category.description }}</p>
|
<h2>{% blocktrans with category.title as kbcat %}{{ kbcat }}{% endblocktrans %}</h2>
|
||||||
|
{{ category.description|linebreaks }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block item_list %}
|
||||||
<div id="accordion">
|
<div id="accordion">
|
||||||
{% for item in items %}
|
{% for item in items %}
|
||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<button class="btn btn-link" data-toggle="collapse" data-target="#collapse{{item.id}}" aria-expanded="true" aria-controls="collapse{{item.id}}">
|
<div class="btn btn-link" data-toggle="collapse" data-target="#collapse{{item.id}}" role="region" aria-expanded="true" aria-controls="collapse{{item.id}}">
|
||||||
<div class="card-header" id="header{{item.id}}">
|
<div class="card-header" id="header{{item.id}}">
|
||||||
<h5 class="mb-0">
|
<h5 class="mb-0">
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</div>
|
||||||
<div id="collapse{{item.id}}" class="collapse {% if item.id == selected_item %}show{% endif %}" aria-labelledby="header{{item.id}}" data-parent="#accordion">
|
<div id="collapse{{item.id}}" class="collapse {% if item.id == selected_item %}show{% endif %}" role="region" aria-labelledby="header{{item.id}}" data-parent="#accordion">
|
||||||
|
{% block card_body %}
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p class="card-text">{{ item.question }}</p>
|
<p class="card-text">{{ item.question }}</p>
|
||||||
<p>{{ item.get_markdown }}</p>
|
<div class="card-answer">
|
||||||
|
{{ item.get_markdown }}
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% if request.user.pk %}
|
{% if request.user.pk %}
|
||||||
<div class="col-sm">
|
<div class="col-sm">
|
||||||
<a href='{% url "helpdesk:kb_vote" item.pk %}?vote=up'><button type="button" class="btn btn-success btn-circle btn-xl"><i class="fa fa-thumbs-up fa-lg"></i></button></a>
|
<a href='{% url "helpdesk:kb_vote" item.pk %}?vote=up'><div class="btn btn-success btn-circle btn-xl"><i class="fa fa-thumbs-up fa-lg"></i></div></a>
|
||||||
<a href='{% url "helpdesk:kb_vote" item.pk %}?vote=down'><button type="button" class="btn btn-danger btn-circle btn-xl"><i class="fa fa-thumbs-down fa-lg"></i></button></a>
|
<a href='{% url "helpdesk:kb_vote" item.pk %}?vote=down'><div class="btn btn-danger btn-circle btn-xl"><i class="fa fa-thumbs-down fa-lg"></i></div></a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if staff %}
|
{% if staff %}
|
||||||
<a href='{% url 'helpdesk:list' %}?kbitem={{item.id}}' class="col-sm">
|
<a href='{% url 'helpdesk:list' %}?kbitem={{item.id}}' class="col-sm">
|
||||||
<button type="button" class="btn btn-success btn-circle btn-xl float-right"><i class="fa fa-search fa-lg"></i> {{item.num_open_tickets}} {% trans 'open tickets' %}</button>
|
<div class="btn btn-success btn-circle btn-xl float-right"><i class="fa fa-search fa-lg"></i> {{item.num_open_tickets}} {% trans 'open tickets' %}</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href='{% if iframe %}{% url 'helpdesk:submit_iframe' %}{% else %}{% url 'helpdesk:submit' %}{%endif%}?{% if category.queue %}queue={{category.queue.pk}};_readonly_fields_=queue;{%endif%}kbitem={{item.id}};{{query_param_string}}' class="col-sm">
|
<a href='{% if iframe %}{% url 'helpdesk:submit_iframe' %}{% else %}{% url 'helpdesk:submit' %}{%endif%}?{% if category.queue %}queue={{category.queue.pk}};_readonly_fields_=queue;{%endif%}kbitem={{item.id}};{{query_param_string}}' class="col-sm">
|
||||||
<button type="button" class="btn btn-success btn-circle btn-xl float-right"><i class="fa fa-envelope fa-lg"></i> {% trans 'Contact a human' %}</button>
|
<div class="btn btn-success btn-circle btn-xl float-right"><i class="fa fa-envelope fa-lg"></i> {% trans 'Contact a human' %}</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -39,12 +46,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block footer %}
|
||||||
|
{% endblock %}
|
||||||
{% if category.queue %}
|
{% if category.queue %}
|
||||||
<a href='{% if iframe %}{% url 'helpdesk:submit_iframe' %}{% else %}{% url 'helpdesk:submit' %}{%endif%}?queue={{category.queue.pk}};_readonly_fields_=queue;{{query_param_string}}'>
|
<a href='{% if iframe %}{% url 'helpdesk:submit_iframe' %}{% else %}{% url 'helpdesk:submit' %}{%endif%}?queue={{category.queue.pk}};_readonly_fields_=queue;{{query_param_string}}'>
|
||||||
<button type="button" class="btn btn-danger btn-circle btn-xl float-right"><i class="fa fa-envelope fa-lg"></i> {% trans 'Contact a human' %}</button>
|
{% block submit_button %}
|
||||||
|
<div class="btn btn-danger btn-circle btn-xl float-right"><i class="fa fa-envelope fa-lg"></i> {% trans 'Contact a human' %}</div>
|
||||||
|
{% endblock %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load saved_queries %}
|
{% load saved_queries %}
|
||||||
|
<!DOCTYPE html>
|
||||||
<head>
|
<head>
|
||||||
{% include 'helpdesk/base-head.html' %}
|
{% include 'helpdesk/base-head.html' %}
|
||||||
{% block helpdesk_head %}{% endblock %}
|
{% block helpdesk_head %}{% endblock %}
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
{% with request|load_helpdesk_settings as helpdesk_settings %}
|
{% with request|load_helpdesk_settings as helpdesk_settings %}
|
||||||
|
|
||||||
{% if helpdesk_settings.HELPDESK_SUBMIT_A_TICKET_PUBLIC %}
|
{% if helpdesk_settings.HELPDESK_SUBMIT_A_TICKET_PUBLIC %}
|
||||||
|
{% block form_header %}
|
||||||
<p>{% trans "Unless otherwise stated, all fields are required." %} {% trans "Please provide as descriptive a title and description as possible." %}</p>
|
<p>{% trans "Unless otherwise stated, all fields are required." %} {% trans "Please provide as descriptive a title and description as possible." %}</p>
|
||||||
|
{% endblock %}
|
||||||
<form method='post' enctype='multipart/form-data'>
|
<form method='post' enctype='multipart/form-data'>
|
||||||
{{ form|bootstrap4form }}
|
{{ form|bootstrap4form }}
|
||||||
<button type="submit" class="btn btn-primary btn-lg btn-block"><i class="fa fa-send"></i> {% trans "Submit Ticket" %}</button>
|
<button type="submit" class="btn btn-primary btn-lg btn-block"><i class="fa fa-send"></i> {% trans "Submit Ticket" %}</button>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load saved_queries %}
|
{% load saved_queries %}
|
||||||
|
<!DOCTYPE html>
|
||||||
<head>
|
<head>
|
||||||
{% include 'helpdesk/base-head.html' %}
|
{% include 'helpdesk/base-head.html' %}
|
||||||
</head>
|
</head>
|
||||||
|
@ -30,7 +30,7 @@ def category(request, slug, iframe=False):
|
|||||||
category = get_object_or_404(KBCategory, slug__iexact=slug)
|
category = get_object_or_404(KBCategory, slug__iexact=slug)
|
||||||
if not user.huser_from_request(request).can_access_kbcategory(category):
|
if not user.huser_from_request(request).can_access_kbcategory(category):
|
||||||
raise Http404
|
raise Http404
|
||||||
items = category.kbitem_set.all()
|
items = category.kbitem_set.filter(enabled=True)
|
||||||
selected_item = request.GET.get('kbitem', None)
|
selected_item = request.GET.get('kbitem', None)
|
||||||
try:
|
try:
|
||||||
selected_item = int(selected_item)
|
selected_item = int(selected_item)
|
||||||
|
Loading…
Reference in New Issue
Block a user