refactor: async/await socket.io/topics
parent
ebe5ed22bb
commit
5c2afe5eac
@ -1,27 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var topics = require('../../topics');
|
||||
var privileges = require('../../privileges');
|
||||
const topics = require('../../topics');
|
||||
const privileges = require('../../privileges');
|
||||
|
||||
module.exports = function (SocketTopics) {
|
||||
SocketTopics.merge = function (socket, tids, callback) {
|
||||
SocketTopics.merge = async function (socket, tids) {
|
||||
if (!Array.isArray(tids)) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.map(tids, function (tid, next) {
|
||||
privileges.topics.isAdminOrMod(tid, socket.uid, next);
|
||||
}, next);
|
||||
},
|
||||
function (allowed, next) {
|
||||
if (allowed.includes(false)) {
|
||||
return next(new Error('[[error:no-privileges]]'));
|
||||
}
|
||||
topics.merge(tids, socket.uid, next);
|
||||
},
|
||||
], callback);
|
||||
const allowed = await Promise.all(tids.map(tid => privileges.topics.isAdminOrMod(tid, socket.uid)));
|
||||
if (allowed.includes(false)) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
await topics.merge(tids, socket.uid);
|
||||
};
|
||||
};
|
||||
|
@ -1,70 +1,46 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var topics = require('../../topics');
|
||||
var categories = require('../../categories');
|
||||
var privileges = require('../../privileges');
|
||||
var socketHelpers = require('../helpers');
|
||||
const async = require('async');
|
||||
const topics = require('../../topics');
|
||||
const categories = require('../../categories');
|
||||
const privileges = require('../../privileges');
|
||||
const socketHelpers = require('../helpers');
|
||||
|
||||
module.exports = function (SocketTopics) {
|
||||
SocketTopics.move = function (socket, data, callback) {
|
||||
SocketTopics.move = async function (socket, data) {
|
||||
if (!data || !Array.isArray(data.tids) || !data.cid) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
|
||||
async.eachLimit(data.tids, 10, function (tid, next) {
|
||||
var topicData;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
privileges.topics.isAdminOrMod(tid, socket.uid, next);
|
||||
},
|
||||
function (canMove, next) {
|
||||
if (!canMove) {
|
||||
return next(new Error('[[error:no-privileges]]'));
|
||||
}
|
||||
await async.eachLimit(data.tids, 10, async function (tid) {
|
||||
const canMove = await privileges.topics.isAdminOrMod(tid, socket.uid);
|
||||
if (!canMove) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
const topicData = await topics.getTopicFields(tid, ['tid', 'cid', 'slug']);
|
||||
data.uid = socket.uid;
|
||||
await topics.tools.move(tid, data);
|
||||
|
||||
topics.getTopicFields(tid, ['cid', 'slug'], next);
|
||||
},
|
||||
function (_topicData, next) {
|
||||
topicData = _topicData;
|
||||
topicData.tid = tid;
|
||||
data.uid = socket.uid;
|
||||
topics.tools.move(tid, data, next);
|
||||
},
|
||||
function (next) {
|
||||
socketHelpers.emitToTopicAndCategory('event:topic_moved', topicData);
|
||||
socketHelpers.emitToTopicAndCategory('event:topic_moved', topicData);
|
||||
|
||||
socketHelpers.sendNotificationToTopicOwner(tid, socket.uid, 'move', 'notifications:moved_your_topic');
|
||||
|
||||
next();
|
||||
},
|
||||
], next);
|
||||
}, callback);
|
||||
socketHelpers.sendNotificationToTopicOwner(tid, socket.uid, 'move', 'notifications:moved_your_topic');
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
SocketTopics.moveAll = function (socket, data, callback) {
|
||||
SocketTopics.moveAll = async function (socket, data) {
|
||||
if (!data || !data.cid || !data.currentCid) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
const canMove = await privileges.categories.canMoveAllTopics(data.currentCid, data.cid, socket.uid);
|
||||
if (!canMove) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
privileges.categories.canMoveAllTopics(data.currentCid, data.cid, socket.uid, next);
|
||||
},
|
||||
function (canMove, next) {
|
||||
if (!canMove) {
|
||||
return callback(new Error('[[error:no-privileges]]'));
|
||||
}
|
||||
|
||||
categories.getAllTopicIds(data.currentCid, 0, -1, next);
|
||||
},
|
||||
function (tids, next) {
|
||||
data.uid = socket.uid;
|
||||
async.eachLimit(tids, 50, function (tid, next) {
|
||||
topics.tools.move(tid, data, next);
|
||||
}, next);
|
||||
},
|
||||
], callback);
|
||||
const tids = await categories.getAllTopicIds(data.currentCid, 0, -1);
|
||||
data.uid = socket.uid;
|
||||
await async.eachLimit(tids, 50, async function (tid) {
|
||||
await topics.tools.move(tid, data);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
@ -1,67 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var db = require('../../database');
|
||||
var topics = require('../../topics');
|
||||
var privileges = require('../../privileges');
|
||||
var utils = require('../../utils');
|
||||
const topics = require('../../topics');
|
||||
const categories = require('../../categories');
|
||||
const privileges = require('../../privileges');
|
||||
const utils = require('../../utils');
|
||||
|
||||
module.exports = function (SocketTopics) {
|
||||
SocketTopics.isTagAllowed = function (socket, data, callback) {
|
||||
SocketTopics.isTagAllowed = async function (socket, data) {
|
||||
if (!data || !utils.isNumber(data.cid) || !data.tag) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.getSortedSetRange('cid:' + data.cid + ':tag:whitelist', 0, -1, next);
|
||||
},
|
||||
function (tagWhitelist, next) {
|
||||
next(null, !tagWhitelist.length || tagWhitelist.includes(data.tag));
|
||||
},
|
||||
], callback);
|
||||
|
||||
const tagWhitelist = await categories.getTagWhitelist([data.cid]);
|
||||
return !tagWhitelist[0].length || tagWhitelist[0].includes(data.tag);
|
||||
};
|
||||
|
||||
SocketTopics.autocompleteTags = function (socket, data, callback) {
|
||||
topics.autocompleteTags(data, callback);
|
||||
SocketTopics.autocompleteTags = async function (socket, data) {
|
||||
return await topics.autocompleteTags(data);
|
||||
};
|
||||
|
||||
SocketTopics.searchTags = function (socket, data, callback) {
|
||||
searchTags(socket.uid, topics.searchTags, data, callback);
|
||||
SocketTopics.searchTags = async function (socket, data) {
|
||||
return await searchTags(socket.uid, topics.searchTags, data);
|
||||
};
|
||||
|
||||
SocketTopics.searchAndLoadTags = function (socket, data, callback) {
|
||||
searchTags(socket.uid, topics.searchAndLoadTags, data, callback);
|
||||
SocketTopics.searchAndLoadTags = async function (socket, data) {
|
||||
return await searchTags(socket.uid, topics.searchAndLoadTags, data);
|
||||
};
|
||||
|
||||
function searchTags(uid, method, data, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
privileges.global.can('search:tags', uid, next);
|
||||
},
|
||||
function (allowed, next) {
|
||||
if (!allowed) {
|
||||
return next(new Error('[[error:no-privileges]]'));
|
||||
}
|
||||
method(data, next);
|
||||
},
|
||||
], callback);
|
||||
async function searchTags(uid, method, data) {
|
||||
const allowed = await privileges.global.can('search:tags', uid);
|
||||
if (!allowed) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
return await method(data);
|
||||
}
|
||||
|
||||
SocketTopics.loadMoreTags = function (socket, data, callback) {
|
||||
SocketTopics.loadMoreTags = async function (socket, data) {
|
||||
if (!data || !utils.isNumber(data.after)) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
|
||||
var start = parseInt(data.after, 10);
|
||||
var stop = start + 99;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
topics.getTags(start, stop, next);
|
||||
},
|
||||
function (tags, next) {
|
||||
tags = tags.filter(Boolean);
|
||||
next(null, { tags: tags, nextStart: stop + 1 });
|
||||
},
|
||||
], callback);
|
||||
const start = parseInt(data.after, 10);
|
||||
const stop = start + 99;
|
||||
const tags = await topics.getTags(start, stop);
|
||||
|
||||
return { tags: tags.filter(Boolean), nextStart: stop + 1 };
|
||||
};
|
||||
};
|
||||
|
@ -1,127 +1,104 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
|
||||
var topics = require('../../topics');
|
||||
var events = require('../../events');
|
||||
var privileges = require('../../privileges');
|
||||
var plugins = require('../../plugins');
|
||||
var socketHelpers = require('../helpers');
|
||||
const topics = require('../../topics');
|
||||
const events = require('../../events');
|
||||
const privileges = require('../../privileges');
|
||||
const plugins = require('../../plugins');
|
||||
const socketHelpers = require('../helpers');
|
||||
|
||||
module.exports = function (SocketTopics) {
|
||||
SocketTopics.loadTopicTools = function (socket, data, callback) {
|
||||
SocketTopics.loadTopicTools = async function (socket, data) {
|
||||
if (!socket.uid) {
|
||||
return callback(new Error('[[error:no-privileges]]'));
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
if (!data) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.parallel({
|
||||
topic: function (next) {
|
||||
topics.getTopicData(data.tid, next);
|
||||
},
|
||||
privileges: function (next) {
|
||||
privileges.topics.get(data.tid, socket.uid, next);
|
||||
},
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
if (!results.topic) {
|
||||
return next(new Error('[[error:no-topic]]'));
|
||||
}
|
||||
|
||||
results.topic.privileges = results.privileges;
|
||||
plugins.fireHook('filter:topic.thread_tools', { topic: results.topic, uid: socket.uid, tools: [] }, next);
|
||||
},
|
||||
function (data, next) {
|
||||
data.topic.thread_tools = data.tools;
|
||||
next(null, data.topic);
|
||||
},
|
||||
], callback);
|
||||
const [topicData, userPrivileges] = await Promise.all([
|
||||
topics.getTopicData(data.tid),
|
||||
privileges.topics.get(data.tid, socket.uid),
|
||||
]);
|
||||
|
||||
if (!topicData) {
|
||||
throw new Error('[[error:no-topic]]');
|
||||
}
|
||||
if (!userPrivileges['topics:read']) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
topicData.privileges = userPrivileges;
|
||||
const result = await plugins.fireHook('filter:topic.thread_tools', { topic: topicData, uid: socket.uid, tools: [] });
|
||||
result.topic.thread_tools = result.tools;
|
||||
return result.topic;
|
||||
};
|
||||
|
||||
SocketTopics.delete = function (socket, data, callback) {
|
||||
SocketTopics.doTopicAction('delete', 'event:topic_deleted', socket, data, callback);
|
||||
SocketTopics.delete = async function (socket, data) {
|
||||
await SocketTopics.doTopicAction('delete', 'event:topic_deleted', socket, data);
|
||||
};
|
||||
|
||||
SocketTopics.restore = function (socket, data, callback) {
|
||||
SocketTopics.doTopicAction('restore', 'event:topic_restored', socket, data, callback);
|
||||
SocketTopics.restore = async function (socket, data) {
|
||||
await SocketTopics.doTopicAction('restore', 'event:topic_restored', socket, data);
|
||||
};
|
||||
|
||||
SocketTopics.purge = function (socket, data, callback) {
|
||||
SocketTopics.doTopicAction('purge', 'event:topic_purged', socket, data, callback);
|
||||
SocketTopics.purge = async function (socket, data) {
|
||||
await SocketTopics.doTopicAction('purge', 'event:topic_purged', socket, data);
|
||||
};
|
||||
|
||||
SocketTopics.lock = function (socket, data, callback) {
|
||||
SocketTopics.doTopicAction('lock', 'event:topic_locked', socket, data, callback);
|
||||
SocketTopics.lock = async function (socket, data) {
|
||||
await SocketTopics.doTopicAction('lock', 'event:topic_locked', socket, data);
|
||||
};
|
||||
|
||||
SocketTopics.unlock = function (socket, data, callback) {
|
||||
SocketTopics.doTopicAction('unlock', 'event:topic_unlocked', socket, data, callback);
|
||||
SocketTopics.unlock = async function (socket, data) {
|
||||
await SocketTopics.doTopicAction('unlock', 'event:topic_unlocked', socket, data);
|
||||
};
|
||||
|
||||
SocketTopics.pin = function (socket, data, callback) {
|
||||
SocketTopics.doTopicAction('pin', 'event:topic_pinned', socket, data, callback);
|
||||
SocketTopics.pin = async function (socket, data) {
|
||||
await SocketTopics.doTopicAction('pin', 'event:topic_pinned', socket, data);
|
||||
};
|
||||
|
||||
SocketTopics.unpin = function (socket, data, callback) {
|
||||
SocketTopics.doTopicAction('unpin', 'event:topic_unpinned', socket, data, callback);
|
||||
SocketTopics.unpin = async function (socket, data) {
|
||||
await SocketTopics.doTopicAction('unpin', 'event:topic_unpinned', socket, data);
|
||||
};
|
||||
|
||||
SocketTopics.doTopicAction = function (action, event, socket, data, callback) {
|
||||
callback = callback || function () {};
|
||||
SocketTopics.doTopicAction = async function (action, event, socket, data) {
|
||||
if (!socket.uid) {
|
||||
return callback(new Error('[[error:no-privileges]]'));
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
|
||||
if (!data || !Array.isArray(data.tids) || !data.cid) {
|
||||
return callback(new Error('[[error:invalid-tid]]'));
|
||||
throw new Error('[[error:invalid-tid]]');
|
||||
}
|
||||
|
||||
if (typeof topics.tools[action] !== 'function') {
|
||||
return callback();
|
||||
return;
|
||||
}
|
||||
|
||||
async.each(data.tids, function (tid, next) {
|
||||
var title;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
topics.getTopicField(tid, 'title', next);
|
||||
},
|
||||
function (_title, next) {
|
||||
title = _title;
|
||||
topics.tools[action](tid, socket.uid, next);
|
||||
},
|
||||
function (data, next) {
|
||||
socketHelpers.emitToTopicAndCategory(event, data);
|
||||
logTopicAction(action, socket, tid, title, next);
|
||||
},
|
||||
], next);
|
||||
}, callback);
|
||||
await Promise.all(data.tids.map(async function (tid) {
|
||||
const title = await topics.getTopicField(tid, 'title');
|
||||
const data = await topics.tools[action](tid, socket.uid);
|
||||
socketHelpers.emitToTopicAndCategory(event, data);
|
||||
await logTopicAction(action, socket, tid, title);
|
||||
}));
|
||||
};
|
||||
|
||||
function logTopicAction(action, socket, tid, title, callback) {
|
||||
async function logTopicAction(action, socket, tid, title) {
|
||||
var actionsToLog = ['delete', 'restore', 'purge'];
|
||||
if (!actionsToLog.includes(action)) {
|
||||
return setImmediate(callback);
|
||||
return;
|
||||
}
|
||||
events.log({
|
||||
await events.log({
|
||||
type: 'topic-' + action,
|
||||
uid: socket.uid,
|
||||
ip: socket.ip,
|
||||
tid: tid,
|
||||
title: String(title),
|
||||
}, callback);
|
||||
});
|
||||
}
|
||||
|
||||
SocketTopics.orderPinnedTopics = function (socket, data, callback) {
|
||||
SocketTopics.orderPinnedTopics = async function (socket, data) {
|
||||
if (!Array.isArray(data)) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
|
||||
topics.tools.orderPinnedTopics(socket.uid, data, callback);
|
||||
await topics.tools.orderPinnedTopics(socket.uid, data);
|
||||
};
|
||||
};
|
||||
|
@ -1,122 +1,71 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
|
||||
var user = require('../../user');
|
||||
var topics = require('../../topics');
|
||||
const user = require('../../user');
|
||||
const topics = require('../../topics');
|
||||
|
||||
module.exports = function (SocketTopics) {
|
||||
SocketTopics.markAsRead = function (socket, tids, callback) {
|
||||
SocketTopics.markAsRead = async function (socket, tids) {
|
||||
if (!Array.isArray(tids) || socket.uid <= 0) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
topics.markAsRead(tids, socket.uid, next);
|
||||
},
|
||||
function (hasMarked, next) {
|
||||
if (hasMarked) {
|
||||
topics.pushUnreadCount(socket.uid);
|
||||
const hasMarked = await topics.markAsRead(tids, socket.uid);
|
||||
if (hasMarked) {
|
||||
topics.pushUnreadCount(socket.uid);
|
||||
|
||||
topics.markTopicNotificationsRead(tids, socket.uid);
|
||||
}
|
||||
next();
|
||||
},
|
||||
], callback);
|
||||
topics.markTopicNotificationsRead(tids, socket.uid);
|
||||
}
|
||||
};
|
||||
|
||||
SocketTopics.markTopicNotificationsRead = function (socket, tids, callback) {
|
||||
SocketTopics.markTopicNotificationsRead = async function (socket, tids) {
|
||||
if (!Array.isArray(tids) || !socket.uid) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
topics.markTopicNotificationsRead(tids, socket.uid, callback);
|
||||
await topics.markTopicNotificationsRead(tids, socket.uid);
|
||||
};
|
||||
|
||||
SocketTopics.markAllRead = function (socket, data, callback) {
|
||||
SocketTopics.markAllRead = async function (socket) {
|
||||
if (socket.uid <= 0) {
|
||||
return callback(new Error('[[error:invalid-uid]]'));
|
||||
throw new Error('[[error:invalid-uid]]');
|
||||
}
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
topics.markAllRead(socket.uid, next);
|
||||
},
|
||||
function (next) {
|
||||
topics.pushUnreadCount(socket.uid);
|
||||
next();
|
||||
},
|
||||
], callback);
|
||||
await topics.markAllRead(socket.uid);
|
||||
topics.pushUnreadCount(socket.uid);
|
||||
};
|
||||
|
||||
SocketTopics.markCategoryTopicsRead = function (socket, cid, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
topics.getUnreadTids({ cid: cid, uid: socket.uid, filter: '' }, next);
|
||||
},
|
||||
function (tids, next) {
|
||||
SocketTopics.markAsRead(socket, tids, next);
|
||||
},
|
||||
], callback);
|
||||
SocketTopics.markCategoryTopicsRead = async function (socket, cid) {
|
||||
const tids = await topics.getUnreadTids({ cid: cid, uid: socket.uid, filter: '' });
|
||||
await SocketTopics.markAsRead(socket, tids);
|
||||
};
|
||||
|
||||
SocketTopics.markUnread = function (socket, tid, callback) {
|
||||
SocketTopics.markUnread = async function (socket, tid) {
|
||||
if (!tid || socket.uid <= 0) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
topics.markUnread(tid, socket.uid, next);
|
||||
},
|
||||
function (next) {
|
||||
topics.pushUnreadCount(socket.uid);
|
||||
next();
|
||||
},
|
||||
], callback);
|
||||
await topics.markUnread(tid, socket.uid);
|
||||
topics.pushUnreadCount(socket.uid);
|
||||
};
|
||||
|
||||
SocketTopics.markAsUnreadForAll = function (socket, tids, callback) {
|
||||
SocketTopics.markAsUnreadForAll = async function (socket, tids) {
|
||||
if (!Array.isArray(tids)) {
|
||||
return callback(new Error('[[error:invalid-tid]]'));
|
||||
throw new Error('[[error:invalid-tid]]');
|
||||
}
|
||||
|
||||
if (socket.uid <= 0) {
|
||||
return callback(new Error('[[error:no-privileges]]'));
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
const isAdmin = await user.isAdministrator(socket.uid);
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
user.isAdministrator(socket.uid, next);
|
||||
},
|
||||
function (isAdmin, next) {
|
||||
async.each(tids, function (tid, next) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
topics.exists(tid, next);
|
||||
},
|
||||
function (exists, next) {
|
||||
if (!exists) {
|
||||
return next(new Error('[[error:no-topic]]'));
|
||||
}
|
||||
topics.getTopicField(tid, 'cid', next);
|
||||
},
|
||||
function (cid, next) {
|
||||
user.isModerator(socket.uid, cid, next);
|
||||
},
|
||||
function (isMod, next) {
|
||||
if (!isAdmin && !isMod) {
|
||||
return next(new Error('[[error:no-privileges]]'));
|
||||
}
|
||||
topics.markAsUnreadForAll(tid, next);
|
||||
},
|
||||
function (next) {
|
||||
topics.updateRecent(tid, Date.now(), next);
|
||||
},
|
||||
], next);
|
||||
}, next);
|
||||
},
|
||||
function (next) {
|
||||
topics.pushUnreadCount(socket.uid);
|
||||
next();
|
||||
},
|
||||
], callback);
|
||||
await Promise.all(tids.map(async (tid) => {
|
||||
const topicData = await topics.getTopicFields(tid, ['tid', 'cid']);
|
||||
if (!topicData.tid) {
|
||||
throw new Error('[[error:no-topic]]');
|
||||
}
|
||||
const isMod = await user.isModerator(socket.uid, topicData.cid);
|
||||
if (!isAdmin && !isMod) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
await topics.markAsUnreadForAll(tid);
|
||||
await topics.updateRecent(tid, Date.now());
|
||||
}));
|
||||
topics.pushUnreadCount(socket.uid);
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue