mirror of
https://gitea.mueller.network/extern/django-helpdesk.git
synced 2024-11-25 01:13:31 +01:00
Fix. Add test markdown and rewrite for last markdown is working
This commit is contained in:
commit
3a13bbfeef
8
.flake8
8
.flake8
@ -2,3 +2,11 @@
|
||||
max-line-length = 120
|
||||
exclude = .git,__pycache__,.tox,.eggs,*.egg,node_modules,.venv,migrations,docs,demo,tests,setup.py
|
||||
import-order-style = pep8
|
||||
max-complexity = 20
|
||||
|
||||
[pycodestyle]
|
||||
max-line-length = 120
|
||||
exclude = "migrations"
|
||||
in-place = true
|
||||
recursive = true
|
||||
|
||||
|
53
.github/workflows/pythonpackage.yml
vendored
Normal file
53
.github/workflows/pythonpackage.yml
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
name: Python package
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.8", "3.9", "3.10"]
|
||||
django-version: ["32","4"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements-testing.txt')}}-${{ hashFiles('tox.ini') }}-${{ matrix.python-version }}-${{ matrix.django-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt -r requirements-testing.txt -c constraints-Django${{ matrix.django-version }}.txt
|
||||
|
||||
- name: Format style check with 'autopep8'
|
||||
run: |
|
||||
pip install autopep8
|
||||
autopep8 --exit-code --global-config .flake8 helpdesk
|
||||
|
||||
- name: Lint with 'flake8'
|
||||
run: |
|
||||
pip install flake8
|
||||
# stop the build if there are Python syntax errors or undefined names
|
||||
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
||||
flake8 helpdesk --count --show-source --statistics --exit-zero --max-complexity=20
|
||||
|
||||
- name: Sort style check with 'isort'
|
||||
run: |
|
||||
isort --line-length=120 --src helpdesk . --check
|
||||
|
||||
- name: Test with pytest
|
||||
run: |
|
||||
pip install pytest
|
||||
cd ${GITHUB_WORKSPACE} && python quicktest.py
|
||||
env:
|
||||
DJANGO_SETTINGS_MODULE: helpdesk.settings
|
||||
|
19
.isort.cfg
Normal file
19
.isort.cfg
Normal file
@ -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
|
||||
|
@ -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__)))
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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")
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
# -*- 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)
|
||||
@ -13,7 +11,7 @@ project_root = os.path.dirname(here)
|
||||
NAME = 'django-helpdesk-demodesk'
|
||||
DESCRIPTION = 'A demo Django project using django-helpdesk'
|
||||
README = open(os.path.join(here, 'README.rst')).read()
|
||||
VERSION = '0.4.1'
|
||||
VERSION = '0.5.0a1'
|
||||
#VERSION = open(os.path.join(project_root, 'VERSION')).read().strip()
|
||||
AUTHOR = 'django-helpdesk team'
|
||||
URL = 'https://github.com/django-helpdesk/django-helpdesk'
|
||||
|
@ -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
|
||||
|
@ -63,6 +63,7 @@ errors with trying to create User settings.
|
||||
'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!
|
||||
)
|
||||
|
||||
|
@ -13,4 +13,4 @@ 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.
|
||||
|
||||
Note: It is possible that pinax-teams will interfere with other packages that you already use in your project. If you do not wish to use team functionality, you can dissable teams by setting the following settings: ``HELPDESK_TEAMS_MODEL`` to any random model, ``HELPDESK_TEAMS_MIGRATION_DEPENDENCIES`` to ``[]``, and ``HELPDESK_KBITEM_TEAM_GETTER`` to ``lambda _: None``. You can also use a different library in place of pinax teams by setting those settings appropriately. ``HELPDESK_KBITEM_TEAM_GETTER`` should take a ``kbitem`` and return a team object with a ``name`` property and a method ``is_member(self, user)`` which returns true if user is a member of the team.
|
||||
Note: It is possible that pinax-teams will interfere with other packages that you already use in your project. If you do not wish to use team functionality, you can disable teams by setting the following settings: ``HELPDESK_TEAMS_MODEL`` to any random model, ``HELPDESK_TEAMS_MIGRATION_DEPENDENCIES`` to ``[]``, and ``HELPDESK_KBITEM_TEAM_GETTER`` to ``lambda _: None``. You can also use a different library in place of pinax teams by setting those settings appropriately. ``HELPDESK_KBITEM_TEAM_GETTER`` should take a ``kbitem`` and return a team object with a ``name`` property and a method ``is_member(self, user)`` which returns true if user is a member of the team.
|
||||
|
@ -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, KBCategory
|
||||
from helpdesk.models import EscalationExclusion, EmailTemplate, KBItem
|
||||
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)
|
||||
@ -82,9 +93,10 @@ if helpdesk_settings.HELPDESK_KB_ENABLED:
|
||||
|
||||
list_display_links = ('title',)
|
||||
|
||||
@admin.register(KBCategory)
|
||||
class KBCategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'title', 'slug', 'public')
|
||||
if helpdesk_settings.HELPDESK_KB_ENABLED:
|
||||
@admin.register(KBCategory)
|
||||
class KBCategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'title', 'slug', 'public')
|
||||
|
||||
|
||||
@admin.register(CustomField)
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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,24 @@ 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
|
||||
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 typing
|
||||
|
||||
|
||||
# import User model, which may be a custom model
|
||||
@ -176,13 +177,13 @@ def imap_sync(q, logger, server):
|
||||
sys.exit()
|
||||
|
||||
try:
|
||||
status, data = server.search(None, 'NOT', 'DELETED')
|
||||
data = server.search(None, 'NOT', 'DELETED')[1]
|
||||
if data:
|
||||
msgnums = data[0].split()
|
||||
logger.info("Received %d messages from IMAP server" % len(msgnums))
|
||||
for num in msgnums:
|
||||
logger.info("Processing message %s" % num)
|
||||
status, data = server.fetch(num, '(RFC822)')
|
||||
data = server.fetch(num, '(RFC822)')[1]
|
||||
full_message = encoding.force_str(data[0][1], errors='replace')
|
||||
try:
|
||||
ticket = object_from_message(
|
||||
@ -342,10 +343,10 @@ 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:
|
||||
for __, cced_email in cc_list:
|
||||
|
||||
cced_email = cced_email.strip()
|
||||
if cced_email == ticket.queue.email_address:
|
||||
@ -354,7 +355,7 @@ def create_ticket_cc(ticket, cc_list):
|
||||
user = None
|
||||
|
||||
try:
|
||||
user = User.objects.get(email=cced_email)
|
||||
user = User.objects.get(email=cced_email) # @UndefinedVariable
|
||||
except User.DoesNotExist:
|
||||
pass
|
||||
|
||||
@ -466,16 +467,6 @@ def create_object_from_email_message(message, ticket_id, payload, files, logger)
|
||||
new_ticket_ccs = []
|
||||
new_ticket_ccs.append(create_ticket_cc(ticket, to_list + cc_list))
|
||||
|
||||
notifications_to_be_sent = [sender_email]
|
||||
|
||||
if queue.enable_notifications_on_email_events and len(notifications_to_be_sent):
|
||||
|
||||
ticket_cc_list = TicketCC.objects.filter(
|
||||
ticket=ticket).all().values_list('email', flat=True)
|
||||
|
||||
for email_address in ticket_cc_list:
|
||||
notifications_to_be_sent.append(email_address)
|
||||
|
||||
autoreply = is_autoreply(message)
|
||||
if autoreply:
|
||||
logger.info(
|
||||
@ -516,7 +507,77 @@ def create_object_from_email_message(message, ticket_id, payload, files, logger)
|
||||
return ticket
|
||||
|
||||
|
||||
def object_from_message(message, queue, logger):
|
||||
def get_ticket_id_from_subject_slug(
|
||||
queue_slug: str,
|
||||
subject: str,
|
||||
logger: logging.Logger
|
||||
) -> typing.Optional[int]:
|
||||
"""Get a ticket id from the subject string
|
||||
|
||||
Performs a match on the subject using the queue_slug as reference,
|
||||
returning the ticket id if a match is found.
|
||||
"""
|
||||
matchobj = re.match(r".*\[" + queue_slug + r"-(?P<id>\d+)\]", subject)
|
||||
ticket_id = None
|
||||
if matchobj:
|
||||
# This is a reply or forward.
|
||||
ticket_id = matchobj.group('id')
|
||||
logger.info("Matched tracking ID %s-%s" % (queue_slug, ticket_id))
|
||||
else:
|
||||
logger.info("No tracking ID matched.")
|
||||
return ticket_id
|
||||
|
||||
|
||||
def add_file_if_always_save_incoming_email_message(
|
||||
files_,
|
||||
message: str
|
||||
) -> None:
|
||||
"""When `settings.HELPDESK_ALWAYS_SAVE_INCOMING_EMAIL_MESSAGE` is `True`
|
||||
add a file to the files_ list"""
|
||||
if getattr(django_settings, 'HELPDESK_ALWAYS_SAVE_INCOMING_EMAIL_MESSAGE', False):
|
||||
# save message as attachment in case of some complex markup renders
|
||||
# wrong
|
||||
files_.append(
|
||||
SimpleUploadedFile(
|
||||
_("original_message.eml").replace(
|
||||
".eml",
|
||||
timezone.localtime().strftime("_%d-%m-%Y_%H:%M") + ".eml"
|
||||
),
|
||||
str(message).encode("utf-8"),
|
||||
'text/plain'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def get_encoded_body(body: str) -> str:
|
||||
try:
|
||||
return body.encode('ascii').decode('unicode_escape')
|
||||
except UnicodeEncodeError:
|
||||
return body
|
||||
|
||||
|
||||
def get_body_from_fragments(body) -> str:
|
||||
"""Gets a body from the fragments, joined by a double line break"""
|
||||
return "\n\n".join(f.content for f in EmailReplyParser.read(body).fragments)
|
||||
|
||||
|
||||
def get_email_body_from_part_payload(part) -> str:
|
||||
"""Gets an decoded body from the payload part, if the decode fails,
|
||||
returns without encoding"""
|
||||
try:
|
||||
return encoding.smart_str(
|
||||
part.get_payload(decode=True)
|
||||
)
|
||||
except UnicodeDecodeError:
|
||||
return encoding.smart_str(
|
||||
part.get_payload(decode=False)
|
||||
)
|
||||
|
||||
|
||||
def object_from_message(message: str,
|
||||
queue: Queue,
|
||||
logger: logging.Logger
|
||||
) -> Ticket:
|
||||
# 'message' must be an RFC822 formatted message.
|
||||
message = email.message_from_string(message)
|
||||
|
||||
@ -539,35 +600,17 @@ def object_from_message(message, queue, logger):
|
||||
sender_email = email.utils.getaddresses(
|
||||
['\"' + sender.replace('<', '\" <')])[0][1]
|
||||
|
||||
cc = message.get_all('cc', None)
|
||||
if cc:
|
||||
# first, fixup the encoding if necessary
|
||||
cc = [decode_mail_headers(decodeUnknown(
|
||||
message.get_charset(), x)) for x in cc]
|
||||
# get_all checks if multiple CC headers, but individual emails may be
|
||||
# comma separated too
|
||||
tempcc = []
|
||||
for hdr in cc:
|
||||
tempcc.extend(hdr.split(','))
|
||||
# use a set to ensure no duplicates
|
||||
cc = set([x.strip() for x in tempcc])
|
||||
|
||||
for ignore in IgnoreEmail.objects.filter(Q(queues=queue) | Q(queues__isnull=True)):
|
||||
if ignore.test(sender_email):
|
||||
if ignore.keep_in_mailbox:
|
||||
# By returning 'False' the message will be kept in the mailbox,
|
||||
# and the 'True' will cause the message to be deleted.
|
||||
return False
|
||||
return True
|
||||
# By returning 'False' the message will be kept in the mailbox,
|
||||
# and the 'True' will cause the message to be deleted.
|
||||
return not ignore.keep_in_mailbox
|
||||
|
||||
matchobj = re.match(r".*\[" + queue.slug + r"-(?P<id>\d+)\]", subject)
|
||||
if matchobj:
|
||||
# This is a reply or forward.
|
||||
ticket = matchobj.group('id')
|
||||
logger.info("Matched tracking ID %s-%s" % (queue.slug, ticket))
|
||||
else:
|
||||
logger.info("No tracking ID matched.")
|
||||
ticket = None
|
||||
ticket_id: typing.Optional[int] = get_ticket_id_from_subject_slug(
|
||||
queue.slug,
|
||||
subject,
|
||||
logger
|
||||
)
|
||||
|
||||
body = None
|
||||
full_body = None
|
||||
@ -591,13 +634,10 @@ def object_from_message(message, queue, logger):
|
||||
body = decodeUnknown(part.get_content_charset(), body)
|
||||
# have to use django_settings here so overwritting it works in tests
|
||||
# the default value is False anyway
|
||||
if ticket is None and getattr(django_settings, 'HELPDESK_FULL_FIRST_MESSAGE_FROM_EMAIL', False):
|
||||
if ticket_id is None and getattr(django_settings, 'HELPDESK_FULL_FIRST_MESSAGE_FROM_EMAIL', False):
|
||||
# first message in thread, we save full body to avoid
|
||||
# losing forwards and things like that
|
||||
body_parts = []
|
||||
for f in EmailReplyParser.read(body).fragments:
|
||||
body_parts.append(f.content)
|
||||
full_body = '\n\n'.join(body_parts)
|
||||
full_body = get_body_from_fragments(body)
|
||||
body = EmailReplyParser.parse_reply(body)
|
||||
else:
|
||||
# second and other reply, save only first part of the
|
||||
@ -605,18 +645,10 @@ def object_from_message(message, queue, logger):
|
||||
body = EmailReplyParser.parse_reply(body)
|
||||
full_body = body
|
||||
# workaround to get unicode text out rather than escaped text
|
||||
try:
|
||||
body = body.encode('ascii').decode('unicode_escape')
|
||||
except UnicodeEncodeError:
|
||||
body.encode('utf-8')
|
||||
body = get_encoded_body(body)
|
||||
logger.debug("Discovered plain text MIME part")
|
||||
else:
|
||||
try:
|
||||
email_body = encoding.smart_str(
|
||||
part.get_payload(decode=True))
|
||||
except UnicodeDecodeError:
|
||||
email_body = encoding.smart_str(
|
||||
part.get_payload(decode=False))
|
||||
email_body = get_email_body_from_part_payload(part)
|
||||
|
||||
if not body and not full_body:
|
||||
# no text has been parsed so far - try such deep parsing
|
||||
@ -683,19 +715,7 @@ def object_from_message(message, queue, logger):
|
||||
if not body:
|
||||
body = ""
|
||||
|
||||
if getattr(django_settings, 'HELPDESK_ALWAYS_SAVE_INCOMING_EMAIL_MESSAGE', False):
|
||||
# save message as attachment in case of some complex markup renders
|
||||
# wrong
|
||||
files.append(
|
||||
SimpleUploadedFile(
|
||||
_("original_message.eml").replace(
|
||||
".eml",
|
||||
timezone.localtime().strftime("_%d-%m-%Y_%H:%M") + ".eml"
|
||||
),
|
||||
str(message).encode("utf-8"),
|
||||
'text/plain'
|
||||
)
|
||||
)
|
||||
add_file_if_always_save_incoming_email_message(files, message)
|
||||
|
||||
smtp_priority = message.get('priority', '')
|
||||
smtp_importance = message.get('importance', '')
|
||||
@ -713,4 +733,4 @@ def object_from_message(message, queue, logger):
|
||||
'files': files,
|
||||
}
|
||||
|
||||
return create_object_from_email_message(message, ticket, payload, files, logger=logger)
|
||||
return create_object_from_email_message(message, ticket_id, payload, files, logger=logger)
|
||||
|
@ -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, date, time
|
||||
|
||||
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()
|
||||
@ -226,7 +239,10 @@ class AbstractTicketForm(CustomFieldMixin, forms.Form):
|
||||
widget=forms.FileInput(attrs={'class': 'form-control-file'}),
|
||||
required=False,
|
||||
label=_('Attach File'),
|
||||
help_text=_('You can attach a file to this ticket. Only file types such as plain text (.txt), a document (.pdf, .docx, or .odt), or screenshot (.png or .jpg) may be uploaded.'),
|
||||
help_text=_('You can attach a file to this ticket. '
|
||||
'Only file types such as plain text (.txt), '
|
||||
'a document (.pdf, .docx, or .odt), '
|
||||
'or screenshot (.png or .jpg) may be uploaded.'),
|
||||
)
|
||||
|
||||
class Media:
|
||||
|
@ -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')
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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):
|
||||
@ -59,7 +53,7 @@ def get_markdown(text):
|
||||
if not text:
|
||||
return ""
|
||||
|
||||
pattern = fr'([\[\s\S\]]*?)\(([\s\S]*?):([\s\S]*?)\)'
|
||||
pattern = r'([\[\s\S\]]*?)\(([\s\S]*?):([\s\S]*?)\)'
|
||||
# Regex check
|
||||
if re.match(pattern, text):
|
||||
# get get value of group regex
|
||||
@ -1969,6 +1963,10 @@ class TicketCustomFieldValue(models.Model):
|
||||
def __str__(self):
|
||||
return '%s / %s' % (self.ticket, self.field)
|
||||
|
||||
@property
|
||||
def default_value(self) -> str:
|
||||
return _("Not defined")
|
||||
|
||||
class Meta:
|
||||
unique_together = (('ticket', 'field'),)
|
||||
verbose_name = _('Ticket custom field value')
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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,
|
||||
|
@ -1,6 +1,5 @@
|
||||
from celery import shared_task
|
||||
|
||||
from .email import process_email
|
||||
from celery import shared_task
|
||||
|
||||
|
||||
@shared_task
|
||||
|
@ -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 {}
|
||||
|
||||
|
@ -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__)
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -1,4 +1,4 @@
|
||||
from django.test import TestCase, override_settings
|
||||
from django.test import override_settings, TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
||||
|
@ -1,22 +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):
|
||||
fixtures = ['emailtemplate.json']
|
||||
|
@ -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()
|
||||
|
@ -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')
|
||||
|
@ -1,23 +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):
|
||||
|
||||
|
@ -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
|
||||
|
@ -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')),
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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.
|
||||
|
@ -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):
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
||||
|
||||
from helpdesk.decorators import is_helpdesk_staff
|
||||
|
||||
|
||||
|
@ -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 = {
|
||||
|
File diff suppressed because it is too large
Load Diff
27
quicktest.py
Normal file → Executable file
27
quicktest.py
Normal file → Executable file
@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Usage:
|
||||
$ python -m venv .venv
|
||||
@ -5,15 +6,15 @@ $ 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):
|
||||
class QuickDjangoTest:
|
||||
"""
|
||||
A quick way to run the Django test suite without a fully-configured project.
|
||||
|
||||
@ -35,14 +36,14 @@ class QuickDjangoTest(object):
|
||||
'django.contrib.sites',
|
||||
'django.contrib.staticfiles',
|
||||
'bootstrap4form',
|
||||
# The following commented apps are optional,
|
||||
# related to teams functionalities
|
||||
#'account',
|
||||
#'pinax.invitations',
|
||||
#'pinax.teams',
|
||||
# The following commented apps are optional,
|
||||
# related to teams functionalities
|
||||
# 'account',
|
||||
# 'pinax.invitations',
|
||||
# 'pinax.teams',
|
||||
'rest_framework',
|
||||
'helpdesk',
|
||||
#'reversion',
|
||||
# 'reversion',
|
||||
)
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
@ -77,6 +78,7 @@ class QuickDjangoTest(object):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.tests = args
|
||||
self.kwargs = kwargs or {"verbosity": 1}
|
||||
self._tests()
|
||||
|
||||
def _tests(self):
|
||||
@ -111,7 +113,7 @@ class QuickDjangoTest(object):
|
||||
)
|
||||
|
||||
from django.test.runner import DiscoverRunner
|
||||
test_runner = DiscoverRunner(verbosity=1)
|
||||
test_runner = DiscoverRunner(verbosity=self.kwargs["verbosity"])
|
||||
django.setup()
|
||||
|
||||
failures = test_runner.run_tests(self.tests)
|
||||
@ -133,7 +135,8 @@ if __name__ == '__main__':
|
||||
description="Run Django tests."
|
||||
)
|
||||
parser.add_argument('tests', nargs="*", type=str)
|
||||
parser.add_argument("--verbosity", "-v", nargs="?", type=int, default=1)
|
||||
args = parser.parse_args()
|
||||
if not args.tests:
|
||||
args.tests = ['helpdesk']
|
||||
QuickDjangoTest(*args.tests)
|
||||
QuickDjangoTest(*args.tests, verbosity=args.verbosity)
|
||||
|
@ -6,3 +6,4 @@ argparse
|
||||
pbr
|
||||
mock
|
||||
freezegun
|
||||
isort
|
||||
|
@ -1,4 +1,4 @@
|
||||
Django>=2.2
|
||||
Django>=3.2
|
||||
django-bootstrap4-form
|
||||
celery
|
||||
email-reply-parser
|
||||
@ -12,3 +12,4 @@ six
|
||||
pinax_teams
|
||||
djangorestframework
|
||||
django-model-utils
|
||||
django-cleanup
|
||||
|
11
setup.py
11
setup.py
@ -1,10 +1,13 @@
|
||||
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'
|
||||
|
||||
version = '0.4.1'
|
||||
|
||||
# Provided as an attribute, so you can append to these instead
|
||||
# of replicating them:
|
||||
|
Loading…
Reference in New Issue
Block a user