From ae92a17aebae6ad2e96e0d0e0726abee959c2ed6 Mon Sep 17 00:00:00 2001 From: Aditya Bhardwaj Date: Sat, 27 Apr 2019 21:36:47 +0530 Subject: [PATCH 1/2] [New] Reply privately to group messages (#14150) * [New] Reply privately to group messages * Cli errors fixed * Add callback to popup the reponse from channel --- app/ui-utils/client/lib/MessageAction.js | 23 +++++++++++++++++++++- app/ui/client/views/app/room.js | 7 +++++++ app/utils/client/lib/roomTypes.js | 11 +++++++++++ packages/rocketchat-i18n/i18n/en.i18n.json | 1 + 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/app/ui-utils/client/lib/MessageAction.js b/app/ui-utils/client/lib/MessageAction.js index eec4248f9f835..2b9540a7c3d43 100644 --- a/app/ui-utils/client/lib/MessageAction.js +++ b/app/ui-utils/client/lib/MessageAction.js @@ -1,4 +1,5 @@ import _ from 'underscore'; +import { FlowRouter } from 'meteor/kadira:flow-router'; import moment from 'moment'; import toastr from 'toastr'; import mem from 'mem'; @@ -317,13 +318,33 @@ Meteor.startup(async function() { if (Subscriptions.findOne({ rid: message.rid }) == null) { return false; } - return true; }, order: 6, group: 'menu', }); + MessageAction.addButton({ + id: 'reply-privately', + icon: 'chat', + label: 'Reply_in_direct_message', + context: ['message', 'message-mobile'], + action() { + const { msg } = messageArgs(this); + roomTypes.openRouteLink('d', { name: msg.u.username }, { ...FlowRouter.current().queryParams, reply: msg._id }); + }, + condition(message) { + if (Subscriptions.findOne({ rid: message.rid }) == null) { + return false; + } + if (roomTypes.getRoomType(message.rid) === 'd') { + return false; + } + return true; + }, + order: 7, + group: 'menu', + }); MessageAction.addButton({ id: 'ignore-user', diff --git a/app/ui/client/views/app/room.js b/app/ui/client/views/app/room.js index c5f663cfc6f9c..0b12c3013151e 100644 --- a/app/ui/client/views/app/room.js +++ b/app/ui/client/views/app/room.js @@ -1255,3 +1255,10 @@ Template.room.onRendered(function() { }); }); + +callbacks.add('enter-room', async (sub) => { + const isAReplyInDMFromChannel = FlowRouter.getQueryParam('reply') && sub.t === 'd'; + if (isAReplyInDMFromChannel && chatMessages[sub.rid]) { + await chatMessages[sub.rid].restoreReplies(); + } +}); diff --git a/app/utils/client/lib/roomTypes.js b/app/utils/client/lib/roomTypes.js index f0ef0325ab604..ce8986f66c99a 100644 --- a/app/utils/client/lib/roomTypes.js +++ b/app/utils/client/lib/roomTypes.js @@ -30,6 +30,17 @@ export const roomTypes = new class RocketChatRoomTypes extends RoomTypesCommon { getUserStatus(roomType, roomId) { return this.roomTypes[roomType] && typeof this.roomTypes[roomType].getUserStatus === 'function' && this.roomTypes[roomType].getUserStatus(roomId); } + getRoomType(roomId) { + const fields = { + t: 1, + }; + const room = ChatRoom.findOne({ + _id: roomId, + }, { + fields, + }); + return room && room.t; + } findRoom(roomType, identifier, user) { return this.roomTypes[roomType] && this.roomTypes[roomType].findRoom(identifier, user); } diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index ac799c09e3d2b..53d5e879f3466 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -2406,6 +2406,7 @@ "Replied_on": "Replied on", "Replies": "Replies", "Reply": "Reply", + "Reply_in_direct_message": "Reply in Direct Message", "ReplyTo": "Reply-To", "Report_Abuse": "Report Abuse", "Report_exclamation_mark": "Report!", From 67d07a2783e8110ab32e9795b959baa4e22c6cd6 Mon Sep 17 00:00:00 2001 From: Aaron Ogle Date: Sat, 27 Apr 2019 13:22:28 -0500 Subject: [PATCH 2/2] Improve: Marketplace auth inside Rocket.Chat instead of inside the iframe. (#14258) * Oauth inside Rocket.Chat instead of inside the iframe. This is more secure. Refactored the cloud page. Changed menu to cloud connect, add button for cloud console and many others * change cloud sync endpoint * add resend button * add i18n. If disconnected and click register again do sync * more error handling and fall back verbose for now. Handle disconnect / reconnect case better. --- app/apps/client/admin/apps.html | 6 ++ app/apps/client/admin/apps.js | 48 ++++++++- app/apps/server/communication/rest.js | 10 +- app/cloud/client/admin/cloud.html | 69 ++++++++++--- app/cloud/client/admin/cloud.js | 70 ++++++++++++- app/cloud/client/index.js | 2 +- .../functions/checkUserHasCloudLogin.js | 22 +++++ .../server/functions/connectWorkspace.js | 2 + .../functions/finishOAuthAuthorization.js | 5 +- .../functions/getUserCloudAccessToken.js | 99 +++++++++++++++++++ .../functions/getWorkspaceAccessToken.js | 2 + .../server/functions/getWorkspaceLicense.js | 6 ++ .../functions/retrieveRegistrationStatus.js | 1 - .../functions/startRegisterWorkspace.js | 19 ++-- app/cloud/server/functions/syncWorkspace.js | 12 ++- .../server/functions/unregisterWorkspace.js | 3 - app/cloud/server/functions/userLoggedOut.js | 20 ++++ app/cloud/server/functions/userLogout.js | 51 ++++++++++ app/cloud/server/index.js | 3 +- app/cloud/server/methods.js | 28 +++++- app/lib/server/startup/settings.js | 10 -- packages/rocketchat-i18n/i18n/en.i18n.json | 22 +++-- 22 files changed, 450 insertions(+), 60 deletions(-) create mode 100644 app/cloud/server/functions/checkUserHasCloudLogin.js create mode 100644 app/cloud/server/functions/getUserCloudAccessToken.js create mode 100644 app/cloud/server/functions/userLoggedOut.js create mode 100644 app/cloud/server/functions/userLogout.js diff --git a/app/apps/client/admin/apps.html b/app/apps/client/admin/apps.html index b6123148cfbef..7fdbd70bb4549 100644 --- a/app/apps/client/admin/apps.html +++ b/app/apps/client/admin/apps.html @@ -6,6 +6,12 @@ {{> icon icon="upload" block="rc-icon--default-size"}} {{_ "Upload app"}} {{/if}} + + {{#unless cloudLoggedIn}} + + {{/unless}} {{/header}}
{{>tabs tabs=tabsData}} diff --git a/app/apps/client/admin/apps.js b/app/apps/client/admin/apps.js index 634c8d25ccf45..5bb872763a4e4 100644 --- a/app/apps/client/admin/apps.js +++ b/app/apps/client/admin/apps.js @@ -1,4 +1,5 @@ import toastr from 'toastr'; +import { Meteor } from 'meteor/meteor'; import { ReactiveVar } from 'meteor/reactive-var'; import { FlowRouter } from 'meteor/kadira:flow-router'; import { Template } from 'meteor/templating'; @@ -63,6 +64,17 @@ const getInstalledApps = async (instance) => { } }; +const getCloudLoggedIn = async (instance) => { + Meteor.call('cloud:checkUserLoggedIn', (error, result) => { + if (error) { + console.warn(error); + return; + } + + instance.cloudLoggedIn.set(result); + }); +}; + Template.apps.onCreated(function() { const instance = this; this.ready = new ReactiveVar(false); @@ -77,6 +89,7 @@ Template.apps.onCreated(function() { this.end = new ReactiveVar(false); this.isLoading = new ReactiveVar(true); this.searchType = new ReactiveVar('marketplace'); + this.cloudLoggedIn = new ReactiveVar(false); const queryTab = FlowRouter.getQueryParam('tab'); if (queryTab) { @@ -103,6 +116,8 @@ Template.apps.onCreated(function() { // }); }; + getCloudLoggedIn(instance); + instance.onAppRemoved = function _appOnAppRemoved(appId) { const apps = instance.apps.get(); @@ -151,6 +166,9 @@ Template.apps.helpers({ appsDevelopmentMode() { return settings.get('Apps_Framework_Development_Mode') === true; }, + cloudLoggedIn() { + return Template.instance().cloudLoggedIn.get(); + }, parseStatus(status) { return t(`App_status_${ status }`); }, @@ -270,6 +288,9 @@ Template.apps.events({ 'click [data-button="install"]'() { FlowRouter.go('/admin/app/install'); }, + 'click [data-button="login"]'() { + FlowRouter.go('/admin/cloud'); + }, 'click .js-install'(e, template) { e.stopPropagation(); const elm = e.currentTarget.parentElement; @@ -298,6 +319,26 @@ Template.apps.events({ const rl = this; + if (!template.cloudLoggedIn.get()) { + modal.open({ + title: t('Apps_Marketplace_Login_Required_Title'), + text: t('Apps_Marketplace_Login_Required_Description'), + type: 'info', + showCancelButton: true, + confirmButtonColor: '#DD6B55', + confirmButtonText: t('Login'), + cancelButtonText: t('Cancel'), + closeOnConfirm: true, + html: false, + }, function(confirmed) { + if (confirmed) { + FlowRouter.go('/admin/cloud'); + } + return; + }); + return; + } + // play animation const elm = e.currentTarget.parentElement; @@ -328,7 +369,12 @@ Template.apps.events({ }); }) .catch((e) => { - toastr.error((e.xhr.responseJSON && e.xhr.responseJSON.error) || e.message); + const errMsg = (e.xhr.responseJSON && e.xhr.responseJSON.error) || e.message; + toastr.error(errMsg); + + if (errMsg === 'Unauthorized') { + getCloudLoggedIn(template); + } }); }, 'keyup .js-search'(e, t) { diff --git a/app/apps/server/communication/rest.js b/app/apps/server/communication/rest.js index bd8f3531279d8..b6124ccf621c0 100644 --- a/app/apps/server/communication/rest.js +++ b/app/apps/server/communication/rest.js @@ -3,7 +3,7 @@ import { HTTP } from 'meteor/http'; import { API } from '../../../api/server'; import Busboy from 'busboy'; -import { getWorkspaceAccessToken } from '../../../cloud/server'; +import { getWorkspaceAccessToken, getUserCloudAccessToken } from '../../../cloud/server'; import { settings } from '../../../settings'; import { Info } from '../../../utils'; @@ -94,7 +94,13 @@ export class AppsRestApi { if (this.queryParams.buildBuyUrl && this.queryParams.appId) { const workspaceId = settings.get('Cloud_Workspace_Id'); - return API.v1.success({ url: `${ baseUrl }/apps/${ this.queryParams.appId }/buy?workspaceId=${ workspaceId }` }); + + const token = getUserCloudAccessToken(this.getLoggedInUser()._id, true, 'marketplace:purchase', false); + if (!token) { + return API.v1.failure({ error: 'Unauthorized' }); + } + + return API.v1.success({ url: `${ baseUrl }/apps/${ this.queryParams.appId }/buy?workspaceId=${ workspaceId }&token=${ token }` }); } const apps = manager.get().map((prl) => { diff --git a/app/cloud/client/admin/cloud.html b/app/cloud/client/admin/cloud.html index 12225ab37f877..c6055e5a517c2 100644 --- a/app/cloud/client/admin/cloud.html +++ b/app/cloud/client/admin/cloud.html @@ -1,10 +1,13 @@