Chore: Migrate to Typescript mergeSubscriptionRooms and findSubscriptionsRooms (#3747)

* fix fromJSONValue type

* migrate findSubscription and mergeSubscription to typescript

* chore: fix subscription param returning null
This commit is contained in:
Gleidson Daniel Silva 2022-02-21 16:41:49 -03:00 committed by GitHub
parent f27ddf2e22
commit 753dec9e27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 142 additions and 38 deletions

View File

@ -1,5 +1,7 @@
import Model from '@nozbe/watermelondb/Model'; import Model from '@nozbe/watermelondb/Model';
import { MarkdownAST } from '@rocket.chat/message-parser';
import { IAttachment } from './IAttachment';
import { IMessage } from './IMessage'; import { IMessage } from './IMessage';
import { IServedBy } from './IServedBy'; import { IServedBy } from './IServedBy';
import { SubscriptionType } from './ISubscription'; import { SubscriptionType } from './ISubscription';
@ -101,3 +103,52 @@ export interface IOmnichannelRoom extends Omit<IRoom, 'default' | 'featured' | '
} }
export type TRoomModel = IRoom & Model; export type TRoomModel = IRoom & Model;
export interface IServerRoomItem {
_id: string;
name: string;
fname: string;
t: SubscriptionType;
u: {
_id: string;
username: string;
};
customFields: {};
ts: string;
ro: boolean;
_updatedAt: string;
lm: string;
lastMessage: {
alias: string;
msg: string;
attachments: IAttachment[];
parseUrls: boolean;
bot: {
i: string;
};
groupable: boolean;
avatar: string;
ts: string;
u: IUser;
rid: string;
_id: string;
_updatedAt: string;
mentions: [];
channels: [];
md: MarkdownAST;
};
topic: string;
joinCodeRequired: boolean;
description: string;
jitsiTimeout: string;
usersCount: number;
e2eKeyId: string;
avatarETag: string;
encrypted: boolean;
}
export interface IServerRoom {
update: IServerRoomItem[];
remove: IServerRoomItem[];
success: boolean;
}

View File

@ -27,6 +27,8 @@ export interface IVisitor {
export interface ISubscription { export interface ISubscription {
_id: string; // _id belongs watermelonDB _id: string; // _id belongs watermelonDB
id: string; // id from server id: string; // id from server
_updatedAt?: string; // from server
v?: IVisitor;
f: boolean; f: boolean;
t: SubscriptionType; t: SubscriptionType;
ts: Date; ts: Date;
@ -38,12 +40,14 @@ export interface ISubscription {
alert: boolean; alert: boolean;
roles?: string[]; roles?: string[];
unread: number; unread: number;
lm: string;
lr: string;
userMentions: number; userMentions: number;
groupMentions: number; groupMentions: number;
tunread?: string[]; tunread?: string[];
tunreadUser?: string[]; tunreadUser?: string[];
tunreadGroup?: string[]; tunreadGroup?: string[];
roomUpdatedAt: Date; roomUpdatedAt: Date | number;
ro: boolean; ro: boolean;
lastOpen?: Date; lastOpen?: Date;
description?: string; description?: string;
@ -88,3 +92,30 @@ export interface ISubscription {
} }
export type TSubscriptionModel = ISubscription & Model; export type TSubscriptionModel = ISubscription & Model;
export interface IServerSubscriptionItem {
_id: string;
rid: string;
u: {
_id: string;
username: string;
};
_updatedAt: string;
alert: boolean;
fname: string;
groupMentions: number;
name: string;
open: boolean;
t: string;
unread: number;
userMentions: number;
ls: string;
lr: string;
tunread: number[] | [];
}
export interface IServerSubscription {
update: IServerSubscriptionItem[];
remove: IServerSubscriptionItem[];
success: boolean;
}

View File

@ -1,15 +1,18 @@
import { Q } from '@nozbe/watermelondb'; import { Q } from '@nozbe/watermelondb';
import { IServerSubscriptionItem, IServerRoomItem } from '../../../definitions';
import database from '../../database'; import database from '../../database';
export default async (subscriptions = [], rooms = []) => { export default async (subscriptions: IServerSubscriptionItem[], rooms: IServerRoomItem[]) => {
let sub = subscriptions;
let room = rooms;
try { try {
const db = database.active; const db = database.active;
const subCollection = db.get('subscriptions'); const subCollection = db.get('subscriptions');
const roomIds = rooms.filter(r => !subscriptions.find(s => s.rid === r._id)).map(r => r._id); const roomIds = rooms.filter(r => !subscriptions.find(s => s.rid === r._id)).map(r => r._id);
let existingSubs = await subCollection.query(Q.where('rid', Q.oneOf(roomIds))).fetch(); const existingSubs = await subCollection.query(Q.where('rid', Q.oneOf(roomIds))).fetch();
existingSubs = existingSubs.map(s => ({ const mappedExistingSubs = existingSubs.map(s => ({
_id: s._id, _id: s._id,
f: s.f, f: s.f,
t: s.t, t: s.t,
@ -55,11 +58,12 @@ export default async (subscriptions = [], rooms = []) => {
E2EKey: s.E2EKey, E2EKey: s.E2EKey,
avatarETag: s.avatarETag avatarETag: s.avatarETag
})); }));
subscriptions = subscriptions.concat(existingSubs); // Assign
sub = subscriptions.concat(mappedExistingSubs as unknown as IServerSubscriptionItem);
const subsIds = subscriptions.filter(s => !rooms.find(r => s.rid === r._id)).map(s => s._id); const subsIds = subscriptions.filter(s => !rooms.find(r => s.rid === r._id)).map(s => s._id);
let existingRooms = await subCollection.query(Q.where('id', Q.oneOf(subsIds))).fetch(); const existingRooms = await subCollection.query(Q.where('id', Q.oneOf(subsIds))).fetch();
existingRooms = existingRooms.map(r => ({ const mappedExistingRooms = existingRooms.map(r => ({
_updatedAt: r._updatedAt, _updatedAt: r._updatedAt,
lastMessage: r.lastMessage, lastMessage: r.lastMessage,
description: r.description, description: r.description,
@ -84,13 +88,14 @@ export default async (subscriptions = [], rooms = []) => {
e2eKeyId: r.e2eKeyId, e2eKeyId: r.e2eKeyId,
avatarETag: r.avatarETag avatarETag: r.avatarETag
})); }));
rooms = rooms.concat(existingRooms); // Assign
room = rooms.concat(mappedExistingRooms as unknown as IServerRoomItem);
} catch { } catch {
// do nothing // do nothing
} }
return { return {
subscriptions, subscriptions: sub,
rooms rooms: room
}; };
}; };

View File

@ -5,17 +5,18 @@ import { store as reduxStore } from '../../auxStore';
import { compareServerVersion } from '../../utils'; import { compareServerVersion } from '../../utils';
import findSubscriptionsRooms from './findSubscriptionsRooms'; import findSubscriptionsRooms from './findSubscriptionsRooms';
import normalizeMessage from './normalizeMessage'; import normalizeMessage from './normalizeMessage';
import { ISubscription, IServerRoom, IServerSubscription, IServerSubscriptionItem, IServerRoomItem } from '../../../definitions';
// TODO: delete and update // TODO: delete and update
export const merge = (subscription, room) => { export const merge = (
const serverVersion = reduxStore.getState().server.version; subscription: ISubscription | IServerSubscriptionItem,
subscription = EJSON.fromJSONValue(subscription); room?: ISubscription | IServerRoomItem
room = EJSON.fromJSONValue(room); ): ISubscription => {
const serverVersion = reduxStore.getState().server.version as string;
subscription = EJSON.fromJSONValue(subscription) as ISubscription;
if (!subscription) {
return;
}
if (room) { if (room) {
room = EJSON.fromJSONValue(room) as ISubscription;
if (room._updatedAt) { if (room._updatedAt) {
subscription.lastMessage = normalizeMessage(room.lastMessage); subscription.lastMessage = normalizeMessage(room.lastMessage);
subscription.description = room.description; subscription.description = room.description;
@ -28,15 +29,21 @@ export const merge = (subscription, room) => {
subscription.usernames = room.usernames; subscription.usernames = room.usernames;
subscription.uids = room.uids; subscription.uids = room.uids;
} }
if (compareServerVersion(serverVersion, 'lowerThan', '3.7.0')) { if (compareServerVersion(serverVersion, 'lowerThan', '3.7.0')) {
const updatedAt = room?._updatedAt ? new Date(room._updatedAt) : null; const updatedAt = room?._updatedAt ? new Date(room._updatedAt) : null;
const lastMessageTs = subscription?.lastMessage?.ts ? new Date(subscription.lastMessage.ts) : null; const lastMessageTs = subscription?.lastMessage?.ts ? new Date(subscription.lastMessage.ts) : null;
// @ts-ignore
// If all parameters are null it will return zero, if only one is null it will return its timestamp only.
// "It works", but it's not the best solution. It does not accept "Date" as a parameter, but it works.
subscription.roomUpdatedAt = Math.max(updatedAt, lastMessageTs); subscription.roomUpdatedAt = Math.max(updatedAt, lastMessageTs);
} else { } else {
// https://github.com/RocketChat/Rocket.Chat/blob/develop/app/ui-sidenav/client/roomList.js#L180 // https://github.com/RocketChat/Rocket.Chat/blob/develop/app/ui-sidenav/client/roomList.js#L180
const lastRoomUpdate = room.lm || subscription.ts || subscription._updatedAt; const lastRoomUpdate = room.lm || subscription.ts || subscription._updatedAt;
// @ts-ignore Same as above scenario
subscription.roomUpdatedAt = subscription.lr subscription.roomUpdatedAt = subscription.lr
? Math.max(new Date(subscription.lr), new Date(lastRoomUpdate)) ? // @ts-ignore Same as above scenario
Math.max(new Date(subscription.lr), new Date(lastRoomUpdate))
: lastRoomUpdate; : lastRoomUpdate;
} }
subscription.ro = room.ro; subscription.ro = room.ro;
@ -76,7 +83,7 @@ export const merge = (subscription, room) => {
} }
if (!subscription.name) { if (!subscription.name) {
subscription.name = subscription.fname; subscription.name = subscription.fname as string;
} }
if (!subscription.autoTranslate) { if (!subscription.autoTranslate) {
@ -88,29 +95,24 @@ export const merge = (subscription, room) => {
return subscription; return subscription;
}; };
export default async (subscriptions = [], rooms = []) => { export default async (serverSubscriptions: IServerSubscription, serverRooms: IServerRoom): Promise<ISubscription[]> => {
if (subscriptions.update) { const subscriptions = serverSubscriptions.update;
subscriptions = subscriptions.update; const rooms = serverRooms.update;
rooms = rooms.update;
}
// Find missing rooms/subscriptions on local database // Find missing rooms/subscriptions on local database
({ subscriptions, rooms } = await findSubscriptionsRooms(subscriptions, rooms)); const findData = await findSubscriptionsRooms(subscriptions, rooms);
// Merge each subscription into a room // Merge each subscription into a room
subscriptions = subscriptions.map(s => { const mergedSubscriptions = findData.subscriptions.map(subscription => {
const index = rooms.findIndex(({ _id }) => _id === s.rid); const index = findData.rooms.findIndex(({ _id }) => _id === subscription.rid);
// Room not found // Room not found
if (index < 0) { if (index < 0) {
return merge(s); return merge(subscription);
} }
const [room] = rooms.splice(index, 1); const [room] = rooms.splice(index, 1);
return merge(s, room); return merge(subscription, room);
}); });
// Decrypt all subscriptions missing decryption // Decrypt all subscriptions missing decryption
subscriptions = await Encryption.decryptSubscriptions(subscriptions); const decryptedSubscriptions = (await Encryption.decryptSubscriptions(mergedSubscriptions)) as ISubscription[];
return { return decryptedSubscriptions;
subscriptions,
rooms
};
}; };

View File

@ -127,8 +127,11 @@ const createOrUpdateSubscription = async (subscription, room) => {
} }
} }
let tmp = merge(subscription, room); let tmp;
tmp = await Encryption.decryptSubscription(tmp); if (subscription) {
tmp = merge(subscription, room);
tmp = await Encryption.decryptSubscription(tmp);
}
let sub; let sub;
try { try {
sub = await subCollection.find(tmp.rid); sub = await subCollection.find(tmp.rid);

View File

@ -57,8 +57,7 @@ const handleRoomsRequest = function* handleRoomsRequest({ params }) {
} }
const [subscriptionsResult, roomsResult] = yield RocketChat.getRooms(roomsUpdatedAt); const [subscriptionsResult, roomsResult] = yield RocketChat.getRooms(roomsUpdatedAt);
const { subscriptions } = yield mergeSubscriptionsRooms(subscriptionsResult, roomsResult); const subscriptions = yield mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
const db = database.active; const db = database.active;
const subCollection = db.get('subscriptions'); const subCollection = db.get('subscriptions');
const messagesCollection = db.get('messages'); const messagesCollection = db.get('messages');

View File

@ -0,0 +1,13 @@
diff --git a/node_modules/@types/ejson/index.d.ts b/node_modules/@types/ejson/index.d.ts
index 3a35636..278ef98 100755
--- a/node_modules/@types/ejson/index.d.ts
+++ b/node_modules/@types/ejson/index.d.ts
@@ -17,7 +17,7 @@ export function parse(str: string): any;
export function stringify(obj: any, options?: StringifyOptions): string;
export function toJSONValue(obj: any): string;
-export function fromJSONValue(obj: string): any;
+export function fromJSONValue(obj: Object): any;
export function isBinary(value: any): boolean;
export function newBinary(len: number): Uint8Array;
export function equals(a: any, b: any, options?: CloneOptions): boolean;