Skip to content

Commit

Permalink
Merge branch 'develop' into integrate-webdav
Browse files Browse the repository at this point in the history
  • Loading branch information
sampaiodiego authored Sep 27, 2018
2 parents e406332 + c4d8f59 commit ad7b58f
Show file tree
Hide file tree
Showing 42 changed files with 764 additions and 132 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
"@google-cloud/language": "^1.2.0",
"@google-cloud/storage": "^1.7.0",
"@google-cloud/vision": "^0.19.0",
"@rocket.chat/apps-engine": "^1.0.0",
"@rocket.chat/apps-engine": "1.1.1",
"@slack/client": "^4.2.2",
"adm-zip": "^0.4.11",
"archiver": "^2.1.1",
Expand All @@ -141,6 +141,7 @@
"core-js": "^2.5.7",
"csv-parse": "^2.4.0",
"emailreplyparser": "^0.0.5",
"express": "^4.16.3",
"file-type": "^8.0.0",
"filesize": "^3.6.1",
"grapheme-splitter": "^1.0.2",
Expand Down
22 changes: 22 additions & 0 deletions packages/rocketchat-apps/client/admin/appManage.html
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,28 @@ <h2> {{_ "Details"}} </h2>
</div>
{{/if}}

{{#if apis}}
<div class="rc-apps-details__row">
<h2> {{_ "Apis"}} </h2>
</div>
<div class="rc-apps-settings">
{{#each apis}}
<div class="rc-apps-settings__item">
<div class="rc-input">
<div class="rc-apps-details__api">
{{renderMethods methods}} {{path}}
</div>
<div class="rc-input__description rc-apps-details__api__description">
{{#each methods}}
<div class="rc-apps-details__api__description__item">{{#each curl . ..}}{{.}}<br />{{/each}}</div>
{{/each}}
</div>
</div>
</div>
{{/each}}
</div>
{{/if}}

{{#if settings}}
<div class="rc-apps-details__row">
<h2> {{_ "Settings"}} </h2>
Expand Down
24 changes: 24 additions & 0 deletions packages/rocketchat-apps/client/admin/appManage.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,17 @@ Template.appManage.onCreated(function() {
this.app = new ReactiveVar({});
this.appsList = new ReactiveVar([]);
this.settings = new ReactiveVar({});
this.apis = new ReactiveVar([]);
this.loading = new ReactiveVar(false);

const id = this.id.get();

this.getApis = async() => {
this.apis.set(await window.Apps.getAppApis(id));
};

this.getApis();

this.__ = (key, options, lang_tag) => {
const appKey = Utilities.getI18nKeyForApp(key, id);
return TAPi18next.exists(`project:${ appKey }`) ? TAPi18n.__(appKey, options, lang_tag) : TAPi18n.__(key, options, lang_tag);
Expand Down Expand Up @@ -210,6 +217,9 @@ Template.appManage.helpers({
settings() {
return Object.values(Template.instance().settings.get());
},
apis() {
return Template.instance().apis.get();
},
parseDescription(i18nDescription) {
const item = RocketChat.Markdown.parseMessageNotEscaped({ html: Template.instance().__(i18nDescription) });

Expand All @@ -220,6 +230,20 @@ Template.appManage.helpers({
saving() {
return Template.instance().loading.get();
},
curl(method, api) {
const example = api.examples[method] || {};
return Utilities.curl({
url: Meteor.absoluteUrl.defaultOptions.rootUrl + api.computedPath,
method,
params: example.params,
query: example.query,
content: example.content,
headers: example.headers,
}).split('\n');
},
renderMethods(methods) {
return methods.join('|').toUpperCase();
},
});

async function setActivate(actiavate, e, t) {
Expand Down
5 changes: 5 additions & 0 deletions packages/rocketchat-apps/client/orchestrator.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ class AppClientOrchestrator {
}
});
}

async getAppApis(appId) {
const result = await RocketChat.API.get(`apps/${ appId }/apis`);
return result.apis;
}
}

Meteor.startup(function _rlClientOrch() {
Expand Down
67 changes: 67 additions & 0 deletions packages/rocketchat-apps/lib/misc/Utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,71 @@ export class Utilities {
static getI18nKeyForApp(key, appId) {
return key && `apps-${ appId }-${ key }`;
}

static curl({ method, params, auth, headers = {}, url, query, content }, opts = {}) {
const newLine = '\\\n ';

const cmd = ['curl'];

// curl options
if (opts.verbose) {
cmd.push('-v');
}
if (opts.headers) {
cmd.push('-i');
}

// method
cmd.push('-X');
cmd.push((method || 'GET').toUpperCase());

// URL
let u = url;

if (typeof params === 'object') {
Object.entries(params).forEach(([key, value]) => {
u = u.replace(`:${ key }`, value);
});
}

if (typeof query === 'object') {
const queryString = Object.entries(query).map(([key, value]) => `${ key }=${ value }`).join('&');
u += `?${ queryString }`;
}
cmd.push(u);

// username
if (auth) {
cmd.push(newLine);
cmd.push('-u');
cmd.push(auth);
}

// headers
const headerKeys = [];
Object.entries(headers).forEach(([key, val]) => {
key = key.toLowerCase();
headerKeys.push(key);
cmd.push(newLine);
cmd.push('-H');
cmd.push(`"${ key }${ val ? ': ' : ';' }${ val || '' }"`);
});

if (content) {
if (typeof content === 'object') {
if (!headerKeys.includes('content-type')) {
cmd.push(newLine);
cmd.push('-H');
cmd.push('"content-type: application/json"');
}
content = JSON.stringify(content);
}

cmd.push(newLine);
cmd.push('--data-binary');
cmd.push(`'${ content }'`);
}

return cmd.join(' ');
}
}
110 changes: 110 additions & 0 deletions packages/rocketchat-apps/server/bridges/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import express from 'express';
import { WebApp } from 'meteor/webapp';

const apiServer = express();
WebApp.connectHandlers.use(apiServer);

export class AppApisBridge {
constructor(orch) {
this.orch = orch;
this.appRouters = new Map();

// apiServer.use('/api/apps', (req, res, next) => {
// console.log({
// method: req.method.toLowerCase(),
// url: req.url,
// query: req.query,
// body: req.body,
// });
// next();
// });

apiServer.use('/api/apps/private/:appId/:hash', (req, res) => {
const notFound = () => res.send(404);

const router = this.appRouters.get(req.params.appId);

if (router) {
req._privateHash = req.params.hash;
return router(req, res, notFound);
}

notFound();
});

apiServer.use('/api/apps/public/:appId', (req, res) => {
const notFound = () => res.send(404);

const router = this.appRouters.get(req.params.appId);

if (router) {
return router(req, res, notFound);
}

notFound();
});
}

registerApi({ api, computedPath, endpoint }, appId) {
console.log(`The App ${ appId } is registering the api: "${ endpoint.path }" (${ computedPath })`);

this._verifyApi(api, endpoint);

if (!this.appRouters.get(appId)) {
this.appRouters.set(appId, express.Router()); // eslint-disable-line
}

const router = this.appRouters.get(appId);

const method = api.method || 'all';

let routePath = endpoint.path.trim();
if (!routePath.startsWith('/')) {
routePath = `/${ routePath }`;
}

router[method](routePath, Meteor.bindEnvironment(this._appApiExecutor(api, endpoint, appId)));
}

unregisterApis(appId) {
console.log(`The App ${ appId } is unregistering all apis`);

if (this.appRouters.get(appId)) {
this.appRouters.delete(appId);
}
}

_verifyApi(api, endpoint) {
if (typeof api !== 'object') {
throw new Error('Invalid Api parameter provided, it must be a valid IApi object.');
}

if (typeof endpoint.path !== 'string') {
throw new Error('Invalid Api parameter provided, it must be a valid IApi object.');
}
}

_appApiExecutor(api, endpoint, appId) {
return (req, res) => {
const request = {
method: req.method.toLowerCase(),
headers: req.headers,
query: req.query || {},
params: req.params || {},
content: req.body,
privateHash: req._privateHash,
};

this.orch.getManager().getApiManager().executeApi(appId, endpoint.path, request)
.then(({ status, headers = {}, content }) => {
res.set(headers);
res.status(status);
res.send(content);
})
.catch((reason) => {
// Should we handle this as an error?
res.status(500).send(reason.message);
});
};
}
}
6 changes: 6 additions & 0 deletions packages/rocketchat-apps/server/bridges/bridges.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AppBridges } from '@rocket.chat/apps-engine/server/bridges';
import { AppActivationBridge } from './activation';
import { AppDetailChangesBridge } from './details';
import { AppCommandsBridge } from './commands';
import { AppApisBridge } from './api';
import { AppEnvironmentalVariableBridge } from './environmental';
import { AppHttpBridge } from './http';
import { AppListenerBridge } from './listeners';
Expand All @@ -18,6 +19,7 @@ export class RealAppBridges extends AppBridges {

this._actBridge = new AppActivationBridge(orch);
this._cmdBridge = new AppCommandsBridge(orch);
this._apiBridge = new AppApisBridge(orch);
this._detBridge = new AppDetailChangesBridge(orch);
this._envBridge = new AppEnvironmentalVariableBridge(orch);
this._httpBridge = new AppHttpBridge();
Expand All @@ -33,6 +35,10 @@ export class RealAppBridges extends AppBridges {
return this._cmdBridge;
}

getApiBridge() {
return this._apiBridge;
}

getEnvironmentalVariableBridge() {
return this._envBridge;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/rocketchat-apps/server/bridges/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export class AppCommandsBridge {
}

registerCommand(command, appId) {
console.log(`The App ${ appId } is registerin the command: "${ command.command }"`);
console.log(`The App ${ appId } is registering the command: "${ command.command }"`);

this._verifyCommand(command);

Expand Down
15 changes: 15 additions & 0 deletions packages/rocketchat-apps/server/communication/rest.js
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,21 @@ export class AppsRestApi {
},
});

this.api.addRoute(':id/apis', { authRequired: true }, {
get() {
console.log(`Getting ${ this.urlParams.id }'s apis..`);
const prl = manager.getOneById(this.urlParams.id);

if (prl) {
return RocketChat.API.v1.success({
apis: manager.apiManager.listApis(this.urlParams.id),
});
} else {
return RocketChat.API.v1.notFound(`No App found by the id of: ${ this.urlParams.id }`);
}
},
});

this.api.addRoute(':id/status', { authRequired: true }, {
get() {
console.log(`Getting ${ this.urlParams.id }'s status..`);
Expand Down
2 changes: 1 addition & 1 deletion packages/rocketchat-apps/server/converters/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export class AppSettingsConverter {
}

convertById(settingId) {
const setting = RocketChat.models.Settings.findOneById(settingId);
const setting = RocketChat.models.Settings.findOneNotHiddenById(settingId);

return this.convertToApp(setting);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@
</div>
{{/with}}
</div>
{{# if retentionEnabled settings.retentionEnabled.value.get }}
{{# if settings.retentionEnabled.value.get }}
{{#with settings.retentionOverrideGlobal}}
<div class="rc-user-info__row">
<div class="rc-switch rc-switch--blue">
Expand Down
Loading

0 comments on commit ad7b58f

Please sign in to comment.