diff --git a/migrations/053-admin-notifications.sql b/migrations/053-admin-notifications.sql
new file mode 100644
index 00000000..9ca49f03
--- /dev/null
+++ b/migrations/053-admin-notifications.sql
@@ -0,0 +1,6 @@
+-- Up
+
+ALTER TABLE users ADD COLUMN adminNotifications INTEGER NOT NULL DEFAULT 7;
+
+-- Down
+
diff --git a/routes/admin.vue b/routes/admin.vue
index 00b4be7e..3beea607 100644
--- a/routes/admin.vue
+++ b/routes/admin.vue
@@ -10,6 +10,16 @@
Moderation rules
+
+ Email notifications when there's items to moderate:
+
+
+
+
+
+
+
+
@@ -192,6 +202,7 @@
localeFilter: true,
adminsFilter: false,
usersShown: false,
+ adminNotifications: this.$user().adminNotifications ?? 7,
}
},
async asyncData({ app, store }) {
@@ -241,6 +252,10 @@
this.userFilterDelayed = this.userFilter;
}, 500);
},
+ async adminNotifications() {
+ const res = await this.$axios.$post(`/admin/set-notification-frequency`, {frequency: parseInt(this.adminNotifications)});
+ this.$store.commit('setToken', res.token);
+ },
},
head() {
return head({
diff --git a/server/notify.js b/server/notify.js
index d363f038..916ca72f 100644
--- a/server/notify.js
+++ b/server/notify.js
@@ -22,6 +22,18 @@ const isGranted = (user, locale, area) => {
return false;
}
+const shouldNotify = (frequency) => {
+ if (frequency === 0) {
+ return false;
+ }
+
+ if (frequency === 7) {
+ return (new Date()).getDay() === 6; // Saturdays
+ }
+
+ return true;
+}
+
async function notify() {
const db = await dbConnection();
@@ -38,13 +50,13 @@ async function notify() {
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 = {}
let count = 0;
for (let m of awaitingModeration) {
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) {
awaitingModerationGrouped[admin.email] = {};
}
diff --git a/server/routes/admin.js b/server/routes/admin.js
index 4c255bfc..9f7affad 100644
--- a/server/routes/admin.js
+++ b/server/routes/admin.js
@@ -11,6 +11,7 @@ import {profilesSnapshot} from "./profile";
import buildLocaleList from "../../src/buildLocaleList";
import {archiveBan, liftBan} from "../ban";
import marked from 'marked';
+import {loadCurrentUser} from "./user";
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;
diff --git a/server/routes/user.js b/server/routes/user.js
index d2c63379..ba1eb9ad 100644
--- a/server/routes/user.js
+++ b/server/routes/user.js
@@ -250,7 +250,7 @@ const router = Router();
router.use(handleErrorAsync(reloadUser));
-router.get('/user/current', handleErrorAsync(async (req, res) => {
+export const loadCurrentUser = async (req, res) => {
if (!req.user) {
res.clearCookie('token');
return res.json(null);
@@ -269,7 +269,9 @@ router.get('/user/current', handleErrorAsync(async (req, res) => {
req.user = req.rawUser;
return res.json({...req.user, token});
-}));
+};
+
+router.get('/user/current', handleErrorAsync(loadCurrentUser));
router.post('/user/init', handleErrorAsync(async (req, res) => {
if (req.body.usernameOrEmail && isSpam(req.body.usernameOrEmail || '')) {