Chore: Server API types POC - loadMessagesForRoom (#3765)
* create interface and implements base types * fix some types * Update app/lib/methods/updateMessages.ts Co-authored-by: Diego Mello <diegolmello@gmail.com> * fix date type * apply types changes * fix type * fix date value * fix types * typescript things... Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
4224f4d9d0
commit
4172d563b7
|
@ -3,7 +3,7 @@ import { MarkdownAST } from '@rocket.chat/message-parser';
|
||||||
|
|
||||||
import { IAttachment } from './IAttachment';
|
import { IAttachment } from './IAttachment';
|
||||||
import { IReaction } from './IReaction';
|
import { IReaction } from './IReaction';
|
||||||
import { IUrl } from './IUrl';
|
import { IUrlFromServer } from './IUrl';
|
||||||
|
|
||||||
export type MessageType = 'jitsi_call_started' | 'discussion-created' | 'e2e' | 'load_more' | 'rm' | 'uj';
|
export type MessageType = 'jitsi_call_started' | 'discussion-created' | 'e2e' | 'load_more' | 'rm' | 'uj';
|
||||||
|
|
||||||
|
@ -59,22 +59,61 @@ export interface ILastMessage {
|
||||||
status: boolean;
|
status: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMessage {
|
interface IMessageFile {
|
||||||
|
_id: string;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IMessageAttachment {
|
||||||
|
ts: string;
|
||||||
|
title: string;
|
||||||
|
title_link: string;
|
||||||
|
title_link_download: true;
|
||||||
|
image_dimensions: {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
image_preview: string;
|
||||||
|
image_url: string;
|
||||||
|
image_type: string;
|
||||||
|
image_size: number;
|
||||||
|
type: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMessageFromServer {
|
||||||
_id: string;
|
_id: string;
|
||||||
rid: string;
|
rid: string;
|
||||||
msg?: string;
|
msg: string;
|
||||||
|
ts: string | Date; // wm date issue
|
||||||
|
u: IUserMessage;
|
||||||
|
_updatedAt: string | Date;
|
||||||
|
urls: IUrlFromServer[];
|
||||||
|
mentions: IUserMention[];
|
||||||
|
channels: IUserChannel[];
|
||||||
|
md: MarkdownAST;
|
||||||
|
file: IMessageFile;
|
||||||
|
files: IMessageFile[];
|
||||||
|
groupable: false;
|
||||||
|
attachments: IMessageAttachment[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILoadMoreMessage {
|
||||||
|
_id: string;
|
||||||
|
rid: string;
|
||||||
|
ts: string;
|
||||||
|
t: string;
|
||||||
|
msg: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMessage extends IMessageFromServer {
|
||||||
id: string;
|
id: string;
|
||||||
t?: MessageType;
|
t?: MessageType;
|
||||||
ts: string | Date;
|
|
||||||
u: IUserMessage;
|
|
||||||
alias?: string;
|
alias?: string;
|
||||||
parseUrls?: boolean;
|
parseUrls?: boolean;
|
||||||
groupable?: boolean;
|
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
emoji?: string;
|
emoji?: string;
|
||||||
attachments?: IAttachment[];
|
|
||||||
urls?: IUrl[];
|
|
||||||
_updatedAt: string | Date;
|
|
||||||
status?: number;
|
status?: number;
|
||||||
pinned?: boolean;
|
pinned?: boolean;
|
||||||
starred?: boolean;
|
starred?: boolean;
|
||||||
|
@ -88,8 +127,6 @@ export interface IMessage {
|
||||||
tcount?: number;
|
tcount?: number;
|
||||||
tlm?: string | Date;
|
tlm?: string | Date;
|
||||||
replies?: string[];
|
replies?: string[];
|
||||||
mentions?: IUserMention[];
|
|
||||||
channels?: IUserChannel[];
|
|
||||||
unread?: boolean;
|
unread?: boolean;
|
||||||
autoTranslate?: boolean;
|
autoTranslate?: boolean;
|
||||||
translations?: ITranslations[];
|
translations?: ITranslations[];
|
||||||
|
@ -97,8 +134,9 @@ export interface IMessage {
|
||||||
blocks?: any;
|
blocks?: any;
|
||||||
e2e?: string;
|
e2e?: string;
|
||||||
tshow?: boolean;
|
tshow?: boolean;
|
||||||
md?: MarkdownAST;
|
|
||||||
subscription?: { id: string };
|
subscription?: { id: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TMessageModel = IMessage & Model;
|
export type TMessageModel = IMessage & Model;
|
||||||
|
|
||||||
|
export type TTypeMessages = IMessageFromServer | ILoadMoreMessage | IMessage;
|
||||||
|
|
|
@ -30,6 +30,7 @@ export interface IThreadResult {
|
||||||
channels?: IUserChannel[];
|
channels?: IUserChannel[];
|
||||||
replies?: string[];
|
replies?: string[];
|
||||||
tcount?: number;
|
tcount?: number;
|
||||||
|
status?: string;
|
||||||
tlm?: string | Date;
|
tlm?: string | Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,3 @@
|
||||||
export interface IUrl {
|
|
||||||
_id: number;
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
image: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IUrlFromServer {
|
export interface IUrlFromServer {
|
||||||
url: string;
|
url: string;
|
||||||
meta: {
|
meta: {
|
||||||
|
@ -47,3 +39,11 @@ export interface IUrlFromServer {
|
||||||
};
|
};
|
||||||
ignoreParse: boolean;
|
ignoreParse: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IUrl extends IUrlFromServer {
|
||||||
|
_id: number;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
image: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
import type { IMessage } from '../../IMessage';
|
import type { IMessage, IMessageFromServer } from '../../IMessage';
|
||||||
import type { IRoom } from '../../IRoom';
|
import type { IRoom } from '../../IRoom';
|
||||||
import type { IUser } from '../../IUser';
|
import type { IUser } from '../../IUser';
|
||||||
|
|
||||||
export type ChannelsEndpoints = {
|
export type ChannelsEndpoints = {
|
||||||
'channels.files': {
|
'channels.files': {
|
||||||
GET: (params: { roomId: IRoom['_id']; offset: number; count: number; sort: string; query: string }) => {
|
GET: (params: {
|
||||||
|
roomId: IRoom['_id'];
|
||||||
|
offset: number;
|
||||||
|
count: number;
|
||||||
|
sort: string | { uploadedAt: number };
|
||||||
|
query: string;
|
||||||
|
}) => {
|
||||||
files: IMessage[];
|
files: IMessage[];
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
|
@ -17,4 +23,9 @@ export type ChannelsEndpoints = {
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
'channels.history': {
|
||||||
|
GET: (params: { roomId: string; count: number; latest?: string }) => {
|
||||||
|
messages: IMessageFromServer[];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import type { IMessage } from '../../IMessage';
|
import type { IMessage, IMessageFromServer } from '../../IMessage';
|
||||||
import type { IRoom } from '../../IRoom';
|
import type { IRoom } from '../../IRoom';
|
||||||
import type { IUser } from '../../IUser';
|
import type { IUser } from '../../IUser';
|
||||||
|
|
||||||
export type GroupsEndpoints = {
|
export type GroupsEndpoints = {
|
||||||
'groups.files': {
|
'groups.files': {
|
||||||
GET: (params: { roomId: IRoom['_id']; count: number; sort: string; query: string }) => {
|
GET: (params: { roomId: IRoom['_id']; count: number; sort: string | { uploadedAt: number }; query: string }) => {
|
||||||
files: IMessage[];
|
files: IMessage[];
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
|
@ -17,4 +17,9 @@ export type GroupsEndpoints = {
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
'groups.history': {
|
||||||
|
GET: (params: { roomId: string; count: number; latest?: string }) => {
|
||||||
|
messages: IMessageFromServer[];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { IMessage } from '../../IMessage';
|
import type { IMessage, IMessageFromServer } from '../../IMessage';
|
||||||
import type { IRoom } from '../../IRoom';
|
import type { IRoom } from '../../IRoom';
|
||||||
import type { IUser } from '../../IUser';
|
import type { IUser } from '../../IUser';
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export type ImEndpoints = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
'im.files': {
|
'im.files': {
|
||||||
GET: (params: { roomId: IRoom['_id']; count: number; sort: string; query: string }) => {
|
GET: (params: { roomId: IRoom['_id']; count: number; sort: string | { uploadedAt: number }; query: string }) => {
|
||||||
files: IMessage[];
|
files: IMessage[];
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
|
@ -33,4 +33,9 @@ export type ImEndpoints = {
|
||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
'im.history': {
|
||||||
|
GET: (params: { roomId: string; count: number; latest?: string }) => {
|
||||||
|
messages: IMessageFromServer[];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -179,7 +179,7 @@ export type OmnichannelEndpoints = {
|
||||||
departmentId?: ILivechatAgent['_id'];
|
departmentId?: ILivechatAgent['_id'];
|
||||||
offset: number;
|
offset: number;
|
||||||
count: number;
|
count: number;
|
||||||
sort: string;
|
sort: string | { uploadedAt: number };
|
||||||
}) => {
|
}) => {
|
||||||
queue: {
|
queue: {
|
||||||
chats: number;
|
chats: number;
|
||||||
|
|
|
@ -244,7 +244,7 @@ class Encryption {
|
||||||
const threadMessagesToDecrypt = await threadMessagesCollection.query(...whereClause).fetch();
|
const threadMessagesToDecrypt = await threadMessagesCollection.query(...whereClause).fetch();
|
||||||
|
|
||||||
// Concat messages/threads/threadMessages
|
// Concat messages/threads/threadMessages
|
||||||
let toDecrypt: (TThreadModel | TThreadMessageModel)[] = [
|
let toDecrypt: (TThreadModel | TThreadMessageModel | TMessageModel)[] = [
|
||||||
...messagesToDecrypt,
|
...messagesToDecrypt,
|
||||||
...threadsToDecrypt,
|
...threadsToDecrypt,
|
||||||
...threadMessagesToDecrypt
|
...threadMessagesToDecrypt
|
||||||
|
@ -259,7 +259,7 @@ class Encryption {
|
||||||
newMessage = await this.decryptMessage({
|
newMessage = await this.decryptMessage({
|
||||||
t,
|
t,
|
||||||
rid,
|
rid,
|
||||||
msg,
|
msg: msg as string,
|
||||||
tmsg
|
tmsg
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -464,12 +464,13 @@ class Encryption {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { rid } = message;
|
const { rid } = message;
|
||||||
const roomE2E = await this.getRoomInstance(rid as string);
|
const roomE2E = await this.getRoomInstance(rid);
|
||||||
return roomE2E.decrypt(message);
|
return roomE2E.decrypt(message);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Decrypt multiple messages
|
// Decrypt multiple messages
|
||||||
decryptMessages = (messages: IMessage[]) => Promise.all(messages.map((m: IMessage) => this.decryptMessage(m)));
|
decryptMessages = (messages: Partial<IMessage>[]) =>
|
||||||
|
Promise.all(messages.map((m: Partial<IMessage>) => this.decryptMessage(m as IMessage)));
|
||||||
|
|
||||||
// Decrypt multiple subscriptions
|
// Decrypt multiple subscriptions
|
||||||
decryptSubscriptions = (subscriptions: ISubscription[]) => Promise.all(subscriptions.map(s => this.decryptSubscription(s)));
|
decryptSubscriptions = (subscriptions: ISubscription[]) => Promise.all(subscriptions.map(s => this.decryptSubscription(s)));
|
||||||
|
|
|
@ -6,9 +6,9 @@ import { getThreadById } from '../database/services/Thread';
|
||||||
import log from '../../utils/log';
|
import log from '../../utils/log';
|
||||||
import { Encryption } from '../encryption';
|
import { Encryption } from '../encryption';
|
||||||
import getSingleMessage from './getSingleMessage';
|
import getSingleMessage from './getSingleMessage';
|
||||||
import { IThread, TThreadModel } from '../../definitions';
|
import { IMessage, IThread, TThreadModel } from '../../definitions';
|
||||||
|
|
||||||
const buildThreadName = (thread: IThread): string | undefined => thread.msg || thread?.attachments?.[0]?.title;
|
const buildThreadName = (thread: IThread | IMessage): string | undefined => thread.msg || thread?.attachments?.[0]?.title;
|
||||||
|
|
||||||
const getThreadName = async (rid: string, tmid: string, messageId: string): Promise<string | undefined> => {
|
const getThreadName = async (rid: string, tmid: string, messageId: string): Promise<string | undefined> => {
|
||||||
let tmsg: string | undefined;
|
let tmsg: string | undefined;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { IMessage } from '../../../definitions';
|
import { IMessage, IThreadResult } from '../../../definitions';
|
||||||
import messagesStatus from '../../../constants/messagesStatus';
|
import messagesStatus from '../../../constants/messagesStatus';
|
||||||
import normalizeMessage from './normalizeMessage';
|
import normalizeMessage from './normalizeMessage';
|
||||||
|
|
||||||
export default (message: IMessage): IMessage => {
|
export default (message: Partial<IMessage> | IThreadResult): Partial<IMessage> | IThreadResult => {
|
||||||
message.status = messagesStatus.SENT;
|
message.status = messagesStatus.SENT;
|
||||||
return normalizeMessage(message);
|
return normalizeMessage(message);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { MESSAGE_TYPE_LOAD_MORE } from '../../constants/messageTypeLoad';
|
import { IMessage, MessageType, TMessageModel } from '../../definitions';
|
||||||
import log from '../../utils/log';
|
import log from '../../utils/log';
|
||||||
import { getMessageById } from '../database/services/Message';
|
import { getMessageById } from '../database/services/Message';
|
||||||
|
import roomTypeToApiType, { RoomTypes } from '../rocketchat/methods/roomTypeToApiType';
|
||||||
|
import sdk from '../rocketchat/services/sdk';
|
||||||
import { generateLoadMoreId } from '../utils';
|
import { generateLoadMoreId } from '../utils';
|
||||||
import updateMessages from './updateMessages';
|
import updateMessages from './updateMessages';
|
||||||
import { IMessage, TMessageModel } from '../../definitions';
|
|
||||||
import sdk from '../rocketchat/services/sdk';
|
|
||||||
import roomTypeToApiType, { RoomTypes } from '../rocketchat/methods/roomTypeToApiType';
|
|
||||||
|
|
||||||
const COUNT = 50;
|
const COUNT = 50;
|
||||||
|
|
||||||
|
@ -23,9 +22,8 @@ async function load({ rid: roomId, latest, t }: { rid: string; latest?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RC 0.48.0
|
// RC 0.48.0
|
||||||
// @ts-ignore
|
const data = await sdk.get(`${apiType}.history`, params);
|
||||||
const data: any = await sdk.get(`${apiType}.history`, params);
|
if (!data.success) {
|
||||||
if (!data || data.status === 'error') {
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return data.messages;
|
return data.messages;
|
||||||
|
@ -36,22 +34,22 @@ export default function loadMessagesForRoom(args: {
|
||||||
t: RoomTypes;
|
t: RoomTypes;
|
||||||
latest: string;
|
latest: string;
|
||||||
loaderItem: TMessageModel;
|
loaderItem: TMessageModel;
|
||||||
}): Promise<IMessage[] | []> {
|
}): Promise<Partial<IMessage>[]> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const data = await load(args);
|
const data: Partial<IMessage>[] = await load(args);
|
||||||
if (data?.length) {
|
if (data?.length) {
|
||||||
const lastMessage = data[data.length - 1];
|
const lastMessage = data[data.length - 1];
|
||||||
const lastMessageRecord = await getMessageById(lastMessage._id);
|
const lastMessageRecord = await getMessageById(lastMessage._id as string);
|
||||||
if (!lastMessageRecord && data.length === COUNT) {
|
if (!lastMessageRecord && data.length === COUNT) {
|
||||||
const loadMoreItem = {
|
const loadMoreMessage = {
|
||||||
_id: generateLoadMoreId(lastMessage._id),
|
_id: generateLoadMoreId(lastMessage._id as string),
|
||||||
rid: lastMessage.rid,
|
rid: lastMessage.rid,
|
||||||
ts: moment(lastMessage.ts).subtract(1, 'millisecond'),
|
ts: moment(lastMessage.ts).subtract(1, 'millisecond').toString(),
|
||||||
t: MESSAGE_TYPE_LOAD_MORE,
|
t: 'load_more' as MessageType,
|
||||||
msg: lastMessage.msg
|
msg: lastMessage.msg
|
||||||
};
|
};
|
||||||
data.push(loadMoreItem);
|
data.push(loadMoreMessage);
|
||||||
}
|
}
|
||||||
await updateMessages({ rid: args.rid, update: data, loaderItem: args.loaderItem });
|
await updateMessages({ rid: args.rid, update: data, loaderItem: args.loaderItem });
|
||||||
return resolve(data);
|
return resolve(data);
|
||||||
|
|
|
@ -12,8 +12,8 @@ import { getSubscriptionByRoomId } from '../database/services/Subscription';
|
||||||
|
|
||||||
interface IUpdateMessages {
|
interface IUpdateMessages {
|
||||||
rid: string;
|
rid: string;
|
||||||
update: IMessage[];
|
update: Partial<IMessage>[];
|
||||||
remove?: IMessage[];
|
remove?: Partial<IMessage>[];
|
||||||
loaderItem?: TMessageModel;
|
loaderItem?: TMessageModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ export default async function updateMessages({
|
||||||
// Decrypt these messages
|
// Decrypt these messages
|
||||||
update = await Encryption.decryptMessages(update);
|
update = await Encryption.decryptMessages(update);
|
||||||
|
|
||||||
const messagesIds: string[] = [...update.map(m => m._id), ...remove.map(m => m._id)];
|
const messagesIds: string[] = [...update.map(m => m._id as string), ...remove.map(m => m._id as string)];
|
||||||
const msgCollection = db.get('messages');
|
const msgCollection = db.get('messages');
|
||||||
const threadCollection = db.get('threads');
|
const threadCollection = db.get('threads');
|
||||||
const threadMessagesCollection = db.get('thread_messages');
|
const threadMessagesCollection = db.get('thread_messages');
|
||||||
|
@ -49,11 +49,11 @@ export default async function updateMessages({
|
||||||
.query(Q.where('subscription_id', rid), Q.where('id', Q.oneOf(messagesIds)))
|
.query(Q.where('subscription_id', rid), Q.where('id', Q.oneOf(messagesIds)))
|
||||||
.fetch();
|
.fetch();
|
||||||
|
|
||||||
update = update.map(m => buildMessage(m));
|
update = update.map(m => buildMessage(m)) as IMessage[];
|
||||||
|
|
||||||
// filter loaders to delete
|
// filter loaders to delete
|
||||||
let loadersToDelete: TMessageModel[] = allMessagesRecords.filter(i1 =>
|
let loadersToDelete: TMessageModel[] = allMessagesRecords.filter(i1 =>
|
||||||
update.find(i2 => i1.id === generateLoadMoreId(i2._id))
|
update.find(i2 => i1.id === generateLoadMoreId(i2._id as string))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Delete
|
// Delete
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
const types = {
|
enum ETypes {
|
||||||
c: 'channels',
|
Channels = 'channels',
|
||||||
d: 'im',
|
Im = 'im',
|
||||||
p: 'groups',
|
Groups = 'groups'
|
||||||
l: 'channels'
|
}
|
||||||
|
|
||||||
|
export const types = {
|
||||||
|
c: ETypes.Channels,
|
||||||
|
d: ETypes.Im,
|
||||||
|
p: ETypes.Groups,
|
||||||
|
l: ETypes.Channels
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: refactor this
|
// TODO: refactor this
|
||||||
|
|
|
@ -287,7 +287,7 @@ class ThreadMessagesView extends React.Component<IThreadMessagesViewProps, IThre
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update && update.length) {
|
if (update && update.length) {
|
||||||
update = update.map(m => buildMessage(m));
|
update = update.map(m => buildMessage(m)) as IThreadResult[];
|
||||||
// filter threads
|
// filter threads
|
||||||
threadsToCreate = update.filter(i1 => !allThreadsRecords.find((i2: { id: string }) => i1._id === i2.id));
|
threadsToCreate = update.filter(i1 => !allThreadsRecords.find((i2: { id: string }) => i1._id === i2.id));
|
||||||
threadsToUpdate = allThreadsRecords.filter((i1: { id: string }) => update.find(i2 => i1.id === i2._id));
|
threadsToUpdate = allThreadsRecords.filter((i1: { id: string }) => update.find(i2 => i1.id === i2._id));
|
||||||
|
|
Loading…
Reference in New Issue