mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-12-16 21:40:23 +01:00
Compare commits
1 Commits
normalize-
...
chat-pruni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edff0d6674 |
@@ -172,6 +172,10 @@ paths:
|
||||
$ref: 'write/admin/analytics.yaml'
|
||||
/admin/analytics/{set}:
|
||||
$ref: 'write/admin/analytics/set.yaml'
|
||||
/admin/chats:
|
||||
$ref: 'write/admin/chats.yaml'
|
||||
/admin/chats/{roomId}:
|
||||
$ref: 'write/admin/chats/roomId.yaml'
|
||||
/files/:
|
||||
$ref: 'write/files.yaml'
|
||||
/files/folder:
|
||||
|
||||
46
public/openapi/write/admin/chats.yaml
Normal file
46
public/openapi/write/admin/chats.yaml
Normal file
@@ -0,0 +1,46 @@
|
||||
get:
|
||||
tags:
|
||||
- admin
|
||||
summary: get chat rooms
|
||||
description: This operation returns all chat rooms managed by NodeBB. **For privacy reasons**, only chat room metadata is shown.
|
||||
parameters:
|
||||
- in: query
|
||||
name: perPage
|
||||
schema:
|
||||
type: number
|
||||
description: The number of chat rooms displayed per page
|
||||
example: 20
|
||||
- in: query
|
||||
name: page
|
||||
schema:
|
||||
type: number
|
||||
description: The page number
|
||||
example: 1
|
||||
responses:
|
||||
'200':
|
||||
description: Chat rooms retrieved
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
$ref: ../../components/schemas/Status.yaml#/Status
|
||||
response:
|
||||
type: object
|
||||
properties:
|
||||
rooms:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
owner:
|
||||
type: number
|
||||
roomId:
|
||||
type: number
|
||||
userCount:
|
||||
type: number
|
||||
roomName:
|
||||
type: string
|
||||
groupChat:
|
||||
type: boolean
|
||||
26
public/openapi/write/admin/chats/roomId.yaml
Normal file
26
public/openapi/write/admin/chats/roomId.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
delete:
|
||||
tags:
|
||||
- admin
|
||||
summary: delete chat room
|
||||
description: This operation deletes a chat room from the database
|
||||
parameters:
|
||||
- in: path
|
||||
name: roomId
|
||||
schema:
|
||||
type: number
|
||||
description: The roomId to be deleted
|
||||
example: 1
|
||||
required: true
|
||||
responses:
|
||||
'200':
|
||||
description: Chat room deleted
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
$ref: ../../../components/schemas/Status.yaml#/Status
|
||||
response:
|
||||
type: object
|
||||
properties: {}
|
||||
@@ -1,8 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const db = require('../../database');
|
||||
const meta = require('../../meta');
|
||||
const privileges = require('../../privileges');
|
||||
const analytics = require('../../analytics');
|
||||
const messaging = require('../../messaging');
|
||||
const events = require('../../events');
|
||||
|
||||
const helpers = require('../helpers');
|
||||
|
||||
@@ -40,3 +43,28 @@ Admin.getAnalyticsData = async (req, res) => {
|
||||
const getStats = req.query.units === 'days' ? analytics.getDailyStatsForSet : analytics.getHourlyStatsForSet;
|
||||
helpers.formatApiResponse(200, res, await getStats(`analytics:${req.params.set}`, parseInt(req.query.until, 10) || Date.now(), req.query.amount));
|
||||
};
|
||||
|
||||
Admin.chats = {};
|
||||
|
||||
Admin.chats.getRooms = async (req, res) => {
|
||||
const page = (isFinite(req.query.page) && parseInt(req.query.page, 10)) || 1;
|
||||
const perPage = (isFinite(req.query.perPage) && parseInt(req.query.perPage, 10)) || 20;
|
||||
const start = Math.max(0, page - 1) * perPage;
|
||||
const stop = start + perPage;
|
||||
const roomIds = await db.getSortedSetRevRange('chat:rooms', start, stop);
|
||||
|
||||
helpers.formatApiResponse(200, res, {
|
||||
rooms: await messaging.getRoomsData(roomIds),
|
||||
});
|
||||
};
|
||||
|
||||
Admin.chats.deleteRoom = async (req, res) => {
|
||||
await messaging.deleteRooms([req.params.roomId]);
|
||||
|
||||
events.log({
|
||||
type: 'chat-room-deleted',
|
||||
uid: req.uid,
|
||||
ip: req.ip,
|
||||
});
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
@@ -75,6 +75,7 @@ events.types = [
|
||||
'export:uploads',
|
||||
'account-locked',
|
||||
'getUsersCSV',
|
||||
'chat-room-deleted',
|
||||
// To add new types from plugins, just Array.push() to this array
|
||||
];
|
||||
|
||||
|
||||
@@ -21,6 +21,12 @@ module.exports = function (Messaging) {
|
||||
|
||||
Messaging.getRoomsData = async (roomIds) => {
|
||||
const roomData = await db.getObjects(roomIds.map(roomId => `chat:room:${roomId}`));
|
||||
|
||||
const userCounts = await db.sortedSetsCard(roomIds.map(roomId => `chat:room:${roomId}:uids`));
|
||||
userCounts.forEach((count, idx) => {
|
||||
roomData[idx].userCount = count;
|
||||
});
|
||||
|
||||
modifyRoomData(roomData);
|
||||
return roomData;
|
||||
};
|
||||
@@ -47,6 +53,7 @@ module.exports = function (Messaging) {
|
||||
|
||||
await Promise.all([
|
||||
db.setObject(`chat:room:${roomId}`, room),
|
||||
db.sortedSetAdd('chat:rooms', now, roomId),
|
||||
db.sortedSetAdd(`chat:room:${roomId}:uids`, now, uid),
|
||||
]);
|
||||
await Promise.all([
|
||||
@@ -59,6 +66,24 @@ module.exports = function (Messaging) {
|
||||
return roomId;
|
||||
};
|
||||
|
||||
Messaging.deleteRooms = async (roomIds) => {
|
||||
// warning: uid:<uid>:chat:room:<roomId>:mids is left behind, along with each message:<mid> obj
|
||||
// deleting them from db requires iterating through all messages; not performant
|
||||
if (!roomIds) {
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
|
||||
if (!Array.isArray(roomIds)) {
|
||||
roomIds = [roomIds];
|
||||
}
|
||||
|
||||
await Promise.all(roomIds.map(async (roomId) => {
|
||||
const uids = await db.getSortedSetMembers(`chat:room:${roomId}:uids`);
|
||||
await Messaging.leaveRoom(uids, roomId);
|
||||
await db.delete(`chat:room:${roomId}`);
|
||||
}));
|
||||
};
|
||||
|
||||
Messaging.isUserInRoom = async (uid, roomId) => {
|
||||
const inRoom = await db.isSortedSetMember(`chat:room:${roomId}:uids`, uid);
|
||||
const data = await plugins.hooks.fire('filter:messaging.isUserInRoom', { uid: uid, roomId: roomId, inRoom: inRoom });
|
||||
|
||||
@@ -15,5 +15,8 @@ module.exports = function () {
|
||||
setupApiRoute(router, 'get', '/analytics', [...middlewares], controllers.write.admin.getAnalyticsKeys);
|
||||
setupApiRoute(router, 'get', '/analytics/:set', [...middlewares], controllers.write.admin.getAnalyticsData);
|
||||
|
||||
setupApiRoute(router, 'get', '/chats', [...middlewares], controllers.write.admin.chats.getRooms);
|
||||
setupApiRoute(router, 'delete', '/chats/:roomId', [...middlewares, middleware.assert.room], controllers.write.admin.chats.deleteRoom);
|
||||
|
||||
return router;
|
||||
};
|
||||
|
||||
19
src/upgrades/3.0.0/save_rooms_zset.js
Normal file
19
src/upgrades/3.0.0/save_rooms_zset.js
Normal file
@@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
const db = require('../../database');
|
||||
|
||||
module.exports = {
|
||||
name: 'Store list of chat rooms',
|
||||
timestamp: Date.UTC(2022, 8, 30),
|
||||
method: async () => {
|
||||
const lastRoomId = await db.getObjectField('global', 'nextChatRoomId');
|
||||
let keys = [];
|
||||
for (let x = 1; x <= lastRoomId; x++) {
|
||||
keys.push(`chat:room:${x}`);
|
||||
}
|
||||
|
||||
const exists = await db.exists(keys);
|
||||
keys = keys.filter((_, idx) => exists[idx]);
|
||||
await db.sortedSetAdd('chat:rooms', keys.map(Date.now), keys.map(key => key.slice(10)));
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user