Skip to content

Commit

Permalink
feat: add broadcast mail
Browse files Browse the repository at this point in the history
  • Loading branch information
Gingmzmzx committed Oct 4, 2024
1 parent 8084e87 commit 9164a36
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 5 deletions.
18 changes: 18 additions & 0 deletions vj4/handler/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,21 @@ async def post(self, *, uid: int):
await user.set_priv(int(uid), privs)
self.json_or_redirect(self.reverse_url("admin_user"))


@app.route('/admin/mail', 'admin_mail')
class AdminMailHandler(base.OperationHandler):
@base.require_priv(builtin.PRIV_ADMIN)
async def get(self):
udocs = []
async for udoc in user.get_multi():
udocs.append(udoc)
self.render('admin_mail.html', udocs=udocs)

@base.require_priv(builtin.PRIV_ADMIN)
@base.require_csrf_token
@base.sanitize
async def post_send_mail(self, *, uid: int, title: str, content: str):
udict = await user.get_by_uid(uid)
mail = udict['mail']
await self.send_mail(mail, "通知 - "+str(title), "broadcast_mail.html", mail_content=content, mail_title=title)
self.json_or_redirect(self.url, mail=mail)
5 changes: 0 additions & 5 deletions vj4/handler/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@
from vj4.util import pagination


@app.route('/test/header', 'test_header')
class TestHeaderHandler(base.Handler):
async def get(self):
self.render('bsod.html', args=self.request.headers)

@app.route('/', 'domain_main')
class DomainMainHandler(contest.ContestStatusMixin, base.OperationHandler):
CONTESTS_ON_MAIN = 5
Expand Down
5 changes: 5 additions & 0 deletions vj4/locale/zh_CN.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ Tools: 工具
admin_dashboard: 管理员面板
admin_user: 管理用户
admin_privilege: 管理特权
admin_mail: 邮件广播
Mail Content: 邮件内容
Send mail to selected users: 发送邮件到指定用户
Mail successfully sent to uid:{0}.: 发送邮件成功(UID:{0})
Confirm sending Email to selected users?: 确定要给选定用户发送广播邮件?
Updates Manager: 动态管理者
Collapse: 收起
Expand: 展开
Expand Down
63 changes: 63 additions & 0 deletions vj4/ui/pages/admin_mail.page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import _ from 'lodash';

import { NamedPage } from 'vj/misc/PageLoader';
import Notification from 'vj/components/notification';
import { ConfirmDialog } from 'vj/components/dialog';

import request from 'vj/utils/request';
import tpl from 'vj/utils/tpl';
import delay from 'vj/utils/delay';
import i18n from 'vj/utils/i18n';

const page = new NamedPage('admin_mail', () => {
function ensureAndGetSelectedUsers() {
const users = _.map(
$('.admin_user_list tbody [type="checkbox"]:checked'),
ch => $(ch).closest('tr').attr('data-uid'),
);
if (users.length === 0) {
Notification.error(i18n('Please select at least one user to perform this operation.'));
return null;
}
return users;
}

async function sendMail(uid, title, content){
try {
await request.post('', {
operation: 'send_mail',
uid: uid,
title: title,
content: content
});
Notification.success(i18n('Mail successfully sent to uid:{0}.', uid));
} catch (error) {
Notification.error(`Error uid:${uid} ${error.message}`);
}
}

async function handleClickSend() {
const selectedUsers = ensureAndGetSelectedUsers();
if (selectedUsers === null) {
return;
}
const action = await new ConfirmDialog({
$body: tpl`
<div class="typo">
<p>${i18n('Confirm sending Email to selected users?')}</p>
</div>`,
}).open();
if (action !== 'yes') {
return;
}
const mail_content_container = $("#mail_content_container");
const mail_title = mail_content_container.find('[name="title"]').val();
const mail_content = mail_content_container.find('[name="content"]').val();
_.map(selectedUsers, async ch => { await sendMail(ch, mail_title, mail_content)});
}


$('[name="btn_send_mail"]').click(() => handleClickSend());
});

export default page;
9 changes: 9 additions & 0 deletions vj4/ui/pages/admin_mail.page.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.page--admin_mail
.col--checkbox
width: 60px

.col--uid
width: 100px

.col--role
width: 160px
1 change: 1 addition & 0 deletions vj4/ui/templates/admin_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<ol class="menu collapsed">
{{ sidemenu.render_item(null, 'admin_dashboard') }}
{{ sidemenu.render_item(null, 'admin_user') }}
{{ sidemenu.render_item(null, 'admin_mail') }}
</ol>
</li>
</ol>
Expand Down
63 changes: 63 additions & 0 deletions vj4/ui/templates/admin_mail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{% extends "admin_base.html" %}
{% block admin_content %}
<div class="section">
<div class="section__header">
<h1 class="section__title">{{ _('Send mail to selected users') }}</h1>
</div>
{{ noscript_note.render() }}
<div class="section__body no-padding admin_user_list">
<table class="data-table">
<colgroup>
<col class="col--checkbox">
<col class="col--uid">
<col class="col--user">
</colgroup>
<thead>
<tr>
<th class="col--checkbox">
<label class="compact checkbox">
<input type="checkbox" name="select_all" data-checkbox-toggle="user">
</label>
</th>
<th class="col--uid">{{ _('User ID') }}</th>
<th class="col--user">{{ _('Username') }}</th>
</tr>
</thead>
<tbody>
{% for udoc in udocs %}
<tr data-uid="{{ udoc['_id'] }}" data-badge="{%if udoc['tags'] %}{{ ' '.join(udoc['tags']) }}{% endif %}">
<td class="col--checkbox">
<label class="compact checkbox">
<input type="checkbox" data-checkbox-group="user">
</label>
</td>
<td class="col--uid">
{{ udoc['_id'] }}
</td>
<td class="col--user">
{{ user.render_inline(udoc) }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>

<div class="section">
<div class="section__header">
<h1 class="section__title">{{ _('Mail Content') }}</h1>
</div>
<div class="section__body" id="mail_content_container">
{% include "partials/admin_send_mail_form.html" %}
<div class="row"><div class="columns">
<button type="submit" name="btn_send_mail" class="rounded primary button">
{{ _('Send') }}
</button>
<button type="button" class="rounded button" onclick="window.history.go(-1)">
{{ _('Cancel') }}
</button>
</div></div>
</div>
</div>
{% endblock %}
9 changes: 9 additions & 0 deletions vj4/ui/templates/broadcast_mail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% extends "layout/mail.html" %}
{% block title %}{{ mail_title }}{% endblock %}
{% block content %}
{{ mail_content|safe }}
<br />
<br />
<br />
<i>This is a broadcast email. Do not reply.</i>
{% endblock %}
4 changes: 4 additions & 0 deletions vj4/ui/templates/bsod.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
<span style="color: #f8f8f2">}</span>
</pre></div>

<pre style="color:white; font-size: 18px; line-height: 125%; display: inline-block; text-align: left; white-space: pre-wrap; word-wrap: break-word;">
<span>Debug Information</span>

{{args}}
</pre>
</body>
</html>
3 changes: 3 additions & 0 deletions vj4/ui/templates/partials/admin_send_mail_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{% import "components/form.html" as form with context %}
{{ form.form_text(label='Title', name='title', autofocus=true, required=true) }}
{{ form.form_textarea(columns=20, label='Content', name='content', hotkeys='ctrl+enter:submit', required=true) }}

0 comments on commit 9164a36

Please sign in to comment.