From 07e33fd98a8e59c813b105a769383e7bcd7e3ae1 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Mon, 13 May 2024 13:32:11 -0700 Subject: [PATCH 1/7] chore: Switch models to gpt-4o (#9458) - Switch model to gpt-4o from gpt-4-turbo --- enterprise/app/models/enterprise/concerns/article.rb | 2 +- enterprise/lib/chat_gpt.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/enterprise/app/models/enterprise/concerns/article.rb b/enterprise/app/models/enterprise/concerns/article.rb index e230a3a28..799584568 100644 --- a/enterprise/app/models/enterprise/concerns/article.rb +++ b/enterprise/app/models/enterprise/concerns/article.rb @@ -66,7 +66,7 @@ module Enterprise::Concerns::Article { role: 'user', content: "title: #{title} \n description: #{description} \n content: #{content}" } ] headers = { 'Content-Type' => 'application/json', 'Authorization' => "Bearer #{ENV.fetch('OPENAI_API_KEY', nil)}" } - body = { model: 'gpt-4-turbo', messages: messages, response_format: { type: 'json_object' } }.to_json + body = { model: 'gpt-4o', messages: messages, response_format: { type: 'json_object' } }.to_json Rails.logger.info "Requesting Chat GPT with body: #{body}" response = HTTParty.post('https://api.openai.com/v1/chat/completions', headers: headers, body: body) Rails.logger.info "Chat GPT response: #{response.body}" diff --git a/enterprise/lib/chat_gpt.rb b/enterprise/lib/chat_gpt.rb index d13ec118f..44afbd641 100644 --- a/enterprise/lib/chat_gpt.rb +++ b/enterprise/lib/chat_gpt.rb @@ -4,7 +4,7 @@ class ChatGpt end def initialize(context_sections = '') - @model = 'gpt-4-0125-preview' + @model = 'gpt-4o' @messages = [system_message(context_sections)] end From e992283993e89e9b4120943395eb91d7b2414104 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Mon, 13 May 2024 16:07:56 -0700 Subject: [PATCH 2/7] fix: [Snyk] Security upgrade omniauth-rails_csrf_protection from 1.0.1 to 1.0.2 (#9454) fix: Gemfile & Gemfile.lock to reduce vulnerabilities The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-RUBY-RACK-1061917 Co-authored-by: snyk-bot --- Gemfile | 2 +- Gemfile.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 38dee9bc4..9241cc253 100644 --- a/Gemfile +++ b/Gemfile @@ -166,7 +166,7 @@ gem 'audited', '~> 5.4', '>= 5.4.1' # need for google auth gem 'omniauth', '>= 2.1.2' gem 'omniauth-google-oauth2', '>= 1.1.2' -gem 'omniauth-rails_csrf_protection', '~> 1.0' +gem 'omniauth-rails_csrf_protection', '~> 1.0', '>= 1.0.2' ## Gems for reponse bot # adds cosine similarity to postgres using vector extension diff --git a/Gemfile.lock b/Gemfile.lock index 5dc67bef1..f9298ee22 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -148,7 +148,7 @@ GEM barnes (0.0.9) multi_json (~> 1) statsd-ruby (~> 1.1) - base64 (0.1.1) + base64 (0.2.0) bcrypt (3.1.20) bigdecimal (3.1.7) bindex (0.8.1) @@ -369,7 +369,7 @@ GEM mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) httpclient (2.8.3) - i18n (1.14.4) + i18n (1.14.5) concurrent-ruby (~> 1.0) image_processing (1.12.2) mini_magick (>= 4.9.5, < 5) @@ -524,7 +524,7 @@ GEM omniauth-oauth2 (1.8.0) oauth2 (>= 1.4, < 3) omniauth (~> 2.0) - omniauth-rails_csrf_protection (1.0.1) + omniauth-rails_csrf_protection (1.0.2) actionpack (>= 4.2) omniauth (~> 2.0) openssl (3.1.0) @@ -904,7 +904,7 @@ DEPENDENCIES omniauth (>= 2.1.2) omniauth-google-oauth2 (>= 1.1.2) omniauth-oauth2 - omniauth-rails_csrf_protection (~> 1.0) + omniauth-rails_csrf_protection (~> 1.0, >= 1.0.2) pg pg_search pgvector From 1d4798a3bf4115c80b127a03a3aab0d44383b8ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 18:12:02 -0700 Subject: [PATCH 3/7] chore(deps): bump nokogiri from 1.16.4 to 1.16.5 (#9459) Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.16.4 to 1.16.5. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.16.4...v1.16.5) --- updated-dependencies: - dependency-name: nokogiri dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f9298ee22..2aa13fea9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -490,14 +490,14 @@ GEM newrelic_rpm (9.6.0) base64 nio4r (2.7.1) - nokogiri (1.16.4) + nokogiri (1.16.5) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.16.4-arm64-darwin) + nokogiri (1.16.5-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.4-x86_64-darwin) + nokogiri (1.16.5-x86_64-darwin) racc (~> 1.4) - nokogiri (1.16.4-x86_64-linux) + nokogiri (1.16.5-x86_64-linux) racc (~> 1.4) oauth (1.1.0) oauth-tty (~> 1.0, >= 1.0.1) From d54492f7b52c217c09d3e288751523a595800aec Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Tue, 14 May 2024 14:19:02 -0700 Subject: [PATCH 4/7] chore: Add debug statement in spec (#9466) - Add a debug statement to check the failed specs --- spec/controllers/api/v1/accounts/contacts_controller_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/controllers/api/v1/accounts/contacts_controller_spec.rb b/spec/controllers/api/v1/accounts/contacts_controller_spec.rb index 815cecc62..97eddc171 100644 --- a/spec/controllers/api/v1/accounts/contacts_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/contacts_controller_spec.rb @@ -97,6 +97,8 @@ RSpec.describe 'Contacts API', type: :request do expect(response).to have_http_status(:success) response_body = response.parsed_body + # TODO: this spec has been flaky for a while, so adding a debug statement to see the response + Rails.logger.info(response_body) expect(response_body['payload'].first['email']).to eq(contact.email) expect(response_body['payload'].first['id']).to eq(contact.id) expect(response_body['payload'].last['email']).to eq(contact_4.email) From e98e27dc1fd5a862d8b79d6aa093e5790dc09a8c Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Tue, 14 May 2024 14:32:17 -0700 Subject: [PATCH 5/7] chore: Make IP_LOOKUP_BASE_URL configurable (#9467) Since we download the GeoIP database during worker/server initialization, there is a high chance of spamming the server with too many requests for downloads, especially if the number of web and worker nodes is high. This PR provides the ability to specify a custom URL for the GeoLite database download, configurable via an environment variable. This helps in distributing the load and avoiding server overload during the initialization process --- lib/tasks/ip_lookup.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/ip_lookup.rake b/lib/tasks/ip_lookup.rake index d0db9dbc5..3225caffa 100644 --- a/lib/tasks/ip_lookup.rake +++ b/lib/tasks/ip_lookup.rake @@ -13,7 +13,7 @@ namespace :ip_lookup do Rails.logger.info '[rake ip_lookup:setup] Fetch GeoLite2-City database' begin - base_url = 'https://download.maxmind.com/app/geoip_download' + base_url = ENV.fetch('IP_LOOKUP_BASE_URL', 'https://download.maxmind.com/app/geoip_download') source_file = Down.download( "#{base_url}?edition_id=GeoLite2-City&suffix=tar.gz&license_key=#{ip_lookup_api_key}" ) From 5a289776de5e8f77f134680c8fe54da903419a9b Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Wed, 15 May 2024 09:48:55 +0530 Subject: [PATCH 6/7] fix: Widget phone number input country undefined in onSelectCountry (#9457) * fix: Widget phone number input country undefined in onSelectCountry * chore: Minor fix --- .../widget/components/Form/PhoneInput.vue | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/app/javascript/widget/components/Form/PhoneInput.vue b/app/javascript/widget/components/Form/PhoneInput.vue index 8a37d02c9..c7fafa916 100644 --- a/app/javascript/widget/components/Form/PhoneInput.vue +++ b/app/javascript/widget/components/Form/PhoneInput.vue @@ -39,6 +39,9 @@ v-on-clickaway="closeDropdown" :class="dropdownBackgroundClass" class="country-dropdown h-48 overflow-y-auto z-10 absolute top-12 px-0 pt-0 pl-1 pr-1 pb-1 rounded shadow-lg" + @keydown.up="moveSelectionUp" + @keydown.down="moveSelectionDown" + @keydown.enter="onSelect" >
import countries from 'shared/constants/countries.js'; import FluentIcon from 'shared/components/FluentIcon/Index.vue'; -import mentionSelectionKeyboardMixin from 'dashboard/components/widgets/mentions/mentionSelectionKeyboardMixin.js'; import FormulateInputMixin from '@braid/vue-formulate/src/FormulateInputMixin'; import darkModeMixin from 'widget/mixins/darkModeMixin'; @@ -93,7 +95,7 @@ export default { components: { FluentIcon, }, - mixins: [mentionSelectionKeyboardMixin, FormulateInputMixin, darkModeMixin], + mixins: [FormulateInputMixin, darkModeMixin], props: { placeholder: { type: String, @@ -185,6 +187,14 @@ export default { ); }, }, + watch: { + items(newItems) { + if (newItems.length < this.selectedIndex + 1) { + // Reset the selected index to 0 if the new items length is less than the selected index. + this.selectedIndex = 0; + } + }, + }, methods: { setContextValue(code) { // This function is used to set the context value. @@ -235,7 +245,26 @@ export default { this.scrollToFocusedOrActiveItem(this.focusedOrActiveItem('focus')); }); }, + adjustSelection(direction) { + if (!this.showDropdown) return; + const maxIndex = this.items.length - 1; + if (direction === 'up') { + this.selectedIndex = + this.selectedIndex <= 0 ? maxIndex : this.selectedIndex - 1; + } else if (direction === 'down') { + this.selectedIndex = + this.selectedIndex >= maxIndex ? 0 : this.selectedIndex + 1; + } + this.adjustScroll(); + }, + moveSelectionUp() { + this.adjustSelection('up'); + }, + moveSelectionDown() { + this.adjustSelection('down'); + }, onSelect() { + if (!this.showDropdown || this.selectedIndex === -1) return; this.onSelectCountry(this.items[this.selectedIndex]); }, scrollToFocusedOrActiveItem(item) { From bc8736c08e8e5f68ad4281d15ab240319b0e2ab5 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 15 May 2024 10:45:03 +0530 Subject: [PATCH 7/7] fix: widget does not load when navigating on pages with view transition [CW-3249] (#9443) * feat: add ids to each element * feat: restore elements for apps that use view transitions * fix: remove generator check condition * feat: handle turbolinks * fix: new body handling * chore: undo debug changes --- app/javascript/packs/sdk.js | 25 ++++++++++++++++++++++++- app/javascript/sdk/DOMHelpers.js | 19 +++++++++++++++++++ app/javascript/sdk/IFrameHelper.js | 1 + app/javascript/sdk/bubbleHelpers.js | 1 + 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/app/javascript/packs/sdk.js b/app/javascript/packs/sdk.js index 9bb8314ca..84cf5fe2d 100755 --- a/app/javascript/packs/sdk.js +++ b/app/javascript/packs/sdk.js @@ -10,14 +10,37 @@ import { getUserCookieName, hasUserKeys, } from '../sdk/cookieHelpers'; -import { addClasses, removeClasses } from '../sdk/DOMHelpers'; +import { + addClasses, + removeClasses, + restoreWidgetInDOM, +} from '../sdk/DOMHelpers'; import { setCookieWithDomain } from '../sdk/cookieHelpers'; import { SDK_SET_BUBBLE_VISIBILITY } from 'shared/constants/sharedFrameEvents'; + const runSDK = ({ baseUrl, websiteToken }) => { if (window.$chatwoot) { return; } + if (window.Turbo) { + // if this is a Rails Turbo app + document.addEventListener('turbo:before-render', event => + restoreWidgetInDOM(event.detail.newBody) + ); + } + + if (window.Turbolinks) { + document.addEventListener('turbolinks:before-render', event => { + restoreWidgetInDOM(event.data.newBody); + }); + } + + // if this is an astro app + document.addEventListener('astro:before-swap', event => + restoreWidgetInDOM(event.newDocument.body) + ); + const chatwootSettings = window.chatwootSettings || {}; let locale = chatwootSettings.locale; let baseDomain = chatwootSettings.baseDomain; diff --git a/app/javascript/sdk/DOMHelpers.js b/app/javascript/sdk/DOMHelpers.js index 47a45cc78..f8ba55337 100644 --- a/app/javascript/sdk/DOMHelpers.js +++ b/app/javascript/sdk/DOMHelpers.js @@ -4,9 +4,28 @@ import { IFrameHelper } from './IFrameHelper'; export const loadCSS = () => { const css = document.createElement('style'); css.innerHTML = `${SDK_CSS}`; + css.id = 'cw-widget-styles'; document.body.appendChild(css); }; +// This is a method specific to Turbo +// The body replacing strategy removes Chatwoot styles +// as well as the widget, this help us get it back +export const restoreElement = (id, newBody) => { + const element = document.getElementById(id); + const newElement = newBody.querySelector(`#${id}`); + + if (element && !newElement) { + newBody.appendChild(element); + } +}; + +export const restoreWidgetInDOM = newBody => { + restoreElement('cw-bubble-holder', newBody); + restoreElement('cw-widget-holder', newBody); + restoreElement('cw-widget-styles', newBody); +}; + export const addClasses = (elm, classes) => { elm.classList.add(...classes.split(' ')); }; diff --git a/app/javascript/sdk/IFrameHelper.js b/app/javascript/sdk/IFrameHelper.js index 2166b4304..3687fa311 100644 --- a/app/javascript/sdk/IFrameHelper.js +++ b/app/javascript/sdk/IFrameHelper.js @@ -78,6 +78,7 @@ export const IFrameHelper = { } addClasses(widgetHolder, holderClassName); + widgetHolder.id = 'cw-widget-holder'; widgetHolder.appendChild(iframe); body.appendChild(widgetHolder); IFrameHelper.initPostMessageCommunication(); diff --git a/app/javascript/sdk/bubbleHelpers.js b/app/javascript/sdk/bubbleHelpers.js index 54401a82c..600c1444a 100644 --- a/app/javascript/sdk/bubbleHelpers.js +++ b/app/javascript/sdk/bubbleHelpers.js @@ -61,6 +61,7 @@ export const createBubbleHolder = hideMessageBubble => { addClasses(bubbleHolder, 'woot-hidden'); } addClasses(bubbleHolder, 'woot--bubble-holder'); + bubbleHolder.id = 'cw-bubble-holder'; body.appendChild(bubbleHolder); };