mirror of
https://gitea.mueller.network/extern/django-helpdesk.git
synced 2024-11-25 01:13:31 +01:00
Redo KB categories as accordion view
This commit is contained in:
parent
c95b24780e
commit
7fe6444f8f
@ -18,7 +18,7 @@ from django.utils import timezone
|
||||
|
||||
from helpdesk.lib import safe_template_context, process_attachments
|
||||
from helpdesk.models import (Ticket, Queue, FollowUp, IgnoreEmail, TicketCC,
|
||||
CustomField, TicketCustomFieldValue, TicketDependency, UserSettings)
|
||||
CustomField, TicketCustomFieldValue, TicketDependency, UserSettings, KBItem)
|
||||
from helpdesk import settings as helpdesk_settings
|
||||
|
||||
User = get_user_model()
|
||||
@ -197,7 +197,10 @@ class AbstractTicketForm(CustomFieldMixin, forms.Form):
|
||||
return Queue.objects.get(id=int(self.cleaned_data['queue']))
|
||||
|
||||
def _create_ticket(self):
|
||||
queue = self._get_queue()
|
||||
queue = Queue.objects.get(id=int(self.cleaned_data['queue']))
|
||||
kbitem = None
|
||||
if 'kbitem' in self.cleaned_data:
|
||||
kbitem = KBItem.objects.get(id=int(self.cleaned_data['kbitem']))
|
||||
|
||||
ticket = Ticket(title=self.cleaned_data['title'],
|
||||
submitter_email=self.cleaned_data['submitter_email'],
|
||||
@ -207,6 +210,7 @@ class AbstractTicketForm(CustomFieldMixin, forms.Form):
|
||||
description=self.cleaned_data['body'],
|
||||
priority=self.cleaned_data['priority'],
|
||||
due_date=self.cleaned_data['due_date'],
|
||||
kbitem=kbitem,
|
||||
)
|
||||
|
||||
return ticket, queue
|
||||
@ -337,13 +341,22 @@ class PublicTicketForm(AbstractTicketForm):
|
||||
help_text=_('We will e-mail you when your ticket is updated.'),
|
||||
)
|
||||
|
||||
def __init__(self, hidden_fields=(), readonly_fields=(), *args, **kwargs):
|
||||
def __init__(self, hidden_fields=(), readonly_fields=(), kbcategory=None, *args, **kwargs):
|
||||
"""
|
||||
Add any (non-staff) custom fields that are defined to the form
|
||||
"""
|
||||
super(PublicTicketForm, self).__init__(*args, **kwargs)
|
||||
self._add_form_custom_fields(False)
|
||||
|
||||
if kbcategory:
|
||||
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)],
|
||||
)
|
||||
|
||||
|
||||
field_hide_table = {
|
||||
'queue': 'HELPDESK_PUBLIC_TICKET_QUEUE',
|
||||
'priority': 'HELPDESK_PUBLIC_TICKET_PRIORITY',
|
||||
|
@ -559,6 +559,14 @@ class Ticket(models.Model):
|
||||
default=mk_secret,
|
||||
)
|
||||
|
||||
kbitem = models.ForeignKey(
|
||||
"KBItem",
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name=_('Knowledge base item the user was viewing when they created this ticket.'),
|
||||
)
|
||||
|
||||
@property
|
||||
def time_spent(self):
|
||||
"""Return back total time spent on the ticket. This is calculated value
|
||||
@ -1310,7 +1318,7 @@ class KBItem(models.Model):
|
||||
|
||||
def get_absolute_url(self):
|
||||
from django.urls import reverse
|
||||
return reverse('helpdesk:kb_item', args=(self.id,))
|
||||
return str(reverse('helpdesk:kb_category', args=(self.category.slug,)))+"?kbitem="+str(self.pk)
|
||||
|
||||
def get_markdown(self):
|
||||
return get_markdown(self.answer)
|
||||
|
@ -19,29 +19,37 @@
|
||||
<p>{{ category.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="accordion">
|
||||
{% for item in items %}
|
||||
{% cycle 'one' 'two' 'three' as itemnumperrow silent %}
|
||||
{% ifequal itemnumperrow 'one' %}<div class="card-deck">{% endifequal %}
|
||||
<div class="card">
|
||||
<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">
|
||||
{% 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>
|
||||
<p>{% trans 'Last Update' %}: {{ item.last_updated|naturaltime }}</p>
|
||||
<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="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 class="card-body">
|
||||
<p class="card-text">{{ item.question }}</p>
|
||||
<p>{{ item.get_markdown }}</p>
|
||||
<div class="row">
|
||||
{% if request.user.pk %}
|
||||
<div>
|
||||
<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>
|
||||
</div>
|
||||
<div>
|
||||
<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>
|
||||
</div>
|
||||
{% blocktrans with recommendations=item.recommendations votes=item.votes %}{{ recommendations }} people found this answer useful of {{votes}}. {% endblocktrans %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% ifequal itemnumperrow 'three' %}</div>{% endifequal %}
|
||||
{% endfor %}
|
||||
{% ifnotequal itemnumperrow 'three' %}</div>{% endifnotequal %}
|
||||
</div>
|
||||
{% if category.queue %}
|
||||
<a href='{% url 'helpdesk:submit' %}?queue={{category.queue.pk}};_readonly_fields_=queue'><button type="button" class="btn btn-success btn-circle btn-xl float-right"><i class="fa fa-envelope fa-lg"></i> {% trans 'Get help with this topic' %}</button></a>
|
||||
{% endif %}
|
||||
|
@ -1,51 +0,0 @@
|
||||
{% extends "helpdesk/public_base.html" %}{% load i18n %}
|
||||
|
||||
{% block helpdesk_breadcrumb %}
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'helpdesk:kb_index' %}">{% trans "Knowledgebase" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{{ category.get_absolute_url }}">{% blocktrans with category.title as kbcat %}{{ kbcat }}{% endblocktrans %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active">Overview</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block helpdesk_body %}
|
||||
<h2>{% trans 'Knowledgebase' %}: {% blocktrans with item.title as item %}{{ item }}{% endblocktrans %}</h2>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-question-circle"></i>
|
||||
{{ item.question }}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>{{ item.get_markdown }}</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="row">
|
||||
<div class="col-lg-2">
|
||||
<p>{% trans "Did you find this article useful?" %}</p>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<a href='vote/?vote=up'><button type="button" class="btn btn-success btn-circle btn-xl"><i class="fa fa-thumbs-up fa-lg"></i></button></a>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<a href='vote/?vote=down'><button type="button" class="btn btn-danger btn-circle btn-xl"><i class="fa fa-thumbs-down fa-lg"></i></button></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-10">
|
||||
<p>{% trans "The results of voting by other readers of this article are below:" %}</p>
|
||||
<ul>
|
||||
<li>{% blocktrans with item.recommendations as recommendations %}Recommendations: {{ recommendations }}{% endblocktrans %}</li>
|
||||
<li>{% blocktrans with item.votes as votes %}Votes: {{ votes }}{% endblocktrans %}</li>
|
||||
<li>{% blocktrans with item.score as score %}Overall Rating: {{ score }}{% endblocktrans %}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>{% blocktrans with item.category.title as category_title and item.category.get_absolute_url as category_url %}View <a href='{{ category_url }}'>other <em>{{ category_title }}</em> articles</a>, or continue <a href='../'>viewing other knowledgebase articles</a>.{% endblocktrans %}</p>
|
||||
|
||||
{% endblock %}
|
@ -232,10 +232,6 @@ if helpdesk_settings.HELPDESK_KB_ENABLED:
|
||||
kb.index,
|
||||
name='kb_index'),
|
||||
|
||||
url(r'^kb/(?P<item>[0-9]+)/$',
|
||||
kb.item,
|
||||
name='kb_item'),
|
||||
|
||||
url(r'^kb/(?P<item>[0-9]+)/vote/$',
|
||||
kb.vote,
|
||||
name='kb_vote'),
|
||||
|
@ -27,18 +27,15 @@ def index(request):
|
||||
def category(request, slug):
|
||||
category = get_object_or_404(KBCategory, slug__iexact=slug)
|
||||
items = category.kbitem_set.all()
|
||||
selected_item = request.GET.get('kbitem', None)
|
||||
try:
|
||||
selected_item = int(selected_item)
|
||||
except ValueError:
|
||||
pass
|
||||
return render(request, 'helpdesk/kb_category.html', {
|
||||
'category': category,
|
||||
'items': items,
|
||||
'helpdesk_settings': helpdesk_settings,
|
||||
})
|
||||
|
||||
|
||||
def item(request, item):
|
||||
item = get_object_or_404(KBItem, pk=item)
|
||||
return render(request, 'helpdesk/kb_item.html', {
|
||||
'category': item.category,
|
||||
'item': item,
|
||||
'selected_item': selected_item,
|
||||
'helpdesk_settings': helpdesk_settings,
|
||||
})
|
||||
|
||||
|
@ -21,7 +21,7 @@ from helpdesk.decorators import protect_view, is_helpdesk_staff
|
||||
import helpdesk.views.staff as staff
|
||||
from helpdesk.forms import PublicTicketForm
|
||||
from helpdesk.lib import text_is_spam
|
||||
from helpdesk.models import CustomField, Ticket, Queue, UserSettings, KBCategory
|
||||
from helpdesk.models import CustomField, Ticket, Queue, UserSettings, KBCategory, KBItem
|
||||
|
||||
|
||||
def create_ticket(request, *args, **kwargs):
|
||||
@ -82,7 +82,7 @@ class BaseCreateTicketView(FormView):
|
||||
if request.user.is_authenticated and request.user.email:
|
||||
initial_data['submitter_email'] = request.user.email
|
||||
|
||||
query_param_fields = ['submitter_email', 'title', 'body', 'queue']
|
||||
query_param_fields = ['submitter_email', 'title', 'body', 'queue', 'kbitem']
|
||||
custom_fields = ["custom_%s" % f.name for f in CustomField.objects.filter(staff_only=False)]
|
||||
query_param_fields += custom_fields
|
||||
for qpf in query_param_fields:
|
||||
@ -93,6 +93,12 @@ class BaseCreateTicketView(FormView):
|
||||
kwargs = super().get_form_kwargs(*args, **kwargs)
|
||||
kwargs['hidden_fields'] = self.request.GET.get('_hide_fields_', '').split(',')
|
||||
kwargs['readonly_fields'] = self.request.GET.get('_readonly_fields_', '').split(',')
|
||||
kbitem = self.request.GET.get('kbitem', None)
|
||||
if kbitem:
|
||||
try:
|
||||
kwargs['kbcategory'] = KBItem.objects.get(pk=int(kbitem))
|
||||
except (ValueError, KBItem.DoesNotExist):
|
||||
pass
|
||||
return kwargs
|
||||
|
||||
def form_valid(self, form):
|
||||
|
Loading…
Reference in New Issue
Block a user