Newer
Older
import { AsyncStorage, InteractionManager } from 'react-native';
import { Rocketchat as RocketchatClient } from '@rocket.chat/sdk';
import RNUserDefaults from 'rn-user-defaults';
import reduxStore from './createStore';
import defaultSettings from '../constants/settings';
import messagesStatus from '../constants/messagesStatus';
import { isIOS, getBundleId } from '../utils/deviceInfo';
setUser, setLoginServices, loginRequest, loginFailure, logout
import { disconnect, connectSuccess, connectRequest } from '../actions/connect';
import {
shareSelectServer, shareSetUser
} from '../actions/share';
import subscribeRooms from './methods/subscriptions/rooms';
import subscribeRoom from './methods/subscriptions/room';
import protectedFunction from './methods/helpers/protectedFunction';
import readMessages from './methods/readMessages';
import getSettings from './methods/getSettings';
import getRooms from './methods/getRooms';
import getPermissions from './methods/getPermissions';
import getCustomEmojis from './methods/getCustomEmojis';
import getSlashCommands from './methods/getSlashCommands';
import getRoles from './methods/getRoles';
import loadMessagesForRoom from './methods/loadMessagesForRoom';
import loadMissedMessages from './methods/loadMissedMessages';
import loadThreadMessages from './methods/loadThreadMessages';
import sendMessage, { getMessage, sendMessageCall } from './methods/sendMessage';
import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFileMessage';
import { getDeviceToken } from '../notifications/push';
import { SERVERS, SERVER_URL } from '../constants/userDefaults';
const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY';
export const MARKDOWN_KEY = 'RC_MARKDOWN_KEY';
const STATUSES = ['offline', 'online', 'away', 'busy'];
createChannel({
name, users, type, readOnly, broadcast
}) {
return this.sdk.methodCall(type ? 'createPrivateGroup' : 'createChannel', name, users, readOnly, {}, { broadcast });
return await RNUserDefaults.get(TOKEN_KEY);
console.warn(`RNUserDefaults error: ${ error.message }`);
const result = await fetch(`${ server }/api/info`).then(response => response.json());
if (result.success) {
if (semver.lt(result.version, MIN_ROCKETCHAT_VERSION)) {
return {
success: false,
message: 'Invalid_server_version',
messageOptions: {
minVersion: MIN_ROCKETCHAT_VERSION
}
};
}
return {
success: false,
message: 'The_URL_is_invalid'
};
this.activeUsers = this.activeUsers || {};
if (ddpMessage.fields && user && user.id === ddpMessage.id) {
if (ddpMessage.cleared && user && user.id === ddpMessage.id) {
reduxStore.dispatch(setUser({ status: 'offline' }));
}
if (!this._setUserTimer) {
this._setUserTimer = setTimeout(() => {
const batchUsers = this.activeUsers;
InteractionManager.runAfterInteractions(() => {
database.memoryDatabase.write(() => {
Object.keys(batchUsers).forEach((key) => {
if (batchUsers[key] && batchUsers[key].id) {
try {
const data = batchUsers[key];
if (data.removed) {
const userRecord = database.memoryDatabase.objectForPrimaryKey('activeUsers', data.id);
if (userRecord) {
userRecord.status = 'offline';
}
} else {
database.memoryDatabase.create('activeUsers', data, true);
}
} catch (error) {
console.log(error);
}
}
});
});
});
this._setUserTimer = null;
return this.activeUsers = {};
}, 10000);
this.activeUsers[ddpMessage.id] = {
id: ddpMessage.id,
removed: true
};
this.activeUsers[ddpMessage.id] = {
id: ddpMessage.id, ...this.activeUsers[ddpMessage.id], ...ddpMessage.fields
};
return new Promise((resolve) => {
database.setActiveDB(server);
reduxStore.dispatch(connectRequest());
if (this.connectTimeout) {
clearTimeout(this.connectTimeout);
}
if (this.roomsSub) {
this.roomsSub.stop();
}
if (this.sdk) {
this.sdk.disconnect();
this.sdk = null;
}
// Use useSsl: false only if server url starts with http://
const useSsl = !/http:\/\//.test(server);
this.sdk = new RocketchatClient({ host: server, protocol: 'ddp', useSsl });
this.getSettings();
this.sdk.connect()
.then(() => {
if (user && user.token) {
reduxStore.dispatch(loginRequest({ resume: user.token }));
}
})
.catch((err) => {
console.log('connect error', err);
// when `connect` raises an error, we try again in 10 seconds
this.connectTimeout = setTimeout(() => {
this.connect({ server, user });
}, 10000);
});
this.sdk.onStreamData('connected', () => {
reduxStore.dispatch(connectSuccess());
// const { isAuthenticated } = reduxStore.getState().login;
// if (isAuthenticated) {
// this.getUserPresence();
// }
this.sdk.onStreamData('close', () => {
reduxStore.dispatch(disconnect());
});
this.sdk.onStreamData('users', protectedFunction(ddpMessage => RocketChat._setUser(ddpMessage)));
this.sdk.onStreamData('stream-notify-logged', protectedFunction((ddpMessage) => {
const { eventName } = ddpMessage.fields;
if (eventName === 'user-status') {
const userStatus = ddpMessage.fields.args[0];
const [id, username, status] = userStatus;
if (username) {
database.memoryDatabase.write(() => {
try {
database.memoryDatabase.create('activeUsers', {
id, username, status: STATUSES[status]
}, true);
} catch (error) {
console.log(error);
}
});
}
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
async shareExtensionInit(server) {
database.setActiveDB(server);
if (this.sdk) {
this.sdk.disconnect();
this.sdk = null;
}
// Use useSsl: false only if server url starts with http://
const useSsl = !/http:\/\//.test(server);
this.sdk = new RocketchatClient({ host: server, protocol: 'ddp', useSsl });
// set Server
const { serversDB } = database.databases;
reduxStore.dispatch(shareSelectServer(server));
// set User info
const userId = await RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ server }`);
const user = userId && serversDB.objectForPrimaryKey('user', userId);
reduxStore.dispatch(shareSetUser({
id: user.id,
token: user.token,
username: user.username
}));
await RocketChat.login({ resume: user.token });
},
return this.sdk.post('users.register', credentials, false);
return this.sdk.methodCall('setUsername', username);
return this.sdk.post('users.forgotPassword', { email }, false);
async loginWithPassword({ user, password, code }) {
let params = { user, password };
const state = reduxStore.getState();
if (state.settings.LDAP_Enable) {
params = {
ldap: true,
ldapOptions: {}
};
} else if (state.settings.CROWD_Enable) {
params = {
};
}
try {
return await this.login(params);
} catch (error) {
throw error;
}
async loginOAuthOrSso(params) {
reduxStore.dispatch(loginRequest({ resume: result.token }));
} catch (error) {
throw error;
}
},
await this.sdk.login(params);
const { result } = this.sdk.currentLogin;
const user = {
id: result.userId,
token: result.authToken,
username: result.me.username,
name: result.me.name,
language: result.me.language,
status: result.me.status,
customFields: result.me.customFields,
emails: result.me.emails,
roles: result.me.roles
if (e.data && e.data.message && /you've been logged out by the server/i.test(e.data.message)) {
reduxStore.dispatch(logout({ server: this.sdk.client.host }));
} else {
reduxStore.dispatch(loginFailure(e));
}
if (this.roomsSub) {
this.roomsSub.stop();
}
if (this.activeUsersSubTimeout) {
clearTimeout(this.activeUsersSubTimeout);
this.activeUsersSubTimeout = false;
}
console.log('logout -> removePushToken -> catch -> error', error);
} catch (error) {
console.log('logout -> api logout -> catch -> error', error);
}
try {
const servers = await RNUserDefaults.objectForKey(SERVERS);
await RNUserDefaults.setObjectForKey(SERVERS, servers && servers.filter(srv => srv[SERVER_URL] !== server));
} catch (error) {
console.log('logout_rn_user_defaults', error);
}
const { serversDB } = database.databases;
const userId = await RNUserDefaults.get(`${ TOKEN_KEY }-${ server }`);
serversDB.write(() => {
const user = serversDB.objectForPrimaryKey('user', userId);
serversDB.delete(user);
});
RNUserDefaults.clear('currentServer'),
RNUserDefaults.clear(TOKEN_KEY),
RNUserDefaults.clear(`${ TOKEN_KEY }-${ server }`)
return new Promise(async(resolve) => {
const token = getDeviceToken();
if (token) {
try {
// RC 0.60.0
await this.sdk.post('push.token', data);
} catch (error) {
console.log(error);
}
}
return resolve();
});
},
removePushToken() {
const token = getDeviceToken();
if (token) {
return this.sdk.del('push.token', { token });
getMessage,
sendMessage,
getRooms,
readMessages,
const message = await database.objects('messages').filtered('_id = $0', messageId)[0];
try {
database.write(() => {
message.status = messagesStatus.TEMP;
database.create('messages', message, true);
});
await sendMessageCall.call(this, JSON.parse(JSON.stringify(message)));
} catch (error) {
try {
database.write(() => {
message.status = messagesStatus.ERROR;
database.create('messages', message, true);
});
} catch (e) {
async search({ text, filterUsers = true, filterRooms = true }) {
const searchText = text.trim();
if (this.oldPromise) {
this.oldPromise('cancel');
}
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
if (searchText === '') {
delete this.oldPromise;
return [];
}
let data = database.objects('subscriptions').filtered('name CONTAINS[c] $0', searchText);
if (filterUsers && !filterRooms) {
data = data.filtered('t = $0', 'd');
} else if (!filterUsers && filterRooms) {
data = data.filtered('t != $0', 'd');
}
data = data.slice(0, 7);
const usernames = data.map(sub => sub.name);
try {
if (data.length < 7) {
const { users, rooms } = await Promise.race([
RocketChat.spotlight(searchText, usernames, { users: filterUsers, rooms: filterRooms }),
new Promise((resolve, reject) => this.oldPromise = reject)
]);
data = data.concat(users.map(user => ({
...user,
rid: user.username,
name: user.username,
t: 'd',
search: true
})), rooms.map(room => ({
rid: room._id,
...room,
search: true
})));
}
return data;
} catch (e) {
console.warn(e);
return this.sdk.methodCall('spotlight', search, usernames, type);
return this.sdk.post('im.create', { username });
if (type === 'p') {
return this.sdk.methodCall('joinRoom', roomId);
}
return this.sdk.post('channels.join', { roomId });
sendFileMessage,
cancelUpload,
isUploadActive,
parseSettings: settings => settings.reduce((ret, item) => {
ret[item._id] = item[defaultSettings[item._id].type];
Guilherme Gazzo
committed
_prepareSettings(settings) {
return settings.map((setting) => {
setting[defaultSettings[setting._id].type] = setting.value;
Guilherme Gazzo
committed
return setting;
});
},
return this.sdk.post('chat.delete', { roomId: rid, msgId: _id });
},
editMessage(message) {
const { _id, msg, rid } = message;
return this.sdk.post('chat.update', { roomId: rid, msgId: _id, text: msg });
return this.sdk.post('chat.unStarMessage', { messageId: message._id });
return this.sdk.post('chat.starMessage', { messageId: message._id });
},
togglePinMessage(message) {
if (message.pinned) {
return this.sdk.post('chat.unPinMessage', { messageId: message._id });
return this.sdk.post('chat.pinMessage', { messageId: message._id });
reportMessage(messageId) {
return this.sdk.post('chat.reportMessage', { messageId, description: 'Message reported by user' });
},
const [result] = database.objects('subscriptions').filtered('rid = $0', rid);
if (!result) {
Guilherme Gazzo
committed
return Promise.reject(new Error('Room not found'));
}
async getPermalinkMessage(message) {
let room;
try {
room = await RocketChat.getRoom(message.rid);
} catch (e) {
Guilherme Gazzo
committed
const roomType = {
p: 'group',
c: 'channel',
d: 'direct'
}[room.t];
return `${ server }/${ roomType }/${ room.name }?msg=${ message._id }`;
Guilherme Gazzo
committed
},
getPermalinkChannel(channel) {
const { server } = reduxStore.getState().server;
const roomType = {
p: 'group',
c: 'channel',
d: 'direct'
}[channel.t];
return `${ server }/${ roomType }/${ channel.name }`;
},
onStreamData(...args) {
return this.sdk.onStreamData(...args);
},
emitTyping(room, t = true) {
const { login } = reduxStore.getState();
return this.sdk.methodCall('stream-notify-room', `${ room }/typing`, login.user.username, t);
return this.sdk.methodCall('UserPresence:away');
return this.sdk.methodCall('UserPresence:online');
return this.sdk.methodCall('UserPresence:setDefaultStatus', status);
return this.sdk.post('chat.react', { emoji, messageId });
return this.sdk.post('rooms.favorite', { roomId, favorite });
toggleRead(read, roomId) {
if (read) {
return this.sdk.post('subscriptions.unread', { roomId });
}
return this.sdk.post('subscriptions.read', { rid: roomId });
},
getRoomMembers(rid, allUsers, skip = 0, limit = 10) {
return this.sdk.methodCall('getUsersOfRoom', rid, allUsers, { skip, limit });
Diego Mello
committed
},
return this.sdk.get(`${ this.roomTypeToApiType(t) }.counters`, { roomId });
getChannelInfo(roomId) {
// RC 0.48.0
return this.sdk.get('channels.info', { roomId });
},
getUserInfo(userId) {
// RC 0.48.0
return this.sdk.get('users.info', { userId });
},
getRoomMemberId(rid, currentUserId) {
if (rid === `${ currentUserId }${ currentUserId }`) {
return currentUserId;
return rid.replace(currentUserId, '').trim();
Diego Mello
committed
toggleBlockUser(rid, blocked, block) {
if (block) {
return this.sdk.methodCall('blockUser', { rid, blocked });
Diego Mello
committed
}
return this.sdk.methodCall('unblockUser', { rid, blocked });
Diego Mello
committed
},
return this.sdk.post(`${ this.roomTypeToApiType(t) }.leave`, { roomId });
return this.sdk.post(`${ this.roomTypeToApiType(t) }.delete`, { roomId });
toggleMuteUserInRoom(rid, username, mute) {
if (mute) {
return this.sdk.methodCall('muteUserInRoom', { rid, username });
return this.sdk.methodCall('unmuteUserInRoom', { rid, username });
return this.sdk.post(`${ this.roomTypeToApiType(t) }.archive`, { roomId });
return this.sdk.post(`${ this.roomTypeToApiType(t) }.unarchive`, { roomId });
hideRoom(roomId, t) {
return this.sdk.post(`${ this.roomTypeToApiType(t) }.close`, { roomId });
},
return this.sdk.methodCall('saveRoomSettings', rid, params);
return this.sdk.post('users.updateOwnBasicInfo', { data, customFields });
return this.sdk.methodCall('saveUserPreferences', params);
saveNotificationSettings(roomId, notifications) {
return this.sdk.post('rooms.saveNotification', { roomId, notifications });
},
addUsersToRoom(rid) {
let { users } = reduxStore.getState().selectedUsers;
users = users.map(u => u.name);
return this.sdk.methodCall('addUsersToRoom', { rid, users });
getSingleMessage(msgId) {
// RC 0.57.0
return this.sdk.methodCall('getSingleMessage', msgId);
},
hasPermission(permissions, rid) {
try {
// get the room from realm
const [room] = database.objects('subscriptions').filtered('rid = $0', rid);
if (!room) {
return permissions.reduce((result, permission) => {
result[permission] = false;
return result;
}, {});
}
} catch (error) {
console.log('hasPermission -> error', error);
}
// get permissions from realm
const permissionsFiltered = database.objects('permissions')
.filter(permission => permissions.includes(permission._id));
// get user roles on the server from redux
const userRoles = (reduxStore.getState().login.user && 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));
return this.sdk.methodCall('getAvatarSuggestion');
return this.sdk.post('users.resetAvatar', { userId });
},
setAvatarFromService({ data, contentType = '', service = null }) {
return this.sdk.methodCall('setAvatarFromService', data, contentType, service);
async getUseMarkdown() {
const useMarkdown = await AsyncStorage.getItem(MARKDOWN_KEY);
if (useMarkdown === null) {
return true;
}
return JSON.parse(useMarkdown);
},
const prefs = await RNUserDefaults.objectForKey(SORT_PREFS_KEY);
return prefs;
},
async saveSortPreference(param) {
try {
let prefs = await RocketChat.getSortPreferences();
prefs = { ...prefs, ...param };
return await RNUserDefaults.setObjectForKey(SORT_PREFS_KEY, prefs);
} catch (error) {
console.warn(error);
}
},
async getLoginServices(server) {
try {
const loginServicesResult = await fetch(`${ server }/api/v1/settings.oauth`).then(response => response.json());
if (loginServicesResult.success && loginServicesResult.services.length > 0) {
const { services } = loginServicesResult;
const loginServicesReducer = loginServices.reduce((ret, item) => {
const name = item.name || item.buttonLabelText || item.service;
const authType = this._determineAuthType(item);
if (authType !== 'not_supported') {
ret[name] = { ...item, name, authType };
}
return ret;
}, {});
reduxStore.dispatch(setLoginServices(loginServicesReducer));
}
return Promise.resolve(loginServices.length);
} catch (error) {
console.warn(error);
return Promise.reject();
}
},
_determineAuthType(services) {
const { name, custom, service } = services;
if (custom) {
return 'oauth_custom';
}
if (service === 'saml') {
return 'saml';
}
if (service === 'cas') {
return 'cas';
}
// TODO: remove this after other oauth providers are implemented. e.g. Drupal, github_enterprise
const availableOAuth = ['facebook', 'github', 'gitlab', 'google', 'linkedin', 'meteor-developer', 'twitter'];
return availableOAuth.includes(name) ? 'oauth' : 'not_supported';
},
return this.sdk.get('users.getUsernameSuggestion');
},
roomTypeToApiType(t) {
const types = {
c: 'channels', d: 'im', p: 'groups'
};
return types[t];
return this.sdk.get(`${ this.roomTypeToApiType(type) }.files`, {
roomId,
offset,
sort: { uploadedAt: -1 },
fields: {
name: 1, description: 1, size: 1, type: 1, uploadedAt: 1, url: 1, userId: 1
}
});
},
getMessages(roomId, type, query, offset) {
return this.sdk.get(`${ this.roomTypeToApiType(type) }.messages`, {
roomId,
query,
offset,
sort: { ts: -1 }
});
},
getReadReceipts(messageId) {
return this.sdk.get('chat.getMessageReadReceipts', {
messageId
});
},
},
toggleFollowMessage(mid, follow) {
// RC 1.0
if (follow) {
return this.sdk.post('chat.followMessage', { mid });
return this.sdk.post('chat.unfollowMessage', { mid });
return this.sdk.get('chat.getThreadsList', {
rid, count, offset, sort: { ts: -1 }
});
},
getSyncThreadsList({ rid, updatedSince }) {
// RC 1.0
return this.sdk.get('chat.syncThreadsList', {
rid, updatedSince
});
runSlashCommand(command, roomId, params) {
// RC 0.60.2
return this.sdk.post('commands.run', {
command, roomId, params
});
},
getCommandPreview(command, roomId, params) {
// RC 0.65.0
return this.sdk.get('commands.preview', {
command, roomId, params
});
},
executeCommandPreview(command, params, roomId, previewItem) {
// RC 0.65.0
return this.sdk.post('commands.preview', {
command, params, roomId, previewItem
});
},
getUserPresence() {
return new Promise(async(resolve) => {
const serverVersion = reduxStore.getState().server.version;
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
// if server is lower than 1.1.0
if (semver.lt(semver.coerce(serverVersion), '1.1.0')) {
if (this.activeUsersSubTimeout) {
clearTimeout(this.activeUsersSubTimeout);
this.activeUsersSubTimeout = false;
}
this.activeUsersSubTimeout = setTimeout(() => {
this.sdk.subscribe('activeUsers');
}, 5000);
return resolve();
} else {
const params = {};
// if (this.lastUserPresenceFetch) {
// params.from = this.lastUserPresenceFetch.toISOString();
// }
// RC 1.1.0
const result = await this.sdk.get('users.presence', params);
if (result.success) {
// this.lastUserPresenceFetch = new Date();
database.memoryDatabase.write(() => {
result.users.forEach((item) => {
try {
item.id = item._id;
database.memoryDatabase.create('activeUsers', item, true);
} catch (error) {
console.log(error);
}
});
this.sdk.subscribe('stream-notify-logged', 'user-status');
return resolve();
}
},
getDirectory({
query, count, offset, sort
}) {
// RC 1.0
return this.sdk.get('directory', {
query, count, offset, sort
});
},
canAutoTranslate() {
try {
const AutoTranslate_Enabled = reduxStore.getState().settings && reduxStore.getState().settings.AutoTranslate_Enabled;
if (!AutoTranslate_Enabled) {
return false;
}
const autoTranslatePermission = database.objectForPrimaryKey('permissions', 'auto-translate');
const userRoles = (reduxStore.getState().login.user && reduxStore.getState().login.user.roles) || [];
return autoTranslatePermission.roles.some(role => userRoles.includes(role));
} catch (error) {
log('err_can_auto_translate', error);
return false;
}
},
saveAutoTranslate({
rid, field, value, options
}) {
return this.sdk.methodCall('autoTranslate.saveSettings', rid, field, value, options);
},
getSupportedLanguagesAutoTranslate() {
return this.sdk.methodCall('autoTranslate.getSupportedLanguages', 'en');
},
translateMessage(message, targetLanguage) {
return this.sdk.methodCall('autoTranslate.translateMessage', message, targetLanguage);
};
export default RocketChat;