mirror of
https://github.com/django-helpdesk/django-helpdesk.git
synced 2024-12-12 18:00:45 +01:00
Merge master 0.2.3 bugfixes into develop
This commit is contained in:
commit
92b43ef495
@ -7,7 +7,7 @@ python:
|
|||||||
- "3.6"
|
- "3.6"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- DJANGO=1.11.4
|
- DJANGO=1.11.8
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- pip install -q Django==$DJANGO
|
- pip install -q Django==$DJANGO
|
||||||
@ -15,7 +15,7 @@ install:
|
|||||||
- pip install -q -r requirements-testing.txt
|
- pip install -q -r requirements-testing.txt
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- "pep8 --exclude=migrations --ignore=E501 helpdesk"
|
- "pycodestyle --exclude=migrations --ignore=E501 helpdesk"
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- coverage run --source='.' quicktest.py helpdesk
|
- coverage run --source='.' quicktest.py helpdesk
|
||||||
|
@ -62,6 +62,7 @@ TEMPLATES = [
|
|||||||
'DIRS': [],
|
'DIRS': [],
|
||||||
'APP_DIRS': True,
|
'APP_DIRS': True,
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
|
'debug': True,
|
||||||
'context_processors': [
|
'context_processors': [
|
||||||
'django.template.context_processors.debug',
|
'django.template.context_processors.debug',
|
||||||
'django.template.context_processors.request',
|
'django.template.context_processors.request',
|
||||||
|
@ -13,7 +13,7 @@ project_root = os.path.dirname(here)
|
|||||||
NAME = 'django-helpdesk-demodesk'
|
NAME = 'django-helpdesk-demodesk'
|
||||||
DESCRIPTION = 'A demo Django project using django-helpdesk'
|
DESCRIPTION = 'A demo Django project using django-helpdesk'
|
||||||
README = open(os.path.join(here, 'README.rst')).read()
|
README = open(os.path.join(here, 'README.rst')).read()
|
||||||
VERSION = '0.2.0'
|
VERSION = '0.2.3'
|
||||||
#VERSION = open(os.path.join(project_root, 'VERSION')).read().strip()
|
#VERSION = open(os.path.join(project_root, 'VERSION')).read().strip()
|
||||||
AUTHOR = 'django-helpdesk team'
|
AUTHOR = 'django-helpdesk team'
|
||||||
URL = 'https://github.com/django-helpdesk/django-helpdesk'
|
URL = 'https://github.com/django-helpdesk/django-helpdesk'
|
||||||
|
@ -119,7 +119,7 @@ errors with trying to create User settings.
|
|||||||
|
|
||||||
Ideally, accessing http://MEDIA_URL/helpdesk/attachments/ will give you a 403 access denied error.
|
Ideally, accessing http://MEDIA_URL/helpdesk/attachments/ will give you a 403 access denied error.
|
||||||
|
|
||||||
7. If it's not already installed, install ``django-markdown-deux`` and ensure it's in your ``INSTALLED_APPS``::
|
7. If it's not already installed, install ``markdown_deux`` and ensure it's in your ``INSTALLED_APPS``::
|
||||||
|
|
||||||
pip install django-markdown-deux
|
pip install django-markdown-deux
|
||||||
|
|
||||||
|
@ -1153,8 +1153,197 @@
|
|||||||
"subject": "(Actualizado)",
|
"subject": "(Actualizado)",
|
||||||
"locale": "es"
|
"locale": "es"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 97,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "已分配_CC",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">温馨提示, {{ ticket.submitter_email }}的工单 <a href=\"{{ ticket.staff_url }}\"><b>{{ ticket.ticket }}</b></a> (<em>{{ ticket.title }}</em>) {% if ticket.assigned_to %}已经分配给 {{ ticket.assigned_to }}{% else %}还未分配{% endif %}.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">\r\n<b>工单 ID</b>: {{ ticket.ticket }}<br>\r\n<b>待办</b>: {{ queue.title }}<br>\r\n<b>标题</b>: {{ ticket.title }}<br>\r\n<b>已打开</b>: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}<br>\r\n<b>提交人</b>: {{ ticket.submitter_email|default:\"Unknown\" }}<br>\r\n<b>优先级</b>: {{ ticket.get_priority_display }}<br>\r\n<b>状态</b>: {{ ticket.get_status }}<br>\r\n<b>已分配给</b>: {{ ticket.get_assigned_to }}<br>\r\n<b><a href='{{ ticket.staff_url }}'>在线查看</a></b> 更新此工单 (需要登录)</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">原工单描述参考::</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.description|linebreaksbr }}</blockquote>",
|
||||||
|
"plain_text": "您好,\r\n\r\n温馨提示, {{ ticket.submitter_email }}提交的工单 {{ ticket.ticket }} (\"{{ ticket.title }}\") 已经 {% if ticket.assigned_to %}分配给 {{ ticket.assigned_to }}{% else %}未分配{% endif %}.\r\n\r\n工单 ID: {{ ticket.ticket }}\r\n待办: {{ queue.title }}\r\n标题: {{ ticket.title }}\r\n已打开: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}\r\n提交人: {{ ticket.submitter_email|default:\"Unknown\" }}\r\n优先级:{{ ticket.get_priority_display }}\r\n状态: {{ ticket.get_status }}\r\n已分配给: {{ ticket.get_assigned_to }}\r\n在线查看: {{ ticket.staff_url }}\r\n\r\n原始描述为:\r\n\r\n{{ ticket.description }}\r\n\r\n",
|
||||||
|
"heading": "工单已分配",
|
||||||
|
"subject": "(已分配)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 98,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "assigned_owner",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">温馨提示, 提交者{{ ticket.submitter_email }}的工单 <a href=\"{{ ticket.staff_url }}\"><b>{{ ticket.ticket }}</b></a> (<em>{{ ticket.title }}</em>) 已经分配给 <b>you</b>.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">\r\n<b>工单 ID</b>: {{ ticket.ticket }}<br>\r\n<b>待办</b>: {{ queue.title }}<br>\r\n<b>标题</b>: {{ ticket.title }}<br>\r\n<b>已打开</b>: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}<br>\r\n<b>提交人</b>: {{ ticket.submitter_email|default:\"Unknown\" }}<br>\r\n<b>优先级</b>: {{ ticket.get_priority_display }}<br>\r\n<b>状态</b>: {{ ticket.get_status }}<br>\r\n<b>已分配给</b>: YOU<br>\r\n<b><a href='{{ ticket.staff_url }}'>在线查看</a></b> 更新此工单 (需要登录)</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">原工单描述参考::</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.description|linebreaksbr }}</blockquote>",
|
||||||
|
"plain_text": "您好,\r\n\r\n温馨提示, 工单 提交者{{ ticket.submitter_email }}的工单{{ ticket.ticket }} 已经 分配给 you.\r\n\r\n工单 ID: {{ ticket.ticket }}\r\n待办: {{ queue.title }}\r\n标题: {{ ticket.title }}\r\n已打开: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}\r\n提交人: {{ ticket.submitter_email|default:\"Unknown\" }}\r\n优先级:{{ ticket.get_priority_display }}\r\n状态: {{ ticket.get_status }}\r\n已分配给: YOU\r\n在线查看: {{ ticket.staff_url }}\r\n\r\n原始描述为:\r\n\r\n{{ ticket.description }}\r\n\r\n",
|
||||||
|
"heading": "工单已分配给您",
|
||||||
|
"subject": "(已分配给您)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 99,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "closed_cc",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">工单 <i>{{ ticket.title }}</i> ('{{ ticket.title }}'){% if ticket.assigned_to %}, 分配给 {{ ticket.get_assigned_to }}{% endif %} 已经 关闭</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">\r\n<b>工单 ID</b>: {{ ticket.ticket }}<br>\r\n<b>待办</b>: {{ queue.title }}<br>\r\n<b>标题</b>: {{ ticket.title }}<br>\r\n<b>已打开</b>: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}<br>\r\n<b>提交人</b>: {{ ticket.submitter_email|default:\"Unknown\" }}<br>\r\n<b>优先级</b>: {{ ticket.get_priority_display }}<br>\r\n<b>状态</b>: {{ ticket.get_status }}<br>\r\n<b>已分配给</b>: {{ ticket.get_assigned_to }}<br>\r\n<b><a href='{{ ticket.staff_url }}'>在线查看</a></b> 更新此工单 (需要登录)</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">原工单描述参考::</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.description|linebreaksbr }}</blockquote>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">提供的解决方案为:</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ resolution }}</blockquote>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">如果您想在线查看, 可以访问 <a href='{{ ticket.staff_url }}'>{{ ticket.staff_url }}</a>.</p>",
|
||||||
|
"plain_text": "您好,\r\n\r\n工单 {{ ticket.title }} (\"{{ ticket.title }}\"){% if ticket.assigned_to %}, 分配给 {{ ticket.assigned_to }}{% endif %} 已经 关闭\r\n\r\n工单 ID: {{ ticket.ticket }}\r\n待办: {{ queue.title }}\r\n标题: {{ ticket.title }}\r\n已打开: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}\r\n提交人: {{ ticket.submitter_email|default:\"Unknown\" }}\r\n优先级:{{ ticket.get_priority_display }}\r\n状态: {{ ticket.get_status }}\r\n已分配给: {{ ticket.get_assigned_to }}\r\n在线查看: {{ ticket.staff_url }} (需要登录)\r\n\r\n原始描述为:\r\n\r\n{{ ticket.description }}\r\n\r\n提供的解决方案为:\r\n\r\n{{ resolution }}\r\n\r\n",
|
||||||
|
"heading": "工单已关闭",
|
||||||
|
"subject": "(已关闭)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 100,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "closed_owner",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">以下分配给您的工单, 已经关闭</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">\r\n<b>工单 ID</b>: {{ ticket.ticket }}<br>\r\n<b>待办</b>: {{ queue.title }}<br>\r\n<b>标题</b>: {{ ticket.title }}<br>\r\n<b>已打开</b>: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}<br>\r\n<b>提交人</b>: {{ ticket.submitter_email|default:\"Unknown\" }}<br>\r\n<b>优先级</b>: {{ ticket.get_priority_display }}<br>\r\n<b>状态</b>: {{ ticket.get_status }}<br>\r\n<b>已分配给</b>: {{ ticket.get_assigned_to }}<br>\r\n<b><a href='{{ ticket.staff_url }}'>在线查看</a></b> 更新此工单 (需要登录)</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">原工单描述参考::</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.description|linebreaksbr }}</blockquote>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">提供的解决方案为:</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.resolution }}</blockquote>",
|
||||||
|
"plain_text": "您好,\r\n\r\n以下分配给您的工单, 已经关闭\r\n\r\n工单 ID: {{ ticket.ticket }}\r\n待办: {{ queue.title }}\r\n标题: {{ ticket.title }}\r\n已打开: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}\r\n提交人: {{ ticket.submitter_email|default:\"Unknown\" }}\r\n优先级:{{ ticket.get_priority_display }}\r\n状态: {{ ticket.get_status }}\r\n已分配给: {{ ticket.get_assigned_to }}\r\n在线查看: {{ ticket.staff_url }} (需要登录)\r\n\r\n如果您想在线查看, 可以访问 {{ ticket.staff_url }}.\r\n\r\n",
|
||||||
|
"heading": "工单已关闭",
|
||||||
|
"subject": "(已关闭)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 101,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "closed_submitter",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">您最近记录了主题为<i>{{ ticket.title }}</i>的工单. 本邮件确认工单已经 关闭</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">已提供的方案为:</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.resolution }}</blockquote>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">如果您想在线查看, 可以访问 <a href=\"{{ ticket.ticket_url }}\">{{ ticket.ticket_url }}</a>. 如果您认为还需要后续工作, 请用原标题回复此邮件.</p>",
|
||||||
|
"plain_text": "您好,\r\n\r\n您最近记录了主题为\"{{ ticket.title }}\"的工单. 本邮件确认工单已经 关闭\r\n\r\nI如果您认为还需要后续工作, 请用原标题回复此邮件.\r\n\r\n如果您想在线查看, 可以访问 {{ ticket.ticket_url }}.\r\n\r\n提供的解决方案为:\r\n\r\n{{ ticket.resolution }}\r\n\r\n",
|
||||||
|
"heading": "工单已关闭",
|
||||||
|
"subject": "(已关闭)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 102,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "escalated_cc",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">温馨提示, 工单 <i>{{ ticket.ticket }}</i> ('{{ ticket.title }}') 已经 自动提升优先级.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">\r\n<b>工单 ID</b>: {{ ticket.ticket }}<br>\r\n<b>待办</b>: {{ queue.title }}<br>\r\n<b>标题</b>: {{ ticket.title }}<br>\r\n<b>已打开</b>: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}<br>\r\n<b>提交人</b>: {{ ticket.submitter_email|default:\"Unknown\" }}<br>\r\n<b>优先级</b>: {{ ticket.get_priority_display }}<br>\r\n<b>状态</b>: {{ ticket.get_status }}<br>\r\n<b>已分配给</b>: {{ ticket.get_assigned_to }}<br>\r\n<b><a href='{{ ticket.staff_url }}'>在线查看</a></b> 更新此工单 (需要登录)</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">原工单描述参考::</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.description|linebreaksbr }}</blockquote>",
|
||||||
|
"plain_text": "您好,\r\n\r\n温馨提示, 工单 {{ ticket.ticket }} (\"{{ ticket.title }}\") 已经自动提升优先级.\r\n\r\n工单 ID: {{ ticket.ticket }}\r\n待办: {{ queue.title }}\r\n标题: {{ ticket.title }}\r\n已打开: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}\r\n提交人: {{ ticket.submitter_email|default:\"Unknown\" }}\r\n优先级:{{ ticket.get_priority_display }}\r\n状态: {{ ticket.get_status }}\r\n已分配给: {{ ticket.get_assigned_to }}\r\n在线查看: {{ ticket.staff_url }} (需要登录)\r\n\r\n原始描述为:\r\n\r\n{{ ticket.description }}\r\n\r\n",
|
||||||
|
"heading": "工单 已经提升优先级",
|
||||||
|
"subject": "(已经提升优先级)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 103,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "escalated_owner",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">A 当前分配给您的工单已经自动提升优先级 as it 已经 打开时间超过预期.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">\r\n<b>工单 ID</b>: {{ ticket.ticket }}<br>\r\n<b>待办</b>: {{ queue.title }}<br>\r\n<b>标题</b>: {{ ticket.title }}<br>\r\n<b>已打开</b>: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}<br>\r\n<b>提交人</b>: {{ ticket.submitter_email|default:\"Unknown\" }}<br>\r\n<b>优先级</b>: {{ ticket.get_priority_display }}<br>\r\n<b>状态</b>: {{ ticket.get_status }}<br>\r\n<b>已分配给</b>: {{ ticket.get_assigned_to }}<br>\r\n<b><a href='{{ ticket.staff_url }}'>在线查看</a></b> 更新此工单 (需要登录)</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">原工单描述参考::</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.description|linebreaksbr }}</blockquote>",
|
||||||
|
"plain_text": "您好,\r\n\r\nA 分配给您的当前工单已经自动提升优先级, 因为打开时间已经超过预期.\r\n\r\n工单 ID: {{ ticket.ticket }}\r\n待办: {{ queue.title }}\r\n标题: {{ ticket.title }}\r\n已打开: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}\r\n提交人: {{ ticket.submitter_email|default:\"Unknown\" }}\r\n优先级:{{ ticket.get_priority_display }}\r\n状态: {{ ticket.get_status }}\r\n已分配给: {{ ticket.get_assigned_to }}\r\n在线查看: {{ ticket.staff_url }} (需要登录)\r\n\r\n原始描述为:\r\n\r\n{{ ticket.description }}\r\n\r\n请查看此工单并尽快提供解决方案.\r\n\r\n",
|
||||||
|
"heading": "工单 已分配给 您 已经提升优先级",
|
||||||
|
"subject": "(已经提升优先级)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 104,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "escalated_submitter",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 11pt;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 11pt;\">您最近记录了主题为<i>{{ ticket.title }}</i>的工单. 本邮件是想提醒您工单自动升级, 因为已经 打开时间超过预期.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 11pt;\">我们将尽快查看并提供解决方案.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 11pt;\">如果您想在线查看, 可以访问 <a href=\"{{ ticket.ticket_url }}\">{{ ticket.ticket_url }}</a>.</p>",
|
||||||
|
"plain_text": "您好,\r\n\r\n您最近为我们记录了一个标题为 \"{{ ticket.title }}\" 的工单. 本邮件是想提醒您工单自动升级, 因为已经打开时间超过预期.\r\n\r\n我们将尽快查看并提供解决方案.\r\n\r\n如果您想在线查看, 可以访问 {{ ticket.ticket_url }}.\r\n\r\n",
|
||||||
|
"heading": "您的 工单 已经 已经提升优先级",
|
||||||
|
"subject": "(已经提升优先级)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 105,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "newticket_cc",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">温馨提示: 新工单已经打开.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">\r\n<b>工单 ID</b>: {{ ticket.ticket }}<br>\r\n<b>待办</b>: {{ queue.title }}<br>\r\n<b>标题</b>: {{ ticket.title }}<br>\r\n<b>已打开</b>: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}<br>\r\n<b>提交人</b>: {{ ticket.submitter_email|default:\"Unknown\" }}<br>\r\n<b>优先级</b>: {{ ticket.get_priority_display }}<br>\r\n<b>状态</b>: {{ ticket.get_status }}<br>\r\n<b><a href='{{ ticket.staff_url }}'>在线查看</a></b> 更新此工单 (需要登录)</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">Description:</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.description|linebreaksbr }}</blockquote>",
|
||||||
|
"plain_text": "您好,\r\n\r\n温馨提示: 新工单已经 打开.\r\n\r\n工单 ID: {{ ticket.ticket }}\r\n待办: {{ queue.title }}\r\n标题: {{ ticket.title }}\r\n已打开: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}\r\n提交人: {{ ticket.submitter_email|default:\"Unknown\" }}\r\n优先级:{{ ticket.get_priority_display }}\r\n状态: {{ ticket.get_status }}\r\n在线查看: {{ ticket.staff_url }} (需要登录)\r\n\r\nDescription:\r\n{{ ticket.description }}\r\n\r\n",
|
||||||
|
"heading": "新工单已打开",
|
||||||
|
"subject": "(已打开)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 106,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "newticket_submitter",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">温馨提示: 我们已收到您主题为 <i>{{ ticket.title }}</i>.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">您当前什么都不用做. 您的工单 已经 分配编号 <b>{{ ticket.ticket }}</b> 且将很快收到回复.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">如果您想告诉我们更多详情, 或者要查询此工单, 请在主题带上工单id <b>{{ ticket.ticket }}</b> . 最简单就是直接点这个消息的 \"回复\" 按钮.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">如果您希望在线查看并提供此工单的更多信息, 附加文件或者查看最近更新, 您可以访问 <a href=\"{{ ticket.ticket_url }}\">{{ ticket.ticket_url }}</a>.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">我们将调查您的问题并尽快解决. 您将通过此邮箱收到后续更新和解决方案.</p>",
|
||||||
|
"plain_text": "您好,\r\n\r\n温馨提示: 我们已经收到您主题为 \"{{ ticket.title }}\" 的查询. \r\n\r\n您当前什么都不用做. 您的工单已经分配编号 {{ ticket.ticket }} 且将很快收到回复.\r\n\r\n如果您想告诉我们更多详情, 或者要查询此工单, 请在主题带上工单id '{{ ticket.ticket }}' . 最简单方式就是按下此消息 \"回复\" .\r\n\r\n如果您希望在线查看并提供此工单的更多信息, 附加文件或者查看最近更新, 您可以访问 {{ ticket.ticket_url }}.\r\n\r\n我们将调查您的问题并尽快解决. 您将通过此邮箱收到后续更新和解决方案.\r\n",
|
||||||
|
"heading": "您的工单已经打开",
|
||||||
|
"subject": "(已打开)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 107,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "解决_cc",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">以下工单 已经 解决.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">\r\n<b>工单 ID</b>: {{ ticket.ticket }}<br>\r\n<b>待办</b>: {{ queue.title }}<br>\r\n<b>标题</b>: {{ ticket.title }}<br>\r\n<b>已打开</b>: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}<br>\r\n<b>提交人</b>: {{ ticket.submitter_email|default:\"Unknown\" }}<br>\r\n<b>优先级</b>: {{ ticket.get_priority_display }}<br>\r\n<b>状态</b>: {{ ticket.get_status }}<br>\r\n<b>已分配给</b>: {{ ticket.get_assigned_to }}<br>\r\n<b><a href='{{ ticket.staff_url }}'>在线查看</a></b> 更新此工单 (需要登录)</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">原工单描述参考::</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.description|linebreaksbr }}</blockquote>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">增加的解决方案为:</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.resolution }}</blockquote>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">此方案已经 邮件发送给提交者, 在您关闭之前需要他先确认.</p>",
|
||||||
|
"plain_text": "您好,\r\n\r\n以下工单 已经 解决:\r\n\r\n工单 ID: {{ ticket.ticket }}\r\n待办: {{ queue.title }}\r\n标题: {{ ticket.title }}\r\n已打开: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}\r\n提交人: {{ ticket.submitter_email|default:\"Unknown\" }}\r\n优先级:{{ ticket.get_priority_display }}\r\n状态: {{ ticket.get_status }}\r\n已分配给: {{ ticket.get_assigned_to }}\r\n在线查看: {{ ticket.staff_url }} (需要登录)\r\n\r\n原始描述为:\r\n\r\n{{ ticket.description }}\r\n\r\n提供的解决方案为:\r\n\r\n{{ ticket.resolution }}\r\n\r\n此方案已经 邮件发送给提交者, 在您关闭之前需要他先确认.\r\n\r\n",
|
||||||
|
"heading": "工单 解决",
|
||||||
|
"subject": "(解决)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 108,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "解决_owner",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">A 当前分配给您的工单已经 解决.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">\r\n<b>工单 ID</b>: {{ ticket.ticket }}<br>\r\n<b>待办</b>: {{ queue.title }}<br>\r\n<b>标题</b>: {{ ticket.title }}<br>\r\n<b>已打开</b>: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}<br>\r\n<b>提交人</b>: {{ ticket.submitter_email|default:\"Unknown\" }}<br>\r\n<b>优先级</b>: {{ ticket.get_priority_display }}<br>\r\n<b>状态</b>: {{ ticket.get_status }}<br>\r\n<b>已分配给</b>: {{ ticket.get_assigned_to }}<br>\r\n<b><a href='{{ ticket.staff_url }}'>在线查看</a></b> 更新此工单 (需要登录)</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">原工单描述参考::</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.description|linebreaksbr }}</blockquote>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">增加的解决方案为:</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.resolution }}</blockquote>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">此方案已经 邮件发送给提交者, 在您关闭之前需要他先确认.</p>",
|
||||||
|
"plain_text": "您好,\r\n\r\nA 当前分配给您的工单已经 解决.\r\n\r\n工单 ID: {{ ticket.ticket }}\r\n待办: {{ queue.title }}\r\n标题: {{ ticket.title }}\r\n已打开: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}\r\n提交人: {{ ticket.submitter_email|default:\"Unknown\" }}\r\n优先级:{{ ticket.get_priority_display }}\r\n状态: {{ ticket.get_status }}\r\n已分配给: {{ ticket.get_assigned_to }}\r\n在线查看: {{ ticket.staff_url }} (需要登录)\r\n\r\n原始描述为:\r\n\r\n{{ ticket.description }}\r\n\r\n提供的方案为:\r\n\r\n{{ ticket.resolution }}\r\n\r\n此方案已经 邮件发送给提交者, 在您关闭之前需要他先确认.\r\n\r\n",
|
||||||
|
"heading": "工单 解决",
|
||||||
|
"subject": "(解决)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 109,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "解决_submitter",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">您最近记录了主题为<i>{{ ticket.title }}</i>的工单. 此邮件是要告知您解决方案.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">工单添加了以下解决方案 <b>{{ ticket.ticket }}</b>:</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ resolution }}</blockquote>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">请您确认下此解决方案是否解决了您的问题, 这样我们可以关闭此工单? 如果有更多问题或者认为方案不够充分,, 请继续使用邮件的主题回复此邮件.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">如果您想在线查看, 可以访问 <a href=\"{{ ticket.ticket_url }}\">{{ ticket.ticket_url }}</a>.</p>",
|
||||||
|
"plain_text": "您好,\r\n\r\n您最近记录了主题为\"{{ ticket.title }}\"的工单. 此邮件是要告知您解决方案.\r\n\r\n工单添加了以下解决方案 {{ ticket.ticket }}:\r\n\r\n{{ resolution }}\r\n\r\n请您确认下此解决方案是否解决了您的问题, 这样我们可以关闭此工单? 如果有更多问题或者认为方案不够充分,, 请继续使用邮件的主题回复此邮件.\r\n\r\n如果您想在线查看, 可以访问 {{ ticket.ticket_url }}\r\n\r\n",
|
||||||
|
"heading": "您的 工单 已经 解决",
|
||||||
|
"subject": "(解决)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 110,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "updated_cc",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">温馨提示, {{ ticket.submitter_email }} 的工单 {{ ticket.ticket }} (\"{{ ticket.title }}\") 已经更新.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">\r\n<b>工单 ID</b>: {{ ticket.ticket }}<br>\r\n<b>待办</b>: {{ queue.title }}<br>\r\n<b>标题</b>: {{ ticket.title }}<br>\r\n<b>已打开</b>: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}<br>\r\n<b>提交人</b>: {{ ticket.submitter_email|default:\"Unknown\" }}<br>\r\n<b>优先级</b>: {{ ticket.get_priority_display }}<br>\r\n<b>状态</b>: {{ ticket.get_status }}<br>\r\n<b>已分配给</b>: {{ ticket.get_assigned_to }}<br>\r\n<b><a href='{{ ticket.staff_url }}'>在线查看</a></b> 更新此工单 (需要登录)</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">原工单描述参考::</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.description|linebreaksbr }}</blockquote>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">已添加以下评论:</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ comment }}</blockquote>\r\n\r\n<p style=\"font-family: Tahoma, Arial, sans-serif; font-size: 11pt;\">本信息 {% if private %} 还没有 {% else %} 已经 {% endif %} 邮件发送给提交者.</p>",
|
||||||
|
"plain_text": "您好,\r\n\r\n温馨提示, 提交者{{ ticket.submitter_email }}的工单{{ ticket.ticket }} 已经更新.\r\n\r\n工单 ID: {{ ticket.ticket }}\r\n待办: {{ queue.title }}\r\n标题: {{ ticket.title }}\r\n已打开: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}\r\n提交人: {{ ticket.submitter_email|default:\"Unknown\" }}\r\n优先级:{{ ticket.get_priority_display }}\r\n状态: {{ ticket.get_status }}\r\n已分配给: {{ ticket.get_assigned_to }}\r\n在线查看: {{ ticket.staff_url }} (需要登录)\r\n\r\n原始描述:\r\n\r\n{{ ticket.description }}\r\n\r\n已添加以下评论:\r\n\r\n{{ comment }}\r\n\r\n本信息 {% if private %}还没有{% else %} 已经 {% endif %} 邮件发送给提交者.\r\n\r\n如果您想在线查看, 可以访问 {{ ticket.staff_url }}.\r\n\r\n",
|
||||||
|
"heading": "工单已更新",
|
||||||
|
"subject": "(已更新)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 111,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "updated_owner",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">温馨提示, 分配给您,提交者{{ ticket.submitter_email }}的工单{{ ticket.ticket }}, 已经更新.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">\r\n<b>工单 ID</b>: {{ ticket.ticket }}<br>\r\n<b>待办</b>: {{ queue.title }}<br>\r\n<b>标题</b>: {{ ticket.title }}<br>\r\n<b>已打开</b>: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}<br>\r\n<b>提交人</b>: {{ ticket.submitter_email|default:\"Unknown\" }}<br>\r\n<b>优先级</b>: {{ ticket.get_priority_display }}<br>\r\n<b>状态</b>: {{ ticket.get_status }}<br>\r\n<b>已分配给</b>: {{ ticket.get_assigned_to }}<br>\r\n<b><a href='{{ ticket.staff_url }}'>在线查看</a></b> 更新此工单 (需要登录)</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">原工单描述参考::</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ ticket.description|linebreaksbr }}</blockquote>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">已添加以下评论:</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ comment }}</blockquote>\r\n\r\n<p style=\"font-family: Tahoma, Arial, sans-serif; font-size: 11pt;\">本信息 {% if private %} 还未 {% else %} 已经 {% endif %} been 邮件发送给提交者.</p>",
|
||||||
|
"plain_text": "您好,\r\n\r\n温馨提示, 提交者分配给{{ ticket.submitter_email }} 您的工单 {{ ticket.ticket }} (\"{{ ticket.title }}\") , 已经更新.\r\n\r\n工单 ID: {{ ticket.ticket }}\r\n待办: {{ queue.title }}\r\n标题: {{ ticket.title }}\r\n已打开: {{ ticket.created|date:\"l N jS Y, \\a\\t P\" }}\r\n提交人: {{ ticket.submitter_email|default:\"Unknown\" }}\r\n优先级:{{ ticket.get_priority_display }}\r\n状态: {{ ticket.get_status }}\r\n已分配给: {{ ticket.get_assigned_to }}\r\n在线查看: {{ ticket.staff_url }} (需要登录)\r\n\r\n原始描述:\r\n\r\n{{ ticket.description }}\r\n\r\n添加了一下评论:\r\n\r\n{{ comment }}\r\n\r\n本信息 {% if private %}还没有 {% endif %} 邮件发送给提交者.\r\n\r\n如果您想在线查看, 可以访问 {{ ticket.staff_url }}\r\n\r\n",
|
||||||
|
"heading": "工单已更新",
|
||||||
|
"subject": "(已更新)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pk": 112,
|
||||||
|
"model": "helpdesk.emailtemplate",
|
||||||
|
"fields": {
|
||||||
|
"template_name": "updated_submitter",
|
||||||
|
"html": "<p style=\"font-family: sans-serif; font-size: 1em;\">您好,</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">您最近记录了主题为<i>{{ ticket.title }}</i>的工单. 此邮件是告知您工单的更新.</p>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">工单添加了以下评论 <b>{{ ticket.ticket }}</b>:</p>\r\n\r\n<blockquote style=\"font-family: sans-serif; font-size: 1em;\">{{ comment }}</blockquote>\r\n\r\n<p style=\"font-family: sans-serif; font-size: 1em;\">如果你需要提供更多信息, 请继续使用邮件的主题回复此邮件. 或者您可以在线查看和更新此工单 <a href=\"{{ ticket.ticket_url }}\">{{ ticket.ticket_url }}</a>.</p>",
|
||||||
|
"plain_text": "您好,\r\n\r\n您最近记录了主题为\"{{ ticket.title }}\"的工单. 此邮件是告知您工单的更新.\r\n\r\n工单添加了以下评论 {{ ticket.ticket }}:\r\n\r\n{{ comment }}\r\n\r\n如果你需要提供更多信息, 请继续使用邮件的主题回复此邮件. 或者您可以在线查看和更新此工单 {{ ticket.ticket_url }}\r\n\r\n",
|
||||||
|
"heading": "您的工单已经更新",
|
||||||
|
"subject": "(已更新)",
|
||||||
|
"locale": "zh"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
@ -267,13 +267,14 @@ def text_is_spam(text, request):
|
|||||||
# False if it is not spam. If it cannot be checked for some reason, we
|
# False if it is not spam. If it cannot be checked for some reason, we
|
||||||
# assume it isn't spam.
|
# assume it isn't spam.
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
try:
|
try:
|
||||||
from helpdesk.akismet import Akismet
|
from helpdesk.akismet import Akismet
|
||||||
except:
|
except ImportError:
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
site = Site.objects.get_current()
|
site = Site.objects.get_current()
|
||||||
except:
|
except ImproperlyConfigured:
|
||||||
site = Site(domain='configure-django-sites.com')
|
site = Site(domain='configure-django-sites.com')
|
||||||
|
|
||||||
ak = Akismet(
|
ak = Akismet(
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
helpdesk/locale/zh_Hans/LC_MESSAGES/django.mo
Normal file
BIN
helpdesk/locale/zh_Hans/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
2394
helpdesk/locale/zh_Hans/LC_MESSAGES/django.po
Normal file
2394
helpdesk/locale/zh_Hans/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,8 @@ scripts/get_email.py - Designed to be run from cron, this script checks the
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
import base64
|
||||||
|
import binascii
|
||||||
import email
|
import email
|
||||||
import imaplib
|
import imaplib
|
||||||
import mimetypes
|
import mimetypes
|
||||||
@ -21,10 +23,12 @@ from os.path import isfile, join
|
|||||||
import poplib
|
import poplib
|
||||||
import re
|
import re
|
||||||
import socket
|
import socket
|
||||||
import base64
|
import ssl
|
||||||
import binascii
|
import sys
|
||||||
from time import ctime
|
from time import ctime
|
||||||
|
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
from email_reply_parser import EmailReplyParser
|
from email_reply_parser import EmailReplyParser
|
||||||
|
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
@ -158,7 +162,17 @@ def process_queue(q, logger):
|
|||||||
messagesInfo = server.list()[1]
|
messagesInfo = server.list()[1]
|
||||||
logger.info("Received %d messages from POP3 server" % len(messagesInfo))
|
logger.info("Received %d messages from POP3 server" % len(messagesInfo))
|
||||||
|
|
||||||
for msg in messagesInfo:
|
for msgRaw in messagesInfo:
|
||||||
|
if six.PY3 and type(msgRaw) is bytes:
|
||||||
|
# in py3, msgRaw may be a bytes object, decode to str
|
||||||
|
try:
|
||||||
|
msg = msgRaw.decode("utf-8")
|
||||||
|
except UnicodeError:
|
||||||
|
# if couldn't decode easily, just leave it raw
|
||||||
|
msg = msgRaw
|
||||||
|
else:
|
||||||
|
# already a str
|
||||||
|
msg = msgRaw
|
||||||
msgNum = msg.split(" ")[0]
|
msgNum = msg.split(" ")[0]
|
||||||
logger.info("Processing message %s" % msgNum)
|
logger.info("Processing message %s" % msgNum)
|
||||||
|
|
||||||
@ -189,11 +203,20 @@ def process_queue(q, logger):
|
|||||||
|
|
||||||
logger.info("Attempting IMAP server login")
|
logger.info("Attempting IMAP server login")
|
||||||
|
|
||||||
server.login(q.email_box_user or
|
try:
|
||||||
settings.QUEUE_EMAIL_BOX_USER,
|
server.login(q.email_box_user or
|
||||||
q.email_box_pass or
|
settings.QUEUE_EMAIL_BOX_USER,
|
||||||
settings.QUEUE_EMAIL_BOX_PASSWORD)
|
q.email_box_pass or
|
||||||
server.select(q.email_box_imap_folder)
|
settings.QUEUE_EMAIL_BOX_PASSWORD)
|
||||||
|
server.select(q.email_box_imap_folder)
|
||||||
|
except imaplib.IMAP.abort:
|
||||||
|
logger.error("IMAP login failed. Check that the server is accessible and that the username and password are correct.")
|
||||||
|
server.logout()
|
||||||
|
sys.exit()
|
||||||
|
except ssl.SSLError:
|
||||||
|
logger.error("IMAP login failed due to SSL error. This is often due to a timeout. Please check your connection and try again.")
|
||||||
|
server.logout()
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
status, data = server.search(None, 'NOT', 'DELETED')
|
status, data = server.search(None, 'NOT', 'DELETED')
|
||||||
@ -232,7 +255,7 @@ def process_queue(q, logger):
|
|||||||
logger.info("Successfully processed message %d, ticket/comment created." % i)
|
logger.info("Successfully processed message %d, ticket/comment created." % i)
|
||||||
try:
|
try:
|
||||||
unlink(m) # delete message file if ticket was successful
|
unlink(m) # delete message file if ticket was successful
|
||||||
except:
|
except OSError:
|
||||||
logger.error("Unable to delete message %d." % i)
|
logger.error("Unable to delete message %d." % i)
|
||||||
else:
|
else:
|
||||||
logger.info("Successfully deleted message %d." % i)
|
logger.info("Successfully deleted message %d." % i)
|
||||||
@ -245,7 +268,7 @@ def decodeUnknown(charset, string):
|
|||||||
if not charset:
|
if not charset:
|
||||||
try:
|
try:
|
||||||
return string.decode('utf-8', 'replace')
|
return string.decode('utf-8', 'replace')
|
||||||
except:
|
except UnicodeError:
|
||||||
return string.decode('iso8859-1', 'replace')
|
return string.decode('iso8859-1', 'replace')
|
||||||
return unicode(string, charset)
|
return unicode(string, charset)
|
||||||
elif six.PY3:
|
elif six.PY3:
|
||||||
@ -253,7 +276,7 @@ def decodeUnknown(charset, string):
|
|||||||
if not charset:
|
if not charset:
|
||||||
try:
|
try:
|
||||||
return str(string, encoding='utf-8', errors='replace')
|
return str(string, encoding='utf-8', errors='replace')
|
||||||
except:
|
except UnicodeError:
|
||||||
return str(string, encoding='iso8859-1', errors='replace')
|
return str(string, encoding='iso8859-1', errors='replace')
|
||||||
return str(string, encoding=charset, errors='replace')
|
return str(string, encoding=charset, errors='replace')
|
||||||
return string
|
return string
|
||||||
@ -344,10 +367,15 @@ def ticket_from_message(message, queue, logger):
|
|||||||
if isinstance(payload, list):
|
if isinstance(payload, list):
|
||||||
payload = payload.pop().as_string()
|
payload = payload.pop().as_string()
|
||||||
payloadToWrite = payload
|
payloadToWrite = payload
|
||||||
|
# check version of python to ensure use of only the correct error type
|
||||||
|
if six.PY2:
|
||||||
|
non_b64_err = binascii.Error
|
||||||
|
else:
|
||||||
|
non_b64_err = TypeError
|
||||||
try:
|
try:
|
||||||
logger.debug("Try to base64 decode the attachment payload")
|
logger.debug("Try to base64 decode the attachment payload")
|
||||||
payloadToWrite = base64.decodestring(payload)
|
payloadToWrite = base64.decodestring(payload)
|
||||||
except (binascii.Error, TypeError):
|
except non_b64_err:
|
||||||
logger.debug("Payload was not base64 encoded, using raw bytes")
|
logger.debug("Payload was not base64 encoded, using raw bytes")
|
||||||
payloadToWrite = payload
|
payloadToWrite = payload
|
||||||
files.append(SimpleUploadedFile(name, part.get_payload(decode=True), mimetypes.guess_type(name)[0]))
|
files.append(SimpleUploadedFile(name, part.get_payload(decode=True), mimetypes.guess_type(name)[0]))
|
||||||
@ -356,7 +384,12 @@ def ticket_from_message(message, queue, logger):
|
|||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
if not body:
|
if not body:
|
||||||
body = _('No plain-text email body available. Please see attachment "email_html_body.html".')
|
mail = BeautifulSoup(part.get_payload(), "lxml")
|
||||||
|
if ">" in mail.text:
|
||||||
|
message_body = mail.text.split(">")[1]
|
||||||
|
body = message_body.encode('ascii', errors='ignore')
|
||||||
|
else:
|
||||||
|
body = mail.text
|
||||||
|
|
||||||
if ticket:
|
if ticket:
|
||||||
try:
|
try:
|
||||||
|
@ -526,10 +526,11 @@ class Ticket(models.Model):
|
|||||||
a URL to the submitter of a ticket.
|
a URL to the submitter of a ticket.
|
||||||
"""
|
"""
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
try:
|
try:
|
||||||
site = Site.objects.get_current()
|
site = Site.objects.get_current()
|
||||||
except:
|
except ImproperlyConfigured:
|
||||||
site = Site(domain='configure-django-sites.com')
|
site = Site(domain='configure-django-sites.com')
|
||||||
return u"http://%s%s?ticket=%s&email=%s" % (
|
return u"http://%s%s?ticket=%s&email=%s" % (
|
||||||
site.domain,
|
site.domain,
|
||||||
@ -545,10 +546,11 @@ class Ticket(models.Model):
|
|||||||
a staff member (in emails etc)
|
a staff member (in emails etc)
|
||||||
"""
|
"""
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
try:
|
try:
|
||||||
site = Site.objects.get_current()
|
site = Site.objects.get_current()
|
||||||
except:
|
except ImproperlyConfigured:
|
||||||
site = Site(domain='configure-django-sites.com')
|
site = Site(domain='configure-django-sites.com')
|
||||||
return u"http://%s%s" % (
|
return u"http://%s%s" % (
|
||||||
site.domain,
|
site.domain,
|
||||||
@ -1149,6 +1151,7 @@ def create_usersettings(sender, instance, created, **kwargs):
|
|||||||
if created:
|
if created:
|
||||||
UserSettings.objects.create(user=instance, settings=DEFAULT_USER_SETTINGS)
|
UserSettings.objects.create(user=instance, settings=DEFAULT_USER_SETTINGS)
|
||||||
|
|
||||||
|
|
||||||
models.signals.post_save.connect(create_usersettings, sender=settings.AUTH_USER_MODEL)
|
models.signals.post_save.connect(create_usersettings, sender=settings.AUTH_USER_MODEL)
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ from django.core.exceptions import ImproperlyConfigured
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
DEFAULT_USER_SETTINGS = settings.HELPDESK_DEFAULT_SETTINGS
|
DEFAULT_USER_SETTINGS = settings.HELPDESK_DEFAULT_SETTINGS
|
||||||
except:
|
except AttributeError:
|
||||||
DEFAULT_USER_SETTINGS = None
|
DEFAULT_USER_SETTINGS = None
|
||||||
|
|
||||||
if not isinstance(DEFAULT_USER_SETTINGS, dict):
|
if not isinstance(DEFAULT_USER_SETTINGS, dict):
|
||||||
|
@ -21,5 +21,6 @@ from django import template
|
|||||||
def in_list(value, arg):
|
def in_list(value, arg):
|
||||||
return value in (arg or [])
|
return value in (arg or [])
|
||||||
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
register.filter(in_list)
|
register.filter(in_list)
|
||||||
|
@ -19,5 +19,6 @@ def load_helpdesk_settings(request):
|
|||||||
print(e, file=sys.stderr)
|
print(e, file=sys.stderr)
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
register.filter('load_helpdesk_settings', load_helpdesk_settings)
|
register.filter('load_helpdesk_settings', load_helpdesk_settings)
|
||||||
|
@ -22,5 +22,6 @@ def saved_queries(user):
|
|||||||
print(e, file=sys.stderr)
|
print(e, file=sys.stderr)
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
register.filter('saved_queries', saved_queries)
|
register.filter('saved_queries', saved_queries)
|
||||||
|
@ -42,5 +42,6 @@ def num_to_link(text):
|
|||||||
text[:match.start() + 1], url, style, match.groups()[0], text[match.end():])
|
text[:match.start() + 1], url, style, match.groups()[0], text[match.end():])
|
||||||
return mark_safe(text)
|
return mark_safe(text)
|
||||||
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
register.filter(num_to_link)
|
register.filter(num_to_link)
|
||||||
|
@ -24,5 +24,6 @@ def user_admin_url(action):
|
|||||||
user._meta.app_label, model_name,
|
user._meta.app_label, model_name,
|
||||||
action)
|
action)
|
||||||
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
register.filter(user_admin_url)
|
register.filter(user_admin_url)
|
||||||
|
@ -355,6 +355,251 @@ class GetEmailParametricTemplate(object):
|
|||||||
self.assertEqual(attach2.followup.id, 2)
|
self.assertEqual(attach2.followup.id, 2)
|
||||||
self.assertEqual(attach2.filename, 'email_html_body.html')
|
self.assertEqual(attach2.filename, 'email_html_body.html')
|
||||||
|
|
||||||
|
def test_read_pgp_signed_email(self):
|
||||||
|
"""Tests reading a PGP signed email to ensure we handle base64
|
||||||
|
and PGP signatures appropriately."""
|
||||||
|
|
||||||
|
# example email text from #567 on GitHub
|
||||||
|
test_email = """Delivered-To: djangohelpdesk@example.com
|
||||||
|
Received: by 10.25.26.207 with SMTP id a198csp5858981lfa;
|
||||||
|
Wed, 8 Nov 2017 13:30:22 -0800 (PST)
|
||||||
|
X-Received: by 10.107.107.3 with SMTP id g3mr2603398ioc.250.1510176622046;
|
||||||
|
Wed, 08 Nov 2017 13:30:22 -0800 (PST)
|
||||||
|
ARC-Seal: i=2; a=rsa-sha256; t=1510176621; cv=pass;
|
||||||
|
d=google.com; s=arc-20160816;
|
||||||
|
b=qQ8kBj8+yIoWcJwFNHUlJDYz7P2NfILAxFsn9uPYzXNn/aRw695T1aNFgGL75KUhkA
|
||||||
|
nDw+h49SUGKDh9ehC+DEiPjwJIxAoz+86rqGWV6XPGW4gQ7GUkHs96CxWndTSD0hdcOl
|
||||||
|
vygeZrsgzpIOvDxJWrujDPZzcEjsPC2qy3KGsTqtbZGEsNhhRUD8rs/hBVVXaGBatLF+
|
||||||
|
Sz2krwBZz8Lm+mWRhScjmF12QIHcXe6qYrDLOLEK0+bRkRMS+ZXg9+GPwqHlp58GaHn+
|
||||||
|
6JncesW3q7k88RQsLlj/8PEw0z1wMndgBVWIcCEtLt4UhZtt/BDxmZSukNN0SzoH4e3k
|
||||||
|
mxOw==
|
||||||
|
ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
|
||||||
|
h=mime-version:user-agent:date:message-id:subject:from:to
|
||||||
|
:dkim-signature:arc-authentication-results:arc-message-signature
|
||||||
|
:arc-authentication-results;
|
||||||
|
bh=cQvDBdivwtDmp1Td9ZWaEf0S4IuZ4hPwaprxSv7XZuE=;
|
||||||
|
b=p/0Y4PgvEfGWZ8W3eqxzRnSGLbT9gObSU2OI/sLwiN4KFfVmGrBJYkx7DGija0A5eU
|
||||||
|
DBbETW/16pib+W0IOUtdD7Pt12oWA3Z/uRf7ybXnHIKZ+MObdCXqRJFkga6nY8tWD0H3
|
||||||
|
maquQR07Q54mYslVMEIKJUKJzVM86npLN2C756ZzZTXiGXf33iowO4/lciGmTAgi+y5p
|
||||||
|
fEDQCTMoSQ9iGbquFRgNHgMtIM5NWjeMksWKpnfbvZyKs0ZICcPklNxQkDCmDlrOBokT
|
||||||
|
Zs1RVsWZ7NyPdTomJ0SRyPeysM040aatmnwxFAzwe4GYFNUWZjaep7uPKKlZ4sV/aHBB
|
||||||
|
iHOQ==
|
||||||
|
ARC-Authentication-Results: i=2; mx.google.com;
|
||||||
|
dkim=pass header.i=@gmail.com header.s=20161025 header.b=AArzbi/1;
|
||||||
|
arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com);
|
||||||
|
spf=pass (google.com: domain of bugreporter@example.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=bugreporter@example.com;
|
||||||
|
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gmail.com
|
||||||
|
Return-Path: <bugreporter@example.com>
|
||||||
|
Received: from mail-sor-f41.google.com (mail-sor-f41.google.com. [209.85.220.41])
|
||||||
|
by mx.google.com with SMTPS id i86sor2420323ioo.204.2017.11.08.13.30.21
|
||||||
|
for <djangohelpdesk@example.com>
|
||||||
|
(Google Transport Security);
|
||||||
|
Wed, 08 Nov 2017 13:30:21 -0800 (PST)
|
||||||
|
Received-SPF: pass (google.com: domain of bugreporter@example.com designates 209.85.220.41 as permitted sender) client-ip=209.85.220.41;
|
||||||
|
Authentication-Results: mx.google.com;
|
||||||
|
dkim=pass header.i=@gmail.com header.s=20161025 header.b=AArzbi/1;
|
||||||
|
arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com);
|
||||||
|
spf=pass (google.com: domain of bugreporter@example.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=bugreporter@example.com;
|
||||||
|
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gmail.com
|
||||||
|
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||||
|
d=1e100.net; s=20161025;
|
||||||
|
h=x-gm-message-state:dkim-signature:to:from:subject:message-id:date
|
||||||
|
:user-agent:mime-version;
|
||||||
|
bh=cQvDBdivwtDmp1Td9ZWaEf0S4IuZ4hPwaprxSv7XZuE=;
|
||||||
|
b=MCiZzHu6ZV3kMTQBRL/b5uBy4jbHFS97+z9apL239dYS+z0LlTiHpKbs3qohFe3As1
|
||||||
|
gu2l0SAcdGw0qeplgmOlX9HXvKetBRLldfHeX/JJZ2yokpjc6CxVT8gF8YP2UmfAs0cb
|
||||||
|
JI8TTDqiWmhayf7xfblRIUP7vfwyTH9cLmvKMMAqWvrppyUlqlxWgyO7xtzV9jdThpqP
|
||||||
|
O0jO9CqsRmbEDc4vZAtOTXm1O69jCz66oll6H4T5Nka9HUpyHFZzv7Z0j0F/5djfzjCQ
|
||||||
|
HCFZhzobEgZAmBC9o2Y5aDvKCnWJGR5kVTtBQaFCuxr57o4zq0D359V3gMMPRGMdujDP
|
||||||
|
hXAQ==
|
||||||
|
X-Google-Smtp-Source: ABhQp+SbAIRuabSw2EkD+7YFXtLiCFINtymAshxVYuNZhApd39ymv2m9UnIM3rZNIHonQBywtZ3VjalQxeN8lVuWD6OquEskEc8=
|
||||||
|
ARC-Seal: i=1; a=rsa-sha256; t=1510176621; cv=none;
|
||||||
|
d=google.com; s=arc-20160816;
|
||||||
|
b=mOqnqVV4oq14hoOdEA+yVvQYQd/sv/Qr//xmW6r94dKaUczdbFG+Uy8x7EbuF/ILJt
|
||||||
|
ByFmE8+HUH8tosfHn8+zFmsHFr3Wi7il64wdeuVqoOuDQS1HejcH9ln5LVjwsr7EE6Ly
|
||||||
|
6gCT7QupvSQ+FkhyNH+zNHuGztw5F4Sa2r5UlmR5VAJ4+V1MEfVYwzEr7vgPnmEj8jga
|
||||||
|
PtmD05EfYWrWt27Cw8oS+CgS0CNcHaaiRr7JX3EQbNRrLp5M9GjKhiq/ckt2a5NKJYMH
|
||||||
|
zISYQzxk7EgHGFrwn+JZx+oKqG3Zl2pd5oKmzJkFeSaGT+qYp3SES4z3Vi6z4VxGduox
|
||||||
|
f38g==
|
||||||
|
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
|
||||||
|
h=mime-version:user-agent:date:message-id:subject:from:to
|
||||||
|
:dkim-signature:arc-authentication-results;
|
||||||
|
bh=cQvDBdivwtDmp1Td9ZWaEf0S4IuZ4hPwaprxSv7XZuE=;
|
||||||
|
b=R5FsED2qOoEJshMotswEPOAn8GyvaHHd4zM9wAH+qnzuoV9RFhSChbkAkypi73SPs/
|
||||||
|
D7K49dYKSfsuWPF1RXoD8qchVfROF5Y7kD0JHy7KJcuHXzwb5gYLNrZpB2R9XbBOGe1j
|
||||||
|
lgQvnEVwmgeJiLXKQVeQDECxs8DFlkIpPIbmJK02Ry/Q0S8TnBEs0mrWn49l70IsZB6U
|
||||||
|
0XCpUPAt9NhsIUxoZKZv+zOwpQq6uwJkqRa5ukH0OPRr891MpeZldw7+gINjxxEmPAS9
|
||||||
|
GYfMeCpX9afFbQMUizbUbKwOZPt7ahn3x1C5x4AwgQmtzXYfA/quyiXAukTzoYk8FUqs
|
||||||
|
U1QA==
|
||||||
|
ARC-Authentication-Results: i=1; gmr-mx.google.com;
|
||||||
|
dkim=pass header.i=@gmail.com header.s=20161025 header.b=AArzbi/1;
|
||||||
|
spf=pass (google.com: domain of bugreporter@example.com designates 2607:f8b0:400e:c00::233 as permitted sender) smtp.mailfrom=bugreporter@example.com;
|
||||||
|
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gmail.com
|
||||||
|
Return-Path: <bugreporter@example.com>
|
||||||
|
Received: from mail-pf0-x233.google.com (mail-pf0-x233.google.com. [2607:f8b0:400e:c00::233])
|
||||||
|
by gmr-mx.google.com with ESMTPS id l10si463482ioc.2.2017.11.08.13.30.21
|
||||||
|
for <djangohelpdesk@example.com>
|
||||||
|
(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);
|
||||||
|
Wed, 08 Nov 2017 13:30:21 -0800 (PST)
|
||||||
|
Received-SPF: pass (google.com: domain of bugreporter@example.com designates 2607:f8b0:400e:c00::233 as permitted sender) client-ip=2607:f8b0:400e:c00::233;
|
||||||
|
Received: by mail-pf0-x233.google.com with SMTP id p87so2672006pfj.3
|
||||||
|
for <djangohelpdesk@example.com>; Wed, 08 Nov 2017 13:30:21 -0800 (PST)
|
||||||
|
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||||
|
d=gmail.com; s=20161025;
|
||||||
|
h=to:from:subject:message-id:date:user-agent:mime-version;
|
||||||
|
bh=cQvDBdivwtDmp1Td9ZWaEf0S4IuZ4hPwaprxSv7XZuE=;
|
||||||
|
b=AArzbi/1RXhgTnCQBzU6vCwndc0/vqLV9FCgiOTp3deq8kFYhtdJCaEBX9s7iJduV+
|
||||||
|
HobvLGsbmWU04Y1O3w8m4jyq5H4HJ1jAr1+i0Tf5jl264kmyu4eowOMkwIFo6UaSVQ/a
|
||||||
|
zP+EYW09fWSSNhljubLkGf62vZ9gD/RF5Awoady6u5/N1GU4GPVCEgsmiK7DmPB2EtSE
|
||||||
|
7YPz3o9l+kDy8bRnUFw0744B7VKiXrAcIqpfltJuItM4T7bS/jyjYMQbRn8W2MXpyGlI
|
||||||
|
LNwt3vUNdKtkcPTK54cs44HMaVA8wGCDaMHFP8JmoTKWSsOgZQja3cdEj/rooM8uz+dq
|
||||||
|
er5g==
|
||||||
|
X-Received: by 10.99.191.78 with SMTP id i14mr1746749pgo.220.1510176620834;
|
||||||
|
Wed, 08 Nov 2017 13:30:20 -0800 (PST)
|
||||||
|
Return-Path: <bugreporter@example.com>
|
||||||
|
Received: from [10.1.1.4] (d114-72-199-247.hum1.act.optusnet.com.au. [114.72.199.247])
|
||||||
|
by smtp.gmail.com with ESMTPSA id u131sm8656745pgc.89.2017.11.08.13.30.18
|
||||||
|
for <djangohelpdesk@example.com>
|
||||||
|
(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);
|
||||||
|
Wed, 08 Nov 2017 13:30:19 -0800 (PST)
|
||||||
|
To: djangohelpdesk@example.com
|
||||||
|
From: Bug Reporter <bugreporter@example.com>
|
||||||
|
Subject: example email that crashes django-helpdesk get_email
|
||||||
|
Message-ID: <8eef2077-8aff-9fb4-0e2a-9876ba2530b1@gmail.com>
|
||||||
|
Date: Thu, 9 Nov 2017 08:30:15 +1100
|
||||||
|
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
|
||||||
|
Thunderbird/52.4.0
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: multipart/signed; micalg=pgp-sha256;
|
||||||
|
protocol="application/pgp-signature";
|
||||||
|
boundary="vnaePdRl5oElllhQPTiU2WarPFVGINT69"
|
||||||
|
|
||||||
|
This is an OpenPGP/MIME signed message (RFC 4880 and 3156)
|
||||||
|
--vnaePdRl5oElllhQPTiU2WarPFVGINT69
|
||||||
|
Content-Type: multipart/mixed; boundary="ckOQ1U5bPjO3W1sVnjdBaEigXBiwem2Rn";
|
||||||
|
protected-headers="v1"
|
||||||
|
From: Bug Reporter <bugreporter@example.com>
|
||||||
|
To: djangohelpdesk@example.com
|
||||||
|
Message-ID: <8eef2077-8aff-9fb4-0e2a-9876ba2530b1@gmail.com>
|
||||||
|
Subject: example email that crashes django-helpdesk get_email
|
||||||
|
|
||||||
|
--ckOQ1U5bPjO3W1sVnjdBaEigXBiwem2Rn
|
||||||
|
Content-Type: text/plain; charset=utf-8
|
||||||
|
Content-Transfer-Encoding: quoted-printable
|
||||||
|
Content-Language: en-US
|
||||||
|
|
||||||
|
hi, thanks for looking into this :)
|
||||||
|
|
||||||
|
https://github.com/django-helpdesk/django-helpdesk/issues/567#issuecommen=
|
||||||
|
t-342954233
|
||||||
|
|
||||||
|
|
||||||
|
--ckOQ1U5bPjO3W1sVnjdBaEigXBiwem2Rn--
|
||||||
|
|
||||||
|
--vnaePdRl5oElllhQPTiU2WarPFVGINT69
|
||||||
|
Content-Type: application/pgp-signature; name="signature.asc"
|
||||||
|
Content-Description: OpenPGP digital signature
|
||||||
|
Content-Disposition: attachment; filename="signature.asc"
|
||||||
|
|
||||||
|
-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
iQIcBAEBCAAGBQJaA3dnAAoJELBLc7QPITnLN54P/3Zsu7+AIQWDFTvziJfCqswG
|
||||||
|
u99fG+iWa6ER+iuZG0YU1BdIxIjSKt1pvqB0yXITlT9FCdf1zc0pmeJ08I0a5pVa
|
||||||
|
iaym5prVUro5BNQ6Vqoo0jvOCKNrACtFNv85zDzXbPNP8TrUss41U+ackPHkOHov
|
||||||
|
cmJ5YZFQebYXXpibFSIDimVGfwI57vyTWvolttZFLSI1mgGX7MvHaKh253QLdXIo
|
||||||
|
EUih40rOw3f/nYPEKyW8QA72ImBsZdcZI5buiiCC1bgMkKSFSNAFiIanYEpGNMnO
|
||||||
|
3zYKBpbpBhnWSi5orwx47/v4/Yb/qVr5ppuV23+YoMfEGT8cHPTAdYpnpE27ByAv
|
||||||
|
jvpxKEwmkUzD1WxOmQdCcPJPyWz1OBUVvjj0nn0Espnz8V8esl9+IFs739lpFBHu
|
||||||
|
fWWA315LTmIJMGH5Ujf4myiQeXDo6Gsy6WhE13q7MKTq3tnyi5dJG9GJCBf646dL
|
||||||
|
RwcDf9O7MvKSV2kSPmryLnUF7D+2fva+Cy+CvJDVJCo5zr4ucXPXZ4htpI6Pjpd5
|
||||||
|
oPHvbqxSCMJrQ7eAFTYmBNGauSyr0XvGM1qmHBZD/laQEJHYgLT2ILrymZhVDHtK
|
||||||
|
W7tXhGjMoUvqAxiKkmG3UHFqN4k3EYo13PwoOWyJHD1M9ArbX/Sk9l8DDguCh3DW
|
||||||
|
a9eiiQ+3V1v+7wWHXCzq
|
||||||
|
=6JeP
|
||||||
|
-----END PGP SIGNATURE-----
|
||||||
|
|
||||||
|
--vnaePdRl5oElllhQPTiU2WarPFVGINT69--
|
||||||
|
|
||||||
|
"""
|
||||||
|
test_mail_len = len(test_email)
|
||||||
|
|
||||||
|
if self.socks:
|
||||||
|
from socks import ProxyConnectionError
|
||||||
|
with self.assertRaisesRegexp(ProxyConnectionError, '%s:%s' % (unrouted_socks_server, unused_port)):
|
||||||
|
call_command('get_email')
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Test local email reading
|
||||||
|
if self.method == 'local':
|
||||||
|
with mock.patch('helpdesk.management.commands.get_email.listdir') as mocked_listdir, \
|
||||||
|
mock.patch('helpdesk.management.commands.get_email.isfile') as mocked_isfile, \
|
||||||
|
mock.patch('builtins.open' if six.PY3 else '__builtin__.open', mock.mock_open(read_data=test_email)):
|
||||||
|
mocked_isfile.return_value = True
|
||||||
|
mocked_listdir.return_value = ['filename1']
|
||||||
|
|
||||||
|
call_command('get_email')
|
||||||
|
|
||||||
|
mocked_listdir.assert_called_with('/var/lib/mail/helpdesk/')
|
||||||
|
mocked_isfile.assert_any_call('/var/lib/mail/helpdesk/filename1')
|
||||||
|
|
||||||
|
elif self.method == 'pop3':
|
||||||
|
# mock poplib.POP3's list and retr methods to provide responses as per RFC 1939
|
||||||
|
pop3_emails = {
|
||||||
|
'1': ("+OK", test_email.split('\n')),
|
||||||
|
}
|
||||||
|
pop3_mail_list = ("+OK 1 message", ("1 %d" % test_mail_len))
|
||||||
|
mocked_poplib_server = mock.Mock()
|
||||||
|
mocked_poplib_server.list = mock.Mock(return_value=pop3_mail_list)
|
||||||
|
mocked_poplib_server.retr = mock.Mock(side_effect=lambda x: pop3_emails['1'])
|
||||||
|
with mock.patch('helpdesk.management.commands.get_email.poplib', autospec=True) as mocked_poplib:
|
||||||
|
mocked_poplib.POP3 = mock.Mock(return_value=mocked_poplib_server)
|
||||||
|
call_command('get_email')
|
||||||
|
|
||||||
|
elif self.method == 'imap':
|
||||||
|
# mock imaplib.IMAP4's search and fetch methods with responses from RFC 3501
|
||||||
|
imap_emails = {
|
||||||
|
"1": ("OK", (("1", test_email),)),
|
||||||
|
}
|
||||||
|
imap_mail_list = ("OK", ("1",))
|
||||||
|
mocked_imaplib_server = mock.Mock()
|
||||||
|
mocked_imaplib_server.search = mock.Mock(return_value=imap_mail_list)
|
||||||
|
|
||||||
|
# we ignore the second arg as the data item/mime-part is constant (RFC822)
|
||||||
|
mocked_imaplib_server.fetch = mock.Mock(side_effect=lambda x, _: imap_emails[x])
|
||||||
|
with mock.patch('helpdesk.management.commands.get_email.imaplib', autospec=True) as mocked_imaplib:
|
||||||
|
mocked_imaplib.IMAP4 = mock.Mock(return_value=mocked_imaplib_server)
|
||||||
|
call_command('get_email')
|
||||||
|
|
||||||
|
ticket1 = get_object_or_404(Ticket, pk=1)
|
||||||
|
self.assertEqual(ticket1.ticket_for_url, "QQ-%s" % ticket1.id)
|
||||||
|
self.assertEqual(ticket1.title, "example email that crashes django-helpdesk get_email")
|
||||||
|
self.assertEqual(ticket1.description, """hi, thanks for looking into this :)\n\nhttps://github.com/django-helpdesk/django-helpdesk/issues/567#issuecomment-342954233""")
|
||||||
|
# MIME part should be attached to follow up
|
||||||
|
followup1 = get_object_or_404(FollowUp, pk=1)
|
||||||
|
self.assertEqual(followup1.ticket.id, 1)
|
||||||
|
attach1 = get_object_or_404(Attachment, pk=1)
|
||||||
|
self.assertEqual(attach1.followup.id, 1)
|
||||||
|
self.assertEqual(attach1.filename, 'signature.asc')
|
||||||
|
self.assertEqual(attach1.file.read(), b"""-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
iQIcBAEBCAAGBQJaA3dnAAoJELBLc7QPITnLN54P/3Zsu7+AIQWDFTvziJfCqswG
|
||||||
|
u99fG+iWa6ER+iuZG0YU1BdIxIjSKt1pvqB0yXITlT9FCdf1zc0pmeJ08I0a5pVa
|
||||||
|
iaym5prVUro5BNQ6Vqoo0jvOCKNrACtFNv85zDzXbPNP8TrUss41U+ackPHkOHov
|
||||||
|
cmJ5YZFQebYXXpibFSIDimVGfwI57vyTWvolttZFLSI1mgGX7MvHaKh253QLdXIo
|
||||||
|
EUih40rOw3f/nYPEKyW8QA72ImBsZdcZI5buiiCC1bgMkKSFSNAFiIanYEpGNMnO
|
||||||
|
3zYKBpbpBhnWSi5orwx47/v4/Yb/qVr5ppuV23+YoMfEGT8cHPTAdYpnpE27ByAv
|
||||||
|
jvpxKEwmkUzD1WxOmQdCcPJPyWz1OBUVvjj0nn0Espnz8V8esl9+IFs739lpFBHu
|
||||||
|
fWWA315LTmIJMGH5Ujf4myiQeXDo6Gsy6WhE13q7MKTq3tnyi5dJG9GJCBf646dL
|
||||||
|
RwcDf9O7MvKSV2kSPmryLnUF7D+2fva+Cy+CvJDVJCo5zr4ucXPXZ4htpI6Pjpd5
|
||||||
|
oPHvbqxSCMJrQ7eAFTYmBNGauSyr0XvGM1qmHBZD/laQEJHYgLT2ILrymZhVDHtK
|
||||||
|
W7tXhGjMoUvqAxiKkmG3UHFqN4k3EYo13PwoOWyJHD1M9ArbX/Sk9l8DDguCh3DW
|
||||||
|
a9eiiQ+3V1v+7wWHXCzq
|
||||||
|
=6JeP
|
||||||
|
-----END PGP SIGNATURE-----
|
||||||
|
""")
|
||||||
|
# should this be 'application/pgp-signature'?
|
||||||
|
# self.assertEqual(attach1.mime_type, 'text/plain')
|
||||||
|
|
||||||
|
|
||||||
class GetEmailCCHandling(TestCase):
|
class GetEmailCCHandling(TestCase):
|
||||||
"""TestCase that checks CC handling in email. Needs its own test harness."""
|
"""TestCase that checks CC handling in email. Needs its own test harness."""
|
||||||
|
@ -29,6 +29,7 @@ class DirectTemplateView(TemplateView):
|
|||||||
context[key] = value
|
context[key] = value
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
app_name = 'helpdesk'
|
app_name = 'helpdesk'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
@ -168,6 +168,8 @@ def dashboard(request):
|
|||||||
'all_tickets_reported_by_current_user': all_tickets_reported_by_current_user,
|
'all_tickets_reported_by_current_user': all_tickets_reported_by_current_user,
|
||||||
'basic_ticket_stats': basic_ticket_stats,
|
'basic_ticket_stats': basic_ticket_stats,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
dashboard = staff_member_required(dashboard)
|
dashboard = staff_member_required(dashboard)
|
||||||
|
|
||||||
@helpdesk_staff_member_required
|
@helpdesk_staff_member_required
|
||||||
@ -183,6 +185,8 @@ def delete_ticket(request, ticket_id):
|
|||||||
else:
|
else:
|
||||||
ticket.delete()
|
ticket.delete()
|
||||||
return HttpResponseRedirect(reverse('helpdesk:home'))
|
return HttpResponseRedirect(reverse('helpdesk:home'))
|
||||||
|
|
||||||
|
|
||||||
delete_ticket = staff_member_required(delete_ticket)
|
delete_ticket = staff_member_required(delete_ticket)
|
||||||
|
|
||||||
|
|
||||||
@ -234,6 +238,8 @@ def followup_edit(request, ticket_id, followup_id):
|
|||||||
# delete old followup
|
# delete old followup
|
||||||
followup.delete()
|
followup.delete()
|
||||||
return HttpResponseRedirect(reverse('helpdesk:view', args=[ticket.id]))
|
return HttpResponseRedirect(reverse('helpdesk:view', args=[ticket.id]))
|
||||||
|
|
||||||
|
|
||||||
followup_edit = staff_member_required(followup_edit)
|
followup_edit = staff_member_required(followup_edit)
|
||||||
|
|
||||||
|
|
||||||
@ -248,6 +254,8 @@ def followup_delete(request, ticket_id, followup_id):
|
|||||||
followup = get_object_or_404(FollowUp, id=followup_id)
|
followup = get_object_or_404(FollowUp, id=followup_id)
|
||||||
followup.delete()
|
followup.delete()
|
||||||
return HttpResponseRedirect(reverse('helpdesk:view', args=[ticket.id]))
|
return HttpResponseRedirect(reverse('helpdesk:view', args=[ticket.id]))
|
||||||
|
|
||||||
|
|
||||||
followup_delete = staff_member_required(followup_delete)
|
followup_delete = staff_member_required(followup_delete)
|
||||||
|
|
||||||
|
|
||||||
@ -317,6 +325,8 @@ def view_ticket(request, ticket_id):
|
|||||||
'ticketcc_string': ticketcc_string,
|
'ticketcc_string': ticketcc_string,
|
||||||
'SHOW_SUBSCRIBE': show_subscribe,
|
'SHOW_SUBSCRIBE': show_subscribe,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
view_ticket = staff_member_required(view_ticket)
|
view_ticket = staff_member_required(view_ticket)
|
||||||
|
|
||||||
|
|
||||||
@ -759,6 +769,8 @@ def mass_update(request):
|
|||||||
t.delete()
|
t.delete()
|
||||||
|
|
||||||
return HttpResponseRedirect(reverse('helpdesk:list'))
|
return HttpResponseRedirect(reverse('helpdesk:list'))
|
||||||
|
|
||||||
|
|
||||||
mass_update = staff_member_required(mass_update)
|
mass_update = staff_member_required(mass_update)
|
||||||
|
|
||||||
|
|
||||||
@ -943,6 +955,8 @@ def ticket_list(request):
|
|||||||
saved_query=saved_query,
|
saved_query=saved_query,
|
||||||
search_message=search_message,
|
search_message=search_message,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
ticket_list = staff_member_required(ticket_list)
|
ticket_list = staff_member_required(ticket_list)
|
||||||
|
|
||||||
|
|
||||||
@ -961,6 +975,8 @@ def edit_ticket(request, ticket_id):
|
|||||||
form = EditTicketForm(instance=ticket)
|
form = EditTicketForm(instance=ticket)
|
||||||
|
|
||||||
return render(request, 'helpdesk/edit_ticket.html', {'form': form})
|
return render(request, 'helpdesk/edit_ticket.html', {'form': form})
|
||||||
|
|
||||||
|
|
||||||
edit_ticket = staff_member_required(edit_ticket)
|
edit_ticket = staff_member_required(edit_ticket)
|
||||||
|
|
||||||
|
|
||||||
@ -999,6 +1015,8 @@ def create_ticket(request):
|
|||||||
form.fields['assigned_to'].widget = forms.HiddenInput()
|
form.fields['assigned_to'].widget = forms.HiddenInput()
|
||||||
|
|
||||||
return render(request, 'helpdesk/create_ticket.html', {'form': form})
|
return render(request, 'helpdesk/create_ticket.html', {'form': form})
|
||||||
|
|
||||||
|
|
||||||
create_ticket = staff_member_required(create_ticket)
|
create_ticket = staff_member_required(create_ticket)
|
||||||
|
|
||||||
|
|
||||||
@ -1021,6 +1039,9 @@ def raw_details(request, type):
|
|||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
|
|
||||||
|
raw_details = staff_member_required(raw_details)
|
||||||
|
|
||||||
|
|
||||||
@helpdesk_staff_member_required
|
@helpdesk_staff_member_required
|
||||||
def hold_ticket(request, ticket_id, unhold=False):
|
def hold_ticket(request, ticket_id, unhold=False):
|
||||||
ticket = get_object_or_404(Ticket, id=ticket_id)
|
ticket = get_object_or_404(Ticket, id=ticket_id)
|
||||||
@ -1048,14 +1069,22 @@ def hold_ticket(request, ticket_id, unhold=False):
|
|||||||
return HttpResponseRedirect(ticket.get_absolute_url())
|
return HttpResponseRedirect(ticket.get_absolute_url())
|
||||||
|
|
||||||
|
|
||||||
|
hold_ticket = staff_member_required(hold_ticket)
|
||||||
|
|
||||||
|
|
||||||
@helpdesk_staff_member_required
|
@helpdesk_staff_member_required
|
||||||
def unhold_ticket(request, ticket_id):
|
def unhold_ticket(request, ticket_id):
|
||||||
return hold_ticket(request, ticket_id, unhold=True)
|
return hold_ticket(request, ticket_id, unhold=True)
|
||||||
|
|
||||||
|
|
||||||
|
unhold_ticket = staff_member_required(unhold_ticket)
|
||||||
|
|
||||||
|
|
||||||
@helpdesk_staff_member_required
|
@helpdesk_staff_member_required
|
||||||
def rss_list(request):
|
def rss_list(request):
|
||||||
return render(request, 'helpdesk/rss_list.html', {'queues': Queue.objects.all()})
|
return render(request, 'helpdesk/rss_list.html', {'queues': Queue.objects.all()})
|
||||||
|
|
||||||
|
|
||||||
rss_list = staff_member_required(rss_list)
|
rss_list = staff_member_required(rss_list)
|
||||||
|
|
||||||
|
|
||||||
@ -1105,6 +1134,8 @@ def report_index(request):
|
|||||||
'basic_ticket_stats': basic_ticket_stats,
|
'basic_ticket_stats': basic_ticket_stats,
|
||||||
'dash_tickets': dash_tickets,
|
'dash_tickets': dash_tickets,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
report_index = staff_member_required(report_index)
|
report_index = staff_member_required(report_index)
|
||||||
|
|
||||||
|
|
||||||
@ -1138,7 +1169,7 @@ def run_report(request, report):
|
|||||||
query_params = json.loads(b64decode(str(saved_query.query)).decode())
|
query_params = json.loads(b64decode(str(saved_query.query)).decode())
|
||||||
else:
|
else:
|
||||||
query_params = json.loads(b64decode(str(saved_query.query)))
|
query_params = json.loads(b64decode(str(saved_query.query)))
|
||||||
except:
|
except json.JSONDecodeError:
|
||||||
return HttpResponseRedirect(reverse('helpdesk:report_index'))
|
return HttpResponseRedirect(reverse('helpdesk:report_index'))
|
||||||
|
|
||||||
report_queryset = apply_query(report_queryset, query_params)
|
report_queryset = apply_query(report_queryset, query_params)
|
||||||
@ -1306,6 +1337,8 @@ def run_report(request, report):
|
|||||||
'from_saved_query': from_saved_query,
|
'from_saved_query': from_saved_query,
|
||||||
'saved_query': saved_query,
|
'saved_query': saved_query,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
run_report = staff_member_required(run_report)
|
run_report = staff_member_required(run_report)
|
||||||
|
|
||||||
|
|
||||||
@ -1324,6 +1357,8 @@ def save_query(request):
|
|||||||
query.save()
|
query.save()
|
||||||
|
|
||||||
return HttpResponseRedirect('%s?saved_query=%s' % (reverse('helpdesk:list'), query.id))
|
return HttpResponseRedirect('%s?saved_query=%s' % (reverse('helpdesk:list'), query.id))
|
||||||
|
|
||||||
|
|
||||||
save_query = staff_member_required(save_query)
|
save_query = staff_member_required(save_query)
|
||||||
|
|
||||||
|
|
||||||
@ -1336,6 +1371,8 @@ def delete_saved_query(request, id):
|
|||||||
return HttpResponseRedirect(reverse('helpdesk:list'))
|
return HttpResponseRedirect(reverse('helpdesk:list'))
|
||||||
else:
|
else:
|
||||||
return render(request, 'helpdesk/confirm_delete_saved_query.html', {'query': query})
|
return render(request, 'helpdesk/confirm_delete_saved_query.html', {'query': query})
|
||||||
|
|
||||||
|
|
||||||
delete_saved_query = staff_member_required(delete_saved_query)
|
delete_saved_query = staff_member_required(delete_saved_query)
|
||||||
|
|
||||||
|
|
||||||
@ -1351,6 +1388,8 @@ def user_settings(request):
|
|||||||
form = UserSettingsForm(s.settings)
|
form = UserSettingsForm(s.settings)
|
||||||
|
|
||||||
return render(request, 'helpdesk/user_settings.html', {'form': form})
|
return render(request, 'helpdesk/user_settings.html', {'form': form})
|
||||||
|
|
||||||
|
|
||||||
user_settings = staff_member_required(user_settings)
|
user_settings = staff_member_required(user_settings)
|
||||||
|
|
||||||
|
|
||||||
@ -1359,6 +1398,8 @@ def email_ignore(request):
|
|||||||
return render(request, 'helpdesk/email_ignore_list.html', {
|
return render(request, 'helpdesk/email_ignore_list.html', {
|
||||||
'ignore_list': IgnoreEmail.objects.all(),
|
'ignore_list': IgnoreEmail.objects.all(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
email_ignore = superuser_required(email_ignore)
|
email_ignore = superuser_required(email_ignore)
|
||||||
|
|
||||||
|
|
||||||
@ -1373,6 +1414,8 @@ def email_ignore_add(request):
|
|||||||
form = EmailIgnoreForm(request.GET)
|
form = EmailIgnoreForm(request.GET)
|
||||||
|
|
||||||
return render(request, 'helpdesk/email_ignore_add.html', {'form': form})
|
return render(request, 'helpdesk/email_ignore_add.html', {'form': form})
|
||||||
|
|
||||||
|
|
||||||
email_ignore_add = superuser_required(email_ignore_add)
|
email_ignore_add = superuser_required(email_ignore_add)
|
||||||
|
|
||||||
|
|
||||||
@ -1384,6 +1427,8 @@ def email_ignore_del(request, id):
|
|||||||
return HttpResponseRedirect(reverse('helpdesk:email_ignore'))
|
return HttpResponseRedirect(reverse('helpdesk:email_ignore'))
|
||||||
else:
|
else:
|
||||||
return render(request, 'helpdesk/email_ignore_del.html', {'ignore': ignore})
|
return render(request, 'helpdesk/email_ignore_del.html', {'ignore': ignore})
|
||||||
|
|
||||||
|
|
||||||
email_ignore_del = superuser_required(email_ignore_del)
|
email_ignore_del = superuser_required(email_ignore_del)
|
||||||
|
|
||||||
|
|
||||||
@ -1398,6 +1443,8 @@ def ticket_cc(request, ticket_id):
|
|||||||
'copies_to': copies_to,
|
'copies_to': copies_to,
|
||||||
'ticket': ticket,
|
'ticket': ticket,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
ticket_cc = staff_member_required(ticket_cc)
|
ticket_cc = staff_member_required(ticket_cc)
|
||||||
|
|
||||||
|
|
||||||
@ -1423,6 +1470,8 @@ def ticket_cc_add(request, ticket_id):
|
|||||||
'form_email': form_email,
|
'form_email': form_email,
|
||||||
'form_user': form_user,
|
'form_user': form_user,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
ticket_cc_add = staff_member_required(ticket_cc_add)
|
ticket_cc_add = staff_member_required(ticket_cc_add)
|
||||||
|
|
||||||
|
|
||||||
@ -1435,6 +1484,8 @@ def ticket_cc_del(request, ticket_id, cc_id):
|
|||||||
return HttpResponseRedirect(reverse('helpdesk:ticket_cc',
|
return HttpResponseRedirect(reverse('helpdesk:ticket_cc',
|
||||||
kwargs={'ticket_id': cc.ticket.id}))
|
kwargs={'ticket_id': cc.ticket.id}))
|
||||||
return render(request, 'helpdesk/ticket_cc_del.html', {'cc': cc})
|
return render(request, 'helpdesk/ticket_cc_del.html', {'cc': cc})
|
||||||
|
|
||||||
|
|
||||||
ticket_cc_del = staff_member_required(ticket_cc_del)
|
ticket_cc_del = staff_member_required(ticket_cc_del)
|
||||||
|
|
||||||
|
|
||||||
@ -1457,6 +1508,8 @@ def ticket_dependency_add(request, ticket_id):
|
|||||||
'ticket': ticket,
|
'ticket': ticket,
|
||||||
'form': form,
|
'form': form,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
ticket_dependency_add = staff_member_required(ticket_dependency_add)
|
ticket_dependency_add = staff_member_required(ticket_dependency_add)
|
||||||
|
|
||||||
|
|
||||||
@ -1467,6 +1520,8 @@ def ticket_dependency_del(request, ticket_id, dependency_id):
|
|||||||
dependency.delete()
|
dependency.delete()
|
||||||
return HttpResponseRedirect(reverse('helpdesk:view', args=[ticket_id]))
|
return HttpResponseRedirect(reverse('helpdesk:view', args=[ticket_id]))
|
||||||
return render(request, 'helpdesk/ticket_dependency_del.html', {'dependency': dependency})
|
return render(request, 'helpdesk/ticket_dependency_del.html', {'dependency': dependency})
|
||||||
|
|
||||||
|
|
||||||
ticket_dependency_del = staff_member_required(ticket_dependency_del)
|
ticket_dependency_del = staff_member_required(ticket_dependency_del)
|
||||||
|
|
||||||
|
|
||||||
@ -1484,6 +1539,8 @@ def attachment_del(request, ticket_id, attachment_id):
|
|||||||
'attachment': attachment,
|
'attachment': attachment,
|
||||||
'filename': attachment.filename,
|
'filename': attachment.filename,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
attachment_del = staff_member_required(attachment_del)
|
attachment_del = staff_member_required(attachment_del)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
pysocks
|
pysocks
|
||||||
pep8
|
pycodestyle
|
||||||
codecov
|
codecov
|
||||||
coverage
|
coverage
|
||||||
argparse
|
argparse
|
||||||
|
@ -2,6 +2,8 @@ Django>=1.11,<2
|
|||||||
django-bootstrap-form>=3.3,<4
|
django-bootstrap-form>=3.3,<4
|
||||||
email-reply-parser
|
email-reply-parser
|
||||||
django-markdown-deux
|
django-markdown-deux
|
||||||
|
beautifulsoup4
|
||||||
|
lxml
|
||||||
simplejson
|
simplejson
|
||||||
pytz
|
pytz
|
||||||
six
|
six
|
||||||
|
Loading…
Reference in New Issue
Block a user