mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-03-03 11:01:20 +01:00
feat: allow configuring unreadCutoff per user, closes #6811
This commit is contained in:
@@ -37,6 +37,7 @@
|
||||
"folder-exists": "Folder exists",
|
||||
|
||||
"invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2",
|
||||
"invalid-unread-cutoff": "Invalid unread cutoff value, must be at least 1 and at most %1",
|
||||
|
||||
"username-taken": "Username taken",
|
||||
"email-taken": "Email address is already taken.",
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
"show-email": "Show My Email",
|
||||
"show-fullname": "Show My Full Name",
|
||||
"restrict-chats": "Only allow chat messages from users I follow",
|
||||
"disable-incoming-chats": "Disable incoming chat messages <a data-bs-toggle=\"tooltip\" href=\"#\" title=\"Admins and moderators can still send you messages\"><i class=\"fa-solid fa-circle-info\"></i></a>",
|
||||
"disable-incoming-chats": "Disable incoming chat messages <a class=\"text-reset\" data-bs-toggle=\"tooltip\" href=\"#\" title=\"Admins and moderators can still send you messages\"><i class=\"fa-solid fa-circle-info\"></i></a>",
|
||||
"chat-allow-list": "Allow chat messages from the following users",
|
||||
"chat-deny-list": "Deny chat messages from the following users",
|
||||
"chat-list-add-user": "Add user",
|
||||
@@ -141,8 +141,8 @@
|
||||
"hidden": "hidden",
|
||||
|
||||
"paginate-description" : "Paginate topics and posts instead of using infinite scroll",
|
||||
"topics-per-page": "Topics per Page",
|
||||
"posts-per-page": "Posts per Page",
|
||||
"topics-per-page": "Topics per page",
|
||||
"posts-per-page": "Posts per page",
|
||||
"category-topic-sort": "Category topic sort",
|
||||
"topic-post-sort": "Topic post sort",
|
||||
"max-items-per-page": "Maximum %1",
|
||||
@@ -157,6 +157,8 @@
|
||||
"upvote-notif-freq.disabled": "Disabled",
|
||||
|
||||
"browsing": "Browsing Settings",
|
||||
"unread.cutoff": "Unread cutoff (Maximum %1 days)",
|
||||
"unread.cutoff-help": "Topics will be marked read if they have not been updated within this number of days.",
|
||||
"open-links-in-new-tab": "Open outgoing links in new tab",
|
||||
|
||||
"enable-topic-searching": "Enable In-Topic Searching",
|
||||
|
||||
@@ -4,6 +4,9 @@ Settings:
|
||||
showemail:
|
||||
type: boolean
|
||||
description: Show user email in profile page
|
||||
unreadCutoff:
|
||||
type: number
|
||||
description: Number of days after which a topic is no longer considered unread
|
||||
usePagination:
|
||||
type: boolean
|
||||
description: Toggles between pagination (when enabled), or infinite scrolling (when disabled)
|
||||
|
||||
@@ -133,6 +133,8 @@ get:
|
||||
type: number
|
||||
maxPostsPerPage:
|
||||
type: number
|
||||
maxUnreadCutoff:
|
||||
type: number
|
||||
title:
|
||||
type: string
|
||||
- $ref: ../../../components/schemas/Breadcrumbs.yaml#/Breadcrumbs
|
||||
|
||||
@@ -20,6 +20,8 @@ define('forum/account/settings', [
|
||||
savedSkin = $('#bootswatchSkin').length && $('#bootswatchSkin').val();
|
||||
header.init();
|
||||
|
||||
$('[data-bs-toggle]').tooltip();
|
||||
|
||||
$('#submitBtn').on('click', function () {
|
||||
const settings = loadSettings();
|
||||
|
||||
|
||||
@@ -132,6 +132,7 @@ usersAPI.updateSettings = async function (caller, data) {
|
||||
|
||||
let defaults = await user.getSettings(0);
|
||||
defaults = {
|
||||
unreadCutoff: defaults.unreadCutoff,
|
||||
postsPerPage: defaults.postsPerPage,
|
||||
topicsPerPage: defaults.topicsPerPage,
|
||||
userLang: defaults.userLang,
|
||||
|
||||
@@ -96,6 +96,7 @@ settingsController.get = async function (req, res, next) {
|
||||
|
||||
userData.maxTopicsPerPage = meta.config.maxTopicsPerPage;
|
||||
userData.maxPostsPerPage = meta.config.maxPostsPerPage;
|
||||
userData.maxUnreadCutoff = Math.max(meta.config.unreadCutoff, 14);
|
||||
|
||||
userData.title = '[[pages:account/settings]]';
|
||||
userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: `/user/${userData.userslug}` }, { text: '[[user:settings]]' }]);
|
||||
|
||||
@@ -11,7 +11,6 @@ const posts = require('../posts');
|
||||
const notifications = require('../notifications');
|
||||
const categories = require('../categories');
|
||||
const privileges = require('../privileges');
|
||||
const meta = require('../meta');
|
||||
const utils = require('../utils');
|
||||
const plugins = require('../plugins');
|
||||
|
||||
@@ -48,8 +47,9 @@ module.exports = function (Topics) {
|
||||
};
|
||||
|
||||
Topics.unreadCutoff = async function (uid) {
|
||||
const cutoff = Date.now() - (meta.config.unreadCutoff * 86400000);
|
||||
const data = await plugins.hooks.fire('filter:topics.unreadCutoff', { uid: uid, cutoff: cutoff });
|
||||
const { unreadCutoff } = await user.getSettings(uid);
|
||||
const cutoff = Date.now() - (unreadCutoff * 86400000);
|
||||
const data = await plugins.hooks.fire('filter:topics.unreadCutoff', { uid, cutoff });
|
||||
return parseInt(data.cutoff, 10);
|
||||
};
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ module.exports = function (User) {
|
||||
};
|
||||
|
||||
async function onSettingsLoaded(uid, settings) {
|
||||
const data = await plugins.hooks.fire('filter:user.getSettings', { uid: uid, settings: settings });
|
||||
const data = await plugins.hooks.fire('filter:user.getSettings', { uid, settings });
|
||||
settings = data.settings;
|
||||
|
||||
const defaultTopicsPerPage = meta.config.topicsPerPage;
|
||||
@@ -59,6 +59,12 @@ module.exports = function (User) {
|
||||
settings.openOutgoingLinksInNewTab = parseInt(getSetting(settings, 'openOutgoingLinksInNewTab', 0), 10) === 1;
|
||||
settings.dailyDigestFreq = getSetting(settings, 'dailyDigestFreq', 'off');
|
||||
settings.usePagination = parseInt(getSetting(settings, 'usePagination', 0), 10) === 1;
|
||||
settings.unreadCutoff = Math.max(1, Math.min(
|
||||
Math.max(meta.config.unreadCutoff, 14),
|
||||
settings.unreadCutoff ?
|
||||
parseInt(settings.unreadCutoff, 10) :
|
||||
meta.config.unreadCutoff,
|
||||
));
|
||||
settings.topicsPerPage = Math.max(1, Math.min(
|
||||
meta.config.maxTopicsPerPage,
|
||||
settings.topicsPerPage ?
|
||||
@@ -116,6 +122,60 @@ module.exports = function (User) {
|
||||
}
|
||||
|
||||
User.saveSettings = async function (uid, data) {
|
||||
await validateSettings(data);
|
||||
|
||||
data.userLang = data.userLang || meta.config.defaultLang;
|
||||
|
||||
plugins.hooks.fire('action:user.saveSettings', { uid: uid, settings: data });
|
||||
|
||||
const settings = {
|
||||
showemail: data.showemail,
|
||||
showfullname: data.showfullname,
|
||||
unreadCutoff: data.unreadCutoff,
|
||||
openOutgoingLinksInNewTab: data.openOutgoingLinksInNewTab,
|
||||
dailyDigestFreq: data.dailyDigestFreq || 'off',
|
||||
usePagination: data.usePagination,
|
||||
topicsPerPage: data.topicsPerPage,
|
||||
postsPerPage: data.postsPerPage,
|
||||
userLang: data.userLang,
|
||||
acpLang: data.acpLang || meta.config.defaultLang,
|
||||
followTopicsOnCreate: data.followTopicsOnCreate,
|
||||
followTopicsOnReply: data.followTopicsOnReply,
|
||||
disableIncomingChats: data.disableIncomingChats,
|
||||
topicSearchEnabled: data.topicSearchEnabled,
|
||||
updateUrlWithPostIndex: data.updateUrlWithPostIndex,
|
||||
homePageRoute: ((data.homePageRoute === 'custom' ? data.homePageCustom : data.homePageRoute) || '').replace(/^\//, ''),
|
||||
scrollToMyPost: data.scrollToMyPost,
|
||||
upvoteNotifFreq: data.upvoteNotifFreq,
|
||||
bootswatchSkin: data.bootswatchSkin,
|
||||
categoryWatchState: data.categoryWatchState,
|
||||
categoryTopicSort: data.categoryTopicSort,
|
||||
topicPostSort: data.topicPostSort,
|
||||
chatAllowList: data.chatAllowList,
|
||||
chatDenyList: data.chatDenyList,
|
||||
};
|
||||
const notificationTypes = await notifications.getAllNotificationTypes();
|
||||
notificationTypes.forEach((notificationType) => {
|
||||
if (data[notificationType]) {
|
||||
settings[notificationType] = data[notificationType];
|
||||
}
|
||||
});
|
||||
const result = await plugins.hooks.fire('filter:user.saveSettings', { uid, settings, data });
|
||||
await db.setObject(`user:${uid}:settings`, result.settings);
|
||||
await User.updateDigestSetting(uid, data.dailyDigestFreq);
|
||||
return await User.getSettings(uid);
|
||||
};
|
||||
|
||||
async function validateSettings(data) {
|
||||
const maxUnreadCutoff = Math.max(meta.config.unreadCutoff, 14);
|
||||
if (
|
||||
!data.unreadCutoff ||
|
||||
parseInt(data.unreadCutoff, 10) <= 0 ||
|
||||
parseInt(data.unreadCutoff, 10) > maxUnreadCutoff
|
||||
) {
|
||||
throw new Error(`[[error:invalid-unread-cutoff, ${maxUnreadCutoff}]]`);
|
||||
}
|
||||
|
||||
const maxPostsPerPage = meta.config.maxPostsPerPage || 20;
|
||||
if (
|
||||
!data.postsPerPage ||
|
||||
@@ -141,46 +201,7 @@ module.exports = function (User) {
|
||||
if (data.acpLang && !languageCodes.includes(data.acpLang)) {
|
||||
throw new Error('[[error:invalid-language]]');
|
||||
}
|
||||
data.userLang = data.userLang || meta.config.defaultLang;
|
||||
|
||||
plugins.hooks.fire('action:user.saveSettings', { uid: uid, settings: data });
|
||||
|
||||
const settings = {
|
||||
showemail: data.showemail,
|
||||
showfullname: data.showfullname,
|
||||
openOutgoingLinksInNewTab: data.openOutgoingLinksInNewTab,
|
||||
dailyDigestFreq: data.dailyDigestFreq || 'off',
|
||||
usePagination: data.usePagination,
|
||||
topicsPerPage: Math.min(data.topicsPerPage, parseInt(maxTopicsPerPage, 10) || 20),
|
||||
postsPerPage: Math.min(data.postsPerPage, parseInt(maxPostsPerPage, 10) || 20),
|
||||
userLang: data.userLang || meta.config.defaultLang,
|
||||
acpLang: data.acpLang || meta.config.defaultLang,
|
||||
followTopicsOnCreate: data.followTopicsOnCreate,
|
||||
followTopicsOnReply: data.followTopicsOnReply,
|
||||
disableIncomingChats: data.disableIncomingChats,
|
||||
topicSearchEnabled: data.topicSearchEnabled,
|
||||
updateUrlWithPostIndex: data.updateUrlWithPostIndex,
|
||||
homePageRoute: ((data.homePageRoute === 'custom' ? data.homePageCustom : data.homePageRoute) || '').replace(/^\//, ''),
|
||||
scrollToMyPost: data.scrollToMyPost,
|
||||
upvoteNotifFreq: data.upvoteNotifFreq,
|
||||
bootswatchSkin: data.bootswatchSkin,
|
||||
categoryWatchState: data.categoryWatchState,
|
||||
categoryTopicSort: data.categoryTopicSort,
|
||||
topicPostSort: data.topicPostSort,
|
||||
chatAllowList: data.chatAllowList,
|
||||
chatDenyList: data.chatDenyList,
|
||||
};
|
||||
const notificationTypes = await notifications.getAllNotificationTypes();
|
||||
notificationTypes.forEach((notificationType) => {
|
||||
if (data[notificationType]) {
|
||||
settings[notificationType] = data[notificationType];
|
||||
}
|
||||
});
|
||||
const result = await plugins.hooks.fire('filter:user.saveSettings', { uid: uid, settings: settings, data: data });
|
||||
await db.setObject(`user:${uid}:settings`, result.settings);
|
||||
await User.updateDigestSetting(uid, data.dailyDigestFreq);
|
||||
return await User.getSettings(uid);
|
||||
};
|
||||
}
|
||||
|
||||
User.updateDigestSetting = async function (uid, dailyDigestFreq) {
|
||||
await db.sortedSetsRemove(['digest:day:uids', 'digest:week:uids', 'digest:month:uids'], uid);
|
||||
|
||||
Reference in New Issue
Block a user