Skip to content

Commit

Permalink
Remove dependency of RC namespace in rc-api/helpers and api.js (#13273)
Browse files Browse the repository at this point in the history
* Move RestAPI client to rc-api package

* Remove dependency of RC namespace in rc-api/helpers and api.js
  • Loading branch information
MarcosSpessatto authored and rodrigok committed Feb 6, 2019
1 parent bff0955 commit 767f35d
Show file tree
Hide file tree
Showing 17 changed files with 214 additions and 187 deletions.
1 change: 1 addition & 0 deletions packages/rocketchat-api/client/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { API } from './lib/RestApiClient';
112 changes: 112 additions & 0 deletions packages/rocketchat-api/client/lib/RestApiClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
export const API = {
delete(endpoint, params) {
return API._jqueryCall('DELETE', endpoint, params);
},

get(endpoint, params) {
return API._jqueryCall('GET', endpoint, params);
},

post(endpoint, params, body) {
if (!body) {
body = params;
params = {};
}

return API._jqueryCall('POST', endpoint, params, body);
},

upload(endpoint, params, formData) {
if (!formData) {
formData = params;
params = {};
}

return API._jqueryFormDataCall(endpoint, params, formData);
},

_generateQueryFromParams(params) {
let query = '';
if (params && typeof params === 'object') {
Object.keys(params).forEach((key) => {
query += query === '' ? '?' : '&';

query += `${ key }=${ params[key] }`;
});
}

return query;
},

_jqueryCall(method, endpoint, params, body) {
const query = API._generateQueryFromParams(params);

return new Promise(function _rlRestApiGet(resolve, reject) {
jQuery.ajax({
method,
url: `${ document.baseURI }api/${ endpoint }${ query }`,
headers: {
'Content-Type': 'application/json',
'X-User-Id': localStorage['Meteor.userId'],
'X-Auth-Token': localStorage['Meteor.loginToken'],
},
data: JSON.stringify(body),
success: function _rlGetSuccess(result) {
resolve(result);
},
error: function _rlGetFailure(xhr, status, errorThrown) {
const error = new Error(errorThrown);
error.xhr = xhr;
reject(error);
},
});
});
},

_jqueryFormDataCall(endpoint, params, formData) {
const query = API._generateQueryFromParams(params);

if (!(formData instanceof FormData)) {
throw new Error('The formData parameter MUST be an instance of the FormData class.');
}

return new Promise(function _jqueryFormDataPromise(resolve, reject) {
jQuery.ajax({
url: `${ document.baseURI }api/${ endpoint }${ query }`,
headers: {
'X-User-Id': localStorage['Meteor.userId'],
'X-Auth-Token': localStorage['Meteor.loginToken'],
},
data: formData,
processData: false,
contentType: false,
type: 'POST',
success: function _jqueryFormDataSuccess(result) {
resolve(result);
},
error: function _jqueryFormDataError(xhr, status, errorThrown) {
reject(new Error(errorThrown));
},
});
});
},

v1: {
delete(endpoint, params) {
return API.delete(`v1/${ endpoint }`, params);
},

get(endpoint, params) {
return API.get(`v1/${ endpoint }`, params);
},

post(endpoint, params, body) {
return API.post(`v1/${ endpoint }`, params, body);
},

upload(endpoint, params, formData) {
return API.upload(`v1/${ endpoint }`, params, formData);
},
},
};
RocketChat.API = API;
5 changes: 5 additions & 0 deletions packages/rocketchat-api/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ Package.onUse(function(api) {
'rate-limit',
'rocketchat:lib',
'rocketchat:models',
'rocketchat:settings',
'rocketchat:utils',
'rocketchat:metrics',
'rocketchat:authorization',
'rocketchat:integrations',
'rocketchat:file-upload',
]);

api.mainModule('client/index.js', 'client');
api.mainModule('server/index.js', 'server');
});
57 changes: 32 additions & 25 deletions packages/rocketchat-api/server/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,22 @@ import { Accounts } from 'meteor/accounts-base';
import { RocketChat } from 'meteor/rocketchat:lib';
import { Restivus } from 'meteor/nimble:restivus';
import { Logger } from 'meteor/rocketchat:logger';
import { settings } from 'meteor/rocketchat:settings';
import { metrics } from 'meteor/rocketchat:metrics';
import { hasPermission } from 'meteor/rocketchat:authorization';
import { RateLimiter } from 'meteor/rate-limit';
import _ from 'underscore';

const logger = new Logger('API', {});
const rateLimiterDictionary = {};
const defaultRateLimiterOptions = {
numRequestsAllowed: RocketChat.settings.get('API_Enable_Rate_Limiter_Limit_Calls_Default'),
intervalTimeInMS: RocketChat.settings.get('API_Enable_Rate_Limiter_Limit_Time_Default'),
numRequestsAllowed: settings.get('API_Enable_Rate_Limiter_Limit_Calls_Default'),
intervalTimeInMS: settings.get('API_Enable_Rate_Limiter_Limit_Time_Default'),
};

class API extends Restivus {
export let API = {};

class APIClass extends Restivus {
constructor(properties) {
super(properties);
this.authMethods = [];
Expand Down Expand Up @@ -48,15 +53,15 @@ class API extends Restivus {
}

hasHelperMethods() {
return RocketChat.API.helperMethods.size !== 0;
return API.helperMethods.size !== 0;
}

getHelperMethods() {
return RocketChat.API.helperMethods;
return API.helperMethods;
}

getHelperMethod(name) {
return RocketChat.API.helperMethods.get(name);
return API.helperMethods.get(name);
}

addAuthMethod(method) {
Expand Down Expand Up @@ -182,7 +187,7 @@ class API extends Restivus {
// Add a try/catch for each endpoint
const originalAction = endpoints[method].action;
endpoints[method].action = function _internalRouteActionHandler() {
const rocketchatRestApiEnd = RocketChat.metrics.rocketchatRestApi.startTimer({
const rocketchatRestApiEnd = metrics.rocketchatRestApi.startTimer({
method,
version,
user_agent: this.request.headers['user-agent'],
Expand All @@ -198,8 +203,8 @@ class API extends Restivus {
let result;
try {
const shouldVerifyRateLimit = rateLimiterDictionary.hasOwnProperty(objectForRateLimitMatch.route)
&& (!this.userId || !RocketChat.authz.hasPermission(this.userId, 'api-bypass-rate-limit'))
&& ((process.env.NODE_ENV === 'development' && RocketChat.settings.get('API_Enable_Rate_Limiter_Dev') === true) || process.env.NODE_ENV !== 'development');
&& (!this.userId || !hasPermission(this.userId, 'api-bypass-rate-limit'))
&& ((process.env.NODE_ENV === 'development' && settings.get('API_Enable_Rate_Limiter_Dev') === true) || process.env.NODE_ENV !== 'development');
if (shouldVerifyRateLimit) {
rateLimiterDictionary[objectForRateLimitMatch.route].rateLimiter.increment(objectForRateLimitMatch);
const attemptResult = rateLimiterDictionary[objectForRateLimitMatch.route].rateLimiter.check(objectForRateLimitMatch);
Expand All @@ -217,9 +222,9 @@ class API extends Restivus {
result = originalAction.apply(this);
} catch (e) {
logger.debug(`${ method } ${ route } threw an error:`, e.stack);
result = RocketChat.API.v1.failure(e.message, e.error);
result = API.v1.failure(e.message, e.error);
}
result = result || RocketChat.API.v1.success();
result = result || API.v1.success();

rocketchatRestApiEnd({
status: result.statusCode,
Expand Down Expand Up @@ -413,8 +418,8 @@ const getUserAuth = function _getUserAuth(...args) {
this.bodyParams = JSON.parse(this.bodyParams.payload);
}

for (let i = 0; i < RocketChat.API.v1.authMethods.length; i++) {
const method = RocketChat.API.v1.authMethods[i];
for (let i = 0; i < API.v1.authMethods.length; i++) {
const method = API.v1.authMethods[i];

if (typeof method === 'function') {
const result = method.apply(this, args);
Expand All @@ -437,17 +442,19 @@ const getUserAuth = function _getUserAuth(...args) {
};
};

RocketChat.API = {
API = {
helperMethods: new Map(),
getUserAuth,
ApiClass: API,
ApiClass: APIClass,
};

RocketChat.API = API;

const defaultOptionsEndpoint = function _defaultOptionsEndpoint() {
if (this.request.method === 'OPTIONS' && this.request.headers['access-control-request-method']) {
if (RocketChat.settings.get('API_Enable_CORS') === true) {
if (settings.get('API_Enable_CORS') === true) {
this.response.writeHead(200, {
'Access-Control-Allow-Origin': RocketChat.settings.get('API_CORS_Origin'),
'Access-Control-Allow-Origin': settings.get('API_CORS_Origin'),
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, HEAD, PATCH',
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, X-User-Id, X-Auth-Token, x-visitor-token',
});
Expand All @@ -462,8 +469,8 @@ const defaultOptionsEndpoint = function _defaultOptionsEndpoint() {
};

const createApi = function _createApi(enableCors) {
if (!RocketChat.API.v1 || RocketChat.API.v1._config.enableCors !== enableCors) {
RocketChat.API.v1 = new API({
if (!API.v1 || API.v1._config.enableCors !== enableCors) {
API.v1 = new APIClass({
version: 'v1',
useDefaultAuth: true,
prettyJson: process.env.NODE_ENV === 'development',
Expand All @@ -473,8 +480,8 @@ const createApi = function _createApi(enableCors) {
});
}

if (!RocketChat.API.default || RocketChat.API.default._config.enableCors !== enableCors) {
RocketChat.API.default = new API({
if (!API.default || API.default._config.enableCors !== enableCors) {
API.default = new APIClass({
useDefaultAuth: true,
prettyJson: process.env.NODE_ENV === 'development',
enableCors,
Expand All @@ -485,19 +492,19 @@ const createApi = function _createApi(enableCors) {
};

// register the API to be re-created once the CORS-setting changes.
RocketChat.settings.get('API_Enable_CORS', (key, value) => {
settings.get('API_Enable_CORS', (key, value) => {
createApi(value);
});

RocketChat.settings.get('API_Enable_Rate_Limiter_Limit_Time_Default', (key, value) => {
settings.get('API_Enable_Rate_Limiter_Limit_Time_Default', (key, value) => {
defaultRateLimiterOptions.intervalTimeInMS = value;
createApi(value);
});

RocketChat.settings.get('API_Enable_Rate_Limiter_Limit_Calls_Default', (key, value) => {
settings.get('API_Enable_Rate_Limiter_Limit_Calls_Default', (key, value) => {
defaultRateLimiterOptions.numRequestsAllowed = value;
createApi(value);
});

// also create the API immediately
createApi(!!RocketChat.settings.get('API_Enable_CORS'));
createApi(!!settings.get('API_Enable_CORS'));
16 changes: 9 additions & 7 deletions packages/rocketchat-api/server/default/info.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { RocketChat } from 'meteor/rocketchat:lib';
import { hasRole } from 'meteor/rocketchat:authorization';
import { Info } from 'meteor/rocketchat:utils';
import { API } from '../api';

RocketChat.API.default.addRoute('info', { authRequired: false }, {
API.default.addRoute('info', { authRequired: false }, {
get() {
const user = this.getLoggedInUser();

if (user && RocketChat.authz.hasRole(user._id, 'admin')) {
return RocketChat.API.v1.success({
info: RocketChat.Info,
if (user && hasRole(user._id, 'admin')) {
return API.v1.success({
info: Info,
});
}

return RocketChat.API.v1.success({
version: RocketChat.Info.version,
return API.v1.success({
version: Info.version,
});
},
});
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { RocketChat } from 'meteor/rocketchat:lib';
import { composeMessageObjectWithUser } from 'meteor/rocketchat:utils';
import { API } from '../api';

RocketChat.API.helperMethods.set('composeRoomWithLastMessage', function _composeRoomWithLastMessage(room, userId) {
API.helperMethods.set('composeRoomWithLastMessage', function _composeRoomWithLastMessage(room, userId) {
if (room.lastMessage) {
room.lastMessage = RocketChat.composeMessageObjectWithUser(room.lastMessage, userId);
room.lastMessage = composeMessageObjectWithUser(room.lastMessage, userId);
}
return room;
});
4 changes: 2 additions & 2 deletions packages/rocketchat-api/server/helpers/deprecationWarning.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { RocketChat } from 'meteor/rocketchat:lib';
import { API } from '../api';

RocketChat.API.helperMethods.set('deprecationWarning', function _deprecationWarning({ endpoint, versionWillBeRemove, response }) {
API.helperMethods.set('deprecationWarning', function _deprecationWarning({ endpoint, versionWillBeRemove, response }) {
const warningMessage = `The endpoint "${ endpoint }" is deprecated and will be removed after version ${ versionWillBeRemove }`;
console.warn(warningMessage);
if (process.env.NODE_ENV === 'development') {
Expand Down
7 changes: 4 additions & 3 deletions packages/rocketchat-api/server/helpers/getLoggedInUser.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Accounts } from 'meteor/accounts-base';
import { RocketChat } from 'meteor/rocketchat:lib';
import { Users } from 'meteor/rocketchat:models';
import { API } from '../api';

RocketChat.API.helperMethods.set('getLoggedInUser', function _getLoggedInUser() {
API.helperMethods.set('getLoggedInUser', function _getLoggedInUser() {
let user;

if (this.request.headers['x-auth-token'] && this.request.headers['x-user-id']) {
user = RocketChat.models.Users.findOne({
user = Users.findOne({
_id: this.request.headers['x-user-id'],
'services.resume.loginTokens.hashedToken': Accounts._hashLoginToken(this.request.headers['x-auth-token']),
});
Expand Down
11 changes: 6 additions & 5 deletions packages/rocketchat-api/server/helpers/getPaginationItems.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// If the count query param is higher than the "API_Upper_Count_Limit" setting, then we limit that
// If the count query param isn't defined, then we set it to the "API_Default_Count" setting
// If the count is zero, then that means unlimited and is only allowed if the setting "API_Allow_Infinite_Count" is true
import { RocketChat } from 'meteor/rocketchat:lib';
import { settings } from 'meteor/rocketchat:settings';
import { API } from '../api';

RocketChat.API.helperMethods.set('getPaginationItems', function _getPaginationItems() {
const hardUpperLimit = RocketChat.settings.get('API_Upper_Count_Limit') <= 0 ? 100 : RocketChat.settings.get('API_Upper_Count_Limit');
const defaultCount = RocketChat.settings.get('API_Default_Count') <= 0 ? 50 : RocketChat.settings.get('API_Default_Count');
API.helperMethods.set('getPaginationItems', function _getPaginationItems() {
const hardUpperLimit = settings.get('API_Upper_Count_Limit') <= 0 ? 100 : settings.get('API_Upper_Count_Limit');
const defaultCount = settings.get('API_Default_Count') <= 0 ? 50 : settings.get('API_Default_Count');
const offset = this.queryParams.offset ? parseInt(this.queryParams.offset) : 0;
let count = defaultCount;

Expand All @@ -20,7 +21,7 @@ RocketChat.API.helperMethods.set('getPaginationItems', function _getPaginationIt
count = hardUpperLimit;
}

if (count === 0 && !RocketChat.settings.get('API_Allow_Infinite_Count')) {
if (count === 0 && !settings.get('API_Allow_Infinite_Count')) {
count = defaultCount;
}

Expand Down
Loading

0 comments on commit 767f35d

Please sign in to comment.