From d4c2a78db6b5057c1d613b83987d19a1c81b330a Mon Sep 17 00:00:00 2001 From: Pranav Raj S Date: Mon, 8 Feb 2021 16:38:35 +0530 Subject: [PATCH] chore: Add Chatwoot SDK to Chatwoot Dashboard (#1726) Add Chatwoot SDK to Chatwoot Dashboard --- app/controllers/dashboard_controller.rb | 3 +- .../assets/scss/widgets/_sidemenu.scss | 60 +--- .../dashboard/components/layout/Sidebar.vue | 263 +++++------------- .../sidebarComponents/AccountSelector.vue | 56 ++++ .../sidebarComponents/AddAccountModal.vue | 92 ++++++ .../layout/sidebarComponents/AgentDetails.vue | 63 +++++ .../sidebarComponents/NotificationBell.vue | 52 ++++ .../layout/sidebarComponents/OptionsMenu.vue | 76 +++++ app/javascript/shared/store/globalConfig.js | 2 + app/models/user.rb | 7 + app/views/api/v1/models/_user.json.jbuilder | 25 +- app/views/layouts/vueapp.html.erb | 22 ++ config/installation_config.yml | 8 +- spec/models/user_spec.rb | 18 ++ 14 files changed, 481 insertions(+), 266 deletions(-) create mode 100644 app/javascript/dashboard/components/layout/sidebarComponents/AccountSelector.vue create mode 100644 app/javascript/dashboard/components/layout/sidebarComponents/AddAccountModal.vue create mode 100644 app/javascript/dashboard/components/layout/sidebarComponents/AgentDetails.vue create mode 100644 app/javascript/dashboard/components/layout/sidebarComponents/NotificationBell.vue create mode 100644 app/javascript/dashboard/components/layout/sidebarComponents/OptionsMenu.vue diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 9ed9f7f47..14030b565 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -20,7 +20,8 @@ class DashboardController < ActionController::Base 'TERMS_URL', 'PRIVACY_URL', 'DISPLAY_MANIFEST', - 'CREATE_NEW_ACCOUNT_FROM_DASHBOARD' + 'CREATE_NEW_ACCOUNT_FROM_DASHBOARD', + 'CHATWOOT_INBOX_TOKEN' ).merge( APP_VERSION: Chatwoot.config[:version] ) diff --git a/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss b/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss index c02016b09..344317735 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss @@ -72,9 +72,9 @@ .dropdown-pane { @include elegant-card; @include border-light; + bottom: 6rem; display: block; - left: 18%; - top: -110px; + left: 5rem; visibility: visible; width: 80%; z-index: 999; @@ -120,62 +120,6 @@ line-height: $global-lineheight; } -.current-user { - @include flex; - align-items: center; - cursor: pointer; - flex-direction: row; - - .current-user--data { - @include flex; - flex-direction: column; - - .current-user--name { - font-size: $font-size-small; - font-weight: $font-weight-medium; - line-height: 1; - margin-bottom: $space-smaller; - margin-left: $space-one; - margin-top: $space-micro; - } - - .current-user--role { - color: $color-gray; - font-size: $font-size-mini; - margin-bottom: $zero; - margin-left: $space-one; - text-transform: capitalize; - } - } - - .current-user--options { - font-size: $font-size-big; - margin-bottom: auto; - margin-left: auto; - margin-top: auto; - } - - .notifications { - font-size: var(--font-size-big); - margin-bottom: auto; - margin-left: auto; - margin-top: auto; - position: relative; - - .unread-badge { - background: var(--r-300); - border-radius: var(--space-small); - color: var(--white); - font-size: var(--font-size-micro); - font-weight: var(--font-weight-black); - left: var(--space-slab); - padding: 0 var(--space-smaller); - position: absolute; - top: var(--space-smaller); - } - } -} - .hamburger--menu { cursor: pointer; display: none; diff --git a/app/javascript/dashboard/components/layout/Sidebar.vue b/app/javascript/dashboard/components/layout/Sidebar.vue index b81515d3e..c2e6c9117 100644 --- a/app/javascript/dashboard/components/layout/Sidebar.vue +++ b/app/javascript/dashboard/components/layout/Sidebar.vue @@ -30,180 +30,65 @@ -
- - - - -
- -
-

- {{ currentUserAvailableName }} -

-
- {{ $t(`AGENT_MGMT.AGENT_TYPES.${currentRole.toUpperCase()}`) }} -
-
- - {{ unreadCount }} - - - -
-
- + - + + + @close-account-create-modal="closeCreateAccountModal" + /> @@ -427,7 +290,19 @@ export default { } } } + .app-context-menu { + align-items: center; + cursor: pointer; + display: flex; + flex-direction: row; height: 6rem; } + +.current-user--options { + font-size: $font-size-big; + margin-bottom: auto; + margin-left: auto; + margin-top: auto; +} diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/AccountSelector.vue b/app/javascript/dashboard/components/layout/sidebarComponents/AccountSelector.vue new file mode 100644 index 000000000..9860d7a09 --- /dev/null +++ b/app/javascript/dashboard/components/layout/sidebarComponents/AccountSelector.vue @@ -0,0 +1,56 @@ + + + diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/AddAccountModal.vue b/app/javascript/dashboard/components/layout/sidebarComponents/AddAccountModal.vue new file mode 100644 index 000000000..2c78495c9 --- /dev/null +++ b/app/javascript/dashboard/components/layout/sidebarComponents/AddAccountModal.vue @@ -0,0 +1,92 @@ + + + diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/AgentDetails.vue b/app/javascript/dashboard/components/layout/sidebarComponents/AgentDetails.vue new file mode 100644 index 000000000..a1233db7c --- /dev/null +++ b/app/javascript/dashboard/components/layout/sidebarComponents/AgentDetails.vue @@ -0,0 +1,63 @@ + + + + diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/NotificationBell.vue b/app/javascript/dashboard/components/layout/sidebarComponents/NotificationBell.vue new file mode 100644 index 000000000..e5f05aed1 --- /dev/null +++ b/app/javascript/dashboard/components/layout/sidebarComponents/NotificationBell.vue @@ -0,0 +1,52 @@ + + + + diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/OptionsMenu.vue b/app/javascript/dashboard/components/layout/sidebarComponents/OptionsMenu.vue new file mode 100644 index 000000000..35eeb696d --- /dev/null +++ b/app/javascript/dashboard/components/layout/sidebarComponents/OptionsMenu.vue @@ -0,0 +1,76 @@ + + + diff --git a/app/javascript/shared/store/globalConfig.js b/app/javascript/shared/store/globalConfig.js index 6d7ab0b6d..bcf4603a9 100644 --- a/app/javascript/shared/store/globalConfig.js +++ b/app/javascript/shared/store/globalConfig.js @@ -1,6 +1,7 @@ const { APP_VERSION: appVersion, BRAND_NAME: brandName, + CHATWOOT_INBOX_TOKEN: chatwootInboxToken, CREATE_NEW_ACCOUNT_FROM_DASHBOARD: createNewAccountFromDashboard, DISPLAY_MANIFEST: displayManifest, INSTALLATION_NAME: installationName, @@ -14,6 +15,7 @@ const { const state = { appVersion, brandName, + chatwootInboxToken, createNewAccountFromDashboard, displayManifest, installationName, diff --git a/app/models/user.rb b/app/models/user.rb index 63a3bd057..b449d89ef 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -109,6 +109,13 @@ class User < ApplicationRecord self[:display_name].presence || name end + def hmac_identifier + hmac_key = GlobalConfig.get('CHATWOOT_INBOX_HMAC_KEY')['CHATWOOT_INBOX_HMAC_KEY'] + return OpenSSL::HMAC.hexdigest('sha256', hmac_key, email) if hmac_key.present? + + '' + end + def account current_account_user&.account end diff --git a/app/views/api/v1/models/_user.json.jbuilder b/app/views/api/v1/models/_user.json.jbuilder index d103061c8..bc7392bf0 100644 --- a/app/views/api/v1/models/_user.json.jbuilder +++ b/app/views/api/v1/models/_user.json.jbuilder @@ -1,19 +1,20 @@ -json.id resource.id -json.provider resource.provider -json.uid resource.uid -json.name resource.name -json.display_name resource.display_name -json.available_name resource.available_name -json.email resource.email +json.access_token resource.access_token.token json.account_id resource.active_account_user&.account_id +json.availability_status resource.availability_status +json.available_name resource.available_name +json.avatar_url resource.avatar_url +json.confirmed resource.confirmed? +json.display_name resource.display_name +json.email resource.email +json.hmac_identifier resource.hmac_identifier if GlobalConfig.get('CHATWOOT_INBOX_HMAC_KEY')['CHATWOOT_INBOX_HMAC_KEY'].present? +json.id resource.id +json.inviter_id resource.active_account_user&.inviter_id +json.name resource.name +json.provider resource.provider json.pubsub_token resource.pubsub_token json.role resource.active_account_user&.role -json.inviter_id resource.active_account_user&.inviter_id -json.confirmed resource.confirmed? -json.avatar_url resource.avatar_url -json.access_token resource.access_token.token -json.availability_status resource.availability_status json.ui_settings resource.ui_settings +json.uid resource.uid json.accounts do json.array! resource.account_users do |account_user| json.id account_user.account_id diff --git a/app/views/layouts/vueapp.html.erb b/app/views/layouts/vueapp.html.erb index 0e0668ee9..5f5c43b81 100644 --- a/app/views/layouts/vueapp.html.erb +++ b/app/views/layouts/vueapp.html.erb @@ -51,5 +51,27 @@
<%= yield %> + <% @global_config['CHATWOOT_INBOX_TOKEN'] %> + <% if @global_config['CHATWOOT_INBOX_TOKEN'] %> + + <% end %> diff --git a/config/installation_config.yml b/config/installation_config.yml index 49545d8d3..e0ca16637 100644 --- a/config/installation_config.yml +++ b/config/installation_config.yml @@ -28,5 +28,11 @@ value: false locked: false - name: INSTALLATION_EVENTS_WEBHOOK_URL - value: + value: + locked: false +- name: CHATWOOT_INBOX_TOKEN + value: + locked: false +- name: CHATWOOT_INBOX_HMAC_KEY + value: locked: false diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index d9e31e686..e9ec95754 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -34,6 +34,24 @@ RSpec.describe User do it { expect(user.saved_changes.keys).not_to eq('pubsub_token') } end + describe 'hmac_identifier' do + it 'return nil if CHATWOOT_INBOX_HMAC_KEY is not set' do + expect(user.hmac_identifier).to eq('') + end + + it 'return value if CHATWOOT_INBOX_HMAC_KEY is set' do + ConfigLoader.new.process + i = InstallationConfig.find_by(name: 'CHATWOOT_INBOX_HMAC_KEY') + i.value = 'random_secret_key' + i.save! + GlobalConfig.clear_cache + + expected_hmac_identifier = OpenSSL::HMAC.hexdigest('sha256', 'random_secret_key', user.email) + + expect(user.hmac_identifier).to eq expected_hmac_identifier + end + end + context 'sso_auth_token' do it 'can generate multiple sso tokens which can be validated' do sso_auth_token1 = user.generate_sso_auth_token