2014-03-21 15:40:37 -04:00
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
|
2016-01-04 11:22:35 +02:00
|
|
|
var async = require('async');
|
2017-06-25 20:00:05 -04:00
|
|
|
var _ = require('lodash');
|
2014-03-21 15:40:37 -04:00
|
|
|
|
2016-01-04 11:22:35 +02:00
|
|
|
var db = require('../database');
|
|
|
|
|
var user = require('../user');
|
2018-09-14 16:23:16 -04:00
|
|
|
var posts = require('../posts');
|
2016-01-04 11:22:35 +02:00
|
|
|
var notifications = require('../notifications');
|
|
|
|
|
var categories = require('../categories');
|
|
|
|
|
var privileges = require('../privileges');
|
2016-01-04 14:33:47 +02:00
|
|
|
var meta = require('../meta');
|
2017-04-08 20:22:21 -06:00
|
|
|
var utils = require('../utils');
|
2017-05-13 18:46:11 -06:00
|
|
|
var plugins = require('../plugins');
|
2014-03-21 15:40:37 -04:00
|
|
|
|
2016-10-13 11:43:39 +02:00
|
|
|
module.exports = function (Topics) {
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.getTotalUnread = async function (uid, filter) {
|
|
|
|
|
filter = filter || '';
|
|
|
|
|
const counts = await Topics.getUnreadTids({ cid: 0, uid: uid, count: true });
|
|
|
|
|
return counts && counts[filter];
|
2014-03-21 15:40:37 -04:00
|
|
|
};
|
|
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.getUnreadTopics = async function (params) {
|
2014-08-29 14:50:24 -04:00
|
|
|
var unreadTopics = {
|
|
|
|
|
showSelect: true,
|
2017-02-18 01:27:46 -07:00
|
|
|
nextStart: 0,
|
2017-02-17 19:31:21 -07:00
|
|
|
topics: [],
|
2014-08-29 14:50:24 -04:00
|
|
|
};
|
2019-07-09 12:46:49 -04:00
|
|
|
let tids = await Topics.getUnreadTids(params);
|
|
|
|
|
unreadTopics.topicCount = tids.length;
|
2014-08-29 14:50:24 -04:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
if (!tids.length) {
|
|
|
|
|
return unreadTopics;
|
|
|
|
|
}
|
2016-05-13 14:08:50 +03:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
tids = tids.slice(params.start, params.stop !== -1 ? params.stop + 1 : undefined);
|
2016-05-13 14:08:50 +03:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
const topicData = await Topics.getTopicsByTids(tids, params.uid);
|
|
|
|
|
if (!topicData.length) {
|
|
|
|
|
return unreadTopics;
|
|
|
|
|
}
|
|
|
|
|
Topics.calculateTopicIndices(topicData, params.start);
|
|
|
|
|
unreadTopics.topics = topicData;
|
|
|
|
|
unreadTopics.nextStart = params.stop + 1;
|
|
|
|
|
return unreadTopics;
|
2014-08-29 14:50:24 -04:00
|
|
|
};
|
|
|
|
|
|
2016-10-13 11:43:39 +02:00
|
|
|
Topics.unreadCutoff = function () {
|
2018-10-21 16:47:51 -04:00
|
|
|
return Date.now() - (meta.config.unreadCutoff * 86400000);
|
2016-01-04 14:33:47 +02:00
|
|
|
};
|
|
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.getUnreadTids = async function (params) {
|
|
|
|
|
const results = await Topics.getUnreadData(params);
|
|
|
|
|
return params.count ? results.counts : results.tids;
|
2018-12-16 00:09:13 -05:00
|
|
|
};
|
|
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.getUnreadData = async function (params) {
|
2018-12-16 00:09:13 -05:00
|
|
|
const uid = parseInt(params.uid, 10);
|
|
|
|
|
const counts = {
|
2018-09-24 12:58:59 -04:00
|
|
|
'': 0,
|
|
|
|
|
new: 0,
|
|
|
|
|
watched: 0,
|
|
|
|
|
unreplied: 0,
|
|
|
|
|
};
|
2018-12-16 00:09:13 -05:00
|
|
|
const noUnreadData = {
|
|
|
|
|
tids: [],
|
|
|
|
|
counts: counts,
|
|
|
|
|
tidsByFilter: {
|
|
|
|
|
'': [],
|
|
|
|
|
new: [],
|
|
|
|
|
watched: [],
|
|
|
|
|
unreplied: [],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2018-09-22 01:28:13 -04:00
|
|
|
if (uid <= 0) {
|
2019-07-09 12:46:49 -04:00
|
|
|
return noUnreadData;
|
2014-08-15 18:11:57 -04:00
|
|
|
}
|
2017-04-21 21:36:42 -04:00
|
|
|
|
2018-09-24 12:58:59 -04:00
|
|
|
params.filter = params.filter || '';
|
|
|
|
|
|
2017-01-27 20:37:54 +03:00
|
|
|
var cutoff = params.cutoff || Topics.unreadCutoff();
|
2014-03-21 15:40:37 -04:00
|
|
|
|
2017-10-30 15:26:12 -04:00
|
|
|
if (params.cid && !Array.isArray(params.cid)) {
|
|
|
|
|
params.cid = [params.cid];
|
|
|
|
|
}
|
2019-07-09 12:46:49 -04:00
|
|
|
const [ignoredTids, recentTids, userScores, tids_unread] = await Promise.all([
|
|
|
|
|
user.getIgnoredTids(uid, 0, -1),
|
|
|
|
|
db.getSortedSetRevRangeByScoreWithScores('topics:recent', 0, -1, '+inf', cutoff),
|
|
|
|
|
db.getSortedSetRevRangeByScoreWithScores('uid:' + uid + ':tids_read', 0, -1, '+inf', cutoff),
|
|
|
|
|
db.getSortedSetRevRangeWithScores('uid:' + uid + ':tids_unread', 0, -1),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
if (recentTids && !recentTids.length && !tids_unread.length) {
|
|
|
|
|
return noUnreadData;
|
|
|
|
|
}
|
2017-10-30 15:26:12 -04:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
const data = await filterTopics(params, {
|
|
|
|
|
ignoredTids: ignoredTids,
|
|
|
|
|
recentTids: recentTids,
|
|
|
|
|
userScores: userScores,
|
|
|
|
|
tids_unread: tids_unread,
|
|
|
|
|
});
|
|
|
|
|
const result = await plugins.fireHook('filter:topics.getUnreadTids', {
|
|
|
|
|
uid: uid,
|
|
|
|
|
tids: data.tids,
|
|
|
|
|
counts: data.counts,
|
|
|
|
|
tidsByFilter: data.tidsByFilter,
|
|
|
|
|
cid: params.cid,
|
|
|
|
|
filter: params.filter,
|
|
|
|
|
});
|
|
|
|
|
return result;
|
2016-04-18 15:44:07 +03:00
|
|
|
};
|
|
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
async function filterTopics(params, results) {
|
2018-09-24 12:58:59 -04:00
|
|
|
const counts = {
|
|
|
|
|
'': 0,
|
|
|
|
|
new: 0,
|
|
|
|
|
watched: 0,
|
|
|
|
|
unreplied: 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const tidsByFilter = {
|
|
|
|
|
'': [],
|
|
|
|
|
new: [],
|
|
|
|
|
watched: [],
|
|
|
|
|
unreplied: [],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var userRead = {};
|
|
|
|
|
results.userScores.forEach(function (userItem) {
|
|
|
|
|
userRead[userItem.value] = userItem.score;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
results.recentTids = results.recentTids.concat(results.tids_unread);
|
|
|
|
|
results.recentTids.sort(function (a, b) {
|
|
|
|
|
return b.score - a.score;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var tids = results.recentTids.filter(function (recentTopic) {
|
|
|
|
|
if (results.ignoredTids.includes(String(recentTopic.value))) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return !userRead[recentTopic.value] || recentTopic.score > userRead[recentTopic.value];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
tids = _.uniq(tids.map(topic => topic.value));
|
|
|
|
|
|
|
|
|
|
var cid = params.cid;
|
|
|
|
|
var uid = params.uid;
|
|
|
|
|
var cids;
|
|
|
|
|
var topicData;
|
|
|
|
|
|
|
|
|
|
tids = tids.slice(0, 200);
|
|
|
|
|
|
2017-04-21 21:36:42 -04:00
|
|
|
if (!tids.length) {
|
2019-07-09 12:46:49 -04:00
|
|
|
return { counts: counts, tids: tids, tidsByFilter: tidsByFilter };
|
2014-08-29 15:57:20 -04:00
|
|
|
}
|
2019-07-09 12:46:49 -04:00
|
|
|
const blockedUids = await user.blocks.list(uid);
|
2014-08-29 15:57:20 -04:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
tids = await filterTidsThatHaveBlockedPosts({
|
|
|
|
|
uid: uid,
|
|
|
|
|
tids: tids,
|
|
|
|
|
blockedUids: blockedUids,
|
|
|
|
|
recentTids: results.recentTids,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
topicData = await Topics.getTopicsFields(tids, ['tid', 'cid', 'uid', 'postcount']);
|
|
|
|
|
cids = _.uniq(topicData.map(topic => topic.cid)).filter(Boolean);
|
|
|
|
|
|
|
|
|
|
const [isTopicsFollowed, categoryWatchState, readCids] = await Promise.all([
|
|
|
|
|
db.sortedSetScores('uid:' + uid + ':followed_tids', tids),
|
|
|
|
|
categories.getWatchState(cids, uid),
|
|
|
|
|
privileges.categories.filterCids('read', cids, uid),
|
|
|
|
|
]);
|
|
|
|
|
cid = cid && cid.map(String);
|
|
|
|
|
const readableCids = readCids.map(String);
|
|
|
|
|
const userCidState = _.zipObject(cids, categoryWatchState);
|
|
|
|
|
|
|
|
|
|
topicData.forEach(function (topic, index) {
|
|
|
|
|
function cidMatch(topicCid) {
|
|
|
|
|
return (!cid || (cid.length && cid.includes(String(topicCid)))) && readableCids.includes(String(topicCid));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (topic && topic.cid && cidMatch(topic.cid) && !blockedUids.includes(parseInt(topic.uid, 10))) {
|
|
|
|
|
topic.tid = parseInt(topic.tid, 10);
|
|
|
|
|
if ((isTopicsFollowed[index] || userCidState[topic.cid] === categories.watchStates.watching)) {
|
|
|
|
|
tidsByFilter[''].push(topic.tid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isTopicsFollowed[index]) {
|
|
|
|
|
tidsByFilter.watched.push(topic.tid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (topic.postcount <= 1) {
|
|
|
|
|
tidsByFilter.unreplied.push(topic.tid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!userRead[topic.tid]) {
|
|
|
|
|
tidsByFilter.new.push(topic.tid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
counts[''] = tidsByFilter[''].length;
|
|
|
|
|
counts.watched = tidsByFilter.watched.length;
|
|
|
|
|
counts.unreplied = tidsByFilter.unreplied.length;
|
|
|
|
|
counts.new = tidsByFilter.new.length;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
counts: counts,
|
|
|
|
|
tids: tidsByFilter[params.filter],
|
|
|
|
|
tidsByFilter: tidsByFilter,
|
|
|
|
|
};
|
2018-09-14 16:23:16 -04:00
|
|
|
}
|
|
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
async function filterTidsThatHaveBlockedPosts(params) {
|
2018-09-24 12:58:59 -04:00
|
|
|
if (!params.blockedUids.length) {
|
2019-07-09 12:46:49 -04:00
|
|
|
return params.tids;
|
2018-09-24 12:58:59 -04:00
|
|
|
}
|
2018-09-27 09:52:56 -04:00
|
|
|
const topicScores = _.mapValues(_.keyBy(params.recentTids, 'value'), 'score');
|
2018-09-24 12:58:59 -04:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
const results = await db.sortedSetScores('uid:' + params.uid + ':tids_read', params.tids);
|
|
|
|
|
|
|
|
|
|
const userScores = _.zipObject(params.tids, results);
|
|
|
|
|
|
|
|
|
|
return await async.filter(params.tids, async function (tid) {
|
|
|
|
|
return await doesTidHaveUnblockedUnreadPosts(tid, {
|
|
|
|
|
blockedUids: params.blockedUids,
|
|
|
|
|
topicTimestamp: topicScores[tid],
|
|
|
|
|
userLastReadTimestamp: userScores[tid],
|
|
|
|
|
});
|
2018-09-24 12:58:59 -04:00
|
|
|
});
|
2018-09-14 16:23:16 -04:00
|
|
|
}
|
|
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
async function doesTidHaveUnblockedUnreadPosts(tid, params) {
|
2018-09-27 09:52:56 -04:00
|
|
|
var userLastReadTimestamp = params.userLastReadTimestamp;
|
2018-09-24 12:58:59 -04:00
|
|
|
if (!userLastReadTimestamp) {
|
2019-07-09 12:46:49 -04:00
|
|
|
return true;
|
2018-09-24 12:58:59 -04:00
|
|
|
}
|
|
|
|
|
var start = 0;
|
2018-09-27 09:52:56 -04:00
|
|
|
var count = 3;
|
2018-09-24 12:58:59 -04:00
|
|
|
var done = false;
|
2018-09-27 09:52:56 -04:00
|
|
|
var hasUnblockedUnread = params.topicTimestamp > userLastReadTimestamp;
|
2019-03-12 14:02:07 -04:00
|
|
|
if (!params.blockedUids.length) {
|
2019-07-09 12:46:49 -04:00
|
|
|
return hasUnblockedUnread;
|
2019-03-12 14:02:07 -04:00
|
|
|
}
|
2019-07-09 12:46:49 -04:00
|
|
|
while (!done) {
|
|
|
|
|
/* eslint-disable no-await-in-loop */
|
|
|
|
|
const pidsSinceLastVisit = await db.getSortedSetRangeByScore('tid:' + tid + ':posts', start, count, userLastReadTimestamp, '+inf');
|
|
|
|
|
if (!pidsSinceLastVisit.length) {
|
|
|
|
|
return hasUnblockedUnread;
|
|
|
|
|
}
|
|
|
|
|
let postData = await posts.getPostsFields(pidsSinceLastVisit, ['pid', 'uid']);
|
|
|
|
|
postData = postData.filter(function (post) {
|
|
|
|
|
return !params.blockedUids.includes(parseInt(post.uid, 10));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
done = postData.length > 0;
|
|
|
|
|
hasUnblockedUnread = postData.length > 0;
|
|
|
|
|
start += count;
|
|
|
|
|
}
|
|
|
|
|
return hasUnblockedUnread;
|
2014-08-29 15:57:20 -04:00
|
|
|
}
|
2014-03-21 15:40:37 -04:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.pushUnreadCount = async function (uid) {
|
2018-11-17 22:31:39 -05:00
|
|
|
if (!uid || parseInt(uid, 10) <= 0) {
|
2019-07-09 12:46:49 -04:00
|
|
|
return;
|
2014-03-21 15:40:37 -04:00
|
|
|
}
|
2019-07-09 12:46:49 -04:00
|
|
|
const results = await Topics.getUnreadTids({ uid: uid, count: true });
|
|
|
|
|
require('../socket.io').in('uid_' + uid).emit('event:unread.updateCount', {
|
|
|
|
|
unreadTopicCount: results[''],
|
|
|
|
|
unreadNewTopicCount: results.new,
|
|
|
|
|
unreadWatchedTopicCount: results.watched,
|
|
|
|
|
unreadUnrepliedTopicCount: results.unreplied,
|
|
|
|
|
});
|
2014-03-21 15:40:37 -04:00
|
|
|
};
|
|
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.markAsUnreadForAll = async function (tid) {
|
|
|
|
|
await Topics.markCategoryUnreadForAll(tid);
|
2014-03-21 15:40:37 -04:00
|
|
|
};
|
|
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.markAsRead = async function (tids, uid) {
|
2014-09-10 21:44:19 -04:00
|
|
|
if (!Array.isArray(tids) || !tids.length) {
|
2019-07-09 12:46:49 -04:00
|
|
|
return false;
|
2014-03-21 15:40:37 -04:00
|
|
|
}
|
2016-01-04 14:33:47 +02:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
tids = _.uniq(tids).filter(tid => tid && utils.isNumber(tid));
|
2016-01-04 14:33:47 +02:00
|
|
|
|
2015-01-27 10:36:30 -05:00
|
|
|
if (!tids.length) {
|
2019-07-09 12:46:49 -04:00
|
|
|
return false;
|
2015-01-27 10:36:30 -05:00
|
|
|
}
|
2019-07-09 12:46:49 -04:00
|
|
|
const [topicScores, userScores] = await Promise.all([
|
|
|
|
|
db.sortedSetScores('topics:recent', tids),
|
|
|
|
|
db.sortedSetScores('uid:' + uid + ':tids_read', tids),
|
|
|
|
|
]);
|
2014-03-21 15:40:37 -04:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
tids = tids.filter(function (tid, index) {
|
|
|
|
|
return topicScores[index] && (!userScores[index] || userScores[index] < topicScores[index]);
|
|
|
|
|
});
|
2014-10-14 02:39:20 -04:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
if (!tids.length) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-11-05 11:53:17 -05:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
var now = Date.now();
|
|
|
|
|
var scores = tids.map(() => now);
|
|
|
|
|
const [topicData] = await Promise.all([
|
|
|
|
|
Topics.getTopicsFields(tids, ['cid']),
|
|
|
|
|
db.sortedSetAdd('uid:' + uid + ':tids_read', scores, tids),
|
|
|
|
|
db.sortedSetRemove('uid:' + uid + ':tids_unread', tids),
|
|
|
|
|
]);
|
2017-06-25 20:00:05 -04:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
var cids = _.uniq(topicData.map(t => t && t.cid).filter(Boolean));
|
|
|
|
|
await categories.markAsRead(cids, uid);
|
2014-10-14 02:39:20 -04:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
plugins.fireHook('action:topics.markAsRead', { uid: uid, tids: tids });
|
|
|
|
|
return true;
|
2014-03-21 17:48:32 -04:00
|
|
|
};
|
2014-03-21 15:40:37 -04:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.markAllRead = async function (uid) {
|
|
|
|
|
const tids = await db.getSortedSetRevRangeByScore('topics:recent', 0, -1, '+inf', Topics.unreadCutoff());
|
|
|
|
|
Topics.markTopicNotificationsRead(tids, uid);
|
|
|
|
|
await Topics.markAsRead(tids, uid);
|
|
|
|
|
await db.delete('uid:' + uid + ':tids_unread');
|
2016-01-04 14:33:47 +02:00
|
|
|
};
|
|
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.markTopicNotificationsRead = async function (tids, uid) {
|
2016-09-19 23:43:50 +03:00
|
|
|
if (!Array.isArray(tids) || !tids.length) {
|
2019-07-09 12:46:49 -04:00
|
|
|
return;
|
2014-09-19 19:45:16 -04:00
|
|
|
}
|
2019-07-09 12:46:49 -04:00
|
|
|
const nids = await user.notifications.getUnreadByField(uid, 'tid', tids);
|
|
|
|
|
await notifications.markReadMultiple(nids, uid);
|
|
|
|
|
user.notifications.pushCount(uid);
|
2014-03-21 15:40:37 -04:00
|
|
|
};
|
|
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.markCategoryUnreadForAll = async function (tid) {
|
|
|
|
|
const cid = await Topics.getTopicField(tid, 'cid');
|
|
|
|
|
await categories.markAsUnreadForAll(cid);
|
2014-03-21 15:40:37 -04:00
|
|
|
};
|
|
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.hasReadTopics = async function (tids, uid) {
|
2018-12-12 19:43:35 -05:00
|
|
|
if (!(parseInt(uid, 10) > 0)) {
|
2019-07-09 12:46:49 -04:00
|
|
|
return tids.map(() => false);
|
2014-03-21 15:40:37 -04:00
|
|
|
}
|
2019-07-09 12:46:49 -04:00
|
|
|
const [topicScores, userScores, tids_unread, blockedUids] = await Promise.all([
|
|
|
|
|
db.sortedSetScores('topics:recent', tids),
|
|
|
|
|
db.sortedSetScores('uid:' + uid + ':tids_read', tids),
|
|
|
|
|
db.sortedSetScores('uid:' + uid + ':tids_unread', tids),
|
|
|
|
|
user.blocks.list(uid),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
var cutoff = Topics.unreadCutoff();
|
|
|
|
|
var result = tids.map(function (tid, index) {
|
|
|
|
|
var read = !tids_unread[index] &&
|
|
|
|
|
(topicScores[index] < cutoff ||
|
|
|
|
|
!!(userScores[index] && userScores[index] >= topicScores[index]));
|
|
|
|
|
return { tid: tid, read: read, index: index };
|
|
|
|
|
});
|
2014-03-21 15:40:37 -04:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
return await async.map(result, async function (data) {
|
|
|
|
|
if (data.read) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
const hasUnblockedUnread = await doesTidHaveUnblockedUnreadPosts(data.tid, {
|
|
|
|
|
topicTimestamp: topicScores[data.index],
|
|
|
|
|
userLastReadTimestamp: userScores[data.index],
|
|
|
|
|
blockedUids: blockedUids,
|
|
|
|
|
});
|
|
|
|
|
if (!hasUnblockedUnread) {
|
|
|
|
|
data.read = true;
|
|
|
|
|
}
|
|
|
|
|
return data.read;
|
|
|
|
|
});
|
2014-03-21 15:40:37 -04:00
|
|
|
};
|
|
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.hasReadTopic = async function (tid, uid) {
|
|
|
|
|
const hasRead = await Topics.hasReadTopics([tid], uid);
|
|
|
|
|
return Array.isArray(hasRead) && hasRead.length ? hasRead[0] : false;
|
2014-03-21 15:40:37 -04:00
|
|
|
};
|
|
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.markUnread = async function (tid, uid) {
|
|
|
|
|
const exists = await Topics.exists(tid);
|
|
|
|
|
if (!exists) {
|
|
|
|
|
throw new Error('[[error:no-topic]]');
|
|
|
|
|
}
|
|
|
|
|
await db.sortedSetRemove('uid:' + uid + ':tids_read', tid);
|
|
|
|
|
await db.sortedSetAdd('uid:' + uid + ':tids_unread', Date.now(), tid);
|
2016-01-04 11:22:35 +02:00
|
|
|
};
|
2014-03-21 15:40:37 -04:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.filterNewTids = async function (tids, uid) {
|
2018-11-22 22:21:03 -05:00
|
|
|
if (parseInt(uid, 10) <= 0) {
|
2019-07-09 12:46:49 -04:00
|
|
|
return [];
|
2018-11-22 22:21:03 -05:00
|
|
|
}
|
2019-07-09 12:46:49 -04:00
|
|
|
const scores = await db.sortedSetScores('uid:' + uid + ':tids_read', tids);
|
|
|
|
|
return tids.filter((tid, index) => tid && !scores[index]);
|
2016-11-03 13:06:21 +03:00
|
|
|
};
|
2017-10-19 13:53:05 -04:00
|
|
|
|
2019-07-09 12:46:49 -04:00
|
|
|
Topics.filterUnrepliedTids = async function (tids) {
|
|
|
|
|
const scores = await db.sortedSetScores('topics:posts', tids);
|
|
|
|
|
return tids.filter((tid, index) => tid && scores[index] <= 1);
|
2017-10-19 13:53:05 -04:00
|
|
|
};
|
2014-04-10 20:31:57 +01:00
|
|
|
};
|