Merge pull request #1140 from django-helpdesk/fix_unassigned_kbitems_not_visible_when_teams_not_active

Simplify teams enable/disable and fix unassigned kbitems not visible when teams not active
This commit is contained in:
Christopher Broderick 2023-11-16 12:45:04 +00:00 committed by GitHub
commit 761b91d2fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 67 deletions

View File

@ -1,14 +1,8 @@
""" """
Django settings for django-helpdesk demodesk project. Django settings for django-helpdesk demodesk project.
For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
""" """
import os import os
@ -39,9 +33,10 @@ ALLOWED_HOSTS = []
# an internal demo you don't need such security, but please # an internal demo you don't need such security, but please
# remember when setting up your own development / production server! # remember when setting up your own development / production server!
# Default teams mode to enabled unless overridden by an environment variable set to "false"
HELPDESK_TEAMS_MODE_ENABLED=os.getenv("HELPDESK_TEAMS_MODE_ENABLED", "true").lower() == "true"
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
@ -52,13 +47,16 @@ INSTALLED_APPS = [
'django.contrib.sites', 'django.contrib.sites',
'django.contrib.humanize', 'django.contrib.humanize',
'bootstrap4form', 'bootstrap4form',
'account', # Required by pinax-teams
'pinax.invitations', # required by pinax-teams
'pinax.teams', # team support
'reversion', # required by pinax-teams
'helpdesk', # This is us! 'helpdesk', # This is us!
'rest_framework', # required for the API 'rest_framework', # required for the API
] ]
if HELPDESK_TEAMS_MODE_ENABLED:
INSTALLED_APPS.extend([
'account', # Required by pinax-teams
'pinax.invitations', # required by pinax-teams
'pinax.teams', # team support
'reversion', # required by pinax-teams
])
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',

View File

@ -1,3 +1,4 @@
.. _installation:
Installation Installation
============ ============
@ -18,7 +19,7 @@ Before getting started, ensure your system meets the following recommended depen
Ensure any extra Django modules you wish to use are compatible before continuing. Ensure any extra Django modules you wish to use are compatible before continuing.
**NOTE**: Python 2.7 support was deprecated in ``django-helpdesk`` as of version 0.2.x **NOTE**: Python 2 support was deprecated in ``django-helpdesk`` as of version 0.2.x
and completely removed in version 0.3.0. Users that still need Python 2 support should and completely removed in version 0.3.0. Users that still need Python 2 support should
remain on version 0.2.x. remain on version 0.2.x.
@ -31,12 +32,12 @@ Installing using PIP
Try using ``pip install django-helpdesk``. Go and have a beer to celebrate Python packaging. Try using ``pip install django-helpdesk``. Go and have a beer to celebrate Python packaging.
Checkout ``stable`` from git (Cutting Edge) Checkout ``main`` branch from git (Cutting Edge)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you're planning on editing the code or just want to get whatever is the latest and greatest, you can clone the official Git repository with ``git clone git://github.com/django-helpdesk/django-helpdesk.git``. We use the ``stable`` branch as our development branch for the next major release of ``django-helpdesk``. If you're planning on editing the code or just want to get whatever is the latest and greatest, you can clone the official Git repository with ``git clone git://github.com/django-helpdesk/django-helpdesk.git``. Each official release of ``django-helpdesk`` is tagged.
Copy the ``helpdesk`` folder into your ``PYTHONPATH``. Copy the ``helpdesk`` folder into your ``PYTHONPATH`` or add it to your ``PYTHONPATH``.
I just want a .tar.gz! I just want a .tar.gz!
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
@ -52,30 +53,36 @@ If you're on a brand new Django installation, make sure you do a ``migrate``
**before** adding ``helpdesk`` to your ``INSTALLED_APPS``. This will avoid **before** adding ``helpdesk`` to your ``INSTALLED_APPS``. This will avoid
errors with trying to create User settings. errors with trying to create User settings.
1. Edit your ``settings.py`` file and add ``helpdesk`` to the ``INSTALLED_APPS`` setting. You also need ``django.contrib.admin`` in ``INSTALLED_APPS`` if you haven't already added it. eg:: 1. Edit your ``settings.py`` file add the following entries:
- add ``helpdesk`` to the ``INSTALLED_APPS`` along with some other required entries in the ``django.contrib`` package.
INSTALLED_APPS = ( An example of the core ``INSTALLED_APPS`` requirements for this app are shown below::
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites', # Required for determining domain url for use in emails
'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.invitations', # Required by pinax-teams
'pinax.teams', # Team support
'reversion', # Required by pinax-teams
'rest_framework', # required for the API
'django_cleanup.apps.CleanupConfig', # Remove this if you do NOT want to delete files on the file system when the associated record is deleted in the database
'helpdesk', # This is us!
)
Note: you do not need to use pinax-teams. To disable teams see the :doc:`teams` section. INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites', # Required for determining domain url for use in emails
'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
'rest_framework', # required for the API
'django_cleanup.apps.CleanupConfig', # Remove this if you do NOT want to delete files on the file system when the associated record is deleted in the database
'helpdesk', # This is us!
)
Your ``settings.py`` file should also define a ``SITE_ID`` that allows multiple projects to share - Enable or disable Teams based ticket assignment by setting the boolean flag named ``HELPDESK_TEAMS_MODE_ENABLED`` to True or False.
a single database, and is required by ``django.contrib.sites`` in Django 1.9+.
If you aren't running multiple sites, you can simply add a default ``SITE_ID`` to ``settings.py``:: IMPORTANT NOTE: It is ENABLED by default if you do not set this flag to False
See the :doc::ref:`teams`. section for a detailed explanation of how to use teams mode.
Below is an example for disabling teams::
HELPDESK_TEAMS_MODE_ENABLED=False
- Your ``settings.py`` file should also define a ``SITE_ID``
This will allow multiple projects to share a single database, and is required by ``django.contrib.sites`` in Django 1.9+.
If you aren't running multiple sites, you can simply add a default ``SITE_ID`` to ``settings.py``
Below is an example for setting a default::
SITE_ID = 1 SITE_ID = 1

View File

@ -1,3 +1,4 @@
.. _teams:
Working with teams and larger organizations Working with teams and larger organizations
=========================================== ===========================================
@ -20,7 +21,6 @@ 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. 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.
Implementing Custom Teams Functionality Implementing Custom Teams Functionality
-------------------------------- --------------------------------
If you want to use a different team app or implement your own team based app, you can hook it into Helpdesk using the following 3 settings: If you want to use a different team app or implement your own team based app, you can hook it into Helpdesk using the following 3 settings:
@ -29,10 +29,23 @@ If you want to use a different team app or implement your own team based app, yo
``HELPDESK_KBITEM_TEAM_GETTER``: the method that will be called that must return a list of users who belong to a given team ``HELPDESK_KBITEM_TEAM_GETTER``: the method that will be called that must return a list of users who belong to a given team
Configuring Teams Functionality
-----------------------------
Teams functionality is enabled by default but can be disabled using this entry in your ``settings.py``::
HELPDESK_TEAMS_MODE_ENABLED=False
If you do not disable teams functionality then you must add additional apps into the ``INSTALLED_APPS`` in your ``settings.py``.
The following can be pasted into your settings.py BELOW the ``INSTALLED_APPS`` definition::
INSTALLED_APPS.extend([
'account', # Required by pinax-teams
'pinax.invitations', # required by pinax-teams
'pinax.teams', # team support
'reversion', # required by pinax-teams
])
Alternatively just add the 4 apps listed above into the ``INSTALLED_APPS``.
Disabling Teams Functionality Disabling Teams Functionality
----------------------------- -----------------------------
If you do not wish to use team functionality, you can disable teams by setting the following settings: Teams functionality is enabled by default but can be disabled using this entry in your ``settings.py``::
HELPDESK_TEAMS_MODE_ENABLED=False
HELPDESK_TEAMS_MODEL='auth.User',
HELPDESK_TEAMS_MIGRATION_DEPENDENCIES=[],
HELPDESK_KBITEM_TEAM_GETTER=lambda _: None,

View File

@ -60,9 +60,6 @@ HELPDESK_ANON_ACCESS_RAISES_404 = getattr(settings,
'HELPDESK_ANON_ACCESS_RAISES_404', 'HELPDESK_ANON_ACCESS_RAISES_404',
False) False)
# show knowledgebase links?
HELPDESK_KB_ENABLED = getattr(settings, 'HELPDESK_KB_ENABLED', True)
# Disable Timeline on ticket list # Disable Timeline on ticket list
HELPDESK_TICKETS_TIMELINE_ENABLED = getattr( HELPDESK_TICKETS_TIMELINE_ENABLED = getattr(
settings, 'HELPDESK_TICKETS_TIMELINE_ENABLED', True) settings, 'HELPDESK_TICKETS_TIMELINE_ENABLED', True)
@ -231,12 +228,23 @@ HELPDESK_ENABLE_PER_QUEUE_STAFF_PERMISSION = getattr(
HELPDESK_USE_HTTPS_IN_EMAIL_LINK = getattr( HELPDESK_USE_HTTPS_IN_EMAIL_LINK = getattr(
settings, 'HELPDESK_USE_HTTPS_IN_EMAIL_LINK', settings.SECURE_SSL_REDIRECT) settings, 'HELPDESK_USE_HTTPS_IN_EMAIL_LINK', settings.SECURE_SSL_REDIRECT)
HELPDESK_TEAMS_MODEL = getattr( # Default to True for backwards compatibility
settings, 'HELPDESK_TEAMS_MODEL', 'pinax_teams.Team') HELPDESK_TEAMS_MODE_ENABLED = getattr(settings, 'HELPDESK_TEAMS_MODE_ENABLED', True)
HELPDESK_TEAMS_MIGRATION_DEPENDENCIES = getattr(settings, 'HELPDESK_TEAMS_MIGRATION_DEPENDENCIES', [ if HELPDESK_TEAMS_MODE_ENABLED:
HELPDESK_TEAMS_MODEL = getattr(
settings, 'HELPDESK_TEAMS_MODEL', 'pinax_teams.Team')
HELPDESK_TEAMS_MIGRATION_DEPENDENCIES = getattr(settings, 'HELPDESK_TEAMS_MIGRATION_DEPENDENCIES', [
('pinax_teams', '0004_auto_20170511_0856')]) ('pinax_teams', '0004_auto_20170511_0856')])
HELPDESK_KBITEM_TEAM_GETTER = getattr( HELPDESK_KBITEM_TEAM_GETTER = getattr(
settings, 'HELPDESK_KBITEM_TEAM_GETTER', lambda kbitem: kbitem.team) settings, 'HELPDESK_KBITEM_TEAM_GETTER', lambda kbitem: kbitem.team)
else:
HELPDESK_TEAMS_MODEL = settings.AUTH_USER_MODEL
HELPDESK_TEAMS_MIGRATION_DEPENDENCIES = []
HELPDESK_KBITEM_TEAM_GETTER = lambda _: None
# show knowledgebase links?
# If Teams mode is enabled then it has to be on
HELPDESK_KB_ENABLED = True if HELPDESK_TEAMS_MODE_ENABLED else getattr(settings, 'HELPDESK_KB_ENABLED', True)
# Include all signatures and forwards in the first ticket message if set # Include all signatures and forwards in the first ticket message if set
# Useful if you get forwards dropped from them while they are useful part # Useful if you get forwards dropped from them while they are useful part

View File

@ -341,27 +341,48 @@ class GetEmailCommonTests(TestCase):
self.assertTrue(inline_found, "Inline file not found in email: %s" % (inline_att_filename)) self.assertTrue(inline_found, "Inline file not found in email: %s" % (inline_att_filename))
def test_email_with_txt_as_attachment(self): def test_email_with_txt_as_attachment_with_simple_alternative_message(self):
""" """
Test an email with an txt extension email attachment to the email Test an email with a txt extension email attachment to the email where the message part of the
email is in a multipart/alternative directly off the main multipart/mixed (no multipart/related)
""" """
email_message, _, _ = utils.generate_multipart_email(type_list=['plain']) email_att_filename = 'the_quick_brown_fox.txt'
email_att_filename = 'test.txt' # Create the actual email with its plain and HTML parts
file_part = utils.generate_file_mime_part("en_US", email_att_filename, "Testing a simple txt attachment.") alt_email_message = MIMEMultipart("alternative")
email_message.attach(file_part) # Create the plain and HTML that will reference the inline attachment
plain_body = "Is wet birds attached?\n\n"
plain_msg = MIMEText(plain_body)
alt_email_message.attach(plain_msg)
html_body = '<div><div>Is wet birds attached?</div><br></div>'
html_msg = MIMEText(html_body, "html")
alt_email_message.attach(html_msg)
# Now create the base multipart and attach all the other parts to it
base_message = MIMEMultipart("mixed")
base_message.attach(alt_email_message)
email_attachment = MIMEText("Wet birds don't fly at night.")
email_attachment.add_header('Content-Disposition', 'attachment', filename=email_att_filename)
base_message.attach(email_attachment)
utils.add_simple_email_headers(base_message, locale="en_US", use_short_email=True)
# Now send the part to the email workflow # Now send the part to the email workflow
extract_email_metadata(email_message.as_string(), self.queue_public, self.logger) extract_email_metadata(base_message.as_string(), self.queue_public, self.logger)
self.assertEqual(len(mail.outbox), 1) # @UndefinedVariable self.assertEqual(len(mail.outbox), 1) # @UndefinedVariable
#self.assertEqual(f'[test-1] {base_message.get("subject")} (Opened)', mail.outbox[0].subject)
ticket = Ticket.objects.get() ticket = Ticket.objects.get()
followup = ticket.followup_set.get() followup = ticket.followup_set.get()
attachments = FollowUpAttachment.objects.filter(followup=followup) # Check attachment is stored as attached file
self.assertEqual(len(attachments), 1) email_attachment_found = False
attachment = attachments[0] for att_retrieved in followup.followupattachment_set.all():
self.assertTrue(attachment.filename.endswith(email_att_filename), "The txt file not found in email: %s" % (email_att_filename)) if (helpdesk.email.HTML_EMAIL_ATTACHMENT_FILENAME == att_retrieved.filename):
# Ignore the HTML formatted content of the email that is attached
continue
if att_retrieved.filename.endswith(email_att_filename):
email_attachment_found = True
else:
self.assertTrue(False, "Unexpected file in ticket attachments: %s" % att_retrieved.filename)
self.assertTrue(email_attachment_found, "Email attachment file not found ticket attachments: %s" % (email_att_filename))
class EmailTaskTests(TestCase): class EmailTaskTests(TestCase):
def setUp(self): def setUp(self):

View File

@ -151,17 +151,20 @@ def dashboard(request):
# closed & resolved tickets, assigned to current user # closed & resolved tickets, assigned to current user
tickets_closed_resolved = Ticket.objects.select_related('queue').filter( tickets_closed_resolved = Ticket.objects.select_related('queue').filter(
assigned_to=request.user, assigned_to=request.user,
status__in=[Ticket.CLOSED_STATUS, Ticket.RESOLVED_STATUS]) status__in=[Ticket.CLOSED_STATUS, Ticket.RESOLVED_STATUS]
)
user_queues = huser.get_queues() user_queues = huser.get_queues()
unassigned_tickets = active_tickets.filter( unassigned_tickets = active_tickets.filter(
assigned_to__isnull=True, assigned_to__isnull=True,
kbitem__isnull=True,
queue__in=user_queues queue__in=user_queues
) )
kbitems = None
kbitems = huser.get_assigned_kb_items() # Teams mode uses assignment via knowledge base items so exclude tickets assigned to KB items
if helpdesk_settings.HELPDESK_TEAMS_MODE_ENABLED:
unassigned_tickets = unassigned_tickets.filter(kbitem__isnull=True)
kbitems = huser.get_assigned_kb_items()
# all tickets, reported by current user # all tickets, reported by current user
all_tickets_reported_by_current_user = '' all_tickets_reported_by_current_user = ''