From 336af1ac9a01e1b501b928f0a1d96d946646ae45 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Tue, 3 Oct 2023 22:18:35 -0700 Subject: [PATCH 1/4] chore: Create client API conversations with custom attributes (#8040) - Update client API create conversations endpoint to accept custom attributes as well. --- .../v1/inboxes/conversations_controller.rb | 9 ++------- .../v1/inbox/conversations_controller_spec.rb | 11 +++++++++++ swagger/definitions/index.yml | 3 +++ .../public/conversation/create_payload.yml | 5 +++++ .../public/inboxes/conversations/create.yml | 6 ++++++ swagger/swagger.json | 19 +++++++++++++++++++ 6 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 swagger/definitions/request/public/conversation/create_payload.yml diff --git a/app/controllers/public/api/v1/inboxes/conversations_controller.rb b/app/controllers/public/api/v1/inboxes/conversations_controller.rb index 3d86ca87c..c79952372 100644 --- a/app/controllers/public/api/v1/inboxes/conversations_controller.rb +++ b/app/controllers/public/api/v1/inboxes/conversations_controller.rb @@ -33,7 +33,7 @@ class Public::Api::V1::Inboxes::ConversationsController < Public::Api::V1::Inbox end def create_conversation - ::Conversation.create!(conversation_params) + ConversationBuilder.new(params: conversation_params, contact_inbox: @contact_inbox).perform end def trigger_typing_event(event) @@ -41,11 +41,6 @@ class Public::Api::V1::Inboxes::ConversationsController < Public::Api::V1::Inbox end def conversation_params - { - account_id: @contact_inbox.contact.account_id, - inbox_id: @contact_inbox.inbox_id, - contact_id: @contact_inbox.contact_id, - contact_inbox_id: @contact_inbox.id - } + params.permit(custom_attributes: {}) end end diff --git a/spec/controllers/public/api/v1/inbox/conversations_controller_spec.rb b/spec/controllers/public/api/v1/inbox/conversations_controller_spec.rb index 19f08d49b..0bd8cbfd0 100644 --- a/spec/controllers/public/api/v1/inbox/conversations_controller_spec.rb +++ b/spec/controllers/public/api/v1/inbox/conversations_controller_spec.rb @@ -44,6 +44,17 @@ RSpec.describe 'Public Inbox Contact Conversations API', type: :request do data = response.parsed_body expect(data['id']).not_to be_nil end + + it 'creates a conversation with custom attributes but prevents other attributes' do + post "/public/api/v1/inboxes/#{api_channel.identifier}/contacts/#{contact_inbox.source_id}/conversations", + params: { custom_attributes: { 'test' => 'test' }, additional_attributes: { 'test' => 'test' } } + + expect(response).to have_http_status(:success) + data = response.parsed_body + conversation = api_channel.inbox.conversations.find_by(display_id: data['id']) + expect(conversation.custom_attributes).to eq('test' => 'test') + expect(conversation.additional_attributes).to be_empty + end end describe 'POST /public/api/v1/inboxes/{identifier}/contact/{source_id}/conversations/{conversation_id}/toggle_typing' do diff --git a/swagger/definitions/index.yml b/swagger/definitions/index.yml index ccc288180..ef9213d2a 100644 --- a/swagger/definitions/index.yml +++ b/swagger/definitions/index.yml @@ -138,6 +138,9 @@ public_message_create_payload: public_message_update_payload: $ref: ./request/public/message/update_payload.yml +public_conversation_create_payload: + $ref: ./request/public/conversation/create_payload.yml + ## ---------- RESPONSE ------------- ## ## -------------------------------- ## diff --git a/swagger/definitions/request/public/conversation/create_payload.yml b/swagger/definitions/request/public/conversation/create_payload.yml new file mode 100644 index 000000000..37cd9f7ef --- /dev/null +++ b/swagger/definitions/request/public/conversation/create_payload.yml @@ -0,0 +1,5 @@ +type: object +properties: + custom_attributes: + type: object + description: Custom attributes of the conversation diff --git a/swagger/paths/public/inboxes/conversations/create.yml b/swagger/paths/public/inboxes/conversations/create.yml index 5f694ff34..4c2a85d22 100644 --- a/swagger/paths/public/inboxes/conversations/create.yml +++ b/swagger/paths/public/inboxes/conversations/create.yml @@ -4,6 +4,12 @@ operationId: create-a-conversation summary: Create a conversation description: Create a conversation security: [] +parameters: + - name: data + in: body + required: true + schema: + $ref: '#/definitions/public_conversation_create_payload' responses: 200: description: Success diff --git a/swagger/swagger.json b/swagger/swagger.json index 70a4d5904..cd8f3e7d3 100644 --- a/swagger/swagger.json +++ b/swagger/swagger.json @@ -847,6 +847,16 @@ "description": "Create a conversation", "security": [ + ], + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/public_conversation_create_payload" + } + } ], "responses": { "200": { @@ -6617,6 +6627,15 @@ } } }, + "public_conversation_create_payload": { + "type": "object", + "properties": { + "custom_attributes": { + "type": "object", + "description": "Custom attributes of the conversation" + } + } + }, "extended_contact": { "allOf": [ { From 6a739530035c1abc0ed2b24fb5de1d11ff5847ac Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Tue, 3 Oct 2023 22:18:57 -0700 Subject: [PATCH 2/4] chore: Add delay before running dataimport job (#8039) - We have observed some failures for data import jobs in the cloud due to race conditions with job executions and active storage file uploading. This PR adds delays and retries to accommodate that. --- app/jobs/data_import_job.rb | 1 + app/models/data_import.rb | 3 ++- spec/jobs/data_import_job_spec.rb | 14 ++++++++++++++ spec/models/data_import_spec.rb | 10 ++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/app/jobs/data_import_job.rb b/app/jobs/data_import_job.rb index b14996fba..0a973c8bd 100644 --- a/app/jobs/data_import_job.rb +++ b/app/jobs/data_import_job.rb @@ -3,6 +3,7 @@ class DataImportJob < ApplicationJob queue_as :low + retry_on ActiveStorage::FileNotFoundError, wait: 1.minute, attempts: 3 def perform(data_import) @data_import = data_import diff --git a/app/models/data_import.rb b/app/models/data_import.rb index 874eb75f8..a44650a22 100644 --- a/app/models/data_import.rb +++ b/app/models/data_import.rb @@ -29,6 +29,7 @@ class DataImport < ApplicationRecord private def process_data_import - DataImportJob.perform_later(self) + # we wait for the file to be uploaded to the cloud + DataImportJob.set(wait: 1.minute).perform_later(self) end end diff --git a/spec/jobs/data_import_job_spec.rb b/spec/jobs/data_import_job_spec.rb index 67ca4dd73..ca20ce43b 100644 --- a/spec/jobs/data_import_job_spec.rb +++ b/spec/jobs/data_import_job_spec.rb @@ -13,6 +13,20 @@ RSpec.describe DataImportJob do end end + describe 'retrying the job' do + context 'when ActiveStorage::FileNotFoundError is raised' do + before do + allow(data_import.import_file).to receive(:download).and_raise(ActiveStorage::FileNotFoundError) + end + + it 'retries the job' do + expect do + described_class.perform_now(data_import) + end.to have_enqueued_job(described_class).at_least(1).times + end + end + end + describe 'importing data' do context 'when the data is valid' do it 'imports data into the account' do diff --git a/spec/models/data_import_spec.rb b/spec/models/data_import_spec.rb index 84805f86d..2b7429cf1 100644 --- a/spec/models/data_import_spec.rb +++ b/spec/models/data_import_spec.rb @@ -10,4 +10,14 @@ RSpec.describe DataImport do expect(build(:data_import, data_type: 'Xyc').valid?).to be false end end + + describe 'callbacks' do + let(:data_import) { build(:data_import) } + + it 'schedules a job after creation' do + expect do + data_import.save + end.to have_enqueued_job(DataImportJob).with(data_import).on_queue('low') + end + end end From b71a580573d0fea88fe9d2e2dfc9605e8e9b4ea6 Mon Sep 17 00:00:00 2001 From: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com> Date: Wed, 4 Oct 2023 11:56:00 +0530 Subject: [PATCH 3/4] feat: Adds dark theme support for public portal [CW-2525] (#7979) Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> --- .../public/api/v1/portals/base_controller.rb | 9 +++ app/helpers/portal_helper.rb | 11 ++++ .../portal/components/PublicSearchInput.vue | 8 +-- .../portal/components/SearchSuggestions.vue | 21 +++++-- .../portal/components/TableOfContents.vue | 4 +- app/views/layouts/portal.html.erb | 9 ++- .../api/v1/portals/_category-block.html.erb | 18 +++--- .../public/api/v1/portals/_footer.html.erb | 2 +- .../public/api/v1/portals/_header.html.erb | 16 ++--- .../public/api/v1/portals/_hero.html.erb | 6 +- .../v1/portals/_uncategorized-block.html.erb | 12 ++-- .../portals/articles/_article_header.html.erb | 6 +- .../api/v1/portals/articles/index.html.erb | 12 ++-- .../api/v1/portals/articles/show.html.erb | 16 ++--- .../categories/_category-block.html.erb | 18 +++--- .../categories/_category-hero.html.erb | 8 +-- .../api/v1/portals/categories/_hero.html.erb | 6 +- .../api/v1/portals/categories/show.html.erb | 12 ++-- public/assets/images/hc/grid_dark.svg | 4 ++ spec/helpers/portal_helper_spec.rb | 60 +++++++++++++++++++ 20 files changed, 178 insertions(+), 80 deletions(-) create mode 100644 app/helpers/portal_helper.rb create mode 100644 public/assets/images/hc/grid_dark.svg create mode 100644 spec/helpers/portal_helper_spec.rb diff --git a/app/controllers/public/api/v1/portals/base_controller.rb b/app/controllers/public/api/v1/portals/base_controller.rb index 68619baf8..d9fec27b1 100644 --- a/app/controllers/public/api/v1/portals/base_controller.rb +++ b/app/controllers/public/api/v1/portals/base_controller.rb @@ -1,5 +1,6 @@ class Public::Api::V1::Portals::BaseController < PublicController before_action :show_plain_layout + before_action :set_color_scheme around_action :set_locale after_action :allow_iframe_requests @@ -9,6 +10,14 @@ class Public::Api::V1::Portals::BaseController < PublicController @is_plain_layout_enabled = params[:show_plain_layout] == 'true' end + def set_color_scheme + @theme = if %w[dark light].include?(params[:theme]) + params[:theme] + else + '' + end + end + def set_locale(&) switch_locale_with_portal(&) if params[:locale].present? switch_locale_with_article(&) if params[:article_slug].present? diff --git a/app/helpers/portal_helper.rb b/app/helpers/portal_helper.rb new file mode 100644 index 000000000..3551b5ac6 --- /dev/null +++ b/app/helpers/portal_helper.rb @@ -0,0 +1,11 @@ +module PortalHelper + def generate_portal_bg_color(portal_color, theme) + base_color = theme == 'dark' ? 'black' : 'white' + "color-mix(in srgb, #{portal_color} 10%, #{base_color})" + end + + def generate_portal_bg(portal_color, theme) + bg_image = theme == 'dark' ? 'grid_dark.svg' : 'grid.svg' + "background: url(/assets/images/hc/#{bg_image}) #{generate_portal_bg_color(portal_color, theme)}" + end +end diff --git a/app/javascript/portal/components/PublicSearchInput.vue b/app/javascript/portal/components/PublicSearchInput.vue index a1b36fd66..53099a08e 100644 --- a/app/javascript/portal/components/PublicSearchInput.vue +++ b/app/javascript/portal/components/PublicSearchInput.vue @@ -1,16 +1,16 @@