diff --git a/Gemfile b/Gemfile index 38dee9bc4..bee9eddc1 100644 --- a/Gemfile +++ b/Gemfile @@ -71,7 +71,7 @@ gem 'barnes' ##--- gems for authentication & authorization ---## gem 'devise', '>= 4.9.4' gem 'devise-secure_password', git: 'https://github.com/chatwoot/devise-secure_password', branch: 'chatwoot' -gem 'devise_token_auth' +gem 'devise_token_auth', '>= 1.2.3' # authorization gem 'jwt' gem 'pundit' @@ -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..2f890deaa 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) @@ -200,10 +200,10 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) - devise_token_auth (1.2.1) + devise_token_auth (1.2.3) bcrypt (~> 3.0) devise (> 3.5.2, < 5) - rails (>= 4.2.0, < 7.1) + rails (>= 4.2.0, < 7.2) diff-lcs (1.5.0) digest-crc (0.6.4) rake (>= 12.0.0, < 14.0.0) @@ -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) @@ -474,7 +474,7 @@ GEM uri net-http-persistent (4.0.2) connection_pool (~> 2.2) - net-imap (0.4.10) + net-imap (0.4.11) date net-protocol net-pop (0.1.2) @@ -489,15 +489,15 @@ GEM sidekiq newrelic_rpm (9.6.0) base64 - nio4r (2.7.1) - nokogiri (1.16.4) + nio4r (2.7.3) + 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) @@ -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) @@ -819,7 +819,7 @@ GEM working_hours (1.4.1) activesupport (>= 3.2) tzinfo - zeitwerk (2.6.13) + zeitwerk (2.6.14) PLATFORMS arm64-darwin-20 @@ -860,7 +860,7 @@ DEPENDENCIES debug (~> 1.8) devise (>= 4.9.4) devise-secure_password! - devise_token_auth + devise_token_auth (>= 1.2.3) dotenv-rails down elastic-apm @@ -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 diff --git a/app.json b/app.json index 4ee025f06..d50040814 100644 --- a/app.json +++ b/app.json @@ -55,7 +55,7 @@ "plan": "heroku-redis:mini" }, { - "plan": "heroku-postgresql:mini" + "plan": "heroku-postgresql:essential-0" } ], "stack": "heroku-20", diff --git a/app/builders/contact_inbox_with_contact_builder.rb b/app/builders/contact_inbox_with_contact_builder.rb index 6e913eda8..2f30093db 100644 --- a/app/builders/contact_inbox_with_contact_builder.rb +++ b/app/builders/contact_inbox_with_contact_builder.rb @@ -19,9 +19,9 @@ class ContactInboxWithContactBuilder ActiveRecord::Base.transaction(requires_new: true) do build_contact_with_contact_inbox - update_contact_avatar(@contact) unless @contact.avatar.attached? - @contact_inbox end + update_contact_avatar(@contact) unless @contact.avatar.attached? + @contact_inbox end private diff --git a/app/controllers/api/v1/accounts/bulk_actions_controller.rb b/app/controllers/api/v1/accounts/bulk_actions_controller.rb index 832f5a49b..34db47861 100644 --- a/app/controllers/api/v1/accounts/bulk_actions_controller.rb +++ b/app/controllers/api/v1/accounts/bulk_actions_controller.rb @@ -21,6 +21,6 @@ class Api::V1::Accounts::BulkActionsController < Api::V1::Accounts::BaseControll end def permitted_params - params.permit(:type, ids: [], fields: [:status, :assignee_id, :team_id], labels: [add: [], remove: []]) + params.permit(:type, :snoozed_until, ids: [], fields: [:status, :assignee_id, :team_id], labels: [add: [], remove: []]) end end diff --git a/app/controllers/api/v1/accounts/contacts_controller.rb b/app/controllers/api/v1/accounts/contacts_controller.rb index 729db34b5..250c64a86 100644 --- a/app/controllers/api/v1/accounts/contacts_controller.rb +++ b/app/controllers/api/v1/accounts/contacts_controller.rb @@ -46,7 +46,8 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController def export column_names = params['column_names'] - Account::ContactsExportJob.perform_later(Current.account.id, column_names, Current.user.email) + filter_params = { :payload => params.permit!['payload'], :label => params.permit!['label'] } + Account::ContactsExportJob.perform_later(Current.account.id, Current.user.id, column_names, filter_params) head :ok, message: I18n.t('errors.contacts.export.success') end @@ -61,7 +62,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController def show; end def filter - result = ::Contacts::FilterService.new(params.permit!, current_user).perform + result = ::Contacts::FilterService.new(Current.account, Current.user, params.permit!).perform contacts = result[:contacts] @contacts_count = result[:count] @contacts = fetch_contacts(contacts) diff --git a/app/javascript/dashboard/api/contacts.js b/app/javascript/dashboard/api/contacts.js index 61312dd24..85c4bba1d 100644 --- a/app/javascript/dashboard/api/contacts.js +++ b/app/javascript/dashboard/api/contacts.js @@ -77,8 +77,8 @@ class ContactAPI extends ApiClient { return axios.delete(`${this.url}/${contactId}/avatar`); } - exportContacts() { - return axios.get(`${this.url}/export`); + exportContacts(queryPayload) { + return axios.post(`${this.url}/export`, queryPayload); } } diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue index e7fae6e01..348d8572a 100644 --- a/app/javascript/dashboard/components/ChatList.vue +++ b/app/javascript/dashboard/components/ChatList.vue @@ -288,7 +288,6 @@ export default { foldersQuery: {}, showAddFoldersModal: false, showDeleteFoldersModal: false, - selectedConversations: [], selectedInboxes: [], isContextMenuOpen: false, appliedFilter: [], @@ -329,6 +328,7 @@ export default { inboxesList: 'inboxes/getInboxes', campaigns: 'campaigns/getAllCampaigns', labels: 'labels/getLabels', + selectedConversations: 'bulkActions/getSelectedConversationIds', }), hasAppliedFilters() { return this.appliedFilters.length !== 0; @@ -799,7 +799,7 @@ export default { }); }, resetBulkActions() { - this.selectedConversations = []; + this.$store.dispatch('bulkActions/clearSelectedConversationIds'); this.selectedInboxes = []; }, onBasicFilterChange(value, type) { @@ -830,12 +830,16 @@ export default { return this.selectedConversations.includes(id); }, selectConversation(conversationId, inboxId) { - this.selectedConversations.push(conversationId); + this.$store.dispatch( + 'bulkActions/setSelectedConversationIds', + conversationId + ); this.selectedInboxes.push(inboxId); }, deSelectConversation(conversationId, inboxId) { - this.selectedConversations = this.selectedConversations.filter( - item => item !== conversationId + this.$store.dispatch( + 'bulkActions/removeSelectedConversationIds', + conversationId ); this.selectedInboxes = this.selectedInboxes.filter( item => item !== inboxId @@ -843,7 +847,10 @@ export default { }, selectAllConversations(check) { if (check) { - this.selectedConversations = this.conversationList.map(item => item.id); + this.$store.dispatch( + 'bulkActions/setSelectedConversationIds', + this.conversationList.map(item => item.id) + ); this.selectedInboxes = this.conversationList.map(item => item.inbox_id); } else { this.resetBulkActions(); @@ -859,7 +866,7 @@ export default { assignee_id: agent.id, }, }); - this.selectedConversations = []; + this.$store.dispatch('bulkActions/clearSelectedConversationIds'); if (conversationId) { this.showAlert( this.$t( @@ -957,7 +964,7 @@ export default { add: labels, }, }); - this.selectedConversations = []; + this.$store.dispatch('bulkActions/clearSelectedConversationIds'); if (conversationId) { this.showAlert( this.$t( @@ -984,13 +991,13 @@ export default { team_id: team.id, }, }); - this.selectedConversations = []; + this.$store.dispatch('bulkActions/clearSelectedConversationIds'); this.showAlert(this.$t('BULK_ACTION.TEAMS.ASSIGN_SUCCESFUL')); } catch (err) { this.showAlert(this.$t('BULK_ACTION.TEAMS.ASSIGN_FAILED')); } }, - async onUpdateConversations(status) { + async onUpdateConversations(status, snoozedUntil) { try { await this.$store.dispatch('bulkActions/process', { type: 'Conversation', @@ -998,8 +1005,9 @@ export default { fields: { status, }, + snoozed_until: snoozedUntil, }); - this.selectedConversations = []; + this.$store.dispatch('bulkActions/clearSelectedConversationIds'); this.showAlert(this.$t('BULK_ACTION.UPDATE.UPDATE_SUCCESFUL')); } catch (err) { this.showAlert(this.$t('BULK_ACTION.UPDATE.UPDATE_FAILED')); diff --git a/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue b/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue index 3722ea208..aa566fd4d 100644 --- a/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue +++ b/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue @@ -5,6 +5,7 @@ +