You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
4.8 KiB
JavaScript
178 lines
4.8 KiB
JavaScript
|
|
'use strict';
|
|
|
|
const db = require('../database');
|
|
const notifications = require('../notifications');
|
|
const privileges = require('../privileges');
|
|
const plugins = require('../plugins');
|
|
const utils = require('../utils');
|
|
|
|
module.exports = function (Topics) {
|
|
Topics.toggleFollow = async function (tid, uid) {
|
|
const exists = await Topics.exists(tid);
|
|
if (!exists) {
|
|
throw new Error('[[error:no-topic]]');
|
|
}
|
|
const isFollowing = await Topics.isFollowing([tid], uid);
|
|
if (isFollowing[0]) {
|
|
await Topics.unfollow(tid, uid);
|
|
} else {
|
|
await Topics.follow(tid, uid);
|
|
}
|
|
return !isFollowing[0];
|
|
};
|
|
|
|
Topics.follow = async function (tid, uid) {
|
|
await setWatching(follow, unignore, 'action:topic.follow', tid, uid);
|
|
};
|
|
|
|
Topics.unfollow = async function (tid, uid) {
|
|
await setWatching(unfollow, unignore, 'action:topic.unfollow', tid, uid);
|
|
};
|
|
|
|
Topics.ignore = async function (tid, uid) {
|
|
await setWatching(ignore, unfollow, 'action:topic.ignore', tid, uid);
|
|
};
|
|
|
|
async function setWatching(method1, method2, hook, tid, uid) {
|
|
if (parseInt(uid, 10) <= 0) {
|
|
return;
|
|
}
|
|
const exists = await Topics.exists(tid);
|
|
if (!exists) {
|
|
throw new Error('[[error:no-topic]]');
|
|
}
|
|
await method1(tid, uid);
|
|
await method2(tid, uid);
|
|
plugins.hooks.fire(hook, { uid: uid, tid: tid });
|
|
}
|
|
|
|
async function follow(tid, uid) {
|
|
await addToSets(`tid:${tid}:followers`, `uid:${uid}:followed_tids`, tid, uid);
|
|
}
|
|
|
|
async function unfollow(tid, uid) {
|
|
await removeFromSets(`tid:${tid}:followers`, `uid:${uid}:followed_tids`, tid, uid);
|
|
}
|
|
|
|
async function ignore(tid, uid) {
|
|
await addToSets(`tid:${tid}:ignorers`, `uid:${uid}:ignored_tids`, tid, uid);
|
|
}
|
|
|
|
async function unignore(tid, uid) {
|
|
await removeFromSets(`tid:${tid}:ignorers`, `uid:${uid}:ignored_tids`, tid, uid);
|
|
}
|
|
|
|
async function addToSets(set1, set2, tid, uid) {
|
|
await db.setAdd(set1, uid);
|
|
await db.sortedSetAdd(set2, Date.now(), tid);
|
|
}
|
|
|
|
async function removeFromSets(set1, set2, tid, uid) {
|
|
await db.setRemove(set1, uid);
|
|
await db.sortedSetRemove(set2, tid);
|
|
}
|
|
|
|
Topics.isFollowing = async function (tids, uid) {
|
|
return await isIgnoringOrFollowing('followers', tids, uid);
|
|
};
|
|
|
|
Topics.isIgnoring = async function (tids, uid) {
|
|
return await isIgnoringOrFollowing('ignorers', tids, uid);
|
|
};
|
|
|
|
Topics.getFollowData = async function (tids, uid) {
|
|
if (!Array.isArray(tids)) {
|
|
return;
|
|
}
|
|
if (parseInt(uid, 10) <= 0) {
|
|
return tids.map(() => ({ following: false, ignoring: false }));
|
|
}
|
|
const keys = [];
|
|
tids.forEach(tid => keys.push(`tid:${tid}:followers`, `tid:${tid}:ignorers`));
|
|
|
|
const data = await db.isMemberOfSets(keys, uid);
|
|
|
|
const followData = [];
|
|
for (let i = 0; i < data.length; i += 2) {
|
|
followData.push({
|
|
following: data[i],
|
|
ignoring: data[i + 1],
|
|
});
|
|
}
|
|
return followData;
|
|
};
|
|
|
|
async function isIgnoringOrFollowing(set, tids, uid) {
|
|
if (!Array.isArray(tids)) {
|
|
return;
|
|
}
|
|
if (parseInt(uid, 10) <= 0) {
|
|
return tids.map(() => false);
|
|
}
|
|
const keys = tids.map(tid => `tid:${tid}:${set}`);
|
|
return await db.isMemberOfSets(keys, uid);
|
|
}
|
|
|
|
Topics.getFollowers = async function (tid) {
|
|
return await db.getSetMembers(`tid:${tid}:followers`);
|
|
};
|
|
|
|
Topics.getIgnorers = async function (tid) {
|
|
return await db.getSetMembers(`tid:${tid}:ignorers`);
|
|
};
|
|
|
|
Topics.filterIgnoringUids = async function (tid, uids) {
|
|
const isIgnoring = await db.isSetMembers(`tid:${tid}:ignorers`, uids);
|
|
const readingUids = uids.filter((uid, index) => uid && !isIgnoring[index]);
|
|
return readingUids;
|
|
};
|
|
|
|
Topics.filterWatchedTids = async function (tids, uid) {
|
|
if (parseInt(uid, 10) <= 0) {
|
|
return [];
|
|
}
|
|
const scores = await db.sortedSetScores(`uid:${uid}:followed_tids`, tids);
|
|
return tids.filter((tid, index) => tid && !!scores[index]);
|
|
};
|
|
|
|
Topics.filterNotIgnoredTids = async function (tids, uid) {
|
|
if (parseInt(uid, 10) <= 0) {
|
|
return tids;
|
|
}
|
|
const scores = await db.sortedSetScores(`uid:${uid}:ignored_tids`, tids);
|
|
return tids.filter((tid, index) => tid && !scores[index]);
|
|
};
|
|
|
|
Topics.notifyFollowers = async function (postData, exceptUid, notifData) {
|
|
notifData = notifData || {};
|
|
let followers = await Topics.getFollowers(postData.topic.tid);
|
|
const index = followers.indexOf(String(exceptUid));
|
|
if (index !== -1) {
|
|
followers.splice(index, 1);
|
|
}
|
|
|
|
followers = await privileges.topics.filterUids('topics:read', postData.topic.tid, followers);
|
|
if (!followers.length) {
|
|
return;
|
|
}
|
|
|
|
let { title } = postData.topic;
|
|
if (title) {
|
|
title = utils.decodeHTMLEntities(title);
|
|
}
|
|
|
|
const notification = await notifications.create({
|
|
subject: title,
|
|
bodyLong: postData.content,
|
|
pid: postData.pid,
|
|
path: `/post/${postData.pid}`,
|
|
tid: postData.topic.tid,
|
|
from: exceptUid,
|
|
topicTitle: title,
|
|
...notifData,
|
|
});
|
|
notifications.push(notification, followers);
|
|
};
|
|
};
|