mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 02:57:57 +00:00 
			
		
		
		
	| @@ -7,7 +7,7 @@ defaults: &defaults | ||||
|   working_directory: ~/build | ||||
|   docker: | ||||
|     # specify the version you desire here | ||||
|     - image: cimg/ruby:3.1.3-browsers | ||||
|     - image: cimg/ruby:3.2.2-browsers | ||||
|  | ||||
|     # Specify service dependencies here if necessary | ||||
|     # CircleCI maintains a library of pre-built images | ||||
|   | ||||
| @@ -30,7 +30,7 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ | ||||
|     npm | ||||
|  | ||||
| # Install rbenv and ruby | ||||
| ARG RUBY_VERSION="3.1.3" | ||||
| ARG RUBY_VERSION="3.2.2" | ||||
| RUN git clone https://github.com/rbenv/rbenv.git ~/.rbenv \ | ||||
|     &&  echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc \ | ||||
|     &&  echo 'eval "$(rbenv init -)"' >> ~/.bashrc | ||||
|   | ||||
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -67,3 +67,10 @@ test/cypress/videos/* | ||||
| # yalc for local testing | ||||
| .yalc | ||||
| yalc.lock | ||||
|  | ||||
| /public/packs | ||||
| /public/packs-test | ||||
| /node_modules | ||||
| /yarn-error.log | ||||
| yarn-debug.log* | ||||
| .yarn-integrity | ||||
|   | ||||
							
								
								
									
										33
									
								
								.rubocop.yml
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								.rubocop.yml
									
									
									
									
									
								
							| @@ -164,6 +164,39 @@ Performance/CollectionLiteralInLoop: | ||||
|     - 'db/migrate/20210315101919_enable_email_channel.rb' | ||||
| RSpec/NamedSubject: | ||||
|   Enabled: false | ||||
| Style/RedundantConstantBase: | ||||
|   Enabled: false | ||||
| Rails/RootPathnameMethods: | ||||
|   Enabled: false | ||||
| RSpec/Rails/MinitestAssertions: | ||||
|   Enabled: false | ||||
| RSpec/Rails/InferredSpecType: | ||||
|   Enabled: false | ||||
| RSpec/IndexedLet: | ||||
|   Enabled: false | ||||
| RSpec/MatchArray: | ||||
|   Enabled: false | ||||
| Rails/ResponseParsedBody: | ||||
|   Enabled: false | ||||
| RSpec/FactoryBot/ConsistentParenthesesStyle: | ||||
|   Enabled: false | ||||
| Rails/ThreeStateBooleanColumn: | ||||
|   Enabled: false | ||||
| Rails/Pluck: | ||||
|   Enabled: false | ||||
| Rails/TopLevelHashWithIndifferentAccess: | ||||
|   Enabled: false | ||||
| Rails/ActionOrder: | ||||
|   Enabled: false | ||||
| Style/ArrayIntersect: | ||||
|   Enabled: false | ||||
| RSpec/NoExpectationExample: | ||||
|   Enabled: false | ||||
| Style/RedundantReturn: | ||||
|   Enabled: false | ||||
| Rails/I18nLocaleTexts: | ||||
|   Enabled: false | ||||
|  | ||||
| # we should bring this down | ||||
| RSpec/MultipleMemoizedHelpers: | ||||
|   Max: 14 | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| 3.1.3 | ||||
| 3.2.2 | ||||
|   | ||||
							
								
								
									
										1
									
								
								.slugignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.slugignore
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| /spec | ||||
							
								
								
									
										46
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								Gemfile
									
									
									
									
									
								
							| @@ -1,10 +1,10 @@ | ||||
| source 'https://rubygems.org' | ||||
|  | ||||
| ruby '3.1.3' | ||||
| ruby '3.2.2' | ||||
|  | ||||
| ##-- base gems for rails --## | ||||
| gem 'rack-cors', require: 'rack/cors' | ||||
| gem 'rails', '~> 6.1', '>= 6.1.7.3' | ||||
| gem 'rails', '~> 7' | ||||
| # Reduces boot times through caching; required in config/boot.rb | ||||
| gem 'bootsnap', require: false | ||||
|  | ||||
| @@ -36,19 +36,19 @@ gem 'json_schemer' | ||||
| # Rack middleware for blocking & throttling abusive requests | ||||
| gem 'rack-attack' | ||||
| # a utility tool for streaming, flexible and safe downloading of remote files | ||||
| gem 'down', '~> 5.0' | ||||
| gem 'down' | ||||
| # authentication type to fetch and send mail over oauth2.0 | ||||
| gem 'gmail_xoauth' | ||||
| # Prevent CSV injection | ||||
| gem 'csv-safe' | ||||
| # Support message translation | ||||
| gem 'google-cloud-translate' | ||||
|  | ||||
| ##-- for active storage --## | ||||
| gem 'aws-sdk-s3', require: false | ||||
| gem 'azure-storage-blob', require: false | ||||
| # original gem isn't maintained actively | ||||
| # we wanted updated version of faraday which is a dependency for slack-ruby-client | ||||
| gem 'azure-storage-blob', git: 'https://github.com/chatwoot/azure-storage-ruby', branch: 'chatwoot', require: false | ||||
| gem 'google-cloud-storage', require: false | ||||
| gem 'image_processing', '~> 1.12.2' | ||||
| gem 'image_processing' | ||||
|  | ||||
| ##-- gems for database --# | ||||
| gem 'groupdate' | ||||
| @@ -62,13 +62,13 @@ gem 'activerecord-import' | ||||
| gem 'dotenv-rails' | ||||
| gem 'foreman' | ||||
| gem 'puma' | ||||
| gem 'webpacker', '~> 5.4', '>= 5.4.3' | ||||
| gem 'webpacker' | ||||
| # metrics on heroku | ||||
| gem 'barnes' | ||||
|  | ||||
| ##--- gems for authentication & authorization ---## | ||||
| gem 'devise' | ||||
| gem 'devise-secure_password', '~> 2.0', git: 'https://github.com/chatwoot/devise-secure_password' | ||||
| gem 'devise-secure_password', git: 'https://github.com/chatwoot/devise-secure_password', branch: 'chatwoot' | ||||
| gem 'devise_token_auth' | ||||
| # authorization | ||||
| gem 'jwt' | ||||
| @@ -81,7 +81,6 @@ gem 'administrate' | ||||
| gem 'wisper', '2.0.0' | ||||
|  | ||||
| ##--- gems for channels ---## | ||||
| # TODO: bump up gem to 2.0 | ||||
| gem 'facebook-messenger' | ||||
| gem 'line-bot-api' | ||||
| gem 'twilio-ruby', '~> 5.66' | ||||
| @@ -91,9 +90,14 @@ gem 'twitty', '~> 0.1.5' | ||||
| # facebook client | ||||
| gem 'koala' | ||||
| # slack client | ||||
| gem 'slack-ruby-client' | ||||
| gem 'slack-ruby-client', '~> 2.0.0' | ||||
| # for dialogflow integrations | ||||
| gem 'google-cloud-dialogflow' | ||||
| gem 'google-cloud-dialogflow-v2' | ||||
| gem 'grpc' | ||||
| # Translate integrations | ||||
| # 'google-cloud-translate' gem depends on faraday 2.0 version | ||||
| # this dependency breaks the slack-ruby-client gem | ||||
| gem 'google-cloud-translate-v3' | ||||
|  | ||||
| ##-- apm and error monitoring ---# | ||||
| # loaded only when environment variables are set. | ||||
| @@ -108,9 +112,9 @@ gem 'sentry-ruby', require: false | ||||
| gem 'sentry-sidekiq', require: false | ||||
|  | ||||
| ##-- background job processing --## | ||||
| gem 'sidekiq', '~> 6.4.2' | ||||
| gem 'sidekiq' | ||||
| # We want cron jobs | ||||
| gem 'sidekiq-cron', '~> 1.6', '>= 1.6.0' | ||||
| gem 'sidekiq-cron' | ||||
|  | ||||
| ##-- Push notification service --## | ||||
| gem 'fcm' | ||||
| @@ -129,7 +133,10 @@ gem 'procore-sift' | ||||
|  | ||||
| # parse email | ||||
| gem 'email_reply_trimmer' | ||||
| gem 'html2text' | ||||
|  | ||||
| # TODO: we might have to fork this gem since 0.3.1 has hard depency on nokogir 1.10. | ||||
| # and this gem hasn't been updated for a while. | ||||
| gem 'html2text', git: 'https://github.com/chatwoot/html2text_ruby', branch: 'chatwoot' | ||||
|  | ||||
| # to calculate working hours | ||||
| gem 'working_hours' | ||||
| @@ -144,11 +151,6 @@ gem 'stripe' | ||||
| ## to populate db with sample data | ||||
| gem 'faker' | ||||
|  | ||||
| # Can remove this in rails 7 | ||||
| gem 'net-imap', require: false | ||||
| gem 'net-pop', require: false | ||||
| gem 'net-smtp', require: false | ||||
|  | ||||
| # Include logrange conditionally in intializer using env variable | ||||
| gem 'lograge', '~> 0.12.0', require: false | ||||
|  | ||||
| @@ -189,7 +191,7 @@ end | ||||
|  | ||||
| group :test do | ||||
|   # Cypress in rails. | ||||
|   gem 'cypress-on-rails', '~> 1.13', '>= 1.13.1' | ||||
|   gem 'cypress-on-rails' | ||||
|   # fast cleaning of database | ||||
|   gem 'database_cleaner' | ||||
|   # mock http calls | ||||
| @@ -211,7 +213,7 @@ group :development, :test do | ||||
|   gem 'mock_redis' | ||||
|   gem 'pry-rails' | ||||
|   gem 'rspec_junit_formatter' | ||||
|   gem 'rspec-rails', '~> 5.0.3' | ||||
|   gem 'rspec-rails' | ||||
|   gem 'rubocop', require: false | ||||
|   gem 'rubocop-performance', require: false | ||||
|   gem 'rubocop-rails', require: false | ||||
|   | ||||
							
								
								
									
										647
									
								
								Gemfile.lock
									
									
									
									
									
								
							
							
						
						
									
										647
									
								
								Gemfile.lock
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -3,7 +3,7 @@ class ApiController < ApplicationController | ||||
|  | ||||
|   def index | ||||
|     render json: { version: Chatwoot.config[:version], | ||||
|                    timestamp: Time.now.utc.to_formatted_s(:db), | ||||
|                    timestamp: Time.now.utc.to_fs(:db), | ||||
|                    queue_services: redis_status, | ||||
|                    data_services: postgres_status } | ||||
|   end | ||||
|   | ||||
| @@ -41,7 +41,7 @@ class WidgetsController < ActionController::Base | ||||
|       source_id: @auth_token_params[:source_id] | ||||
|     ) | ||||
|  | ||||
|     @contact = @contact_inbox ? @contact_inbox.contact : nil | ||||
|     @contact = @contact_inbox&.contact | ||||
|   end | ||||
|  | ||||
|   def build_contact | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| <template> | ||||
|   <div v-on-clickaway="onCloseAgentList" class="bulk-action__agents"> | ||||
|     <div class="triangle" :style="cssVars"> | ||||
|     <div class="triangle"> | ||||
|       <svg height="12" viewBox="0 0 24 12" width="24"> | ||||
|         <path | ||||
|           d="M20 12l-8-8-12 12" | ||||
| @@ -104,14 +104,13 @@ import { mapGetters } from 'vuex'; | ||||
| import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue'; | ||||
| import Spinner from 'shared/components/Spinner'; | ||||
| import { mixin as clickaway } from 'vue-clickaway'; | ||||
| import bulkActionsMixin from 'dashboard/mixins/bulkActionsMixin.js'; | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     Thumbnail, | ||||
|     Spinner, | ||||
|   }, | ||||
|   mixins: [clickaway, bulkActionsMixin], | ||||
|   mixins: [clickaway], | ||||
|   props: { | ||||
|     selectedInboxes: { | ||||
|       type: Array, | ||||
| @@ -240,7 +239,7 @@ export default { | ||||
|     display: block; | ||||
|     z-index: var(--z-index-one); | ||||
|     position: absolute; | ||||
|     top: calc(var(--space-slab) * -1); | ||||
|     top: var(--space-minus-slab); | ||||
|     right: var(--triangle-position); | ||||
|     text-align: left; | ||||
|   } | ||||
|   | ||||
| @@ -58,7 +58,7 @@ | ||||
|       <transition name="popover-animation"> | ||||
|         <label-actions | ||||
|           v-if="showLabelActions" | ||||
|           triangle-position="8.5" | ||||
|           class="label-actions-box" | ||||
|           @assign="assignLabels" | ||||
|           @close="showLabelActions = false" | ||||
|         /> | ||||
| @@ -66,12 +66,12 @@ | ||||
|       <transition name="popover-animation"> | ||||
|         <update-actions | ||||
|           v-if="showUpdateActions" | ||||
|           class="update-actions-box" | ||||
|           :selected-inboxes="selectedInboxes" | ||||
|           :conversation-count="conversations.length" | ||||
|           :show-resolve="!showResolvedAction" | ||||
|           :show-reopen="!showOpenAction" | ||||
|           :show-snooze="!showSnoozedAction" | ||||
|           triangle-position="5.6" | ||||
|           @update="updateConversations" | ||||
|           @close="showUpdateActions = false" | ||||
|         /> | ||||
| @@ -79,9 +79,9 @@ | ||||
|       <transition name="popover-animation"> | ||||
|         <agent-selector | ||||
|           v-if="showAgentsList" | ||||
|           class="agent-actions-box" | ||||
|           :selected-inboxes="selectedInboxes" | ||||
|           :conversation-count="conversations.length" | ||||
|           triangle-position="2.8" | ||||
|           @select="submit" | ||||
|           @close="showAgentsList = false" | ||||
|         /> | ||||
| @@ -89,7 +89,7 @@ | ||||
|       <transition name="popover-animation"> | ||||
|         <team-actions | ||||
|           v-if="showTeamsList" | ||||
|           triangle-position="0.2" | ||||
|           class="team-actions-box" | ||||
|           @assign-team="assignTeam" | ||||
|           @close="showTeamsList = false" | ||||
|         /> | ||||
| @@ -247,4 +247,17 @@ export default { | ||||
|   opacity: 0; | ||||
|   transform: scale(0.95); | ||||
| } | ||||
|  | ||||
| .label-actions-box { | ||||
|   --triangle-position: 8.5rem; | ||||
| } | ||||
| .update-actions-box { | ||||
|   --triangle-position: 5.6rem; | ||||
| } | ||||
| .agent-actions-box { | ||||
|   --triangle-position: 2.8rem; | ||||
| } | ||||
| .team-actions-box { | ||||
|   --triangle-position: 0.2rem; | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| <template> | ||||
|   <div v-on-clickaway="onClose" class="labels-container"> | ||||
|     <div class="triangle" :style="cssVars"> | ||||
|     <div class="triangle"> | ||||
|       <svg height="12" viewBox="0 0 24 12" width="24"> | ||||
|         <path | ||||
|           d="M20 12l-8-8-12 12" | ||||
| @@ -75,10 +75,9 @@ | ||||
| <script> | ||||
| import { mixin as clickaway } from 'vue-clickaway'; | ||||
| import { mapGetters } from 'vuex'; | ||||
| import bulkActionsMixin from 'dashboard/mixins/bulkActionsMixin.js'; | ||||
|  | ||||
| export default { | ||||
|   mixins: [clickaway, bulkActionsMixin], | ||||
|   mixins: [clickaway], | ||||
|   data() { | ||||
|     return { | ||||
|       query: '', | ||||
| @@ -207,7 +206,7 @@ export default { | ||||
|     position: absolute; | ||||
|     right: var(--triangle-position); | ||||
|     text-align: left; | ||||
|     top: calc(var(--space-slab) * -1); | ||||
|     top: var(--space-minus-slab); | ||||
|     z-index: var(--z-index-one); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| <template> | ||||
|   <div v-on-clickaway="onClose" class="bulk-action__teams"> | ||||
|     <div class="triangle" :style="cssVars"> | ||||
|     <div class="triangle"> | ||||
|       <svg height="12" viewBox="0 0 24 12" width="24"> | ||||
|         <path | ||||
|           d="M20 12l-8-8-12 12" | ||||
| @@ -59,9 +59,8 @@ | ||||
| <script> | ||||
| import { mixin as clickaway } from 'vue-clickaway'; | ||||
| import { mapGetters } from 'vuex'; | ||||
| import bulkActionsMixin from 'dashboard/mixins/bulkActionsMixin.js'; | ||||
| export default { | ||||
|   mixins: [clickaway, bulkActionsMixin], | ||||
|   mixins: [clickaway], | ||||
|   data() { | ||||
|     return { | ||||
|       query: '', | ||||
| @@ -141,7 +140,7 @@ export default { | ||||
|     display: block; | ||||
|     z-index: var(--z-index-one); | ||||
|     position: absolute; | ||||
|     top: calc(var(--space-slab) * -1); | ||||
|     top: var(--space-minus-slab); | ||||
|     right: var(--triangle-position); | ||||
|     text-align: left; | ||||
|   } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| <template> | ||||
|   <div v-on-clickaway="onClose" class="actions-container"> | ||||
|     <div class="triangle" :style="cssVars"> | ||||
|     <div class="triangle"> | ||||
|       <svg height="12" viewBox="0 0 24 12" width="24"> | ||||
|         <path | ||||
|           d="M20 12l-8-8-12 12" | ||||
| @@ -45,14 +45,13 @@ | ||||
| import { mixin as clickaway } from 'vue-clickaway'; | ||||
| import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue'; | ||||
| import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue'; | ||||
| import bulkActionsMixin from 'dashboard/mixins/bulkActionsMixin.js'; | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     WootDropdownItem, | ||||
|     WootDropdownMenu, | ||||
|   }, | ||||
|   mixins: [clickaway, bulkActionsMixin], | ||||
|   mixins: [clickaway], | ||||
|   props: { | ||||
|     selectedInboxes: { | ||||
|       type: Array, | ||||
| @@ -156,7 +155,7 @@ export default { | ||||
|     position: absolute; | ||||
|     right: var(--triangle-position); | ||||
|     text-align: left; | ||||
|     top: calc(var(--space-slab) * -1); | ||||
|     top: var(--space-minus-slab); | ||||
|     z-index: var(--z-index-one); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -4,7 +4,7 @@ class ApplicationMailbox < ActionMailbox::Base | ||||
|   # Last part is the regex for the UUID | ||||
|   # Eg: email should be something like : reply+6bdc3f4d-0bec-4515-a284-5d916fdde489@domain.com | ||||
|   REPLY_EMAIL_UUID_PATTERN = /^reply\+([0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12})$/i | ||||
|   CONVERSATION_MESSAGE_ID_PATTERN = %r{conversation/([a-zA-Z0-9\-]*?)/messages/(\d+?)@(\w+\.\w+)} | ||||
|   CONVERSATION_MESSAGE_ID_PATTERN = %r{conversation/([a-zA-Z0-9-]*?)/messages/(\d+?)@(\w+\.\w+)} | ||||
|  | ||||
|   # routes as a reply to existing conversations | ||||
|   routing( | ||||
|   | ||||
| @@ -62,7 +62,7 @@ class Attachment < ApplicationRecord | ||||
|  | ||||
|   def thumb_url | ||||
|     if file.attached? && file.representable? | ||||
|       url_for(file.representation(resize: '250x250')) | ||||
|       url_for(file.representation(resize_to_fill: [250, nil])) | ||||
|     else | ||||
|       '' | ||||
|     end | ||||
|   | ||||
| @@ -11,7 +11,7 @@ module Avatarable | ||||
|   end | ||||
|  | ||||
|   def avatar_url | ||||
|     return url_for(avatar.representation(resize: '250x250')) if avatar.attached? && avatar.representable? | ||||
|     return url_for(avatar.representation(resize_to_fill: [250, nil])) if avatar.attached? && avatar.representable? | ||||
|  | ||||
|     '' | ||||
|   end | ||||
|   | ||||
| @@ -10,7 +10,7 @@ module Pubsubable | ||||
|  | ||||
|   def pubsub_token | ||||
|     # backfills tokens for existing records | ||||
|     regenerate_pubsub_token if self[:pubsub_token].blank? | ||||
|     regenerate_pubsub_token if self[:pubsub_token].blank? && persisted? | ||||
|     self[:pubsub_token] | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -1,3 +1,3 @@ | ||||
| json.identifier @inbox_channel.identifier | ||||
| json.identity_validation_enabled @inbox_channel.hmac_mandatory | ||||
| json.partial! 'public/api/v1/models/inbox.json.jbuilder', resource: @inbox_channel.inbox | ||||
| json.partial! 'public/api/v1/models/inbox', formats: [:json], resource: @inbox_channel.inbox | ||||
|   | ||||
| @@ -7,20 +7,20 @@ json.position category.position | ||||
| json.related_categories do | ||||
|   if category.related_categories.any? | ||||
|     json.array! category.related_categories.each do |related_category| | ||||
|       json.partial! partial: 'public/api/v1/models/associated_category.json.jbuilder', category: related_category | ||||
|       json.partial! partial: 'public/api/v1/models/associated_category', formats: [:json], category: related_category | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| if category.parent_category.present? | ||||
|   json.parent_category do | ||||
|     json.partial! partial: 'public/api/v1/models/associated_category.json.jbuilder', category: category.parent_category | ||||
|     json.partial! partial: 'public/api/v1/models/associated_category', formats: [:json], category: category.parent_category | ||||
|   end | ||||
| end | ||||
|  | ||||
| if category.root_category.present? | ||||
|   json.root_category do | ||||
|     json.partial! partial: 'public/api/v1/models/associated_category.json.jbuilder', category: category.root_category | ||||
|     json.partial! partial: 'public/api/v1/models/associated_category', formats: [:json], category: category.root_category | ||||
|   end | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| json.payload do | ||||
|   json.array! @articles, partial: 'public/api/v1/models/article.json.jbuilder', as: :article | ||||
|   json.array! @articles, partial: 'public/api/v1/models/article', formats: [:json], as: :article | ||||
| end | ||||
|  | ||||
| json.meta do | ||||
|   | ||||
| @@ -1,3 +1,3 @@ | ||||
| json.payload do | ||||
|   json.array! @categories, partial: 'public/api/v1/models/category.json.jbuilder', as: :category | ||||
|   json.array! @categories, partial: 'public/api/v1/models/category', formats: [:json], as: :category | ||||
| end | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| json.array! @portals, partial: 'public/api/v1/models/portal.json.jbuilder', as: :portal | ||||
| json.array! @portals, partial: 'public/api/v1/models/portal', formats: [:json], as: :portal | ||||
|   | ||||
							
								
								
									
										0
									
								
								bin/validate_push
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								bin/validate_push
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -30,7 +30,7 @@ end | ||||
| module Chatwoot | ||||
|   class Application < Rails::Application | ||||
|     # Initialize configuration defaults for originally generated Rails version. | ||||
|     config.load_defaults 6.0 | ||||
|     config.load_defaults 7.0 | ||||
|  | ||||
|     config.eager_load_paths << Rails.root.join('lib') | ||||
|     config.eager_load_paths << Rails.root.join('enterprise/lib') | ||||
| @@ -51,7 +51,7 @@ module Chatwoot | ||||
|     # https://stackoverflow.com/questions/72970170/upgrading-to-rails-6-1-6-1-causes-psychdisallowedclass-tried-to-load-unspecif | ||||
|     # https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017 | ||||
|     # FIX ME : fixes breakage of installation config. we need to migrate. | ||||
|     config.active_record.yaml_column_permitted_classes = [HashWithIndifferentAccess] | ||||
|     config.active_record.yaml_column_permitted_classes = [ActiveSupport::HashWithIndifferentAccess] | ||||
|   end | ||||
|  | ||||
|   def self.config | ||||
|   | ||||
| @@ -4,7 +4,7 @@ default: &default | ||||
|   host: <%= ENV.fetch('POSTGRES_HOST', 'localhost') %> | ||||
|   port: <%= ENV.fetch('POSTGRES_PORT', '5432') %> | ||||
|    # ref: https://github.com/mperham/sidekiq/issues/2985#issuecomment-531097962 | ||||
|   pool: <%= Sidekiq.server? ? Sidekiq.options[:concurrency] : ENV.fetch('RAILS_MAX_THREADS', 5) %> | ||||
|   pool: <%= Sidekiq.server? ? ENV.fetch('SIDEKIQ_CONCURRENCY', 10) : ENV.fetch('RAILS_MAX_THREADS', 5) %> | ||||
|   variables: | ||||
|     # we are setting this value to be close to the racktimeout value. we will iterate and reduce this value going forward | ||||
|     statement_timeout: <%= ENV["POSTGRES_STATEMENT_TIMEOUT"] || "14s" %> | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| # Alfred | ||||
| # Add here as you use it for more features | ||||
| # Used for Round Robin, Conversation Emails & Online Presence | ||||
| $alfred = ConnectionPool.new(size: 5, timeout: 3) do | ||||
| $alfred = ConnectionPool.new(size: 5, timeout: 1) do | ||||
|   redis = Rails.env.test? ? MockRedis.new : Redis.new(Redis::Config.app) | ||||
|   Redis::Namespace.new('alfred', redis: redis, warning: true) | ||||
| end | ||||
|  | ||||
| # Velma : Determined protector | ||||
| # used in rack attack | ||||
| $velma = ConnectionPool.new(size: 5, timeout: 3) do | ||||
| $velma = ConnectionPool.new(size: 5, timeout: 1) do | ||||
|   config = Rails.env.test? ? MockRedis.new : Redis.new(Redis::Config.app) | ||||
|   Redis::Namespace.new('velma', redis: config, warning: true) | ||||
| end | ||||
|   | ||||
| @@ -1,45 +0,0 @@ | ||||
| # Be sure to restart your server when you modify this file. | ||||
| # | ||||
| # This file contains migration options to ease your Rails 6.0 upgrade. | ||||
| # | ||||
| # Once upgraded flip defaults one by one to migrate to the new default. | ||||
| # | ||||
| # Read the Guide for Upgrading Ruby on Rails for more info on each option. | ||||
|  | ||||
| # Don't force requests from old versions of IE to be UTF-8 encoded. | ||||
| # Rails.application.config.action_view.default_enforce_utf8 = false | ||||
|  | ||||
| # Embed purpose and expiry metadata inside signed and encrypted | ||||
| # cookies for increased security. | ||||
| # | ||||
| # This option is not backwards compatible with earlier Rails versions. | ||||
| # It's best enabled when your entire app is migrated and stable on 6.0. | ||||
| # Rails.application.config.action_dispatch.use_cookies_with_metadata = true | ||||
|  | ||||
| # Change the return value of `ActionDispatch::Response#content_type` to Content-Type header without modification. | ||||
| # Rails.application.config.action_dispatch.return_only_media_type_on_content_type = false | ||||
|  | ||||
| # Return false instead of self when enqueuing is aborted from a callback. | ||||
| # Rails.application.config.active_job.return_false_on_aborted_enqueue = true | ||||
|  | ||||
| # Send Active Storage analysis and purge jobs to dedicated queues. | ||||
| # Rails.application.config.active_storage.queues.analysis = :active_storage_analysis | ||||
| # Rails.application.config.active_storage.queues.purge    = :active_storage_purge | ||||
|  | ||||
| # When assigning to a collection of attachments declared via `has_many_attached`, replace existing | ||||
| # attachments instead of appending. Use #attach to add new attachments without replacing existing ones. | ||||
| # Rails.application.config.active_storage.replace_on_assign_to_many = true | ||||
|  | ||||
| # Use ActionMailer::MailDeliveryJob for sending parameterized and normal mail. | ||||
| # | ||||
| # The default delivery jobs (ActionMailer::Parameterized::DeliveryJob, ActionMailer::DeliveryJob), | ||||
| # will be removed in Rails 6.1. This setting is not backwards compatible with earlier Rails versions. | ||||
| # If you send mail in the background, job workers need to have a copy of | ||||
| # MailDeliveryJob to ensure all delivery jobs are processed properly. | ||||
| # Make sure your entire app is migrated and stable on 6.0 before using this setting. | ||||
| # Rails.application.config.action_mailer.delivery_job = "ActionMailer::MailDeliveryJob" | ||||
|  | ||||
| # Enable the same cache key to be reused when the object being cached of type | ||||
| # `ActiveRecord::Relation` changes by moving the volatile information (max updated at and count) | ||||
| # of the relation's cache key into the cache version to support recycling cache key. | ||||
| # Rails.application.config.active_record.collection_cache_versioning = true | ||||
							
								
								
									
										11
									
								
								config/initializers/permissions_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								config/initializers/permissions_policy.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| # Define an application-wide HTTP permissions policy. For further | ||||
| # information see https://developers.google.com/web/updates/2018/06/feature-policy | ||||
| # | ||||
| # Rails.application.config.permissions_policy do |f| | ||||
| #   f.camera      :none | ||||
| #   f.gyroscope   :none | ||||
| #   f.microphone  :none | ||||
| #   f.usb         :none | ||||
| #   f.fullscreen  :self | ||||
| #   f.payment     :self, "https://secure.example.com" | ||||
| # end | ||||
| @@ -4,7 +4,7 @@ | ||||
| # pick it up automatically. | ||||
| --- | ||||
| :verbose: false | ||||
| :concurrency: <%= ENV.fetch("SIDEKIQ_CONCURRENCY", 5) %> | ||||
| :concurrency: <%= ENV.fetch("SIDEKIQ_CONCURRENCY", 10) %> | ||||
| :timeout: 25 | ||||
| :max_retries: 3 | ||||
|  | ||||
| @@ -32,4 +32,4 @@ | ||||
| production: | ||||
|   :concurrency: <%= ENV.fetch("SIDEKIQ_CONCURRENCY", 10) %> | ||||
| staging: | ||||
|   :concurrency: <%= ENV.fetch("SIDEKIQ_CONCURRENCY", 5) %> | ||||
|   :concurrency: <%= ENV.fetch("SIDEKIQ_CONCURRENCY", 10) %> | ||||
|   | ||||
| @@ -0,0 +1,8 @@ | ||||
| # This migration comes from active_storage (originally 20211119233751) | ||||
| class RemoveNotNullOnActiveStorageBlobsChecksum < ActiveRecord::Migration[6.0] | ||||
|   def change | ||||
|     return unless table_exists?(:active_storage_blobs) | ||||
|  | ||||
|     change_column_null(:active_storage_blobs, :checksum, true) | ||||
|   end | ||||
| end | ||||
							
								
								
									
										283
									
								
								db/schema.rb
									
									
									
									
									
								
							
							
						
						
									
										283
									
								
								db/schema.rb
									
									
									
									
									
								
							| @@ -10,8 +10,7 @@ | ||||
| # | ||||
| # It's strongly recommended that you check this file into your version control system. | ||||
|  | ||||
| ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|  | ||||
| ActiveRecord::Schema[7.0].define(version: 2023_04_26_130150) do | ||||
|   # These are extensions that must be enabled in order to support this database | ||||
|   enable_extension "pg_stat_statements" | ||||
|   enable_extension "pg_trgm" | ||||
| @@ -22,8 +21,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "owner_type" | ||||
|     t.bigint "owner_id" | ||||
|     t.string "token" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["owner_type", "owner_id"], name: "index_access_tokens_on_owner_type_and_owner_id" | ||||
|     t.index ["token"], name: "index_access_tokens_on_token", unique: true | ||||
|   end | ||||
| @@ -33,9 +32,9 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.bigint "user_id" | ||||
|     t.integer "role", default: 0 | ||||
|     t.bigint "inviter_id" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "active_at" | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.datetime "active_at", precision: nil | ||||
|     t.integer "availability", default: 0, null: false | ||||
|     t.boolean "auto_offline", default: true, null: false | ||||
|     t.index ["account_id", "user_id"], name: "uniq_user_id_per_account_id", unique: true | ||||
| @@ -45,8 +44,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|  | ||||
|   create_table "accounts", id: :serial, force: :cascade do |t| | ||||
|     t.string "name", null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.datetime "updated_at", precision: nil, null: false | ||||
|     t.integer "locale", default: 0 | ||||
|     t.string "domain", limit: 100 | ||||
|     t.string "support_email", limit: 100 | ||||
| @@ -62,8 +61,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "status", default: 0, null: false | ||||
|     t.string "message_id", null: false | ||||
|     t.string "message_checksum", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["message_id", "message_checksum"], name: "index_action_mailbox_inbound_emails_uniqueness", unique: true | ||||
|   end | ||||
|  | ||||
| @@ -72,7 +71,7 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "record_type", null: false | ||||
|     t.bigint "record_id", null: false | ||||
|     t.bigint "blob_id", null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id" | ||||
|     t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true | ||||
|   end | ||||
| @@ -83,8 +82,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "content_type" | ||||
|     t.text "metadata" | ||||
|     t.bigint "byte_size", null: false | ||||
|     t.string "checksum", null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.string "checksum" | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.string "service_name", null: false | ||||
|     t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true | ||||
|   end | ||||
| @@ -99,8 +98,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "inbox_id" | ||||
|     t.integer "agent_bot_id" | ||||
|     t.integer "status", default: 0 | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.integer "account_id" | ||||
|   end | ||||
|  | ||||
| @@ -108,8 +107,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "name" | ||||
|     t.string "description" | ||||
|     t.string "outgoing_url" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.bigint "account_id" | ||||
|     t.integer "bot_type", default: 0 | ||||
|     t.jsonb "bot_config", default: {} | ||||
| @@ -126,8 +125,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.text "content" | ||||
|     t.integer "status" | ||||
|     t.integer "views" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.bigint "author_id" | ||||
|     t.bigint "associated_article_id" | ||||
|     t.jsonb "meta", default: {} | ||||
| @@ -145,8 +144,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.float "coordinates_long", default: 0.0 | ||||
|     t.integer "message_id", null: false | ||||
|     t.integer "account_id", null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.datetime "updated_at", precision: nil, null: false | ||||
|     t.string "fallback_title" | ||||
|     t.string "extension" | ||||
|     t.index ["account_id"], name: "index_attachments_on_account_id" | ||||
| @@ -167,7 +166,7 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "comment" | ||||
|     t.string "remote_address" | ||||
|     t.string "request_uuid" | ||||
|     t.datetime "created_at" | ||||
|     t.datetime "created_at", precision: nil | ||||
|     t.index ["associated_type", "associated_id"], name: "associated_index" | ||||
|     t.index ["auditable_type", "auditable_id", "version"], name: "auditable_index" | ||||
|     t.index ["created_at"], name: "index_audits_on_created_at" | ||||
| @@ -182,8 +181,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "event_name", null: false | ||||
|     t.jsonb "conditions", default: "{}", null: false | ||||
|     t.jsonb "actions", default: "{}", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.boolean "active", default: true, null: false | ||||
|     t.index ["account_id"], name: "index_automation_rules_on_account_id" | ||||
|   end | ||||
| @@ -198,12 +197,12 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.bigint "account_id", null: false | ||||
|     t.bigint "inbox_id", null: false | ||||
|     t.jsonb "trigger_rules", default: {} | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.integer "campaign_type", default: 0, null: false | ||||
|     t.integer "campaign_status", default: 0, null: false | ||||
|     t.jsonb "audience", default: [] | ||||
|     t.datetime "scheduled_at" | ||||
|     t.datetime "scheduled_at", precision: nil | ||||
|     t.boolean "trigger_only_during_business_hours", default: false | ||||
|     t.index ["account_id"], name: "index_campaigns_on_account_id" | ||||
|     t.index ["campaign_status"], name: "index_campaigns_on_campaign_status" | ||||
| @@ -216,8 +215,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "account_id", null: false | ||||
|     t.string "short_code" | ||||
|     t.text "content" | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.datetime "updated_at", precision: nil, null: false | ||||
|   end | ||||
|  | ||||
|   create_table "categories", force: :cascade do |t| | ||||
| @@ -226,8 +225,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "name" | ||||
|     t.text "description" | ||||
|     t.integer "position" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.string "locale", default: "en" | ||||
|     t.string "slug", null: false | ||||
|     t.bigint "parent_category_id" | ||||
| @@ -242,8 +241,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|   create_table "channel_api", force: :cascade do |t| | ||||
|     t.integer "account_id", null: false | ||||
|     t.string "webhook_url" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.string "identifier" | ||||
|     t.string "hmac_token" | ||||
|     t.boolean "hmac_mandatory", default: false | ||||
| @@ -256,15 +255,15 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "account_id", null: false | ||||
|     t.string "email", null: false | ||||
|     t.string "forward_to_email", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.boolean "imap_enabled", default: false | ||||
|     t.string "imap_address", default: "" | ||||
|     t.integer "imap_port", default: 0 | ||||
|     t.string "imap_login", default: "" | ||||
|     t.string "imap_password", default: "" | ||||
|     t.boolean "imap_enable_ssl", default: true | ||||
|     t.datetime "imap_inbox_synced_at" | ||||
|     t.datetime "imap_inbox_synced_at", precision: nil | ||||
|     t.boolean "smtp_enabled", default: false | ||||
|     t.string "smtp_address", default: "" | ||||
|     t.integer "smtp_port", default: 0 | ||||
| @@ -286,8 +285,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "user_access_token", null: false | ||||
|     t.string "page_access_token", null: false | ||||
|     t.integer "account_id", null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.datetime "updated_at", precision: nil, null: false | ||||
|     t.string "instagram_id" | ||||
|     t.index ["page_id", "account_id"], name: "index_channel_facebook_pages_on_page_id_and_account_id", unique: true | ||||
|     t.index ["page_id"], name: "index_channel_facebook_pages_on_page_id" | ||||
| @@ -298,8 +297,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "line_channel_id", null: false | ||||
|     t.string "line_channel_secret", null: false | ||||
|     t.string "line_channel_token", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["line_channel_id"], name: "index_channel_line_on_line_channel_id", unique: true | ||||
|   end | ||||
|  | ||||
| @@ -308,8 +307,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "phone_number", null: false | ||||
|     t.string "provider", default: "default" | ||||
|     t.jsonb "provider_config", default: {} | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["phone_number"], name: "index_channel_sms_on_phone_number", unique: true | ||||
|   end | ||||
|  | ||||
| @@ -317,8 +316,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "bot_name" | ||||
|     t.integer "account_id", null: false | ||||
|     t.string "bot_token", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["bot_token"], name: "index_channel_telegram_on_bot_token", unique: true | ||||
|   end | ||||
|  | ||||
| @@ -327,8 +326,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "auth_token", null: false | ||||
|     t.string "account_sid", null: false | ||||
|     t.integer "account_id", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.integer "medium", default: 0 | ||||
|     t.string "messaging_service_sid" | ||||
|     t.index ["account_sid", "phone_number"], name: "index_channel_twilio_sms_on_account_sid_and_phone_number", unique: true | ||||
| @@ -341,8 +340,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "twitter_access_token", null: false | ||||
|     t.string "twitter_access_token_secret", null: false | ||||
|     t.integer "account_id", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.boolean "tweets_enabled", default: true | ||||
|     t.index ["account_id", "profile_id"], name: "index_channel_twitter_profiles_on_account_id_and_profile_id", unique: true | ||||
|   end | ||||
| @@ -350,8 +349,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|   create_table "channel_web_widgets", id: :serial, force: :cascade do |t| | ||||
|     t.string "website_url" | ||||
|     t.integer "account_id" | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.datetime "updated_at", precision: nil, null: false | ||||
|     t.string "website_token" | ||||
|     t.string "widget_color", default: "#1f93ff" | ||||
|     t.string "welcome_title" | ||||
| @@ -372,10 +371,10 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "phone_number", null: false | ||||
|     t.string "provider", default: "default" | ||||
|     t.jsonb "provider_config", default: {} | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.jsonb "message_templates", default: {} | ||||
|     t.datetime "message_templates_last_updated" | ||||
|     t.datetime "message_templates_last_updated", precision: nil | ||||
|     t.index ["phone_number"], name: "index_channel_whatsapp_on_phone_number", unique: true | ||||
|   end | ||||
|  | ||||
| @@ -383,8 +382,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.bigint "contact_id" | ||||
|     t.bigint "inbox_id" | ||||
|     t.string "source_id", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.boolean "hmac_verified", default: false | ||||
|     t.string "pubsub_token" | ||||
|     t.index ["contact_id"], name: "index_contact_inboxes_on_contact_id" | ||||
| @@ -399,12 +398,12 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "email" | ||||
|     t.string "phone_number" | ||||
|     t.integer "account_id", null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.datetime "updated_at", precision: nil, null: false | ||||
|     t.jsonb "additional_attributes", default: {} | ||||
|     t.string "identifier" | ||||
|     t.jsonb "custom_attributes", default: {} | ||||
|     t.datetime "last_activity_at" | ||||
|     t.datetime "last_activity_at", precision: nil | ||||
|     t.index "lower((email)::text), account_id", name: "index_contacts_on_lower_email_account_id" | ||||
|     t.index ["account_id"], name: "index_contacts_on_account_id" | ||||
|     t.index ["email", "account_id"], name: "uniq_email_per_account_contact", unique: true | ||||
| @@ -417,8 +416,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.bigint "account_id", null: false | ||||
|     t.bigint "user_id", null: false | ||||
|     t.bigint "conversation_id", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["account_id"], name: "index_conversation_participants_on_account_id" | ||||
|     t.index ["conversation_id"], name: "index_conversation_participants_on_conversation_id" | ||||
|     t.index ["user_id", "conversation_id"], name: "index_conversation_participants_on_user_id_and_conversation_id", unique: true | ||||
| @@ -430,23 +429,23 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "inbox_id", null: false | ||||
|     t.integer "status", default: 0, null: false | ||||
|     t.integer "assignee_id" | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.datetime "updated_at", precision: nil, null: false | ||||
|     t.bigint "contact_id" | ||||
|     t.integer "display_id", null: false | ||||
|     t.datetime "contact_last_seen_at" | ||||
|     t.datetime "agent_last_seen_at" | ||||
|     t.datetime "contact_last_seen_at", precision: nil | ||||
|     t.datetime "agent_last_seen_at", precision: nil | ||||
|     t.jsonb "additional_attributes", default: {} | ||||
|     t.bigint "contact_inbox_id" | ||||
|     t.uuid "uuid", default: -> { "gen_random_uuid()" }, null: false | ||||
|     t.string "identifier" | ||||
|     t.datetime "last_activity_at", default: -> { "CURRENT_TIMESTAMP" }, null: false | ||||
|     t.datetime "last_activity_at", precision: nil, default: -> { "CURRENT_TIMESTAMP" }, null: false | ||||
|     t.bigint "team_id" | ||||
|     t.bigint "campaign_id" | ||||
|     t.datetime "snoozed_until" | ||||
|     t.datetime "snoozed_until", precision: nil | ||||
|     t.jsonb "custom_attributes", default: {} | ||||
|     t.datetime "assignee_last_seen_at" | ||||
|     t.datetime "first_reply_created_at" | ||||
|     t.datetime "assignee_last_seen_at", precision: nil | ||||
|     t.datetime "first_reply_created_at", precision: nil | ||||
|     t.integer "priority" | ||||
|     t.index ["account_id", "display_id"], name: "index_conversations_on_account_id_and_display_id", unique: true | ||||
|     t.index ["account_id", "id"], name: "index_conversations_on_id_and_account_id" | ||||
| @@ -474,8 +473,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.text "feedback_message" | ||||
|     t.bigint "contact_id", null: false | ||||
|     t.bigint "assigned_agent_id" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["account_id"], name: "index_csat_survey_responses_on_account_id" | ||||
|     t.index ["assigned_agent_id"], name: "index_csat_survey_responses_on_assigned_agent_id" | ||||
|     t.index ["contact_id"], name: "index_csat_survey_responses_on_contact_id" | ||||
| @@ -490,8 +489,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "default_value" | ||||
|     t.integer "attribute_model", default: 0 | ||||
|     t.bigint "account_id" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.text "attribute_description" | ||||
|     t.jsonb "attribute_values", default: [] | ||||
|     t.index ["account_id"], name: "index_custom_attribute_definitions_on_account_id" | ||||
| @@ -504,8 +503,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.jsonb "query", default: "{}", null: false | ||||
|     t.bigint "account_id", null: false | ||||
|     t.bigint "user_id", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["account_id"], name: "index_custom_filters_on_account_id" | ||||
|     t.index ["user_id"], name: "index_custom_filters_on_user_id" | ||||
|   end | ||||
| @@ -515,8 +514,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.jsonb "content", default: [] | ||||
|     t.bigint "account_id", null: false | ||||
|     t.bigint "user_id" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["account_id"], name: "index_dashboard_apps_on_account_id" | ||||
|     t.index ["user_id"], name: "index_dashboard_apps_on_user_id" | ||||
|   end | ||||
| @@ -528,8 +527,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.text "processing_errors" | ||||
|     t.integer "total_records" | ||||
|     t.integer "processed_records" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["account_id"], name: "index_data_imports_on_account_id" | ||||
|   end | ||||
|  | ||||
| @@ -539,8 +538,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "account_id" | ||||
|     t.integer "template_type", default: 1 | ||||
|     t.integer "locale", default: 0, null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["name", "account_id"], name: "index_email_templates_on_name_and_account_id", unique: true | ||||
|   end | ||||
|  | ||||
| @@ -548,15 +547,15 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "account_id", null: false | ||||
|     t.integer "category_id", null: false | ||||
|     t.string "name" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|   end | ||||
|  | ||||
|   create_table "inbox_members", id: :serial, force: :cascade do |t| | ||||
|     t.integer "user_id", null: false | ||||
|     t.integer "inbox_id", null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.datetime "updated_at", precision: nil, null: false | ||||
|     t.index ["inbox_id", "user_id"], name: "index_inbox_members_on_inbox_id_and_user_id", unique: true | ||||
|     t.index ["inbox_id"], name: "index_inbox_members_on_inbox_id" | ||||
|   end | ||||
| @@ -565,8 +564,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "channel_id", null: false | ||||
|     t.integer "account_id", null: false | ||||
|     t.string "name", null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.datetime "updated_at", precision: nil, null: false | ||||
|     t.string "channel_type" | ||||
|     t.boolean "enable_auto_assignment", default: true | ||||
|     t.boolean "greeting_enabled", default: false | ||||
| @@ -589,8 +588,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|   create_table "installation_configs", force: :cascade do |t| | ||||
|     t.string "name", null: false | ||||
|     t.jsonb "serialized_value", default: {}, null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.boolean "locked", default: true, null: false | ||||
|     t.index ["name", "created_at"], name: "index_installation_configs_on_name_and_created_at", unique: true | ||||
|     t.index ["name"], name: "index_installation_configs_on_name", unique: true | ||||
| @@ -604,8 +603,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "hook_type", default: 0 | ||||
|     t.string "reference_id" | ||||
|     t.string "access_token" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.jsonb "settings", default: {} | ||||
|   end | ||||
|  | ||||
| @@ -615,8 +614,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "color", default: "#1f93ff", null: false | ||||
|     t.boolean "show_on_sidebar" | ||||
|     t.bigint "account_id" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["account_id"], name: "index_labels_on_account_id" | ||||
|     t.index ["title", "account_id"], name: "index_labels_on_title_and_account_id", unique: true | ||||
|   end | ||||
| @@ -628,8 +627,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.bigint "created_by_id" | ||||
|     t.bigint "updated_by_id" | ||||
|     t.jsonb "actions", default: {}, null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["account_id"], name: "index_macros_on_account_id" | ||||
|   end | ||||
|  | ||||
| @@ -637,9 +636,9 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.bigint "user_id", null: false | ||||
|     t.bigint "conversation_id", null: false | ||||
|     t.bigint "account_id", null: false | ||||
|     t.datetime "mentioned_at", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "mentioned_at", precision: nil, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["account_id"], name: "index_mentions_on_account_id" | ||||
|     t.index ["conversation_id"], name: "index_mentions_on_conversation_id" | ||||
|     t.index ["user_id", "conversation_id"], name: "index_mentions_on_user_id_and_conversation_id", unique: true | ||||
| @@ -652,8 +651,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "inbox_id", null: false | ||||
|     t.integer "conversation_id", null: false | ||||
|     t.integer "message_type", null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.datetime "updated_at", precision: nil, null: false | ||||
|     t.boolean "private", default: false | ||||
|     t.integer "status", default: 0 | ||||
|     t.string "source_id" | ||||
| @@ -678,8 +677,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.bigint "account_id", null: false | ||||
|     t.bigint "contact_id", null: false | ||||
|     t.bigint "user_id" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["account_id"], name: "index_notes_on_account_id" | ||||
|     t.index ["contact_id"], name: "index_notes_on_contact_id" | ||||
|     t.index ["user_id"], name: "index_notes_on_user_id" | ||||
| @@ -689,8 +688,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "account_id" | ||||
|     t.integer "user_id" | ||||
|     t.integer "email_flags", default: 0, null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.integer "push_flags", default: 0, null: false | ||||
|     t.index ["account_id", "user_id"], name: "by_account_user", unique: true | ||||
|   end | ||||
| @@ -699,8 +698,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.bigint "user_id", null: false | ||||
|     t.integer "subscription_type", null: false | ||||
|     t.jsonb "subscription_attributes", default: {}, null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.string "identifier" | ||||
|     t.index ["identifier"], name: "index_notification_subscriptions_on_identifier", unique: true | ||||
|     t.index ["user_id"], name: "index_notification_subscriptions_on_user_id" | ||||
| @@ -714,9 +713,9 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.bigint "primary_actor_id", null: false | ||||
|     t.string "secondary_actor_type" | ||||
|     t.bigint "secondary_actor_id" | ||||
|     t.datetime "read_at" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "read_at", precision: nil | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["account_id"], name: "index_notifications_on_account_id" | ||||
|     t.index ["primary_actor_type", "primary_actor_id"], name: "uniq_primary_actor_per_account_notifications" | ||||
|     t.index ["secondary_actor_type", "secondary_actor_id"], name: "uniq_secondary_actor_per_account_notifications" | ||||
| @@ -727,8 +726,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.bigint "platform_app_id", null: false | ||||
|     t.string "permissible_type", null: false | ||||
|     t.bigint "permissible_id", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["permissible_type", "permissible_id"], name: "index_platform_app_permissibles_on_permissibles" | ||||
|     t.index ["platform_app_id", "permissible_id", "permissible_type"], name: "unique_permissibles_index", unique: true | ||||
|     t.index ["platform_app_id"], name: "index_platform_app_permissibles_on_platform_app_id" | ||||
| @@ -736,15 +735,15 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|  | ||||
|   create_table "platform_apps", force: :cascade do |t| | ||||
|     t.string "name", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|   end | ||||
|  | ||||
|   create_table "portal_members", force: :cascade do |t| | ||||
|     t.bigint "portal_id" | ||||
|     t.bigint "user_id" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["portal_id", "user_id"], name: "index_portal_members_on_portal_id_and_user_id", unique: true | ||||
|     t.index ["user_id", "portal_id"], name: "index_portal_members_on_user_id_and_portal_id", unique: true | ||||
|   end | ||||
| @@ -758,8 +757,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "homepage_link" | ||||
|     t.string "page_title" | ||||
|     t.text "header_text" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.jsonb "config", default: {"allowed_locales"=>["en"]} | ||||
|     t.boolean "archived", default: false | ||||
|     t.index ["custom_domain"], name: "index_portals_on_custom_domain", unique: true | ||||
| @@ -777,8 +776,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|   create_table "related_categories", force: :cascade do |t| | ||||
|     t.bigint "category_id" | ||||
|     t.bigint "related_category_id" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["category_id", "related_category_id"], name: "index_related_categories_on_category_id_and_related_category_id", unique: true | ||||
|     t.index ["related_category_id", "category_id"], name: "index_related_categories_on_related_category_id_and_category_id", unique: true | ||||
|   end | ||||
| @@ -790,11 +789,11 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "inbox_id" | ||||
|     t.integer "user_id" | ||||
|     t.integer "conversation_id" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.float "value_in_business_hours" | ||||
|     t.datetime "event_start_time" | ||||
|     t.datetime "event_end_time" | ||||
|     t.datetime "event_start_time", precision: nil | ||||
|     t.datetime "event_end_time", precision: nil | ||||
|     t.index ["account_id"], name: "index_reporting_events_on_account_id" | ||||
|     t.index ["conversation_id"], name: "index_reporting_events_on_conversation_id" | ||||
|     t.index ["created_at"], name: "index_reporting_events_on_created_at" | ||||
| @@ -810,7 +809,7 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "tagger_type" | ||||
|     t.integer "tagger_id" | ||||
|     t.string "context", limit: 128 | ||||
|     t.datetime "created_at" | ||||
|     t.datetime "created_at", precision: nil | ||||
|     t.index ["context"], name: "index_taggings_on_context" | ||||
|     t.index ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true | ||||
|     t.index ["tag_id"], name: "index_taggings_on_tag_id" | ||||
| @@ -832,8 +831,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|   create_table "team_members", force: :cascade do |t| | ||||
|     t.bigint "team_id", null: false | ||||
|     t.bigint "user_id", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["team_id", "user_id"], name: "index_team_members_on_team_id_and_user_id", unique: true | ||||
|     t.index ["team_id"], name: "index_team_members_on_team_id" | ||||
|     t.index ["user_id"], name: "index_team_members_on_user_id" | ||||
| @@ -844,8 +843,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.text "description" | ||||
|     t.boolean "allow_auto_assign", default: true | ||||
|     t.bigint "account_id", null: false | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.index ["account_id"], name: "index_teams_on_account_id" | ||||
|     t.index ["name", "account_id"], name: "index_teams_on_name_and_account_id", unique: true | ||||
|   end | ||||
| @@ -854,8 +853,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "name" | ||||
|     t.string "auth_key" | ||||
|     t.integer "account_id" | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.datetime "updated_at", precision: nil, null: false | ||||
|   end | ||||
|  | ||||
|   create_table "users", id: :serial, force: :cascade do |t| | ||||
| @@ -863,23 +862,23 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.string "uid", default: "", null: false | ||||
|     t.string "encrypted_password", default: "", null: false | ||||
|     t.string "reset_password_token" | ||||
|     t.datetime "reset_password_sent_at" | ||||
|     t.datetime "remember_created_at" | ||||
|     t.datetime "reset_password_sent_at", precision: nil | ||||
|     t.datetime "remember_created_at", precision: nil | ||||
|     t.integer "sign_in_count", default: 0, null: false | ||||
|     t.datetime "current_sign_in_at" | ||||
|     t.datetime "last_sign_in_at" | ||||
|     t.datetime "current_sign_in_at", precision: nil | ||||
|     t.datetime "last_sign_in_at", precision: nil | ||||
|     t.string "current_sign_in_ip" | ||||
|     t.string "last_sign_in_ip" | ||||
|     t.string "confirmation_token" | ||||
|     t.datetime "confirmed_at" | ||||
|     t.datetime "confirmation_sent_at" | ||||
|     t.datetime "confirmed_at", precision: nil | ||||
|     t.datetime "confirmation_sent_at", precision: nil | ||||
|     t.string "unconfirmed_email" | ||||
|     t.string "name", null: false | ||||
|     t.string "display_name" | ||||
|     t.string "email" | ||||
|     t.json "tokens" | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.datetime "created_at", precision: nil, null: false | ||||
|     t.datetime "updated_at", precision: nil, null: false | ||||
|     t.string "pubsub_token" | ||||
|     t.integer "availability", default: 0 | ||||
|     t.jsonb "ui_settings", default: {} | ||||
| @@ -896,8 +895,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "account_id" | ||||
|     t.integer "inbox_id" | ||||
|     t.string "url" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.integer "webhook_type", default: 0 | ||||
|     t.jsonb "subscriptions", default: ["conversation_status_changed", "conversation_updated", "conversation_created", "contact_created", "contact_updated", "message_created", "message_updated", "webwidget_triggered"] | ||||
|     t.index ["account_id", "url"], name: "index_webhooks_on_account_id_and_url", unique: true | ||||
| @@ -912,8 +911,8 @@ ActiveRecord::Schema.define(version: 2023_04_26_130150) do | ||||
|     t.integer "open_minutes" | ||||
|     t.integer "close_hour" | ||||
|     t.integer "close_minutes" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.boolean "open_all_day", default: false | ||||
|     t.index ["account_id"], name: "index_working_hours_on_account_id" | ||||
|     t.index ["inbox_id"], name: "index_working_hours_on_inbox_id" | ||||
|   | ||||
| @@ -16,10 +16,10 @@ KillMode=mixed | ||||
| StandardInput=null | ||||
| SyslogIdentifier=%p | ||||
|  | ||||
| Environment="PATH=/home/chatwoot/.rvm/gems/ruby-3.1.3/bin:/home/chatwoot/.rvm/gems/ruby-3.1.3@global/bin:/home/chatwoot/.rvm/rubies/ruby-3.1.3/bin:/home/chatwoot/.rvm/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/home/chatwoot/.rvm/bin:/home/chatwoot/.rvm/bin" | ||||
| Environment="PATH=/home/chatwoot/.rvm/gems/ruby-3.2.2/bin:/home/chatwoot/.rvm/gems/ruby-3.2.2@global/bin:/home/chatwoot/.rvm/rubies/ruby-3.2.2/bin:/home/chatwoot/.rvm/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/home/chatwoot/.rvm/bin:/home/chatwoot/.rvm/bin" | ||||
| Environment="PORT=3000" | ||||
| Environment="RAILS_ENV=production" | ||||
| Environment="NODE_ENV=production" | ||||
| Environment="RAILS_LOG_TO_STDOUT=true" | ||||
| Environment="GEM_HOME=/home/chatwoot/.rvm/gems/ruby-3.1.3" | ||||
| Environment="GEM_PATH=/home/chatwoot/.rvm/gems/ruby-3.1.3:/home/chatwoot/.rvm/gems/ruby-3.1.3@global" | ||||
| Environment="GEM_HOME=/home/chatwoot/.rvm/gems/ruby-3.2.2" | ||||
| Environment="GEM_PATH=/home/chatwoot/.rvm/gems/ruby-3.2.2:/home/chatwoot/.rvm/gems/ruby-3.2.2@global" | ||||
|   | ||||
| @@ -16,10 +16,10 @@ KillMode=mixed | ||||
| StandardInput=null | ||||
| SyslogIdentifier=%p | ||||
|  | ||||
| Environment="PATH=/home/chatwoot/.rvm/gems/ruby-3.1.3/bin:/home/chatwoot/.rvm/gems/ruby-3.1.3@global/bin:/home/chatwoot/.rvm/rubies/ruby-3.1.3/bin:/home/chatwoot/.rvm/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/home/chatwoot/.rvm/bin:/home/chatwoot/.rvm/bin" | ||||
| Environment="PATH=/home/chatwoot/.rvm/gems/ruby-3.2.2/bin:/home/chatwoot/.rvm/gems/ruby-3.2.2@global/bin:/home/chatwoot/.rvm/rubies/ruby-3.2.2/bin:/home/chatwoot/.rvm/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/home/chatwoot/.rvm/bin:/home/chatwoot/.rvm/bin" | ||||
| Environment="PORT=3000" | ||||
| Environment="RAILS_ENV=production" | ||||
| Environment="NODE_ENV=production" | ||||
| Environment="RAILS_LOG_TO_STDOUT=true" | ||||
| Environment="GEM_HOME=/home/chatwoot/.rvm/gems/ruby-3.1.3" | ||||
| Environment="GEM_PATH=/home/chatwoot/.rvm/gems/ruby-3.1.3:/home/chatwoot/.rvm/gems/ruby-3.1.3@global" | ||||
| Environment="GEM_HOME=/home/chatwoot/.rvm/gems/ruby-3.2.2" | ||||
| Environment="GEM_PATH=/home/chatwoot/.rvm/gems/ruby-3.2.2:/home/chatwoot/.rvm/gems/ruby-3.2.2@global" | ||||
|   | ||||
| @@ -328,8 +328,8 @@ function setup_chatwoot() { | ||||
|   sudo -i -u chatwoot << EOF | ||||
|   rvm --version | ||||
|   rvm autolibs disable | ||||
|   rvm install "ruby-3.1.3" | ||||
|   rvm use 3.1.3 --default | ||||
|   rvm install "ruby-3.2.2" | ||||
|   rvm use 3.2.2 --default | ||||
|  | ||||
|   git clone https://github.com/chatwoot/chatwoot.git | ||||
|   cd chatwoot | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| # pre-build stage | ||||
| FROM ruby:3.1.3-alpine3.16 AS pre-builder | ||||
| FROM ruby:3.2.2-alpine3.16 AS pre-builder | ||||
|  | ||||
| # ARG default to production settings | ||||
| # For development docker-compose file overrides ARGS | ||||
| @@ -64,13 +64,13 @@ RUN if [ "$RAILS_ENV" = "production" ]; then \ | ||||
| RUN git rev-parse HEAD > /app/.git_sha | ||||
|  | ||||
| # Remove unnecessary files | ||||
| RUN rm -rf /gems/ruby/3.1.0/cache/*.gem \ | ||||
|   && find /gems/ruby/3.1.0/gems/ \( -name "*.c" -o -name "*.o" \) -delete \ | ||||
| RUN rm -rf /gems/ruby/3.2.0/cache/*.gem \ | ||||
|   && find /gems/ruby/3.2.0/gems/ \( -name "*.c" -o -name "*.o" \) -delete \ | ||||
|   && rm -rf .git \ | ||||
|   && rm .gitignore | ||||
|  | ||||
| # final build stage | ||||
| FROM ruby:3.1.3-alpine3.16 | ||||
| FROM ruby:3.2.2-alpine3.16 | ||||
|  | ||||
|  | ||||
| ARG BUNDLE_WITHOUT="development:test" | ||||
|   | ||||
| @@ -59,7 +59,7 @@ class ConfigLoader | ||||
|   end | ||||
|  | ||||
|   def save_as_new_config(latest) | ||||
|     config = InstallationConfig.find_or_create_by(name: latest[:name]) | ||||
|     config = InstallationConfig.find_or_initialize_by(name: latest[:name]) | ||||
|     config.value = latest[:value] | ||||
|     config.locked = latest[:locked] | ||||
|     config.save! | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| require 'google/cloud/dialogflow/v2' | ||||
|  | ||||
| class Integrations::Dialogflow::ProcessorService < Integrations::BotProcessorService | ||||
|   pattr_initialize [:event_name!, :hook!, :event_data!] | ||||
|  | ||||
| @@ -17,11 +19,15 @@ class Integrations::Dialogflow::ProcessorService < Integrations::BotProcessorSer | ||||
|       Rails.logger.warn "Account: #{hook.try(:account_id)} Hook: #{hook.id} credentials are not present." && return | ||||
|     end | ||||
|  | ||||
|     Google::Cloud::Dialogflow.configure { |config| config.credentials = hook.settings['credentials'] } | ||||
|     session_client = Google::Cloud::Dialogflow.sessions | ||||
|     session = session_client.session_path project: hook.settings['project_id'], session: session_id | ||||
|     ::Google::Cloud::Dialogflow::V2::Sessions::Client.configure do |config| | ||||
|       config.timeout = 10.0 | ||||
|       config.credentials = hook.settings['credentials'] | ||||
|     end | ||||
|  | ||||
|     client = ::Google::Cloud::Dialogflow::V2::Sessions::Client.new | ||||
|     session = "projects/#{hook.settings['project_id']}/agent/sessions/#{session_id}" | ||||
|     query_input = { text: { text: message, language_code: 'en-US' } } | ||||
|     session_client.detect_intent session: session, query_input: query_input | ||||
|     client.detect_intent session: session, query_input: query_input | ||||
|   end | ||||
|  | ||||
|   def process_response(message, response) | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| require 'google/cloud/translate/v3' | ||||
| class Integrations::GoogleTranslate::DetectLanguageService | ||||
|   pattr_initialize [:hook!, :message!] | ||||
|  | ||||
| @@ -33,7 +34,7 @@ class Integrations::GoogleTranslate::DetectLanguageService | ||||
|   end | ||||
|  | ||||
|   def client | ||||
|     @client ||= Google::Cloud::Translate.translation_service do |config| | ||||
|     @client ||= ::Google::Cloud::Translate::V3::TranslationService::Client.new do |config| | ||||
|       config.credentials = hook.settings['credentials'] | ||||
|     end | ||||
|   end | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| require 'google/cloud/translate/v3' | ||||
| class Integrations::GoogleTranslate::ProcessorService | ||||
|   pattr_initialize [:message!, :target_language!] | ||||
|  | ||||
| @@ -23,7 +24,7 @@ class Integrations::GoogleTranslate::ProcessorService | ||||
|   end | ||||
|  | ||||
|   def client | ||||
|     @client ||= Google::Cloud::Translate.translation_service do |config| | ||||
|     @client ||= ::Google::Cloud::Translate::V3::TranslationService::Client.new do |config| | ||||
|       config.credentials = hook.settings['credentials'] | ||||
|     end | ||||
|   end | ||||
|   | ||||
| @@ -15,7 +15,7 @@ module Redis::Config | ||||
|         password: ENV.fetch('REDIS_PASSWORD', nil).presence, | ||||
|         ssl_params: { verify_mode: Chatwoot.redis_ssl_verify_mode }, | ||||
|         reconnect_attempts: 2, | ||||
|         network_timeout: 5 | ||||
|         timeout: 1 | ||||
|       } | ||||
|     end | ||||
|  | ||||
|   | ||||
| @@ -16,8 +16,7 @@ db_namespace = namespace :db do | ||||
|   desc 'Runs setup if database does not exist, or runs migrations if it does' | ||||
|   task chatwoot_prepare: :load_config do | ||||
|     ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config| | ||||
|       ActiveRecord::Base.establish_connection(db_config.config) | ||||
|       # handling case where database was created by the provider, with out running db:setup | ||||
|       ActiveRecord::Base.establish_connection(db_config.configuration_hash) | ||||
|       unless ActiveRecord::Base.connection.table_exists? 'ar_internal_metadata' | ||||
|         db_namespace['load_config'].invoke if ActiveRecord::Base.schema_format == :ruby | ||||
|         ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV.fetch('SCHEMA', nil)) | ||||
|   | ||||
							
								
								
									
										10
									
								
								lib/tasks/yarn.rake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								lib/tasks/yarn.rake
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| # ref: https://github.com/rails/rails/issues/43906#issuecomment-1094380699 | ||||
| # https://github.com/rails/rails/issues/43906#issuecomment-1099992310 | ||||
| task before_assets_precompile: :environment do | ||||
|   # run a command which starts your packaging | ||||
|   system('yarn') | ||||
| end | ||||
|  | ||||
| # every time you execute 'rake assets:precompile' | ||||
| # run 'before_assets_precompile' first | ||||
| Rake::Task['assets:precompile'].enhance ['before_assets_precompile'] | ||||
| @@ -25,7 +25,7 @@ | ||||
|     "@june-so/analytics-next": "^1.36.5", | ||||
|     "@rails/actioncable": "6.1.3", | ||||
|     "@rails/ujs": "^7.0.3-1", | ||||
|     "@rails/webpacker": "5.3.0", | ||||
|     "@rails/webpacker": "5.4.4", | ||||
|     "@sentry/tracing": "^6.19.7", | ||||
|     "@sentry/vue": "^6.19.7", | ||||
|     "@tailwindcss/typography": "0.2.0", | ||||
| @@ -78,7 +78,9 @@ | ||||
|     "vuelidate": "0.7.7", | ||||
|     "vuex": "~2.1.1", | ||||
|     "vuex-router-sync": "~4.1.2", | ||||
|     "wavesurfer.js": "^6.0.4" | ||||
|     "wavesurfer.js": "^6.0.4", | ||||
|     "webpack": "^4.46.0", | ||||
|     "webpack-cli": "^3.3.12" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@babel/core": "7.13.16", | ||||
| @@ -119,7 +121,7 @@ | ||||
|     "prettier": "^1.16.4", | ||||
|     "rimraf": "^3.0.0", | ||||
|     "vue-jest": "4", | ||||
|     "webpack-dev-server": "3.11.2" | ||||
|     "webpack-dev-server": "^3" | ||||
|   }, | ||||
|   "engines": { | ||||
|     "node": ">=10.x", | ||||
|   | ||||
| @@ -231,8 +231,8 @@ RSpec.describe 'Api::V1::Accounts::Articles', type: :request do | ||||
|         json_response = JSON.parse(response.body) | ||||
|  | ||||
|         expect(json_response['payload']['associated_articles'].length).to eq(2) | ||||
|         expect(json_response['payload']['associated_articles'][0]['id']).to eq(child_article_1.id) | ||||
|         expect(json_response['payload']['associated_articles'][1]['id']).to eq(child_article_2.id) | ||||
|         associated_articles_ids = json_response['payload']['associated_articles'].map { |article| article['id'] } | ||||
|         expect(associated_articles_ids).to match_array([child_article_1.id, child_article_2.id]) | ||||
|         expect(json_response['payload']['id']).to eq(root_article.id) | ||||
|       end | ||||
|     end | ||||
|   | ||||
| @@ -150,7 +150,7 @@ describe Integrations::Dialogflow::ProcessorService do | ||||
|   end | ||||
|  | ||||
|   describe '#get_response' do | ||||
|     let(:google_dialogflow) { Google::Cloud::Dialogflow } | ||||
|     let(:google_dialogflow) { ::Google::Cloud::Dialogflow::V2::Sessions::Client } | ||||
|     let(:session_client) { double } | ||||
|     let(:session) { double } | ||||
|     let(:query_input) { { text: { text: message, language_code: 'en-US' } } } | ||||
| @@ -158,8 +158,7 @@ describe Integrations::Dialogflow::ProcessorService do | ||||
|  | ||||
|     before do | ||||
|       hook.update(settings: { 'project_id' => 'test', 'credentials' => 'creds' }) | ||||
|       allow(google_dialogflow).to receive(:sessions).and_return(session_client) | ||||
|       allow(session_client).to receive(:session_path).and_return(session) | ||||
|       allow(google_dialogflow).to receive(:new).and_return(session_client) | ||||
|       allow(session_client).to receive(:detect_intent).and_return({ session: session, query_input: query_input }) | ||||
|     end | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,7 @@ describe Integrations::GoogleTranslate::DetectLanguageService do | ||||
|   let(:translate_client) { double } | ||||
|  | ||||
|   before do | ||||
|     allow(::Google::Cloud::Translate).to receive(:translation_service).and_return(translate_client) | ||||
|     allow(::Google::Cloud::Translate::V3::TranslationService::Client).to receive(:new).and_return(translate_client) | ||||
|     allow(translate_client).to receive(:detect_language).and_return(::Google::Cloud::Translate::V3::DetectLanguageResponse | ||||
|       .new({ languages: [{ language_code: 'es', confidence: 0.71875 }] })) | ||||
|   end | ||||
|   | ||||
| @@ -14,7 +14,7 @@ describe ::Redis::Config do | ||||
|  | ||||
|     it 'checks for app redis config' do | ||||
|       app_config = described_class.app | ||||
|       expect(app_config.keys).to match_array([:url, :password, :network_timeout, :reconnect_attempts, :ssl_params]) | ||||
|       expect(app_config.keys).to match_array([:url, :password, :timeout, :reconnect_attempts, :ssl_params]) | ||||
|       expect(app_config[:url]).to eq(redis_url) | ||||
|       expect(app_config[:password]).to eq(redis_pasword) | ||||
|     end | ||||
| @@ -43,7 +43,7 @@ describe ::Redis::Config do | ||||
|     end | ||||
|  | ||||
|     it 'checks for app redis config' do | ||||
|       expect(described_class.app.keys).to match_array([:url, :password, :sentinels, :network_timeout, :reconnect_attempts, :ssl_params]) | ||||
|       expect(described_class.app.keys).to match_array([:url, :password, :sentinels, :timeout, :reconnect_attempts, :ssl_params]) | ||||
|       expect(described_class.app[:url]).to eq("redis://#{redis_master_name}") | ||||
|       expect(described_class.app[:sentinels]).to match_array(expected_sentinels) | ||||
|     end | ||||
| @@ -60,7 +60,7 @@ describe ::Redis::Config do | ||||
|       end | ||||
|  | ||||
|       it 'checks for app redis config and sentinel passwords will be empty' do | ||||
|         expect(described_class.app.keys).to match_array([:url, :password, :sentinels, :network_timeout, :reconnect_attempts, :ssl_params]) | ||||
|         expect(described_class.app.keys).to match_array([:url, :password, :sentinels, :timeout, :reconnect_attempts, :ssl_params]) | ||||
|         expect(described_class.app[:url]).to eq("redis://#{redis_master_name}") | ||||
|         expect(described_class.app[:sentinels]).to match_array(expected_sentinels.map { |s| s.except(:password) }) | ||||
|       end | ||||
| @@ -78,7 +78,7 @@ describe ::Redis::Config do | ||||
|       end | ||||
|  | ||||
|       it 'checks for app redis config and redis password is replaced in sentinel config' do | ||||
|         expect(described_class.app.keys).to match_array([:url, :password, :sentinels, :network_timeout, :reconnect_attempts, :ssl_params]) | ||||
|         expect(described_class.app.keys).to match_array([:url, :password, :sentinels, :timeout, :reconnect_attempts, :ssl_params]) | ||||
|         expect(described_class.app[:url]).to eq("redis://#{redis_master_name}") | ||||
|         expect(described_class.app[:sentinels]).to match_array(expected_sentinels.map { |s| s.merge(password: redis_sentinel_password) }) | ||||
|       end | ||||
|   | ||||
| @@ -63,10 +63,10 @@ describe ActionCableListener do | ||||
|         a_collection_containing_exactly( | ||||
|           admin.pubsub_token, conversation.contact_inbox.pubsub_token | ||||
|         ), | ||||
|         'conversation.typing_on', conversation: conversation.push_event_data, | ||||
|         'conversation.typing_on', { conversation: conversation.push_event_data, | ||||
|                                     user: agent.push_event_data, | ||||
|                                     account_id: account.id, | ||||
|                                   is_private: false | ||||
|                                     is_private: false } | ||||
|       ) | ||||
|       listener.conversation_typing_on(event) | ||||
|     end | ||||
| @@ -83,10 +83,10 @@ describe ActionCableListener do | ||||
|         a_collection_containing_exactly( | ||||
|           admin.pubsub_token, agent.pubsub_token | ||||
|         ), | ||||
|         'conversation.typing_on', conversation: conversation.push_event_data, | ||||
|         'conversation.typing_on', { conversation: conversation.push_event_data, | ||||
|                                     user: conversation.contact.push_event_data, | ||||
|                                     account_id: account.id, | ||||
|                                   is_private: false | ||||
|                                     is_private: false } | ||||
|       ) | ||||
|       listener.conversation_typing_on(event) | ||||
|     end | ||||
| @@ -103,10 +103,10 @@ describe ActionCableListener do | ||||
|         a_collection_containing_exactly( | ||||
|           admin.pubsub_token, conversation.contact_inbox.pubsub_token | ||||
|         ), | ||||
|         'conversation.typing_off', conversation: conversation.push_event_data, | ||||
|         'conversation.typing_off', { conversation: conversation.push_event_data, | ||||
|                                      user: agent.push_event_data, | ||||
|                                      account_id: account.id, | ||||
|                                    is_private: false | ||||
|                                      is_private: false } | ||||
|       ) | ||||
|       listener.conversation_typing_off(event) | ||||
|     end | ||||
|   | ||||
| @@ -245,6 +245,7 @@ RSpec.describe SupportMailbox, type: :mailbox do | ||||
|         expect(conversation.messages.last.content_attributes['email']['html_content']['reply']).to include( | ||||
|           <<~BODY.chomp | ||||
|             Hi, | ||||
|  | ||||
|             We are providing you platform from here you can sell paid posts on your website. | ||||
|  | ||||
|             Chatwoot | CS team | [C](https://d33wubrfki0l68.cloudfront.net/973467c532160fd8b940300a43fa85fa2d060307/dc9a0/static/brand-73f58cdefae282ae74cebfa74c1d7003.svg) | ||||
|   | ||||
| @@ -41,7 +41,7 @@ end | ||||
| RSpec.configure do |config| | ||||
|   config.include FactoryBot::Syntax::Methods | ||||
|   # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures | ||||
|   config.fixture_path = "#{::Rails.root}/spec/fixtures" | ||||
|   config.fixture_path = Rails.root.join('spec/fixtures') | ||||
|  | ||||
|   # If you're not using ActiveRecord, or you'd prefer not to run each of your | ||||
|   # examples within a transaction, remove the following line or assign false | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Sojan Jose
					Sojan Jose