diff --git a/.circleci/config.yml b/.circleci/config.yml index 99ac1c29a..59702c139 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -93,8 +93,8 @@ jobs: exit 1 fi mkdir -p ~/tmp - curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/6.3.0/openapi-generator-cli-6.3.0.jar > ~/tmp/openapi-generator-cli-6.3.0.jar - java -jar ~/tmp/openapi-generator-cli-6.3.0.jar validate -i swagger/swagger.json + curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.19.0/openapi-generator-cli-7.19.0.jar > ~/tmp/openapi-generator-cli-7.19.0.jar + java -jar ~/tmp/openapi-generator-cli-7.19.0.jar validate -i swagger/swagger.json # Bundle audit - run: diff --git a/Gemfile b/Gemfile index 0636b7b2b..01c7a9f83 100644 --- a/Gemfile +++ b/Gemfile @@ -268,6 +268,7 @@ group :development, :test do gem 'seed_dump' gem 'shoulda-matchers' gem 'simplecov', '>= 0.21', require: false + gem 'skooma' gem 'spring' gem 'spring-watcher-listen' end diff --git a/Gemfile.lock b/Gemfile.lock index 7a7316e3c..cf07f32f6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -191,7 +191,7 @@ GEM coderay (1.1.3) commonmarker (0.23.10) concurrent-ruby (1.3.5) - connection_pool (2.5.3) + connection_pool (2.5.5) crack (1.0.0) bigdecimal rexml @@ -473,6 +473,12 @@ GEM hana (~> 1.3) regexp_parser (~> 2.0) uri_template (~> 0.7) + json_skooma (0.2.5) + bigdecimal + hana (~> 1.3) + regexp_parser (~> 2.0) + uri-idna (~> 0.2) + zeitwerk (~> 2.6) judoscale-rails (1.8.2) judoscale-ruby (= 1.8.2) railties @@ -736,7 +742,7 @@ GEM ffi (~> 1.0) redis (5.0.6) redis-client (>= 0.9.0) - redis-client (0.22.2) + redis-client (0.26.4) connection_pool redis-namespace (1.10.0) redis (>= 4) @@ -910,6 +916,9 @@ GEM simplecov_json_formatter (~> 0.1) simplecov-html (0.13.2) simplecov_json_formatter (0.1.4) + skooma (0.3.7) + json_skooma (~> 0.2.5) + zeitwerk (~> 2.6) slack-ruby-client (2.7.0) faraday (>= 2.0.1) faraday-mashify @@ -970,6 +979,7 @@ GEM unicode-emoji (4.0.4) uniform_notifier (1.17.0) uri (1.1.1) + uri-idna (0.3.1) uri_template (0.7.0) valid_email2 (5.2.6) activemodel (>= 3.2) @@ -1143,6 +1153,7 @@ DEPENDENCIES sidekiq_alive simplecov (>= 0.21) simplecov_json_formatter + skooma slack-ruby-client (~> 2.7.0) spring spring-watcher-listen diff --git a/VERSION_CW b/VERSION_CW index d782fca8f..4f89fb960 100644 --- a/VERSION_CW +++ b/VERSION_CW @@ -1 +1 @@ -4.11.1 +4.11.2 diff --git a/app/actions/contact_identify_action.rb b/app/actions/contact_identify_action.rb index bcf5a93c3..9afa5d019 100644 --- a/app/actions/contact_identify_action.rb +++ b/app/actions/contact_identify_action.rb @@ -104,7 +104,7 @@ class ContactIdentifyAction # blank identifier or email will throw unique index error # TODO: replace reject { |_k, v| v.blank? } with compact_blank when rails is upgraded @contact.discard_invalid_attrs if discard_invalid_attrs - @contact.save! + @contact.save! if @contact.changed? enqueue_avatar_job end diff --git a/app/controllers/api/v1/accounts/contacts_controller.rb b/app/controllers/api/v1/accounts/contacts_controller.rb index 14d4f2c89..dd5346bd6 100644 --- a/app/controllers/api/v1/accounts/contacts_controller.rb +++ b/app/controllers/api/v1/accounts/contacts_controller.rb @@ -201,7 +201,9 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController end def fetch_contact - @contact = Current.account.contacts.includes(contact_inboxes: [:inbox]).find(params[:id]) + contact_scope = Current.account.contacts + contact_scope = contact_scope.includes(contact_inboxes: [:inbox]) if @include_contact_inboxes + @contact = contact_scope.find(params[:id]) end def process_avatar_from_url diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index bcbf80355..3e513a4b2 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -100,7 +100,7 @@ class Api::V1::AccountsController < Api::BaseController end def check_signup_enabled - raise ActionController::RoutingError, 'Not Found' if GlobalConfigService.load('ENABLE_ACCOUNT_SIGNUP', 'false') == 'false' + raise ActionController::RoutingError, 'Not Found' unless GlobalConfigService.account_signup_enabled? end def validate_captcha diff --git a/app/controllers/api/v2/accounts_controller.rb b/app/controllers/api/v2/accounts_controller.rb index bed0a212a..5a19ddeed 100644 --- a/app/controllers/api/v2/accounts_controller.rb +++ b/app/controllers/api/v2/accounts_controller.rb @@ -58,7 +58,7 @@ class Api::V2::AccountsController < Api::BaseController end def check_signup_enabled - raise ActionController::RoutingError, 'Not Found' if GlobalConfigService.load('ENABLE_ACCOUNT_SIGNUP', 'false') == 'false' + raise ActionController::RoutingError, 'Not Found' unless GlobalConfigService.account_signup_enabled? end def validate_captcha diff --git a/app/controllers/devise_overrides/omniauth_callbacks_controller.rb b/app/controllers/devise_overrides/omniauth_callbacks_controller.rb index 900125670..af759af54 100644 --- a/app/controllers/devise_overrides/omniauth_callbacks_controller.rb +++ b/app/controllers/devise_overrides/omniauth_callbacks_controller.rb @@ -51,8 +51,7 @@ class DeviseOverrides::OmniauthCallbacksController < DeviseTokenAuth::OmniauthCa end def account_signup_allowed? - # set it to true by default, this is the behaviour across the app - GlobalConfigService.load('ENABLE_ACCOUNT_SIGNUP', 'false') != 'false' + GlobalConfigService.account_signup_enabled? end def resource_class(_mapping = nil) diff --git a/app/dashboards/user_dashboard.rb b/app/dashboards/user_dashboard.rb index 753b617ef..b499193cc 100644 --- a/app/dashboards/user_dashboard.rb +++ b/app/dashboards/user_dashboard.rb @@ -25,7 +25,7 @@ class UserDashboard < Administrate::BaseDashboard current_sign_in_ip: Field::String, last_sign_in_ip: Field::String, confirmation_token: Field::String, - confirmed_at: Field::DateTime, + confirmed_at: ConfirmedAtField, confirmation_sent_at: Field::DateTime, unconfirmed_email: Field::String, name: Field::String.with_options(searchable: true), diff --git a/app/fields/confirmed_at_field.rb b/app/fields/confirmed_at_field.rb new file mode 100644 index 000000000..67e04c4a0 --- /dev/null +++ b/app/fields/confirmed_at_field.rb @@ -0,0 +1,4 @@ +require 'administrate/field/base' + +class ConfirmedAtField < Administrate::Field::DateTime +end diff --git a/app/helpers/filters/filter_helper.rb b/app/helpers/filters/filter_helper.rb index fe03dae28..4f345676e 100644 --- a/app/helpers/filters/filter_helper.rb +++ b/app/helpers/filters/filter_helper.rb @@ -47,11 +47,15 @@ module Filters::FilterHelper def handle_additional_attributes(query_hash, filter_operator_value, data_type) if data_type == 'text_case_insensitive' - "LOWER(#{filter_config[:table_name]}.additional_attributes ->> '#{query_hash[:attribute_key]}') " \ - "#{filter_operator_value} #{query_hash[:query_operator]}" + ActiveRecord::Base.sanitize_sql_array( + ["LOWER(#{filter_config[:table_name]}.additional_attributes ->> ?) #{filter_operator_value} #{query_hash[:query_operator]}", + query_hash[:attribute_key]] + ) else - "#{filter_config[:table_name]}.additional_attributes ->> '#{query_hash[:attribute_key]}' " \ - "#{filter_operator_value} #{query_hash[:query_operator]} " + ActiveRecord::Base.sanitize_sql_array( + ["#{filter_config[:table_name]}.additional_attributes ->> ? #{filter_operator_value} #{query_hash[:query_operator]} ", + query_hash[:attribute_key]] + ) end end @@ -70,7 +74,7 @@ module Filters::FilterHelper def date_filter(current_filter, query_hash, filter_operator_value) "(#{filter_config[:table_name]}.#{query_hash[:attribute_key]})::#{current_filter['data_type']} " \ - "#{filter_operator_value}#{current_filter['data_type']} #{query_hash[:query_operator]}" + "#{filter_operator_value} #{query_hash[:query_operator]}" end def text_case_insensitive_filter(query_hash, filter_operator_value) diff --git a/app/javascript/dashboard/components-next/captain/assistant/AssistantPlayground.vue b/app/javascript/dashboard/components-next/captain/assistant/AssistantPlayground.vue index 69cbb9be5..51aae6477 100644 --- a/app/javascript/dashboard/components-next/captain/assistant/AssistantPlayground.vue +++ b/app/javascript/dashboard/components-next/captain/assistant/AssistantPlayground.vue @@ -18,10 +18,18 @@ const newMessage = ref(''); const isLoading = ref(false); const formatMessagesForApi = () => { - return messages.value.map(message => ({ - role: message.sender, - content: message.content, - })); + return messages.value.map(message => { + const payload = { + role: message.sender, + content: message.content, + }; + + if (message.sender === 'assistant' && message.agentName) { + payload.agent_name = message.agentName; + } + + return payload; + }); }; const resetConversation = () => { @@ -62,6 +70,7 @@ const sendMessage = async () => { messages.value.push({ content: data.response, sender: 'assistant', + agentName: data.agent_name, timestamp: new Date().toISOString(), }); } catch (error) { diff --git a/app/javascript/dashboard/components/widgets/conversation/CopilotEditorSection.vue b/app/javascript/dashboard/components/widgets/conversation/CopilotEditorSection.vue index b22ac308d..bdd537d92 100644 --- a/app/javascript/dashboard/components/widgets/conversation/CopilotEditorSection.vue +++ b/app/javascript/dashboard/components/widgets/conversation/CopilotEditorSection.vue @@ -78,7 +78,7 @@ const onSend = () => {
diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue index 81c424aec..c11aff8b0 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue @@ -162,7 +162,8 @@ export default { this.inReplyTo?.id && !this.isPrivate && this.inboxHasFeature(INBOX_FEATURES.REPLY_TO) && - !this.is360DialogWhatsAppChannel + !this.is360DialogWhatsAppChannel && + !this.copilot.isActive.value ); }, showWhatsappTemplates() { @@ -1464,7 +1465,7 @@ export default { } .reply-box__top { - @apply relative py-0 px-4 -mt-px; + @apply relative py-0 px-3 -mt-px; } .emoji-dialog { diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyToMessage.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyToMessage.vue index 1c8dc962d..67ad8ae0d 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ReplyToMessage.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ReplyToMessage.vue @@ -14,7 +14,7 @@ const emit = defineEmits(['dismiss']);