nodebb-plugin-admin-chats 3.6.1 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,88 @@
1
+ 'use strict';
2
+
3
+ // Last-activity ordering for the admin chat list. Core only keeps such
4
+ // ordering per user (`uid:<uid>:chat:rooms`, bumped on every message) — the
5
+ // global `chat:rooms` set is scored once at room creation and never again,
6
+ // so listing from it sorts by creation date and buries active rooms. This
7
+ // module maintains a plugin-owned set scored like the per-user one.
8
+
9
+ const Messaging = nodebb.require('./src/messaging');
10
+ const db = nodebb.require('./src/database');
11
+
12
+ const ACTIVITY_SET = 'admin-chats:rooms:lastpost';
13
+ const BACKFILL_BATCH_SIZE = 100;
14
+
15
+ function overrideForActivityTracking() {
16
+ if (typeof Messaging.addRoomToUsers === 'function' && !Messaging.addRoomToUsers._adminChatsActivityWrapped) {
17
+ const originalAddRoomToUsers = Messaging.addRoomToUsers;
18
+
19
+ // addRoomToUsers is core's own "bump this private room" signal — it runs
20
+ // on private room creation (src/messaging/rooms.js) and on every message
21
+ // (src/messaging/create.js), always with the activity timestamp.
22
+ const wrappedAddRoomToUsers = async function (roomId, uids, timestamp) {
23
+ await db.sortedSetAdd(ACTIVITY_SET, timestamp, roomId);
24
+ return await originalAddRoomToUsers.call(this, roomId, uids, timestamp);
25
+ };
26
+
27
+ wrappedAddRoomToUsers._adminChatsActivityWrapped = true;
28
+ Messaging.addRoomToUsers = wrappedAddRoomToUsers;
29
+ }
30
+
31
+ if (typeof Messaging.deleteRooms === 'function' && !Messaging.deleteRooms._adminChatsActivityWrapped) {
32
+ const originalDeleteRooms = Messaging.deleteRooms;
33
+
34
+ const wrappedDeleteRooms = async function (roomIds) {
35
+ const result = await originalDeleteRooms.call(this, roomIds);
36
+ await db.sortedSetRemove(ACTIVITY_SET, Array.isArray(roomIds) ? roomIds : [roomIds]);
37
+ return result;
38
+ };
39
+
40
+ wrappedDeleteRooms._adminChatsActivityWrapped = true;
41
+ Messaging.deleteRooms = wrappedDeleteRooms;
42
+ }
43
+ }
44
+
45
+ // Reconcile on startup: private rooms not yet in the activity set (created
46
+ // before this feature existed, or while the plugin was disabled) get scored
47
+ // by their last message's timestamp, falling back to room creation time.
48
+ async function backfillActivitySet() {
49
+ const allRooms = await db.getSortedSetRangeWithScores('chat:rooms', 0, -1);
50
+ if (!allRooms.length) {
51
+ return;
52
+ }
53
+
54
+ const roomIds = allRooms.map(item => item.value);
55
+ const [inActivitySet, isPublic] = await Promise.all([
56
+ db.isSortedSetMembers(ACTIVITY_SET, roomIds),
57
+ db.isSortedSetMembers('chat:rooms:public', roomIds),
58
+ ]);
59
+
60
+ const missing = allRooms.filter((item, index) => !inActivitySet[index] && !isPublic[index]);
61
+
62
+ for (let offset = 0; offset < missing.length; offset += BACKFILL_BATCH_SIZE) {
63
+ const batch = missing.slice(offset, offset + BACKFILL_BATCH_SIZE);
64
+ const lastMessages = await Promise.all(
65
+ batch.map(item => db.getSortedSetRevRangeWithScores(`chat:room:${item.value}:mids`, 0, 0))
66
+ );
67
+ await db.sortedSetAddBulk(batch.map((item, index) => [
68
+ ACTIVITY_SET,
69
+ (lastMessages[index][0] && lastMessages[index][0].score) || item.score,
70
+ item.value,
71
+ ]));
72
+ }
73
+ }
74
+
75
+ // Entries whose room no longer resolves (deleted outside deleteRooms, or
76
+ // before this module wrapped it) are pruned lazily by the room list.
77
+ async function pruneActivityEntries(roomIds) {
78
+ if (roomIds.length) {
79
+ await db.sortedSetRemove(ACTIVITY_SET, roomIds);
80
+ }
81
+ }
82
+
83
+ module.exports = {
84
+ ACTIVITY_SET,
85
+ overrideForActivityTracking,
86
+ backfillActivitySet,
87
+ pruneActivityEntries,
88
+ };
package/lib/routes.js CHANGED
@@ -11,9 +11,9 @@ const sockets = nodebb.require('./src/socket.io');
11
11
  const { canAccessAdminChats, canManageAdminChats } = require('./access');
12
12
  const { getMessageEditHistory, deleteRevision } = require('./history');
13
13
  const { roomExists, lockRoom, unlockRoom, getRoomLockData } = require('./lock');
14
+ const { ACTIVITY_SET, pruneActivityEntries } = require('./activity');
14
15
 
15
16
  const ADMIN_CHAT_PAGE_SIZE = 30;
16
- const ADMIN_CHAT_SCAN_SIZE = 100;
17
17
 
18
18
  async function assertAdminChatsAccess(req, res) {
19
19
  if (!req.uid || !await canAccessAdminChats(req.uid)) {
@@ -132,34 +132,32 @@ async function getPrivateRoomCount() {
132
132
  }
133
133
 
134
134
  async function getAdminRecentChats(uid, start, limit) {
135
- let cursor = Math.max(0, parseInt(start, 10) || 0);
136
- const roomPairs = [];
135
+ const cursor = Math.max(0, parseInt(start, 10) || 0);
137
136
 
138
- while (roomPairs.length < limit) {
139
- const roomIds = await db.getSortedSetRevRange('chat:rooms', cursor, cursor + ADMIN_CHAT_SCAN_SIZE - 1);
140
- if (!roomIds.length) {
141
- break;
142
- }
137
+ // The activity set is scored by each room's last message (see lib/activity.js),
138
+ // so a plain reverse range yields the same most-recent-first ordering the
139
+ // user's own chats page gets from `uid:<uid>:chat:rooms`.
140
+ const allRoomIds = await db.getSortedSetRevRange(ACTIVITY_SET, cursor, cursor + limit - 1);
141
+ const allRooms = await Messaging.getRoomsData(allRoomIds);
143
142
 
144
- const rooms = await Messaging.getRoomsData(roomIds);
145
- rooms.forEach((room, index) => {
146
- if (room && !room.public && roomPairs.length < limit) {
147
- roomPairs.push({ roomId: roomIds[index], room });
148
- }
149
- });
150
-
151
- cursor += roomIds.length;
152
- if (roomIds.length < ADMIN_CHAT_SCAN_SIZE) {
153
- break;
143
+ const roomPairs = [];
144
+ const staleRoomIds = [];
145
+ allRooms.forEach((room, index) => {
146
+ if (room && !room.public) {
147
+ roomPairs.push({ roomId: allRoomIds[index], room });
148
+ } else if (!room) {
149
+ staleRoomIds.push(allRoomIds[index]);
154
150
  }
155
- }
151
+ });
152
+
153
+ await pruneActivityEntries(staleRoomIds);
156
154
 
157
155
  const rooms = roomPairs.map(item => item.room);
158
156
  const roomIds = roomPairs.map(item => item.roomId);
159
157
 
160
158
  await enrichAdminRecentRooms(uid, roomIds, rooms);
161
159
 
162
- return { rooms, nextStart: cursor };
160
+ return { rooms, nextStart: cursor + allRoomIds.length };
163
161
  }
164
162
 
165
163
  async function enrichAdminRecentRooms(uid, roomIds, rooms) {
@@ -354,6 +352,36 @@ function registerRoutes(app, router, middleware) {
354
352
  }
355
353
  });
356
354
 
355
+ // Room deletion from the admin-chats page. Core's DELETE
356
+ // /api/v3/admin/chats/:roomId is gated on real admin privileges
357
+ // (middleware.admin.checkPrivileges), so holders of the
358
+ // admin-chats:manage privilege cannot use it — this endpoint accepts
359
+ // them too. Goes through Messaging.deleteRooms, so the activity-set
360
+ // wrapper (lib/activity.js) prunes the deleted room from the admin list.
361
+ router.delete('/api/admin-chats/:roomId', ...routeMiddleware, async (req, res) => {
362
+ try {
363
+ const roomId = parseInt(req.params.roomId, 10);
364
+
365
+ if (!req.uid || Number.isNaN(roomId)) {
366
+ return res.status(400).json({ status: { code: 'bad-request', message: 'Invalid room id' } });
367
+ }
368
+
369
+ if (!await User.isAdministrator(req.uid) && !await canManageAdminChats(req.uid)) {
370
+ return res.status(403).json({ status: { code: 'forbidden', message: 'Admin or manage privilege required' } });
371
+ }
372
+
373
+ if (!await roomExists(roomId)) {
374
+ return res.status(404).json({ status: { code: 'not-found', message: 'Room not found' } });
375
+ }
376
+
377
+ await Messaging.deleteRooms([roomId]);
378
+
379
+ return res.json({ status: { code: 'ok', message: 'Room deleted' }, roomId });
380
+ } catch (err) {
381
+ return res.status(500).json({ status: { code: 'error', message: err.message } });
382
+ }
383
+ });
384
+
357
385
  router.get('/api/admin-chats/:roomId/lock', ...routeMiddleware, async (req, res) => {
358
386
  try {
359
387
  const roomId = parseInt(req.params.roomId, 10);
package/library.js CHANGED
@@ -3,6 +3,7 @@
3
3
  const hooks = require('./lib/hooks');
4
4
  const { registerRoutes, renderAdminChatsPage } = require('./lib/routes');
5
5
  const { overrideMessagingFunctions, overrideChatsApi, overrideCoreChatRedirect } = require('./lib/overrides');
6
+ const { overrideForActivityTracking, backfillActivitySet } = require('./lib/activity');
6
7
 
7
8
  const plugin = Object.assign({}, hooks);
8
9
 
@@ -11,6 +12,8 @@ plugin.init = async function (params) {
11
12
  overrideMessagingFunctions();
12
13
  overrideChatsApi();
13
14
  overrideCoreChatRedirect(params.controllers, renderAdminChatsPage);
15
+ overrideForActivityTracking();
16
+ await backfillActivitySet();
14
17
  };
15
18
 
16
19
  module.exports = plugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-admin-chats",
3
- "version": "3.6.1",
3
+ "version": "3.8.0",
4
4
  "description": "A plugin that allows the administrator to view and manage user chats.",
5
5
  "main": "library.js",
6
6
  "nbbpm": {
package/plugin.json CHANGED
@@ -8,6 +8,7 @@
8
8
  "scripts": [
9
9
  "static/lib/switch-chat.js",
10
10
  "static/lib/lock-toggle.js",
11
+ "static/lib/delete-room.js",
11
12
  "static/lib/live-updates.js",
12
13
  "static/lib/profile-link.js",
13
14
  "static/lib/message-history.js"
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "לא ניתן לטעון או לעדכן את היסטוריית העריכות.",
19
19
  "history.restore": "שחזור גרסה",
20
20
  "history.restored": "ההודעה שוחזרה לגרסה שנבחרה",
21
- "history.restoreDescription": "שחזור יציב את תוכן הגרסה שנבחרה כגרסה הנוכחית; הגרסה שהוחלפה תישמר בהיסטוריה."
21
+ "history.restoreDescription": "שחזור יציב את תוכן הגרסה שנבחרה כגרסה הנוכחית; הגרסה שהוחלפה תישמר בהיסטוריה.",
22
+ "errors.delete": "לא ניתן למחוק את חדר הצ'אט."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -18,5 +18,6 @@
18
18
  "errors.history": "Unable to load or update the edit history.",
19
19
  "history.restore": "Restore version",
20
20
  "history.restored": "Message restored to the selected version",
21
- "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history."
21
+ "history.restoreDescription": "Restoring sets the selected version as the current one; the replaced version is kept in the history.",
22
+ "errors.delete": "Unable to delete the chat room."
22
23
  }
@@ -0,0 +1,67 @@
1
+ 'use strict';
2
+
3
+ // The Delete Room menu item on the admin-all-chats page is rendered
4
+ // server-side (templates/partials/chats/options.tpl, gated on the manage
5
+ // privilege via room.isAdmin). It deliberately does NOT use core's
6
+ // data-action="delete": core's handler calls the admin-only
7
+ // DELETE /api/v3/admin/chats/:roomId endpoint, which rejects non-admin
8
+ // holders of the admin-chats:manage privilege — so the click goes through
9
+ // the plugin's own endpoint, which accepts them too.
10
+ $(document).ready(function () {
11
+ async function deleteRoom(roomId) {
12
+ const response = await fetch(`${config.relative_path || ''}/api/admin-chats/${roomId}`, {
13
+ method: 'DELETE',
14
+ headers: {
15
+ 'x-csrf-token': config.csrf_token,
16
+ },
17
+ credentials: 'same-origin',
18
+ });
19
+
20
+ if (!response.ok) {
21
+ throw new Error('Unable to delete room');
22
+ }
23
+
24
+ return await response.json();
25
+ }
26
+
27
+ $(document).on('click', '.admin-chat-delete-room-item', function (ev) {
28
+ ev.preventDefault();
29
+
30
+ const $button = $(this);
31
+ const roomId = parseInt($button.attr('data-room-id'), 10);
32
+
33
+ if (!roomId || $button.hasClass('disabled')) {
34
+ return;
35
+ }
36
+
37
+ require(['modals', 'forum/chats'], function (modals, Chats) {
38
+ // Same confirm dialog core shows for its own Delete Room item
39
+ modals.confirm({
40
+ size: 'small',
41
+ title: '[[modules:chat.delete]]',
42
+ message: '<p>[[modules:chat.delete-prompt]]</p>',
43
+ callback: async function (ok) {
44
+ if (!ok) {
45
+ return;
46
+ }
47
+
48
+ $button.addClass('disabled').attr('aria-disabled', 'true');
49
+
50
+ try {
51
+ await deleteRoom(roomId);
52
+ // Drop the room from the sidebar lists and close the
53
+ // open chat window (the patched switchChat renders the
54
+ // empty state for a falsy roomId)
55
+ $(`[component="chat/nav-wrapper"] [data-roomid="${roomId}"]`).remove();
56
+ if (Chats && Chats.switchChat) {
57
+ Chats.switchChat('');
58
+ }
59
+ } catch (err) {
60
+ app.alertError('[[admin-chats:errors.delete]]');
61
+ $button.removeClass('disabled').removeAttr('aria-disabled');
62
+ }
63
+ },
64
+ });
65
+ });
66
+ });
67
+ });
@@ -81,13 +81,20 @@
81
81
  </a>
82
82
  </li>
83
83
  {{{ end }}}
84
- {{{ if (public && isAdmin) }}}
84
+ {{{ if ((public && isAdmin) && !adminAllChats) }}}
85
85
  <li>
86
86
  <a class="dropdown-item rounded-1 d-flex align-items-center gap-2" href="#" data-action="delete" role="menuitem">
87
87
  <i class="fa fa-fw text-danger fa-trash"></i> {{tx("modules:chat.delete-room")}}
88
88
  </a>
89
89
  </li>
90
90
  {{{ end }}}
91
+ {{{ if (adminAllChats && isAdmin) }}}
92
+ <li>
93
+ <a class="dropdown-item rounded-1 d-flex align-items-center gap-2 admin-chat-delete-room-item" href="#" data-room-id="{roomId}" role="menuitem">
94
+ <i class="fa fa-fw text-danger fa-trash"></i> {{tx("modules:chat.delete-room")}}
95
+ </a>
96
+ </li>
97
+ {{{ end }}}
91
98
  </ul>
92
99
  </div>
93
100