diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index f604ea30..83ba7e3b 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -31,6 +31,9 @@ jobs: flake8 helpdesk --count --show-source --statistics --exit-zero # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide # flake8 . --count --exit-zero --max-complexity=10 --statistics + - name: Sort style check with 'isort' + run: | + isort --line-length=120 --src helpdesk . --check - name: Test with pytest run: | pip install pytest diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 00000000..d854b4fc --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,19 @@ +[settings] +src_paths=helpdesk +skip_glob=migrations/* +skip=migrations +multi_line_output=3 +line_length=120 +use_parentheses=true +sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER +lines_after_imports=2 +lines_before_imports=1 +balanced_wrapping=true +lines_between_types=1 +combine_as_imports=true +force_alphabetical_sort=true +skip_gitignore=true +force_sort_within_sections=true +group_by_package=false +from_first=true + diff --git a/demo/demodesk/config/settings.py b/demo/demodesk/config/settings.py index 5aaccfbf..55ab94f2 100644 --- a/demo/demodesk/config/settings.py +++ b/demo/demodesk/config/settings.py @@ -8,8 +8,10 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.11/ref/settings/ """ + import os + # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/demo/demodesk/config/urls.py b/demo/demodesk/config/urls.py index 22d4f803..2fb2a3d7 100644 --- a/demo/demodesk/config/urls.py +++ b/demo/demodesk/config/urls.py @@ -13,10 +13,10 @@ Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ -from django.urls import include, path -from django.contrib import admin from django.conf import settings from django.conf.urls.static import static +from django.contrib import admin +from django.urls import include, path # The following uses the static() helper function, diff --git a/demo/demodesk/config/wsgi.py b/demo/demodesk/config/wsgi.py index f8e39f59..3fb82a46 100644 --- a/demo/demodesk/config/wsgi.py +++ b/demo/demodesk/config/wsgi.py @@ -7,9 +7,10 @@ For more information on this file, see https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/ """ -import os from django.core.wsgi import get_wsgi_application +import os + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demodesk.config.settings") diff --git a/demo/setup.py b/demo/setup.py index 310cdae1..b866210c 100644 --- a/demo/setup.py +++ b/demo/setup.py @@ -1,10 +1,20 @@ # -*- coding: utf-8 -*- """Python packaging.""" + + + + + + + + + from __future__ import unicode_literals -from setuptools import setup import os +from setuptools import setup + here = os.path.abspath(os.path.dirname(__file__)) project_root = os.path.dirname(here) diff --git a/docs/conf.py b/docs/conf.py index 6e384cb3..f79715bb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,8 +11,9 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys import os +import sys + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the diff --git a/helpdesk/admin.py b/helpdesk/admin.py index 8beb35f1..d51cf209 100644 --- a/helpdesk/admin.py +++ b/helpdesk/admin.py @@ -1,13 +1,24 @@ + from django.contrib import admin from django.utils.translation import gettext_lazy as _ -from helpdesk.models import Queue, Ticket, FollowUp, PreSetReply -from helpdesk.models import EscalationExclusion, EmailTemplate -from helpdesk.models import TicketChange, KBIAttachment, FollowUpAttachment, IgnoreEmail -from helpdesk.models import CustomField from helpdesk import settings as helpdesk_settings +from helpdesk.models import ( + CustomField, + EmailTemplate, + EscalationExclusion, + FollowUp, + FollowUpAttachment, + IgnoreEmail, + KBIAttachment, + PreSetReply, + Queue, + Ticket, + TicketChange +) + + if helpdesk_settings.HELPDESK_KB_ENABLED: - from helpdesk.models import KBCategory - from helpdesk.models import KBItem + from helpdesk.models import KBCategory, KBItem @admin.register(Queue) diff --git a/helpdesk/decorators.py b/helpdesk/decorators.py index 1dedbc02..e003440a 100644 --- a/helpdesk/decorators.py +++ b/helpdesk/decorators.py @@ -1,12 +1,8 @@ -from functools import wraps - +from django.contrib.auth.decorators import user_passes_test from django.core.exceptions import PermissionDenied from django.http import Http404 from django.shortcuts import redirect - -from django.contrib.auth.decorators import user_passes_test - - +from functools import wraps from helpdesk import settings as helpdesk_settings diff --git a/helpdesk/email.py b/helpdesk/email.py index 6fe347ac..8f92b521 100644 --- a/helpdesk/email.py +++ b/helpdesk/email.py @@ -4,23 +4,11 @@ Django Helpdesk - A Django powered ticket tracker for small enterprise. (c) Copyright 2008 Jutda. Copyright 2018 Timothy Hobbs. All Rights Reserved. See LICENSE for details. """ + # import base64 -import email -import imaplib -import logging -import mimetypes -import os -import poplib -import re -import socket -import ssl -import sys -from datetime import timedelta -from email.utils import getaddresses -from os.path import isfile, join -from time import ctime from bs4 import BeautifulSoup +from datetime import timedelta from django.conf import settings as django_settings from django.contrib.auth import get_user_model from django.core.exceptions import ValidationError @@ -28,11 +16,23 @@ from django.core.files.uploadedfile import SimpleUploadedFile from django.db.models import Q from django.utils import encoding, timezone from django.utils.translation import gettext as _ +import email +from email.utils import getaddresses from email_reply_parser import EmailReplyParser - from helpdesk import settings -from helpdesk.lib import safe_template_context, process_attachments -from helpdesk.models import Queue, Ticket, TicketCC, FollowUp, IgnoreEmail +from helpdesk.lib import process_attachments, safe_template_context +from helpdesk.models import FollowUp, IgnoreEmail, Queue, Ticket, TicketCC +import imaplib +import logging +import mimetypes +import os +from os.path import isfile, join +import poplib +import re +import socket +import ssl +import sys +from time import ctime # import User model, which may be a custom model @@ -342,7 +342,7 @@ def create_ticket_cc(ticket, cc_list): return [] # Local import to deal with non-defined / circular reference problem - from helpdesk.views.staff import User, subscribe_to_ticket_updates + from helpdesk.views.staff import subscribe_to_ticket_updates, User new_ticket_ccs = [] for cced_name, cced_email in cc_list: diff --git a/helpdesk/forms.py b/helpdesk/forms.py index 0db3016c..11ec89ed 100644 --- a/helpdesk/forms.py +++ b/helpdesk/forms.py @@ -6,25 +6,38 @@ django-helpdesk - A Django powered ticket tracker for small enterprise. forms.py - Definitions of newforms-based forms for creating and maintaining tickets. """ -import logging -from datetime import datetime -from django.core.exceptions import ObjectDoesNotExist, ValidationError +from datetime import datetime from django import forms from django.conf import settings -from django.utils.translation import gettext_lazy as _ from django.contrib.auth import get_user_model +from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.utils import timezone - -from helpdesk.lib import safe_template_context, process_attachments, convert_value -from helpdesk.models import (Ticket, Queue, FollowUp, IgnoreEmail, TicketCC, - CustomField, TicketCustomFieldValue, TicketDependency, UserSettings) +from django.utils.translation import gettext_lazy as _ from helpdesk import settings as helpdesk_settings -from helpdesk.settings import CUSTOMFIELD_TO_FIELD_DICT, CUSTOMFIELD_DATETIME_FORMAT, \ - CUSTOMFIELD_DATE_FORMAT, CUSTOMFIELD_TIME_FORMAT +from helpdesk.lib import convert_value, process_attachments, safe_template_context +from helpdesk.models import ( + CustomField, + FollowUp, + IgnoreEmail, + Queue, + Ticket, + TicketCC, + TicketCustomFieldValue, + TicketDependency, + UserSettings +) +from helpdesk.settings import ( + CUSTOMFIELD_DATE_FORMAT, + CUSTOMFIELD_DATETIME_FORMAT, + CUSTOMFIELD_TIME_FORMAT, + CUSTOMFIELD_TO_FIELD_DICT +) +import logging + if helpdesk_settings.HELPDESK_KB_ENABLED: - from helpdesk.models import (KBItem) + from helpdesk.models import KBItem logger = logging.getLogger(__name__) User = get_user_model() diff --git a/helpdesk/lib.py b/helpdesk/lib.py index 911c7a96..028d6353 100644 --- a/helpdesk/lib.py +++ b/helpdesk/lib.py @@ -6,14 +6,14 @@ django-helpdesk - A Django powered ticket tracker for small enterprise. lib.py - Common functions (eg multipart e-mail) """ -import logging -import mimetypes -from datetime import datetime, date, time +from datetime import date, datetime, time from django.conf import settings from django.utils.encoding import smart_str +from helpdesk.settings import CUSTOMFIELD_DATE_FORMAT, CUSTOMFIELD_DATETIME_FORMAT, CUSTOMFIELD_TIME_FORMAT +import logging +import mimetypes -from helpdesk.settings import CUSTOMFIELD_DATETIME_FORMAT, CUSTOMFIELD_DATE_FORMAT, CUSTOMFIELD_TIME_FORMAT logger = logging.getLogger('helpdesk') diff --git a/helpdesk/management/commands/create_escalation_exclusions.py b/helpdesk/management/commands/create_escalation_exclusions.py index 9e2148d5..6d3e249f 100644 --- a/helpdesk/management/commands/create_escalation_exclusions.py +++ b/helpdesk/management/commands/create_escalation_exclusions.py @@ -8,12 +8,11 @@ scripts/create_escalation_exclusion.py - Easy way to routinely add particular days to the list of days on which no escalation should take place. """ + +from datetime import date, timedelta from django.core.management.base import BaseCommand, CommandError - -from helpdesk.models import EscalationExclusion, Queue - -from datetime import timedelta, date import getopt +from helpdesk.models import EscalationExclusion, Queue from optparse import make_option import sys diff --git a/helpdesk/management/commands/create_queue_permissions.py b/helpdesk/management/commands/create_queue_permissions.py index 91f064dc..1da97851 100644 --- a/helpdesk/management/commands/create_queue_permissions.py +++ b/helpdesk/management/commands/create_queue_permissions.py @@ -13,15 +13,13 @@ scripts/create_queue_permissions.py - existing permissions. """ -from optparse import make_option - from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType from django.core.management.base import BaseCommand, CommandError from django.db.utils import IntegrityError from django.utils.translation import gettext_lazy as _ - from helpdesk.models import Queue +from optparse import make_option class Command(BaseCommand): diff --git a/helpdesk/management/commands/create_usersettings.py b/helpdesk/management/commands/create_usersettings.py index 2ed628a1..7f5203cf 100644 --- a/helpdesk/management/commands/create_usersettings.py +++ b/helpdesk/management/commands/create_usersettings.py @@ -8,12 +8,12 @@ create_usersettings.py - Easy way to create helpdesk-specific settings for users who don't yet have them. """ -from django.utils.translation import gettext as _ -from django.core.management.base import BaseCommand from django.contrib.auth import get_user_model - +from django.core.management.base import BaseCommand +from django.utils.translation import gettext as _ from helpdesk.models import UserSettings + User = get_user_model() diff --git a/helpdesk/management/commands/escalate_tickets.py b/helpdesk/management/commands/escalate_tickets.py index 020a3b78..d0a920a8 100644 --- a/helpdesk/management/commands/escalate_tickets.py +++ b/helpdesk/management/commands/escalate_tickets.py @@ -8,18 +8,17 @@ scripts/escalate_tickets.py - Easy way to escalate tickets based on their age, designed to be run from Cron or similar. """ -from datetime import timedelta, date -import getopt -from optparse import make_option -import sys +from datetime import date, timedelta from django.core.management.base import BaseCommand, CommandError from django.db.models import Q -from django.utils.translation import gettext as _ from django.utils import timezone - -from helpdesk.models import Queue, Ticket, FollowUp, EscalationExclusion, TicketChange +from django.utils.translation import gettext as _ +import getopt from helpdesk.lib import safe_template_context +from helpdesk.models import EscalationExclusion, FollowUp, Queue, Ticket, TicketChange +from optparse import make_option +import sys class Command(BaseCommand): diff --git a/helpdesk/management/commands/get_email.py b/helpdesk/management/commands/get_email.py index ce344bd5..0111b93b 100755 --- a/helpdesk/management/commands/get_email.py +++ b/helpdesk/management/commands/get_email.py @@ -11,7 +11,6 @@ scripts/get_email.py - Designed to be run from cron, this script checks the adding to existing tickets if needed) """ from django.core.management.base import BaseCommand - from helpdesk.email import process_email diff --git a/helpdesk/models.py b/helpdesk/models.py index 0f5db4cf..291e7323 100644 --- a/helpdesk/models.py +++ b/helpdesk/models.py @@ -7,35 +7,29 @@ models.py - Model (and hence database) definitions. This is the core of the helpdesk structure. """ -from django.contrib.auth.models import Permission + +from .lib import convert_value +from .templated_email import send_templated_mail +from .validators import validate_file_extension +import datetime +from django.conf import settings from django.contrib.auth import get_user_model +from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.db import models -from django.conf import settings from django.utils import timezone -from django.utils.translation import gettext_lazy as _, gettext -from io import StringIO -import re -import os -import mimetypes -import datetime - from django.utils.safestring import mark_safe +from django.utils.translation import gettext, gettext_lazy as _ +from helpdesk import settings as helpdesk_settings +from io import StringIO from markdown import markdown from markdown.extensions import Extension - - -import uuid - +import mimetypes +import os +import re from rest_framework import serializers - -from helpdesk import settings as helpdesk_settings -from .lib import convert_value - -from .validators import validate_file_extension - -from .templated_email import send_templated_mail +import uuid def format_time_spent(time_spent): diff --git a/helpdesk/query.py b/helpdesk/query.py index 14da72a8..9ebef3e9 100644 --- a/helpdesk/query.py +++ b/helpdesk/query.py @@ -1,15 +1,12 @@ + +from base64 import b64decode, b64encode from django.db.models import Q from django.urls import reverse from django.utils.html import escape from django.utils.translation import gettext as _ - -from base64 import b64encode -from base64 import b64decode -import json - -from model_utils import Choices - from helpdesk.serializers import DatatablesTicketSerializer +import json +from model_utils import Choices def query_to_base64(query): diff --git a/helpdesk/serializers.py b/helpdesk/serializers.py index c4134fa2..6474060d 100644 --- a/helpdesk/serializers.py +++ b/helpdesk/serializers.py @@ -1,13 +1,12 @@ -from rest_framework import serializers +from .forms import TicketForm +from .lib import format_time_spent, process_attachments +from .models import CustomField, FollowUp, FollowUpAttachment, Ticket +from .user import HelpdeskUser from django.contrib.auth.models import User from django.contrib.humanize.templatetags import humanize +from rest_framework import serializers from rest_framework.exceptions import ValidationError -from .forms import TicketForm -from .models import Ticket, CustomField, FollowUp, FollowUpAttachment -from .lib import format_time_spent, process_attachments -from .user import HelpdeskUser - class DatatablesTicketSerializer(serializers.ModelSerializer): """ diff --git a/helpdesk/settings.py b/helpdesk/settings.py index 2724c01b..4594a510 100644 --- a/helpdesk/settings.py +++ b/helpdesk/settings.py @@ -2,12 +2,13 @@ Default settings for django-helpdesk. """ -import os -import warnings from django import forms from django.conf import settings from django.core.exceptions import ImproperlyConfigured +import os +import warnings + DEFAULT_USER_SETTINGS = { 'login_view_ticketlist': True, diff --git a/helpdesk/tasks.py b/helpdesk/tasks.py index 2fdee3e4..d7ce1d68 100644 --- a/helpdesk/tasks.py +++ b/helpdesk/tasks.py @@ -1,6 +1,5 @@ -from celery import shared_task - from .email import process_email +from celery import shared_task @shared_task diff --git a/helpdesk/templated_email.py b/helpdesk/templated_email.py index 2fc83973..5c98cdc7 100644 --- a/helpdesk/templated_email.py +++ b/helpdesk/templated_email.py @@ -1,9 +1,10 @@ -import os -import logging -from smtplib import SMTPException from django.conf import settings from django.utils.safestring import mark_safe +import logging +import os +from smtplib import SMTPException + logger = logging.getLogger('helpdesk') @@ -50,8 +51,7 @@ def send_templated_mail(template_name, from_string = engines['django'].from_string from helpdesk.models import EmailTemplate - from helpdesk.settings import HELPDESK_EMAIL_SUBJECT_TEMPLATE, \ - HELPDESK_EMAIL_FALLBACK_LOCALE + from helpdesk.settings import HELPDESK_EMAIL_FALLBACK_LOCALE, HELPDESK_EMAIL_SUBJECT_TEMPLATE headers = extra_headers or {} diff --git a/helpdesk/templatetags/helpdesk_staff.py b/helpdesk/templatetags/helpdesk_staff.py index ab1ea3cf..621398cc 100644 --- a/helpdesk/templatetags/helpdesk_staff.py +++ b/helpdesk/templatetags/helpdesk_staff.py @@ -4,10 +4,10 @@ django-helpdesk - A Django powered ticket tracker for small enterprise. The is_helpdesk_staff template filter returns True if the user qualifies as Helpdesk staff. templatetags/helpdesk_staff.py """ -import logging -from django.template import Library +from django.template import Library from helpdesk.decorators import is_helpdesk_staff +import logging logger = logging.getLogger(__name__) diff --git a/helpdesk/templatetags/helpdesk_util.py b/helpdesk/templatetags/helpdesk_util.py index b096824c..2498e2e5 100644 --- a/helpdesk/templatetags/helpdesk_util.py +++ b/helpdesk/templatetags/helpdesk_util.py @@ -1,10 +1,9 @@ +from datetime import datetime +from django.conf import settings from django.template import Library from django.template.defaultfilters import date as date_filter -from django.conf import settings +from helpdesk.forms import CUSTOMFIELD_DATE_FORMAT, CUSTOMFIELD_DATETIME_FORMAT, CUSTOMFIELD_TIME_FORMAT -from datetime import datetime - -from helpdesk.forms import CUSTOMFIELD_DATE_FORMAT, CUSTOMFIELD_TIME_FORMAT, CUSTOMFIELD_DATETIME_FORMAT register = Library() diff --git a/helpdesk/templatetags/saved_queries.py b/helpdesk/templatetags/saved_queries.py index 533e13a6..5956fc86 100644 --- a/helpdesk/templatetags/saved_queries.py +++ b/helpdesk/templatetags/saved_queries.py @@ -7,7 +7,6 @@ templatetags/saved_queries.py - This template tag returns previously saved """ from django import template from django.db.models import Q - from helpdesk.models import SavedSearch diff --git a/helpdesk/templatetags/ticket_to_link.py b/helpdesk/templatetags/ticket_to_link.py index 39683bfb..9111ff11 100644 --- a/helpdesk/templatetags/ticket_to_link.py +++ b/helpdesk/templatetags/ticket_to_link.py @@ -10,12 +10,11 @@ templatetags/ticket_to_link.py - Used in ticket comments to allow wiki-style to show the status of that ticket (eg a closed ticket would have a strikethrough). """ + from django import template from django.urls import reverse from django.utils.safestring import mark_safe - from helpdesk.models import Ticket - import re diff --git a/helpdesk/tests/helpers.py b/helpdesk/tests/helpers.py index 57775c76..fe4d65de 100644 --- a/helpdesk/tests/helpers.py +++ b/helpdesk/tests/helpers.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- -import sys -from django.contrib.auth import get_user_model -from helpdesk.models import Ticket, Queue, UserSettings +from django.contrib.auth import get_user_model +from helpdesk.models import Queue, Ticket, UserSettings +import sys + User = get_user_model() diff --git a/helpdesk/tests/test_api.py b/helpdesk/tests/test_api.py index 45c4bcfe..75bf895e 100644 --- a/helpdesk/tests/test_api.py +++ b/helpdesk/tests/test_api.py @@ -1,18 +1,22 @@ + import base64 from collections import OrderedDict from datetime import datetime - +from django.contrib.auth.models import User from django.core.files.uploadedfile import SimpleUploadedFile from freezegun import freeze_time - -from django.contrib.auth.models import User +from helpdesk.models import CustomField, Queue, Ticket from rest_framework import HTTP_HEADER_ENCODING from rest_framework.exceptions import ErrorDetail -from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_204_NO_CONTENT, HTTP_400_BAD_REQUEST, HTTP_403_FORBIDDEN +from rest_framework.status import ( + HTTP_200_OK, + HTTP_201_CREATED, + HTTP_204_NO_CONTENT, + HTTP_400_BAD_REQUEST, + HTTP_403_FORBIDDEN +) from rest_framework.test import APITestCase -from helpdesk.models import Queue, Ticket, CustomField - class TicketTest(APITestCase): due_date = datetime(2022, 4, 10, 15, 6) diff --git a/helpdesk/tests/test_attachments.py b/helpdesk/tests/test_attachments.py index 46e7151d..b8f16b28 100644 --- a/helpdesk/tests/test_attachments.py +++ b/helpdesk/tests/test_attachments.py @@ -1,15 +1,13 @@ # vim: set fileencoding=utf-8 : + from django.core.files.uploadedfile import SimpleUploadedFile -from django.urls import reverse from django.test import override_settings, TestCase +from django.urls import reverse from django.utils.encoding import smart_str - from helpdesk import lib, models - import os import shutil from tempfile import gettempdir - from unittest import mock from unittest.case import skip diff --git a/helpdesk/tests/test_get_email.py b/helpdesk/tests/test_get_email.py index f1cf010e..89afa95d 100644 --- a/helpdesk/tests/test_get_email.py +++ b/helpdesk/tests/test_get_email.py @@ -1,24 +1,23 @@ # -*- coding: utf-8 -*- -from django.test import TestCase, override_settings + +from django.contrib.auth.hashers import make_password +from django.contrib.auth.models import User from django.core.management import call_command from django.shortcuts import get_object_or_404 -from django.contrib.auth.models import User -from django.contrib.auth.hashers import make_password - -from helpdesk.models import Queue, Ticket, TicketCC, FollowUp, FollowUpAttachment -from helpdesk.management.commands.get_email import Command +from django.test import override_settings, TestCase import helpdesk.email - -import six +from helpdesk.management.commands.get_email import Command +from helpdesk.models import FollowUp, FollowUpAttachment, Queue, Ticket, TicketCC import itertools -from shutil import rmtree -import sys -import os -from tempfile import mkdtemp import logging - +import os +from shutil import rmtree +import six +import sys +from tempfile import mkdtemp from unittest import mock + THIS_DIR = os.path.dirname(os.path.abspath(__file__)) # class A addresses can't have first octet of 0 diff --git a/helpdesk/tests/test_kb.py b/helpdesk/tests/test_kb.py index ed1ab7ba..511aae67 100644 --- a/helpdesk/tests/test_kb.py +++ b/helpdesk/tests/test_kb.py @@ -1,11 +1,8 @@ # -*- coding: utf-8 -*- -from django.urls import reverse from django.test import TestCase - +from django.urls import reverse from helpdesk.models import KBCategory, KBItem, Queue, Ticket - -from helpdesk.tests.helpers import ( - get_staff_user, reload_urlconf, User, create_ticket, print_response) +from helpdesk.tests.helpers import create_ticket, get_staff_user, print_response, reload_urlconf, User class KBTests(TestCase): diff --git a/helpdesk/tests/test_login.py b/helpdesk/tests/test_login.py index 800ae71d..ad0ebddc 100644 --- a/helpdesk/tests/test_login.py +++ b/helpdesk/tests/test_login.py @@ -1,4 +1,4 @@ -from django.test import TestCase, override_settings +from django.test import override_settings, TestCase from django.urls import reverse diff --git a/helpdesk/tests/test_navigation.py b/helpdesk/tests/test_navigation.py index 21e51ab9..fef74fce 100644 --- a/helpdesk/tests/test_navigation.py +++ b/helpdesk/tests/test_navigation.py @@ -1,14 +1,14 @@ # -*- coding: utf-8 -*- -import sys -from importlib import reload -from django.urls import reverse -from django.test import TestCase + +from django.test import TestCase +from django.test.utils import override_settings +from django.urls import reverse from helpdesk import settings as helpdesk_settings from helpdesk.models import Queue -from helpdesk.tests.helpers import ( - get_staff_user, reload_urlconf, User, create_ticket, print_response) -from django.test.utils import override_settings +from helpdesk.tests.helpers import create_ticket, get_staff_user, print_response, reload_urlconf, User +from importlib import reload +import sys class KBDisabledTestCase(TestCase): diff --git a/helpdesk/tests/test_per_queue_staff_permission.py b/helpdesk/tests/test_per_queue_staff_permission.py index c16dd7a2..b04f53bc 100644 --- a/helpdesk/tests/test_per_queue_staff_permission.py +++ b/helpdesk/tests/test_per_queue_staff_permission.py @@ -1,11 +1,10 @@ from django.contrib.auth import get_user_model from django.contrib.auth.models import Permission -from django.urls import reverse from django.test import TestCase from django.test.client import Client - -from helpdesk.models import Queue, Ticket +from django.urls import reverse from helpdesk import settings +from helpdesk.models import Queue, Ticket from helpdesk.query import __Query__ from helpdesk.user import HelpdeskUser diff --git a/helpdesk/tests/test_public_actions.py b/helpdesk/tests/test_public_actions.py index feba1a66..f07c2fdf 100644 --- a/helpdesk/tests/test_public_actions.py +++ b/helpdesk/tests/test_public_actions.py @@ -1,7 +1,7 @@ -from helpdesk.models import Queue, Ticket from django.test import TestCase from django.test.client import Client from django.urls import reverse +from helpdesk.models import Queue, Ticket class PublicActionsTestCase(TestCase): diff --git a/helpdesk/tests/test_query.py b/helpdesk/tests/test_query.py index 43ede439..9e7d8842 100644 --- a/helpdesk/tests/test_query.py +++ b/helpdesk/tests/test_query.py @@ -1,12 +1,9 @@ from django.contrib.auth import get_user_model from django.test import TestCase from django.urls import reverse - from helpdesk.models import KBCategory, KBItem, Queue, Ticket from helpdesk.query import query_to_base64 - -from helpdesk.tests.helpers import ( - get_staff_user, reload_urlconf, User, create_ticket, print_response) +from helpdesk.tests.helpers import create_ticket, get_staff_user, print_response, reload_urlconf, User class QueryTests(TestCase): diff --git a/helpdesk/tests/test_savequery.py b/helpdesk/tests/test_savequery.py index 5916782b..b7130d25 100644 --- a/helpdesk/tests/test_savequery.py +++ b/helpdesk/tests/test_savequery.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -from django.urls import reverse from django.test import TestCase +from django.urls import reverse from helpdesk.models import Queue from helpdesk.tests.helpers import get_user diff --git a/helpdesk/tests/test_ticket_actions.py b/helpdesk/tests/test_ticket_actions.py index b0b9daec..1836f429 100644 --- a/helpdesk/tests/test_ticket_actions.py +++ b/helpdesk/tests/test_ticket_actions.py @@ -1,21 +1,21 @@ from django.contrib.auth import get_user_model from django.contrib.sites.models import Site from django.core import mail -from django.urls import reverse from django.test import TestCase from django.test.client import Client +from django.urls import reverse from django.utils import timezone - -from helpdesk.models import CustomField, Queue, Ticket from helpdesk import settings as helpdesk_settings +from helpdesk.models import CustomField, Queue, Ticket +from helpdesk.templatetags.ticket_to_link import num_to_link +from helpdesk.user import HelpdeskUser + try: # python 3 from urllib.parse import urlparse except ImportError: # python 2 from urlparse import urlparse -from helpdesk.templatetags.ticket_to_link import num_to_link -from helpdesk.user import HelpdeskUser class TicketActionsTestCase(TestCase): diff --git a/helpdesk/tests/test_ticket_lookup.py b/helpdesk/tests/test_ticket_lookup.py index e2891f95..8b3fcaba 100644 --- a/helpdesk/tests/test_ticket_lookup.py +++ b/helpdesk/tests/test_ticket_lookup.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- from django.contrib.auth import get_user_model -from django.urls import reverse from django.test import TestCase -from helpdesk.models import Ticket, Queue from django.test.utils import override_settings +from django.urls import reverse +from helpdesk.models import Queue, Ticket User = get_user_model() diff --git a/helpdesk/tests/test_ticket_submission.py b/helpdesk/tests/test_ticket_submission.py index 90923967..2e1da9ac 100644 --- a/helpdesk/tests/test_ticket_submission.py +++ b/helpdesk/tests/test_ticket_submission.py @@ -1,22 +1,19 @@ -import email -import uuid -from helpdesk.models import Queue, CustomField, FollowUp, Ticket, TicketCC, KBCategory, KBItem -from django.test import TestCase from django.contrib.auth import get_user_model from django.core import mail from django.core.exceptions import ObjectDoesNotExist from django.forms import ValidationError +from django.test import TestCase from django.test.client import Client from django.urls import reverse - -from helpdesk.email import object_from_message, create_ticket_cc +import email +from helpdesk.email import create_ticket_cc, object_from_message +from helpdesk.models import CustomField, FollowUp, KBCategory, KBItem, Queue, Ticket, TicketCC from helpdesk.tests.helpers import print_response - -from urllib.parse import urlparse - import logging +from urllib.parse import urlparse +import uuid logger = logging.getLogger('helpdesk') diff --git a/helpdesk/tests/test_time_spent.py b/helpdesk/tests/test_time_spent.py index 5caf7df5..ad1749c4 100644 --- a/helpdesk/tests/test_time_spent.py +++ b/helpdesk/tests/test_time_spent.py @@ -1,22 +1,24 @@ + +import datetime from django.contrib.auth import get_user_model +from django.contrib.auth.hashers import make_password +from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.core import mail -from django.urls import reverse from django.test import TestCase from django.test.client import Client -from helpdesk.models import Queue, Ticket, FollowUp +from django.urls import reverse from helpdesk import settings as helpdesk_settings -from django.contrib.auth.models import User -from django.contrib.auth.hashers import make_password +from helpdesk.models import FollowUp, Queue, Ticket +from helpdesk.templatetags.ticket_to_link import num_to_link import uuid -import datetime + try: # python 3 from urllib.parse import urlparse except ImportError: # python 2 from urlparse import urlparse -from helpdesk.templatetags.ticket_to_link import num_to_link class TimeSpentTestCase(TestCase): diff --git a/helpdesk/tests/test_usersettings.py b/helpdesk/tests/test_usersettings.py index 293adbf6..b7d72866 100644 --- a/helpdesk/tests/test_usersettings.py +++ b/helpdesk/tests/test_usersettings.py @@ -1,10 +1,11 @@ from django.contrib.auth import get_user_model from django.core import mail -from django.urls import reverse from django.test import TestCase from django.test.client import Client +from django.urls import reverse from helpdesk.models import CustomField, Queue, Ticket + try: # python 3 from urllib.parse import urlparse except ImportError: # python 2 diff --git a/helpdesk/tests/urls.py b/helpdesk/tests/urls.py index 9a96671c..e07fd6c8 100644 --- a/helpdesk/tests/urls.py +++ b/helpdesk/tests/urls.py @@ -1,5 +1,6 @@ -from django.urls import include, path from django.contrib import admin +from django.urls import include, path + urlpatterns = [ path('', include('helpdesk.urls', namespace='helpdesk')), diff --git a/helpdesk/urls.py b/helpdesk/urls.py index 9ccd4d38..f0fcceab 100644 --- a/helpdesk/urls.py +++ b/helpdesk/urls.py @@ -7,17 +7,16 @@ urls.py - Mapping of URL's to our various views. Note we always used NAMED views for simplicity in linking later on. """ -from django.urls import path, re_path -from django.contrib.auth.decorators import login_required from django.contrib.auth import views as auth_views -from django.urls import include +from django.contrib.auth.decorators import login_required +from django.urls import include, path, re_path from django.views.generic import TemplateView +from helpdesk import settings as helpdesk_settings +from helpdesk.decorators import helpdesk_staff_member_required, protect_view +from helpdesk.views import feeds, login, public, staff +from helpdesk.views.api import CreateUserView, FollowUpAttachmentViewSet, FollowUpViewSet, TicketViewSet from rest_framework.routers import DefaultRouter -from helpdesk.decorators import helpdesk_staff_member_required, protect_view -from helpdesk.views import feeds, staff, public, login -from helpdesk import settings as helpdesk_settings -from helpdesk.views.api import TicketViewSet, CreateUserView, FollowUpViewSet, FollowUpAttachmentViewSet if helpdesk_settings.HELPDESK_KB_ENABLED: from helpdesk.views import kb diff --git a/helpdesk/user.py b/helpdesk/user.py index eb11d5d0..e21fd064 100644 --- a/helpdesk/user.py +++ b/helpdesk/user.py @@ -1,15 +1,10 @@ -from helpdesk.models import ( - Ticket, - Queue -) from helpdesk import settings as helpdesk_settings +from helpdesk.models import Queue, Ticket + if helpdesk_settings.HELPDESK_KB_ENABLED: - from helpdesk.models import ( - KBCategory, - KBItem - ) + from helpdesk.models import KBCategory, KBItem def huser_from_request(req): diff --git a/helpdesk/validators.py b/helpdesk/validators.py index bd2cd522..08086e1f 100644 --- a/helpdesk/validators.py +++ b/helpdesk/validators.py @@ -2,16 +2,18 @@ # # validators for file uploads, etc. + from django.conf import settings + # TODO: can we use the builtin Django validator instead? # see: # https://docs.djangoproject.com/en/4.0/ref/validators/#fileextensionvalidator def validate_file_extension(value): - import os from django.core.exceptions import ValidationError + import os ext = os.path.splitext(value.name)[1] # [0] returns path+filename # TODO: we might improve this with more thorough checks of file types # rather than just the extensions. diff --git a/helpdesk/views/api.py b/helpdesk/views/api.py index d217a1a4..7e3f0448 100644 --- a/helpdesk/views/api.py +++ b/helpdesk/views/api.py @@ -1,11 +1,10 @@ +from django.contrib.auth import get_user_model +from helpdesk.models import FollowUp, FollowUpAttachment, Ticket +from helpdesk.serializers import FollowUpAttachmentSerializer, FollowUpSerializer, TicketSerializer, UserSerializer from rest_framework import viewsets +from rest_framework.mixins import CreateModelMixin from rest_framework.permissions import IsAdminUser from rest_framework.viewsets import GenericViewSet -from rest_framework.mixins import CreateModelMixin -from django.contrib.auth import get_user_model - -from helpdesk.models import Ticket, FollowUp, FollowUpAttachment -from helpdesk.serializers import TicketSerializer, UserSerializer, FollowUpSerializer, FollowUpAttachmentSerializer class TicketViewSet(viewsets.ModelViewSet): diff --git a/helpdesk/views/feeds.py b/helpdesk/views/feeds.py index 7975fa4e..cccf4b19 100644 --- a/helpdesk/views/feeds.py +++ b/helpdesk/views/feeds.py @@ -9,12 +9,12 @@ views/feeds.py - A handful of staff-only RSS feeds to provide ticket details from django.contrib.auth import get_user_model from django.contrib.syndication.views import Feed -from django.urls import reverse from django.db.models import Q -from django.utils.translation import gettext as _ from django.shortcuts import get_object_or_404 +from django.urls import reverse +from django.utils.translation import gettext as _ +from helpdesk.models import FollowUp, Queue, Ticket -from helpdesk.models import Ticket, FollowUp, Queue User = get_user_model() diff --git a/helpdesk/views/kb.py b/helpdesk/views/kb.py index 55b3424d..1f619a65 100644 --- a/helpdesk/views/kb.py +++ b/helpdesk/views/kb.py @@ -8,12 +8,10 @@ views/kb.py - Public-facing knowledgebase views. The knowledgebase is a resolutions to common problems. """ -from django.http import HttpResponseRedirect, Http404 -from django.shortcuts import render, get_object_or_404 +from django.http import Http404, HttpResponseRedirect +from django.shortcuts import get_object_or_404, render from django.views.decorators.clickjacking import xframe_options_exempt - -from helpdesk import settings as helpdesk_settings -from helpdesk import user +from helpdesk import settings as helpdesk_settings, user from helpdesk.models import KBCategory, KBItem diff --git a/helpdesk/views/permissions.py b/helpdesk/views/permissions.py index 955e71c9..3ebd556c 100644 --- a/helpdesk/views/permissions.py +++ b/helpdesk/views/permissions.py @@ -1,5 +1,4 @@ from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin - from helpdesk.decorators import is_helpdesk_staff diff --git a/helpdesk/views/public.py b/helpdesk/views/public.py index 7a0b28bf..dfe42e53 100644 --- a/helpdesk/views/public.py +++ b/helpdesk/views/public.py @@ -6,30 +6,29 @@ django-helpdesk - A Django powered ticket tracker for small enterprise. views/public.py - All public facing views, eg non-staff (no authentication required) views. """ -import logging -from importlib import import_module -from django.core.exceptions import ( - ObjectDoesNotExist, PermissionDenied, ImproperlyConfigured, -) -from django.urls import reverse + +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist, PermissionDenied from django.http import HttpResponseRedirect from django.shortcuts import render -from urllib.parse import quote +from django.urls import reverse from django.utils.translation import gettext as _ -from django.conf import settings from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.csrf import csrf_exempt from django.views.generic.base import TemplateView from django.views.generic.edit import FormView - from helpdesk import settings as helpdesk_settings -from helpdesk.decorators import protect_view, is_helpdesk_staff -import helpdesk.views.staff as staff -import helpdesk.views.abstract_views as abstract_views +from helpdesk.decorators import is_helpdesk_staff, protect_view from helpdesk.lib import text_is_spam -from helpdesk.models import Ticket, Queue, UserSettings +from helpdesk.models import Queue, Ticket, UserSettings from helpdesk.user import huser_from_request +import helpdesk.views.abstract_views as abstract_views +import helpdesk.views.staff as staff +from importlib import import_module +import logging +from urllib.parse import quote + logger = logging.getLogger(__name__) @@ -212,6 +211,7 @@ def view_ticket(request): if 'close' in request.GET and ticket.status == Ticket.RESOLVED_STATUS: from helpdesk.views.staff import update_ticket + # Trick the update_ticket() view into thinking it's being called with # a valid POST. request.POST = { diff --git a/helpdesk/views/staff.py b/helpdesk/views/staff.py index 94117637..38ba3743 100644 --- a/helpdesk/views/staff.py +++ b/helpdesk/views/staff.py @@ -6,67 +6,78 @@ django-helpdesk - A Django powered ticket tracker for small enterprise. views/staff.py - The bulk of the application - provides most business logic and renders all staff-facing views. """ -from copy import deepcopy -import json +from ..lib import format_time_spent +from ..templated_email import send_templated_mail +from copy import deepcopy +from datetime import date, datetime, timedelta from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.auth.decorators import user_passes_test from django.contrib.contenttypes.models import ContentType -from django.urls import reverse, reverse_lazy -from django.core.exceptions import ValidationError, PermissionDenied -from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger +from django.core.exceptions import PermissionDenied, ValidationError +from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator from django.db.models import Q -from django.http import HttpResponseRedirect, Http404, HttpResponse, JsonResponse -from django.shortcuts import render, get_object_or_404, redirect -from django.utils.translation import gettext as _ -from django.utils.html import escape +from django.http import Http404, HttpResponse, HttpResponseRedirect, JsonResponse +from django.shortcuts import get_object_or_404, redirect, render +from django.urls import reverse, reverse_lazy from django.utils import timezone +from django.utils.html import escape +from django.utils.translation import gettext as _ from django.views.decorators.csrf import requires_csrf_token from django.views.generic.edit import FormView, UpdateView - -from helpdesk.forms import CUSTOMFIELD_DATE_FORMAT -from helpdesk.query import ( - get_query_class, - query_to_base64, - query_from_base64, -) - -from helpdesk.user import HelpdeskUser - +from helpdesk import settings as helpdesk_settings from helpdesk.decorators import ( - helpdesk_staff_member_required, helpdesk_superuser_required, - is_helpdesk_staff + helpdesk_staff_member_required, + helpdesk_superuser_required, + is_helpdesk_staff, + superuser_required ) from helpdesk.forms import ( - TicketForm, UserSettingsForm, EmailIgnoreForm, EditTicketForm, TicketCCForm, - TicketCCEmailForm, TicketCCUserForm, EditFollowUpForm, TicketDependencyForm, MultipleTicketSelectForm -) -from helpdesk.decorators import superuser_required -from helpdesk.lib import ( - safe_template_context, - process_attachments, - queue_template_context, + CUSTOMFIELD_DATE_FORMAT, + EditFollowUpForm, + EditTicketForm, + EmailIgnoreForm, + MultipleTicketSelectForm, + TicketCCEmailForm, + TicketCCForm, + TicketCCUserForm, + TicketDependencyForm, + TicketForm, + UserSettingsForm ) +from helpdesk.lib import process_attachments, queue_template_context, safe_template_context from helpdesk.models import ( - Ticket, Queue, FollowUp, TicketChange, PreSetReply, FollowUpAttachment, SavedSearch, - IgnoreEmail, TicketCC, TicketDependency, UserSettings, CustomField, TicketCustomFieldValue, + CustomField, + FollowUp, + FollowUpAttachment, + IgnoreEmail, + PreSetReply, + Queue, + SavedSearch, + Ticket, + TicketCC, + TicketChange, + TicketCustomFieldValue, + TicketDependency, + UserSettings ) -from helpdesk import settings as helpdesk_settings -if helpdesk_settings.HELPDESK_KB_ENABLED: - from helpdesk.models import (KBItem) - +from helpdesk.query import get_query_class, query_from_base64, query_to_base64 +from helpdesk.user import HelpdeskUser import helpdesk.views.abstract_views as abstract_views from helpdesk.views.permissions import MustBeStaffMixin -from ..lib import format_time_spent - +import json +import re from rest_framework import status from rest_framework.decorators import api_view -from datetime import date, datetime, timedelta -import re -from ..templated_email import send_templated_mail +if helpdesk_settings.HELPDESK_KB_ENABLED: + from helpdesk.models import KBItem + + + + User = get_user_model() Query = get_query_class() diff --git a/quicktest.py b/quicktest.py index 184b17bf..c5001732 100755 --- a/quicktest.py +++ b/quicktest.py @@ -6,12 +6,12 @@ $ source .venv/bin/activate $ pip install -r requirements-testing.txt -r requirements.txt $ python ./quicktest.py """ -import os -import sys -import argparse +import argparse import django from django.conf import settings +import os +import sys class QuickDjangoTest(object): diff --git a/requirements-testing.txt b/requirements-testing.txt index c07a8ced..12adeae7 100644 --- a/requirements-testing.txt +++ b/requirements-testing.txt @@ -6,3 +6,4 @@ argparse pbr mock freezegun +isort diff --git a/setup.py b/setup.py index 1aac84d1..720de9da 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,14 @@ -import os -import sys +"""django-helpdesk setup""" from distutils.util import convert_path from fnmatch import fnmatchcase -from setuptools import setup, find_packages +import os +from setuptools import find_packages, setup +import sys + version = '0.5.0a1' + # Provided as an attribute, so you can append to these instead # of replicating them: standard_exclude = ("*.py", "*.pyc", "*$py.class", "*~", ".*", "*.bak") diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..05309446 --- /dev/null +++ b/tox.ini @@ -0,0 +1,9 @@ +[tox] +minversion = 3.25.1 +requires = pytest + freezegun + + +[testenv:release] +commands = pip install -r requirements-testing.txt + python quicktest.py