diff --git a/app/containers/message/Content.tsx b/app/containers/message/Content.tsx index 919b1dbb7..db664d2cc 100644 --- a/app/containers/message/Content.tsx +++ b/app/containers/message/Content.tsx @@ -10,7 +10,7 @@ import { SYSTEM_MESSAGE_TYPES_WITH_AUTHOR_NAME, getInfoMessage } from './utils'; import { themes } from '../../constants/colors'; import MessageContext from './Context'; import Encrypted from './Encrypted'; -import { E2E_MESSAGE_TYPE } from '../../lib/encryption/constants'; +import { E2E_MESSAGE_TYPE } from '../../lib/constants'; import { IMessageContent } from './interfaces'; import { useTheme } from '../../theme'; diff --git a/app/containers/message/Encrypted.tsx b/app/containers/message/Encrypted.tsx index c2818f220..5896f4b36 100644 --- a/app/containers/message/Encrypted.tsx +++ b/app/containers/message/Encrypted.tsx @@ -1,7 +1,7 @@ import React, { useContext } from 'react'; import Touchable from './Touchable'; -import { E2E_MESSAGE_TYPE } from '../../lib/encryption/constants'; +import { E2E_MESSAGE_TYPE } from '../../lib/constants'; import { CustomIcon } from '../../lib/Icons'; import { themes } from '../../constants/colors'; import { BUTTON_HIT_SLOP } from './utils'; diff --git a/app/containers/message/index.tsx b/app/containers/message/index.tsx index a892c15dc..804794196 100644 --- a/app/containers/message/index.tsx +++ b/app/containers/message/index.tsx @@ -6,7 +6,7 @@ import Message from './Message'; import MessageContext from './Context'; import debounce from '../../utils/debounce'; import { SYSTEM_MESSAGES, getMessageTranslation } from './utils'; -import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../../lib/encryption/constants'; +import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../../lib/constants'; import messagesStatus from '../../constants/messagesStatus'; import { useTheme, withTheme } from '../../theme'; import openLink from '../../utils/openLink'; diff --git a/app/definitions/ISubscription.ts b/app/definitions/ISubscription.ts index 6f13a040c..41cd4d5e6 100644 --- a/app/definitions/ISubscription.ts +++ b/app/definitions/ISubscription.ts @@ -106,6 +106,7 @@ export interface ISubscription { } export type TSubscriptionModel = ISubscription & Model; +export type TSubscription = TSubscriptionModel | ISubscription; // https://github.com/RocketChat/Rocket.Chat/blob/a88a96fcadd925b678ff27ada37075e029f78b5e/definition/ISubscription.ts#L8 export interface IServerSubscription extends IRocketChatRecord { diff --git a/app/definitions/rest/v1/users.ts b/app/definitions/rest/v1/users.ts index 035e62509..898799102 100644 --- a/app/definitions/rest/v1/users.ts +++ b/app/definitions/rest/v1/users.ts @@ -49,6 +49,9 @@ export type UsersEndpoints = { 'users.resetAvatar': { POST: (params: { userId: string }) => {}; }; + 'users.removeOtherTokens': { + POST: (params: { userId: string }) => {}; + }; 'users.getPreferences': { GET: (params: { userId: IUser['_id'] }) => { preferences: INotificationPreferences; diff --git a/app/lib/encryption/constants.ts b/app/lib/constants.ts similarity index 66% rename from app/lib/encryption/constants.ts rename to app/lib/constants.ts index 566fa1b65..ff48f2a05 100644 --- a/app/lib/encryption/constants.ts +++ b/app/lib/constants.ts @@ -14,3 +14,8 @@ export const E2E_ROOM_TYPES: Record = { d: 'd', p: 'p' }; + +export const THEME_PREFERENCES_KEY = 'RC_THEME_PREFERENCES_KEY'; +export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY'; +export const ANALYTICS_EVENTS_KEY = 'RC_ANALYTICS_EVENTS_KEY'; +export const MIN_ROCKETCHAT_VERSION = '0.70.0'; diff --git a/app/lib/encryption/encryption.ts b/app/lib/encryption/encryption.ts index 6e9abae2d..39ca516bb 100644 --- a/app/lib/encryption/encryption.ts +++ b/app/lib/encryption/encryption.ts @@ -17,7 +17,7 @@ import { E2E_PUBLIC_KEY, E2E_RANDOM_PASSWORD_KEY, E2E_STATUS -} from './constants'; +} from '../constants'; import { joinVectorData, randomPassword, splitVectorData, toString, utf8ToBuffer } from './utils'; import { EncryptionRoom } from './index'; import { IMessage, ISubscription, TMessageModel, TSubscriptionModel, TThreadMessageModel, TThreadModel } from '../../definitions'; diff --git a/app/lib/encryption/room.ts b/app/lib/encryption/room.ts index ee3519207..45907aa98 100644 --- a/app/lib/encryption/room.ts +++ b/app/lib/encryption/room.ts @@ -9,7 +9,7 @@ import Deferred from '../../utils/deferred'; import debounce from '../../utils/debounce'; import database from '../database'; import log from '../../utils/log'; -import { E2E_MESSAGE_TYPE, E2E_STATUS } from './constants'; +import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../constants'; import { b64ToBuffer, bufferToB64, diff --git a/app/lib/methods/actions.ts b/app/lib/methods/actions.ts index 73dc44468..2e4323598 100644 --- a/app/lib/methods/actions.ts +++ b/app/lib/methods/actions.ts @@ -1,18 +1,10 @@ -import random from '../../utils/random'; +import { ITriggerAction, IUserInteraction, ModalActions } from '../../containers/UIKit/interfaces'; +import { TRocketChat } from '../../definitions/IRocketChat'; import EventEmitter from '../../utils/events'; import fetch from '../../utils/fetch'; +import random from '../../utils/random'; import Navigation from '../Navigation'; import sdk from '../rocketchat/services/sdk'; -import { - ActionTypes, - ITriggerAction, - ITriggerBlockAction, - ITriggerCancel, - ITriggerSubmitView, - IUserInteraction, - ModalActions -} from '../../containers/UIKit/interfaces'; -import { TRocketChat } from '../../definitions/IRocketChat'; const triggersId = new Map(); @@ -139,18 +131,3 @@ export function triggerAction( return reject(); }); } - -export default function triggerBlockAction(this: TRocketChat, options: ITriggerBlockAction) { - return triggerAction.call(this, { type: ActionTypes.ACTION, ...options }); -} - -export async function triggerSubmitView(this: TRocketChat, { viewId, ...options }: ITriggerSubmitView) { - const result = await triggerAction.call(this, { type: ActionTypes.SUBMIT, viewId, ...options }); - if (!result || ModalActions.CLOSE === result) { - Navigation.back(); - } -} - -export function triggerCancel(this: TRocketChat, { view, ...options }: ITriggerCancel) { - return triggerAction.call(this, { type: ActionTypes.CLOSED, view, ...options }); -} diff --git a/app/lib/rocketchat/methods/clearCache.ts b/app/lib/methods/clearCache.ts similarity index 93% rename from app/lib/rocketchat/methods/clearCache.ts rename to app/lib/methods/clearCache.ts index 41fc4f62d..eeb5a97b2 100644 --- a/app/lib/rocketchat/methods/clearCache.ts +++ b/app/lib/methods/clearCache.ts @@ -1,4 +1,4 @@ -import database from '../../database'; +import database from '../database'; export default async function clearCache({ server }: { server: string }): Promise { try { diff --git a/app/lib/rocketchat/methods/getRoom.ts b/app/lib/methods/getRoom.ts similarity index 74% rename from app/lib/rocketchat/methods/getRoom.ts rename to app/lib/methods/getRoom.ts index 849a8a6c7..35842e4f3 100644 --- a/app/lib/rocketchat/methods/getRoom.ts +++ b/app/lib/methods/getRoom.ts @@ -1,5 +1,5 @@ -import { TSubscriptionModel } from '../../../definitions'; -import database from '../../database'; +import { TSubscriptionModel } from '../../definitions'; +import database from '../database'; export default async function getRoom(rid: string): Promise { try { diff --git a/app/lib/methods/loadMessagesForRoom.ts b/app/lib/methods/loadMessagesForRoom.ts index f2bce7102..f190473f4 100644 --- a/app/lib/methods/loadMessagesForRoom.ts +++ b/app/lib/methods/loadMessagesForRoom.ts @@ -4,7 +4,7 @@ import { MessageTypeLoad } from '../../constants/messageTypeLoad'; import { IMessage, TMessageModel } from '../../definitions'; import log from '../../utils/log'; import { getMessageById } from '../database/services/Message'; -import roomTypeToApiType, { RoomTypes } from '../rocketchat/methods/roomTypeToApiType'; +import roomTypeToApiType, { RoomTypes } from './roomTypeToApiType'; import sdk from '../rocketchat/services/sdk'; import { generateLoadMoreId } from '../utils'; import updateMessages from './updateMessages'; diff --git a/app/lib/methods/loadNextMessages.ts b/app/lib/methods/loadNextMessages.ts index 063170652..e1f668a3a 100644 --- a/app/lib/methods/loadNextMessages.ts +++ b/app/lib/methods/loadNextMessages.ts @@ -8,7 +8,7 @@ import { MessageTypeLoad } from '../../constants/messageTypeLoad'; import { generateLoadMoreId } from '../utils'; import updateMessages from './updateMessages'; import { TMessageModel } from '../../definitions'; -import RocketChat from '../rocketchat'; +import sdk from '../rocketchat/services/sdk'; const COUNT = 50; @@ -22,7 +22,7 @@ interface ILoadNextMessages { export default function loadNextMessages(args: ILoadNextMessages): Promise { return new Promise(async (resolve, reject) => { try { - const data = await RocketChat.methodCallWrapper('loadNextMessages', args.rid, args.ts, COUNT); + const data = await sdk.methodCallWrapper('loadNextMessages', args.rid, args.ts, COUNT); let messages = EJSON.fromJSONValue(data?.messages); messages = orderBy(messages, 'ts'); if (messages?.length) { diff --git a/app/lib/rocketchat/methods/roomTypeToApiType.ts b/app/lib/methods/roomTypeToApiType.ts similarity index 100% rename from app/lib/rocketchat/methods/roomTypeToApiType.ts rename to app/lib/methods/roomTypeToApiType.ts diff --git a/app/lib/methods/sendMessage.ts b/app/lib/methods/sendMessage.ts index d41d38612..aaf03ea8d 100644 --- a/app/lib/methods/sendMessage.ts +++ b/app/lib/methods/sendMessage.ts @@ -6,7 +6,7 @@ import database from '../database'; import log from '../../utils/log'; import random from '../../utils/random'; import { Encryption } from '../encryption'; -import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../encryption/constants'; +import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../constants'; import { E2EType, IMessage, IUser, TMessageModel } from '../../definitions'; import sdk from '../rocketchat/services/sdk'; @@ -85,7 +85,7 @@ export async function resendMessage(message: TMessageModel, tmid?: string) { } } -export default async function ( +export async function sendMessage( rid: string, msg: string, tmid: string | undefined, diff --git a/app/lib/methods/subscriptions/room.ts b/app/lib/methods/subscriptions/room.ts index ce2bf766a..baac2b72c 100644 --- a/app/lib/methods/subscriptions/room.ts +++ b/app/lib/methods/subscriptions/room.ts @@ -17,6 +17,7 @@ import { subscribeRoom, unsubscribeRoom } from '../../../actions/room'; import { Encryption } from '../../encryption'; import { IMessage, TMessageModel, TSubscriptionModel, TThreadMessageModel, TThreadModel } from '../../../definitions'; import { IDDPMessage } from '../../../definitions/IDDPMessage'; +import sdk from '../../rocketchat/services/sdk'; const WINDOW_TIME = 1000; @@ -57,12 +58,12 @@ export default class RoomSubscription { if (this.promises) { await this.unsubscribe(); } - this.promises = RocketChat.subscribeRoom(this.rid); + this.promises = sdk.subscribeRoom(this.rid); - this.connectedListener = RocketChat.onStreamData('connected', this.handleConnection); - this.disconnectedListener = RocketChat.onStreamData('close', this.handleConnection); - this.notifyRoomListener = RocketChat.onStreamData('stream-notify-room', this.handleNotifyRoomReceived); - this.messageReceivedListener = RocketChat.onStreamData('stream-room-messages', this.handleMessageReceived); + this.connectedListener = sdk.onStreamData('connected', this.handleConnection); + this.disconnectedListener = sdk.onStreamData('close', this.handleConnection); + this.notifyRoomListener = sdk.onStreamData('stream-notify-room', this.handleNotifyRoomReceived); + this.messageReceivedListener = sdk.onStreamData('stream-room-messages', this.handleMessageReceived); if (!this.isAlive) { await this.unsubscribe(); } diff --git a/app/lib/methods/subscriptions/rooms.ts b/app/lib/methods/subscriptions/rooms.ts index f6af324b9..fa7f3a734 100644 --- a/app/lib/methods/subscriptions/rooms.ts +++ b/app/lib/methods/subscriptions/rooms.ts @@ -17,7 +17,7 @@ import { removedRoom } from '../../../actions/room'; import { setUser } from '../../../actions/login'; import { INAPP_NOTIFICATION_EMITTER } from '../../../containers/InAppNotification'; import { Encryption } from '../../encryption'; -import { E2E_MESSAGE_TYPE } from '../../encryption/constants'; +import { E2E_MESSAGE_TYPE } from '../../constants'; import updateMessages from '../updateMessages'; import { IMessage, diff --git a/app/lib/rocketchat/index.ts b/app/lib/rocketchat/index.ts index 0a63687ae..43695952e 100644 --- a/app/lib/rocketchat/index.ts +++ b/app/lib/rocketchat/index.ts @@ -1,4 +1,77 @@ -import RocketChat, { THEME_PREFERENCES_KEY, CRASH_REPORT_KEY, ANALYTICS_EVENTS_KEY } from './rocketchat'; +// Methods +import canOpenRoom from '../methods/canOpenRoom'; +import clearCache from '../methods/clearCache'; +import getRoom from '../methods/getRoom'; +import getRooms from '../methods/getRooms'; +import getSlashCommands from '../methods/getSlashCommands'; +import loadMessagesForRoom from '../methods/loadMessagesForRoom'; +import loadMissedMessages from '../methods/loadMissedMessages'; +import loadNextMessages from '../methods/loadNextMessages'; +import loadSurroundingMessages from '../methods/loadSurroundingMessages'; +import loadThreadMessages from '../methods/loadThreadMessages'; +import readMessages from '../methods/readMessages'; +import roomTypeToApiType from '../methods/roomTypeToApiType'; +// Spread Methods +import * as sendMessage from '../methods/sendMessage'; +import * as callJitsi from './methods/callJitsi'; +import * as enterpriseModules from './methods/enterpriseModules'; +import * as getCustomEmojis from './methods/getCustomEmojis'; +import * as getPermalinks from './methods/getPermalinks'; +import * as getPermissions from './methods/getPermissions'; +import * as getRoles from './methods/getRoles'; +import * as getSettings from './methods/getSettings'; +import * as getUsersPresence from './methods/getUsersPresence'; +import * as helpers from './methods/helpers'; +import * as logout from './methods/logout'; +import * as search from './methods/search'; +import * as sendFileMessage from './methods/sendFileMessage'; +import * as setUser from './methods/setUser'; +import * as triggerActions from './methods/triggerActions'; +import * as userPreferencesMethods from './methods/userPreferencesMethods'; +import * as connect from './services/connect'; +import * as restApis from './services/restApi'; +import * as shareExtension from './services/shareExtension'; + +const TOKEN_KEY = 'reactnativemeteor_usertoken'; +const CURRENT_SERVER = 'currentServer'; +const CERTIFICATE_KEY = 'RC_CERTIFICATE_KEY'; + +const RocketChat = { + TOKEN_KEY, + CURRENT_SERVER, + CERTIFICATE_KEY, + ...restApis, + ...search, + ...getPermalinks, + ...connect, + ...enterpriseModules, + ...sendMessage, + ...shareExtension, + ...sendFileMessage, + ...logout, + ...getUsersPresence, + ...getSettings, + ...getRoles, + ...getPermissions, + ...triggerActions, + ...callJitsi, + ...getCustomEmojis, + ...helpers, + ...userPreferencesMethods, + ...setUser, + + canOpenRoom, + clearCache, + loadMissedMessages, + loadMessagesForRoom, + loadSurroundingMessages, + loadNextMessages, + loadThreadMessages, + getRooms, + readMessages, + getSlashCommands, + getRoom, + roomTypeToApiType +}; -export { THEME_PREFERENCES_KEY, CRASH_REPORT_KEY, ANALYTICS_EVENTS_KEY }; export default RocketChat; diff --git a/app/lib/methods/callJitsi.ts b/app/lib/rocketchat/methods/callJitsi.ts similarity index 81% rename from app/lib/methods/callJitsi.ts rename to app/lib/rocketchat/methods/callJitsi.ts index b04fbb19d..0bd2567cc 100644 --- a/app/lib/methods/callJitsi.ts +++ b/app/lib/rocketchat/methods/callJitsi.ts @@ -1,8 +1,8 @@ -import { ISubscription } from '../../definitions'; -import { events, logEvent } from '../../utils/log'; -import { store } from '../auxStore'; -import Navigation from '../Navigation'; -import sdk from '../rocketchat'; +import { ISubscription } from '../../../definitions'; +import { events, logEvent } from '../../../utils/log'; +import { store } from '../../auxStore'; +import Navigation from '../../Navigation'; +import sdk from '../services/sdk'; async function jitsiURL({ room }: { room: ISubscription }) { const { settings } = store.getState(); @@ -46,10 +46,8 @@ export function callJitsiWithoutServer(path: string): void { Navigation.navigate('JitsiMeetView', { url, onlyAudio: false }); } -async function callJitsi(room: ISubscription, onlyAudio = false): Promise { +export async function callJitsi(room: ISubscription, onlyAudio = false): Promise { logEvent(onlyAudio ? events.RA_JITSI_AUDIO : events.RA_JITSI_VIDEO); const url = await jitsiURL({ room }); Navigation.navigate('JitsiMeetView', { url, onlyAudio, rid: room?.rid }); } - -export default callJitsi; diff --git a/app/lib/methods/enterpriseModules.ts b/app/lib/rocketchat/methods/enterpriseModules.ts similarity index 87% rename from app/lib/methods/enterpriseModules.ts rename to app/lib/rocketchat/methods/enterpriseModules.ts index 8769e3818..5f1475913 100644 --- a/app/lib/methods/enterpriseModules.ts +++ b/app/lib/rocketchat/methods/enterpriseModules.ts @@ -1,9 +1,9 @@ -import sdk from '../rocketchat/services/sdk'; -import { compareServerVersion } from '../utils'; -import { store as reduxStore } from '../auxStore'; -import database from '../database'; -import log from '../../utils/log'; -import { clearEnterpriseModules, setEnterpriseModules as setEnterpriseModulesAction } from '../../actions/enterpriseModules'; +import sdk from '../services/sdk'; +import { compareServerVersion } from '../../utils'; +import { store as reduxStore } from '../../auxStore'; +import database from '../../database'; +import log from '../../../utils/log'; +import { clearEnterpriseModules, setEnterpriseModules as setEnterpriseModulesAction } from '../../../actions/enterpriseModules'; const LICENSE_OMNICHANNEL_MOBILE_ENTERPRISE = 'omnichannel-mobile-enterprise'; const LICENSE_LIVECHAT_ENTERPRISE = 'livechat-enterprise'; diff --git a/app/lib/methods/getCustomEmojis.ts b/app/lib/rocketchat/methods/getCustomEmojis.ts similarity index 91% rename from app/lib/methods/getCustomEmojis.ts rename to app/lib/rocketchat/methods/getCustomEmojis.ts index 87a549d18..8e73891ae 100644 --- a/app/lib/methods/getCustomEmojis.ts +++ b/app/lib/rocketchat/methods/getCustomEmojis.ts @@ -1,14 +1,14 @@ import orderBy from 'lodash/orderBy'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; -import { ICustomEmojis } from '../../reducers/customEmojis'; -import { compareServerVersion } from '../utils'; -import { store as reduxStore } from '../auxStore'; -import database from '../database'; -import log from '../../utils/log'; -import { setCustomEmojis as setCustomEmojisAction } from '../../actions/customEmojis'; -import { ICustomEmoji, TCustomEmojiModel } from '../../definitions'; -import sdk from '../rocketchat/services/sdk'; +import { ICustomEmojis } from '../../../reducers/customEmojis'; +import { compareServerVersion } from '../../utils'; +import { store as reduxStore } from '../../auxStore'; +import database from '../../database'; +import log from '../../../utils/log'; +import { setCustomEmojis as setCustomEmojisAction } from '../../../actions/customEmojis'; +import { ICustomEmoji, TCustomEmojiModel } from '../../../definitions'; +import sdk from '../services/sdk'; interface IUpdateEmojis { update: TCustomEmojiModel[]; diff --git a/app/lib/rocketchat/methods/getPermalinkMessage.ts b/app/lib/rocketchat/methods/getPermalinkMessage.ts deleted file mode 100644 index 9bc96bdd8..000000000 --- a/app/lib/rocketchat/methods/getPermalinkMessage.ts +++ /dev/null @@ -1,25 +0,0 @@ -import log from '../../../utils/log'; -import { TMessageModel, TSubscriptionModel } from '../../../definitions'; -import reduxStore from '../../createStore'; -import getRoom from './getRoom'; -import isGroupChat from './isGroupChat'; - -type TRoomType = 'p' | 'c' | 'd'; - -export default async function getPermalinkMessage(message: TMessageModel): Promise { - if (!message.subscription) return null; - let room: TSubscriptionModel; - try { - room = await getRoom(message.subscription.id); - } catch (e) { - log(e); - return null; - } - const { server } = reduxStore.getState().server; - const roomType = { - p: 'group', - c: 'channel', - d: 'direct' - }[room.t as TRoomType]; - return `${server}/${roomType}/${isGroupChat(room) ? room.rid : room.name}?msg=${message.id}`; -} diff --git a/app/lib/rocketchat/methods/getPermalinks.ts b/app/lib/rocketchat/methods/getPermalinks.ts new file mode 100644 index 000000000..9bbe89a15 --- /dev/null +++ b/app/lib/rocketchat/methods/getPermalinks.ts @@ -0,0 +1,39 @@ +import log from '../../../utils/log'; +import { TMessageModel, TSubscriptionModel } from '../../../definitions'; +import { store } from '../../auxStore'; +import getRoom from '../../methods/getRoom'; +import { isGroupChat } from './helpers'; + +type TRoomType = 'p' | 'c' | 'd'; + +export async function getPermalinkMessage(message: TMessageModel): Promise { + if (!message.subscription) return null; + let room: TSubscriptionModel; + try { + room = await getRoom(message.subscription.id); + } catch (e) { + log(e); + return null; + } + const { server } = store.getState().server; + const roomType = { + p: 'group', + c: 'channel', + d: 'direct' + }[room.t as TRoomType]; + return `${server}/${roomType}/${isGroupChat(room) ? room.rid : room.name}?msg=${message.id}`; +} + +export function getPermalinkChannel(channel: TSubscriptionModel): string { + const { server } = store.getState().server; + const roomType = { + p: 'group', + c: 'channel', + d: 'direct' + }; + + // @ts-ignore - wrong SubscriptionType + const room = roomType[channel.t]; + + return `${server}/${room}/${channel.name}`; +} diff --git a/app/lib/methods/getPermissions.ts b/app/lib/rocketchat/methods/getPermissions.ts similarity index 90% rename from app/lib/methods/getPermissions.ts rename to app/lib/rocketchat/methods/getPermissions.ts index fa807d7fa..d75af0f0c 100644 --- a/app/lib/methods/getPermissions.ts +++ b/app/lib/rocketchat/methods/getPermissions.ts @@ -1,16 +1,15 @@ -import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; import { Q } from '@nozbe/watermelondb'; +import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; import orderBy from 'lodash/orderBy'; -import { compareServerVersion } from '../utils'; -import database from '../database'; -import log from '../../utils/log'; -import { store as reduxStore } from '../auxStore'; -import RocketChat from '../rocketchat'; -import sdk from '../rocketchat/services/sdk'; -import { setPermissions as setPermissionsAction } from '../../actions/permissions'; -import protectedFunction from './helpers/protectedFunction'; -import { TPermissionModel, IPermission } from '../../definitions'; +import { setPermissions as setPermissionsAction } from '../../../actions/permissions'; +import { IPermission, TPermissionModel } from '../../../definitions'; +import log from '../../../utils/log'; +import { store as reduxStore } from '../../auxStore'; +import database from '../../database'; +import sdk from '../services/sdk'; +import { compareServerVersion } from '../../utils'; +import protectedFunction from '../../methods/helpers/protectedFunction'; export const SUPPORTED_PERMISSIONS = [ 'add-user-to-any-c-room', @@ -154,7 +153,7 @@ export function getPermissions(): Promise { const db = database.active; const permissionsCollection = db.get('permissions'); const allRecords = await permissionsCollection.query().fetch(); - RocketChat.subscribe('stream-notify-logged', 'permissions-changed'); + sdk.subscribe('stream-notify-logged', 'permissions-changed'); // if server version is lower than 0.73.0, fetches from old api if (serverVersion && compareServerVersion(serverVersion, 'lowerThan', '0.73.0')) { // RC 0.66.0 diff --git a/app/lib/methods/getRoles.ts b/app/lib/rocketchat/methods/getRoles.ts similarity index 89% rename from app/lib/methods/getRoles.ts rename to app/lib/rocketchat/methods/getRoles.ts index 6add9e897..97677305a 100644 --- a/app/lib/methods/getRoles.ts +++ b/app/lib/rocketchat/methods/getRoles.ts @@ -1,14 +1,14 @@ import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; import Model from '@nozbe/watermelondb/Model'; -import database from '../database'; -import { getRoleById } from '../database/services/Role'; -import log from '../../utils/log'; -import { store as reduxStore } from '../auxStore'; -import { removeRoles, setRoles as setRolesAction, updateRoles } from '../../actions/roles'; -import protectedFunction from './helpers/protectedFunction'; -import { TRoleModel } from '../../definitions'; -import sdk from '../rocketchat/services/sdk'; +import database from '../../database'; +import { getRoleById } from '../../database/services/Role'; +import log from '../../../utils/log'; +import { store as reduxStore } from '../../auxStore'; +import { removeRoles, setRoles as setRolesAction, updateRoles } from '../../../actions/roles'; +import protectedFunction from '../../methods/helpers/protectedFunction'; +import { TRoleModel } from '../../../definitions'; +import sdk from '../services/sdk'; export async function setRoles(): Promise { const db = database.active; diff --git a/app/lib/methods/getSettings.ts b/app/lib/rocketchat/methods/getSettings.ts similarity index 90% rename from app/lib/methods/getSettings.ts rename to app/lib/rocketchat/methods/getSettings.ts index 2ef89b603..cae346c15 100644 --- a/app/lib/methods/getSettings.ts +++ b/app/lib/rocketchat/methods/getSettings.ts @@ -1,17 +1,17 @@ import { Q } from '@nozbe/watermelondb'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; -import { addSettings, clearSettings } from '../../actions/settings'; -import { DEFAULT_AUTO_LOCK } from '../../constants/localAuthentication'; -import settings from '../../constants/settings'; -import { IPreparedSettings, ISettingsIcon } from '../../definitions'; -import fetch from '../../utils/fetch'; -import log from '../../utils/log'; -import { store as reduxStore } from '../auxStore'; -import database from '../database'; -import RocketChat from '../rocketchat'; -import sdk from '../rocketchat/services/sdk'; -import protectedFunction from './helpers/protectedFunction'; +import { addSettings, clearSettings } from '../../../actions/settings'; +import { DEFAULT_AUTO_LOCK } from '../../../constants/localAuthentication'; +import settings from '../../../constants/settings'; +import { IPreparedSettings, ISettingsIcon } from '../../../definitions'; +import fetch from '../../../utils/fetch'; +import log from '../../../utils/log'; +import { store as reduxStore } from '../../auxStore'; +import database from '../../database'; +import RocketChat from '..'; +import sdk from '../services/sdk'; +import protectedFunction from '../../methods/helpers/protectedFunction'; const serverInfoKeys = [ 'Site_Name', @@ -136,12 +136,12 @@ export async function setSettings(): Promise { } export function subscribeSettings(): void { - return RocketChat.subscribe('stream-notify-all', 'public-settings-changed'); + return sdk.subscribe('stream-notify-all', 'public-settings-changed'); } type IData = ISettingsIcon | IPreparedSettings; -export default async function (): Promise { +export async function getSettings(): Promise { try { const db = database.active; const settingsParams = Object.keys(settings).filter(key => !loginSettings.includes(key)); diff --git a/app/lib/methods/getUsersPresence.ts b/app/lib/rocketchat/methods/getUsersPresence.ts similarity index 88% rename from app/lib/methods/getUsersPresence.ts rename to app/lib/rocketchat/methods/getUsersPresence.ts index 8df7a432a..eb6e349cc 100644 --- a/app/lib/methods/getUsersPresence.ts +++ b/app/lib/rocketchat/methods/getUsersPresence.ts @@ -1,14 +1,14 @@ import { InteractionManager } from 'react-native'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; -import { IActiveUsers } from '../../reducers/activeUsers'; -import { compareServerVersion } from '../utils'; -import { store as reduxStore } from '../auxStore'; -import { setActiveUsers } from '../../actions/activeUsers'; -import { setUser } from '../../actions/login'; -import database from '../database'; -import { IRocketChat, IUser } from '../../definitions'; -import sdk from '../rocketchat/services/sdk'; +import { IActiveUsers } from '../../../reducers/activeUsers'; +import { compareServerVersion } from '../../utils'; +import { store as reduxStore } from '../../auxStore'; +import { setActiveUsers } from '../../../actions/activeUsers'; +import { setUser } from '../../../actions/login'; +import database from '../../database'; +import { IRocketChat, IUser } from '../../../definitions'; +import sdk from '../services/sdk'; export function subscribeUsersPresence(this: IRocketChat) { const serverVersion = reduxStore.getState().server.version as string; diff --git a/app/lib/rocketchat/methods/helpers.ts b/app/lib/rocketchat/methods/helpers.ts new file mode 100644 index 000000000..a0fcd64cf --- /dev/null +++ b/app/lib/rocketchat/methods/helpers.ts @@ -0,0 +1,176 @@ +// @ts-nocheck - TEMP +import AsyncStorage from '@react-native-community/async-storage'; + +import log from '../../../utils/log'; +import { store as reduxStore } from '../../auxStore'; +import { ANALYTICS_EVENTS_KEY, CRASH_REPORT_KEY } from '../../constants'; +import defaultSettings from '../../../constants/settings'; +import database from '../../database'; +import subscribeRoomsTmp from '../../methods/subscriptions/rooms'; + +export function isGroupChat(room): boolean { + return ((room.uids && room.uids.length > 2) || (room.usernames && room.usernames.length > 2)) ?? false; +} + +export function getRoomAvatar(room) { + if (isGroupChat(room) && room.uids && room.usernames) { + return room.uids.length + room.usernames.join(); + } + return room.prid ? room.fname : room.name; +} + +export function getUidDirectMessage(room) { + const { id: userId } = reduxStore.getState().login.user; + + if (!room) { + return null; + } + + // legacy method + if (!room?.uids && room.rid && room.t === 'd' && userId) { + return room.rid.replace(userId, '').trim(); + } + + if (isGroupChat(room)) { + return null; + } + + const me = room.uids?.find(uid => uid === userId); + const other = room.uids?.filter(uid => uid !== userId); + + return other && other.length ? other[0] : me; +} + +export function getRoomTitle(room) { + const { UI_Use_Real_Name: useRealName, UI_Allow_room_names_with_special_chars: allowSpecialChars } = + reduxStore.getState().settings; + const { username } = reduxStore.getState().login.user; + if (isGroupChat(room) && !(room.name && room.name.length) && room.usernames) { + return room.usernames + .filter(u => u !== username) + .sort((u1, u2) => u1.localeCompare(u2)) + .join(', '); + } + if (allowSpecialChars && room.t !== 'd') { + return room.fname || room.name; + } + return ((room.prid || useRealName) && room.fname) || room.name; +} + +export function getSenderName(sender) { + const { UI_Use_Real_Name: useRealName } = reduxStore.getState().settings; + return useRealName ? sender.name : sender.username; +} + +export function canAutoTranslate() { + try { + const { AutoTranslate_Enabled } = reduxStore.getState().settings; + if (!AutoTranslate_Enabled) { + return false; + } + const autoTranslatePermission = reduxStore.getState().permissions['auto-translate']; + const userRoles = reduxStore.getState().login?.user?.roles ?? []; + return autoTranslatePermission?.some(role => userRoles.includes(role)) ?? false; + } catch (e) { + log(e); + return false; + } +} + +export function isRead(item) { + let isUnread = item.archived !== true && item.open === true; // item is not archived and not opened + isUnread = isUnread && (item.unread > 0 || item.alert === true); // either its unread count > 0 or its alert + return !isUnread; +} + +export function hasRole(role): boolean { + const shareUser = reduxStore.getState().share.user; + const loginUser = reduxStore.getState().login.user; + const userRoles = shareUser?.roles || loginUser?.roles || []; + return userRoles.indexOf(role) > -1; +} + +// AsyncStorage +export async function getAllowCrashReport() { + const allowCrashReport = await AsyncStorage.getItem(CRASH_REPORT_KEY); + if (allowCrashReport === null) { + return true; + } + return JSON.parse(allowCrashReport); +} + +export async function getAllowAnalyticsEvents() { + const allowAnalyticsEvents = await AsyncStorage.getItem(ANALYTICS_EVENTS_KEY); + if (allowAnalyticsEvents === null) { + return true; + } + return JSON.parse(allowAnalyticsEvents); +} + +// TODO: remove this +export async function subscribeRooms(this: any) { + if (!this.roomsSub) { + try { + // TODO: We need to change this naming. Maybe move this logic to the SDK? + this.roomsSub = await subscribeRoomsTmp.call(this); + } catch (e) { + log(e); + } + } +} + +// TODO: remove this +export function unsubscribeRooms(this: any) { + if (this.roomsSub) { + this.roomsSub.stop(); + this.roomsSub = null; + } +} + +export function parseSettings(settings) { + return settings.reduce((ret, item) => { + ret[item._id] = defaultSettings[item._id] && item[defaultSettings[item._id].type]; + if (item._id === 'Hide_System_Messages') { + ret[item._id] = ret[item._id].reduce( + (array, value) => [...array, ...(value === 'mute_unmute' ? ['user-muted', 'user-unmuted'] : [value])], + [] + ); + } + return ret; + }); +} + +export function _prepareSettings(settings) { + return settings.map(setting => { + setting[defaultSettings[setting._id].type] = setting.value; + return setting; + }); +} + +export async function hasPermission(permissions, rid?: any) { + let roomRoles = []; + if (rid) { + const db = database.active; + const subsCollection = db.get('subscriptions'); + try { + // get the room from database + const room = await subsCollection.find(rid); + // get room roles + roomRoles = room.roles || []; + } catch (error) { + console.log('hasPermission -> Room not found'); + return permissions.map(() => false); + } + } + + try { + const shareUser = reduxStore.getState().share.user; + const loginUser = reduxStore.getState().login.user; + // get user roles on the server from redux + const userRoles = shareUser?.roles || loginUser?.roles || []; + const mergedRoles = [...new Set([...roomRoles, ...userRoles])]; + return permissions.map(permission => permission?.some(r => mergedRoles.includes(r) ?? false)); + } catch (e) { + log(e); + } +} diff --git a/app/lib/rocketchat/methods/isGroupChat.ts b/app/lib/rocketchat/methods/isGroupChat.ts deleted file mode 100644 index 558091b60..000000000 --- a/app/lib/rocketchat/methods/isGroupChat.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ISubscription, TSubscriptionModel } from '../../../definitions'; - -export default function isGroupChat(room: ISubscription | TSubscriptionModel): boolean { - return ((room.uids && room.uids.length > 2) || (room.usernames && room.usernames.length > 2)) ?? false; -} diff --git a/app/lib/methods/logout.ts b/app/lib/rocketchat/methods/logout.ts similarity index 83% rename from app/lib/methods/logout.ts rename to app/lib/rocketchat/methods/logout.ts index 0086fe102..a9bad1df1 100644 --- a/app/lib/methods/logout.ts +++ b/app/lib/rocketchat/methods/logout.ts @@ -2,17 +2,17 @@ import * as FileSystem from 'expo-file-system'; import { Rocketchat as RocketchatClient } from '@rocket.chat/sdk'; import Model from '@nozbe/watermelondb/Model'; -import { getDeviceToken } from '../../notifications/push'; -import { extractHostname } from '../../utils/server'; -import { BASIC_AUTH_KEY } from '../../utils/fetch'; -import database, { getDatabase } from '../database'; -import RocketChat from '../rocketchat'; -import { useSsl } from '../../utils/url'; -import log from '../../utils/log'; -import { E2E_PRIVATE_KEY, E2E_PUBLIC_KEY, E2E_RANDOM_PASSWORD_KEY } from '../encryption/constants'; -import UserPreferences from '../userPreferences'; -import { ICertificate, IRocketChat } from '../../definitions'; -import sdk from '../rocketchat/services/sdk'; +import { getDeviceToken } from '../../../notifications/push'; +import { extractHostname } from '../../../utils/server'; +import { BASIC_AUTH_KEY } from '../../../utils/fetch'; +import database, { getDatabase } from '../../database'; +import RocketChat from '..'; +import { useSsl } from '../../../utils/url'; +import log from '../../../utils/log'; +import { E2E_PRIVATE_KEY, E2E_PUBLIC_KEY, E2E_RANDOM_PASSWORD_KEY } from '../../constants'; +import UserPreferences from '../../userPreferences'; +import { ICertificate, IRocketChat } from '../../../definitions'; +import sdk from '../services/sdk'; function removeServerKeys({ server, userId }: { server: string; userId?: string | null }) { UserPreferences.removeItem(`${RocketChat.TOKEN_KEY}-${server}`); @@ -98,7 +98,7 @@ export async function removeServer({ server }: { server: string }): Promise { +export async function logout(this: IRocketChat, { server }: { server: string }): Promise { if (this.roomsSub) { this.roomsSub.stop(); this.roomsSub = null; diff --git a/app/lib/rocketchat/methods/search.ts b/app/lib/rocketchat/methods/search.ts index 136dce0b6..f094077dd 100644 --- a/app/lib/rocketchat/methods/search.ts +++ b/app/lib/rocketchat/methods/search.ts @@ -3,8 +3,8 @@ import { Q } from '@nozbe/watermelondb'; import { sanitizeLikeString } from '../../database/utils'; import database from '../../database/index'; import { spotlight } from '../services/restApi'; -import isGroupChat from './isGroupChat'; import { ISearch, ISearchLocal, SubscriptionType } from '../../../definitions'; +import { isGroupChat } from './helpers'; let debounce: null | ((reason: string) => void) = null; diff --git a/app/lib/methods/sendFileMessage.ts b/app/lib/rocketchat/methods/sendFileMessage.ts similarity index 93% rename from app/lib/methods/sendFileMessage.ts rename to app/lib/rocketchat/methods/sendFileMessage.ts index e282f5555..2d5a012e2 100644 --- a/app/lib/methods/sendFileMessage.ts +++ b/app/lib/rocketchat/methods/sendFileMessage.ts @@ -3,11 +3,11 @@ import { settings as RocketChatSettings } from '@rocket.chat/sdk'; import { FetchBlobResponse, StatefulPromise } from 'rn-fetch-blob'; import isEmpty from 'lodash/isEmpty'; -import FileUpload from '../../utils/fileUpload'; -import database from '../database'; -import log from '../../utils/log'; -import { IUpload, IUser, TUploadModel } from '../../definitions'; -import { IFileUpload } from '../../utils/fileUpload/interfaces'; +import FileUpload from '../../../utils/fileUpload'; +import database from '../../database'; +import log from '../../../utils/log'; +import { IUpload, IUser, TUploadModel } from '../../../definitions'; +import { IFileUpload } from '../../../utils/fileUpload/interfaces'; const uploadQueue: { [index: string]: StatefulPromise } = {}; diff --git a/app/lib/rocketchat/methods/setUser.ts b/app/lib/rocketchat/methods/setUser.ts new file mode 100644 index 000000000..f67c9ab2f --- /dev/null +++ b/app/lib/rocketchat/methods/setUser.ts @@ -0,0 +1,40 @@ +import { InteractionManager } from 'react-native'; + +import { setActiveUsers } from '../../../actions/activeUsers'; +import { setUser } from '../../../actions/login'; +import { store as reduxStore } from '../../auxStore'; +import { compareServerVersion } from '../../utils'; + +// TODO +export function _setUser(this: any, ddpMessage: { fields: any; id: any; cleared: any }) { + this.activeUsers = this.activeUsers || {}; + const { user } = reduxStore.getState().login; + + if (ddpMessage.fields && user && user.id === ddpMessage.id) { + reduxStore.dispatch(setUser(ddpMessage.fields)); + } + + if (ddpMessage.cleared && user && user.id === ddpMessage.id) { + reduxStore.dispatch(setUser({ status: 'offline' })); + } + + const serverVersion = reduxStore.getState().server.version; + if (compareServerVersion(serverVersion, 'lowerThan', '4.1.0')) { + if (!this._setUserTimer) { + this._setUserTimer = setTimeout(() => { + const activeUsersBatch = this.activeUsers; + InteractionManager.runAfterInteractions(() => { + reduxStore.dispatch(setActiveUsers(activeUsersBatch)); + }); + this._setUserTimer = null; + return (this.activeUsers = {}); + }, 10000); + } + } + + if (!ddpMessage.fields) { + this.activeUsers[ddpMessage.id] = { status: 'offline' }; + } else if (ddpMessage.fields.status) { + this.activeUsers[ddpMessage.id] = { status: ddpMessage.fields.status }; + } +} diff --git a/app/lib/rocketchat/methods/triggerActions.ts b/app/lib/rocketchat/methods/triggerActions.ts new file mode 100644 index 000000000..9816f386d --- /dev/null +++ b/app/lib/rocketchat/methods/triggerActions.ts @@ -0,0 +1,25 @@ +import { + ActionTypes, + ITriggerBlockAction, + ITriggerCancel, + ITriggerSubmitView, + ModalActions +} from '../../../containers/UIKit/interfaces'; +import { TRocketChat } from '../../../definitions'; +import { triggerAction } from '../../methods/actions'; +import Navigation from '../../Navigation'; + +export function triggerBlockAction(this: TRocketChat, options: ITriggerBlockAction) { + return triggerAction.call(this, { type: ActionTypes.ACTION, ...options }); +} + +export async function triggerSubmitView(this: TRocketChat, { viewId, ...options }: ITriggerSubmitView) { + const result = await triggerAction.call(this, { type: ActionTypes.SUBMIT, viewId, ...options }); + if (!result || ModalActions.CLOSE === result) { + Navigation.back(); + } +} + +export function triggerCancel(this: TRocketChat, { view, ...options }: ITriggerCancel) { + return triggerAction.call(this, { type: ActionTypes.CLOSED, view, ...options }); +} diff --git a/app/lib/rocketchat/methods/userPreferencesMethods.ts b/app/lib/rocketchat/methods/userPreferencesMethods.ts new file mode 100644 index 000000000..fd8ae9741 --- /dev/null +++ b/app/lib/rocketchat/methods/userPreferencesMethods.ts @@ -0,0 +1,14 @@ +import { IPreferences } from '../../../definitions'; +import userPreferences from '../../userPreferences'; + +const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY'; + +export function getSortPreferences() { + return userPreferences.getMap(SORT_PREFS_KEY); +} + +export function saveSortPreference(param: Partial) { + let prefs = getSortPreferences(); + prefs = { ...prefs, ...param } as object; + return userPreferences.setMap(SORT_PREFS_KEY, prefs); +} diff --git a/app/lib/rocketchat/rocketchat.js b/app/lib/rocketchat/rocketchat.js deleted file mode 100644 index cae66d8cf..000000000 --- a/app/lib/rocketchat/rocketchat.js +++ /dev/null @@ -1,373 +0,0 @@ -import { Q } from '@nozbe/watermelondb'; -import AsyncStorage from '@react-native-community/async-storage'; -import { InteractionManager } from 'react-native'; -import { setActiveUsers } from '../../actions/activeUsers'; -import { setUser } from '../../actions/login'; -import defaultSettings from '../../constants/settings'; -import { getDeviceToken } from '../../notifications/push'; -import log from '../../utils/log'; -import database from '../database'; -import triggerBlockAction, { triggerCancel, triggerSubmitView } from '../methods/actions'; -import callJitsi, { callJitsiWithoutServer } from '../methods/callJitsi'; -import canOpenRoom from '../methods/canOpenRoom'; -import { - getEnterpriseModules, - hasLicense, - isOmnichannelModuleAvailable, - setEnterpriseModules -} from '../methods/enterpriseModules'; -import { getCustomEmojis, setCustomEmojis } from '../methods/getCustomEmojis'; -import { getPermissions, setPermissions } from '../methods/getPermissions'; -import { getRoles, setRoles } from '../methods/getRoles'; -import getRooms from '../methods/getRooms'; -import getSettings, { getLoginSettings, setSettings, subscribeSettings } from '../methods/getSettings'; -import getSlashCommands from '../methods/getSlashCommands'; -import loadMessagesForRoom from '../methods/loadMessagesForRoom'; -import loadMissedMessages from '../methods/loadMissedMessages'; -import loadNextMessages from '../methods/loadNextMessages'; -import loadSurroundingMessages from '../methods/loadSurroundingMessages'; -import loadThreadMessages from '../methods/loadThreadMessages'; -import logout, { removeServer } from '../methods/logout'; -import readMessages from '../methods/readMessages'; -import { cancelUpload, isUploadActive, sendFileMessage } from '../methods/sendFileMessage'; -import sendMessage, { resendMessage } from '../methods/sendMessage'; -import subscribeRooms from '../methods/subscriptions/rooms'; -import UserPreferences from '../userPreferences'; -import { compareServerVersion } from '../utils'; -import { getUserPresence, subscribeUsersPresence } from '../methods/getUsersPresence'; -import { store as reduxStore } from '../auxStore'; -// Methods -import clearCache from './methods/clearCache'; -import getPermalinkMessage from './methods/getPermalinkMessage'; -import getRoom from './methods/getRoom'; -import isGroupChat from './methods/isGroupChat'; -import roomTypeToApiType from './methods/roomTypeToApiType'; -import getUserInfo from './services/getUserInfo'; -import * as search from './methods/search'; -// Services -import sdk from './services/sdk'; -import toggleFavorite from './services/toggleFavorite'; -import { - login, - loginTOTP, - loginWithPassword, - loginOAuthOrSso, - getLoginServices, - determineAuthType, - disconnect, - checkAndReopen, - abort, - getServerInfo, - getWebsocketInfo, - stopListener, - connect -} from './services/connect'; -import { shareExtensionInit, closeShareExtension } from './services/shareExtension'; -import * as restApis from './services/restApi'; - -const TOKEN_KEY = 'reactnativemeteor_usertoken'; -const CURRENT_SERVER = 'currentServer'; -const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY'; -const CERTIFICATE_KEY = 'RC_CERTIFICATE_KEY'; -export const THEME_PREFERENCES_KEY = 'RC_THEME_PREFERENCES_KEY'; -export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY'; -export const ANALYTICS_EVENTS_KEY = 'RC_ANALYTICS_EVENTS_KEY'; -export const MIN_ROCKETCHAT_VERSION = '0.70.0'; - -const RocketChat = { - TOKEN_KEY, - CURRENT_SERVER, - CERTIFICATE_KEY, - ...restApis, - ...search, - callJitsi, - callJitsiWithoutServer, - async subscribeRooms() { - if (!this.roomsSub) { - try { - this.roomsSub = await subscribeRooms.call(this); - } catch (e) { - log(e); - } - } - }, - unsubscribeRooms() { - if (this.roomsSub) { - this.roomsSub.stop(); - this.roomsSub = null; - } - }, - canOpenRoom, - getWebsocketInfo, - getServerInfo, - stopListener, - // Abort all requests and create a new AbortController - abort, - checkAndReopen, - disconnect, - connect, - shareExtensionInit, - closeShareExtension, - loginTOTP, - loginWithPassword, - loginOAuthOrSso, - login, - logout, - logoutOtherLocations() { - const { id: userId } = reduxStore.getState().login.user; - return this.sdk.post('users.removeOtherTokens', { userId }); - }, - removeServer, - clearCache, - loadMissedMessages, - loadMessagesForRoom, - loadSurroundingMessages, - loadNextMessages, - loadThreadMessages, - sendMessage, - getRooms, - readMessages, - resendMessage, - triggerBlockAction, - triggerSubmitView, - triggerCancel, - sendFileMessage, - cancelUpload, - isUploadActive, - getSettings, - getLoginSettings, - setSettings, - subscribeSettings, - getPermissions, - setPermissions, - getCustomEmojis, - setCustomEmojis, - getEnterpriseModules, - setEnterpriseModules, - hasLicense, - isOmnichannelModuleAvailable, - getSlashCommands, - getRoles, - setRoles, - parseSettings: settings => - settings.reduce((ret, item) => { - ret[item._id] = defaultSettings[item._id] && item[defaultSettings[item._id].type]; - if (item._id === 'Hide_System_Messages') { - ret[item._id] = ret[item._id].reduce( - (array, value) => [...array, ...(value === 'mute_unmute' ? ['user-muted', 'user-unmuted'] : [value])], - [] - ); - } - return ret; - }, {}), - _prepareSettings(settings) { - return settings.map(setting => { - setting[defaultSettings[setting._id].type] = setting.value; - return setting; - }); - }, - getRoom, - getPermalinkMessage, - getPermalinkChannel(channel) { - const { server } = reduxStore.getState().server; - const roomType = { - p: 'group', - c: 'channel', - d: 'direct' - }[channel.t]; - return `${server}/${roomType}/${channel.name}`; - }, - subscribe(...args) { - return sdk.subscribe(...args); - }, - subscribeRaw(...args) { - return sdk.subscribeRaw(...args); - }, - subscribeRoom(...args) { - return sdk.subscribeRoom(...args); - }, - unsubscribe(subscription) { - return sdk.unsubscribe(subscription); - }, - onStreamData(...args) { - return sdk.onStreamData(...args); - }, - toggleFavorite, - methodCallWrapper(method, ...params) { - return sdk.methodCallWrapper(method, ...params); - }, - getUserInfo, - getUidDirectMessage(room) { - const { id: userId } = reduxStore.getState().login.user; - - if (!room) { - return false; - } - - // legacy method - if (!room?.uids && room.rid && room.t === 'd') { - return room.rid.replace(userId, '').trim(); - } - - if (RocketChat.isGroupChat(room)) { - return false; - } - - const me = room.uids?.find(uid => uid === userId); - const other = room.uids?.filter(uid => uid !== userId); - - return other && other.length ? other[0] : me; - }, - - isRead(item) { - let isUnread = item.archived !== true && item.open === true; // item is not archived and not opened - isUnread = isUnread && (item.unread > 0 || item.alert === true); // either its unread count > 0 or its alert - return !isUnread; - }, - isGroupChat, - post(...args) { - return sdk.post(...args); - }, - methodCall(...args) { - return sdk.methodCall(...args); - }, - hasRole(role) { - const shareUser = reduxStore.getState().share.user; - const loginUser = reduxStore.getState().login.user; - // get user roles on the server from redux - const userRoles = shareUser?.roles || loginUser?.roles || []; - - return userRoles.indexOf(r => r === role) > -1; - }, - /** - * Permissions: array of permissions' roles from redux. Example: [['owner', 'admin'], ['leader']] - * Returns an array of boolean for each permission from permissions arg - */ - async hasPermission(permissions, rid) { - let roomRoles = []; - if (rid) { - const db = database.active; - const subsCollection = db.get('subscriptions'); - try { - // get the room from database - const room = await subsCollection.find(rid); - // get room roles - roomRoles = room.roles || []; - } catch (error) { - console.log('hasPermission -> Room not found'); - return permissions.map(() => false); - } - } - - try { - const shareUser = reduxStore.getState().share.user; - const loginUser = reduxStore.getState().login.user; - // get user roles on the server from redux - const userRoles = shareUser?.roles || loginUser?.roles || []; - const mergedRoles = [...new Set([...roomRoles, ...userRoles])]; - return permissions.map(permission => permission?.some(r => mergedRoles.includes(r) ?? false)); - } catch (e) { - log(e); - } - }, - async getAllowCrashReport() { - const allowCrashReport = await AsyncStorage.getItem(CRASH_REPORT_KEY); - if (allowCrashReport === null) { - return true; - } - return JSON.parse(allowCrashReport); - }, - async getAllowAnalyticsEvents() { - const allowAnalyticsEvents = await AsyncStorage.getItem(ANALYTICS_EVENTS_KEY); - if (allowAnalyticsEvents === null) { - return true; - } - return JSON.parse(allowAnalyticsEvents); - }, - getSortPreferences() { - return UserPreferences.getMap(SORT_PREFS_KEY); - }, - saveSortPreference(param) { - let prefs = RocketChat.getSortPreferences(); - prefs = { ...prefs, ...param }; - return UserPreferences.setMap(SORT_PREFS_KEY, prefs); - }, - getLoginServices, - determineAuthType, - roomTypeToApiType, - _setUser(ddpMessage) { - this.activeUsers = this.activeUsers || {}; - const { user } = reduxStore.getState().login; - - if (ddpMessage.fields && user && user.id === ddpMessage.id) { - reduxStore.dispatch(setUser(ddpMessage.fields)); - } - - if (ddpMessage.cleared && user && user.id === ddpMessage.id) { - reduxStore.dispatch(setUser({ status: { status: 'offline' } })); - } - - const serverVersion = reduxStore.getState().server.version; - if (compareServerVersion(serverVersion, 'lowerThan', '4.1.0')) { - if (!this._setUserTimer) { - this._setUserTimer = setTimeout(() => { - const activeUsersBatch = this.activeUsers; - InteractionManager.runAfterInteractions(() => { - reduxStore.dispatch(setActiveUsers(activeUsersBatch)); - }); - this._setUserTimer = null; - return (this.activeUsers = {}); - }, 10000); - } - } - - if (!ddpMessage.fields) { - this.activeUsers[ddpMessage.id] = { status: 'offline' }; - } else if (ddpMessage.fields.status) { - this.activeUsers[ddpMessage.id] = { status: ddpMessage.fields.status }; - } - }, - getUserPresence, - subscribeUsersPresence, - canAutoTranslate() { - try { - const { AutoTranslate_Enabled } = reduxStore.getState().settings; - if (!AutoTranslate_Enabled) { - return false; - } - const autoTranslatePermission = reduxStore.getState().permissions['auto-translate']; - const userRoles = reduxStore.getState().login?.user?.roles ?? []; - return autoTranslatePermission?.some(role => userRoles.includes(role)) ?? false; - } catch (e) { - log(e); - return false; - } - }, - getSenderName(sender) { - const { UI_Use_Real_Name: useRealName } = reduxStore.getState().settings; - return useRealName ? sender.name : sender.username; - }, - getRoomTitle(room) { - const { UI_Use_Real_Name: useRealName, UI_Allow_room_names_with_special_chars: allowSpecialChars } = - reduxStore.getState().settings; - const { username } = reduxStore.getState().login.user; - if (RocketChat.isGroupChat(room) && !(room.name && room.name.length)) { - return room.usernames - .filter(u => u !== username) - .sort((u1, u2) => u1.localeCompare(u2)) - .join(', '); - } - if (allowSpecialChars && room.t !== 'd') { - return room.fname || room.name; - } - return ((room.prid || useRealName) && room.fname) || room.name; - }, - getRoomAvatar(room) { - if (RocketChat.isGroupChat(room)) { - return room.uids?.length + room.usernames?.join(); - } - return room.prid ? room.fname : room.name; - } -}; - -export default RocketChat; diff --git a/app/lib/rocketchat/services/connect.ts b/app/lib/rocketchat/services/connect.ts index acc10eb49..ed7ca610a 100644 --- a/app/lib/rocketchat/services/connect.ts +++ b/app/lib/rocketchat/services/connect.ts @@ -5,7 +5,7 @@ import { InteractionManager } from 'react-native'; import { Q } from '@nozbe/watermelondb'; import log from '../../../utils/log'; -import { onRolesChanged } from '../../methods/getRoles'; +import { onRolesChanged } from '../methods/getRoles'; import { setActiveUsers } from '../../../actions/activeUsers'; import protectedFunction from '../../methods/helpers/protectedFunction'; import database from '../../database'; @@ -16,7 +16,7 @@ import { store } from '../../auxStore'; import { loginRequest, setLoginServices, setUser } from '../../../actions/login'; import sdk from './sdk'; import I18n from '../../../i18n'; -import RocketChat, { MIN_ROCKETCHAT_VERSION } from '../rocketchat'; +import RocketChat from '..'; import { ICredentials, ILoggedUser, IRocketChat, STATUSES } from '../../../definitions'; import { isIOS } from '../../../utils/deviceInfo'; import { connectRequest, connectSuccess, disconnect as disconnectAction } from '../../../actions/connect'; @@ -24,6 +24,7 @@ import { updatePermission } from '../../../actions/permissions'; import EventEmitter from '../../../utils/events'; import { updateSettings } from '../../../actions/settings'; import defaultSettings from '../../../constants/settings'; +import { MIN_ROCKETCHAT_VERSION } from '../../constants'; interface IServices { [index: string]: string | boolean; diff --git a/app/lib/rocketchat/services/getUserInfo.ts b/app/lib/rocketchat/services/getUserInfo.ts deleted file mode 100644 index 1da955456..000000000 --- a/app/lib/rocketchat/services/getUserInfo.ts +++ /dev/null @@ -1,6 +0,0 @@ -import sdk from './sdk'; - -export default function getUserInfo(userId: string) { - // RC 0.48.0 - return sdk.get('users.info', { userId }); -} diff --git a/app/lib/rocketchat/services/restApi.ts b/app/lib/rocketchat/services/restApi.ts index 0d7f766bc..3039f400c 100644 --- a/app/lib/rocketchat/services/restApi.ts +++ b/app/lib/rocketchat/services/restApi.ts @@ -17,7 +17,7 @@ import { store as reduxStore } from '../../auxStore'; import { getDeviceToken } from '../../../notifications/push'; import { getBundleId, isIOS } from '../../../utils/deviceInfo'; import { compareServerVersion } from '../../utils'; -import roomTypeToApiType, { RoomTypes } from '../methods/roomTypeToApiType'; +import roomTypeToApiType, { RoomTypes } from '../../methods/roomTypeToApiType'; import sdk from './sdk'; export const createChannel = ({ @@ -901,3 +901,15 @@ export const e2eFetchMyKeys = async () => { } return result; }; + +export const logoutOtherLocations = () => { + const { id } = reduxStore.getState().login.user; + return sdk.post('users.removeOtherTokens', { userId: id as string }); +}; + +export function getUserInfo(userId: string) { + // RC 0.48.0 + return sdk.get('users.info', { userId }); +} + +export const toggleFavorite = (roomId: string, favorite: boolean) => sdk.post('rooms.favorite', { roomId, favorite }); diff --git a/app/lib/rocketchat/services/shareExtension.ts b/app/lib/rocketchat/services/shareExtension.ts index ad83eb989..65a7f76dd 100644 --- a/app/lib/rocketchat/services/shareExtension.ts +++ b/app/lib/rocketchat/services/shareExtension.ts @@ -6,7 +6,7 @@ import log from '../../../utils/log'; import { IShareServer, IShareUser } from '../../../reducers/share'; import UserPreferences from '../../userPreferences'; import database from '../../database'; -import RocketChat from '../rocketchat'; +import RocketChat from '..'; import { encryptionInit } from '../../../actions/encryption'; import { store } from '../../auxStore'; import sdk from './sdk'; diff --git a/app/lib/rocketchat/services/toggleFavorite.ts b/app/lib/rocketchat/services/toggleFavorite.ts deleted file mode 100644 index ed3049634..000000000 --- a/app/lib/rocketchat/services/toggleFavorite.ts +++ /dev/null @@ -1,6 +0,0 @@ -import sdk from './sdk'; - -// RC 0.64.0 -const toggleFavorite = (roomId: string, favorite: boolean) => sdk.post('rooms.favorite', { roomId, favorite }); - -export default toggleFavorite; diff --git a/app/presentation/RoomItem/LastMessage.tsx b/app/presentation/RoomItem/LastMessage.tsx index b21f0a6f3..b2715bb42 100644 --- a/app/presentation/RoomItem/LastMessage.tsx +++ b/app/presentation/RoomItem/LastMessage.tsx @@ -5,7 +5,7 @@ import I18n from '../../i18n'; import styles from './styles'; import { MarkdownPreview } from '../../containers/markdown'; import { themes } from '../../constants/colors'; -import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../../lib/encryption/constants'; +import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../../lib/constants'; interface ILastMessage { theme: string; diff --git a/app/reducers/permissions.ts b/app/reducers/permissions.ts index d2887a555..be97f7936 100644 --- a/app/reducers/permissions.ts +++ b/app/reducers/permissions.ts @@ -1,6 +1,6 @@ import { PERMISSIONS } from '../actions/actionsTypes'; import { TActionPermissions } from '../actions/permissions'; -import { SUPPORTED_PERMISSIONS } from '../lib/methods/getPermissions'; +import { SUPPORTED_PERMISSIONS } from '../lib/rocketchat/methods/getPermissions'; export type TSupportedPermissions = typeof SUPPORTED_PERMISSIONS[number]; diff --git a/app/sagas/encryption.js b/app/sagas/encryption.js index e99f8b72b..6f6f6186e 100644 --- a/app/sagas/encryption.js +++ b/app/sagas/encryption.js @@ -5,7 +5,7 @@ import { ENCRYPTION } from '../actions/actionsTypes'; import { encryptionSet } from '../actions/encryption'; import { Encryption } from '../lib/encryption'; import Navigation from '../lib/Navigation'; -import { E2E_BANNER_TYPE, E2E_PRIVATE_KEY, E2E_PUBLIC_KEY, E2E_RANDOM_PASSWORD_KEY } from '../lib/encryption/constants'; +import { E2E_BANNER_TYPE, E2E_PRIVATE_KEY, E2E_PUBLIC_KEY, E2E_RANDOM_PASSWORD_KEY } from '../lib/constants'; import database from '../lib/database'; import RocketChat from '../lib/rocketchat'; import UserPreferences from '../lib/userPreferences'; diff --git a/app/sagas/login.js b/app/sagas/login.js index adde0dad3..41fe6c5ca 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -20,6 +20,7 @@ import UserPreferences from '../lib/userPreferences'; import { inquiryRequest, inquiryReset } from '../ee/omnichannel/actions/inquiry'; import { isOmnichannelStatusAvailable } from '../ee/omnichannel/lib'; import { RootEnum } from '../definitions'; +import sdk from '../lib/rocketchat/services/sdk'; const getServer = state => state.server.server; const loginWithPasswordCall = args => RocketChat.loginWithPassword(args); @@ -86,7 +87,7 @@ const fetchCustomEmojis = function* fetchCustomEmojis() { }; const fetchRoles = function* fetchRoles() { - RocketChat.subscribe('stream-roles', 'roles'); + sdk.subscribe('stream-roles', 'roles'); yield RocketChat.getRoles(); }; diff --git a/app/utils/theme.ts b/app/utils/theme.ts index eab93830d..08079ca22 100644 --- a/app/utils/theme.ts +++ b/app/utils/theme.ts @@ -6,9 +6,10 @@ import { IThemePreference, TThemeMode } from '../definitions/ITheme'; import { themes } from '../constants/colors'; import { isAndroid } from './deviceInfo'; import UserPreferences from '../lib/userPreferences'; -import { THEME_PREFERENCES_KEY } from '../lib/rocketchat'; +import { THEME_PREFERENCES_KEY } from '../lib/constants'; import { TSupportedThemes } from '../theme'; + let themeListener: { remove: () => void } | null; export const initialTheme = (): IThemePreference => { diff --git a/app/views/CreateDiscussionView/index.tsx b/app/views/CreateDiscussionView/index.tsx index e57095b80..97d263680 100644 --- a/app/views/CreateDiscussionView/index.tsx +++ b/app/views/CreateDiscussionView/index.tsx @@ -20,7 +20,7 @@ import { showErrorAlert } from '../../utils/info'; import SafeAreaView from '../../containers/SafeAreaView'; import { goRoom } from '../../utils/goRoom'; import { events, logEvent } from '../../utils/log'; -import { E2E_ROOM_TYPES } from '../../lib/encryption/constants'; +import { E2E_ROOM_TYPES } from '../../lib/constants'; import styles from './styles'; import SelectUsers from './SelectUsers'; import SelectChannel from './SelectChannel'; diff --git a/app/views/E2ESaveYourPasswordView.tsx b/app/views/E2ESaveYourPasswordView.tsx index ebd75a59f..9bd9a3fbf 100644 --- a/app/views/E2ESaveYourPasswordView.tsx +++ b/app/views/E2ESaveYourPasswordView.tsx @@ -12,7 +12,7 @@ import StatusBar from '../containers/StatusBar'; import { LISTENER } from '../containers/Toast'; import { IApplicationState, IBaseScreen } from '../definitions'; import I18n from '../i18n'; -import { E2E_RANDOM_PASSWORD_KEY } from '../lib/encryption/constants'; +import { E2E_RANDOM_PASSWORD_KEY } from '../lib/constants'; import UserPreferences from '../lib/userPreferences'; import { E2ESaveYourPasswordStackParamList } from '../stacks/types'; import { withTheme } from '../theme'; diff --git a/app/views/RoomActionsView/index.tsx b/app/views/RoomActionsView/index.tsx index ed56fc72f..7cf1c17bc 100644 --- a/app/views/RoomActionsView/index.tsx +++ b/app/views/RoomActionsView/index.tsx @@ -21,7 +21,7 @@ import { IApplicationState, IBaseScreen, IRoom, ISubscription, IUser, TSubscript import { withDimensions } from '../../dimensions'; import I18n from '../../i18n'; import database from '../../lib/database'; -import { E2E_ROOM_TYPES } from '../../lib/encryption/constants'; +import { E2E_ROOM_TYPES } from '../../lib/constants'; import protectedFunction from '../../lib/methods/helpers/protectedFunction'; import RocketChat from '../../lib/rocketchat'; import { compareServerVersion } from '../../lib/utils'; diff --git a/app/views/RoomMembersView/index.tsx b/app/views/RoomMembersView/index.tsx index 43395d912..866924cbe 100644 --- a/app/views/RoomMembersView/index.tsx +++ b/app/views/RoomMembersView/index.tsx @@ -28,7 +28,7 @@ import { goRoom, TGoRoomItem } from '../../utils/goRoom'; import { showConfirmationAlert, showErrorAlert } from '../../utils/info'; import log from '../../utils/log'; import scrollPersistTaps from '../../utils/scrollPersistTaps'; -import { RoomTypes } from '../../lib/rocketchat/methods/roomTypeToApiType'; +import { RoomTypes } from '../../lib/methods/roomTypeToApiType'; import styles from './styles'; const PAGE_SIZE = 25; diff --git a/app/views/RoomView/index.tsx b/app/views/RoomView/index.tsx index c6dc8d133..491e7f780 100644 --- a/app/views/RoomView/index.tsx +++ b/app/views/RoomView/index.tsx @@ -48,7 +48,7 @@ import Navigation from '../../lib/Navigation'; import SafeAreaView from '../../containers/SafeAreaView'; import { withDimensions } from '../../dimensions'; import { getHeaderTitlePosition } from '../../containers/Header'; -import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../../lib/encryption/constants'; +import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../../lib/constants'; import { takeInquiry } from '../../ee/omnichannel/lib'; import Loading from '../../containers/Loading'; import { goRoom, TGoRoomItem } from '../../utils/goRoom'; diff --git a/app/views/RoomsListView/ListHeader/index.tsx b/app/views/RoomsListView/ListHeader/index.tsx index ad9e00eb5..1dbe9eb3b 100644 --- a/app/views/RoomsListView/ListHeader/index.tsx +++ b/app/views/RoomsListView/ListHeader/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useTheme } from '../../../theme'; import * as List from '../../../containers/List'; -import { E2E_BANNER_TYPE } from '../../../lib/encryption/constants'; +import { E2E_BANNER_TYPE } from '../../../lib/constants'; import { themes } from '../../../constants/colors'; import OmnichannelStatus from '../../../ee/omnichannel/containers/OmnichannelStatus'; import { IUser } from '../../../definitions'; diff --git a/app/views/RoomsListView/index.tsx b/app/views/RoomsListView/index.tsx index 24c6414d1..e2367b06d 100644 --- a/app/views/RoomsListView/index.tsx +++ b/app/views/RoomsListView/index.tsx @@ -43,7 +43,7 @@ import SafeAreaView from '../../containers/SafeAreaView'; import Header, { getHeaderTitlePosition } from '../../containers/Header'; import { withDimensions } from '../../dimensions'; import { showConfirmationAlert, showErrorAlert } from '../../utils/info'; -import { E2E_BANNER_TYPE } from '../../lib/encryption/constants'; +import { E2E_BANNER_TYPE } from '../../lib/constants'; import { getInquiryQueueSelector } from '../../ee/omnichannel/selectors/inquiry'; import { changeLivechatStatus, isOmnichannelStatusAvailable } from '../../ee/omnichannel/lib'; import { IApplicationState, IBaseScreen, ISubscription, IUser, RootEnum, TSubscriptionModel } from '../../definitions'; @@ -53,7 +53,7 @@ import ServerDropdown from './ServerDropdown'; import ListHeader, { TEncryptionBanner } from './ListHeader'; import RoomsListHeaderView from './Header'; import { ChatsStackParamList } from '../../stacks/types'; -import { RoomTypes } from '../../lib/rocketchat/methods/roomTypeToApiType'; +import { RoomTypes } from '../../lib/methods/roomTypeToApiType'; interface IRoomsListViewProps extends IBaseScreen { [key: string]: any; diff --git a/app/views/SecurityPrivacyView.tsx b/app/views/SecurityPrivacyView.tsx index ffd61d31e..529964752 100644 --- a/app/views/SecurityPrivacyView.tsx +++ b/app/views/SecurityPrivacyView.tsx @@ -8,7 +8,6 @@ import { SWITCH_TRACK_COLOR } from '../constants/colors'; import StatusBar from '../containers/StatusBar'; import * as List from '../containers/List'; import I18n from '../i18n'; -import { CRASH_REPORT_KEY, ANALYTICS_EVENTS_KEY } from '../lib/rocketchat'; import { logEvent, events, @@ -19,6 +18,7 @@ import { } from '../utils/log'; import SafeAreaView from '../containers/SafeAreaView'; import { isFDroidBuild } from '../constants/environment'; +import { ANALYTICS_EVENTS_KEY, CRASH_REPORT_KEY } from '../lib/constants'; interface ISecurityPrivacyViewProps { navigation: StackNavigationProp; diff --git a/app/views/ThemeView.tsx b/app/views/ThemeView.tsx index 5bc365d35..512b8b123 100644 --- a/app/views/ThemeView.tsx +++ b/app/views/ThemeView.tsx @@ -6,12 +6,12 @@ import { withTheme } from '../theme'; import { themes } from '../constants/colors'; import StatusBar from '../containers/StatusBar'; import * as List from '../containers/List'; -import { THEME_PREFERENCES_KEY } from '../lib/rocketchat'; import { supportSystemTheme } from '../utils/deviceInfo'; import SafeAreaView from '../containers/SafeAreaView'; import UserPreferences from '../lib/userPreferences'; import { events, logEvent } from '../utils/log'; import { IThemePreference, TThemeMode, TDarkLevel } from '../definitions/ITheme'; +import { THEME_PREFERENCES_KEY } from '../lib/constants'; const THEME_GROUP = 'THEME_GROUP'; const DARK_GROUP = 'DARK_GROUP';