diff --git a/apps/authentication/api/login_confirm.py b/apps/authentication/api/login_confirm.py index 5232dd753..986488f2b 100644 --- a/apps/authentication/api/login_confirm.py +++ b/apps/authentication/api/login_confirm.py @@ -12,7 +12,7 @@ from ..models import LoginConfirmSetting from ..serializers import LoginConfirmSettingSerializer from .. import errors, mixins -__all__ = ['LoginConfirmSettingUpdateApi', 'LoginConfirmTicketStatusApi'] +__all__ = ['LoginConfirmSettingUpdateApi', 'TicketStatusApi'] logger = get_logger(__name__) @@ -31,17 +31,17 @@ class LoginConfirmSettingUpdateApi(UpdateAPIView): return s -class LoginConfirmTicketStatusApi(mixins.AuthMixin, APIView): +class TicketStatusApi(mixins.AuthMixin, APIView): permission_classes = () def get_ticket(self): - from tickets.models import LoginConfirmTicket + from tickets.models import Ticket ticket_id = self.request.session.get("auth_ticket_id") logger.debug('Login confirm ticket id: {}'.format(ticket_id)) if not ticket_id: ticket = None else: - ticket = get_object_or_none(LoginConfirmTicket, pk=ticket_id) + ticket = get_object_or_none(Ticket, pk=ticket_id) return ticket def get(self, request, *args, **kwargs): diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py index ceb54f592..80f54dbc9 100644 --- a/apps/authentication/mixins.py +++ b/apps/authentication/mixins.py @@ -104,13 +104,13 @@ class AuthMixin: raise errors.MFAFailedError(username=user.username, request=self.request) def get_ticket(self): - from tickets.models import LoginConfirmTicket + from tickets.models import Ticket ticket_id = self.request.session.get("auth_ticket_id") logger.debug('Login confirm ticket id: {}'.format(ticket_id)) if not ticket_id: ticket = None else: - ticket = get_object_or_none(LoginConfirmTicket, pk=ticket_id) + ticket = get_object_or_none(Ticket, pk=ticket_id) return ticket def get_ticket_or_create(self, confirm_setting): diff --git a/apps/authentication/models.py b/apps/authentication/models.py index cb4f97e4d..614906c73 100644 --- a/apps/authentication/models.py +++ b/apps/authentication/models.py @@ -49,23 +49,25 @@ class LoginConfirmSetting(CommonModelMixin): return get_object_or_none(cls, user=user) def create_confirm_ticket(self, request=None): - from tickets.models import LoginConfirmTicket - title = _('User login confirm: {}').format(self.user) + from tickets.models import Ticket + title = '[' + __('Login confirm') + ']: {}'.format(self.user) if request: remote_addr = get_request_ip(request) city = get_ip_city(remote_addr) - body = _("User: {}\nIP: {}\nCity: {}\nDate: {}\n").format( - self.user, remote_addr, city, timezone.now() + body = __("{user_key}: {username}
" + "IP: {ip}
" + "{city_key}: {city}
" + "{date_key}: {date}
").format( + user_key=__("User"), username=self.user, + ip=remote_addr, city_key=_("City"), city=city, + date_key=__("Datetime"), date=timezone.now() ) else: - city = 'Localhost' - remote_addr = '127.0.0.1' body = '' reviewer = self.reviewers.all() - ticket = LoginConfirmTicket.objects.create( + ticket = Ticket.objects.create( user=self.user, title=title, body=body, - city=city, ip=remote_addr, - type=LoginConfirmTicket.TYPE_LOGIN_CONFIRM, + type=Ticket.TYPE_LOGIN_CONFIRM, ) ticket.assignees.set(reviewer) return ticket diff --git a/apps/authentication/templates/authentication/login_wait_confirm.html b/apps/authentication/templates/authentication/login_wait_confirm.html index 28f84baf9..8a67a501e 100644 --- a/apps/authentication/templates/authentication/login_wait_confirm.html +++ b/apps/authentication/templates/authentication/login_wait_confirm.html @@ -126,7 +126,7 @@ function handleProgressBar() { progressBarRef.attr('aria-valuenow', offset); } -function cancelLoginConfirmTicket() { +function cancelTicket() { requestApi({ url: url, method: "DELETE", @@ -144,7 +144,7 @@ function setCloseConfirm() { return 'Confirm'; }; window.onunload = function (e) { - cancelLoginConfirmTicket(); + cancelTicket(); } } diff --git a/apps/authentication/urls/api_urls.py b/apps/authentication/urls/api_urls.py index 2da89a19f..da59711c4 100644 --- a/apps/authentication/urls/api_urls.py +++ b/apps/authentication/urls/api_urls.py @@ -18,7 +18,7 @@ urlpatterns = [ path('connection-token/', api.UserConnectionTokenApi.as_view(), name='connection-token'), path('otp/verify/', api.UserOtpVerifyApi.as_view(), name='user-otp-verify'), - path('login-confirm-ticket/status/', api.LoginConfirmTicketStatusApi.as_view(), name='login-confirm-ticket-status'), + path('login-confirm-ticket/status/', api.TicketStatusApi.as_view(), name='login-confirm-ticket-status'), path('login-confirm-settings//', api.LoginConfirmSettingUpdateApi.as_view(), name='login-confirm-setting-update') ] diff --git a/apps/authentication/views/login.py b/apps/authentication/views/login.py index 873057169..d6bb2af6c 100644 --- a/apps/authentication/views/login.py +++ b/apps/authentication/views/login.py @@ -144,16 +144,16 @@ class UserLoginWaitConfirmView(TemplateView): template_name = 'authentication/login_wait_confirm.html' def get_context_data(self, **kwargs): - from tickets.models import LoginConfirmTicket + from tickets.models import Ticket ticket_id = self.request.session.get("auth_ticket_id") if not ticket_id: ticket = None else: - ticket = get_object_or_none(LoginConfirmTicket, pk=ticket_id) + ticket = get_object_or_none(Ticket, pk=ticket_id) context = super().get_context_data(**kwargs) if ticket: timestamp_created = datetime.datetime.timestamp(ticket.date_created) - ticket_detail_url = reverse('tickets:login-confirm-ticket-detail', kwargs={'pk': ticket_id}) + ticket_detail_url = reverse('tickets:ticket-detail', kwargs={'pk': ticket_id}) msg = _("""Wait for {} confirm, You also can copy link to her/him
Don't close this page""").format(ticket.assignees_display) else: diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 720b8a9cf..83f364a18 100644 Binary files a/apps/locale/zh/LC_MESSAGES/django.mo and b/apps/locale/zh/LC_MESSAGES/django.mo differ diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index cfc940bec..fcdd6011c 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Jumpserver 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-11-14 19:29+0800\n" +"POT-Creation-Date: 2019-11-15 17:39+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: Jumpserver team\n" @@ -354,7 +354,6 @@ msgstr "重置" #: terminal/templates/terminal/command_list.html:47 #: terminal/templates/terminal/session_list.html:52 #: terminal/templates/terminal/terminal_update.html:46 -#: tickets/templates/tickets/login_confirm_ticket_list.html:32 #: users/templates/users/_user.html:52 #: users/templates/users/forgot_password.html:42 #: users/templates/users/user_bulk_update.html:24 @@ -528,8 +527,7 @@ msgstr "创建远程应用" #: settings/templates/settings/terminal_setting.html:107 #: terminal/templates/terminal/session_list.html:36 #: terminal/templates/terminal/terminal_list.html:36 -#: tickets/templates/tickets/login_confirm_ticket_list.html:18 -#: tickets/templates/tickets/login_confirm_ticket_list.html:106 +#: tickets/templates/tickets/ticket_list.html:93 #: users/templates/users/_granted_assets.html:34 #: users/templates/users/user_group_list.html:38 #: users/templates/users/user_list.html:41 @@ -1046,7 +1044,8 @@ msgstr "过滤器" #: settings/templates/settings/replay_storage_create.html:31 #: settings/templates/settings/terminal_setting.html:84 #: settings/templates/settings/terminal_setting.html:106 -#: tickets/models/base.py:34 tickets/templates/tickets/ticket_detail.html:33 +#: tickets/models/ticket.py:42 tickets/templates/tickets/ticket_detail.html:33 +#: tickets/templates/tickets/ticket_list.html:23 msgid "Type" msgstr "类型" @@ -1127,11 +1126,10 @@ msgstr "默认资产组" #: terminal/models.py:156 terminal/templates/terminal/command_list.html:29 #: terminal/templates/terminal/command_list.html:65 #: terminal/templates/terminal/session_list.html:27 -#: terminal/templates/terminal/session_list.html:71 tickets/models/base.py:25 -#: tickets/models/base.py:68 -#: tickets/templates/tickets/login_confirm_ticket_list.html:15 -#: tickets/templates/tickets/login_confirm_ticket_list.html:101 -#: tickets/templates/tickets/ticket_detail.html:32 users/forms.py:339 +#: terminal/templates/terminal/session_list.html:71 tickets/models/ticket.py:32 +#: tickets/models/ticket.py:85 tickets/templates/tickets/ticket_detail.html:32 +#: tickets/templates/tickets/ticket_list.html:22 +#: tickets/templates/tickets/ticket_list.html:88 users/forms.py:339 #: users/models/user.py:149 users/models/user.py:165 users/models/user.py:537 #: users/serializers/group.py:21 #: users/templates/users/user_group_detail.html:78 @@ -1506,7 +1504,7 @@ msgstr "获取认证信息错误" #: authentication/templates/authentication/_access_key_modal.html:142 #: authentication/templates/authentication/_mfa_confirm_modal.html:53 #: settings/templates/settings/_ldap_list_users_modal.html:171 -#: templates/_modal.html:22 tickets/models/base.py:50 +#: templates/_modal.html:22 tickets/models/ticket.py:67 #: tickets/templates/tickets/ticket_detail.html:103 msgid "Close" msgstr "关闭" @@ -1517,7 +1515,7 @@ msgstr "关闭" #: ops/templates/ops/task_adhoc.html:63 #: terminal/templates/terminal/command_list.html:33 #: terminal/templates/terminal/session_detail.html:50 -#: tickets/templates/tickets/login_confirm_ticket_list.html:17 +#: tickets/templates/tickets/ticket_list.html:25 msgid "Datetime" msgstr "日期" @@ -1717,7 +1715,7 @@ msgstr "Jumpserver 使用该用户来 `推送系统用户`、`获取资产硬件 #: users/templates/users/user_group_list.html:10 #: users/templates/users/user_list.html:10 #: xpack/plugins/gathered_user/templates/gathered_user/gathered_user_list.html:49 -#: xpack/plugins/vault/templates/vault/vault.html:55 +#: xpack/plugins/vault/templates/vault/vault.html:47 msgid "Export" msgstr "导出" @@ -1728,7 +1726,7 @@ msgstr "导出" #: users/templates/users/user_group_list.html:15 #: users/templates/users/user_list.html:15 #: xpack/plugins/license/templates/license/license_detail.html:110 -#: xpack/plugins/vault/templates/vault/vault.html:60 +#: xpack/plugins/vault/templates/vault/vault.html:52 msgid "Import" msgstr "导入" @@ -1747,7 +1745,7 @@ msgstr "创建管理用户" #: users/templates/users/user_group_list.html:195 #: users/templates/users/user_list.html:165 #: users/templates/users/user_list.html:197 -#: xpack/plugins/vault/templates/vault/vault.html:224 +#: xpack/plugins/vault/templates/vault/vault.html:200 msgid "Please select file" msgstr "选择文件" @@ -2239,7 +2237,7 @@ msgstr "成功" #: audits/models.py:33 #: authentication/templates/authentication/_access_key_modal.html:22 -#: xpack/plugins/vault/templates/vault/vault.html:46 +#: xpack/plugins/vault/templates/vault/vault.html:38 msgid "Create" msgstr "创建" @@ -2306,9 +2304,9 @@ msgid "Reason" msgstr "原因" #: audits/models.py:88 audits/templates/audits/login_log_list.html:64 -#: tickets/templates/tickets/login_confirm_ticket_list.html:16 -#: tickets/templates/tickets/login_confirm_ticket_list.html:102 #: tickets/templates/tickets/ticket_detail.html:34 +#: tickets/templates/tickets/ticket_list.html:24 +#: tickets/templates/tickets/ticket_list.html:89 #: xpack/plugins/cloud/models.py:275 xpack/plugins/cloud/models.py:310 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:70 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:65 @@ -2368,7 +2366,7 @@ msgstr "ID" msgid "UA" msgstr "Agent" -#: audits/templates/audits/login_log_list.html:61 +#: audits/templates/audits/login_log_list.html:61 authentication/models.py:62 msgid "City" msgstr "城市" @@ -2379,23 +2377,23 @@ msgid "Date" msgstr "日期" #: audits/views.py:86 audits/views.py:130 audits/views.py:167 -#: audits/views.py:212 audits/views.py:244 templates/_nav.html:139 +#: audits/views.py:212 audits/views.py:244 templates/_nav.html:137 msgid "Audits" msgstr "日志审计" -#: audits/views.py:87 templates/_nav.html:143 +#: audits/views.py:87 templates/_nav.html:141 msgid "FTP log" msgstr "FTP日志" -#: audits/views.py:131 templates/_nav.html:144 +#: audits/views.py:131 templates/_nav.html:142 msgid "Operate log" msgstr "操作日志" -#: audits/views.py:168 templates/_nav.html:145 +#: audits/views.py:168 templates/_nav.html:143 msgid "Password change log" msgstr "改密日志" -#: audits/views.py:213 templates/_nav.html:142 +#: audits/views.py:213 templates/_nav.html:140 msgid "Login log" msgstr "登录日志" @@ -2530,22 +2528,6 @@ msgstr "ssh密钥" msgid "Reviewers" msgstr "审批人" -#: authentication/models.py:53 -msgid "User login confirm: {}" -msgstr "用户登录复核: {}" - -#: authentication/models.py:57 -msgid "" -"User: {}\n" -"IP: {}\n" -"City: {}\n" -"Date: {}\n" -msgstr "" -"用户: {}\n" -"IP: {}\n" -"城市: {}\n" -"日期: {}\n" - #: authentication/templates/authentication/_access_key_modal.html:6 msgid "API key list" msgstr "API Key列表" @@ -4025,7 +4007,7 @@ msgstr "在ou:{}中没有匹配条目" #: settings/views.py:20 settings/views.py:47 settings/views.py:74 #: settings/views.py:105 settings/views.py:133 settings/views.py:146 -#: settings/views.py:160 settings/views.py:187 templates/_nav.html:180 +#: settings/views.py:160 settings/views.py:187 templates/_nav.html:178 msgid "Settings" msgstr "系统设置" @@ -4218,7 +4200,7 @@ msgstr "终端管理" msgid "Job Center" msgstr "作业中心" -#: templates/_nav.html:116 templates/_nav.html:146 +#: templates/_nav.html:116 templates/_nav.html:144 msgid "Batch command" msgstr "批量命令" @@ -4226,24 +4208,19 @@ msgstr "批量命令" msgid "Task monitor" msgstr "任务监控" -#: templates/_nav.html:127 tickets/views.py:16 tickets/views.py:30 +#: templates/_nav.html:128 tickets/views.py:17 tickets/views.py:32 msgid "Tickets" msgstr "工单管理" -#: templates/_nav.html:130 tickets/models/base.py:23 -#: users/templates/users/user_detail.html:257 -msgid "Login confirm" -msgstr "登录复核" - -#: templates/_nav.html:156 +#: templates/_nav.html:154 msgid "XPack" msgstr "" -#: templates/_nav.html:164 xpack/plugins/cloud/views.py:28 +#: templates/_nav.html:162 xpack/plugins/cloud/views.py:28 msgid "Account list" msgstr "账户列表" -#: templates/_nav.html:165 +#: templates/_nav.html:163 msgid "Sync instance" msgstr "同步实例" @@ -4585,10 +4562,7 @@ msgid "Accept" msgstr "接受" #: terminal/templates/terminal/terminal_list.html:80 -#: tickets/models/login_confirm.py:16 -#: tickets/templates/tickets/login_confirm_ticket_detail.html:10 -#: tickets/templates/tickets/login_confirm_ticket_list.html:70 -#: tickets/templates/tickets/login_confirm_ticket_list.html:108 +#: tickets/models/ticket.py:30 tickets/templates/tickets/ticket_list.html:95 msgid "Reject" msgstr "拒绝" @@ -4625,78 +4599,77 @@ msgid "" "You should use your ssh client tools connect terminal: {}

{}" msgstr "你可以使用ssh客户端工具连接终端" -#: tickets/models/base.py:16 tickets/models/base.py:52 -#: tickets/templates/tickets/login_confirm_ticket_list.html:103 +#: tickets/models/ticket.py:17 tickets/models/ticket.py:69 +#: tickets/templates/tickets/ticket_list.html:90 msgid "Open" msgstr "开启" -#: tickets/models/base.py:17 -#: tickets/templates/tickets/login_confirm_ticket_list.html:104 +#: tickets/models/ticket.py:18 tickets/templates/tickets/ticket_list.html:91 msgid "Closed" msgstr "关闭" -#: tickets/models/base.py:22 +#: tickets/models/ticket.py:23 msgid "General" msgstr "一般" -#: tickets/models/base.py:26 tickets/models/base.py:69 -msgid "User display name" -msgstr "用户显示名称" +#: tickets/models/ticket.py:24 users/templates/users/user_detail.html:257 +msgid "Login confirm" +msgstr "登录复核" -#: tickets/models/base.py:28 -#: tickets/templates/tickets/login_confirm_ticket_list.html:14 -#: tickets/templates/tickets/login_confirm_ticket_list.html:100 -msgid "Title" -msgstr "标题" - -#: tickets/models/base.py:29 tickets/models/base.py:70 -msgid "Body" -msgstr "内容" - -#: tickets/models/base.py:30 tickets/templates/tickets/ticket_detail.html:51 -msgid "Assignee" -msgstr "处理人" - -#: tickets/models/base.py:31 -msgid "Assignee display name" -msgstr "处理人名称" - -#: tickets/models/base.py:32 tickets/templates/tickets/ticket_detail.html:50 -msgid "Assignees" -msgstr "待处理人" - -#: tickets/models/base.py:33 -msgid "Assignees display name" -msgstr "待处理人名称" - -#: tickets/models/base.py:53 -msgid "{} {} this ticket" -msgstr "{} {} 这个工单" - -#: tickets/models/login_confirm.py:15 -#: tickets/templates/tickets/login_confirm_ticket_detail.html:9 -#: tickets/templates/tickets/login_confirm_ticket_list.html:69 -#: tickets/templates/tickets/login_confirm_ticket_list.html:107 +#: tickets/models/ticket.py:29 tickets/templates/tickets/ticket_list.html:94 msgid "Approve" msgstr "同意" -#: tickets/models/login_confirm.py:24 -msgid "this order" -msgstr "这个工单" +#: tickets/models/ticket.py:33 tickets/models/ticket.py:86 +msgid "User display name" +msgstr "用户显示名称" -#: tickets/templates/tickets/login_confirm_ticket_list.html:27 -msgid "Approve selected" -msgstr "同意所选" +#: tickets/models/ticket.py:35 tickets/templates/tickets/ticket_list.html:21 +#: tickets/templates/tickets/ticket_list.html:87 +msgid "Title" +msgstr "标题" -#: tickets/templates/tickets/login_confirm_ticket_list.html:28 -msgid "Reject selected" -msgstr "拒绝所选" +#: tickets/models/ticket.py:36 tickets/models/ticket.py:87 +msgid "Body" +msgstr "内容" + +#: tickets/models/ticket.py:37 +msgid "Meta" +msgstr "" + +#: tickets/models/ticket.py:38 tickets/templates/tickets/ticket_detail.html:51 +msgid "Assignee" +msgstr "处理人" + +#: tickets/models/ticket.py:39 +msgid "Assignee display name" +msgstr "处理人名称" + +#: tickets/models/ticket.py:40 tickets/templates/tickets/ticket_detail.html:50 +msgid "Assignees" +msgstr "待处理人" + +#: tickets/models/ticket.py:41 +msgid "Assignees display name" +msgstr "待处理人名称" + +#: tickets/models/ticket.py:70 +msgid "{} {} this ticket" +msgstr "{} {} 这个工单" #: tickets/templates/tickets/ticket_detail.html:66 #: tickets/templates/tickets/ticket_detail.html:81 msgid "ago" msgstr "前" +#: tickets/templates/tickets/ticket_list.html:9 +msgid "My tickets" +msgstr "我的工单" + +#: tickets/templates/tickets/ticket_list.html:10 +msgid "Assigned me" +msgstr "待处理" + #: tickets/utils.py:18 msgid "New ticket" msgstr "新工单" @@ -4708,15 +4681,7 @@ msgid "" "
\n" "

Your has a new ticket

\n" "
\n" -" Title: {ticket.title}\n" -"
\n" -" User: {user}\n" -"
\n" -" Assignees: {ticket.assignees_display}\n" -"
\n" -" City: {ticket.city}\n" -"
\n" -" IP: {ticket.ip}\n" +" {body}\n" "
\n" " click here to review \n" "
\n" @@ -4725,28 +4690,20 @@ msgid "" msgstr "" "\n" "
\n" -"

您有一个新工单

\n" +"

你有一个新工单

\n" "
\n" -" 标题: {ticket.title}\n" +" {body}\n" "
\n" -" 用户: {user}\n" -"
\n" -" 待处理人: {ticket.assignees_display}\n" -"
\n" -" 城市: {ticket.city}\n" -"
\n" -" IP: {ticket.ip}\n" -"
\n" -" 点我查看 \n" +" 点击我查看 \n" "
\n" "
\n" " " -#: tickets/utils.py:48 +#: tickets/utils.py:40 msgid "Ticket has been reply" msgstr "工单已被回复" -#: tickets/utils.py:49 +#: tickets/utils.py:41 #, python-brace-format msgid "" "\n" @@ -4777,13 +4734,13 @@ msgstr "" "
\n" " " -#: tickets/views.py:17 -msgid "Login confirm ticket list" -msgstr "登录复核工单列表" +#: tickets/views.py:18 +msgid "Ticket list" +msgstr "工单列表" -#: tickets/views.py:31 -msgid "Login confirm ticket detail" -msgstr "登录复核工单详情" +#: tickets/views.py:33 +msgid "Ticket detail" +msgstr "工单详情" #: users/api/user.py:173 msgid "Could not reset self otp, use profile reset instead" @@ -6455,6 +6412,80 @@ msgstr "密码匣子" msgid "vault create" msgstr "创建" +#~ msgid "Assigned ticket" +#~ msgstr "处理人" + +#~ msgid "My ticket" +#~ msgstr "我的工单" + +#~ msgid "User login confirm: {}" +#~ msgstr "用户登录复核: {}" + +#~ msgid "" +#~ "User: {}\n" +#~ "IP: {}\n" +#~ "City: {}\n" +#~ "Date: {}\n" +#~ msgstr "" +#~ "用户: {}\n" +#~ "IP: {}\n" +#~ "城市: {}\n" +#~ "日期: {}\n" + +#~ msgid "this order" +#~ msgstr "这个工单" + +#~ msgid "Approve selected" +#~ msgstr "同意所选" + +#~ msgid "Reject selected" +#~ msgstr "拒绝所选" + +#~ msgid "" +#~ "\n" +#~ "
\n" +#~ "

Your has a new ticket

\n" +#~ "
\n" +#~ " Title: {ticket.title}\n" +#~ "
\n" +#~ " User: {user}\n" +#~ "
\n" +#~ " Assignees: {ticket.assignees_display}\n" +#~ "
\n" +#~ " City: {ticket.city}\n" +#~ "
\n" +#~ " IP: {ticket.ip}\n" +#~ "
\n" +#~ " click here to review \n" +#~ "
\n" +#~ "
\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ "
\n" +#~ "

您有一个新工单

\n" +#~ "
\n" +#~ " 标题: {ticket.title}\n" +#~ "
\n" +#~ " 用户: {user}\n" +#~ "
\n" +#~ " 待处理人: {ticket.assignees_display}\n" +#~ "
\n" +#~ " 城市: {ticket.city}\n" +#~ "
\n" +#~ " IP: {ticket.ip}\n" +#~ "
\n" +#~ " 点我查看 \n" +#~ "
\n" +#~ "
\n" +#~ " " + +#~ msgid "Login confirm ticket list" +#~ msgstr "登录复核工单列表" + +#~ msgid "Login confirm ticket detail" +#~ msgstr "登录复核工单详情" + #, fuzzy #~| msgid "Login" #~ msgid "Login IP" diff --git a/apps/templates/_nav.html b/apps/templates/_nav.html index 794d9b243..eb2df90ff 100644 --- a/apps/templates/_nav.html +++ b/apps/templates/_nav.html @@ -123,12 +123,10 @@ {% if request.user.can_admin_current_org and LOGIN_CONFIRM_ENABLE %}
  • - - {% trans 'Tickets' %} + + + {% trans 'Tickets' %} -
  • {% endif %} diff --git a/apps/tickets/api/__init__.py b/apps/tickets/api/__init__.py index 99396f9f3..0b5dd0e7d 100644 --- a/apps/tickets/api/__init__.py +++ b/apps/tickets/api/__init__.py @@ -1,4 +1,3 @@ # -*- coding: utf-8 -*- # -from .base import * -from .login_confirm import * +from .ticket import * diff --git a/apps/tickets/api/login_confirm.py b/apps/tickets/api/login_confirm.py deleted file mode 100644 index e0c6f9cf5..000000000 --- a/apps/tickets/api/login_confirm.py +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- -# -from rest_framework_bulk import BulkModelViewSet - -from common.permissions import IsValidUser -from common.mixins import CommonApiMixin -from .. import serializers, mixins -from ..models import LoginConfirmTicket - - -class LoginConfirmTicketViewSet(CommonApiMixin, mixins.TicketMixin, BulkModelViewSet): - serializer_class = serializers.LoginConfirmTicketSerializer - permission_classes = (IsValidUser,) - queryset = LoginConfirmTicket.objects.all() - filter_fields = ['status', 'title', 'action', 'ip'] - search_fields = ['user_display', 'title', 'ip', 'city'] diff --git a/apps/tickets/api/base.py b/apps/tickets/api/ticket.py similarity index 75% rename from apps/tickets/api/base.py rename to apps/tickets/api/ticket.py index 266f9f855..1706c38a7 100644 --- a/apps/tickets/api/base.py +++ b/apps/tickets/api/ticket.py @@ -4,6 +4,7 @@ from rest_framework import viewsets from django.shortcuts import get_object_or_404 +from common.permissions import IsValidUser from common.utils import lazyproperty from .. import serializers, models, mixins @@ -11,14 +12,19 @@ from .. import serializers, models, mixins class TicketViewSet(mixins.TicketMixin, viewsets.ModelViewSet): serializer_class = serializers.TicketSerializer queryset = models.Ticket.objects.all() + permission_classes = (IsValidUser,) + filter_fields = ['status', 'title', 'action'] + search_fields = ['user_display', 'title'] class TicketCommentViewSet(viewsets.ModelViewSet): serializer_class = serializers.CommentSerializer + http_method_names = ['get', 'post'] def check_permissions(self, request): ticket = self.ticket - if request.user == ticket.user or request.user in ticket.assignees.all(): + if request.user == ticket.user or \ + request.user in ticket.assignees.all(): return True return False diff --git a/apps/tickets/migrations/0001_initial.py b/apps/tickets/migrations/0001_initial.py index e86fc44ad..9b2b5d54e 100644 --- a/apps/tickets/migrations/0001_initial.py +++ b/apps/tickets/migrations/0001_initial.py @@ -1,5 +1,6 @@ -# Generated by Django 2.2.5 on 2019-11-07 08:02 +# Generated by Django 2.2.5 on 2019-11-15 06:57 +import common.fields.model from django.conf import settings from django.db import migrations, models import django.db.models.deletion @@ -25,10 +26,12 @@ class Migration(migrations.Migration): ('user_display', models.CharField(max_length=128, verbose_name='User display name')), ('title', models.CharField(max_length=256, verbose_name='Title')), ('body', models.TextField(verbose_name='Body')), + ('meta', common.fields.model.JsonDictTextField(default='{}', verbose_name='Meta')), ('assignee_display', models.CharField(blank=True, max_length=128, null=True, verbose_name='Assignee display name')), ('assignees_display', models.CharField(blank=True, max_length=128, verbose_name='Assignees display name')), - ('type', models.CharField(default='general', max_length=16, verbose_name='Type')), + ('type', models.CharField(choices=[('general', 'General'), ('login_confirm', 'Login confirm')], default='general', max_length=16, verbose_name='Type')), ('status', models.CharField(choices=[('open', 'Open'), ('closed', 'Closed')], default='open', max_length=16)), + ('action', models.CharField(blank=True, choices=[('approve', 'Approve'), ('reject', 'Reject')], default='', max_length=16)), ('assignee', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ticket_handled', to=settings.AUTH_USER_MODEL, verbose_name='Assignee')), ('assignees', models.ManyToManyField(related_name='ticket_assigned', to=settings.AUTH_USER_MODEL, verbose_name='Assignees')), ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ticket_requested', to=settings.AUTH_USER_MODEL, verbose_name='User')), @@ -37,19 +40,6 @@ class Migration(migrations.Migration): 'ordering': ('-date_created',), }, ), - migrations.CreateModel( - name='LoginConfirmTicket', - fields=[ - ('ticket_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tickets.Ticket')), - ('ip', models.GenericIPAddressField(blank=True, null=True)), - ('city', models.CharField(blank=True, default='', max_length=16)), - ('action', models.CharField(blank=True, choices=[('approve', 'Approve'), ('reject', 'Reject')], default='', max_length=16)), - ], - options={ - 'abstract': False, - }, - bases=('tickets.ticket',), - ), migrations.CreateModel( name='Comment', fields=[ @@ -59,7 +49,7 @@ class Migration(migrations.Migration): ('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')), ('user_display', models.CharField(max_length=128, verbose_name='User display name')), ('body', models.TextField(verbose_name='Body')), - ('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tickets.Ticket')), + ('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='tickets.Ticket')), ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='comments', to=settings.AUTH_USER_MODEL, verbose_name='User')), ], options={ diff --git a/apps/tickets/migrations/0002_auto_20191114_1105.py b/apps/tickets/migrations/0002_auto_20191114_1105.py deleted file mode 100644 index 87cec4056..000000000 --- a/apps/tickets/migrations/0002_auto_20191114_1105.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 2.2.5 on 2019-11-14 03:05 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('tickets', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='comment', - name='ticket', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='tickets.Ticket'), - ), - migrations.AlterField( - model_name='ticket', - name='type', - field=models.CharField(choices=[('general', 'General'), ('login_confirm', 'Login confirm')], default='general', max_length=16, verbose_name='Type'), - ), - ] diff --git a/apps/tickets/models/__init__.py b/apps/tickets/models/__init__.py index 99396f9f3..0b5dd0e7d 100644 --- a/apps/tickets/models/__init__.py +++ b/apps/tickets/models/__init__.py @@ -1,4 +1,3 @@ # -*- coding: utf-8 -*- # -from .base import * -from .login_confirm import * +from .ticket import * diff --git a/apps/tickets/models/login_confirm.py b/apps/tickets/models/login_confirm.py deleted file mode 100644 index 87baaefee..000000000 --- a/apps/tickets/models/login_confirm.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -# -from django.db import models -from django.utils.translation import ugettext_lazy as _ - -from .base import Ticket - -__all__ = ['LoginConfirmTicket'] - - -class LoginConfirmTicket(Ticket): - ACTION_APPROVE = 'approve' - ACTION_REJECT = 'reject' - ACTION_CHOICES = ( - (ACTION_APPROVE, _('Approve')), - (ACTION_REJECT, _('Reject')), - ) - ip = models.GenericIPAddressField(blank=True, null=True) - city = models.CharField(max_length=16, blank=True, default='') - action = models.CharField(choices=ACTION_CHOICES, max_length=16, default='', blank=True) - - def create_action_comment(self, action, user): - action_display = dict(self.ACTION_CHOICES).get(action) - body = '{} {} {}'.format(user, action_display, _("this order")) - self.comments.create(body=body, user=user, user_display=str(user)) - - def perform_action(self, action, user): - self.create_action_comment(action, user) - self.action = action - self.status = self.STATUS_CLOSED - self.assignee = user - self.assignees_display = str(user) - self.save() diff --git a/apps/tickets/models/base.py b/apps/tickets/models/ticket.py similarity index 72% rename from apps/tickets/models/base.py rename to apps/tickets/models/ticket.py index d369e534f..98712da1e 100644 --- a/apps/tickets/models/base.py +++ b/apps/tickets/models/ticket.py @@ -5,6 +5,7 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from common.mixins.models import CommonModelMixin +from common.fields.model import JsonDictTextField __all__ = ['Ticket', 'Comment'] @@ -22,17 +23,25 @@ class Ticket(CommonModelMixin): (TYPE_GENERAL, _("General")), (TYPE_LOGIN_CONFIRM, _("Login confirm")) ) + ACTION_APPROVE = 'approve' + ACTION_REJECT = 'reject' + ACTION_CHOICES = ( + (ACTION_APPROVE, _('Approve')), + (ACTION_REJECT, _('Reject')), + ) user = models.ForeignKey('users.User', on_delete=models.SET_NULL, null=True, related_name='%(class)s_requested', verbose_name=_("User")) user_display = models.CharField(max_length=128, verbose_name=_("User display name")) title = models.CharField(max_length=256, verbose_name=_("Title")) body = models.TextField(verbose_name=_("Body")) + meta = JsonDictTextField(verbose_name=_("Meta"), default='{}') assignee = models.ForeignKey('users.User', on_delete=models.SET_NULL, null=True, related_name='%(class)s_handled', verbose_name=_("Assignee")) assignee_display = models.CharField(max_length=128, blank=True, null=True, verbose_name=_("Assignee display name")) assignees = models.ManyToManyField('users.User', related_name='%(class)s_assigned', verbose_name=_("Assignees")) assignees_display = models.CharField(max_length=128, verbose_name=_("Assignees display name"), blank=True) type = models.CharField(max_length=16, choices=TYPE_CHOICES, default=TYPE_GENERAL, verbose_name=_("Type")) status = models.CharField(choices=STATUS_CHOICES, max_length=16, default='open') + action = models.CharField(choices=ACTION_CHOICES, max_length=16, default='', blank=True) def __str__(self): return '{}: {}'.format(self.user_display, self.title) @@ -45,6 +54,14 @@ class Ticket(CommonModelMixin): def status_display(self): return self.get_status_display() + @property + def type_display(self): + return self.get_type_display() + + @property + def action_display(self): + return self.get_action_display() + def create_status_comment(self, status, user): if status == self.STATUS_CLOSED: action = _("Close") @@ -59,6 +76,19 @@ class Ticket(CommonModelMixin): self.status = status self.save() + def create_action_comment(self, action, user): + action_display = dict(self.ACTION_CHOICES).get(action) + body = '{} {} {}'.format(user, action_display, _("this order")) + self.comments.create(body=body, user=user, user_display=str(user)) + + def perform_action(self, action, user): + self.create_action_comment(action, user) + self.action = action + self.status = self.STATUS_CLOSED + self.assignee = user + self.assignees_display = str(user) + self.save() + class Meta: ordering = ('-date_created',) diff --git a/apps/tickets/serializers/__init__.py b/apps/tickets/serializers/__init__.py index 99396f9f3..0b5dd0e7d 100644 --- a/apps/tickets/serializers/__init__.py +++ b/apps/tickets/serializers/__init__.py @@ -1,4 +1,3 @@ # -*- coding: utf-8 -*- # -from .base import * -from .login_confirm import * +from .ticket import * diff --git a/apps/tickets/serializers/login_confirm.py b/apps/tickets/serializers/login_confirm.py deleted file mode 100644 index cdd450d6d..000000000 --- a/apps/tickets/serializers/login_confirm.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: utf-8 -*- -# -from rest_framework import serializers - -from common.serializers import AdaptedBulkListSerializer -from common.mixins.serializers import BulkSerializerMixin -from .base import TicketSerializer -from ..models import LoginConfirmTicket - - -__all__ = ['LoginConfirmTicketSerializer', 'LoginConfirmTicketActionSerializer'] - - -class LoginConfirmTicketSerializer(BulkSerializerMixin, serializers.ModelSerializer): - class Meta: - list_serializer_class = AdaptedBulkListSerializer - model = LoginConfirmTicket - fields = TicketSerializer.Meta.fields + [ - 'ip', 'city', 'action' - ] - read_only_fields = TicketSerializer.Meta.read_only_fields - - def create(self, validated_data): - validated_data.pop('action') - return super().create(validated_data) - - def update(self, instance, validated_data): - action = validated_data.get("action") - user = self.context["request"].user - - if action and user not in instance.assignees.all(): - error = {"action": "Only assignees can update"} - raise serializers.ValidationError(error) - if instance.status == instance.STATUS_CLOSED: - validated_data.pop('action') - instance = super().update(instance, validated_data) - if not instance.status == instance.STATUS_CLOSED: - instance.perform_action(action, user) - return instance - - -class LoginConfirmTicketActionSerializer(serializers.ModelSerializer): - comment = serializers.CharField(allow_blank=True) - - class Meta: - model = LoginConfirmTicket - fields = ['action'] - - def update(self, instance, validated_data): - pass - - def create(self, validated_data): - pass diff --git a/apps/tickets/serializers/base.py b/apps/tickets/serializers/ticket.py similarity index 61% rename from apps/tickets/serializers/base.py rename to apps/tickets/serializers/ticket.py index e465fa691..9eb2d777b 100644 --- a/apps/tickets/serializers/base.py +++ b/apps/tickets/serializers/ticket.py @@ -14,12 +14,31 @@ class TicketSerializer(serializers.ModelSerializer): 'id', 'user', 'user_display', 'title', 'body', 'assignees', 'assignees_display', 'status', 'date_created', 'date_updated', + 'type_display', 'action_display', ] read_only_fields = [ 'user_display', 'assignees_display', 'date_created', 'date_updated', ] + def create(self, validated_data): + validated_data.pop('action') + return super().create(validated_data) + + def update(self, instance, validated_data): + action = validated_data.get("action") + user = self.context["request"].user + + if action and user not in instance.assignees.all(): + error = {"action": "Only assignees can update"} + raise serializers.ValidationError(error) + if instance.status == instance.STATUS_CLOSED: + validated_data.pop('action') + instance = super().update(instance, validated_data) + if not instance.status == instance.STATUS_CLOSED and action: + instance.perform_action(action, user) + return instance + class CurrentTicket(object): ticket = None diff --git a/apps/tickets/signals_handler.py b/apps/tickets/signals_handler.py index 212892d0c..0e4298a61 100644 --- a/apps/tickets/signals_handler.py +++ b/apps/tickets/signals_handler.py @@ -4,24 +4,24 @@ from django.dispatch import receiver from django.db.models.signals import m2m_changed, post_save, pre_save from common.utils import get_logger -from .models import LoginConfirmTicket, Ticket, Comment +from .models import Ticket, Comment from .utils import ( - send_login_confirm_ticket_mail_to_assignees, - send_login_confirm_action_mail_to_user + send_new_ticket_mail_to_assignees, + send_ticket_action_mail_to_user ) logger = get_logger(__name__) -@receiver(m2m_changed, sender=LoginConfirmTicket.assignees.through) +@receiver(m2m_changed, sender=Ticket.assignees.through) def on_login_confirm_ticket_assignees_set(sender, instance=None, action=None, reverse=False, model=None, pk_set=None, **kwargs): if action == 'post_add': logger.debug('New ticket create, send mail: {}'.format(instance.id)) assignees = model.objects.filter(pk__in=pk_set) - send_login_confirm_ticket_mail_to_assignees(instance, assignees) + send_new_ticket_mail_to_assignees(instance, assignees) if action.startswith('post') and not reverse: instance.assignees_display = ', '.join([ str(u) for u in instance.assignees.all() @@ -29,15 +29,15 @@ def on_login_confirm_ticket_assignees_set(sender, instance=None, action=None, instance.save() -@receiver(post_save, sender=LoginConfirmTicket) +@receiver(post_save, sender=Ticket) def on_login_confirm_ticket_status_change(sender, instance=None, created=False, **kwargs): if created or instance.status == "open": return logger.debug('Ticket changed, send mail: {}'.format(instance.id)) - send_login_confirm_action_mail_to_user(instance) + send_ticket_action_mail_to_user(instance) -@receiver(pre_save, sender=LoginConfirmTicket) +@receiver(pre_save, sender=Ticket) def on_ticket_create(sender, instance=None, **kwargs): instance.user_display = str(instance.user) if instance.assignee: diff --git a/apps/tickets/templates/tickets/login_confirm_ticket_detail.html b/apps/tickets/templates/tickets/login_confirm_ticket_detail.html deleted file mode 100644 index e0cc25b0d..000000000 --- a/apps/tickets/templates/tickets/login_confirm_ticket_detail.html +++ /dev/null @@ -1,34 +0,0 @@ -{% extends 'tickets/ticket_detail.html' %} -{% load static %} -{% load i18n %} - -{% block status %} -{% endblock %} - -{% block action %} - {% trans 'Approve' %} - {% trans 'Reject' %} -{% endblock %} - -{% block custom_foot_js %} -{{ block.super }} - -{% endblock %} - - - diff --git a/apps/tickets/templates/tickets/login_confirm_ticket_list.html b/apps/tickets/templates/tickets/login_confirm_ticket_list.html deleted file mode 100644 index 267af970b..000000000 --- a/apps/tickets/templates/tickets/login_confirm_ticket_list.html +++ /dev/null @@ -1,154 +0,0 @@ -{% extends '_base_list.html' %} -{% load i18n static %} -{% block table_search %} -{% endblock %} -{% block custom_head_css_js %} -{% endblock %} -{% block table_container %} - - - - - - - - - - - - - -
    - - {% trans 'Title' %}{% trans 'User' %}{% trans 'Status' %}{% trans 'Datetime' %}{% trans 'Action' %}
    -
    -
    - -
    - -
    -
    -
    -{% include '_filter_dropdown.html' %} -{% endblock %} -{% block content_bottom_left %}{% endblock %} -{% block custom_foot_js %} - -{% endblock %} - diff --git a/apps/tickets/templates/tickets/ticket_detail.html b/apps/tickets/templates/tickets/ticket_detail.html index 320010398..ec25f50e7 100644 --- a/apps/tickets/templates/tickets/ticket_detail.html +++ b/apps/tickets/templates/tickets/ticket_detail.html @@ -72,7 +72,6 @@ {% for comment in object.comments.all %} -
    - {% block action %} - {% endblock %} - {% block status %} - {% trans 'Close' %} - {% endblock %} - {% block comment %} + {% if object.type == object.TYPE_LOGIN_CONFIRM %} + {% trans 'Approve' %} + {% trans 'Reject' %} + {% endif %} + {% trans 'Close' %} {% trans 'Comment' %} - {% endblock %}
    @@ -127,6 +124,7 @@ var ticketId = "{{ object.id }}"; var status = "{{ object.status }}"; var commentUrl = "{% url 'api-tickets:ticket-comment-list' ticket_id=object.id %}"; +var ticketDetailUrl = "{% url 'api-tickets:ticket-detail' pk=object.id %}"; function createComment(successCallback) { var commentText = $("#comment").val(); @@ -158,5 +156,26 @@ $(document).ready(function () { .on('click', '.btn-comment', function () { createComment(); }) +.on('click', '.btn-action', function () { + createComment(function () {}); + var action = $(this).data('action'); + var data = { + url: ticketDetailUrl, + body: JSON.stringify({action: action}), + method: "PATCH", + success: reloadPage + }; + requestApi(data); +}) +.on('click', '.btn-status', function () { + var status = $(this).data('uid'); + var data = { + url: ticketDetailUrl, + body: JSON.stringify({status: status}), + method: "PATCH", + success: reloadPage + }; + requestApi(data); +}) {% endblock %} diff --git a/apps/tickets/templates/tickets/ticket_list.html b/apps/tickets/templates/tickets/ticket_list.html new file mode 100644 index 000000000..ba515997b --- /dev/null +++ b/apps/tickets/templates/tickets/ticket_list.html @@ -0,0 +1,115 @@ +{% extends 'base.html' %} +{% load i18n static %} + +{% block content %} +
    +
    +
    + +
    +
    +
    + + + + + + + + + + + + + +
    + + {% trans 'Title' %}{% trans 'User' %}{% trans 'Type' %}{% trans 'Status' %}{% trans 'Datetime' %}
    +
    +
    +
    +
    +
    +
    +{% include '_filter_dropdown.html' %} +{% endblock %} +{% block content_bottom_left %}{% endblock %} +{% block custom_foot_js %} + +{% endblock %} + diff --git a/apps/tickets/urls/api_urls.py b/apps/tickets/urls/api_urls.py index d160235ab..33cb5a216 100644 --- a/apps/tickets/urls/api_urls.py +++ b/apps/tickets/urls/api_urls.py @@ -9,7 +9,6 @@ router = BulkRouter() router.register('tickets', api.TicketViewSet, 'ticket') router.register('tickets/(?P[0-9a-zA-Z\-]{36})/comments', api.TicketCommentViewSet, 'ticket-comment') -router.register('login-confirm-tickets', api.LoginConfirmTicketViewSet, 'login-confirm-ticket') urlpatterns = [ diff --git a/apps/tickets/urls/views_urls.py b/apps/tickets/urls/views_urls.py index f0b19c6f5..46e15437e 100644 --- a/apps/tickets/urls/views_urls.py +++ b/apps/tickets/urls/views_urls.py @@ -6,6 +6,6 @@ from .. import views app_name = 'tickets' urlpatterns = [ - path('login-confirm-tickets/', views.LoginConfirmTicketListView.as_view(), name='login-confirm-ticket-list'), - path('login-confirm-tickets//', views.LoginConfirmTicketDetailView.as_view(), name='login-confirm-ticket-detail') + path('tickets/', views.TicketListView.as_view(), name='ticket-list'), + path('tickets//', views.TicketDetailView.as_view(), name='ticket-detail'), ] diff --git a/apps/tickets/utils.py b/apps/tickets/utils.py index e2901ca3d..13727a77d 100644 --- a/apps/tickets/utils.py +++ b/apps/tickets/utils.py @@ -9,37 +9,29 @@ from common.tasks import send_mail_async logger = get_logger(__name__) -def send_login_confirm_ticket_mail_to_assignees(ticket, assignees): +def send_new_ticket_mail_to_assignees(ticket, assignees): recipient_list = [user.email for user in assignees] user = ticket.user if not recipient_list: logger.error("Ticket not has assignees: {}".format(ticket.id)) return subject = '{}: {}'.format(_("New ticket"), ticket.title) - detail_url = reverse('tickets:login-confirm-ticket-detail', + detail_url = reverse('tickets:ticket-detail', kwargs={'pk': ticket.id}, external=True) message = _("""

    Your has a new ticket

    - Title: {ticket.title} -
    - User: {user} -
    - Assignees: {ticket.assignees_display} -
    - City: {ticket.city} -
    - IP: {ticket.ip} + {body}
    click here to review
    - """).format(ticket=ticket, user=user, url=detail_url) + """).format(body=ticket.body, user=user, url=detail_url) send_mail_async.delay(subject, message, recipient_list, html_message=message) -def send_login_confirm_action_mail_to_user(ticket): +def send_ticket_action_mail_to_user(ticket): if not ticket.user: logger.error("Ticket not has user: {}".format(ticket.id)) return diff --git a/apps/tickets/views.py b/apps/tickets/views.py index aac6b136c..0432ec6bc 100644 --- a/apps/tickets/views.py +++ b/apps/tickets/views.py @@ -2,32 +2,34 @@ from django.views.generic import TemplateView, DetailView from django.utils.translation import ugettext as _ from common.permissions import PermissionsMixin, IsValidUser -from .models import LoginConfirmTicket +from .models import Ticket from . import mixins -class LoginConfirmTicketListView(PermissionsMixin, TemplateView): - template_name = 'tickets/login_confirm_ticket_list.html' +class TicketListView(PermissionsMixin, TemplateView): + template_name = 'tickets/ticket_list.html' permission_classes = (IsValidUser,) + def get_context_data(self, **kwargs): + assign = self.request.GET.get('assign', '0') == '1' + context = super().get_context_data(**kwargs) + context.update({ + 'app': _("Tickets"), + 'action': _("Ticket list"), + 'assign': assign, + }) + return context + + +class TicketDetailView(PermissionsMixin, mixins.TicketMixin, DetailView): + template_name = 'tickets/ticket_detail.html' + permission_classes = (IsValidUser,) + queryset = Ticket.objects.all() + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context.update({ 'app': _("Tickets"), - 'action': _("Login confirm ticket list") - }) - return context - - -class LoginConfirmTicketDetailView(PermissionsMixin, mixins.TicketMixin, DetailView): - template_name = 'tickets/login_confirm_ticket_detail.html' - queryset = LoginConfirmTicket.objects.all() - permission_classes = (IsValidUser,) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context.update({ - 'app': _("Tickets"), - 'action': _("Login confirm ticket detail") + 'action': _("Ticket detail") }) return context