Skip to content
Snippets Groups Projects
rocketchat.js 26.5 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 RNFetchBlob from 'react-native-fetch-blob';
import reduxStore from './createStore';
import defaultSettings from '../constants/settings';
import messagesStatus from '../constants/messagesStatus';
import database from './realm';
import log from '../utils/log';
Guilherme Gazzo's avatar
Guilherme Gazzo committed
// import * as actions from '../actions';

import { setUser, setLoginServices, removeLoginServices, loginRequest, loginSuccess, loginFailure, logout } from '../actions/login';
Guilherme Gazzo's avatar
Guilherme Gazzo committed
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 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';

import { getDeviceToken } from '../push';

Guilherme Gazzo's avatar
Guilherme Gazzo committed
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, readOnly, broadcast
	}) {
		return call(type ? 'createPrivateGroup' : 'createChannel', name, users, readOnly, {}, { broadcast });
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 }`);
		}
	},
	_hasInstanceId(headers) {
		return (headers['x-instance-id'] != null && headers['x-instance-id'].length > 0) || (headers['X-Instance-ID'] != null && headers['X-Instance-ID'].length > 0);
	},
	async testServer(url) {
		if (/^(https?:\/\/)?(((\w|[0-9-_])+(\.(\w|[0-9-_])+)+)|localhost)(:\d+)?$/.test(url)) {
			try {
				let response = await RNFetchBlob.fetch('HEAD', url);
				response = response.respInfo;
				if (response.status === 200 && RocketChat._hasInstanceId(response.headers)) {
					return url;
				}
			} catch (e) {
				log('testServer', e);
			}
		}
		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;
Diego Mello's avatar
Diego Mello committed
		if (ddpMessage.fields && user && user.id === ddpMessage.id) {
Diego Mello's avatar
Diego Mello committed
			reduxStore.dispatch(setUser(ddpMessage.fields));
		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

Diego Mello's avatar
Diego Mello committed
		const activeUser = reduxStore.getState().activeUsers[ddpMessage.id];
		if (!ddpMessage.fields) {
			this.activeUsers[ddpMessage.id] = {};
		} else {
			this.activeUsers[ddpMessage.id] = { ...this.activeUsers[ddpMessage.id], ...activeUser, ...ddpMessage.fields };
		}
Diego Mello's avatar
Diego Mello committed
	},
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	async loginSuccess(user) {
		try {
			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 });
Diego Mello's avatar
Diego Mello committed
				user = { ...user, ...me };
			}
			if (user.username) {
				const userInfo = await this.userInfo({ token: user.token, userId: user.id });
Diego Mello's avatar
Diego Mello committed
				user = { ...user, ...userInfo.user };
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			}
			return reduxStore.dispatch(loginSuccess(user));
		} catch (e) {
			log('rocketchat.loginSuccess', e);
Guilherme Gazzo's avatar
Guilherme Gazzo committed
	},
	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())));

Diego Mello's avatar
Diego Mello committed
			this.ddp.on('loginError', protectedFunction(err => reduxStore.dispatch(loginFailure(err))));
Guilherme Gazzo's avatar
Guilherme Gazzo committed

			this.ddp.on('forbidden', protectedFunction(() => reduxStore.dispatch(logout())));

Guilherme Gazzo's avatar
Guilherme Gazzo committed
			this.ddp.on('users', protectedFunction(ddpMessage => RocketChat._setUser(ddpMessage)));

			this.ddp.on('background', () => this.getRooms().catch(e => log('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.loginSuccess(user);
				this.getRooms().catch(e => log('logged getRooms', e));
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			}));
Diego Mello's avatar
Diego Mello committed
			this.ddp.once('logged', protectedFunction(({ id }) => {
				this.subscribeRooms(id);
				// this.ddp.subscribe('stream-notify-logged', 'updateAvatar', false);
Diego Mello's avatar
Diego Mello committed
			}));
Guilherme Gazzo's avatar
Guilherme Gazzo committed

			this.ddp.on('disconnected', protectedFunction(() => {
				reduxStore.dispatch(disconnect());
Guilherme Gazzo's avatar
Guilherme Gazzo committed
				console.warn(this.ddp);
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			}));
			this.ddp.on('stream-room-messages', (ddpMessage) => {
Guilherme Gazzo's avatar
Guilherme Gazzo committed
				// TODO: debounce
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
			}));
			// this.ddp.on('stream-notify-logged', (ddpMessage) => {
			// 	// this entire logic needs a better solution
			// 	// we're using it only because our image cache lib doesn't support clear cache
			// 	if (ddpMessage.fields && ddpMessage.fields.eventName === 'updateAvatar') {
			// 		const { args } = ddpMessage.fields;
			// 		InteractionManager.runAfterInteractions(() =>
			// 			args.forEach((arg) => {
			// 				const user = database.objects('users').filtered('username = $0', arg.username);
			// 				if (user.length > 0) {
			// 					database.write(() => {
			// 						user[0].avatarVersion += 1;
			// 					});
			// 				}
			// 			}));
			// 	}
			// });
Guilherme Gazzo's avatar
Guilherme Gazzo committed
			// this.ddp.on('stream-notify-user', protectedFunction((ddpMessage) => {
			// 	console.warn('rc.stream-notify-user')
			// 	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;
			// 		}
			// 		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);
			// 			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;
			// 			if (data.muted) {
			// 				sub.muted = data.muted.map(m => ({ value: m }));
			// 			}
			// 		});
			// 	}
			// 	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;
			}));
			this.ddp.on('error', (err) => {
				log('rocketchat.onerror', err);
Guilherme Gazzo's avatar
Guilherme Gazzo committed
				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((e) => {
			log('rocketchat.connect catch', e);
		});
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) {
			try {
				this.ddp.logout();
			} catch (e) {
				log('rocketchat.logout', e);
			}
Guilherme Gazzo's avatar
Guilherme Gazzo committed
		}
		database.deleteAll();
		AsyncStorage.removeItem(TOKEN_KEY);
		AsyncStorage.removeItem(`${ TOKEN_KEY }-${ server }`);
Guilherme Gazzo's avatar
Guilherme Gazzo committed

	registerPushToken(userId) {
		const deviceToken = getDeviceToken();
		if (deviceToken) {
			const key = Platform.OS === 'ios' ? 'apn' : 'gcm';
			const data = {
				id: `RocketChatRN${ userId }`,
				token: { [key]: deviceToken },
				appName: 'chat.rocket.reactnative', // TODO: try to get from config file
				userId,
				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) {
		let placeholder;
			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 { FileUpload_MaxFileSize } = reduxStore.getState().settings;

			// -1 maxFileSize means there is no limit
			if (FileUpload_MaxFileSize > -1 && fileInfo.size > FileUpload_MaxFileSize) {
				return Promise.reject({ error: 'error-file-too-large' }); // eslint-disable-line
			}

			placeholder = RocketChat.getMessage(rid, 'Sending a file');

			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
				if (placeholder) {
					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[defaultSettings[item._id].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[defaultSettings[setting._id].type] = setting.value;
	_filterSettings: settings => settings.filter(setting => defaultSettings[setting._id] && setting.value),
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) {
		let room;
		try {
			room = await RocketChat.getRoom(message.rid);
		} catch (e) {
			log('rocketchat.getPermalink', e);
			return null;
		}
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);
	},
Diego Mello's avatar
Diego Mello committed
	saveUserProfile(params, customFields) {
		return call('saveUserProfile', params, customFields);
	},
	saveUserPreferences(params) {
		return call('saveUserPreferences', 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 permissions from realm
		const permissionsFiltered = database.objects('permissions')
			.filter(permission => permissions.includes(permission._id));
		// 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 || [];
		// 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] = false;
			const permissionFound = permissionsFiltered.find(p => p._id === permission);
			if (permissionFound) {
				result[permission] = returnAnArray(permissionFound.roles).some(r => mergedRoles.includes(r.value));
			}
			return result;
		}, {});
Diego Mello's avatar
Diego Mello committed
	},
	getAvatarSuggestion() {
		return call('getAvatarSuggestion');
	},
	resetAvatar() {
		return call('resetAvatar');
	},
	setAvatarFromService({ data, contentType = '', service = null }) {
		return call('setAvatarFromService', data, contentType, service);
};

export default RocketChat;