[admin] make the notification frequency configurable

This commit is contained in:
Andrea 2022-05-07 10:26:23 -05:00
parent 001999a069
commit 3090d167b3
5 changed files with 54 additions and 4 deletions

View File

@ -0,0 +1,6 @@
-- Up
ALTER TABLE users ADD COLUMN adminNotifications INTEGER NOT NULL DEFAULT 7;
-- Down

View File

@ -10,6 +10,16 @@
<p><nuxt-link to="/admin/moderation" class="btn btn-outline-primary">Moderation rules</nuxt-link></p> <p><nuxt-link to="/admin/moderation" class="btn btn-outline-primary">Moderation rules</nuxt-link></p>
<p>
Email notifications when there's items to moderate:
</p>
<p>
<span v-for="(label, value) in {0: 'Never', 1: 'Daily', 7: 'Weekly'}" class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="inlineRadioOptions" :id="`notifiactionFrequency_${value}`" :value="value" v-model="adminNotifications">
<label class="form-check-label" :for="`notifiactionFrequency_${value}`">{{label}}</label>
</span>
</p>
<section v-if="$isGranted('users')"> <section v-if="$isGranted('users')">
<details class="border mb-3" @click="usersShown = true"> <details class="border mb-3" @click="usersShown = true">
<summary class="bg-light p-3"> <summary class="bg-light p-3">
@ -192,6 +202,7 @@
localeFilter: true, localeFilter: true,
adminsFilter: false, adminsFilter: false,
usersShown: false, usersShown: false,
adminNotifications: this.$user().adminNotifications ?? 7,
} }
}, },
async asyncData({ app, store }) { async asyncData({ app, store }) {
@ -241,6 +252,10 @@
this.userFilterDelayed = this.userFilter; this.userFilterDelayed = this.userFilter;
}, 500); }, 500);
}, },
async adminNotifications() {
const res = await this.$axios.$post(`/admin/set-notification-frequency`, {frequency: parseInt(this.adminNotifications)});
this.$store.commit('setToken', res.token);
},
}, },
head() { head() {
return head({ return head({

View File

@ -22,6 +22,18 @@ const isGranted = (user, locale, area) => {
return false; return false;
} }
const shouldNotify = (frequency) => {
if (frequency === 0) {
return false;
}
if (frequency === 7) {
return (new Date()).getDay() === 6; // Saturdays
}
return true;
}
async function notify() { async function notify() {
const db = await dbConnection(); const db = await dbConnection();
@ -38,13 +50,13 @@ async function notify() {
return; return;
} }
const admins = await db.all(`SELECT email, roles FROM users WHERE roles != ''`); const admins = await db.all(`SELECT email, roles, adminNotifications FROM users WHERE roles != ''`);
const awaitingModerationGrouped = {} const awaitingModerationGrouped = {}
let count = 0; let count = 0;
for (let m of awaitingModeration) { for (let m of awaitingModeration) {
for (let admin of admins) { for (let admin of admins) {
if (isGranted(admin, m.locale, m.type)) { if (isGranted(admin, m.locale, m.type) && shouldNotify(admin.adminNotifications)) {
if (awaitingModerationGrouped[admin.email] === undefined) { if (awaitingModerationGrouped[admin.email] === undefined) {
awaitingModerationGrouped[admin.email] = {}; awaitingModerationGrouped[admin.email] = {};
} }

View File

@ -11,6 +11,7 @@ import {profilesSnapshot} from "./profile";
import buildLocaleList from "../../src/buildLocaleList"; import buildLocaleList from "../../src/buildLocaleList";
import {archiveBan, liftBan} from "../ban"; import {archiveBan, liftBan} from "../ban";
import marked from 'marked'; import marked from 'marked';
import {loadCurrentUser} from "./user";
const router = Router(); const router = Router();
@ -247,4 +248,18 @@ router.get('/admin/moderation', handleErrorAsync(async (req, res) => {
}) })
})); }));
router.post('/admin/set-notification-frequency', handleErrorAsync(async (req, res) => {
if (!req.isGranted()) {
return res.status(401).json({error: 'Unauthorised'});
}
if (![0, 1, 7].includes(req.body.frequency)) {
return res.status(400).json({error: 'Bad request'});
}
await req.db.get(SQL`UPDATE users SET adminNotifications = ${req.body.frequency} WHERE id = ${req.user.id}`);
return await loadCurrentUser(req, res);
}));
export default router; export default router;

View File

@ -250,7 +250,7 @@ const router = Router();
router.use(handleErrorAsync(reloadUser)); router.use(handleErrorAsync(reloadUser));
router.get('/user/current', handleErrorAsync(async (req, res) => { export const loadCurrentUser = async (req, res) => {
if (!req.user) { if (!req.user) {
res.clearCookie('token'); res.clearCookie('token');
return res.json(null); return res.json(null);
@ -269,7 +269,9 @@ router.get('/user/current', handleErrorAsync(async (req, res) => {
req.user = req.rawUser; req.user = req.rawUser;
return res.json({...req.user, token}); return res.json({...req.user, token});
})); };
router.get('/user/current', handleErrorAsync(loadCurrentUser));
router.post('/user/init', handleErrorAsync(async (req, res) => { router.post('/user/init', handleErrorAsync(async (req, res) => {
if (req.body.usernameOrEmail && isSpam(req.body.usernameOrEmail || '')) { if (req.body.usernameOrEmail && isSpam(req.body.usernameOrEmail || '')) {