mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-18 03:31:03 +01:00
ability to pin chat messages (#11964)
This commit is contained in:
committed by
GitHub
parent
94f07c149a
commit
54706b1182
@@ -30,6 +30,10 @@
|
|||||||
"chat.delete_message_confirm": "Are you sure you wish to delete this message?",
|
"chat.delete_message_confirm": "Are you sure you wish to delete this message?",
|
||||||
"chat.retrieving-users": "Retrieving users...",
|
"chat.retrieving-users": "Retrieving users...",
|
||||||
"chat.view-users-list": "View users list",
|
"chat.view-users-list": "View users list",
|
||||||
|
"chat.pinned-messages": "Pinned Messages",
|
||||||
|
"chat.no-pinned-messages": "There are no pinned messages",
|
||||||
|
"chat.pin-message": "Pin Message",
|
||||||
|
"chat.unpin-message": "Unpin Message",
|
||||||
"chat.public-rooms": "Public Rooms (%1)",
|
"chat.public-rooms": "Public Rooms (%1)",
|
||||||
"chat.private-rooms": "Private Rooms (%1)",
|
"chat.private-rooms": "Private Rooms (%1)",
|
||||||
"chat.create-room": "Create Chat Room",
|
"chat.create-room": "Create Chat Room",
|
||||||
|
|||||||
@@ -184,6 +184,8 @@ paths:
|
|||||||
$ref: 'write/chats/roomId/messages.yaml'
|
$ref: 'write/chats/roomId/messages.yaml'
|
||||||
/chats/{roomId}/messages/{mid}:
|
/chats/{roomId}/messages/{mid}:
|
||||||
$ref: 'write/chats/roomId/messages/mid.yaml'
|
$ref: 'write/chats/roomId/messages/mid.yaml'
|
||||||
|
/chats/{roomId}/messages/{mid}/pin:
|
||||||
|
$ref: 'write/chats/roomId/messages/mid/pin.yaml'
|
||||||
/flags/:
|
/flags/:
|
||||||
$ref: 'write/flags.yaml'
|
$ref: 'write/flags.yaml'
|
||||||
/flags/{flagId}:
|
/flags/{flagId}:
|
||||||
|
|||||||
66
public/openapi/write/chats/roomId/messages/mid/pin.yaml
Normal file
66
public/openapi/write/chats/roomId/messages/mid/pin.yaml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
put:
|
||||||
|
tags:
|
||||||
|
- chats
|
||||||
|
summary: pin a chat message
|
||||||
|
description: This operation pins an existing chat message in a chat room
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: roomId
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
description: a valid chat room id
|
||||||
|
example: 1
|
||||||
|
- in: path
|
||||||
|
name: mid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
description: a valid chat message id
|
||||||
|
example: 1
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Chat message successfully pinned
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
$ref: ../../../../../components/schemas/Status.yaml#/Status
|
||||||
|
response:
|
||||||
|
type: object
|
||||||
|
properties: {}
|
||||||
|
delete:
|
||||||
|
tags:
|
||||||
|
- chats
|
||||||
|
summary: unpin a chat message
|
||||||
|
description: This operation unpins a chat message in a room
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: roomId
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
description: a valid chat room id
|
||||||
|
example: 1
|
||||||
|
- in: path
|
||||||
|
name: mid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
description: a valid chat message id
|
||||||
|
example: 1
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Chat message successfully unpinned
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
$ref: ../../../../../components/schemas/Status.yaml#/Status
|
||||||
|
response:
|
||||||
|
type: object
|
||||||
|
properties: {}
|
||||||
@@ -10,6 +10,7 @@ define('forum/chats', [
|
|||||||
'forum/chats/messages',
|
'forum/chats/messages',
|
||||||
'forum/chats/user-list',
|
'forum/chats/user-list',
|
||||||
'forum/chats/message-search',
|
'forum/chats/message-search',
|
||||||
|
'forum/chats/pinned-messages',
|
||||||
'composer/autocomplete',
|
'composer/autocomplete',
|
||||||
'hooks',
|
'hooks',
|
||||||
'bootbox',
|
'bootbox',
|
||||||
@@ -19,8 +20,9 @@ define('forum/chats', [
|
|||||||
'uploadHelpers',
|
'uploadHelpers',
|
||||||
], function (
|
], function (
|
||||||
components, mousetrap, recentChats, create,
|
components, mousetrap, recentChats, create,
|
||||||
manage, messages, userList, messageSearch, autocomplete,
|
manage, messages, userList, messageSearch, pinnedMessages,
|
||||||
hooks, bootbox, alerts, chatModule, api, uploadHelpers
|
autocomplete, hooks, bootbox, alerts, chatModule, api,
|
||||||
|
uploadHelpers
|
||||||
) {
|
) {
|
||||||
const Chats = {
|
const Chats = {
|
||||||
initialised: false,
|
initialised: false,
|
||||||
@@ -66,6 +68,7 @@ define('forum/chats', [
|
|||||||
messages.wrapImagesInLinks(changeContentEl);
|
messages.wrapImagesInLinks(changeContentEl);
|
||||||
messages.scrollToBottomAfterImageLoad(changeContentEl);
|
messages.scrollToBottomAfterImageLoad(changeContentEl);
|
||||||
create.init();
|
create.init();
|
||||||
|
pinnedMessages.init($('[component="chat/main-wrapper"]'));
|
||||||
|
|
||||||
hooks.fire('action:chat.loaded', $('.chats-full'));
|
hooks.fire('action:chat.loaded', $('.chats-full'));
|
||||||
};
|
};
|
||||||
@@ -77,7 +80,7 @@ define('forum/chats', [
|
|||||||
const chatControls = components.get('chat/controls');
|
const chatControls = components.get('chat/controls');
|
||||||
Chats.addSendHandlers(roomId, $('.chat-input'), $('.expanded-chat button[data-action="send"]'));
|
Chats.addSendHandlers(roomId, $('.chat-input'), $('.expanded-chat button[data-action="send"]'));
|
||||||
Chats.addPopoutHandler();
|
Chats.addPopoutHandler();
|
||||||
Chats.addActionHandlers(components.get('chat/messages'), roomId);
|
Chats.addActionHandlers(components.get('chat/message/window'), roomId);
|
||||||
Chats.addManageHandler(roomId, chatControls.find('[data-action="manage"]'));
|
Chats.addManageHandler(roomId, chatControls.find('[data-action="manage"]'));
|
||||||
Chats.addRenameHandler(roomId, chatControls.find('[data-action="rename"]'));
|
Chats.addRenameHandler(roomId, chatControls.find('[data-action="rename"]'));
|
||||||
Chats.addLeaveHandler(roomId, chatControls.find('[data-action="leave"]'));
|
Chats.addLeaveHandler(roomId, chatControls.find('[data-action="leave"]'));
|
||||||
@@ -152,6 +155,7 @@ define('forum/chats', [
|
|||||||
placement: 'top',
|
placement: 'top',
|
||||||
container: '#content',
|
container: '#content',
|
||||||
animation: false,
|
animation: false,
|
||||||
|
trigger: 'hover',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -310,10 +314,10 @@ define('forum/chats', [
|
|||||||
const msgEl = $(this).parents('[data-mid]');
|
const msgEl = $(this).parents('[data-mid]');
|
||||||
const messageId = msgEl.attr('data-mid');
|
const messageId = msgEl.attr('data-mid');
|
||||||
const action = this.getAttribute('data-action');
|
const action = this.getAttribute('data-action');
|
||||||
|
$(this).tooltip('dispose');
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 'reply':
|
case 'reply':
|
||||||
messages.prepReplyTo(msgEl, roomId);
|
messages.prepReplyTo(msgEl, element);
|
||||||
break;
|
break;
|
||||||
case 'edit':
|
case 'edit':
|
||||||
messages.prepEdit(msgEl, messageId, roomId);
|
messages.prepEdit(msgEl, messageId, roomId);
|
||||||
@@ -324,6 +328,12 @@ define('forum/chats', [
|
|||||||
case 'restore':
|
case 'restore':
|
||||||
messages.restore(messageId, roomId);
|
messages.restore(messageId, roomId);
|
||||||
break;
|
break;
|
||||||
|
case 'pin':
|
||||||
|
pinnedMessages.pin(messageId, roomId);
|
||||||
|
break;
|
||||||
|
case 'unpin':
|
||||||
|
pinnedMessages.unpin(messageId, roomId);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -168,10 +168,9 @@ define('forum/chats/messages', [
|
|||||||
.toggleClass('hidden', isAtBottom);
|
.toggleClass('hidden', isAtBottom);
|
||||||
};
|
};
|
||||||
|
|
||||||
messages.prepReplyTo = async function (msgEl, roomId) {
|
messages.prepReplyTo = async function (msgEl, chatMessageWindow) {
|
||||||
const chatMessages = msgEl.parents(`[component="chat/messages"][data-roomid="${roomId}"]`);
|
const chatContent = chatMessageWindow.find('[component="chat/message/content"]');
|
||||||
const chatContent = chatMessages.find('[component="chat/message/content"]');
|
const composerEl = chatMessageWindow.find('[component="chat/composer"]');
|
||||||
const composerEl = chatMessages.find('[component="chat/composer"]');
|
|
||||||
const mid = msgEl.attr('data-mid');
|
const mid = msgEl.attr('data-mid');
|
||||||
const replyToEl = composerEl.find('[component="chat/composer/replying-to"]');
|
const replyToEl = composerEl.find('[component="chat/composer/replying-to"]');
|
||||||
replyToEl.attr('data-tomid', mid)
|
replyToEl.attr('data-tomid', mid)
|
||||||
|
|||||||
86
public/src/client/chats/pinned-messages.js
Normal file
86
public/src/client/chats/pinned-messages.js
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
|
define('forum/chats/pinned-messages', ['api', 'alerts'], function (api, alerts) {
|
||||||
|
const pinnedMessages = {};
|
||||||
|
let container;
|
||||||
|
pinnedMessages.init = function (_container) {
|
||||||
|
container = _container;
|
||||||
|
$('[component="chat/pinned/messages/btn"]').on('click', async () => {
|
||||||
|
const pinnedMessagesContainer = container.find('[component="chat/messages/pinned/container"]');
|
||||||
|
if (!pinnedMessagesContainer.hasClass('hidden')) {
|
||||||
|
return pinnedMessagesContainer.addClass('hidden');
|
||||||
|
}
|
||||||
|
const userListEl = container.find('[component="chat/user/list"]');
|
||||||
|
userListEl.addClass('hidden');
|
||||||
|
await pinnedMessages.refreshList();
|
||||||
|
pinnedMessagesContainer.removeClass('hidden');
|
||||||
|
});
|
||||||
|
|
||||||
|
handleInfiniteScroll(container);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleInfiniteScroll(container) {
|
||||||
|
const listEl = container.find('[component="chat/messages/pinned"]');
|
||||||
|
listEl.on('scroll', utils.debounce(async () => {
|
||||||
|
const bottom = (listEl[0].scrollHeight - listEl.height()) * 0.85;
|
||||||
|
if (listEl.scrollTop() > bottom) {
|
||||||
|
const lastIndex = listEl.find('[data-index]').last().attr('data-index');
|
||||||
|
const data = await loadData(parseInt(lastIndex, 10) + 1);
|
||||||
|
if (data && data.length) {
|
||||||
|
const html = await parseMessages(data);
|
||||||
|
container.find('[component="chat/messages/pinned"]').append(html);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
pinnedMessages.refreshList = async function () {
|
||||||
|
const data = await loadData(0);
|
||||||
|
|
||||||
|
if (!data.length) {
|
||||||
|
container.find('[component="chat/messages/pinned/empty"]').removeClass('hidden');
|
||||||
|
container.find('[component="chat/messages/pinned"]').html('');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
container.find('[component="chat/messages/pinned/empty"]').addClass('hidden');
|
||||||
|
const html = await parseMessages(data);
|
||||||
|
container.find('[component="chat/messages/pinned"]').html(html);
|
||||||
|
html.find('.timeago').timeago();
|
||||||
|
};
|
||||||
|
|
||||||
|
async function parseMessages(data) {
|
||||||
|
return await app.parseAndTranslate('partials/chats/pinned-messages', 'messages', {
|
||||||
|
isOwner: ajaxify.data.isOwner,
|
||||||
|
isAdminOrGlobalMod: ajaxify.data.isAdminOrGlobalMod,
|
||||||
|
messages: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadData(start) {
|
||||||
|
const data = await socket.emit('modules.chats.loadPinnedMessages', {
|
||||||
|
roomId: ajaxify.data.roomId,
|
||||||
|
start: start,
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
pinnedMessages.pin = function (mid, roomId) {
|
||||||
|
api.put(`/chats/${roomId}/messages/${mid}/pin`, {}).then(() => {
|
||||||
|
$(`[component="chat/message"][data-mid="${mid}"]`).toggleClass('pinned', true);
|
||||||
|
pinnedMessages.refreshList();
|
||||||
|
}).catch(alerts.error);
|
||||||
|
};
|
||||||
|
|
||||||
|
pinnedMessages.unpin = function (mid, roomId) {
|
||||||
|
api.del(`/chats/${roomId}/messages/${mid}/pin`, {}).then(() => {
|
||||||
|
$(`[component="chat/message"][data-mid="${mid}"]`).toggleClass('pinned', false);
|
||||||
|
container.find(`[component="chat/messages/pinned"] [data-mid="${mid}"]`).remove();
|
||||||
|
if (!container.find(`[component="chat/messages/pinned"] [data-mid]`).length) {
|
||||||
|
container.find('[component="chat/messages/pinned/empty"]').removeClass('hidden');
|
||||||
|
}
|
||||||
|
}).catch(alerts.error);
|
||||||
|
};
|
||||||
|
|
||||||
|
return pinnedMessages;
|
||||||
|
});
|
||||||
@@ -11,11 +11,13 @@ define('forum/chats/user-list', ['api'], function (api) {
|
|||||||
if (!userListEl.length) {
|
if (!userListEl.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const pinnedMessageListEl = container.find('[component="chat/messages/pinned/container"]');
|
||||||
container.find('[component="chat/user/list/btn"]').on('click', () => {
|
container.find('[component="chat/user/list/btn"]').on('click', () => {
|
||||||
userListEl.toggleClass('hidden');
|
userListEl.toggleClass('hidden');
|
||||||
if (userListEl.hasClass('hidden')) {
|
if (userListEl.hasClass('hidden')) {
|
||||||
stopUpdating();
|
stopUpdating();
|
||||||
} else {
|
} else {
|
||||||
|
pinnedMessageListEl.addClass('hidden');
|
||||||
startUpdating(roomId, userListEl);
|
startUpdating(roomId, userListEl);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -29,6 +31,9 @@ define('forum/chats/user-list', ['api'], function (api) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function startUpdating(roomId, userListEl) {
|
function startUpdating(roomId, userListEl) {
|
||||||
|
if (updateInterval) {
|
||||||
|
clearInterval(updateInterval);
|
||||||
|
}
|
||||||
updateInterval = setInterval(() => {
|
updateInterval = setInterval(() => {
|
||||||
updateUserList(roomId, userListEl);
|
updateUserList(roomId, userListEl);
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ define('chat', [
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Chats.addActionHandlers(chatModal.find('[component="chat/messages"]'), roomId);
|
Chats.addActionHandlers(chatModal.find('[component="chat/message/window"]'), roomId);
|
||||||
Chats.addRenameHandler(roomId, chatModal.find('[data-action="rename"]'));
|
Chats.addRenameHandler(roomId, chatModal.find('[data-action="rename"]'));
|
||||||
Chats.addLeaveHandler(roomId, chatModal.find('[data-action="leave"]'));
|
Chats.addLeaveHandler(roomId, chatModal.find('[data-action="leave"]'));
|
||||||
Chats.addDeleteHandler(roomId, chatModal.find('[data-action="delete"]'));
|
Chats.addDeleteHandler(roomId, chatModal.find('[data-action="delete"]'));
|
||||||
|
|||||||
@@ -272,3 +272,13 @@ chatsAPI.restoreMessage = async (caller, { mid }) => {
|
|||||||
await messaging.canDelete(mid, caller.uid);
|
await messaging.canDelete(mid, caller.uid);
|
||||||
await messaging.restoreMessage(mid, caller.uid);
|
await messaging.restoreMessage(mid, caller.uid);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
chatsAPI.pinMessage = async (caller, { roomId, mid }) => {
|
||||||
|
await messaging.canPin(roomId, caller.uid);
|
||||||
|
await messaging.pinMessage(mid, roomId);
|
||||||
|
};
|
||||||
|
|
||||||
|
chatsAPI.unpinMessage = async (caller, { roomId, mid }) => {
|
||||||
|
await messaging.canPin(roomId, caller.uid);
|
||||||
|
await messaging.unpinMessage(mid, roomId);
|
||||||
|
};
|
||||||
|
|||||||
@@ -142,3 +142,17 @@ Chats.messages.restore = async (req, res) => {
|
|||||||
|
|
||||||
helpers.formatApiResponse(200, res);
|
helpers.formatApiResponse(200, res);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Chats.messages.pin = async (req, res) => {
|
||||||
|
const { mid, roomId } = req.params;
|
||||||
|
await api.chats.pinMessage(req, { mid, roomId });
|
||||||
|
|
||||||
|
helpers.formatApiResponse(200, res);
|
||||||
|
};
|
||||||
|
|
||||||
|
Chats.messages.unpin = async (req, res) => {
|
||||||
|
const { mid, roomId } = req.params;
|
||||||
|
await api.chats.unpinMessage(req, { mid, roomId });
|
||||||
|
|
||||||
|
helpers.formatApiResponse(200, res);
|
||||||
|
};
|
||||||
|
|||||||
@@ -46,21 +46,17 @@ module.exports = function (Messaging) {
|
|||||||
|
|
||||||
Messaging.getMessagesData = async (mids, uid, roomId, isNew) => {
|
Messaging.getMessagesData = async (mids, uid, roomId, isNew) => {
|
||||||
let messages = await Messaging.getMessagesFields(mids, []);
|
let messages = await Messaging.getMessagesFields(mids, []);
|
||||||
messages = await user.blocks.filter(uid, 'fromuid', messages);
|
|
||||||
messages = messages
|
messages = messages
|
||||||
.map((msg, idx) => {
|
.map((msg, idx) => {
|
||||||
if (msg) {
|
if (msg) {
|
||||||
msg.messageId = parseInt(mids[idx], 10);
|
msg.messageId = parseInt(mids[idx], 10);
|
||||||
msg.ip = undefined;
|
msg.ip = undefined;
|
||||||
msg.isOwner = msg.fromuid === parseInt(uid, 10);
|
msg.isOwner = msg.fromuid === parseInt(uid, 10);
|
||||||
if (msg.deleted && !msg.isOwner) {
|
|
||||||
msg.content = `<p>[[modules:chat.message-deleted]]</p>`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return msg;
|
return msg;
|
||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
|
messages = await user.blocks.filter(uid, 'fromuid', messages);
|
||||||
const users = await user.getUsersFields(
|
const users = await user.getUsersFields(
|
||||||
messages.map(msg => msg && msg.fromuid),
|
messages.map(msg => msg && msg.fromuid),
|
||||||
['uid', 'username', 'userslug', 'picture', 'status', 'banned']
|
['uid', 'username', 'userslug', 'picture', 'status', 'banned']
|
||||||
@@ -175,8 +171,12 @@ module.exports = function (Messaging) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function parseMessages(messages, uid, roomId, isNew) {
|
async function parseMessages(messages, uid, roomId, isNew) {
|
||||||
await Promise.all(messages.map(async (message) => {
|
await Promise.all(messages.map(async (msg) => {
|
||||||
message.content = await parseMessage(message, uid, roomId, isNew);
|
if (msg.deleted && !msg.isOwner) {
|
||||||
|
msg.content = `<p>[[modules:chat.message-deleted]]</p>`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
msg.content = await parseMessage(msg, uid, roomId, isNew);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
async function parseMessage(message, uid, roomId, isNew) {
|
async function parseMessage(message, uid, roomId, isNew) {
|
||||||
|
|||||||
@@ -90,4 +90,16 @@ module.exports = function (Messaging) {
|
|||||||
|
|
||||||
Messaging.canEdit = async (messageId, uid) => await canEditDelete(messageId, uid, 'edit');
|
Messaging.canEdit = async (messageId, uid) => await canEditDelete(messageId, uid, 'edit');
|
||||||
Messaging.canDelete = async (messageId, uid) => await canEditDelete(messageId, uid, 'delete');
|
Messaging.canDelete = async (messageId, uid) => await canEditDelete(messageId, uid, 'delete');
|
||||||
|
|
||||||
|
Messaging.canPin = async (roomId, uid) => {
|
||||||
|
const [isAdmin, isGlobalMod, inRoom, isRoomOwner] = await Promise.all([
|
||||||
|
user.isAdministrator(uid),
|
||||||
|
user.isGlobalModerator(uid),
|
||||||
|
Messaging.isUserInRoom(uid, roomId),
|
||||||
|
Messaging.isRoomOwner(uid, roomId),
|
||||||
|
]);
|
||||||
|
if (!isAdmin && !isGlobalMod && (!inRoom || !isRoomOwner)) {
|
||||||
|
throw new Error('[[error:no-privileges]]');
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ require('./edit')(Messaging);
|
|||||||
require('./rooms')(Messaging);
|
require('./rooms')(Messaging);
|
||||||
require('./unread')(Messaging);
|
require('./unread')(Messaging);
|
||||||
require('./notifications')(Messaging);
|
require('./notifications')(Messaging);
|
||||||
|
require('./pins')(Messaging);
|
||||||
|
|
||||||
Messaging.notificationSettings = Object.create(null);
|
Messaging.notificationSettings = Object.create(null);
|
||||||
Messaging.notificationSettings.NONE = 1;
|
Messaging.notificationSettings.NONE = 1;
|
||||||
|
|||||||
36
src/messaging/pins.js
Normal file
36
src/messaging/pins.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const db = require('../database');
|
||||||
|
|
||||||
|
module.exports = function (Messaging) {
|
||||||
|
Messaging.pinMessage = async (mid, roomId) => {
|
||||||
|
const isMessageInRoom = await db.isSortedSetMember(`chat:room:${roomId}:mids`, mid);
|
||||||
|
if (isMessageInRoom) {
|
||||||
|
await db.sortedSetAdd(`chat:room:${roomId}:mids:pinned`, Date.now(), mid);
|
||||||
|
await Messaging.setMessageFields(mid, { pinned: 1 });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Messaging.unpinMessage = async (mid, roomId) => {
|
||||||
|
const isMessageInRoom = await db.isSortedSetMember(`chat:room:${roomId}:mids`, mid);
|
||||||
|
if (isMessageInRoom) {
|
||||||
|
await db.sortedSetRemove(`chat:room:${roomId}:mids:pinned`, mid);
|
||||||
|
await Messaging.setMessageFields(mid, { pinned: 0 });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Messaging.getPinnedMessages = async (roomId, uid, start, stop) => {
|
||||||
|
const mids = await db.getSortedSetRevRange(`chat:room:${roomId}:mids:pinned`, start, stop);
|
||||||
|
if (!mids.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageData = await Messaging.getMessagesData(mids, uid, roomId, true);
|
||||||
|
messageData.forEach((msg, i) => {
|
||||||
|
if (msg) {
|
||||||
|
msg.index = start + i;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return messageData;
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -32,5 +32,8 @@ module.exports = function () {
|
|||||||
setupApiRoute(router, 'post', '/:roomId/messages/:mid', [...middlewares, middleware.assert.room, middleware.assert.message], controllers.write.chats.messages.restore);
|
setupApiRoute(router, 'post', '/:roomId/messages/:mid', [...middlewares, middleware.assert.room, middleware.assert.message], controllers.write.chats.messages.restore);
|
||||||
setupApiRoute(router, 'delete', '/:roomId/messages/:mid', [...middlewares, middleware.assert.room, middleware.assert.message], controllers.write.chats.messages.delete);
|
setupApiRoute(router, 'delete', '/:roomId/messages/:mid', [...middlewares, middleware.assert.room, middleware.assert.message], controllers.write.chats.messages.delete);
|
||||||
|
|
||||||
|
setupApiRoute(router, 'put', '/:roomId/messages/:mid/pin', [...middlewares, middleware.assert.room, middleware.assert.message], controllers.write.chats.messages.pin);
|
||||||
|
setupApiRoute(router, 'delete', '/:roomId/messages/:mid/pin', [...middlewares, middleware.assert.room, middleware.assert.message], controllers.write.chats.messages.unpin);
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -251,4 +251,18 @@ SocketModules.chats.searchMessages = async (socket, data) => {
|
|||||||
return messageData.filter(msg => msg && !msg.deleted && msg.timestamp > userjoinTimestamp);
|
return messageData.filter(msg => msg && !msg.deleted && msg.timestamp > userjoinTimestamp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SocketModules.chats.loadPinnedMessages = async (socket, data) => {
|
||||||
|
if (!data || !data.roomId || !utils.isNumber(data.start)) {
|
||||||
|
throw new Error('[[error:invalid-data]]');
|
||||||
|
}
|
||||||
|
const isInRoom = await Messaging.isUserInRoom(socket.uid, data.roomId);
|
||||||
|
if (!isInRoom) {
|
||||||
|
throw new Error('[[error:no-privileges]]');
|
||||||
|
}
|
||||||
|
const start = parseInt(data.start, 10) || 0;
|
||||||
|
const pinnedMsgs = await Messaging.getPinnedMessages(data.roomId, socket.uid, start, start + 49);
|
||||||
|
return pinnedMsgs;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
require('../promisify')(SocketModules);
|
require('../promisify')(SocketModules);
|
||||||
|
|||||||
Reference in New Issue
Block a user