-
Tasso Evangelista authoredTasso Evangelista authored
userData.ts 3.84 KiB
import type { ILivechatAgent, IUser, Serialized } from '@rocket.chat/core-typings';
import { ReactiveVar } from 'meteor/reactive-var';
import { Users } from '../../app/models/client';
import { Notifications } from '../../app/notifications/client';
import { sdk } from '../../app/utils/client/lib/SDKClient';
export const isSyncReady = new ReactiveVar(false);
type RawUserData = Serialized<
Pick<
IUser,
| '_id'
| 'type'
| 'name'
| 'username'
| 'emails'
| 'status'
| 'statusDefault'
| 'statusText'
| 'statusConnection'
| 'avatarOrigin'
| 'utcOffset'
| 'language'
| 'settings'
| 'roles'
| 'active'
| 'defaultRoom'
| 'customFields'
| 'oauth'
| 'createdAt'
| '_updatedAt'
| 'avatarETag'
> & { statusLivechat?: ILivechatAgent['statusLivechat'] }
>;
const updateUser = (userData: IUser): void => {
const user = Users.findOne({ _id: userData._id }) as IUser | undefined;
if (!user?._updatedAt || user._updatedAt.getTime() < userData._updatedAt.getTime()) {
Users.upsert({ _id: userData._id }, userData);
return;
}
// delete data already on user's collection as those are newer
Object.keys(user).forEach((key) => {
delete userData[key as keyof IUser];
});
Users.update({ _id: user._id }, { $set: { ...userData } });
};
let cancel: undefined | (() => void);
export const synchronizeUserData = async (uid: IUser['_id']): Promise<RawUserData | void> => {
if (!uid) {
return;
}
// Remove data from any other user that we may have retained
Users.remove({ _id: { $ne: uid } });
cancel?.();
const result = Notifications.onUser('userData', (data) => {
switch (data.type) {
case 'inserted':
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { type, id, ...user } = data;
Users.insert(user as unknown as IUser);
break;
case 'updated':
Users.upsert({ _id: uid }, { $set: data.diff, $unset: data.unset as any });
break;
case 'removed':
Users.remove({ _id: uid });
break;
}
});
cancel = result.stop;
await result.ready();
const { ldap, lastLogin, services: rawServices, ...userData } = await sdk.rest.get('/v1/me');
// email?: {
// verificationTokens?: IUserEmailVerificationToken[];
// };
// export interface IUserEmailVerificationToken {
// token: string;
// address: string;
// when: Date;
// }
if (userData) {
const { email, cloud, resume, email2fa, emailCode, ...services } = rawServices || {};
updateUser({
...userData,
...(rawServices && {
services: {
...(services ? { ...services } : {}),
...(resume
? {
resume: {
...(resume.loginTokens && {
loginTokens: resume.loginTokens.map((token) => ({
...token,
when: new Date('when' in token ? token.when : ''),
createdAt: ('createdAt' in token ? new Date(token.createdAt) : undefined) as Date,
twoFactorAuthorizedUntil: token.twoFactorAuthorizedUntil ? new Date(token.twoFactorAuthorizedUntil) : undefined,
})),
}),
},
}
: {}),
...(cloud
? {
cloud: {
...cloud,
expiresAt: new Date(cloud.expiresAt),
},
}
: {}),
emailCode: emailCode?.map(({ expire, ...data }) => ({ expire: new Date(expire), ...data })) || [],
...(email2fa ? { email2fa: { ...email2fa, changedAt: new Date(email2fa.changedAt) } } : {}),
...(email?.verificationTokens && {
email: {
verificationTokens: email.verificationTokens.map((token) => ({
...token,
when: new Date(token.when),
})),
},
}),
},
}),
...(lastLogin && {
lastLogin: new Date(lastLogin),
}),
ldap: Boolean(ldap),
createdAt: new Date(userData.createdAt),
_updatedAt: new Date(userData._updatedAt),
});
}
isSyncReady.set(true);
return userData;
};
export const removeLocalUserData = (): number => Users.remove({});