mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat: add direct message link (#12138)
* feat: add direct message link /message/:mid add /:index? to chat routes add copy link to chat messages add messageCount to each room object add infinitescroll in both directions to chat * fix more tests * test: more text fixes * test: fix tests * remove async * dont crash if element not in dom clamp scrollToIndex values to 0, msgCount
This commit is contained in:
committed by
GitHub
parent
7a8c27bf90
commit
4c4f3ac983
@@ -68,6 +68,7 @@
|
|||||||
"chat.in-room": "In this room",
|
"chat.in-room": "In this room",
|
||||||
"chat.kick": "Kick",
|
"chat.kick": "Kick",
|
||||||
"chat.show-ip": "Show IP",
|
"chat.show-ip": "Show IP",
|
||||||
|
"chat.copy-link": "Copy link",
|
||||||
"chat.owner": "Room Owner",
|
"chat.owner": "Room Owner",
|
||||||
"chat.grant-rescind-ownership": "Grant/Rescind Ownership",
|
"chat.grant-rescind-ownership": "Grant/Rescind Ownership",
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ RoomObject:
|
|||||||
userCount:
|
userCount:
|
||||||
type: number
|
type: number
|
||||||
description: number of users in this chat room
|
description: number of users in this chat room
|
||||||
|
messageCount:
|
||||||
|
type: number
|
||||||
|
description: number of messages sent in this chat room
|
||||||
groups:
|
groups:
|
||||||
type: array
|
type: array
|
||||||
description: list of groups that can access the room
|
description: list of groups that can access the room
|
||||||
|
|||||||
@@ -310,8 +310,14 @@ paths:
|
|||||||
$ref: 'read/notifications.yaml'
|
$ref: 'read/notifications.yaml'
|
||||||
"/api/user/{userslug}/chats/{roomid}":
|
"/api/user/{userslug}/chats/{roomid}":
|
||||||
$ref: 'read/user/userslug/chats/roomid.yaml'
|
$ref: 'read/user/userslug/chats/roomid.yaml'
|
||||||
|
"/api/user/{userslug}/chats/{roomid}/{index}":
|
||||||
|
$ref: 'read/user/userslug/chats/roomid.yaml'
|
||||||
"/api/chats/{roomid}":
|
"/api/chats/{roomid}":
|
||||||
$ref: 'read/chats/roomid.yaml'
|
$ref: 'read/chats/roomid.yaml'
|
||||||
|
"/api/chats/{roomid}/{index}":
|
||||||
|
$ref: 'read/chats/roomid.yaml'
|
||||||
|
"/api/message/{mid}":
|
||||||
|
$ref: 'read/message/mid.yaml'
|
||||||
/api/groups:
|
/api/groups:
|
||||||
$ref: 'read/groups.yaml'
|
$ref: 'read/groups.yaml'
|
||||||
"/api/groups/{slug}":
|
"/api/groups/{slug}":
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ get:
|
|||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
example: 1
|
example: 1
|
||||||
|
- name: index
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: 1
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: "Chat identifier resolved"
|
description: "Chat identifier resolved"
|
||||||
|
|||||||
19
public/openapi/read/message/mid.yaml
Normal file
19
public/openapi/read/message/mid.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- shorthand
|
||||||
|
summary: Access a specific chat message
|
||||||
|
description: This route comes in handy when all you have is the `mid`, and you want to redirect users to the canonical URL for the chat message, with the appropriate user slug and room id
|
||||||
|
parameters:
|
||||||
|
- name: mid
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: 1
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: "Canonical URL of chat message"
|
||||||
|
content:
|
||||||
|
text/plain:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
@@ -15,6 +15,12 @@ get:
|
|||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
example: 1
|
example: 1
|
||||||
|
- name: index
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: 1
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: ""
|
description: ""
|
||||||
@@ -32,6 +38,11 @@ get:
|
|||||||
type: boolean
|
type: boolean
|
||||||
userCount:
|
userCount:
|
||||||
type: number
|
type: number
|
||||||
|
messageCount:
|
||||||
|
type: number
|
||||||
|
scrollToIndex:
|
||||||
|
type: number
|
||||||
|
nullable: true
|
||||||
icon:
|
icon:
|
||||||
type: string
|
type: string
|
||||||
groups:
|
groups:
|
||||||
@@ -187,6 +198,8 @@ get:
|
|||||||
type: boolean
|
type: boolean
|
||||||
userCount:
|
userCount:
|
||||||
type: number
|
type: number
|
||||||
|
messageCount:
|
||||||
|
type: number
|
||||||
groups:
|
groups:
|
||||||
type: array
|
type: array
|
||||||
timestamp:
|
timestamp:
|
||||||
@@ -238,6 +251,8 @@ get:
|
|||||||
teaser:
|
teaser:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
roomId:
|
||||||
|
type: number
|
||||||
fromuid:
|
fromuid:
|
||||||
type: number
|
type: number
|
||||||
content:
|
content:
|
||||||
|
|||||||
@@ -69,9 +69,19 @@ define('forum/chats', [
|
|||||||
}
|
}
|
||||||
|
|
||||||
Chats.initialised = true;
|
Chats.initialised = true;
|
||||||
const changeContentEl = $('[component="chat/message/content"]');
|
const chatContentEl = $('[component="chat/message/content"]');
|
||||||
messages.wrapImagesInLinks(changeContentEl);
|
messages.wrapImagesInLinks(chatContentEl);
|
||||||
messages.scrollToBottomAfterImageLoad(changeContentEl);
|
if (ajaxify.data.scrollToIndex) {
|
||||||
|
messages.toggleScrollUpAlert(chatContentEl);
|
||||||
|
const scrollToEl = chatContentEl.find(`[data-index="${ajaxify.data.scrollToIndex - 1}"]`);
|
||||||
|
if (scrollToEl.length) {
|
||||||
|
chatContentEl.scrollTop(
|
||||||
|
chatContentEl.scrollTop() - chatContentEl.offset().top + scrollToEl.offset().top
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
messages.scrollToBottomAfterImageLoad(chatContentEl);
|
||||||
|
}
|
||||||
create.init();
|
create.init();
|
||||||
|
|
||||||
hooks.fire('action:chat.loaded', $('.chats-full'));
|
hooks.fire('action:chat.loaded', $('.chats-full'));
|
||||||
@@ -90,12 +100,13 @@ define('forum/chats', [
|
|||||||
Chats.addLeaveHandler(roomId, chatControls.find('[data-action="leave"]'));
|
Chats.addLeaveHandler(roomId, chatControls.find('[data-action="leave"]'));
|
||||||
Chats.addDeleteHandler(roomId, chatControls.find('[data-action="delete"]'));
|
Chats.addDeleteHandler(roomId, chatControls.find('[data-action="delete"]'));
|
||||||
Chats.addScrollHandler(roomId, ajaxify.data.uid, chatMessageContent);
|
Chats.addScrollHandler(roomId, ajaxify.data.uid, chatMessageContent);
|
||||||
Chats.addScrollBottomHandler(chatMessageContent);
|
Chats.addScrollBottomHandler(roomId, chatMessageContent);
|
||||||
Chats.addParentHandler(mainWrapper);
|
Chats.addParentHandler(mainWrapper);
|
||||||
Chats.addCharactersLeftHandler(mainWrapper);
|
Chats.addCharactersLeftHandler(mainWrapper);
|
||||||
Chats.addTextareaResizeHandler(mainWrapper);
|
Chats.addTextareaResizeHandler(mainWrapper);
|
||||||
Chats.addTypingHandler(mainWrapper, roomId);
|
Chats.addTypingHandler(mainWrapper, roomId);
|
||||||
Chats.addIPHandler(mainWrapper);
|
Chats.addIPHandler(mainWrapper);
|
||||||
|
Chats.addCopyLinkHandler(mainWrapper);
|
||||||
Chats.createAutoComplete(roomId, $('[component="chat/input"]'));
|
Chats.createAutoComplete(roomId, $('[component="chat/input"]'));
|
||||||
Chats.addUploadHandler({
|
Chats.addUploadHandler({
|
||||||
dragDropAreaEl: $('.chats-full'),
|
dragDropAreaEl: $('.chats-full'),
|
||||||
@@ -230,6 +241,19 @@ define('forum/chats', [
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Chats.addCopyLinkHandler = function (container) {
|
||||||
|
container.off('click', '[data-action="copy-link"]')
|
||||||
|
.on('click', '[data-action="copy-link"]', function () {
|
||||||
|
const copyEl = $(this);
|
||||||
|
const mid = copyEl.attr('data-mid');
|
||||||
|
if (mid) {
|
||||||
|
navigator.clipboard.writeText(`${window.location.origin}/message/${mid}`);
|
||||||
|
copyEl.find('i').addClass('fa-check').removeClass('fa-link');
|
||||||
|
setTimeout(() => copyEl.find('i').removeClass('fa-check').addClass('fa-link'), 2000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
Chats.addPopoutHandler = function () {
|
Chats.addPopoutHandler = function () {
|
||||||
$('[data-action="pop-out"]').on('click', function () {
|
$('[data-action="pop-out"]').on('click', function () {
|
||||||
const text = components.get('chat/input').val();
|
const text = components.get('chat/input').val();
|
||||||
@@ -252,49 +276,82 @@ define('forum/chats', [
|
|||||||
|
|
||||||
Chats.addScrollHandler = function (roomId, uid, el) {
|
Chats.addScrollHandler = function (roomId, uid, el) {
|
||||||
let loading = false;
|
let loading = false;
|
||||||
|
let previousScrollTop = el.scrollTop();
|
||||||
|
let currentScrollTop = previousScrollTop;
|
||||||
el.off('scroll').on('scroll', utils.debounce(function () {
|
el.off('scroll').on('scroll', utils.debounce(function () {
|
||||||
|
if (parseInt(el.attr('data-ignore-next-scroll'), 10) === 1) {
|
||||||
|
el.removeAttr('data-ignore-next-scroll');
|
||||||
|
previousScrollTop = el.scrollTop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
messages.toggleScrollUpAlert(el);
|
messages.toggleScrollUpAlert(el);
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
currentScrollTop = el.scrollTop();
|
||||||
|
|
||||||
const top = (el[0].scrollHeight - el.height()) * 0.1;
|
const direction = currentScrollTop > previousScrollTop ? 1 : -1;
|
||||||
if (el.scrollTop() >= top) {
|
previousScrollTop = currentScrollTop;
|
||||||
|
const scrollPercent = 100 * (currentScrollTop / (el[0].scrollHeight - el.height()));
|
||||||
|
const top = 15;
|
||||||
|
const bottom = 85;
|
||||||
|
|
||||||
|
if (direction === 1 && !ajaxify.data.scrollToIndex) {
|
||||||
|
// dont trigger infinitescroll if there is no /index in url
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((scrollPercent < top && direction === -1) || (scrollPercent > bottom && direction === 1)) {
|
||||||
loading = true;
|
loading = true;
|
||||||
const start = parseInt(el.children('[data-mid]').length, 10);
|
|
||||||
api.get(`/chats/${roomId}/messages`, { uid, start }).then((data) => {
|
|
||||||
data = data.messages;
|
|
||||||
|
|
||||||
if (!data) {
|
const msgEls = el.children('[data-mid]').not('.new');
|
||||||
|
const afterEl = direction > 0 ? msgEls.last() : msgEls.first();
|
||||||
|
const start = parseInt(afterEl.attr('data-index'), 10) || 0;
|
||||||
|
|
||||||
|
api.get(`/chats/${roomId}/messages`, { uid, start, direction }).then((data) => {
|
||||||
|
let messageData = data.messages;
|
||||||
|
if (!messageData) {
|
||||||
loading = false;
|
loading = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data = data.filter(function (chatMsg) {
|
messageData = messageData.filter(function (chatMsg) {
|
||||||
return !$('[component="chat/message"][data-mid="' + chatMsg.messageId + '"]').length;
|
const msgOnDom = el.find('[component="chat/message"][data-mid="' + chatMsg.messageId + '"]');
|
||||||
|
msgOnDom.removeClass('new');
|
||||||
|
return !msgOnDom.length;
|
||||||
});
|
});
|
||||||
if (!data.length) {
|
if (!messageData.length) {
|
||||||
loading = false;
|
loading = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
messages.parseMessage(data, function (html) {
|
messages.parseMessage(messageData, function (html) {
|
||||||
|
el.attr('data-ignore-next-scroll', 1);
|
||||||
|
if (direction > 0) {
|
||||||
|
html.insertAfter(afterEl);
|
||||||
|
messages.onMessagesAddedToDom(html);
|
||||||
|
} else {
|
||||||
const currentScrollTop = el.scrollTop();
|
const currentScrollTop = el.scrollTop();
|
||||||
const previousHeight = el[0].scrollHeight;
|
const previousHeight = el[0].scrollHeight;
|
||||||
el.prepend(html);
|
el.prepend(html);
|
||||||
messages.onMessagesAddedToDom(html);
|
messages.onMessagesAddedToDom(html);
|
||||||
el.scrollTop((el[0].scrollHeight - previousHeight) + currentScrollTop);
|
el.scrollTop((el[0].scrollHeight - previousHeight) + currentScrollTop);
|
||||||
|
}
|
||||||
|
|
||||||
loading = false;
|
loading = false;
|
||||||
});
|
});
|
||||||
}).catch(alerts.error);
|
}).catch(alerts.error);
|
||||||
|
}
|
||||||
}, 100));
|
}, 100));
|
||||||
};
|
};
|
||||||
|
|
||||||
Chats.addScrollBottomHandler = function (chatContent) {
|
Chats.addScrollBottomHandler = function (roomId, chatContent) {
|
||||||
chatContent.parents('[component="chat/message/window"]')
|
chatContent.parents('[component="chat/message/window"]')
|
||||||
.find('[component="chat/messages/scroll-up-alert"]')
|
.find('[component="chat/messages/scroll-up-alert"]')
|
||||||
.off('click').on('click', function () {
|
.off('click').on('click', function () {
|
||||||
|
if (ajaxify.data.scrollToIndex && parseInt(ajaxify.data.roomId, 10) === parseInt(roomId, 10)) {
|
||||||
|
Chats.switchChat(roomId);
|
||||||
|
} else {
|
||||||
messages.scrollToBottom(chatContent);
|
messages.scrollToBottom(chatContent);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ define('forum/chats/messages', [
|
|||||||
if (!Array.isArray(data)) {
|
if (!Array.isArray(data)) {
|
||||||
data.newSet = data.toMid || lastSpeaker !== parseInt(data.fromuid, 10) ||
|
data.newSet = data.toMid || lastSpeaker !== parseInt(data.fromuid, 10) ||
|
||||||
parseInt(data.timestamp, 10) > parseInt(lasttimestamp, 10) + (1000 * 60 * 3);
|
parseInt(data.timestamp, 10) > parseInt(lasttimestamp, 10) + (1000 * 60 * 3);
|
||||||
|
data.index = parseInt(lastMsgEl.attr('data-index'), 10) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
messages.parseMessage(data, function (html) {
|
messages.parseMessage(data, function (html) {
|
||||||
@@ -93,6 +94,7 @@ define('forum/chats/messages', [
|
|||||||
function onMessagesParsed(chatContentEl, html, msgData) {
|
function onMessagesParsed(chatContentEl, html, msgData) {
|
||||||
const newMessage = $(html);
|
const newMessage = $(html);
|
||||||
const isAtBottom = messages.isAtBottom(chatContentEl);
|
const isAtBottom = messages.isAtBottom(chatContentEl);
|
||||||
|
newMessage.addClass('new');
|
||||||
newMessage.appendTo(chatContentEl);
|
newMessage.appendTo(chatContentEl);
|
||||||
messages.onMessagesAddedToDom(newMessage);
|
messages.onMessagesAddedToDom(newMessage);
|
||||||
if (isAtBottom || msgData.self) {
|
if (isAtBottom || msgData.self) {
|
||||||
@@ -102,6 +104,7 @@ define('forum/chats/messages', [
|
|||||||
if (chatMsgEls.length > 150) {
|
if (chatMsgEls.length > 150) {
|
||||||
const removeCount = chatMsgEls.length - 150;
|
const removeCount = chatMsgEls.length - 150;
|
||||||
chatMsgEls.slice(0, removeCount).remove();
|
chatMsgEls.slice(0, removeCount).remove();
|
||||||
|
chatContentEl.find('[data-mid].new').removeClass('new');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,6 +153,7 @@ define('forum/chats/messages', [
|
|||||||
|
|
||||||
messages.scrollToBottom = function (containerEl) {
|
messages.scrollToBottom = function (containerEl) {
|
||||||
if (containerEl && containerEl.length) {
|
if (containerEl && containerEl.length) {
|
||||||
|
containerEl.attr('data-ignore-next-scroll', 1);
|
||||||
containerEl.scrollTop(containerEl[0].scrollHeight - containerEl.height());
|
containerEl.scrollTop(containerEl[0].scrollHeight - containerEl.height());
|
||||||
containerEl.parents('[component="chat/message/window"]')
|
containerEl.parents('[component="chat/message/window"]')
|
||||||
.find('[component="chat/messages/scroll-up-alert"]')
|
.find('[component="chat/messages/scroll-up-alert"]')
|
||||||
|
|||||||
@@ -399,7 +399,7 @@ define('chat', [
|
|||||||
Chats.createAutoComplete(roomId, chatModal.find('[component="chat/input"]'));
|
Chats.createAutoComplete(roomId, chatModal.find('[component="chat/input"]'));
|
||||||
|
|
||||||
Chats.addScrollHandler(roomId, data.uid, chatModal.find('[component="chat/message/content"]'));
|
Chats.addScrollHandler(roomId, data.uid, chatModal.find('[component="chat/message/content"]'));
|
||||||
Chats.addScrollBottomHandler(chatModal.find('[component="chat/message/content"]'));
|
Chats.addScrollBottomHandler(roomId, chatModal.find('[component="chat/message/content"]'));
|
||||||
Chats.addParentHandler(chatModal.find('[component="chat/message/content"]'));
|
Chats.addParentHandler(chatModal.find('[component="chat/message/content"]'));
|
||||||
Chats.addCharactersLeftHandler(chatModal);
|
Chats.addCharactersLeftHandler(chatModal);
|
||||||
Chats.addTextareaResizeHandler(chatModal);
|
Chats.addTextareaResizeHandler(chatModal);
|
||||||
|
|||||||
@@ -244,13 +244,29 @@ chatsAPI.kick = async (caller, data) => {
|
|||||||
return chatsAPI.users(caller, data);
|
return chatsAPI.users(caller, data);
|
||||||
};
|
};
|
||||||
|
|
||||||
chatsAPI.listMessages = async (caller, { uid, roomId, start }) => {
|
chatsAPI.listMessages = async (caller, { uid, roomId, start, direction = null }) => {
|
||||||
|
const count = 50;
|
||||||
|
let stop = start + count - 1;
|
||||||
|
if (direction === 1 || direction === -1) {
|
||||||
|
const msgCount = await db.getObjectField(`chat:room:${roomId}`, 'messageCount');
|
||||||
|
start = msgCount - start;
|
||||||
|
if (direction === 1) {
|
||||||
|
start -= count + 1;
|
||||||
|
}
|
||||||
|
stop = start + count - 1;
|
||||||
|
start = Math.max(0, start);
|
||||||
|
if (stop <= -1) {
|
||||||
|
return { messages: [] };
|
||||||
|
}
|
||||||
|
stop = Math.max(0, stop);
|
||||||
|
}
|
||||||
|
|
||||||
const messages = await messaging.getMessages({
|
const messages = await messaging.getMessages({
|
||||||
callerUid: caller.uid,
|
callerUid: caller.uid,
|
||||||
uid,
|
uid,
|
||||||
roomId,
|
roomId,
|
||||||
start,
|
start,
|
||||||
count: 50,
|
count: stop - start + 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
return { messages };
|
return { messages };
|
||||||
|
|||||||
@@ -48,7 +48,19 @@ chatsController.get = async function (req, res, next) {
|
|||||||
return res.render('chats', payload);
|
return res.render('chats', payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
const room = await messaging.loadRoom(req.uid, { uid: uid, roomId: req.params.roomid });
|
const { index } = req.params;
|
||||||
|
let start = 0;
|
||||||
|
payload.scrollToIndex = null;
|
||||||
|
if (index) {
|
||||||
|
const msgCount = await db.getObjectField(`chat:room:${req.params.roomid}`, 'messageCount');
|
||||||
|
start = Math.max(0, parseInt(msgCount, 10) - index - 49);
|
||||||
|
payload.scrollToIndex = Math.min(msgCount, Math.max(0, parseInt(index, 10) || 1));
|
||||||
|
}
|
||||||
|
const room = await messaging.loadRoom(req.uid, {
|
||||||
|
uid: uid,
|
||||||
|
roomId: req.params.roomid,
|
||||||
|
start: start,
|
||||||
|
});
|
||||||
if (!room) {
|
if (!room) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
@@ -72,5 +84,26 @@ chatsController.redirectToChat = async function (req, res, next) {
|
|||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
const roomid = parseInt(req.params.roomid, 10);
|
const roomid = parseInt(req.params.roomid, 10);
|
||||||
helpers.redirect(res, `/user/${userslug}/chats${roomid ? `/${roomid}` : ''}`);
|
const index = parseInt(req.params.index, 10);
|
||||||
|
helpers.redirect(res, `/user/${userslug}/chats${roomid ? `/${roomid}` : ''}${index ? `/${index}` : ''}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
chatsController.redirectToMessage = async function (req, res, next) {
|
||||||
|
const mid = parseInt(req.params.mid, 10);
|
||||||
|
if (!mid) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
const [userslug, roomId] = await Promise.all([
|
||||||
|
user.getUserField(req.uid, 'userslug'),
|
||||||
|
messaging.getMessageField(mid, 'roomId'),
|
||||||
|
]);
|
||||||
|
if (!userslug || !roomId) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
const index = await db.sortedSetRank(`chat:room:${roomId}:mids`, mid);
|
||||||
|
if (!(parseInt(index, 10) >= 0)) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
helpers.redirect(res, `/user/${userslug}/chats/${roomId}${index ? `/${index + 1}` : ''}`, true);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -110,7 +110,10 @@ Chats.messages.list = async (req, res) => {
|
|||||||
const uid = req.query.uid || req.uid;
|
const uid = req.query.uid || req.uid;
|
||||||
const { roomId } = req.params;
|
const { roomId } = req.params;
|
||||||
const start = parseInt(req.query.start, 10) || 0;
|
const start = parseInt(req.query.start, 10) || 0;
|
||||||
const { messages } = await api.chats.listMessages(req, { uid, roomId, start });
|
const direction = parseInt(req.query.direction, 10) || null;
|
||||||
|
const { messages } = await api.chats.listMessages(req, {
|
||||||
|
uid, roomId, start, direction,
|
||||||
|
});
|
||||||
|
|
||||||
helpers.formatApiResponse(200, res, { messages });
|
helpers.formatApiResponse(200, res, { messages });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -127,5 +127,6 @@ module.exports = function (Messaging) {
|
|||||||
|
|
||||||
Messaging.addMessageToRoom = async (roomId, mid, timestamp) => {
|
Messaging.addMessageToRoom = async (roomId, mid, timestamp) => {
|
||||||
await db.sortedSetAdd(`chat:room:${roomId}:mids`, timestamp, mid);
|
await db.sortedSetAdd(`chat:room:${roomId}:mids`, timestamp, mid);
|
||||||
|
await db.incrObjectField(`chat:room:${roomId}`, 'messageCount');
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,13 +43,17 @@ Messaging.getMessages = async (params) => {
|
|||||||
if (!ok) {
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const mids = await getMessageIds(roomId, uid, start, stop);
|
const [mids, messageCount] = await Promise.all([
|
||||||
|
getMessageIds(roomId, uid, start, stop),
|
||||||
|
db.getObjectField(`chat:room:${roomId}`, 'messageCount'),
|
||||||
|
]);
|
||||||
if (!mids.length) {
|
if (!mids.length) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
const count = parseInt(messageCount, 10) || 0;
|
||||||
const indices = {};
|
const indices = {};
|
||||||
mids.forEach((mid, index) => {
|
mids.forEach((mid, index) => {
|
||||||
indices[mid] = start + index;
|
indices[mid] = count - start - index - 1;
|
||||||
});
|
});
|
||||||
mids.reverse();
|
mids.reverse();
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const roomUidCache = cacheCreate({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const intFields = [
|
const intFields = [
|
||||||
'roomId', 'timestamp', 'userCount',
|
'roomId', 'timestamp', 'userCount', 'messageCount',
|
||||||
];
|
];
|
||||||
|
|
||||||
module.exports = function (Messaging) {
|
module.exports = function (Messaging) {
|
||||||
@@ -86,6 +86,7 @@ module.exports = function (Messaging) {
|
|||||||
roomId: roomId,
|
roomId: roomId,
|
||||||
timestamp: now,
|
timestamp: now,
|
||||||
notificationSetting: data.notificationSetting,
|
notificationSetting: data.notificationSetting,
|
||||||
|
messageCount: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data.hasOwnProperty('roomName') && data.roomName) {
|
if (data.hasOwnProperty('roomName') && data.roomName) {
|
||||||
@@ -500,6 +501,7 @@ module.exports = function (Messaging) {
|
|||||||
Messaging.getUsersInRoomFromSet(`chat:room:${roomId}:uids:online`, roomId, 0, 39, true),
|
Messaging.getUsersInRoomFromSet(`chat:room:${roomId}:uids:online`, roomId, 0, 39, true),
|
||||||
Messaging.getMessages({
|
Messaging.getMessages({
|
||||||
callerUid: uid,
|
callerUid: uid,
|
||||||
|
start: data.start || 0,
|
||||||
uid: data.uid || uid,
|
uid: data.uid || uid,
|
||||||
roomId: roomId,
|
roomId: roomId,
|
||||||
isNew: false,
|
isNew: false,
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ module.exports = function (app, name, middleware, controllers) {
|
|||||||
setupPageRoute(app, `/${name}/:userslug/sessions`, accountMiddlewares, controllers.accounts.sessions.get);
|
setupPageRoute(app, `/${name}/:userslug/sessions`, accountMiddlewares, controllers.accounts.sessions.get);
|
||||||
|
|
||||||
setupPageRoute(app, '/notifications', [middleware.ensureLoggedIn], controllers.accounts.notifications.get);
|
setupPageRoute(app, '/notifications', [middleware.ensureLoggedIn], controllers.accounts.notifications.get);
|
||||||
setupPageRoute(app, `/${name}/:userslug/chats/:roomid?`, [middleware.exposeUid, middleware.canViewUsers], controllers.accounts.chats.get);
|
setupPageRoute(app, `/${name}/:userslug/chats/:roomid?/:index?`, [middleware.exposeUid, middleware.canViewUsers], controllers.accounts.chats.get);
|
||||||
setupPageRoute(app, '/chats/:roomid?', [middleware.ensureLoggedIn], controllers.accounts.chats.redirectToChat);
|
setupPageRoute(app, '/chats/:roomid?/:index?', [middleware.ensureLoggedIn], controllers.accounts.chats.redirectToChat);
|
||||||
|
|
||||||
|
setupPageRoute(app, `/message/:mid`, [middleware.ensureLoggedIn], controllers.accounts.chats.redirectToMessage);
|
||||||
};
|
};
|
||||||
|
|||||||
20
src/upgrades/3.6.0/chat_message_counts.js
Normal file
20
src/upgrades/3.6.0/chat_message_counts.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/* eslint-disable no-await-in-loop */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const db = require('../../database');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'Set messageCount on chat rooms',
|
||||||
|
timestamp: Date.UTC(2023, 6, 27),
|
||||||
|
method: async function () {
|
||||||
|
const { progress } = this;
|
||||||
|
const allRoomIds = await db.getSortedSetRange(`chat:rooms`, 0, -1);
|
||||||
|
progress.total = allRoomIds.length;
|
||||||
|
for (const roomId of allRoomIds) {
|
||||||
|
const count = await db.sortedSetCard(`chat:room:${roomId}:mids`);
|
||||||
|
await db.setObject(`chat:room:${roomId}`, { messageCount: count });
|
||||||
|
progress.incr(1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -281,7 +281,7 @@ describe('API', async () => {
|
|||||||
await flags.create('post', 2, unprivUid, 'sample reasons', Date.now()); // for testing flag notes (since flag 1 deleted)
|
await flags.create('post', 2, unprivUid, 'sample reasons', Date.now()); // for testing flag notes (since flag 1 deleted)
|
||||||
|
|
||||||
// Create a new chat room
|
// Create a new chat room
|
||||||
await messaging.newRoom(1, { uids: [2] });
|
await messaging.newRoom(adminUid, { uids: [unprivUid] });
|
||||||
|
|
||||||
// Create an empty file to test DELETE /files and thumb deletion
|
// Create an empty file to test DELETE /files and thumb deletion
|
||||||
fs.closeSync(fs.openSync(path.resolve(nconf.get('upload_path'), 'files/test.txt'), 'w'));
|
fs.closeSync(fs.openSync(path.resolve(nconf.get('upload_path'), 'files/test.txt'), 'w'));
|
||||||
|
|||||||
Reference in New Issue
Block a user