mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat: show unread categories based on unread topics (#12317)
* feat: show unread categories based on unread topics if a category has unread topics in one of its children then mark category unread deprecate cid:<cid>:read_by_uid sets upgrade script to remove the old sets * chore: up harmony
This commit is contained in:
committed by
GitHub
parent
ef06be6d3f
commit
45cfb3691e
@@ -103,7 +103,7 @@
|
|||||||
"nodebb-plugin-ntfy": "1.7.3",
|
"nodebb-plugin-ntfy": "1.7.3",
|
||||||
"nodebb-plugin-spam-be-gone": "2.2.0",
|
"nodebb-plugin-spam-be-gone": "2.2.0",
|
||||||
"nodebb-rewards-essentials": "1.0.0",
|
"nodebb-rewards-essentials": "1.0.0",
|
||||||
"nodebb-theme-harmony": "1.2.10",
|
"nodebb-theme-harmony": "1.2.11",
|
||||||
"nodebb-theme-lavender": "7.1.7",
|
"nodebb-theme-lavender": "7.1.7",
|
||||||
"nodebb-theme-peace": "2.2.0",
|
"nodebb-theme-peace": "2.2.0",
|
||||||
"nodebb-theme-persona": "13.3.3",
|
"nodebb-theme-persona": "13.3.3",
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ get:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
unread:
|
||||||
|
type: boolean
|
||||||
|
description: True if category or it's children have unread topics
|
||||||
unread-class:
|
unread-class:
|
||||||
type: string
|
type: string
|
||||||
children:
|
children:
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ get:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
unread:
|
||||||
|
type: boolean
|
||||||
|
description: True if category or it's children have unread topics
|
||||||
unread-class:
|
unread-class:
|
||||||
type: string
|
type: string
|
||||||
children:
|
children:
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ get:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
unread:
|
||||||
|
type: boolean
|
||||||
|
description: True if category or it's children have unread topics
|
||||||
unread-class:
|
unread-class:
|
||||||
type: string
|
type: string
|
||||||
children:
|
children:
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ categoriesAPI.create = async function (caller, data) {
|
|||||||
await hasAdminPrivilege(caller.uid);
|
await hasAdminPrivilege(caller.uid);
|
||||||
|
|
||||||
const response = await categories.create(data);
|
const response = await categories.create(data);
|
||||||
const categoryObjs = await categories.getCategories([response.cid], caller.uid);
|
const categoryObjs = await categories.getCategories([response.cid]);
|
||||||
return categoryObjs[0];
|
return categoryObjs[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const _ = require('lodash');
|
|||||||
|
|
||||||
const db = require('../database');
|
const db = require('../database');
|
||||||
const user = require('../user');
|
const user = require('../user');
|
||||||
|
const topics = require('../topics');
|
||||||
const plugins = require('../plugins');
|
const plugins = require('../plugins');
|
||||||
const privileges = require('../privileges');
|
const privileges = require('../privileges');
|
||||||
const cache = require('../cache');
|
const cache = require('../cache');
|
||||||
@@ -30,7 +31,7 @@ Categories.exists = async function (cids) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Categories.getCategoryById = async function (data) {
|
Categories.getCategoryById = async function (data) {
|
||||||
const categories = await Categories.getCategories([data.cid], data.uid);
|
const categories = await Categories.getCategories([data.cid]);
|
||||||
if (!categories[0]) {
|
if (!categories[0]) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -78,9 +79,9 @@ Categories.getAllCidsFromSet = async function (key) {
|
|||||||
return cids.slice();
|
return cids.slice();
|
||||||
};
|
};
|
||||||
|
|
||||||
Categories.getAllCategories = async function (uid) {
|
Categories.getAllCategories = async function () {
|
||||||
const cids = await Categories.getAllCidsFromSet('categories:cid');
|
const cids = await Categories.getAllCidsFromSet('categories:cid');
|
||||||
return await Categories.getCategories(cids, uid);
|
return await Categories.getCategories(cids);
|
||||||
};
|
};
|
||||||
|
|
||||||
Categories.getCidsByPrivilege = async function (set, uid, privilege) {
|
Categories.getCidsByPrivilege = async function (set, uid, privilege) {
|
||||||
@@ -90,7 +91,7 @@ Categories.getCidsByPrivilege = async function (set, uid, privilege) {
|
|||||||
|
|
||||||
Categories.getCategoriesByPrivilege = async function (set, uid, privilege) {
|
Categories.getCategoriesByPrivilege = async function (set, uid, privilege) {
|
||||||
const cids = await Categories.getCidsByPrivilege(set, uid, privilege);
|
const cids = await Categories.getCidsByPrivilege(set, uid, privilege);
|
||||||
return await Categories.getCategories(cids, uid);
|
return await Categories.getCategories(cids);
|
||||||
};
|
};
|
||||||
|
|
||||||
Categories.getModerators = async function (cid) {
|
Categories.getModerators = async function (cid) {
|
||||||
@@ -102,7 +103,7 @@ Categories.getModeratorUids = async function (cids) {
|
|||||||
return await privileges.categories.getUidsWithPrivilege(cids, 'moderate');
|
return await privileges.categories.getUidsWithPrivilege(cids, 'moderate');
|
||||||
};
|
};
|
||||||
|
|
||||||
Categories.getCategories = async function (cids, uid) {
|
Categories.getCategories = async function (cids) {
|
||||||
if (!Array.isArray(cids)) {
|
if (!Array.isArray(cids)) {
|
||||||
throw new Error('[[error:invalid-cid]]');
|
throw new Error('[[error:invalid-cid]]');
|
||||||
}
|
}
|
||||||
@@ -110,22 +111,46 @@ Categories.getCategories = async function (cids, uid) {
|
|||||||
if (!cids.length) {
|
if (!cids.length) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
uid = parseInt(uid, 10);
|
|
||||||
|
|
||||||
const [categories, tagWhitelist, hasRead] = await Promise.all([
|
const [categories, tagWhitelist] = await Promise.all([
|
||||||
Categories.getCategoriesData(cids),
|
Categories.getCategoriesData(cids),
|
||||||
Categories.getTagWhitelist(cids),
|
Categories.getTagWhitelist(cids),
|
||||||
Categories.hasReadCategories(cids, uid),
|
|
||||||
]);
|
]);
|
||||||
categories.forEach((category, i) => {
|
categories.forEach((category, i) => {
|
||||||
if (category) {
|
if (category) {
|
||||||
category.tagWhitelist = tagWhitelist[i];
|
category.tagWhitelist = tagWhitelist[i];
|
||||||
category['unread-class'] = (category.topic_count === 0 || (hasRead[i] && uid !== 0)) ? '' : 'unread';
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return categories;
|
return categories;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Categories.setUnread = async function (tree, cids, uid) {
|
||||||
|
if (uid <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { unreadCids } = await topics.getUnreadData({
|
||||||
|
uid: uid,
|
||||||
|
cid: cids,
|
||||||
|
});
|
||||||
|
if (!unreadCids.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCategoryUnread(category) {
|
||||||
|
if (category) {
|
||||||
|
category.unread = false;
|
||||||
|
if (unreadCids.includes(category.cid)) {
|
||||||
|
category.unread = category.topic_count > 0 && true;
|
||||||
|
} else if (category.children.length) {
|
||||||
|
category.children.forEach(setCategoryUnread);
|
||||||
|
category.unread = category.children.some(c => c && c.unread);
|
||||||
|
}
|
||||||
|
category['unread-class'] = category.unread ? 'unread' : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tree.forEach(setCategoryUnread);
|
||||||
|
};
|
||||||
|
|
||||||
Categories.getTagWhitelist = async function (cids) {
|
Categories.getTagWhitelist = async function (cids) {
|
||||||
const cachedData = {};
|
const cachedData = {};
|
||||||
|
|
||||||
@@ -210,10 +235,6 @@ async function getChildrenTree(category, uid) {
|
|||||||
let childrenData = await Categories.getCategoriesData(childrenCids);
|
let childrenData = await Categories.getCategoriesData(childrenCids);
|
||||||
childrenData = childrenData.filter(Boolean);
|
childrenData = childrenData.filter(Boolean);
|
||||||
childrenCids = childrenData.map(child => child.cid);
|
childrenCids = childrenData.map(child => child.cid);
|
||||||
const hasRead = await Categories.hasReadCategories(childrenCids, uid);
|
|
||||||
childrenData.forEach((child, i) => {
|
|
||||||
child['unread-class'] = (child.topic_count === 0 || (hasRead[i] && uid !== 0)) ? '' : 'unread';
|
|
||||||
});
|
|
||||||
Categories.getTree([category].concat(childrenData), category.parentCid);
|
Categories.getTree([category].concat(childrenData), category.parentCid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ module.exports = function (Categories) {
|
|||||||
|
|
||||||
const childrenCids = await getChildrenCids(cids, uid);
|
const childrenCids = await getChildrenCids(cids, uid);
|
||||||
const uniqCids = _.uniq(cids.concat(childrenCids));
|
const uniqCids = _.uniq(cids.concat(childrenCids));
|
||||||
const categoryData = await Categories.getCategories(uniqCids, uid);
|
const categoryData = await Categories.getCategories(uniqCids);
|
||||||
|
|
||||||
Categories.getTree(categoryData, 0);
|
Categories.getTree(categoryData, 0);
|
||||||
await Categories.getRecentTopicReplies(categoryData, uid, data.qs);
|
await Categories.getRecentTopicReplies(categoryData, uid, data.qs);
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ const db = require('../database');
|
|||||||
|
|
||||||
module.exports = function (Categories) {
|
module.exports = function (Categories) {
|
||||||
Categories.markAsRead = async function (cids, uid) {
|
Categories.markAsRead = async function (cids, uid) {
|
||||||
|
// TODO: remove in 4.0
|
||||||
|
console.warn('[deprecated] Categories.markAsRead deprecated');
|
||||||
if (!Array.isArray(cids) || !cids.length || parseInt(uid, 10) <= 0) {
|
if (!Array.isArray(cids) || !cids.length || parseInt(uid, 10) <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -14,6 +16,8 @@ module.exports = function (Categories) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Categories.markAsUnreadForAll = async function (cid) {
|
Categories.markAsUnreadForAll = async function (cid) {
|
||||||
|
// TODO: remove in 4.0
|
||||||
|
console.warn('[deprecated] Categories.markAsUnreadForAll deprecated');
|
||||||
if (!parseInt(cid, 10)) {
|
if (!parseInt(cid, 10)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -21,6 +25,8 @@ module.exports = function (Categories) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Categories.hasReadCategories = async function (cids, uid) {
|
Categories.hasReadCategories = async function (cids, uid) {
|
||||||
|
// TODO: remove in 4.0
|
||||||
|
console.warn('[deprecated] Categories.hasReadCategories deprecated, see Categories.setUnread');
|
||||||
if (parseInt(uid, 10) <= 0) {
|
if (parseInt(uid, 10) <= 0) {
|
||||||
return cids.map(() => false);
|
return cids.map(() => false);
|
||||||
}
|
}
|
||||||
@@ -30,6 +36,8 @@ module.exports = function (Categories) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Categories.hasReadCategory = async function (cid, uid) {
|
Categories.hasReadCategory = async function (cid, uid) {
|
||||||
|
// TODO: remove in 4.0
|
||||||
|
console.warn('[deprecated] Categories.hasReadCategory deprecated, see Categories.setUnread');
|
||||||
if (parseInt(uid, 10) <= 0) {
|
if (parseInt(uid, 10) <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const categoriesController = module.exports;
|
|||||||
|
|
||||||
categoriesController.get = async function (req, res, next) {
|
categoriesController.get = async function (req, res, next) {
|
||||||
const [categoryData, parent, selectedData] = await Promise.all([
|
const [categoryData, parent, selectedData] = await Promise.all([
|
||||||
categories.getCategories([req.params.category_id], req.uid),
|
categories.getCategories([req.params.category_id]),
|
||||||
categories.getParents([req.params.category_id]),
|
categories.getParents([req.params.category_id]),
|
||||||
helpers.getSelectedCategory(req.params.category_id),
|
helpers.getSelectedCategory(req.params.category_id),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -30,9 +30,12 @@ categoriesController.list = async function (req, res) {
|
|||||||
|
|
||||||
const allChildCids = _.flatten(await Promise.all(pageCids.map(categories.getChildrenCids)));
|
const allChildCids = _.flatten(await Promise.all(pageCids.map(categories.getChildrenCids)));
|
||||||
const childCids = await privileges.categories.filterCids('find', allChildCids, req.uid);
|
const childCids = await privileges.categories.filterCids('find', allChildCids, req.uid);
|
||||||
const categoryData = await categories.getCategories(pageCids.concat(childCids), req.uid);
|
const categoryData = await categories.getCategories(pageCids.concat(childCids));
|
||||||
const tree = categories.getTree(categoryData, 0);
|
const tree = categories.getTree(categoryData, 0);
|
||||||
await categories.getRecentTopicReplies(categoryData, req.uid, req.query);
|
await Promise.all([
|
||||||
|
categories.getRecentTopicReplies(categoryData, req.uid, req.query),
|
||||||
|
categories.setUnread(tree, pageCids.concat(childCids), req.uid),
|
||||||
|
]);
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
title: meta.config.homePageTitle || '[[pages:home]]',
|
title: meta.config.homePageTitle || '[[pages:home]]',
|
||||||
|
|||||||
@@ -98,10 +98,15 @@ categoryController.get = async function (req, res, next) {
|
|||||||
categories.modifyTopicsByPrivilege(categoryData.topics, userPrivileges);
|
categories.modifyTopicsByPrivilege(categoryData.topics, userPrivileges);
|
||||||
categoryData.tagWhitelist = categories.filterTagWhitelist(categoryData.tagWhitelist, userPrivileges.isAdminOrMod);
|
categoryData.tagWhitelist = categories.filterTagWhitelist(categoryData.tagWhitelist, userPrivileges.isAdminOrMod);
|
||||||
|
|
||||||
await buildBreadcrumbs(req, categoryData);
|
|
||||||
if (categoryData.children.length) {
|
|
||||||
const allCategories = [];
|
const allCategories = [];
|
||||||
categories.flattenCategories(allCategories, categoryData.children);
|
categories.flattenCategories(allCategories, categoryData.children);
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
buildBreadcrumbs(req, categoryData),
|
||||||
|
categories.setUnread([categoryData], allCategories.map(c => c.cid).concat(cid), req.uid),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (categoryData.children.length) {
|
||||||
await categories.getRecentTopicReplies(allCategories, req.uid, req.query);
|
await categories.getRecentTopicReplies(allCategories, req.uid, req.query);
|
||||||
categoryData.subCategoriesLeft = Math.max(0, categoryData.children.length - categoryData.subCategoriesPerPage);
|
categoryData.subCategoriesLeft = Math.max(0, categoryData.children.length - categoryData.subCategoriesPerPage);
|
||||||
categoryData.hasMoreSubCategories = categoryData.children.length > categoryData.subCategoriesPerPage;
|
categoryData.hasMoreSubCategories = categoryData.children.length > categoryData.subCategoriesPerPage;
|
||||||
@@ -124,9 +129,6 @@ categoryController.get = async function (req, res, next) {
|
|||||||
categoryData.topicIndex = topicIndex;
|
categoryData.topicIndex = topicIndex;
|
||||||
categoryData.selectedTag = tagData.selectedTag;
|
categoryData.selectedTag = tagData.selectedTag;
|
||||||
categoryData.selectedTags = tagData.selectedTags;
|
categoryData.selectedTags = tagData.selectedTags;
|
||||||
if (req.loggedIn) {
|
|
||||||
categories.markAsRead([cid], req.uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!meta.config['feeds:disableRSS']) {
|
if (!meta.config['feeds:disableRSS']) {
|
||||||
categoryData.rssFeedUrl = `${url}/category/${categoryData.cid}.rss`;
|
categoryData.rssFeedUrl = `${url}/category/${categoryData.cid}.rss`;
|
||||||
|
|||||||
@@ -224,7 +224,6 @@ module.exports = function (Topics) {
|
|||||||
|
|
||||||
async function onNewPost(postData, data) {
|
async function onNewPost(postData, data) {
|
||||||
const { tid, uid } = postData;
|
const { tid, uid } = postData;
|
||||||
await Topics.markCategoryUnreadForAll(tid);
|
|
||||||
await Topics.markAsRead([tid], uid);
|
await Topics.markAsRead([tid], uid);
|
||||||
const [
|
const [
|
||||||
userInfo,
|
userInfo,
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ module.exports = function (Topics) {
|
|||||||
tids: data.tids,
|
tids: data.tids,
|
||||||
counts: data.counts,
|
counts: data.counts,
|
||||||
tidsByFilter: data.tidsByFilter,
|
tidsByFilter: data.tidsByFilter,
|
||||||
|
unreadCids: data.unreadCids,
|
||||||
cid: params.cid,
|
cid: params.cid,
|
||||||
filter: params.filter,
|
filter: params.filter,
|
||||||
query: params.query || {},
|
query: params.query || {},
|
||||||
@@ -90,9 +91,9 @@ module.exports = function (Topics) {
|
|||||||
async function getTids(params) {
|
async function getTids(params) {
|
||||||
const counts = { '': 0, new: 0, watched: 0, unreplied: 0 };
|
const counts = { '': 0, new: 0, watched: 0, unreplied: 0 };
|
||||||
const tidsByFilter = { '': [], new: [], watched: [], unreplied: [] };
|
const tidsByFilter = { '': [], new: [], watched: [], unreplied: [] };
|
||||||
|
const unreadCids = [];
|
||||||
if (params.uid <= 0) {
|
if (params.uid <= 0) {
|
||||||
return { counts: counts, tids: [], tidsByFilter: tidsByFilter };
|
return { counts, tids: [], tidsByFilter, unreadCids };
|
||||||
}
|
}
|
||||||
|
|
||||||
params.cutoff = await Topics.unreadCutoff(params.uid);
|
params.cutoff = await Topics.unreadCutoff(params.uid);
|
||||||
@@ -126,7 +127,7 @@ module.exports = function (Topics) {
|
|||||||
let tids = _.uniq(unreadTopics.map(topic => topic.value)).slice(0, 200);
|
let tids = _.uniq(unreadTopics.map(topic => topic.value)).slice(0, 200);
|
||||||
|
|
||||||
if (!tids.length) {
|
if (!tids.length) {
|
||||||
return { counts: counts, tids: tids, tidsByFilter: tidsByFilter };
|
return { counts, tids, tidsByFilter, unreadCids };
|
||||||
}
|
}
|
||||||
|
|
||||||
const blockedUids = await user.blocks.list(params.uid);
|
const blockedUids = await user.blocks.list(params.uid);
|
||||||
@@ -157,6 +158,7 @@ module.exports = function (Topics) {
|
|||||||
if (isTopicsFollowed[topic.tid] ||
|
if (isTopicsFollowed[topic.tid] ||
|
||||||
[categories.watchStates.watching, categories.watchStates.tracking].includes(userCidState[topic.cid])) {
|
[categories.watchStates.watching, categories.watchStates.tracking].includes(userCidState[topic.cid])) {
|
||||||
tidsByFilter[''].push(topic.tid);
|
tidsByFilter[''].push(topic.tid);
|
||||||
|
unreadCids.push(topic.cid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTopicsFollowed[topic.tid]) {
|
if (isTopicsFollowed[topic.tid]) {
|
||||||
@@ -182,6 +184,7 @@ module.exports = function (Topics) {
|
|||||||
counts: counts,
|
counts: counts,
|
||||||
tids: tidsByFilter[params.filter],
|
tids: tidsByFilter[params.filter],
|
||||||
tidsByFilter: tidsByFilter,
|
tidsByFilter: tidsByFilter,
|
||||||
|
unreadCids: _.uniq(unreadCids),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,7 +283,6 @@ module.exports = function (Topics) {
|
|||||||
Topics.markAsUnreadForAll = async function (tid) {
|
Topics.markAsUnreadForAll = async function (tid) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const cid = await Topics.getTopicField(tid, 'cid');
|
const cid = await Topics.getTopicField(tid, 'cid');
|
||||||
await Topics.markCategoryUnreadForAll(tid);
|
|
||||||
await Topics.updateRecent(tid, now);
|
await Topics.updateRecent(tid, now);
|
||||||
await db.sortedSetAdd(`cid:${cid}:tids:lastposttime`, now, tid);
|
await db.sortedSetAdd(`cid:${cid}:tids:lastposttime`, now, tid);
|
||||||
await Topics.setTopicField(tid, 'lastposttime', now);
|
await Topics.setTopicField(tid, 'lastposttime', now);
|
||||||
@@ -312,15 +314,11 @@ module.exports = function (Topics) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const scores = topics.map(topic => (topic.scheduled ? topic.lastposttime : now));
|
const scores = topics.map(topic => (topic.scheduled ? topic.lastposttime : now));
|
||||||
const [topicData] = await Promise.all([
|
await Promise.all([
|
||||||
Topics.getTopicsFields(tids, ['cid']),
|
|
||||||
db.sortedSetAdd(`uid:${uid}:tids_read`, scores, tids),
|
db.sortedSetAdd(`uid:${uid}:tids_read`, scores, tids),
|
||||||
db.sortedSetRemove(`uid:${uid}:tids_unread`, tids),
|
db.sortedSetRemove(`uid:${uid}:tids_unread`, tids),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const cids = _.uniq(topicData.map(t => t && t.cid).filter(Boolean));
|
|
||||||
await categories.markAsRead(cids, uid);
|
|
||||||
|
|
||||||
plugins.hooks.fire('action:topics.markAsRead', { uid: uid, tids: tids });
|
plugins.hooks.fire('action:topics.markAsRead', { uid: uid, tids: tids });
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -343,9 +341,11 @@ module.exports = function (Topics) {
|
|||||||
user.notifications.pushCount(uid);
|
user.notifications.pushCount(uid);
|
||||||
};
|
};
|
||||||
|
|
||||||
Topics.markCategoryUnreadForAll = async function (tid) {
|
Topics.markCategoryUnreadForAll = async function (/* tid */) {
|
||||||
const cid = await Topics.getTopicField(tid, 'cid');
|
// TODO: remove in 4.x
|
||||||
await categories.markAsUnreadForAll(cid);
|
console.warn('[deprecated] Topics.markCategoryUnreadForAll deprecated');
|
||||||
|
// const cid = await Topics.getTopicField(tid, 'cid');
|
||||||
|
// await categories.markAsUnreadForAll(cid);
|
||||||
};
|
};
|
||||||
|
|
||||||
Topics.hasReadTopics = async function (tids, uid) {
|
Topics.hasReadTopics = async function (tids, uid) {
|
||||||
|
|||||||
26
src/upgrades/3.7.0/category-read-by-uid.js
Normal file
26
src/upgrades/3.7.0/category-read-by-uid.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/* eslint-disable no-await-in-loop */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const db = require('../../database');
|
||||||
|
const batch = require('../../batch');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'Remove cid:<cid>:read_by_uid sets',
|
||||||
|
timestamp: Date.UTC(2024, 0, 29),
|
||||||
|
method: async function () {
|
||||||
|
const { progress } = this;
|
||||||
|
const nextCid = await db.getObjectField('global', 'nextCid');
|
||||||
|
const allCids = [];
|
||||||
|
for (let i = 1; i <= nextCid; i++) {
|
||||||
|
allCids.push(i);
|
||||||
|
}
|
||||||
|
await batch.processArray(allCids, async (cids) => {
|
||||||
|
await db.deleteAll(cids.map(cid => `cid:${cid}:read_by_uid`));
|
||||||
|
progress.incr(cids.length);
|
||||||
|
}, {
|
||||||
|
batch: 500,
|
||||||
|
progress,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -68,7 +68,7 @@ describe('Categories', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should get all categories', (done) => {
|
it('should get all categories', (done) => {
|
||||||
Categories.getAllCategories(1, (err, data) => {
|
Categories.getAllCategories((err, data) => {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert(Array.isArray(data));
|
assert(Array.isArray(data));
|
||||||
assert.equal(data[0].cid, categoryObj.cid);
|
assert.equal(data[0].cid, categoryObj.cid);
|
||||||
|
|||||||
Reference in New Issue
Block a user