Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEW] Cloud Integration #13013

Merged
merged 26 commits into from
Jan 7, 2019
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1d5b7c7
Cloud package inside of rocket.chat, enforcing a few items now
graywolf336 Dec 20, 2018
29135fc
Implementing more of the requirements to get cloud up
graywolf336 Dec 20, 2018
02788b2
Fix the linter error.
graywolf336 Dec 20, 2018
c3d89b4
Switch callback to webview and rename some of the variables
geekgonecrazy Dec 21, 2018
38a8b29
fix additional lint
geekgonecrazy Dec 21, 2018
a8099f0
clean up
geekgonecrazy Dec 21, 2018
0eb755d
remove console log
geekgonecrazy Dec 21, 2018
9e5f9d1
use check for register server on statistics
geekgonecrazy Dec 21, 2018
2fe6b91
Implement calling the server-to-cloud and store the tokens
graywolf336 Dec 21, 2018
09ed71c
Add the workspace token to various services Rocket.Chat, the company,…
graywolf336 Dec 22, 2018
45c8ae8
Clean up the html spacing in the cloud.html
graywolf336 Dec 22, 2018
6d4c126
Remove the check on stats for sending the organization email
graywolf336 Dec 22, 2018
ad8ede7
Cloud workspace and user connected
graywolf336 Dec 22, 2018
8614f9f
Update to include refresh token now that cloud does
graywolf336 Dec 22, 2018
f59666b
Add a license api and try/catches
graywolf336 Dec 22, 2018
c1658cc
Add support for the token in the url of the admin/cloud page
graywolf336 Dec 22, 2018
0420637
Change redirectUrl var to redirectUri. dont save scope, and remove w…
geekgonecrazy Dec 22, 2018
87f272f
fix messy looking if
geekgonecrazy Dec 22, 2018
04bbffd
try increasing wait time on test
geekgonecrazy Dec 22, 2018
74e2d7a
Merge branch 'develop' into cloud-additions
geekgonecrazy Dec 22, 2018
d021450
add missing import after merge with develop
geekgonecrazy Dec 22, 2018
a64119c
Check users email
sampaiodiego Dec 24, 2018
214d6c8
Don't save the org email from the wizard
graywolf336 Dec 24, 2018
6837e1d
Merge branch 'develop' into cloud-additions
geekgonecrazy Jan 3, 2019
d95fb18
Fix the review issues, adding i18n
graywolf336 Jan 4, 2019
4e9f94b
Remove console.log
sampaiodiego Jan 4, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .meteor/packages
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ rocketchat:bot-helpers
rocketchat:cas
rocketchat:channel-settings
rocketchat:channel-settings-mail-messages
rocketchat:cloud
rocketchat:colors
rocketchat:crowd
rocketchat:custom-oauth
Expand Down
1 change: 1 addition & 0 deletions .meteor/versions
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ rocketchat:bot-helpers@0.0.1
rocketchat:cas@1.0.0
rocketchat:channel-settings@0.0.1
rocketchat:channel-settings-mail-messages@0.0.1
rocketchat:cloud@0.0.1
rocketchat:colors@0.0.1
rocketchat:cors@0.0.1
rocketchat:crowd@1.0.0
Expand Down
16 changes: 16 additions & 0 deletions packages/rocketchat-cloud/client/admin/callback.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template name="cloudCallback">
<div class="main-content-flex">
<section class="page-container page-home page-static page-settings">
{{> header sectionName="Cloud_connect"}}
<div class="content">
{{#requiresPermission 'manage-cloud'}}
{{#if callbackError.error}}
<p>{{_ "Cloud_error_in_authenticating"}}</p>

<p>{{_ "Cloud_error_code"}} {{ callbackError.errorCode }}</p>
{{/if}}
{{/requiresPermission}}
</div>
</section>
</div>
</template>
37 changes: 37 additions & 0 deletions packages/rocketchat-cloud/client/admin/callback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import './callback.html';

import { Meteor } from 'meteor/meteor';
import { ReactiveVar } from 'meteor/reactive-var';
import { Template } from 'meteor/templating';

import { FlowRouter } from 'meteor/kadira:flow-router';

import queryString from 'query-string';

Template.cloudCallback.onCreated(function() {
const instance = this;

instance.loading = new ReactiveVar(true);
instance.callbackError = new ReactiveVar({ error: false });

const params = queryString.parse(location.search);

if (params.error_code) {
instance.callbackError.set({ error: true, errorCode: params.error_code });
} else {
Meteor.call('cloud:finishOAuthAuthorization', params.code, params.state, (error) => {
if (error) {
console.warn('cloud:finishOAuthAuthorization', error);
return;
}

FlowRouter.go('/admin/cloud');
});
}
});

Template.cloudCallback.helpers({
callbackError() {
return Template.instance().callbackError.get();
},
});
83 changes: 83 additions & 0 deletions packages/rocketchat-cloud/client/admin/cloud.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<template name="cloud">
<div class="main-content-flex">
<section class="page-container page-home page-static page-settings">
{{> header sectionName="Cloud_connect"}}
<div class="content">
{{#requiresPermission 'manage-cloud'}}
<div class="section">
<div class="section-title">
<div class="section-title-text">
{{_ "Cloud_what_is_it"}}
</div>
</div>

<div class="section-content">
<p>{{_ "Cloud_what_is_it_description"}}</p>
</div>
</div>
<div class="section">
{{#if info.registeredWithWizard}}
{{#if info.workspaceConnected}}
<div class="section-content border-component-color">
{{#if info.userAssociated}}
<p>{{_ "Cloud_workspace_connected_plus_account"}}</p>
{{else}}
<p>{{_ "Cloud_workspace_connected_without_account"}}</p>
<div class="input-line double-col">
<label class="setting-label" title=""></label>
<div class="setting-field">
<button type="button" class="rc-button rc-button--primary action login-btn">{{_ "Cloud_login_to_cloud"}}</button>
</div>
</div>
{{/if}}
</div>
{{else}}
<div class="section-content border-component-color">
<div class="input-line double-col">
<label class="setting-label" title="cloudEmail">Email</label>
<div class="setting-field">
<input class="input-monitor rc-input__element" type="text" name="cloudEmail" value="{{ info.email }}">
sampaiodiego marked this conversation as resolved.
Show resolved Hide resolved
<div class="settings-description secondary-font-color">{{_ "Cloud_address_to_send_registration_to"}}</div>
</div>
</div>
<div class="input-line double-col">
<label class="setting-label" title=""></label>
<div class="setting-field">
<button type="button" class="rc-button rc-button--primary action update-email-btn">{{_ "Cloud_update_email"}}</button>
</div>
</div>

<pre>{{ registeredWithWizard }}</pre>

<div class="input-line double-col">
<label class="setting-label" title="cloudToken">{{_ "Token"}}</label>
<div class="setting-field">
<input class="input-monitor rc-input__element" type="text" name="cloudToken" value="{{ info.token }}">
<div class="settings-description secondary-font-color">{{_ "Cloud_manually_input_token"}}</div>
</div>
</div>
<div class="input-line double-col">
<label class="setting-label" title=""></label>
<div class="setting-field">
<button type="button" class="rc-button rc-button--primary action connect-btn">{{_ "Connect"}}</button>
</div>
</div>
</div>
{{/if}}
{{else}}
<div class="section-title">
<div class="section-title-text">
{{_ "Cloud_registration_required"}}
</div>
</div>
<div class="section-content border-component-color">
<p>{{_ "Cloud_registration_required_description"}}</p>
<p><a href="./admin/Setup_Wizard">{{_ "Cloud_registration_requried_link_text"}}</a></p>
</div>
{{/if}}
</div>
{{/requiresPermission}}
</div>
</section>
</div>
</template>
93 changes: 93 additions & 0 deletions packages/rocketchat-cloud/client/admin/cloud.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import './cloud.html';

import { Meteor } from 'meteor/meteor';
import { ReactiveVar } from 'meteor/reactive-var';
import { Template } from 'meteor/templating';
import { t } from 'meteor/rocketchat:utils';

import queryString from 'query-string';
import toastr from 'toastr';

Template.cloud.onCreated(function() {
const instance = this;
instance.info = new ReactiveVar();
instance.loading = new ReactiveVar(true);

instance.loadRegStatus = function _loadRegStatus() {
Meteor.call('cloud:checkRegisterStatus', (error, info) => {
if (error) {
console.warn('cloud:checkRegisterStatus', error);
return;
}

instance.info.set(info);
instance.loading.set(false);
});
};

instance.connectWorkspace = function _connectWorkspace(token) {
Meteor.call('cloud:connectWorkspace', token, (error, success) => {
if (error) {
toastr.error(error);
instance.loadRegStatus();
return;
}

if (!success) {
toastr.error('Invalid token');
instance.loadRegStatus();
return;
}

toastr.success(t('Connected'));

instance.loadRegStatus();
});
};

const params = queryString.parse(location.search);

if (params.token) {
instance.connectWorkspace();
} else {
instance.loadRegStatus();
}
});

Template.cloud.helpers({
info() {
return Template.instance().info.get();
},
});

Template.cloud.events({
'click .update-email-btn'() {
const val = $('input[name=cloudEmail]').val();

Meteor.call('cloud:updateEmail', val, (error) => {
if (error) {
console.warn(error);
return;
}

toastr.success(t('Saved'));
});
},

'click .login-btn'() {
Meteor.call('cloud:getOAuthAuthorizationUrl', (error, url) => {
if (error) {
console.warn(error);
return;
}

window.location.href = url;
});
},

'click .connect-btn'(e, i) {
const token = $('input[name=cloudToken]').val();

i.connectWorkspace(token);
},
});
28 changes: 28 additions & 0 deletions packages/rocketchat-cloud/client/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import './admin/callback';
import './admin/cloud';

import { BlazeLayout } from 'meteor/kadira:blaze-layout';
import { FlowRouter } from 'meteor/kadira:flow-router';

FlowRouter.route('/admin/cloud', {
name: 'cloud-config',
action() {
BlazeLayout.render('main', { center: 'cloud', old: true });
},
});

FlowRouter.route('/admin/cloud/oauth-callback', {
name: 'cloud-oauth-callback',
action() {
BlazeLayout.render('main', { center: 'cloudCallback', old: true });
},
});

RocketChat.AdminBox.addOption({
icon: 'cloud-plus',
href: 'admin/cloud',
i18nLabel: 'Cloud',
permissionGranted() {
return RocketChat.authz.hasAtLeastOnePermission(['manage-cloud']);
},
});
17 changes: 17 additions & 0 deletions packages/rocketchat-cloud/package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Package.describe({
name: 'rocketchat:cloud',
version: '0.0.1',
summary: 'Package which interacts with the Rocket.Chat Cloud offerings.',
git: '',
});

Package.onUse(function(api) {
api.use([
'ecmascript',
'rocketchat:lib',
'templating',
]);

api.mainModule('client/index.js', 'client');
api.mainModule('server/index.js', 'server');
});
70 changes: 70 additions & 0 deletions packages/rocketchat-cloud/server/functions/connectWorkspace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import querystring from 'querystring';
import { HTTP } from 'meteor/http';

import { getRedirectUri } from './getRedirectUri';
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';

export function connectWorkspace(token) {
const { registeredWithWizard } = retrieveRegistrationStatus();
if (!registeredWithWizard) {
return false;
}

const redirectUri = getRedirectUri();

const regInfo = {
email: RocketChat.settings.get('Organization_Email'),
client_name: RocketChat.settings.get('Site_Name'),
redirect_uris: [redirectUri],
};

const cloudUrl = RocketChat.settings.get('Cloud_Url');
let result;
try {
result = HTTP.post(`${ cloudUrl }/api/oauth/clients`, {
headers: {
Authorization: `Bearer ${ token }`,
},
data: regInfo,
});
} catch (e) {
return false;
}

const { data } = result;

if (!data) {
return false;
}

RocketChat.models.Settings.updateValueById('Cloud_Workspace_Id', data.workspaceId);
RocketChat.models.Settings.updateValueById('Cloud_Workspace_Name', data.client_name);
RocketChat.models.Settings.updateValueById('Cloud_Workspace_Client_Id', data.client_id);
RocketChat.models.Settings.updateValueById('Cloud_Workspace_Client_Secret', data.client_secret);
RocketChat.models.Settings.updateValueById('Cloud_Workspace_Client_Secret_Expires_At', data.client_secret_expires_at);
RocketChat.models.Settings.updateValueById('Cloud_Workspace_Registration_Client_Uri', data.registration_client_uri);

// Now that we have the client id and secret, let's get the access token
let authTokenResult;
try {
authTokenResult = HTTP.post(`${ cloudUrl }/api/oauth/token`, {
data: {},
query: querystring.stringify({
client_id: data.client_id,
client_secret: data.client_secret,
grant_type: 'client_credentials',
redirect_uri: redirectUri,
}),
});
} catch (e) {
return false;
}

const expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + authTokenResult.data.expires_in);

RocketChat.models.Settings.updateValueById('Cloud_Workspace_Access_Token', authTokenResult.data.access_token);
RocketChat.models.Settings.updateValueById('Cloud_Workspace_Access_Token_Expires_At', expiresAt);

return true;
}
Loading