Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 app/api/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import './default/info';
import './v1/assets';
import './v1/channels';
import './v1/chat';
import './v1/cloud';
import './v1/commands';
import './v1/e2e';
import './v1/emoji-custom';
Expand Down
30 changes: 30 additions & 0 deletions app/api/server/v1/cloud.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { check } from 'meteor/check';

import { API } from '../api';
import { hasRole } from '../../../authorization';
import { saveRegistrationData } from '../../../cloud/server/functions/saveRegistrationData';
import { retrieveRegistrationStatus } from '../../../cloud/server/functions/retrieveRegistrationStatus';

API.v1.addRoute('cloud.manualRegister', { authRequired: true }, {
post() {
check(this.bodyParams, {
cloudBlob: String,
});

if (!hasRole(this.userId, 'admin')) {
return API.v1.unauthorized();
}

const registrationInfo = retrieveRegistrationStatus();

if (registrationInfo.connectToCloud) {
return API.v1.failure('Workspace is already registered');
}

const settingsData = JSON.parse(Buffer.from(this.bodyParams.cloudBlob, 'base64').toString());

Promise.await(saveRegistrationData(settingsData));

return API.v1.success();
},
});
9 changes: 8 additions & 1 deletion app/cloud/client/admin/cloud.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
<div class="main-content-flex">
<section class="page-container page-home page-static page-settings">
{{#header sectionName="Connectivity_Services" hideHelp=true fixedHeight=true fullpage=true}}
<a href="https://cloud.rocket.chat" class="rc-button rc-button--primary action cloud-console-btn" target="_blank">{{_ "Cloud_console"}}</a>
<div class="rc-header__section-button">
{{#unless info.connectToCloud}}
<button class="rc-button rc-button--small rc-button--primary rc-button--outline js-register">
{{_ "Cloud_Register_manually"}}
</button>
{{/unless}}
<a href="https://cloud.rocket.chat" class="rc-button rc-button--primary action cloud-console-btn" target="_blank">{{_ "Cloud_console"}}</a>
</div>
{{/header}}
<div class="content">
{{#requiresPermission 'manage-cloud'}}
Expand Down
13 changes: 12 additions & 1 deletion app/cloud/client/admin/cloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import queryString from 'query-string';
import toastr from 'toastr';

import { t } from '../../../utils';
import { SideNav } from '../../../ui-utils/client';
import { SideNav, modal } from '../../../ui-utils/client';


Template.cloud.onCreated(function() {
Expand Down Expand Up @@ -161,6 +161,17 @@ Template.cloud.helpers({
});

Template.cloud.events({
'click .js-register'() {
modal.open({
template: 'cloudRegisterManually',
showCancelButton: false,
showConfirmButton: false,
showFooter: false,
closeOnCancel: true,
html: true,
confirmOnEnter: false,
});
},
'click .update-email-btn'() {
const val = $('input[name=cloudEmail]').val();

Expand Down
26 changes: 26 additions & 0 deletions app/cloud/client/admin/cloudRegisterManually.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.rc-promtp {
display: flex;

min-height: 188px;
padding: 1rem;

border-radius: 2px;
background: #2f343d;
flex-flow: column wrap;
justify-content: space-between;

&--element,
&--element[disabled] {
flex: 1 1 auto;

resize: none;

color: #cbced1;
border: none;
background: none;

font-family: Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
font-size: 14px;
line-height: 20px;
}
}
36 changes: 36 additions & 0 deletions app/cloud/client/admin/cloudRegisterManually.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<template name="cloudRegisterManually">
{{> header sectionName="Cloud_Register_manually" hideHelp=true fullpage=true}}
{{# if copyStep }}
<form class="preferences-page__content">
<p class="rc-modal__description">{{_ "Cloud_register_offline_helper" }}</p>
<div class="rc-promtp">
<textarea class="rc-promtp--element" disabled>{{clientKey}}</textarea>
<button class="rc-button rc-button--primary js-copy" data-clipboard-text="{{clientKey}}">
{{>icon icon='copy'}} {{_ "Copy"}}
</button>
</div>
<p class="rc-modal__description js-cloud">{{#if cloudLink}} {{{cloudLink}}} {{else}} <a href="https://cloud.rocket.chat" rel="noopener noreferrer" class="cloud-console-btn" target="_blank"></a>{{/if}}</p>
</form>

<footer class="rc-modal__footer rc-modal__footer--empty">
<button class="rc-button rc-button--primary js-next">{{_ "Next"}}</button>
</footer>

{{else}}

<form class="preferences-page__content">
<p class="rc-modal__description">{{_ "Cloud_register_offline_finish_helper"}}</p>
<div class="rc-promtp">
<textarea class="js-cloud-key rc-promtp--element" placeholder="{{_ "Paste_here"}}" disabled={{isLoading}}></textarea>
</div>
</form>

<footer class="rc-modal__footer rc-modal__footer--empty">
<button class="rc-button rc-button--secondary js-back">{{_ "Back"}}</button>
<button class="rc-button rc-button--primary js-finish" disabled='{{disabled}}'>
{{#if isLoading}} {{> loading}} {{/if}}
<span style="{{#if isLoading}} visibility:hidden {{/if}}">{{_ "Finish Registration"}}</span>
</button>
</footer>
{{/if}}
</template>
106 changes: 106 additions & 0 deletions app/cloud/client/admin/cloudRegisterManually.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { Meteor } from 'meteor/meteor';
import { ReactiveDict } from 'meteor/reactive-dict';
import { ReactiveVar } from 'meteor/reactive-var';
import { Template } from 'meteor/templating';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';
import Clipboard from 'clipboard';
import toastr from 'toastr';

import { APIClient } from '../../../utils/client';
import { modal } from '../../../ui-utils/client';

import './cloudRegisterManually.html';
import './cloudRegisterManually.css';

const CLOUD_STEPS = {
COPY: 0,
PASTE: 1,
DONE: 2,
ERROR: 3,
};

Template.cloudRegisterManually.events({
'submit form'(e) {
e.preventDefault();
},
'input .js-cloud-key'(e, instance) {
instance.state.set('cloudKey', e.currentTarget.value);
},
'click .js-next'(event, instance) {
instance.state.set('step', CLOUD_STEPS.PASTE);
},
'click .js-back'(event, instance) {
instance.state.set('step', CLOUD_STEPS.COPY);
},
'click .js-finish'(event, instance) {
instance.state.set('loading', true);

APIClient
.post('v1/cloud.manualRegister', {}, { cloudBlob: instance.state.get('cloudKey') })
.then(() => modal.open({
type: 'success',
title: TAPi18n.__('Success'),
text: TAPi18n.__('Cloud_register_success'),
confirmButtonText: TAPi18n.__('Ok'),
closeOnConfirm: false,
showCancelButton: false,
}, () => window.location.reload()))
.catch(() => modal.open({
type: 'error',
title: TAPi18n.__('Error'),
text: TAPi18n.__('Cloud_register_error'),
}))
.then(() => instance.state.set('loading', false));
},
});

Template.cloudRegisterManually.helpers({
cloudLink() {
return Template.instance().cloudLink.get();
},
copyStep() {
return Template.instance().state.get('step') === CLOUD_STEPS.COPY;
},
clientKey() {
return Template.instance().state.get('clientKey');
},
isLoading() {
return Template.instance().state.get('loading');
},
step() {
return Template.instance().state.get('step');
},
disabled() {
const { state } = Template.instance();

const shouldDisable = state.get('cloudKey').trim().length === 0 || state.get('loading');

return shouldDisable && 'disabled';
},
});

Template.cloudRegisterManually.onRendered(function() {
const clipboard = new Clipboard('.js-copy');
clipboard.on('success', function() {
toastr.success(TAPi18n.__('Copied'));
});

const btn = this.find('.cloud-console-btn');
// After_copy_the_text_go_to_cloud
this.cloudLink.set(TAPi18n.__('Cloud_click_here').replace(/(\[(.*)\]\(\))/ig, (_, __, text) => btn.outerHTML.replace('</a>', `${ text }</a>`)));
});

Template.cloudRegisterManually.onCreated(function() {
this.cloudLink = new ReactiveVar();
this.state = new ReactiveDict({
step: CLOUD_STEPS.COPY,
loading: false,
clientKey: '',
cloudKey: '',
error: '',
});

Meteor.call('cloud:getWorkspaceRegisterData', (error, result) => {
this.state.set('clientKey', result);
});
});
4 changes: 4 additions & 0 deletions app/cloud/client/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import './admin/callback';
import './admin/cloud';
import './admin/cloudRegisterManually';

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

Expand Down
54 changes: 54 additions & 0 deletions app/cloud/server/functions/buildRegistrationData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { settings } from '../../../settings';
import { Users } from '../../../models';
import { statistics } from '../../../statistics';

export function buildWorkspaceRegistrationData() {
const stats = statistics.get();

const address = settings.get('Site_Url');
const siteName = settings.get('Site_Name');

// If we have it lets send it because likely an update
const workspaceId = settings.get('Cloud_Workspace_Id');

const firstUser = Users.getOldest({ name: 1, emails: 1 });
const contactName = firstUser && firstUser.name;
let contactEmail = firstUser && firstUser.emails && firstUser.emails[0].address;

if (settings.get('Organization_Email')) {
contactEmail = settings.get('Organization_Email');
}

const allowMarketing = settings.get('Allow_Marketing_Emails');

const accountName = settings.get('Organization_Name');

const website = settings.get('Website');

const agreePrivacyTerms = settings.get('Cloud_Service_Agree_PrivacyTerms');

const { organizationType, industry, size: orgSize, country, language, serverType: workspaceType } = stats.wizard;

return {
uniqueId: stats.uniqueId,
workspaceId,
address,
contactName,
contactEmail,
allowMarketing,
accountName,
organizationType,
industry,
orgSize,
country,
language,
agreePrivacyTerms,
website,
siteName,
workspaceType,
deploymentMethod: stats.deploy.method,
deploymentPlatform: stats.deploy.platform,
version: stats.version,
setupComplete: true,
};
}
9 changes: 2 additions & 7 deletions app/cloud/server/functions/connectWorkspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
import { getWorkspaceAccessToken } from './getWorkspaceAccessToken';
import { Settings } from '../../../models';
import { settings } from '../../../settings';
import { saveRegistrationData } from './saveRegistrationData';

export function connectWorkspace(token) {
const { connectToCloud } = retrieveRegistrationStatus();
Expand Down Expand Up @@ -46,13 +47,7 @@ export function connectWorkspace(token) {
return false;
}

Settings.updateValueById('Cloud_Workspace_Id', data.workspaceId);
Settings.updateValueById('Cloud_Workspace_Name', data.client_name);
Settings.updateValueById('Cloud_Workspace_Client_Id', data.client_id);
Settings.updateValueById('Cloud_Workspace_Client_Secret', data.client_secret);
Settings.updateValueById('Cloud_Workspace_Client_Secret_Expires_At', data.client_secret_expires_at);
Settings.updateValueById('Cloud_Workspace_PublicKey', data.publicKey);
Settings.updateValueById('Cloud_Workspace_Registration_Client_Uri', data.registration_client_uri);
Promise.await(saveRegistrationData(data));

// Now that we have the client id and secret, let's get the access token
const accessToken = getWorkspaceAccessToken(true);
Expand Down
22 changes: 22 additions & 0 deletions app/cloud/server/functions/saveRegistrationData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Settings } from '../../../models/server/raw';

export function saveRegistrationData({
workspaceId,
client_name,
client_id,
client_secret,
client_secret_expires_at,
publicKey,
registration_client_uri,
}) {
return Promise.all([
Settings.updateValueById('Register_Server', true),
Settings.updateValueById('Cloud_Workspace_Id', workspaceId),
Settings.updateValueById('Cloud_Workspace_Name', client_name),
Settings.updateValueById('Cloud_Workspace_Client_Id', client_id),
Settings.updateValueById('Cloud_Workspace_Client_Secret', client_secret),
Settings.updateValueById('Cloud_Workspace_Client_Secret_Expires_At', client_secret_expires_at),
Settings.updateValueById('Cloud_Workspace_PublicKey', publicKey),
Settings.updateValueById('Cloud_Workspace_Registration_Client_Uri', registration_client_uri),
]);
}
Loading