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 { MarkdownAST } from '@rocket.chat/message-parser';
import { IAttachment } from './IAttachment';
import { IMessage } from './IMessage';
import { IServedBy } from './IServedBy';
import { SubscriptionType } from './ISubscription';
@ -101,3 +103,52 @@ export interface IOmnichannelRoom extends Omit<IRoom, 'default' | 'featured' | '
}
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 {
_id: string; // _id belongs watermelonDB
id: string; // id from server
_updatedAt?: string; // from server
v?: IVisitor;
f: boolean;
t: SubscriptionType;
ts: Date;
@ -38,12 +40,14 @@ export interface ISubscription {
alert: boolean;
roles?: string[];
unread: number;
lm: string;
lr: string;
userMentions: number;
groupMentions: number;
tunread?: string[];
tunreadUser?: string[];
tunreadGroup?: string[];
roomUpdatedAt: Date;
roomUpdatedAt: Date | number;
ro: boolean;
lastOpen?: Date;
description?: string;
@ -88,3 +92,30 @@ export interface ISubscription {
}
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 { IServerSubscriptionItem, IServerRoomItem } from '../../../definitions';
import database from '../../database';
export default async (subscriptions = [], rooms = []) => {
export default async (subscriptions: IServerSubscriptionItem[], rooms: IServerRoomItem[]) => {
let sub = subscriptions;
let room = rooms;
try {
const db = database.active;
const subCollection = db.get('subscriptions');
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();
existingSubs = existingSubs.map(s => ({
const existingSubs = await subCollection.query(Q.where('rid', Q.oneOf(roomIds))).fetch();
const mappedExistingSubs = existingSubs.map(s => ({
_id: s._id,
f: s.f,
t: s.t,
@ -55,11 +58,12 @@ export default async (subscriptions = [], rooms = []) => {
E2EKey: s.E2EKey,
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);
let existingRooms = await subCollection.query(Q.where('id', Q.oneOf(subsIds))).fetch();
existingRooms = existingRooms.map(r => ({
const existingRooms = await subCollection.query(Q.where('id', Q.oneOf(subsIds))).fetch();
const mappedExistingRooms = existingRooms.map(r => ({
_updatedAt: r._updatedAt,
lastMessage: r.lastMessage,
description: r.description,
@ -84,13 +88,14 @@ export default async (subscriptions = [], rooms = []) => {
e2eKeyId: r.e2eKeyId,
avatarETag: r.avatarETag
}));
rooms = rooms.concat(existingRooms);
// Assign
room = rooms.concat(mappedExistingRooms as unknown as IServerRoomItem);
} catch {
// do nothing
}
return {
subscriptions,
rooms
subscriptions: sub,
rooms: room
};
};

View File

@ -5,17 +5,18 @@ import { store as reduxStore } from '../../auxStore';
import { compareServerVersion } from '../../utils';
import findSubscriptionsRooms from './findSubscriptionsRooms';
import normalizeMessage from './normalizeMessage';
import { ISubscription, IServerRoom, IServerSubscription, IServerSubscriptionItem, IServerRoomItem } from '../../../definitions';
// TODO: delete and update
export const merge = (subscription, room) => {
const serverVersion = reduxStore.getState().server.version;
subscription = EJSON.fromJSONValue(subscription);
room = EJSON.fromJSONValue(room);
export const merge = (
subscription: ISubscription | IServerSubscriptionItem,
room?: ISubscription | IServerRoomItem
): ISubscription => {
const serverVersion = reduxStore.getState().server.version as string;
subscription = EJSON.fromJSONValue(subscription) as ISubscription;
if (!subscription) {
return;
}
if (room) {
room = EJSON.fromJSONValue(room) as ISubscription;
if (room._updatedAt) {
subscription.lastMessage = normalizeMessage(room.lastMessage);
subscription.description = room.description;
@ -28,15 +29,21 @@ export const merge = (subscription, room) => {
subscription.usernames = room.usernames;
subscription.uids = room.uids;
}
if (compareServerVersion(serverVersion, 'lowerThan', '3.7.0')) {
const updatedAt = room?._updatedAt ? new Date(room._updatedAt) : 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);
} else {
// https://github.com/RocketChat/Rocket.Chat/blob/develop/app/ui-sidenav/client/roomList.js#L180
const lastRoomUpdate = room.lm || subscription.ts || subscription._updatedAt;
// @ts-ignore Same as above scenario
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;
}
subscription.ro = room.ro;
@ -76,7 +83,7 @@ export const merge = (subscription, room) => {
}
if (!subscription.name) {
subscription.name = subscription.fname;
subscription.name = subscription.fname as string;
}
if (!subscription.autoTranslate) {
@ -88,29 +95,24 @@ export const merge = (subscription, room) => {
return subscription;
};
export default async (subscriptions = [], rooms = []) => {
if (subscriptions.update) {
subscriptions = subscriptions.update;
rooms = rooms.update;
}
export default async (serverSubscriptions: IServerSubscription, serverRooms: IServerRoom): Promise<ISubscription[]> => {
const subscriptions = serverSubscriptions.update;
const rooms = serverRooms.update;
// 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
subscriptions = subscriptions.map(s => {
const index = rooms.findIndex(({ _id }) => _id === s.rid);
const mergedSubscriptions = findData.subscriptions.map(subscription => {
const index = findData.rooms.findIndex(({ _id }) => _id === subscription.rid);
// Room not found
if (index < 0) {
return merge(s);
return merge(subscription);
}
const [room] = rooms.splice(index, 1);
return merge(s, room);
return merge(subscription, room);
});
// Decrypt all subscriptions missing decryption
subscriptions = await Encryption.decryptSubscriptions(subscriptions);
const decryptedSubscriptions = (await Encryption.decryptSubscriptions(mergedSubscriptions)) as ISubscription[];
return {
subscriptions,
rooms
};
return decryptedSubscriptions;
};

View File

@ -127,8 +127,11 @@ const createOrUpdateSubscription = async (subscription, room) => {
}
}
let tmp = merge(subscription, room);
tmp = await Encryption.decryptSubscription(tmp);
let tmp;
if (subscription) {
tmp = merge(subscription, room);
tmp = await Encryption.decryptSubscription(tmp);
}
let sub;
try {
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 { subscriptions } = yield mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
const subscriptions = yield mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
const db = database.active;
const subCollection = db.get('subscriptions');
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;