Merge pull request #1 from auto-mat/kb_forms

Vylepšení znalostní báze pro DPNK 2020
This commit is contained in:
Timothy Hobbs 2020-02-27 11:19:11 +00:00 committed by GitHub
commit 4acbb32ef5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 136 additions and 19 deletions

View File

@ -70,7 +70,7 @@ class FollowUpAdmin(admin.ModelAdmin):
@admin.register(KBItem)
class KBItemAdmin(admin.ModelAdmin):
list_display = ('category', 'title', 'last_updated', 'team', )
list_display = ('category', 'title', 'last_updated', 'team', 'order', 'enabled')
inlines = [KBIAttachmentInline]
readonly_fields = ('voted_by', 'downvoted_by')
@ -93,6 +93,10 @@ class IgnoreEmailAdmin(admin.ModelAdmin):
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(EscalationExclusion)
admin.site.register(KBCategory)

View File

@ -183,8 +183,8 @@ class AbstractTicketForm(CustomFieldMixin, forms.Form):
self.fields['kbitem'] = forms.ChoiceField(
widget=forms.Select(attrs={'class': 'form-control'}),
required=False,
label=_('Knowedge Base Item'),
choices=[(kbi.pk, kbi.title) for kbi in KBItem.objects.filter(category=kbcategory.pk)],
label=_('Knowledge Base Item'),
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):

View 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'),
),
]

View 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'),
),
]

View 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'),
),
]

View File

@ -1215,8 +1215,13 @@ class KBCategory(models.Model):
listing of questions & answers.
"""
name = models.CharField(
_('Name of the category'),
max_length=100,
)
title = models.CharField(
_('Title'),
_('Title on knowledgebase page'),
max_length=100,
)
@ -1242,7 +1247,7 @@ class KBCategory(models.Model):
)
def __str__(self):
return '%s' % self.title
return '%s' % self.name
class Meta:
ordering = ('title',)
@ -1312,6 +1317,17 @@ class KBItem(models.Model):
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):
if not self.last_updated:
self.last_updated = timezone.now()
@ -1328,7 +1344,7 @@ class KBItem(models.Model):
return '%s: %s' % (self.category.title, self.title)
class Meta:
ordering = ('title',)
ordering = ('order', 'title',)
verbose_name = _('Knowledge base item')
verbose_name_plural = _('Knowledge base items')

View File

@ -242,6 +242,10 @@ body.fixed-nav.sidebar-toggled #content-wrapper {
overflow-y: auto;
}
.card-text {
font-weight: bold;
}
.card-body-icon {
position: absolute;
z-index: 0;

View File

@ -27,3 +27,6 @@
<!-- Custom Theme JavaScript -->
<script src="{% static 'helpdesk/js/sb-admin.js' %}"></script>
{% block js_bottom %}
{% endblock %}

View File

@ -1,35 +1,42 @@
{% load i18n %}
<h2>{% trans 'Knowledgebase Category' %}:{% blocktrans with category.title as kbcat %}{{ kbcat }}{% endblocktrans %}</h2>
<p>{{ category.description }}</p>
{% block header %}
<h2>{% blocktrans with category.title as kbcat %}{{ kbcat }}{% endblocktrans %}</h2>
{{ category.description|linebreaks }}
{% endblock %}
{% block item_list %}
<div id="accordion">
{% for item in items %}
<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}}">
<h5 class="mb-0">
{{ item.title }}
</h5>
</div>
</button>
<div id="collapse{{item.id}}" class="collapse {% if item.id == selected_item %}show{% endif %}" aria-labelledby="header{{item.id}}" data-parent="#accordion">
</div>
<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">
<p class="card-text">{{ item.question }}</p>
<p>{{ item.get_markdown }}</p>
<div class="card-answer">
{{ item.get_markdown }}
</div>
<div class="row">
{% if request.user.pk %}
<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=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=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'><div class="btn btn-danger btn-circle btn-xl"><i class="fa fa-thumbs-down fa-lg"></i></div></a>
</div>
{% endif %}
{% if staff %}
<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>
{% 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">
<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>
</div>
<div>
@ -39,12 +46,18 @@
</div>
</div>
{% endblock %}
</div>
</div>
{% endfor %}
</div>
{% endblock %}
{% block footer %}
{% endblock %}
{% 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}}'>
<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>
{% endif %}

View File

@ -1,5 +1,6 @@
{% load i18n %}
{% load saved_queries %}
<!DOCTYPE html>
<head>
{% include 'helpdesk/base-head.html' %}
{% block helpdesk_head %}{% endblock %}

View File

@ -3,7 +3,9 @@
{% with request|load_helpdesk_settings as helpdesk_settings %}
{% 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>
{% endblock %}
<form method='post' enctype='multipart/form-data'>
{{ form|bootstrap4form }}
<button type="submit" class="btn btn-primary btn-lg btn-block"><i class="fa fa-send"></i>&nbsp;{% trans "Submit Ticket" %}</button>

View File

@ -1,5 +1,6 @@
{% load i18n %}
{% load saved_queries %}
<!DOCTYPE html>
<head>
{% include 'helpdesk/base-head.html' %}
</head>

View File

@ -30,7 +30,7 @@ def category(request, slug, iframe=False):
category = get_object_or_404(KBCategory, slug__iexact=slug)
if not user.huser_from_request(request).can_access_kbcategory(category):
raise Http404
items = category.kbitem_set.all()
items = category.kbitem_set.filter(enabled=True)
selected_item = request.GET.get('kbitem', None)
try:
selected_item = int(selected_item)