Skip to content
Snippets Groups Projects
rocketchat.js 24.3 KiB
Newer Older
import { AsyncStorage, Platform } from 'react-native';
import { hashPassword } from 'react-native-meteor/lib/utils';
Guilherme Gazzo's avatar
Guilherme Gazzo committed
import foreach from 'lodash/forEach';
import Random from 'react-native-meteor/lib/Random';
import { Answers } from 'react-native-fabric';
import RNFetchBlob from 'react-native-fetch-blob';
import reduxStore from './createStore';
import settingsType from '../constants/settings';
import messagesStatus from '../constants/messagesStatus';
import database from './realm';
Guilherme Gazzo's avatar
Guilherme Gazzo committed
// import * as actions from '../actions';

import { setUser, setLoginServices, removeLoginServices, loginRequest, loginSuccess, loginFailure } from '../actions/login';
import { disconnect, connectSuccess, connectFailure } from '../actions/connect';
import { setActiveUser } from '../actions/activeUsers';
import { starredMessagesReceived, starredMessageUnstarred } from '../actions/starredMessages';
import { pinnedMessagesReceived, pinnedMessageUnpinned } from '../actions/pinnedMessages';
import { mentionedMessagesReceived } from '../actions/mentionedMessages';
import { snippetedMessagesReceived } from '../actions/snippetedMessages';
import { roomFilesReceived } from '../actions/roomFiles';
Guilherme Gazzo's avatar
Guilherme Gazzo committed
import { someoneTyping, roomMessageReceived } from '../actions/room';
import { setRoles } from '../actions/roles';
import Ddp from './ddp';
Guilherme Gazzo's avatar
Guilherme Gazzo committed
import normalizeMessage from './methods/helpers/normalizeMessage';
Guilherme Gazzo's avatar
Guilherme Gazzo committed
import subscribeRooms from './methods/subscriptions/rooms';
import subscribeRoom from './methods/subscriptions/room';
Guilherme Gazzo's avatar
Guilherme Gazzo committed

Guilherme Gazzo's avatar
Guilherme Gazzo committed
import protectedFunction from './methods/helpers/protectedFunction';
import readMessages from './methods/readMessages';
import getSettings from './methods/getSettings';
Guilherme Gazzo's avatar
Guilherme Gazzo committed
import getRooms from './methods/getRooms';
import getPermissions from './methods/getPermissions';
import getCustomEmoji from './methods/getCustomEmojis';
Diego Mello's avatar
Diego Mello committed
import canOpenRoom from './methods/canOpenRoom';
Guilherme Gazzo's avatar
Guilherme Gazzo committed

import _buildMessage from './methods/helpers/buildMessage';
import loadMessagesForRoom from './methods/loadMessagesForRoom';
import loadMissedMessages from './methods/loadMissedMessages';
Guilherme Gazzo's avatar
Guilherme Gazzo committed
import sendMessage, { getMessage, _sendMessageCall } from './methods/sendMessage';

const TOKEN_KEY = 'reactnativemeteor_usertoken';
const call = (method, ...params) => RocketChat.ddp.call(method, ...params); // eslint-disable-line
const returnAnArray = obj => obj || [];
Rodrigo Nascimento's avatar
Rodrigo Nascimento committed
const RocketChat = {
Diego Mello's avatar
Diego Mello committed
	TOKEN_KEY,
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	subscribeRooms,
	subscribeRoom,
Diego Mello's avatar
Diego Mello committed
	canOpenRoom,
	createChannel({ name, users, type }) {
		return call(type ? 'createChannel' : 'createPrivateGroup', name, users, type);
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	async createDirectMessageAndWait(username) {
		const room = await RocketChat.createDirectMessage(username);
		return new Promise((resolve) => {
			const data = database.objects('subscriptions')
				.filtered('rid = $1', room.rid);

			if (data.length) {
				return resolve(data[0]);
			}
			data.addListener(() => {
				if (!data.length) { return; }
				data.removeAllListeners();
				resolve(data[0]);
			});
		});
	},
Rodrigo Nascimento's avatar
Rodrigo Nascimento committed

	async getUserToken() {
		try {
			return await AsyncStorage.getItem(TOKEN_KEY);
		} catch (error) {
			console.warn(`AsyncStorage error: ${ error.message }`);
		}
	},
	async testServer(url) {
		if (/^(https?:\/\/)?(((\w|[0-9-_])+(\.(\w|[0-9-_])+)+)|localhost)(:\d+)?$/.test(url)) {
			const response = await fetch(url, { method: 'HEAD' });
			if (response.status === 200 && response.headers.get('x-instance-id') != null && response.headers.get('x-instance-id').length) {
				return url;
			}
		}
		throw new Error({ error: 'invalid server' });
	},
Diego Mello's avatar
Diego Mello committed
	_setUser(ddpMessage) {
		this.activeUsers = this.activeUsers || {};
Diego Mello's avatar
Diego Mello committed
		const { user } = reduxStore.getState().login;

		const status = (ddpMessage.fields && ddpMessage.fields.status) || 'offline';

Diego Mello's avatar
Diego Mello committed
		if (user && user.id === ddpMessage.id) {
			reduxStore.dispatch(setUser({ status }));
		if (this._setUserTimer) {
			clearTimeout(this._setUserTimer);
			this._setUserTimer = null;
		}

		this._setUserTimer = setTimeout(() => {
			reduxStore.dispatch(setActiveUser(this.activeUsers));
			this._setUserTimer = null;
			return this.activeUsers = {};
Guilherme Gazzo's avatar
Guilherme Gazzo committed
		}, 1000);

		this.activeUsers[ddpMessage.id] = ddpMessage.fields;
Diego Mello's avatar
Diego Mello committed
	},
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	async loginSuccess(user) {
		if (!user) {
			const { user: u } = reduxStore.getState().login;
			user = Object.assign({}, u);
Guilherme Gazzo's avatar
Guilherme Gazzo committed

		// TODO: one api call
		// call /me only one time
		if (!user.username) {
			const me = await this.me({ token: user.token, userId: user.id });
			// eslint-disable-next-line
			user.username = me.username;
		}
		if (user.username) {
			const userInfo = await this.userInfo({ token: user.token, userId: user.id });
			user.username = userInfo.user.username;
			if (userInfo.user.roles) {
				user.roles = userInfo.user.roles;
			}
Guilherme Gazzo's avatar
Guilherme Gazzo committed
		return reduxStore.dispatch(loginSuccess(user));
	},
	connect(url, login) {
		return new Promise((resolve) => {
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			if (this.ddp) {
				this.ddp.disconnect();
				delete this.ddp;
			}
Guilherme Gazzo's avatar
Guilherme Gazzo committed

Guilherme Gazzo's avatar
Guilherme Gazzo committed
			this.ddp = new Ddp(url, login);
			if (login) {
				protectedFunction(() => RocketChat.getRooms());
			}

			this.ddp.on('login', protectedFunction(() => reduxStore.dispatch(loginRequest())));

			this.ddp.on('logginError', protectedFunction(err => reduxStore.dispatch(loginFailure(err))));

			this.ddp.on('users', protectedFunction(ddpMessage => RocketChat._setUser(ddpMessage)));

			this.ddp.on('background', () => this.getRooms().catch(e => console.warn('background getRooms', e)));
Guilherme Gazzo's avatar
Guilherme Gazzo committed

Guilherme Gazzo's avatar
Guilherme Gazzo committed
			this.ddp.on('disconnected', () => console.log('disconnected'));

			this.ddp.on('logged', protectedFunction((user) => {
				this.getRooms().catch(e => console.warn('logged getRooms', e));
				this.loginSuccess(user);
			}));
			this.ddp.once('logged', protectedFunction(({ id }) => { this.subscribeRooms(id); }));

			this.ddp.on('disconnected', protectedFunction(() => {
				reduxStore.dispatch(disconnect());
			}));
			this.ddp.on('stream-room-messages', (ddpMessage) => {
Guilherme Gazzo's avatar
Guilherme Gazzo committed
				const message = _buildMessage(ddpMessage.fields.args[0]);
				requestAnimationFrame(() => reduxStore.dispatch(roomMessageReceived(message)));
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			this.ddp.on('stream-notify-room', protectedFunction((ddpMessage) => {
				const [_rid, ev] = ddpMessage.fields.eventName.split('/');
				if (ev !== 'typing') {
					return;
				}
				return reduxStore.dispatch(someoneTyping({ _rid, username: ddpMessage.fields.args[0], typing: ddpMessage.fields.args[1] }));
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			}));
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			this.ddp.on('stream-notify-user', protectedFunction((ddpMessage) => {
				const [type, data] = ddpMessage.fields.args;
				const [, ev] = ddpMessage.fields.eventName.split('/');
				if (/subscriptions/.test(ev)) {
					if (data.roles) {
						data.roles = data.roles.map(role => ({ value: role }));
					if (data.blocker) {
						data.blocked = true;
					} else {
						data.blocked = false;
					}
Guilherme Gazzo's avatar
Guilherme Gazzo committed
					if (data.mobilePushNotifications === 'nothing') {
						data.notifications = true;
					} else {
						data.notifications = false;
					}
					database.write(() => {
						database.create('subscriptions', data, true);
				if (/rooms/.test(ev) && type === 'updated') {
					const sub = database.objects('subscriptions').filtered('rid == $0', data._id)[0];
					database.write(() => {
						sub.roomUpdatedAt = data._updatedAt;
						sub.lastMessage = normalizeMessage(data.lastMessage);
Diego Mello's avatar
Diego Mello committed
						sub.ro = data.ro;
						sub.description = data.description;
						sub.topic = data.topic;
						sub.announcement = data.announcement;
						sub.reactWhenReadOnly = data.reactWhenReadOnly;
						sub.archived = data.archived;
						sub.joinCodeRequired = data.joinCodeRequired;
Guilherme Gazzo's avatar
Guilherme Gazzo committed
						if (data.muted) {
							sub.muted = data.muted.map(m => ({ value: m }));
						}
Guilherme Gazzo's avatar
Guilherme Gazzo committed
				if (/message/.test(ev)) {
					const [args] = ddpMessage.fields.args;
					const _id = Random.id();
					const message = {
						_id,
						rid: args.rid,
						msg: args.msg,
						ts: new Date(),
						_updatedAt: new Date(),
						status: messagesStatus.SENT,
						u: {
							_id,
							username: 'rocket.cat'
						}
					};
					requestAnimationFrame(() => database.write(() => {
						database.create('messages', message, true);
					}));
				}
			}));
Diego Mello's avatar
Diego Mello committed

Guilherme Gazzo's avatar
Guilherme Gazzo committed
			this.ddp.on('rocketchat_starred_message', protectedFunction((ddpMessage) => {
Diego Mello's avatar
Diego Mello committed
				if (ddpMessage.msg === 'added') {
					this.starredMessages = this.starredMessages || [];

					if (this.starredMessagesTimer) {
						clearTimeout(this.starredMessagesTimer);
						this.starredMessagesTimer = null;
					}

Guilherme Gazzo's avatar
Guilherme Gazzo committed
					this.starredMessagesTimer = setTimeout(protectedFunction(() => {
						reduxStore.dispatch(starredMessagesReceived(this.starredMessages));
						this.starredMessagesTimer = null;
						return this.starredMessages = [];
Guilherme Gazzo's avatar
Guilherme Gazzo committed
					}), 1000);
Diego Mello's avatar
Diego Mello committed
					const message = ddpMessage.fields;
					message._id = ddpMessage.id;
Guilherme Gazzo's avatar
Guilherme Gazzo committed
					const starredMessage = _buildMessage(message);
					this.starredMessages = [...this.starredMessages, starredMessage];
Diego Mello's avatar
Diego Mello committed
				}
				if (ddpMessage.msg === 'removed') {
					if (reduxStore.getState().starredMessages.isOpen) {
						return reduxStore.dispatch(starredMessageUnstarred(ddpMessage.id));
					}
Diego Mello's avatar
Diego Mello committed
				}
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			}));
Diego Mello's avatar
Diego Mello committed

Guilherme Gazzo's avatar
Guilherme Gazzo committed
			this.ddp.on('rocketchat_pinned_message', protectedFunction((ddpMessage) => {
Diego Mello's avatar
Diego Mello committed
				if (ddpMessage.msg === 'added') {
					this.pinnedMessages = this.pinnedMessages || [];

					if (this.pinnedMessagesTimer) {
						clearTimeout(this.pinnedMessagesTimer);
						this.pinnedMessagesTimer = null;
					}

					this.pinnedMessagesTimer = setTimeout(() => {
						reduxStore.dispatch(pinnedMessagesReceived(this.pinnedMessages));
						this.pinnedMessagesTimer = null;
						return this.pinnedMessages = [];
					}, 1000);
Diego Mello's avatar
Diego Mello committed
					const message = ddpMessage.fields;
					message._id = ddpMessage.id;
Guilherme Gazzo's avatar
Guilherme Gazzo committed
					const pinnedMessage = _buildMessage(message);
					this.pinnedMessages = [...this.pinnedMessages, pinnedMessage];
Diego Mello's avatar
Diego Mello committed
				}
				if (ddpMessage.msg === 'removed') {
					if (reduxStore.getState().pinnedMessages.isOpen) {
						return reduxStore.dispatch(pinnedMessageUnpinned(ddpMessage.id));
					}
				}
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			}));
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			this.ddp.on('rocketchat_mentioned_message', protectedFunction((ddpMessage) => {
				if (ddpMessage.msg === 'added') {
					this.mentionedMessages = this.mentionedMessages || [];

					if (this.mentionedMessagesTimer) {
						clearTimeout(this.mentionedMessagesTimer);
						this.mentionedMessagesTimer = null;
					}

					this.mentionedMessagesTimer = setTimeout(() => {
						reduxStore.dispatch(mentionedMessagesReceived(this.mentionedMessages));
						this.mentionedMessagesTimer = null;
						return this.mentionedMessages = [];
					}, 1000);
					const message = ddpMessage.fields;
					message._id = ddpMessage.id;
Guilherme Gazzo's avatar
Guilherme Gazzo committed
					const mentionedMessage = _buildMessage(message);
					this.mentionedMessages = [...this.mentionedMessages, mentionedMessage];
Diego Mello's avatar
Diego Mello committed
				}
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			}));
Diego Mello's avatar
Diego Mello committed

Guilherme Gazzo's avatar
Guilherme Gazzo committed
			this.ddp.on('rocketchat_snippeted_message', protectedFunction((ddpMessage) => {
				if (ddpMessage.msg === 'added') {
					this.snippetedMessages = this.snippetedMessages || [];

					if (this.snippetedMessagesTimer) {
						clearTimeout(this.snippetedMessagesTimer);
						this.snippetedMessagesTimer = null;
					}

					this.snippetedMessagesTimer = setTimeout(() => {
						reduxStore.dispatch(snippetedMessagesReceived(this.snippetedMessages));
						this.snippetedMessagesTimer = null;
						return this.snippetedMessages = [];
					}, 1000);
					const message = ddpMessage.fields;
					message._id = ddpMessage.id;
Guilherme Gazzo's avatar
Guilherme Gazzo committed
					const snippetedMessage = _buildMessage(message);
					this.snippetedMessages = [...this.snippetedMessages, snippetedMessage];
				}
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			}));
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			this.ddp.on('room_files', protectedFunction((ddpMessage) => {
				if (ddpMessage.msg === 'added') {
					this.roomFiles = this.roomFiles || [];

					if (this.roomFilesTimer) {
						clearTimeout(this.roomFilesTimer);
						this.roomFilesTimer = null;
					}

					this.roomFilesTimer = setTimeout(() => {
						reduxStore.dispatch(roomFilesReceived(this.roomFiles));
						this.roomFilesTimer = null;
						return this.roomFiles = [];
					}, 1000);
					const { fields } = ddpMessage;
					const message = {
						_id: ddpMessage.id,
						ts: fields.uploadedAt,
						msg: fields.description,
						status: 0,
						attachments: [{
							title: fields.name
						}],
						urls: [],
						reactions: [],
						u: {
							username: fields.user.username
						}
					};
					const fileUrl = `/file-upload/${ ddpMessage.id }/${ fields.name }`;
					if (/image/.test(fields.type)) {
						message.attachments[0].image_type = fields.type;
						message.attachments[0].image_url = fileUrl;
					} else if (/audio/.test(fields.type)) {
						message.attachments[0].audio_type = fields.type;
						message.attachments[0].audio_url = fileUrl;
					} else if (/video/.test(fields.type)) {
						message.attachments[0].video_type = fields.type;
						message.attachments[0].video_url = fileUrl;
					}
					this.roomFiles = [...this.roomFiles, message];
				}
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			}));
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			this.ddp.on('meteor_accounts_loginServiceConfiguration', protectedFunction((ddpMessage) => {
Diego Mello's avatar
Diego Mello committed
				if (ddpMessage.msg === 'added') {
					this.loginServices = this.loginServices || {};
					if (this.loginServiceTimer) {
						clearTimeout(this.loginServiceTimer);
						this.loginServiceTimer = null;
					}
					this.loginServiceTimer = setTimeout(() => {
						reduxStore.dispatch(setLoginServices(this.loginServices));
						this.loginServiceTimer = null;
						return this.loginServices = {};
					}, 1000);
					this.loginServices[ddpMessage.fields.service] = { ...ddpMessage.fields };
					delete this.loginServices[ddpMessage.fields.service].service;
				} else if (ddpMessage.msg === 'removed') {
					if (this.loginServiceTimer) {
						clearTimeout(this.loginServiceTimer);
					}
					this.loginServiceTimer = setTimeout(() => reduxStore.dispatch(removeLoginServices()), 1000);
				}
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			}));
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			this.ddp.on('rocketchat_roles', protectedFunction((ddpMessage) => {
				this.roles = this.roles || {};

				if (this.roleTimer) {
					clearTimeout(this.roleTimer);
					this.roleTimer = null;
				}
				this.roleTimer = setTimeout(() => {
					reduxStore.dispatch(setRoles(this.roles));

					database.write(() => {
Guilherme Gazzo's avatar
Guilherme Gazzo committed
						foreach(this.roles, (description, _id) => {
							database.create('roles', { _id, description }, true);
						});
					});

					this.roleTimer = null;
					return this.roles = {};
Guilherme Gazzo's avatar
Guilherme Gazzo committed
				}, 1000);
				this.roles[ddpMessage.id] = (ddpMessage.fields && ddpMessage.fields.description) || undefined;
			}));
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			this.ddp.on('error', protectedFunction((err) => {
				console.warn('onError', JSON.stringify(err));
				Answers.logCustom('disconnect', err);
				reduxStore.dispatch(connectFailure());
			}));
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			// TODO: fix api (get emojis by date/version....)

			this.ddp.on('open', protectedFunction(() => {
				RocketChat.getSettings();
				RocketChat.getPermissions();
				reduxStore.dispatch(connectSuccess());
				resolve();
			}));

			this.ddp.once('open', protectedFunction(() => {
				this.ddp.subscribe('activeUsers');
				this.ddp.subscribe('roles');
				RocketChat.getCustomEmoji();
			}));
		}).catch(err => console.warn(`asd ${ err }`));
gilmarsquinelato's avatar
gilmarsquinelato committed
	register({ credentials }) {
		return call('registerUser', credentials);
gilmarsquinelato's avatar
gilmarsquinelato committed
	},

	setUsername({ credentials }) {
		return call('setUsername', credentials.username);
Diego Mello's avatar
Diego Mello committed
	forgotPassword(email) {
		return call('sendForgotPasswordEmail', email);
	loginWithPassword({ username, password, code }, callback) {
		let params = {};
		const state = reduxStore.getState();

		if (state.settings.LDAP_Enable) {
			params = {
				ldap: true,
				username,
				ldapPass: password,
				ldapOptions: {}
			};
		} else if (state.settings.CROWD_Enable) {
			params = {
				crowd: true,
				username,
				crowdPassword: password
			};
		} else {
			params = {
				password: hashPassword(password),
				user: {
					username
				}
			};

Guilherme Gazzo's avatar
Guilherme Gazzo committed
			if (typeof username === 'string' && username.indexOf('@') !== -1) {
				params.user = { email: username };
Rodrigo Nascimento's avatar
Rodrigo Nascimento committed
		if (code) {
			params = {
				totp: {
					login: params,
					code
				}
			};
		}

		return this.login(params, callback);
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	login(params) {
		return this.ddp.login(params);
	},
	logout({ server }) {
		if (this.ddp) {
			this.ddp.logout();
		}
		database.deleteAll();
		AsyncStorage.removeItem(TOKEN_KEY);
		AsyncStorage.removeItem(`${ TOKEN_KEY }-${ server }`);
Guilherme Gazzo's avatar
Guilherme Gazzo committed

	registerPushToken(id, token) {
		const key = Platform.OS === 'ios' ? 'apn' : 'gcm';
		const data = {
			id: `RocketChatRN${ id }`,
			token: { [key]: token },
			appName: 'chat.rocket.reactnative', // TODO: try to get from config file
			userId: id,
			metadata: {}
		};
		return call('raix:push-update', data);
	},

	updatePushToken(pushId) {
		return call('raix:push-setuser', pushId);
	},
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	loadMissedMessages,
	loadMessagesForRoom,
	getMessage,
	sendMessage,
	getRooms,
	readMessages,
	me({ server = reduxStore.getState().server.server, token, userId }) {
		return fetch(`${ server }/api/v1/me`, {
			method: 'get',
			headers: {
				'Content-Type': 'application/json',
				'X-Auth-Token': token,
				'X-User-Id': userId
Guilherme Gazzo's avatar
Guilherme Gazzo committed
		}).then(response => response.json());
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	userInfo({ server = reduxStore.getState().server.server, token, userId }) {
		return fetch(`${ server }/api/v1/users.info?userId=${ userId }`, {
			method: 'get',
			headers: {
				'Content-Type': 'application/json',
				'X-Auth-Token': token,
				'X-User-Id': userId
Guilherme Gazzo's avatar
Guilherme Gazzo committed
		}).then(response => response.json());
	},
	async resendMessage(messageId) {
		const message = await database.objects('messages').filtered('_id = $0', messageId)[0];
		database.write(() => {
			message.status = messagesStatus.TEMP;
			database.create('messages', message, true);
Guilherme Gazzo's avatar
Guilherme Gazzo committed
		return _sendMessageCall(JSON.parse(JSON.stringify(message)));
	spotlight(search, usernames, type) {
		return call('spotlight', search, usernames, type);
Diego Sampaio's avatar
Diego Sampaio committed
	},

	createDirectMessage(username) {
		return call('createDirectMessage', username);
Diego Sampaio's avatar
Diego Sampaio committed
	},
	joinRoom(rid) {
		return call('joinRoom', rid);
	},


	/*
		"name":"yXfExLErmNR5eNPx7.png"
		"size":961
		"type":"image/png"
		"rid":"GENERAL"
		"description":""
		"store":"fileSystem"
	*/
	_ufsCreate(fileInfo) {
		// return call('ufsCreate', fileInfo);
		return call('ufsCreate', fileInfo);
	},

	// ["ZTE8CKHJt7LATv7Me","fileSystem","e8E96b2819"
	_ufsComplete(fileId, store, token) {
		return call('ufsComplete', fileId, store, token);
	},

	/*
		- "GENERAL"
		- {
			"type":"image/png",
			"size":961,
			"name":"yXfExLErmNR5eNPx7.png",
			"description":"",
			"url":"/ufs/fileSystem/ZTE8CKHJt7LATv7Me/yXfExLErmNR5eNPx7.png"
		}
	*/
	_sendFileMessage(rid, data, msg = {}) {
		return call('sendFileMessage', rid, null, data, msg);
	async sendFileMessage(rid, fileInfo, data) {
		const placeholder = RocketChat.getMessage(rid, 'Sending a file');
			if (!data) {
				data = await RNFetchBlob.wrap(fileInfo.path);
				const fileStat = await RNFetchBlob.fs.stat(fileInfo.path);
				fileInfo.size = fileStat.size;
				fileInfo.name = fileStat.filename;
			}
			const result = await RocketChat._ufsCreate({ ...fileInfo, rid });
			await RNFetchBlob.fetch('POST', result.url, {
				'Content-Type': 'application/octet-stream'
			}, data);

			const completeRresult = await RocketChat._ufsComplete(result.fileId, fileInfo.store, result.token);

			return await RocketChat._sendFileMessage(completeRresult.rid, {
				_id: completeRresult._id,
				type: completeRresult.type,
				size: completeRresult.size,
				name: completeRresult.name,
				url: completeRresult.path
			});
		} catch (e) {
			return e;
		} finally {
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			// TODO: fix that
			try {
				database.write(() => {
					const msg = database.objects('messages').filtered('_id = $0', placeholder._id);
					database.delete(msg);
				});
			} catch (e) {
				console.error(e);
			}
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	getSettings,
	getPermissions,
	getCustomEmoji,
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	parseSettings: settings => settings.reduce((ret, item) => {
		ret[item._id] = item[settingsType[item.type]] || item.valueAsString || item.valueAsNumber ||
			item.valueAsBoolean || item.value;
Guilherme Gazzo's avatar
Guilherme Gazzo committed
		return ret;
	}, {}),
	_prepareSettings(settings) {
		return settings.map((setting) => {
			setting[settingsType[setting.type]] = setting.value;
			return setting;
		});
	},
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	_filterSettings: settings => settings.filter(setting => settingsType[setting.type] && setting.value),
	parsePermissions: permissions => permissions.reduce((ret, item) => {
		ret[item._id] = item.roles.reduce((roleRet, role) => [...roleRet, role.value], []);
		return ret;
	}, {}),
	_preparePermissions(permissions) {
		permissions.forEach((permission) => {
			permission.roles = permission.roles.map(role => ({ value: role }));
		});
		return permissions;
	},
Diego Mello's avatar
Diego Mello committed
	parseEmojis: emojis => emojis.reduce((ret, item) => {
		ret[item.name] = item.extension;
		item.aliases.forEach((alias) => {
			ret[alias.value] = item.extension;
		});
		return ret;
	}, {}),
	_prepareEmojis(emojis) {
		emojis.forEach((emoji) => {
			emoji.aliases = emoji.aliases.map(alias => ({ value: alias }));
		});
		return emojis;
	},
Diego Mello's avatar
Diego Mello committed
	deleteMessage(message) {
		return call('deleteMessage', { _id: message._id });
	},
	editMessage(message) {
		const { _id, msg, rid } = message;
		return call('updateMessage', { _id, msg, rid });
	},
	toggleStarMessage(message) {
Diego Mello's avatar
Diego Mello committed
		return call('starMessage', { _id: message._id, rid: message.rid, starred: !message.starred });
	},
	togglePinMessage(message) {
		if (message.pinned) {
			return call('unpinMessage', message);
		}
		return call('pinMessage', message);
	},
	getRoom(rid) {
Guilherme Gazzo's avatar
Guilherme Gazzo committed
		const [result] = database.objects('subscriptions').filtered('rid = $0', rid);
		if (!result) {
			return Promise.reject(new Error('Room not found'));
		}
Guilherme Gazzo's avatar
Guilherme Gazzo committed
		return Promise.resolve(result);
Diego Mello's avatar
Diego Mello committed
	},
	async getPermalink(message) {
		const room = await RocketChat.getRoom(message.rid);
Guilherme Gazzo's avatar
Guilherme Gazzo committed
		const { server } = reduxStore.getState().server;
		const roomType = {
			p: 'group',
			c: 'channel',
			d: 'direct'
		}[room.t];
Guilherme Gazzo's avatar
Guilherme Gazzo committed
		return `${ server }/${ roomType }/${ room.name }?msg=${ message._id }`;
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	subscribe(...args) {
		return this.ddp.subscribe(...args);
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	},
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	emitTyping(room, t = true) {
		const { login } = reduxStore.getState();
		return call('stream-notify-room', `${ room }/typing`, login.user.username, t);
	},
	setUserPresenceAway() {
		return call('UserPresence:away');
	},
	setUserPresenceOnline() {
		return call('UserPresence:online');
	},
	setUserPresenceDefaultStatus(status) {
		return call('UserPresence:setDefaultStatus', status);
Diego Mello's avatar
Diego Mello committed
	},
	setReaction(emoji, messageId) {
		return call('setReaction', emoji, messageId);
Diego Mello's avatar
Diego Mello committed
	},
	toggleFavorite(rid, f) {
		return call('toggleFavorite', rid, !f);
	},
	getRoomMembers(rid, allUsers) {
		return call('getUsersOfRoom', rid, allUsers);
	getUserRoles() {
		return call('getUserRoles');
	},
	async getRoomMember(rid, currentUserId) {
		try {
			const membersResult = await RocketChat.getRoomMembers(rid, true);
			return Promise.resolve(membersResult.records.find(m => m.id !== currentUserId));
		} catch (error) {
			return Promise.reject(error);
		}
	},
	toggleBlockUser(rid, blocked, block) {
		if (block) {
			return call('blockUser', { rid, blocked });
		}
		return call('unblockUser', { rid, blocked });
	},
	leaveRoom(rid) {
		return call('leaveRoom', rid);
	},
	eraseRoom(rid) {
		return call('eraseRoom', rid);
	},
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	toggleMuteUserInRoom(rid, username, mute) {
		if (mute) {
			return call('muteUserInRoom', { rid, username });
		}
		return call('unmuteUserInRoom', { rid, username });
	},
	toggleArchiveRoom(rid, archive) {
		if (archive) {
			return call('archiveRoom', rid);
		}
		return call('unarchiveRoom', rid);
	},
	saveRoomSettings(rid, params) {
		return call('saveRoomSettings', rid, params);
	},
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	saveNotificationSettings(rid, param, value) {
		return call('saveNotificationSettings', rid, param, value);
	},
	messageSearch(text, rid, limit) {
		return call('messageSearch', text, rid, limit);
	},
	addUsersToRoom(rid) {
		let { users } = reduxStore.getState().selectedUsers;
		users = users.map(u => u.name);
		return call('addUsersToRoom', { rid, users });
	},
	hasPermission(permissions, rid) {
		// get the room from realm
		const room = database.objects('subscriptions').filtered('rid = $0', rid)[0];
		// get room roles
		const { roles } = room;
		// transform room roles to array
		const roomRoles = Array.from(Object.keys(roles), i => roles[i].value);
		// get user roles on the server from redux
		const userRoles = reduxStore.getState().login.user.roles || [];
		// get all permissions from redux
		const allPermissions = reduxStore.getState().permissions;
		// merge both roles
		const mergedRoles = [...new Set([...roomRoles, ...userRoles])];

		// return permissions in object format
		// e.g. { 'edit-room': true, 'set-readonly': false }
		return permissions.reduce((result, permission) => {
			result[permission] = returnAnArray(allPermissions[permission])
				.some(item => mergedRoles.indexOf(item) !== -1);
			return result;
		}, {});
};

export default RocketChat;