mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-12-19 06:50:21 +01:00
Compare commits
1 Commits
custom-use
...
chat-pruni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edff0d6674 |
@@ -172,6 +172,10 @@ paths:
|
|||||||
$ref: 'write/admin/analytics.yaml'
|
$ref: 'write/admin/analytics.yaml'
|
||||||
/admin/analytics/{set}:
|
/admin/analytics/{set}:
|
||||||
$ref: 'write/admin/analytics/set.yaml'
|
$ref: 'write/admin/analytics/set.yaml'
|
||||||
|
/admin/chats:
|
||||||
|
$ref: 'write/admin/chats.yaml'
|
||||||
|
/admin/chats/{roomId}:
|
||||||
|
$ref: 'write/admin/chats/roomId.yaml'
|
||||||
/files/:
|
/files/:
|
||||||
$ref: 'write/files.yaml'
|
$ref: 'write/files.yaml'
|
||||||
/files/folder:
|
/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';
|
'use strict';
|
||||||
|
|
||||||
|
const db = require('../../database');
|
||||||
const meta = require('../../meta');
|
const meta = require('../../meta');
|
||||||
const privileges = require('../../privileges');
|
const privileges = require('../../privileges');
|
||||||
const analytics = require('../../analytics');
|
const analytics = require('../../analytics');
|
||||||
|
const messaging = require('../../messaging');
|
||||||
|
const events = require('../../events');
|
||||||
|
|
||||||
const helpers = require('../helpers');
|
const helpers = require('../helpers');
|
||||||
|
|
||||||
@@ -40,3 +43,28 @@ Admin.getAnalyticsData = async (req, res) => {
|
|||||||
const getStats = req.query.units === 'days' ? analytics.getDailyStatsForSet : analytics.getHourlyStatsForSet;
|
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));
|
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',
|
'export:uploads',
|
||||||
'account-locked',
|
'account-locked',
|
||||||
'getUsersCSV',
|
'getUsersCSV',
|
||||||
|
'chat-room-deleted',
|
||||||
// To add new types from plugins, just Array.push() to this array
|
// To add new types from plugins, just Array.push() to this array
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ module.exports = function (Messaging) {
|
|||||||
|
|
||||||
Messaging.getRoomsData = async (roomIds) => {
|
Messaging.getRoomsData = async (roomIds) => {
|
||||||
const roomData = await db.getObjects(roomIds.map(roomId => `chat:room:${roomId}`));
|
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);
|
modifyRoomData(roomData);
|
||||||
return roomData;
|
return roomData;
|
||||||
};
|
};
|
||||||
@@ -47,6 +53,7 @@ module.exports = function (Messaging) {
|
|||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
db.setObject(`chat:room:${roomId}`, room),
|
db.setObject(`chat:room:${roomId}`, room),
|
||||||
|
db.sortedSetAdd('chat:rooms', now, roomId),
|
||||||
db.sortedSetAdd(`chat:room:${roomId}:uids`, now, uid),
|
db.sortedSetAdd(`chat:room:${roomId}:uids`, now, uid),
|
||||||
]);
|
]);
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
@@ -59,6 +66,24 @@ module.exports = function (Messaging) {
|
|||||||
return roomId;
|
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) => {
|
Messaging.isUserInRoom = async (uid, roomId) => {
|
||||||
const inRoom = await db.isSortedSetMember(`chat:room:${roomId}:uids`, uid);
|
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 });
|
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', [...middlewares], controllers.write.admin.getAnalyticsKeys);
|
||||||
setupApiRoute(router, 'get', '/analytics/:set', [...middlewares], controllers.write.admin.getAnalyticsData);
|
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;
|
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