Skip to content

Commit

Permalink
Merge pull request #803 from auto-mat/teams
Browse files Browse the repository at this point in the history
Add Teams functionality, using pinax-teams
  • Loading branch information
gwasser committed Mar 4, 2020
2 parents 4236c64 + 4acbb32 commit 0e9358e
Show file tree
Hide file tree
Showing 36 changed files with 3,103 additions and 61 deletions.
2 changes: 2 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Contents
settings
spam
custom_fields
integration
teams
contributing
license

Expand Down
4 changes: 4 additions & 0 deletions docs/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ errors with trying to create User settings.
'django.contrib.admin', # Required for helpdesk admin/maintenance
'django.contrib.humanize', # Required for elapsed time formatting
'bootstrap4form', # Required for nicer formatting of forms with the default templates
'account', # Required by pinax-teams
'pinax.inviations', # required by pinax-teams
'pinax.teams', # team support
'helpdesk', # This is us!
'reversion', # required by pinax-teams
)

Your ``settings.py`` file should also define a ``SITE_ID`` that allows multiple projects to share
Expand Down
14 changes: 14 additions & 0 deletions docs/teams.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Working with teams and larger organizations
===========================================

If you only have one or two people working on tickets, basic Queue setup is enough to get you going. You can now assign tickets to teams for better ticket filtering, reducing noise and improving organization efficiency.

Rather than assigning tickets to teams directly, django-helpdesk allows you assign tickets to knowledge-base items and then assign knowledge base items to teams.

Knowledge-base items can be in either public or private knowledge-base categories, so this organizational structure need not have any influence on the external appearance of your public helpdesk web portal.

You can visit the 'Pinax Teams' page in your django admin in order to create a team and add team members.

You can assign a knowledge-base item to a team on the Helpdesk admin page.

Once you have set up teams. Unassigned tickets which are associated with a knowledge-base item will only be shown on the dashboard to those users who are members of the team which is associated with that knowledge-base item.
8 changes: 6 additions & 2 deletions helpdesk/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def ticket_get_ticket_for_url(self, obj):

@admin.register(KBItem)
class KBItemAdmin(admin.ModelAdmin):
list_display = ('category', 'title', 'last_updated',)
list_display = ('category', 'title', 'last_updated', 'team', 'order', 'enabled')
inlines = [KBIAttachmentInline]
readonly_fields = ('voted_by', 'downvoted_by')

Expand All @@ -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)
4 changes: 2 additions & 2 deletions helpdesk/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ def __init__(self, kbcategory=None, *args, **kwargs):
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):
Expand Down
20 changes: 20 additions & 0 deletions helpdesk/migrations/0028_kbitem_team.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 2.2.9 on 2020-01-27 15:01

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('pinax_teams', '0004_auto_20170511_0856'),
('helpdesk', '0027_auto_20200107_1221'),
]

operations = [
migrations.AddField(
model_name='kbitem',
name='team',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pinax_teams.Team', verbose_name='Team'),
),
]
18 changes: 18 additions & 0 deletions helpdesk/migrations/0029_kbcategory_public.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.9 on 2020-01-27 16:00

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('helpdesk', '0028_kbitem_team'),
]

operations = [
migrations.AddField(
model_name='kbcategory',
name='public',
field=models.BooleanField(default=True, verbose_name='Is KBCategory publicly visible?'),
),
]
33 changes: 33 additions & 0 deletions helpdesk/migrations/0030_add_kbcategory_name.py
Original file line number Diff line number Diff line change
@@ -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 changes: 22 additions & 0 deletions helpdesk/migrations/0031_auto_20200225_1440.py
Original file line number Diff line number Diff line change
@@ -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 changes: 18 additions & 0 deletions helpdesk/migrations/0032_kbitem_enabled.py
Original file line number Diff line number Diff line change
@@ -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'),
),
]
42 changes: 38 additions & 4 deletions helpdesk/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from markdown import markdown
from markdown.extensions import Extension

import pinax.teams.models


import uuid

Expand Down Expand Up @@ -1213,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,
)

Expand All @@ -1234,8 +1241,13 @@ class KBCategory(models.Model):
verbose_name=_('Default queue when creating a ticket after viewing this category.'),
)

public = models.BooleanField(
default=True,
verbose_name=_("Is KBCategory publicly visible?")
)

def __str__(self):
return '%s' % self.title
return '%s' % self.name

class Meta:
ordering = ('title',)
Expand Down Expand Up @@ -1297,6 +1309,25 @@ class KBItem(models.Model):
blank=True,
)

team = models.ForeignKey(
pinax.teams.models.Team,
on_delete=models.CASCADE,
verbose_name=_('Team'),
blank=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):
if not self.last_updated:
self.last_updated = timezone.now()
Expand All @@ -1310,10 +1341,10 @@ def _score(self):
score = property(_score)

def __str__(self):
return '%s' % self.title
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')

Expand All @@ -1328,6 +1359,9 @@ def query_url(self):
def num_open_tickets(self):
return Ticket.objects.filter(kbitem=self, status__in=(1, 2)).count()

def unassigned_tickets(self):
return Ticket.objects.filter(kbitem=self, status__in=(1, 2), assigned_to__isnull=True)

def get_markdown(self):
return get_markdown(self.answer)

Expand Down
36 changes: 19 additions & 17 deletions helpdesk/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,16 @@ def get_search_filter_args(search):

DATATABLES_ORDER_COLUMN_CHOICES = Choices(
('0', 'id'),
('1', 'title'),
('2', 'priority'),
('3', 'title'),
('4', 'queue'),
('5', 'status'),
('6', 'created'),
('7', 'due_date'),
('8', 'assigned_to')
('3', 'queue'),
('4', 'status'),
('5', 'created'),
('6', 'due_date'),
('7', 'assigned_to'),
('8', 'submitter_email'),
# ('9', 'time_spent'),
('10', 'kbitem'),
)


Expand Down Expand Up @@ -123,10 +126,9 @@ def __run__(self, queryset):
sorting: The name of the column to sort by
"""
for key in self.params.get('filtering', {}).keys():
filter = {key: self.params['filtering'][key]}
queryset = queryset.filter(**filter)
queryset = queryset.filter(self.get_search_filter_args())
filter = self.params.get('filtering', {})
filter_or = self.params.get('filtering_or', {})
queryset = queryset.filter((Q(**filter) | Q(**filter_or)) & self.get_search_filter_args())
sorting = self.params.get('sorting', None)
if sorting:
sortreverse = self.params.get('sortreverse', None)
Expand Down Expand Up @@ -162,12 +164,12 @@ def get_datatables_context(self, **kwargs):
"""
objects = self.get()
order_by = '-date_created'
draw = int(kwargs.get('draw', None)[0])
length = int(kwargs.get('length', None)[0])
start = int(kwargs.get('start', None)[0])
search_value = kwargs.get('search[value]', None)[0]
order_column = kwargs.get('order[0][column]', None)[0]
order = kwargs.get('order[0][dir]', None)[0]
draw = int(kwargs.get('draw', [0])[0])
length = int(kwargs.get('length', [25])[0])
start = int(kwargs.get('start', [0])[0])
search_value = kwargs.get('search[value]', [""])[0]
order_column = kwargs.get('order[0][column]', ['5'])[0]
order = kwargs.get('order[0][dir]', ["asc"])[0]

order_column = DATATABLES_ORDER_COLUMN_CHOICES[order_column]
# django orm '-' -> desc
Expand All @@ -177,7 +179,7 @@ def get_datatables_context(self, **kwargs):
queryset = objects.all().order_by(order_by)
total = queryset.count()

if search_value:
if search_value: # Dead code currently
queryset = queryset.filter(get_search_filter_args(search_value))

count = queryset.count()
Expand Down
6 changes: 5 additions & 1 deletion helpdesk/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ class DatatablesTicketSerializer(serializers.ModelSerializer):
row_class = serializers.SerializerMethodField()
time_spent = serializers.SerializerMethodField()
queue = serializers.SerializerMethodField()
kbitem = serializers.SerializerMethodField()

class Meta:
model = Ticket
# fields = '__all__'
fields = ('ticket', 'id', 'priority', 'title', 'queue', 'status',
'created', 'due_date', 'assigned_to', 'submitter', 'row_class',
'time_spent')
'time_spent', 'kbitem')

def get_queue(self, obj):
return ({"title": obj.queue.title, "id": obj.queue.id})
Expand Down Expand Up @@ -62,3 +63,6 @@ def get_time_spent(self, obj):

def get_row_class(self, obj):
return (obj.get_priority_css_class)

def get_kbitem(self, obj):
return obj.kbitem.title if obj.kbitem else ""
4 changes: 4 additions & 0 deletions helpdesk/static/helpdesk/css/sb-admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 0e9358e

Please sign in to comment.