Compare commits

...
430 Commits
Author SHA1 Message Date
Sojan 480eb3043c Merge branch 'release/2.4.0'
Publish Chatwoot CE docker images / build (push) Waiting to run
2022-04-18 23:25:37 +05:30
Sojan 569ae24d8a Bump version to 2.4.0 2022-04-18 23:23:17 +05:30
Sojan JoseandGitHub 615a575bdd fix: Agent typing indicator for website widget (#4495)
When we migrated the pubsub tokens from contact to contact inboxes, we missed out on doing this update for the typing indicator events. Hence the agent typing events weren't visible on the widget side. This change fixes that and removes the necessary column contact pubsub token from the model.

fixes: #4476
2022-04-18 19:05:45 +05:30
Pranav Raj SandGitHub 17fb6b8d55 fix: Update business hour calculation (#4496) 2022-04-18 18:15:20 +05:30
Muhsin KelothandGitHub e010f0c6f0 chore: Sync pre-chat fields after custom attribute destroy (#4456) 2022-04-18 14:06:27 +05:30
Shivam ChaharandGitHub 04e890070d fix: Change report_type to type in report API docs (#4492) 2022-04-18 11:38:22 +05:30
Pranav Raj SandGitHub 0319b78eac fix: Allow users to login even if they have access to more than 15 accounts (#4475) 2022-04-14 20:54:26 +05:30
Vishnu NarayananandGitHub 80e5d6d7a0 feat: add chatwoot_edition variable for CE docker images (#4462)
* chore: add chatwoot_edition variable for CE docker images

* fix cw_edition variable

* chore: update comment

* feat: include cw_edition data in payload to hub

* refactor cw_edition to edition
2022-04-14 17:15:57 +05:30
337a74a10c feat: Add send message, fix issues with message conditions (#4423)
Co-authored-by: Tejaswini <tejaswini@chatwoot.com>
2022-04-14 13:36:55 +05:30
d4be268cc3 enhancement: Remove clickaway for expanded reply box (#4414)
* enhancement: Remove clickaway for expanded reply box

* Removes unused imports

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2022-04-13 12:04:34 +05:30
Tejaswini ChileandGitHub a6b119d187 Feat: twitter image support (#4429) 2022-04-13 01:29:51 +05:30
Tejaswini ChileandGitHub 923b4637db chore: Automation bug fix (#4442) 2022-04-12 20:23:34 +05:30
b6ad468eb4 fix: Nokogiri bundle update (#4448)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2022-04-12 11:30:54 +05:30
14503b5fe0 feat: Add missing password validation at signup (#4441)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-04-12 11:08:12 +05:30
c64e2e3bc5 chore: Report improvements (#4392)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-04-11 20:57:22 +05:30
Aswin Dev P.SandGitHub 31cdc63e18 fix: Remove IMAP and SMTP email validation (#4435)
* Remove IMAP and SMTP email validation
* Rename imap_email & smtp_email columns to imap_login & smtp_login respectively.
* Use channel email domain if inbound email domain not present
2022-04-11 07:07:20 -07:00
Nithin David ThomasandGitHub 3d164271a8 fix: Yellow color shades are inconsistent (#4391) 2022-04-11 17:27:28 +05:30
Sojan JoseandGitHub 1194188f13 chore: Swagger doc for Conversation meta API (#4394)
fixes: https://github.com/chatwoot/chatwoot/issues/4327
2022-04-11 16:43:09 +05:30
Aswin Dev P.SandGitHub 9b5eb98c59 feat: Support additional authentication mechanisms for SMTP (#4431)
* Support additional authentication mechanisms for SMTP
2022-04-11 03:13:05 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8622740161 chore(deps): bump moment from 2.29.1 to 2.29.2 (#4434)
Bumps [moment](https://github.com/moment/moment) from 2.29.1 to 2.29.2.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.1...2.29.2)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-11 15:10:37 +05:30
Muhsin KelothandGitHub fb3ed29c90 chore: Add missing test cases in conversations_controller_spec (#4438) 2022-04-11 14:06:44 +05:30
Aswin Dev P.SandGitHub f1ae09d21b fix: SMTP shouldn't be configurable without IMAP enabled (#4428)
* fix: Configure SMTP only if IMAP is enabled
2022-04-11 00:05:03 -07:00
Pranav Raj SandGitHub b1efcde495 feat: Remove duplicate Switch Component (#4427) 2022-04-08 18:25:08 +05:30
Pranav Raj SandGitHub bc7bcc20b8 Revert "feat: Adds support for draft in conversation reply box (#4205)" (#4425)
This reverts commit 5ea0436051.
2022-04-08 15:52:39 +05:30
Muhsin KelothandGitHub 7e5ec7925c feat: Add phone_number & custom_attributes in create conversation end point (#4421) 2022-04-08 14:53:37 +05:30
727993aa19 feat: Add toggle button component(#4419)
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2022-04-08 14:02:26 +05:30
Aswin Dev P.SandGitHub d5536d65f7 feat: Consider business hours while generating the reports (#4330)
* feat: Consider business hours while generating the reports
2022-04-08 00:18:18 -07:00
Tejaswini ChileandGitHub 57359be37e Fix: Find mailbox with cc email (#4372) 2022-04-08 11:20:19 +05:30
Sivin VargheseandGitHub 14e6a5d6b0 fix: Background dark mode colour issue in campaign view (#4416) 2022-04-08 10:54:51 +05:30
5ea0436051 feat: Adds support for draft in conversation reply box (#4205)
* Add draft support

* Fixes issue with draft loading

* Adds draft for private notes

* Use localstorage helper

* .remove instead of .clear

* Remove timestamp

* clearLocalStorageOnLogout

* Fix draft save on refresh

* Remove usage of delete operator

* Adds autosave for draft messages

* Remove setinterval and add debounce

* Removes draft redundancy check

* Adds test cases for debouncer

* Update app/javascript/shared/helpers/specs/TimeHelpers.spec.js

Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>

* Update app/javascript/shared/helpers/specs/TimeHelpers.spec.js

Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>

* Review fixes

* Fixes issue with debouncer

* FIxes debouncer issue

* Fixes issue with draft empty message

* Removes empty keys from local storage drafts

* Fixes error with empty draft

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
Co-authored-by: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: iamsivin <iamsivin@gmail.com>
2022-04-07 22:16:45 +05:30
Muhsin KelothandGitHub dfb56f6bb8 doc: Swagger for custom attribute APIs (#4382) 2022-04-07 19:01:31 +05:30
d4a046a21e fix: Audio notification would not work without action on the dashboard (#4303)
* fixes: Audio notification would not work without an action on dashboard

* fixes spec

* Minor fixes

* Minor fixes

* Review fixes

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2022-04-07 10:23:18 +05:30
Fayaz AhmedandGitHub 8482ecc1b1 Feat - Sort inboxes alphabetically (#4383) 2022-04-07 10:01:08 +05:30
Sivin VargheseandGitHub 5b490bc8cc chore: fix scroll bar color in the dark mode (#4404) 2022-04-07 07:14:40 +05:30
Muhsin KelothandGitHub c2afdd5c93 chore: Remove unnecessary fields from notification payload (#4403) 2022-04-07 00:07:53 +05:30
Vishnu NarayananandGitHub 75ce5345a9 feat: add gh action to build Chatwoot CE/foss docker image (#4406)
Github action to build and push chatwoot-ce(foss) edition images. This action will run on merges to master, develop and when tags are created. Corresponding docker tags are as follows.

GitHub branch/tag  -->	docker tag
----
master 	--> latest-ce
develop 	---> develop-ce
v2.3.2 	---> v2.3.2-ce
v* 	---> v*-ce

Fixes #4388
2022-04-06 21:14:04 +05:30
9329f08e14 chore: Fix typo in en localisation file (#4405)
Fix

Co-authored-by: Vishnu Narayanan <vishnu@chatwoot.com>
2022-04-06 20:21:19 +05:30
Pranav Raj SandGitHub 0b03e4b296 feat: Add an option to disable endConversation button (#4352) 2022-04-06 13:54:55 +05:30
Tejaswini ChileandGitHub 821b953ee9 Fix: handling UTF encoded mail (#4384) 2022-04-06 12:36:32 +05:30
Sojan JoseandGitHub 7a8aa4ca2e chore: Add Swagger Doc for Team Members (#4390)
Add swagger documentation for Team Members APIs
2022-04-05 16:05:49 +05:30
2595e774e5 fix: Update validations in automation edit actions (#4370)
Co-authored-by: fayazara <fayazara@gmail.com>
2022-04-05 15:22:56 +05:30
Sojan JoseandGitHub 9a8a0bd865 feat: Ability to customize the online presence duration (#4385) 2022-04-05 15:20:34 +05:30
cd5646b4b9 fix: Skip contact_last_seen_at in empty conversation payload (#4387)
* Fix undefined `last_seen_at` empty conversation

* chore: remove the comment

Co-authored-by: Sojan Jose <sojan@pepalo.com>
2022-04-05 14:00:07 +05:30
Vishnu NarayananandGitHub 76f53d9a11 feat: add gh action to run CE edition tests (#4342)
* feat: add gh action to run CE spec

* setup ruby
* add pg,redis services
* fix failing tests
2022-04-04 19:27:01 +05:30
Muhsin KelothandGitHub 591d186d66 chore: Add agent_last_seen_at in conversation API (#4377) 2022-04-04 18:23:38 +05:30
Jordan BroughandGitHub 73d8073530 chore: Fix test failure in action_cable_listener_spec.rb due to ordering (#4357) 2022-04-04 15:15:45 +05:30
Muhsin KelothandGitHub 1dd0c7249c fix: Unread notification count in multiple accounts (#4373)
Fixes: #4367
2022-04-04 14:34:01 +05:30
Pranav Raj SandGitHub 3509692055 chore: Fix brand name in survey translations (#4360) 2022-04-03 19:22:56 +05:30
Sivin VargheseandGitHub 5d85a21287 fix: Fix login button is missing in Safari (#4332)
Fixes #4328
2022-04-01 21:03:53 +05:30
caee9535f1 feat: Support Dark mode for the widget (#4137)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-04-01 20:59:03 +05:30
Vishnu NarayananandGitHub 3813b3b372 feat: make linux script installation non-interactive (#4355)
This PR changes the LetsEncrypt behaviour to be non-interactive. Earlier, the installation flow was waiting for user input at the SSL cert generation stage. With this change, once the user confirms completes the initial selection, the installation can be completed unattended.
2022-04-01 00:34:50 +05:30
Pranav Raj SandGitHub c397fe1964 fix: Update the URL for POST inbox_members (#4354) 2022-03-31 21:21:25 +05:30
cb23ff53bf fix: Reset Captcha if account signup is an error (#4279)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-03-31 21:20:37 +05:30
Sivin VargheseandGitHub 3cd1616df6 fix: Fix agent name in Twitter channel private note acting as a link (#4326) 2022-03-31 20:22:52 +05:30
Muhsin KelothandGitHub eff3a50316 fix: Disable showing read messages in unread view (#4324) 2022-03-31 17:35:39 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
0477123f92 chore(deps): bump minimist from 1.2.5 to 1.2.6 (#4351)
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-31 16:33:14 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c9f821cc5b chore(deps): bump puma from 5.6.2 to 5.6.4 (#4348)
Bumps [puma](https://github.com/puma/puma) from 5.6.2 to 5.6.4.
- [Release notes](https://github.com/puma/puma/releases)
- [Changelog](https://github.com/puma/puma/blob/master/History.md)
- [Commits](https://github.com/puma/puma/compare/v5.6.2...v5.6.4)

---
updated-dependencies:
- dependency-name: puma
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-31 16:02:53 +05:30
baf697f064 design: Changes yellow color palette for better contrast ratio (#4334)
Co-authored-by: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com>
2022-03-30 18:53:24 +05:30
Tejaswini ChileandGitHub 5be9380547 Fix: html mail fix with html_body content (#4011) 2022-03-30 18:04:30 +05:30
Muhsin KelothandGitHub 24b20c10ce fix: Referer URL validation (#4309)
Fixes #354
2022-03-30 14:36:22 +05:30
Tejaswini ChileandGitHub bfe6324d9a chore: Webhook event data improvements (#4317) 2022-03-30 11:37:36 +05:30
Tejaswini ChileandGitHub 15fd37b124 Feat: attachments automation (#4266) 2022-03-30 08:08:58 +05:30
3f2ac2042f fix: Fetch conversation attributes after contact reset (#4319)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2022-03-29 19:51:51 +05:30
Tejaswini ChileandGitHub 3158966241 Feat: automation rule based on contact conditions (#4230) 2022-03-29 17:29:34 +05:30
Fayaz AhmedandGitHub c674393c02 feat: New automation actions (#4033) 2022-03-29 13:27:16 +05:30
Kyle KillionandGitHub cffc984ef6 chore: Add active_storage_purge queue to Sidekiq (#4322)
I found that these jobs were just enqueuing without processing until I added this queue after switching to S3 storage. This fixed that issue.
2022-03-29 11:43:07 +05:30
Aswin Dev P.SandGitHub 5e8fd689c9 feat: Add live agent load report api (#4297)
This change allows the admin user to fetch conversation metrics for an account, agents, and filter conversation metrics for a specific agent.

Fixes #4305
2022-03-29 10:31:52 +05:30
Muhsin KelothandGitHub ccf52a620b feat: Update notifications and unread count in real time (#4261) 2022-03-28 20:01:23 +05:30
Vishnu NarayananandGitHub ec0ea0b1dc chore: Upgrade to next gen docker convenience image (#4310)
* chore: Upgrade to next gen docker convenience image

https://discuss.circleci.com/t/legacy-convenience-image-deprecation/41034/16

* switch to postgres:14.1 and redis:6.2 images
2022-03-28 18:15:38 +05:30
Vishnu NarayananandGitHub 8155024b6a feat: fix logging levels (#4314)
https://ruby-doc.org/stdlib-2.7.0/libdoc/logger/rdoc/Logger.html

Fixes https://github.com/chatwoot/chatwoot/issues/4313
2022-03-28 18:14:30 +05:30
823c0ab6a7 chore: Use Round Robin service for team assignment (#4237)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-03-28 14:38:07 +05:30
e8bc30e3c6 feat: Add a confirmation note before deleting a note about a contact (#4294)
Co-authored-by: Richardo <richardokusuma.sali@medirecords.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-03-28 14:19:12 +05:30
Fayaz AhmedandGitHub 30ac8054ba feat: Add an SDK method for opening conversation in popout window (#4232) 2022-03-28 13:31:51 +05:30
Aswin Dev P.SandGitHub 0ba6e772a4 feat: Display how many conversations are considered for the metric calculation (#4273)
* feat: Display how many conversations are considered for the metric calculation
2022-03-28 00:38:23 -07:00
Aswin Dev P.SandGitHub ba0188aefc fix: Report spec failure (#4304) 2022-03-28 12:31:09 +05:30
Sojan JoseandGitHub e0f29b9d81 chore: Add swagger docs for Canned Responses (#4295)
fixes: #3962
2022-03-26 00:43:44 +05:30
Pranav Raj SandGitHub 971755b845 fix: Remove unnecessary dispatchWindowEvent (#4288) 2022-03-25 20:25:07 +05:30
0667d9f016 fix: Avatars get cropped on the widget (#4238)
Co-authored-by: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2022-03-25 19:20:53 +05:30
Sivin VargheseandGitHub 48389d69d8 feat: New notification panel for unread notifications (#4061)
Fixes: #4052
2022-03-25 19:02:45 +05:30
Sojan JoseandGitHub ff881fcad9 chore: Support Email should give priority to environment variable (#4270)
Account.support_email should give priority to environment variables over installation config

Fixes: #3304
2022-03-25 16:13:45 +05:30
SagarandGitHub 5da0b0667f Fix: SMTP IMAP configuration from email
This fix should allow emails from the "Email" inbox to show from as "Name <email@example.com>". if SMTP within Inbox is disabled.
2022-03-25 16:05:26 +05:30
Jordan BroughandGitHub a8cfcbc168 chore: Timezone fixes for ReportBuilder and for ReportController spec (#4246)
- ReportBuilder wasn't using the specified time zone for the timestamp in the
"build" method
- The ReportController spec was calling `Time.zone.today.to_time`, but
`Date#to_time` disregards the zone from `Time.zone` and reverts to the system
time zone.
2022-03-25 14:00:27 +05:30
6bfe0f2fc1 feat: Add support for rich editor and allow CCs in email for a new conversation. (#4194)
* feat: Add support for rich editor and allow CCs in email for a new conversation.

* Minor fixes

Co-authored-by: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2022-03-25 11:27:45 +05:30
Jordan BroughandGitHub 131c0a8668 chore: Don't send confirmation email when creating User via platform api (#4272)
The platform api automatically confirms users so we don't need to send this
email.
2022-03-25 00:36:59 +05:30
Sojan JoseandGitHub 8e153d6350 fix: Redis 6 on Heroku breaks ActionCable config (#4269)
Heroku made some SSL/TLS changes with Redis 6, which is breaking the ActionCable configuration.
Hence providing an environment variable configuration `REDIS_OPENSSL_VERIFY_MODE` to fix that.

set the value `none` for this environment variable in your Heroku installations where breakage occurs.

fixes: #2420
2022-03-24 19:25:07 +05:30
Tejaswini ChileandGitHub 60a0709de6 Fix: added validation for custom and additional attribute (#4260) 2022-03-24 15:38:28 +05:30
Jordan BroughandGitHub 14c53b8b54 chore: Use "contain_exactly" in some tests (#4243) 2022-03-24 13:50:04 +05:30
Vishnu NarayananandGitHub 7577c9c888 fix: drop conv and campaign seq on account delete (#4256)
Conversation and campaign sequences persist in the database even after the related account is deleted. This PR adds an after_desttory callback on the account model that will delete the associated sequences.

Fixes: #4252
2022-03-24 13:33:15 +05:30
Jordan BroughandGitHub 0cf970dafd chore: Eliminate deprecation warning in "app_config_controller_spec.rb" (#4258)
Fix the warning:

Using `should` from rspec-expectations' old `:should` syntax without
explicitly enabling the syntax is deprecated. Use the new `:expect` syntax
or explicitly enable `:should` with `config.expect_with(:rspec) { |c| c.syntax = :should }` instead.
2022-03-24 13:31:19 +05:30
Jordan BroughandGitHub c2647a1f27 chore: Use "destroy!" instead of "destroy" when not checking the return value (#4259) 2022-03-24 13:28:25 +05:30
giquieuandGitHub 8b9aea231c feat: support audio player on widget (#4250) 2022-03-24 12:44:34 +05:30
Jordan BroughandGitHub b735135431 chore: Fix "action_mailer.delivery_method" in the test env (#4257)
Fixes: #4247
2022-03-23 20:46:28 +05:30
Sojan 160e8a8ab4 Merge branch 'release/2.3.2' into develop 2022-03-23 19:06:52 +05:30
Sojan 2605f24539 Merge branch 'release/2.3.2' 2022-03-23 19:06:45 +05:30
Sojan dd76dd4204 Bump version to 2.3.2 2022-03-23 19:05:34 +05:30
86b4183bde fix: Add multiple file paste support and fix for bugs (#4066)
- Add multiple files paste support.
- Fixes showing file name in the editor field when we paste the file from finder.
- Fixes showing the image in the advance editor when we paste the image as an attachment from the clipboard.

Fixes: #4036

Co-authored-by: Nithin David <1277421+nithindavid@users.noreply.github.com>
2022-03-23 18:25:57 +05:30
Jordan BroughandGitHub 4a21633a2b chore: Use bang version of "find_or_create_by!" in Platform UsersController (#4248) 2022-03-23 16:09:10 +05:30
Sojan JoseandGitHub f8c46341f6 chore: Disable invalid contact resolved activity messages (#4253)
Fixes the bug which triggered "Contact resolved conversation" activity messages when snoozed conversations where reopened
2022-03-23 16:08:42 +05:30
Pranav Raj SandGitHub 771cb5b9fc fix: Update scroll event name to fix auto-scroll (#4251)
Fixes #3622
2022-03-23 13:27:50 +05:30
Sojan JoseandGitHub f43018e017 chore: New translations automation.json (Italian) (#4231) 2022-03-22 12:42:10 +05:30
Sojan JoseandGitHub 467f3b9191 chore: Disable fetching new emails after mailbox error (#4176)
- Disabled email fetch job if credentials for the channel isn't working
- notify customers when the email channel isn't working

fixes: https://github.com/chatwoot/chatwoot/issues/4174
2022-03-22 12:14:17 +05:30
Muhsin KelothandGitHub 715400f7ab fix: Disable pre-chat fields for identified users (#4234) 2022-03-22 01:28:22 +05:30
Tejaswini ChileandGitHub 7b4cac746a feat: enhancement to un-send instagram message (#4120) 2022-03-21 17:10:15 +05:30
Sojan JoseandGitHub 6169d172d8 chore: Update translations from Crowdin (#4217) 2022-03-21 13:15:33 +05:30
Tejaswini ChileandGitHub e06a6a7c55 Automation enhancement (#4087) 2022-03-21 13:12:27 +05:30
c608ca37e0 fix: Contact conversations are showing in the chat list (#4078)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-03-21 11:46:43 +05:30
Pranav Raj SandGitHub 6097f4c122 fix: Update survey locale based on the account (#4207) 2022-03-20 13:07:36 +05:30
Fayaz AhmedandGitHub 8372ae418e System default monospace fonts for code elem (#4222) 2022-03-19 20:56:29 +05:30
Sojan JoseandGitHub 71391d982b chore: filter .xml files for Bandwidth SMS (#4206)
MMS sent from an ATT or Verizon phone number seems to be appending a SMIL file in .xml format for MMS.
2022-03-18 19:00:36 +05:30
b77fad52fb fix: Add missing contact information to fix invalid activity messages (#4195)
Co-authored-by: Tejaswini <tejaswini@chatwoot.com>
2022-03-18 13:43:02 +05:30
Sojan JoseandGitHub 40f31cb0a3 chore: Update translations (#4208) 2022-03-18 11:24:22 +05:30
7f8a199b29 chore: Update translations (#4099)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-03-17 20:02:32 +05:30
Muhsin KelothandGitHub 23fe8847d8 feat: Notification action cable event (#4154) 2022-03-17 18:56:36 +05:30
Sojan 430547e026 Merge branch 'hotfix/2.3.1' into develop 2022-03-17 16:55:00 +05:30
Sojan d0702363f4 Merge branch 'hotfix/2.3.1' 2022-03-17 16:54:49 +05:30
Sojan d6d0c79618 Bump version to 2.3.1 2022-03-17 16:53:36 +05:30
Sojan JoseandGitHub 9f8e442333 chore: Improve n+1 queries (#4202)
Fixes the n+1 queries that get triggered while accessing agents endpoint
2022-03-17 15:57:32 +05:30
Pranav Raj SandGitHub 4a3ddad02f fix: Reduce the height of the unread container while campaign is active (#4185) 2022-03-16 14:45:57 +05:30
Tejaswini ChileandGitHub 207a03155e Feat: authenticate direct upload (#4160) 2022-03-16 13:54:18 +05:30
Sojan 796a7805db Merge branch 'release/2.3.0' into develop 2022-03-15 23:04:09 +05:30
Sojan a50ea9c88a Merge branch 'release/2.3.0' 2022-03-15 23:03:59 +05:30
Sojan 711251560b Bump version to 2.3.0 2022-03-15 22:59:54 +05:30
c4837cd7ac feat: End conversation from widget (#3660)
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-03-15 22:07:30 +05:30
Pranav Raj SandGitHub 4b748e2c8c fix: Delete content_attributes in message destroy API (#4184) 2022-03-15 22:01:16 +05:30
8c8c5a77c8 feat: Show banner message if Chatwoot update available (#3999)
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
Co-authored-by: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com>
Co-authored-by: Pranav <pranav@chatwoot.com>
2022-03-15 21:09:14 +05:30
Sojan JoseandGitHub 02dd5ecfab chore: 360Dialog attachments fix (#4173)
fixes: #3701
2022-03-15 17:42:21 +05:30
Muhsin KelothandGitHub f405572e5c Revert "feat: Custom fields in pre-chat form (#4135)" (#4182)
This reverts commit e730804b48.
2022-03-15 16:54:33 +05:30
Sojan JoseandGitHub 25876993ff fix: NoMethodError: undefined method `id' for nil:NilClass (#4172)
fixes: #4171
2022-03-15 14:30:33 +05:30
b3ba8b9513 fix: Could not able to create label (#4161)
* fixes: Could not able to create label

* review fixes

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2022-03-14 20:43:56 +05:30
Fayaz AhmedandGitHub 4a2452173e feat: Added support for Created At, Last Activity At filters in the UI (#4031) 2022-03-14 20:24:53 +05:30
Aswin Dev P.SandGitHub c62d74a01d feat: Display trends in report metrics (#4144) 2022-03-14 18:15:27 +05:30
Sivin VargheseandGitHub 5edf0f2bbe fix: Fix modal responsiveness (#4149) 2022-03-14 18:14:16 +05:30
Fayaz AhmedandGitHub dd1fe4f93a fix: Handle unsanitized markup in DOM (#4110) 2022-03-14 18:13:21 +05:30
Muhsin KelothandGitHub e730804b48 feat: Custom fields in pre-chat form (#4135)
Fixes: #2744
2022-03-14 15:06:56 +05:30
Sivin VargheseandGitHub 578414d788 feat: Adds ability to delete contact without having to type name (#4155) 2022-03-11 17:00:55 +05:30
Sivin VargheseandGitHub 619441ce1c fixes: Showing vue warning in the console (#4152)
* fixes: Showing vue warn with PR#4100

* Minor fixes
2022-03-10 22:06:59 +05:30
Nithin David ThomasandGitHub 3c3b6f90c7 fix: Add base_url to the audio notification file (#4116) 2022-03-10 20:40:47 +05:30
Tejaswini ChileandGitHub 647efa12e7 fix: Attach instagram images with file type story_mentions (#4100) 2022-03-10 20:27:30 +05:30
b3545f42f1 fixes: Contact search is skipping the '+' sign for email. (#4142)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-03-10 11:15:41 +05:30
Pranav Raj SandGitHub fb03b6f434 chore: Upgrade rails to 6.1.4.7 to fix (#4143)
Fixes CVE-2022-21831
2022-03-10 11:01:40 +05:30
Pranav Raj SandGitHub 1aa7d6f7d8 fix: Update brand name in mailers (#4123) 2022-03-08 09:22:57 +05:30
giquieuandGitHub 96b719017b feat: Ability to send voice message to channel (#4064)
Created the possibility to send audio as an attachment via the dashboard.
The channels that can send audio are the same channels that can send any type of attachment.
Used RecordRTC (https://github.com/muaz-khan/RecordRTC) to capture the audio and Wavesurfer (https://github.com/katspaugh/wavesurfer.js) to display the audio waves.
RecordRTC can be used to record videos if necessary.

Fixes #1973
2022-03-04 19:43:07 +05:30
Aswin Dev P.SandGitHub b94e67f5d7 feat: Add agents filter in CSAT reports (#4106)
* add agents filter in csat reports
2022-03-04 03:49:26 -08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Pranav Raj S
c76b588850 chore(deps): bump marked from 2.0.3 to 4.0.10 (#3771)
* chore(deps): bump marked from 2.0.3 to 4.0.10

Bumps [marked](https://github.com/markedjs/marked) from 2.0.3 to 4.0.10.
- [Release notes](https://github.com/markedjs/marked/releases)
- [Changelog](https://github.com/markedjs/marked/blob/master/.releaserc.json)
- [Commits](https://github.com/markedjs/marked/compare/v2.0.3...v4.0.10)

---
updated-dependencies:
- dependency-name: marked
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* use {marked}

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-03-04 14:53:40 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Muhsin KelothNithin David Thomas
a28b911132 chore(deps): bump url-parse from 1.5.7 to 1.5.10 (#4076)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.7 to 1.5.10.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.7...1.5.10)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2022-03-04 10:58:05 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6e4ae1a1bc chore(deps): bump commonmarker from 0.23.2 to 0.23.4 (#4108)
Bumps [commonmarker](https://github.com/gjtorikian/commonmarker) from 0.23.2 to 0.23.4.
- [Release notes](https://github.com/gjtorikian/commonmarker/releases)
- [Changelog](https://github.com/gjtorikian/commonmarker/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gjtorikian/commonmarker/compare/v0.23.2...v0.23.4)

---
updated-dependencies:
- dependency-name: commonmarker
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-04 10:57:22 +05:30
Pranav Raj SandGitHub 9583a2dbad chore: Pass sso_account_id to select the account during SSO Login (#4103) 2022-03-03 20:49:51 +05:30
Sojan JoseandGitHub 11adfd2384 chore: remove unnecessary dependent destroy (#4104) 2022-03-03 13:02:02 +05:30
Pranav Raj SandGitHub 28d102f526 fix: Show new message screen instead of input field (#4102) 2022-03-03 12:36:31 +05:30
3d7ca61481 Show email signature with maximum height 8vh, fixes #4021 (#4063)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2022-03-02 15:28:56 +05:30
Sojan JoseandGitHub 7b9e4982cf Feat: Support MMS in SMS Channel ( Bandwidth ) (#4046)
Ability to send and receive MMS to bandwidth channel

fixes: #3961
2022-03-02 15:09:56 +05:30
4d458c2184 feat: Support respective input types in custom attributes - filters (#4032)
* Support differnt input types in custom attributes

* Handle list type custom attributes

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: Vishnu Narayanan <vishnu@chatwoot.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2022-03-02 14:16:42 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
0582d15eb5 chore(deps): bump image_processing from 1.12.1 to 1.12.2 (#4095)
Bumps [image_processing](https://github.com/janko/image_processing) from 1.12.1 to 1.12.2.
- [Release notes](https://github.com/janko/image_processing/releases)
- [Changelog](https://github.com/janko/image_processing/blob/master/CHANGELOG.md)
- [Commits](https://github.com/janko/image_processing/compare/v1.12.1...v1.12.2)

---
updated-dependencies:
- dependency-name: image_processing
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-02 10:31:37 +05:30
915fe3897c chore: Add Github in contact social profiles (#4086)
* Add github in social links

* Code cleanup

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2022-03-01 14:33:26 +05:30
Muhsin KelothandGitHub f08d1b35d0 feat: Toggle automation status (#3991) 2022-03-01 14:14:23 +05:30
a3cb26a317 fix: AudioContext warning when loading widget on Chrome (#3956)
* fix: AudioContext warning when loading widget on Chrome

* minor fixes

* Minor fixes

* adds event on document

* Play audio from parent window through SDK

* Adds notification to dashboard

Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
Co-authored-by: Vishnu Narayanan <vishnu@chatwoot.com>
2022-02-28 21:43:24 +05:30
eee89bf0d8 feat: Show cc from last email on reply editor (#3983)
* Adds last emails to reply editor

* Fixes bug in reply box

* Adds test cases

* Prevents private notes having cc bcc data

* Prevents private notes having cc bcc data

* Init reply head with values

* fix broken tests

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2022-02-28 21:42:50 +05:30
Muhsin KelothandGitHub 1de18391b4 fix: Handle invalid country code in contact details (#4081) 2022-02-28 19:48:13 +05:30
Muhsin KelothandGitHub bb16780278 chore: Upgrade utils to 0.0.5 (#4082) 2022-02-28 18:50:29 +05:30
4260441f8c Chore: clean up Reporting Events (#4044)
Tech debt clean up

Fixes #4057

Co-authored-by: Aswin Dev P S <aswin@chatwoot.com>
2022-02-28 18:16:12 +05:30
12c0be002e feat: Format time in reports (#4072)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-02-28 16:54:43 +05:30
Muhsin KelothandGitHub aff14b697f chore: Add webhook URL validation (#4080) 2022-02-28 15:44:02 +05:30
Pranav Raj SandGitHub 87a6266ddc fix: Add resetTriggered flag to fix reset loop (#4079) 2022-02-28 14:53:11 +05:30
Sojan cebb1bf871 Merge branch 'release/2.2.1' into develop 2022-02-28 14:12:36 +05:30
Sojan ed2772dd59 Merge branch 'release/2.2.1' 2022-02-28 14:12:22 +05:30
Sojan 4f19fa763c Bump version to 2.2.1 2022-02-28 14:04:40 +05:30
Muhsin KelothandGitHub 46c1734ba1 feat: Add additional attributes in setUser method (#3958) 2022-02-28 12:10:55 +05:30
9b615f11f1 fix: Consider timezone in the reports (#4027)
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2022-02-28 10:56:24 +05:30
Sojan JoseandGitHub 4ca66c1195 fix: Automation loop on conversation_update (#4071) 2022-02-25 18:01:21 +05:30
Pranav Raj SandGitHub cc74bebc0f feat: Display Account context in the UI (#4069) 2022-02-25 16:36:36 +05:30
2c8a3ef3b2 fix: Message signature going with other channels message (#4024)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-02-25 16:36:10 +05:30
Pranav Raj SandGitHub 6c94768bdb feat: Add flat design for widget (#4065) 2022-02-25 16:18:18 +05:30
Nithin David ThomasandGitHub dcecbf4b80 Fix: show empty emails in chat (#4030) 2022-02-24 21:33:16 -08:00
Vishnu NarayananandGitHub d590b0ebc4 fix: nokogiri gem build failure in docker (#4060)
tar (child): xz: Cannot exec: No such file or directory¶

Starting in v1.13.2, the source archive used for libxml2 and libxslt is compressed with xz (previous versions were compressed with gzip. As a result, when compiling from source, your system will need to have xz installed in order to extract the source code for these libraries.
2022-02-23 23:27:19 +05:30
Pranav Raj SandGitHub 85f19fa25a chore: Show error messages from server in agent APIs (#4055) 2022-02-23 20:18:20 +05:30
Tejaswini ChileandGitHub 1ca1b4d36b feat: bulk actions to update conversation objects (#3934)
Added the endpoints for bulk updating conversation objects

Fixes: #3845 #3940 #3943
2022-02-23 16:53:36 +05:30
Sivin VargheseandGitHub 9059f5906a fix: Throwing error when click load more conversation (#4049) 2022-02-23 16:48:53 +05:30
Sojan JoseandGitHub eb0da2026f chore: Bundle update (#4038)
- address the nokogiri security issues
2022-02-22 16:06:04 +05:30
Aswin Dev P.SandGitHub e348db1e37 Fix: add option to choose 24 hour working slot (#4018)
* Add option to choose 24 hour working slot

* fix spec

* add check to update open hour and close hour for open all day

* update 24 hour working slot change in widget side

* add validation to check open_all_day and closed_all_day true at the same time
2022-02-22 01:28:49 -08:00
Muhsin KelothandGitHub 7ba24b90c4 feat: Add chatwoot:error sdk event (#3998) 2022-02-21 09:40:11 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
3b015d4dd8 chore(deps): bump url-parse from 1.5.3 to 1.5.7 (#4016)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.3 to 1.5.7.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.3...1.5.7)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-20 11:30:19 +05:30
ea44a32758 feat: Add hCaptcha for public forms (#4017)
- added hCaptcha based verification for chatwoot signups

Co-authored-by: Sojan <sojan@pepalo.com>
2022-02-18 20:02:50 +05:30
Muhsin KelothandGitHub 80d83b401c feat: Show refresh modal on action cable disconnect (#4010) 2022-02-18 11:09:43 +05:30
Sivin VargheseandGitHub ea3e011d3f fix: Auto scroll to bottom when agent sends a message (#3764) 2022-02-17 20:42:13 +05:30
Sivin VargheseandGitHub 2586c8e7e5 fix: Lock icon colour issue in private messages (#4009)
* fix: Lock icon colour issue in private messages

* minor fixes
2022-02-17 18:58:53 +05:30
Sojan b9025a98d3 Merge branch 'release/2.2.0' into develop 2022-02-15 23:41:56 +05:30
Sojan b6c3d61163 Merge branch 'release/2.2.0' 2022-02-15 23:41:48 +05:30
Sojan 991f291c69 Bump version to 2.2.0 2022-02-15 23:39:57 +05:30
Fayaz AhmedandGitHub 5ad6db07b4 fix: Automation Bugs and minor enhancements (#3936) 2022-02-15 23:36:29 +05:30
Sivin VargheseandGitHub e345a4486d fix: Throwing NavigationDuplicated error (#3978) 2022-02-15 22:49:53 +05:30
Sojan JoseandGitHub 5ad7e93059 chore: Discard activities from email notifiable messages (#3989) 2022-02-15 18:15:45 +05:30
Pranav Raj SandGitHub 505c93c467 revert: "fix: html content is available and mail_part empty" (#3986)
Reverts de4e4c6
2022-02-15 17:19:28 +05:30
464e12ceb7 fix: Update auto reply and hide reply time for email inbox (#3985)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-02-15 17:11:28 +05:30
Aswin Dev P.SandGitHub e6f8895c1b feat: Group by filter in reports (#3973) 2022-02-15 17:10:49 +05:30
Sojan JoseandGitHub a703ef2de6 chore: Update translations (#3980) 2022-02-15 16:22:42 +05:30
94a473c9f8 chore: Delayed deploy of direct uploads (#3966)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-02-15 16:16:54 +05:30
Pranav Raj SandGitHub 2591a04c0b chore: Remove message_signature_enabled from users (#3982) 2022-02-15 12:10:53 +05:30
Nithin David ThomasandGitHub 351a3dc372 feat: Adds email signature form to profile settings (#3906) 2022-02-15 10:38:24 +05:30
Tejaswini ChileandGitHub d5c9193d1a feat: Add specs for reply-to changes (#3959) 2022-02-15 10:28:04 +05:30
Tejaswini ChileandGitHub de4e4c6f65 fix: html content is available and mail_part empty (#3964) 2022-02-14 20:22:58 +05:30
dependabot[bot]andGitHub f34a2e6115 chore(deps): bump puma from to 5.6.2, rails to 6.1.4.6 (#3969) 2022-02-14 20:09:21 +05:30
Pranav Raj SandGitHub 9c7044c81b fix: Use default from attribute if undefined (#3977) 2022-02-14 17:37:40 +05:30
Sojan JoseandGitHub 04148b95a6 chore: Update translations (#3937) 2022-02-14 17:11:43 +05:30
Sojan JoseandGitHub 3d73d8935a feat: Add the ability for a super admin to define account limits (#3946)
Fixes: #3773
2022-02-14 15:55:08 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
edd93ca4a3 chore(deps): bump follow-redirects from 1.14.7 to 1.14.8 (#3970)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-14 15:53:13 +05:30
Nithin David ThomasandGitHub 2c15d5b4f3 fix: Custom attribute not getting changed on conversations (#3965) 2022-02-14 15:52:15 +05:30
Nithin David ThomasandGitHub 74d9203868 feat: Show the sender email address (#3974) 2022-02-14 15:46:20 +05:30
Tejaswini ChileandGitHub 25001689ec fix: Use to_i in campaign scheduled_at key (#3968) 2022-02-14 11:20:31 +05:30
Muhsin KelothandGitHub 2da618bd5e feat: Add conversation_created event in webhooks (#3949) 2022-02-14 09:44:25 +05:30
ba7f387dde chore: Reduces clutter in inbox settings page (#3960)
* chore: Reduces clutter in inbox settings page

* Fix spacing issues

Co-authored-by: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2022-02-11 08:38:42 +05:30
Sivin VargheseandGitHub 1115bd18ed fix: Icon colors are not recognizable in bubble (#3957) 2022-02-11 07:15:07 +05:30
e9a162e71a feat: Prefer reply-to over from in email channels (#3837)
Co-authored-by: root <root@support.loomio.com>
2022-02-10 19:20:30 +05:30
Nithin David ThomasandGitHub 4201b57315 fix: Fixes console error with image component in widget (#3955) 2022-02-10 12:48:22 +05:30
Sivin VargheseandGitHub 0ec3a56041 fix: Blank page after deleting contact (#3948) 2022-02-09 14:35:18 +05:30
Aswin Dev P.SandGitHub 4e416b4d51 Add openssl verify mode and email encryption for smtp configuration (#3885)
* Add openssl verify mode and email encryption for smtp configuration
* Add spec for code coverage
2022-02-08 03:26:13 -08:00
Muhsin KelothandGitHub 4ae9ed8f94 chore: Assign the conversation to agent who opens the conversation (#3925) 2022-02-08 16:39:19 +05:30
Pranav Raj SandGitHub 7b2ff2f112 feat: Show assignee name in folders view (#3933) 2022-02-08 10:38:14 +05:30
Sojan JoseandGitHub e2ff1b1a15 chore: Update German translations (#3928) 2022-02-08 10:12:34 +05:30
Sivin VargheseandGitHub d891c1e7b5 Fixes API call failing after opening the saved filter (#3932) 2022-02-08 10:11:56 +05:30
Pranav Raj SandGitHub 2a07eae69f fix: URL encode params on Platform API call (#3929)
Add URL encoding for the params in platform API calls.

Fixes: product#307
Fixes: #2186
2022-02-07 15:17:36 -08:00
375d943a48 fix: Avoid filter payload changing to null on load more conversations (#3926)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2022-02-07 22:14:21 +05:30
Sojan JoseandGitHub 4c0f6c1333 chore: Update translations (#3927) 2022-02-07 20:17:49 +05:30
97675c61ea chore: Update to the latest translations (#3923)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-02-07 17:19:34 +05:30
Muhsin KelothandGitHub f4c0ce5dfa chore: Assign to agent who create new message from contact panel (#3924) 2022-02-07 13:43:16 +05:30
Muhsin KelothandGitHub 9f37a6e2ba fix: Render valid urls only in custom attributes (#3921) 2022-02-07 13:04:27 +05:30
047070ad87 chore: Fix translations in Swedish language (#3765)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-02-07 12:44:05 +05:30
1a3d39a7f3 feat: Shows an alert while replying if chats are not assigned to them (#3867)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-02-07 12:27:20 +05:30
Muhsin KelothandGitHub a737f89c47 fix: Ongoing campaign URL validation (#3890) 2022-02-04 14:38:18 +05:30
Tejaswini ChileandGitHub a7987d4d1c feat: Add date custom filter (#3892) 2022-02-04 13:14:20 +05:30
SagarandGitHub 32673ea8b4 chore: Allow Self Hosted Instances to use Support Inbox within Dashboard for Agents (#3907) 2022-02-04 09:58:53 +05:30
Sojan JoseandGitHub 9454c6b14f Fix: Conversation filter permissions (#3908)
fixes: chatwoot/product#225
2022-02-03 18:25:28 -08:00
Sojan JoseandGitHub cf10f3d03b chore: Provider APIs for SMS Channel - Bandwidth (#3889)
fixes: #3888
2022-02-03 15:22:13 -08:00
Tejaswini ChileandGitHub fba7f40bee Fix: Custom filter distinct select (#3895) 2022-02-03 14:39:47 +05:30
Nithin David ThomasandGitHub 5c6958482f fix: Shows tooltip and avatar for template messages (#3898) 2022-02-03 12:14:34 +05:30
Pranav Raj SandGitHub 8dcb4a5ed4 chore: Add resolve action in Dialogflow Integration (#3900) 2022-02-03 12:05:39 +05:30
Pranav Raj SandGitHub dbb50e5923 fix: Update font-size/width to fix iOS input zoom (#3894) 2022-02-03 10:11:02 +05:30
Muhsin KelothandGitHub 903072ef14 chore: Add custom attributes in conversation webhook payload (#3839) 2022-02-03 10:05:56 +05:30
fc1f257793 feat: Clone automation rules (#3893)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2022-02-03 09:14:22 +05:30
Tejaswini ChileandGitHub 8821106da9 Fix: Added the backend validation for name (#3878)
- Added the backend validation for name
- Add message size constraint
2022-02-02 14:21:17 -08:00
Tejaswini ChileandGitHub e99ea0b582 feat: Email signature API support (#3874) 2022-02-02 19:37:33 +05:30
193a531e49 feat: Edit automation modal (#3876)
* Add automation modal

* Fix the v-model for automations

* Actions and Condition dropdowns for automations

* Fix merge conflicts

* Handle event change and confirmation

* Appends new action

* Removes actions

* Automation api integration

* Api integration for creating automations

* Registers vuex module to the global store

* Automations table

* Updarted labels and actions

* Integrate automation api

* Fixes the mutation error - removed the data key wrapper

* Fixed the automation condition models to work with respective event types

* Remove temporary fixes added to the api request

* Displa timestamp and automation status values

* Added the clone buton

* Removed uncessary helper method

* Specs for automations

* Handle WIP code

* Remove the payload wrap

* Fix the action query payload

* Removed unnecessary files

* Disabled Automations routes

* Ability to delete automations

* Fix specs

* Edit automation modal

* Edit automation modal and api integration

* Replaced hardcoded values

* Using absolute paths

* Update app/javascript/dashboard/routes/dashboard/settings/automation/EditAutomationRule.vue

Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>

* Update app/javascript/dashboard/routes/dashboard/settings/automation/Index.vue

Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>

* Intendation fix

* Disable automation route

* Minor fix

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2022-02-02 19:15:02 +05:30
91b9168fae feat: Add the ability to add new automation rule (#3459)
* Add automation modal

* Fix the v-model for automations

* Actions and Condition dropdowns for automations

* Fix merge conflicts

* Handle event change and confirmation

* Appends new action

* Removes actions

* Automation api integration

* Api integration for creating automations

* Registers vuex module to the global store

* Automations table

* Updarted labels and actions

* Integrate automation api

* Fixes the mutation error - removed the data key wrapper

* Fixed the automation condition models to work with respective event types

* Remove temporary fixes added to the api request

* Displa timestamp and automation status values

* Added the clone buton

* Removed uncessary helper method

* Specs for automations

* Handle WIP code

* Remove the payload wrap

* Fix the action query payload

* Removed unnecessary files

* Disabled Automations routes

* Ability to delete automations

* Fix specs

* Fixed merge conflicts

Co-authored-by: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com>
Co-authored-by: fayazara <fayazara@gmail.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2022-02-02 18:46:07 +05:30
1f3c5002b3 feat: Shows agent avatar for message sent by agent (#3884)
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2022-02-01 16:34:54 +05:30
Vishnu NarayananandGitHub c0276d252a chore: add aws rds root cert for tls connection (#3812)
* chore: add aws rds cert for tls connection

* add aws rds ca cert

* remove intermediate ca cert
2022-02-01 16:01:25 +05:30
Fayaz AhmedandGitHub 52d1821cd3 feature: Filtering conversations and contacts with custom attributes (#3851) 2022-02-01 13:13:55 +05:30
Pranav Raj SandGitHub e0d24e0a73 chore: Use globalConfig in NetworkNotification (#3871) 2022-02-01 12:25:51 +05:30
Prithvi TharunandGitHub b1e1d7e423 fix: Update the copy to use inclusive language (#3880)
Fixes #3879
2022-02-01 11:12:20 +05:30
Tejaswini ChileandGitHub a95d249ec1 Feat: Custom attribute advanced filter (#3818) 2022-01-31 13:36:44 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
a1034a70c4 chore(deps): bump node-fetch from 2.6.1 to 2.6.7 (#3862)
Bumps [node-fetch](https://github.com/node-fetch/node-fetch) from 2.6.1 to 2.6.7.
- [Release notes](https://github.com/node-fetch/node-fetch/releases)
- [Commits](https://github.com/node-fetch/node-fetch/compare/v2.6.1...v2.6.7)

---
updated-dependencies:
- dependency-name: node-fetch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-28 11:41:12 -08:00
Tejaswini ChileandGitHub 357a374478 Fix: Update yarn (#3866) 2022-01-28 13:19:22 +05:30
Tejaswini ChileandGitHub 1467a8fa33 Fix: parse verification mail (#3864)
Email parsing logic was stripping of HTML tables which was causing the issue in this case.

Fixes: #3731
2022-01-27 15:45:26 -08:00
13eaff156a Added keybindings for commandbar (#3854)
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2022-01-27 17:57:33 +05:30
Sivin VargheseandGitHub e7e46590a4 bug: Fixes sidebar does not show an active page for settings page (#3861) 2022-01-27 17:39:21 +05:30
Frederik KriewitzandGitHub 17018d392d chore: update deployment scripts to install sudo (#3841)
* Update setup_20.04.sh to install sudo
* Update setup_18.04.sh to install sudo
2022-01-27 16:55:27 +05:30
Tejaswini ChileandGitHub 69eaf3ff7f feat: Activestorage direct upload (#3768) 2022-01-27 15:57:22 +05:30
Sivin VargheseandGitHub cd6c9a8fe9 enhancement: Custom views (#3838)
* enhancement: Custom views

* Review fixes
2022-01-27 08:26:12 +05:30
Pranav Raj SandGitHub 5710b7559e fix: Fix email template to render the chat bubble properly (#3858) 2022-01-26 17:52:08 -08:00
Shivam ChaharandGitHub 8e6d8e7654 fix: Validate avatar only when it has changed (#3849) 2022-01-26 16:01:41 -08:00
59deffc7e3 feat: Ability to toggle conversation continuity via email (#3817)
Fixes: #3368
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-01-26 15:59:48 -08:00
Sojan JoseandGitHub 34e8ad9dc5 feat: Unify user and super admin credentials (#3830)
Fixes: #3061, #3489
2022-01-25 16:58:49 -08:00
Pranav Raj SandGitHub 23965fbaa3 fix: Return if window.$chatwoot is already defined (#3847) 2022-01-25 16:39:19 -08:00
8cff690640 feat: Support multiple file upload on dashboard (#3748)
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2022-01-24 18:46:58 -08:00
Sivin VargheseandGitHub b304f5a826 feat: Adds the ability to delete a segment (#3836)
* feat: Adds the ability to delete a segment

* Minor fixes

* Small changes
2022-01-24 17:37:43 +05:30
Prithvi TharunandGitHub e90d064648 fix: Fixes typo in documentation on sidebar 2022-01-24 16:03:37 +05:30
Sivin VargheseandGitHub 504fc24fb3 feat: Add the ability to save filters for contact (#3791) 2022-01-21 14:11:59 -08:00
Sojan JoseandGitHub 693f2531ab feat: Support 360Dialog Interactive Templates (#3823)
fixes: #3795
2022-01-20 17:09:30 -08:00
Tejaswini ChileandGitHub e997aaceb7 Fix: Email Parsing for html fix (#3659) 2022-01-20 15:55:35 -08:00
Tejaswini ChileandGitHub a7c947aeae feat: Clone and update automation rules (#3782)
- endpoints to clone and update automation rules

fixes: #3740
2022-01-20 15:30:21 -08:00
ab864a86fd fix: File and emoji pickers are disabled by default (#3803)
File and emoji pickers should be enabled by default.

Fixes: #3560

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2022-01-19 22:20:04 -08:00
Shivam ChaharandGitHub 9617137688 chore: Account auto resolution time validation (#3651) 2022-01-19 13:16:21 +05:30
1b36143d27 fix: Fixes alignment of widget unread view close button (#3806)
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2022-01-19 12:43:04 +05:30
241e7d0c29 Enhancement: Add background color to draggable blocks in the sidebar (#3778)
* add background

* update background color in contact info

Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2022-01-19 11:26:52 +05:30
Sivin VargheseandGitHub 185f916b2a feat: Adds the ability to delete the saved custom views (#3780)
* feat: Adds the ability to delete the saved custom views

* Removed unused tag

* Review fixes

* Review fixes

* Update DeleteCustomViews.vue
2022-01-19 09:40:32 +05:30
Sojan 4a68d13310 Merge branch 'hotfix/2.1.1' into develop 2022-01-17 23:37:52 -08:00
Sojan ceb2b9673c Merge branch 'hotfix/2.1.1' 2022-01-17 23:37:45 -08:00
Sojan Jose 1749b4eb61 chore: Clean up assignment logic (#3763) 2022-01-17 23:36:54 -08:00
Sojan 346d89ecc0 Bump version to 2.1.1 2022-01-17 23:33:47 -08:00
c64cffb294 fix: Update the hardcoded scroll-width to match with the current table length (#3774)
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2022-01-18 07:37:51 +05:30
6deb3764dc Fix: Pagination bug with filters payload (#3747)
* Removes the last operators value

* Moved removing the last operator to the payload generator

* Update app/javascript/dashboard/helper/filterQueryGenerator.js

This makes sure the last operator is never sent to the request

Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>

* Fixed the test specs

* Fixed the intendation and added comments

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2022-01-17 20:35:53 +05:30
4398734bdf feat: Adds the ability to have custom view for conversations (#3666)
* feat: Adds the ability to save custom filters and display folders on the sidebar

* Minor fixes

* Review fixes

* Review fixes

* i18n fixes

* Shows conversations when the user click on the folder sidebar item

* Spacing fixes

* Review fixes

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2022-01-17 09:18:54 +05:30
Sojan JoseandGitHub 290196d43b chore: Clean up assignment logic (#3763) 2022-01-13 21:38:10 -08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
fcd2b892bf chore(deps): bump follow-redirects from 1.14.5 to 1.14.7 (#3760)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.5 to 1.14.7.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.5...v1.14.7)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-13 12:46:09 -08:00
cab5a3e53b chore: Add a redirect link to the conversation in success toast message (#3711)
When creating a conversation from the contacts tab now we can go directly to the conversation by clicking the link in the success message

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2022-01-13 11:15:40 -08:00
Muhsin KelothandGitHub 359caf754c fix: Update contact bio style to solve overflow (#3753) 2022-01-13 10:57:12 -08:00
Sivin VargheseandGitHub 7fcac532df fix: Update timestamp style on the private message from bot (#3758) 2022-01-13 10:54:52 -08:00
Nithin David ThomasandGitHub d57be3ffae fix: Allow private note without selecting a tweet (#3754) 2022-01-13 10:54:00 -08:00
Pranav Raj SandGitHub 5046dcaf61 fix: Update broken CSS Styles in liquid template (#3756) 2022-01-13 10:52:48 -08:00
Tejaswini ChileandGitHub 7df68c6388 Feat: Automations Actions (#3564) 2022-01-13 11:21:06 +05:30
Sojan JoseandGitHub 905fd62974 chore: Support Whatsapp Interactive messages (360Dialog) (#3751)
Render button and list reply clicks as text messages in agent dashboard

fixes: #3684
2022-01-12 19:42:23 -08:00
Sojan JoseandGitHub 1c99294c8c chore: Fix 360Dialog template message breakage (#3750)
Template parsing fails when regexp characters are present in templates.

Fixes: #3587
2022-01-12 17:41:42 -08:00
94209d29cb fix: Fixes widget unread view blocking parent page (#3658)
Co-authored-by: Pranav <pranav@chatwoot.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2022-01-12 12:27:16 -08:00
9c31d7c672 feat: Use vue-router on widget route management (#3415)
* feat: Add vue-router to widget

Co-authored-by: Pranav <pranav@chatwoot.com>

* Move to dynamic imports

* Move to routerMixin

* Fix popup button display

* Remove unnecessary import

* router -> route

* Fix open state

* Fix issues

* Remove used CSS

* Fix specs

* Fix specs

* Fix widgetColor specs

* Fix mutation specs

* Fixes broken lint errors

* Fixes issues with widget flow

Co-authored-by: Nithin <nithin@chatwoot.com>
Co-authored-by: Nithin David <1277421+nithindavid@users.noreply.github.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2022-01-12 16:25:27 +05:30
Sojan 991a42c417 Merge branch 'release/2.1.0' into develop 2022-01-11 19:28:49 -08:00
Sojan 4a902fce6d Merge branch 'release/2.1.0' 2022-01-11 19:28:42 -08:00
Sojan 5475746a87 Bump version to 2.1.0 2022-01-11 19:26:23 -08:00
Vishnu NarayananandGitHub acba07cf6e chore: revert GlobalConfig changes (#3702)
Priority to GlobalConfig changes are reverted and for the time being, env vars will take precedence if set.

Fixes #3699
2022-01-11 19:20:23 -08:00
Sojan JoseandGitHub f44be0b1e6 fix: SuperAdmin Improvements (#3733)
- Fix broken access tokens pages
- Fix broken avatar images in the super admin users tab
- Fix broken pagination links in super admin
- Add agent bot tabs

Fixes: #2021
2022-01-11 19:00:00 -08:00
Prithvi TharunandGitHub bec1266242 fix: Update shortcode -> short code (#3708)
Closes #3672
2022-01-11 15:20:52 -08:00
Sojan JoseandGitHub ebb04487a8 chore: Prevent null in Contact JSONB attributes (#3730) 2022-01-11 15:14:55 -08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
de37975be4 chore(deps): bump google-protobuf from 3.18.1 to 3.19.2 (#3714)
Bumps [google-protobuf](https://github.com/protocolbuffers/protobuf) from 3.18.1 to 3.19.2.
- [Release notes](https://github.com/protocolbuffers/protobuf/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf/blob/master/generate_changelog.py)
- [Commits](https://github.com/protocolbuffers/protobuf/compare/v3.18.1...v3.19.2)

---
updated-dependencies:
- dependency-name: google-protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-11 13:25:44 -08:00
Axel TietjeandGitHub 8a26d78623 chore: fix german translations (#3724) 2022-01-12 00:36:57 +05:30
Aswin Dev P.SandGitHub 7ee7062843 feat: Toggle to disallow users to send messages after a conversation is resolved (#3605) 2022-01-11 00:32:03 -08:00
Tejaswini ChileandGitHub a0884310f4 feat: Save automation rules (#3359) 2022-01-10 12:41:59 +05:30
Anisha-artandGitHub 9a9462f5cb fix: Removed extra space before "." (#3717)
Fixes Removed extra space before "." as mentioned in the issue: #3669
2022-01-09 22:27:45 -08:00
Prithvi TharunandGitHub 9b6f1df871 fix: Update copy in canned responses (#3716)
Fixes #3669
2022-01-09 22:26:35 -08:00
Anisha-artandGitHub ab4d63a006 Error with plurals in Invite members onboarding guide. Issue #3671 (#3718)
Updated "email address" to "email addresses" in the Invite your team members guide.
2022-01-10 10:29:16 +05:30
Fayaz AhmedandGitHub 0745ceb430 Chore: Update ninja keys to 1.1.9 (#3710) 2022-01-07 13:52:08 -08:00
Pranav Raj SandGitHub f7ed7756d9 chore: Use logo thumbnail instead of logo in the sidebar (#3706) 2022-01-06 15:09:01 -08:00
Muhsin KelothandGitHub e1fe4f09bc chore: Add subscription delete API (#3703) 2022-01-06 21:40:43 +05:30
Nayan PatelandGitHub a61dae0bb2 General updates and add CODEOWNERS (#3685) 2022-01-05 12:37:22 +05:30
Nithin David ThomasandGitHub fade94658a chore: Show scrollbar for sidebar only on hover (#3688) 2022-01-05 09:37:43 +05:30
Vishnu NarayananandGitHub e775d22b98 feat: add new view and controller to display app configs together (#3563)
fixes: #3578
2022-01-04 21:50:16 +05:30
Tejaswini ChileandGitHub e304ad27cb Chore: Custom filter api docs updated (#3668) 2022-01-04 13:10:29 +05:30
Prithvi TharunandGitHub 3e8ae3865f chore: Update the copy for new password in profile settings (#3676)
Fixes #3656
2022-01-02 22:43:50 -08:00
Nithin David ThomasandGitHub 223fb2b7e4 chore: Updates design of resolve context menu (#3667) 2021-12-29 22:24:11 +05:30
Nithin David ThomasandGitHub 666028a443 feat: Adds multiple path support for fluent icons (#3665)
* feat: Adds multiple path support for icons

* Changes dashboard icon
2021-12-29 18:01:49 +05:30
Sojan 8bdd7ba3e4 Merge branch 'release/2.0.2' 2021-12-28 21:56:59 +05:30
Sojan a1c77c8c4c Bump version to 2.0.2 2021-12-28 21:55:57 +05:30
Sojan JoseandGitHub 577e9905c6 chore: Fix issue with conversation assignment notifications (#3661)
- fixes issues with conversation assignment notifications not working in certain cases
2021-12-28 21:53:13 +05:30
Muhsin KelothandGitHub 9606abe251 chore: Fix Eslint warnings (#3654)
* Fix all the eslint warnings

* Revert the schema
2021-12-27 13:49:31 +05:30
Sojan 28da30f7e4 Merge branch 'release/2.0.1' into develop 2021-12-23 01:04:10 +05:30
Sojan 9f663ed4e5 Merge branch 'release/2.0.1' 2021-12-23 01:04:02 +05:30
Sojan acc55ea79c Bump version to 2.0.1 2021-12-23 01:02:56 +05:30
Sojan JoseandGitHub 13d6734977 chore: Minor API cleanups (#3645)
- exception list updated
- revert mail presenter changes
2021-12-23 00:55:49 +05:30
Tejaswini ChileandGitHub c57c975a0d bug: NoMethodError: undefined method `match' for in_reply_to (#3641)
Fixes #3615
2021-12-22 22:33:18 +05:30
Tejaswini ChileandGitHub 44486fc8e1 chore: Improve email parsing using email trimmer gem (#3611)
Email parsing using email_trimmer gem

Fixes: #3539 , #2954, #3572
2021-12-22 18:16:40 +05:30
Sojan JoseandGitHub 009abc1948 chore: API improvements (#3637)
- Unique validations for Inbox members and Team member objects
- Move notification processing to Async
2021-12-21 22:48:01 +05:30
Muhsin KelothandGitHub 262474166f chore: Add display id in all conversation notifications (#3635)
- Added conversation display id in push payload for the notifications conversation_creation and conversation_assignment
2021-12-21 19:59:22 +05:30
Nithin David ThomasandGitHub 307118b235 feat: Shows error message with retry for widget messages (#3594)
- Adds error message retry option for widget bubbles
- Adds a fallback for widget images with file type bubble
2021-12-21 12:02:43 +05:30
Sivin VargheseandGitHub 0130e08016 fix: Remove animated running numbers (#3604) 2021-12-20 18:19:59 -08:00
Nithin David ThomasandGitHub 83655f4ca4 feat: Show errors for message bubbles in dashboard (#3585) 2021-12-21 00:07:33 +05:30
6fe5484119 chore: Allow more filetypes in uploads (#3557)
- Allowing the ability to upload more common file types like zip, Docx etc
- Fallback for image bubble when the image URL isn't available

fixes: #3270

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Nithin David <1277421+nithindavid@users.noreply.github.com>
2021-12-20 23:50:37 +05:30
Tejaswini ChileandGitHub 76e8acd3c6 Fix: Editable attrs presence check for the channel class (#3630) 2021-12-20 19:38:38 +05:30
Sivin VargheseandGitHub ad09c5dc5f bug: Fixes pressing enter key not submitting values in widget. (#3610) 2021-12-20 08:48:09 +05:30
Sojan JoseandGitHub f8cf0cd7c5 chore: Enable Slovak Language (#3614) 2021-12-19 11:38:21 +05:30
Sojan JoseandGitHub 46d2a8f218 chore: New Crowdin updates (#3616) 2021-12-19 11:38:02 +05:30
Amit KumarandGitHub 6069cd9eba chore: Contact builder ignores custom attributes (#3571)
This is incorrect as per the documentation here: https://www.chatwoot.com/developers/api/#operation/create-a-contact
This allows setting the proper attributes when creating a contact
2021-12-19 10:59:03 +05:30
Sojan JoseandGitHub 8d65608666 chore: Clean up migrations (#3613)
Fixes: #3530
2021-12-19 09:47:07 +05:30
Aswin Dev P.SandGitHub 5ee209c079 chore: Fix user email re-confirmation flow (#3581)
Users can change their email from profile settings. They will be logged out immediately. Users can log in again with the updated email without verifying the same. This is a security problem.

So this change enforce the user to reconfirm the email after changing it. Users can log in with the updated email only after the confirmation.

Fixes: https://huntr.dev/bounties/7afd04b4-232e-4907-8a3c-acf8bd4b5b22/
2021-12-16 19:32:49 +05:30
Sivin VargheseandGitHub e0c9687f5e bug: Fixes irregular padding on agent selector in report page (#3593)
* bug: Fixes irregular padding on agent selector in report page

* code climate fixes
2021-12-16 13:20:35 +05:30
Sivin VargheseandGitHub 93f384a3ec enhancement: Changes button design for tables in settings page (#3553)
* enhancement: Changes button design for tables in settings page

* Minor fixes

* Review fixes
2021-12-16 13:00:55 +05:30
Tejaswini ChileandGitHub 9984edd3ef Feat: Manage conversation for tweets based on the tweet flag (#3353)
Add tweet conversation only if tweets are enabled.

Fixes #1961
2021-12-16 00:24:50 +05:30
Sivin VargheseandGitHub e2e459a1ac bug: Fixes space missing issue with message bubbles after sending messages (#3562) 2021-12-15 19:12:11 +05:30
Tejaswini ChileandGitHub b7336eca65 Fix: Add max retries for all jobs (#3582) 2021-12-15 17:31:16 +05:30
Nithin David ThomasandGitHub 6ae06f2c7a fix: Fixes wrong color for note tab in reply box (#3566)
* fix: Fixes wrong color for note tab in reply box

* Changes color for warning button

* Fixes spacing
2021-12-14 20:09:52 +05:30
Vishnu NarayananandGitHub 7986d61b6f feat: allow users to select components to install when using linux script (#3528)
Provide a choice to select the components to install. The script
should be able to just install chatwoot alone. Postgres, redis,
SSL certs via letsencrypt and nginx as a webserver should be
installed after confirmation.

Fixes: #3513
2021-12-14 18:26:57 +05:30
Nithin David ThomasandGitHub c2191e48b1 Chore: Fixes icon size in button (#3555)
* Chore: Fixes icon size in button

* Changes normal button to woot button
2021-12-14 17:37:25 +05:30
Vishnu NarayananandGitHub ac372f188d chore: add line messenger in readme (#3552) 2021-12-13 14:19:12 +05:30
Sivin VargheseandGitHub 178cb34319 bug: Fixes expanded reply box is not closing after the message is sent (#3537) 2021-12-13 12:37:21 +05:30
Tejaswini ChileandGitHub c2519ea1ea Fix: fixing mail to and in_reply_to issues (#3451) 2021-12-10 19:42:26 +05:30
Pranav Raj SandGitHub dcdeaa7954 chore: Remove license tag from Readme 2021-12-09 02:30:33 -08:00
arabakevinandGitHub 0b7eb2e2c1 chore: Fix typo in enterprise license (#3535) 2021-12-09 02:22:37 -08:00
Pranav Raj SandGitHub 2defe4a8fe chore: Fix line breaks in Readme.md 2021-12-09 02:19:16 -08:00
Pranav Raj SandGitHub b0af3f2498 chore: Update Readme.md 2021-12-09 02:16:05 -08:00
Sojan JoseandGitHub 5feb5aba72 Merge tag 'v2.0.0' into develop
v2.0.0
2021-12-09 08:17:34 +00:00
Sojan JoseandGitHub a7623041bf Merge branch 'release/2.0.0' 2021-12-09 08:17:15 +00:00
Sojan JoseandGitHub d268f155e4 Bump version to 2.0.0 2021-12-09 06:59:23 +00:00
b1eea7f7d1 chore: Introduce enterprise edition license (#3209)
- Initialize an "enterprise" folder that is copyrighted.
- You can remove this folder and the system will continue functioning normally, in case you want a purely MIT licensed product.
- Enable limit on the number of user accounts in enterprise code.
- Use enterprise edition injector methods (inspired from Gitlab).
- SaaS software would run enterprise edition software always.

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-12-09 12:07:48 +05:30
Pranav Raj SandGitHub 2f63ebb8a6 fix: Add fixes for sentry errors (#3522)
- Add fixes for sentry errors
2021-12-09 11:50:28 +05:30
Pranav Raj SandGitHub 2be71e73dc feat: Add a view for mentions (#3505)
- Added a new table mentions for saving user mentions
- Added a filter conversation_type in the API
- Added a view to see the mentions
2021-12-09 11:20:14 +05:30
Sojan JoseandGitHub 1db82f235d Chore: Improve confirmation flow for agents (#3519)
- Agents are redirected to the password reset page which confirms the agent as well as sets a new password.
2021-12-09 11:11:46 +05:30
9306b725d8 chore: Fix pre-commit hooks (#3525)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-12-08 17:32:00 -08:00
Muhsin KelothandGitHub 3ee6b7d6e9 chore: Add the ability to use same key for conversation and contact (#3526) 2021-12-08 20:15:27 +05:30
Tejaswini ChileandGitHub 35130bc83e Fix: Add foreign key with delete cascade for destroy_async (#3527) 2021-12-08 18:03:27 +05:30
Tejaswini ChileandGitHub f609a28c6b Fix: Added facebook login scope with new advanced access for page read (#3518) 2021-12-08 16:17:49 +05:30
Sivin VargheseandGitHub 714c10dc66 bug: Fixes error with the secondary menu. (#3524) 2021-12-08 14:20:59 +05:30
f5d79ffe58 chore: Updates icon for network disconnect alert (#3514)
* chore: Upadates icon for network disconnect alert

* Changes background color

* Review fixes

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2021-12-07 23:45:36 +05:30
Nithin David ThomasandGitHub 824101bc30 fix: Fixes cc bcc being sent when mail head is empty (#3515)
* fix: Fixes cc bcc being sent wrongly with emails

* fixes values not sycned to parent component

* Update app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue

* Review fixes
2021-12-07 23:44:32 +05:30
Muhsin KelothandGitHub 46afcd9348 fix: Index custom attribute uniqueness on account (#3516)
- Move custom attribute uniqueness validation to account
2021-12-07 18:20:47 +05:30
Nithin David ThomasandGitHub 6b025816f5 fix: Update sidebar toggle icon breaking message view (#3512) 2021-12-06 08:41:34 -08:00
Sivin VargheseandGitHub 3c72a2759f enhancement: Improves sidebar open/close toggle design (#3507) 2021-12-06 18:16:36 +05:30
a98f10130b bug: Fix cannot copy text content from sidebar (#3506)
* bug: Fixes cannot copy text content from sidebar .

* fixes cannot copy issue in sidebar

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-12-06 14:38:04 +05:30
Muhsin KelothandGitHub b46ee5e580 Fix: Conversation status event in widget side (#3509) 2021-12-03 22:45:00 +05:30
thedev105andGitHub 6d378eb206 Fix: Update contact validation messages (#3500)
Fixes #3476
2021-12-03 13:19:11 +05:30
d7cfe6858e feat: Add advanced contact filters (#3471)
Co-authored-by: Tejaswini <tejaswini@chatwoot.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-12-02 19:12:44 -08:00
Sivin VargheseandGitHub 1c29f5bbe4 bug: Fixes missing inbox icon in Twillio SMS channel. (#3502) 2021-12-02 11:47:49 +05:30
8b4134c790 fix: Update route permissions in the new primary menu (#3499)
* fix: Display rolewise primary sidebar

* Fix issues with roles

* Fix active style

* Fix accessible menu

* Fix key missing

* Changes menu icon size

Co-authored-by: Nithin David <1277421+nithindavid@users.noreply.github.com>
2021-12-02 11:02:43 +05:30
Sojan JoseandGitHub b826319776 chore: create CONTRIBUTING.md 2021-12-01 23:21:02 +05:30
Muhsin KelothandGitHub 025bbf1bfb chore: Add i18n survey transaltion in crowdin (#3496) 2021-12-01 18:25:22 +05:30
Nithin David ThomasandGitHub 2a5932cf1b chore: Fixes error in reply box code (#3494) 2021-12-01 16:04:02 +05:30
0a18993b70 fix: Changes thumbnail colors to new color scheme (#3483)
* Enhancement: Updates sidebar to a new design (#2733)

* feat: Changes primary navbar to new design (#2598)

* feat: updates design for secondary navbar (#2612)

* Changes primary nvbar to new design

* Updates design for contexual sidebar

* Fixes issues with JSON

* Remove duplication of notificatons in Navigation

* Fixes broken tests

* Fixes broken tests

* Update app/javascript/dashboard/components/layout/AvailabilityStatus.vue

* Update app/javascript/dashboard/components/layout/AvailabilityStatus.vue

* Update app/javascript/dashboard/components/layout/SidebarItem.vue

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>

* Update app/javascript/dashboard/components/layout/SidebarItem.vue

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>

* Update app/javascript/dashboard/modules/sidebar/components/Secondary.vue

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>

* Chore: Update design changes to features

* Fixes menu transitions and refactors code

* Refactors sidebar routeing logic

* lint error fixes

* Fixes dropdown menu styles

* Fixes secondary new item links

* Fixes lint scss issues

* fixes linter issues

* Fixes broken test cases

* Update AvailabilityStatus.spec.js

* Review feedbacks

* Fixes add modal for label

* Add tooltip for primary menu item

* Tooltip for notifications

* Adds tooltip for primary menu items

* Review fixes

* Review fixes

* Fix merge issues

* fixes logo size for login pages

* fixes Merge breaks with styles

* fix: Changes thumbnail colors to new color scheme

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-12-01 15:18:41 +05:30
b01d032d0d feat: Updates sidebar to accomodate sub menu (#3416)
* Enhancement: Updates sidebar to a new design (#2733)

* feat: Changes primary navbar to new design (#2598)

* feat: updates design for secondary navbar (#2612)

* Changes primary nvbar to new design

* Updates design for contexual sidebar

* Fixes issues with JSON

* Remove duplication of notificatons in Navigation

* Fixes broken tests

* Fixes broken tests

* Update app/javascript/dashboard/components/layout/AvailabilityStatus.vue

* Update app/javascript/dashboard/components/layout/AvailabilityStatus.vue

* Update app/javascript/dashboard/components/layout/SidebarItem.vue

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>

* Update app/javascript/dashboard/components/layout/SidebarItem.vue

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>

* Update app/javascript/dashboard/modules/sidebar/components/Secondary.vue

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>

* Chore: Update design changes to features

* Fixes menu transitions and refactors code

* Refactors sidebar routeing logic

* lint error fixes

* Fixes dropdown menu styles

* Fixes secondary new item links

* Fixes lint scss issues

* fixes linter issues

* Fixes broken test cases

* Update AvailabilityStatus.spec.js

* Review feedbacks

* Fixes add modal for label

* Add tooltip for primary menu item

* Tooltip for notifications

* Adds tooltip for primary menu items

* Review fixes

* Review fixes

* Fix merge issues

* fixes logo size for login pages

* fixes Merge breaks with styles

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-12-01 12:45:39 +05:30
Pranav Raj SandGitHub c792cfc0be feat: Use Fluent SVG icons on the dashboard (#3482) 2021-11-30 21:03:18 -08:00
Pranav Raj SandGitHub 98be3b33c1 fix: Update missing method onNewToastMessage (#3481) 2021-11-30 10:57:44 -08:00
Sojan JoseandGitHub 0115b4ddc4 chore: validation spec for schedules (#3480)
We had instances where after copy-pasting the schedule block, the dev forgets to change the schedule key,
This would break some of the scheduled jobs without explicit errors.

this PR add a spec that will prevent it from happening
2021-11-30 21:44:30 +05:30
Sojan JoseandGitHub d5c30760a7 chore: Whatsapp templates fix for 360 dialog (#3479)
Fixes: #3426
2021-11-30 20:50:35 +05:30
Pranav Raj SandGitHub 0899f62912 fix: Use bus.$off to remove listeners on destroy (#3478) 2021-11-30 10:45:36 +05:30
Sojan JoseandGitHub 86dfdfb9ab chore: fix scheduled jobs (#3473)
- fixes the duplicate schedule job key
2021-11-27 17:08:40 +05:30
Shivam ChaharandGitHub bfcde9b022 chore: Conversation history in email notifications (#3414)
Display recent messages in the notification email when a new conversation is created.

Fixes: #2041
2021-11-27 15:38:27 +05:30
Akhil G KrishnanandGitHub 6a98a812e7 Fix: Outgoing email sender header translation issue (#3393)
Outgoing email-sender header translation fix for "from"

Fixes #3380
2021-11-27 09:46:12 +05:30
Shivam ChaharandGitHub a4ee8ee239 Chore: Improve conversation auto resolution (#3405)
Fixes: #1583
2021-11-27 09:26:18 +05:30
SanjuandGitHub 89f9f39e6e chore: add account id in account settings page (#3365)
Fixes: #3317
2021-11-27 09:07:09 +05:30
Santhosh CandGitHub b326da7d94 feat: Ability to remove user profile picture (#3156)
Fixes #3107
2021-11-27 00:56:07 +05:30
Sojan JoseandGitHub add004a56e Chore: API Improvements (#3469) 2021-11-27 00:48:46 +05:30
Sivin VargheseandGitHub 55843c5bad chore: fixes filter input multiselect height issue (#3466) 2021-11-26 13:41:09 +05:30
2c3c1888f1 Enhancement: Show unread marker on widget bubble (#3390)
* add unread marker

* add removeClass in IFramehelper

* Update app/javascript/sdk/sdk.js

* Update app/javascript/sdk/sdk.js

Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2021-11-25 20:25:14 +05:30
Tejaswini ChileandGitHub b0370ce44d Feat: Fix contact filter pagination (#3463) 2021-11-25 12:01:31 +05:30
Vishnu NarayananandGitHub 3a48e08fe0 feat: migrate facebook env vars to globalConfig (#3369)
Migrate facebook env vars to globalConfig and make it editable from the super admin UI.
2021-11-25 00:55:26 +05:30
Nithin David ThomasandGitHub c23e2c23d4 chore: Update design for filters (#3423) 2021-11-24 14:26:32 +05:30
Tejaswini ChileandGitHub 330a97b5c5 Fix: contact filter values (#3456) 2021-11-24 12:58:00 +05:30
Muhsin KelothandGitHub 00143f7ee5 fix: Render checkbox if string value passed (#3453) 2021-11-24 11:02:45 +05:30
Sivin VargheseandGitHub da8f9d0337 feat: Add support for List and Checkbox in Custom Attributes (#3439) 2021-11-24 09:00:55 +05:30
Pranav Raj SandGitHub 0530e9491c fix: Use role permissions from accounts instead of role attribute (#3445)
Use role permissions from accounts instead of the role attribute

Fixes: #2557
2021-11-23 17:37:01 +05:30
Tejaswini ChileandGitHub 11cd7fd6c5 Feat: Added support changes for contact filters (#3435) 2021-11-23 16:36:44 +05:30
Tejaswini ChileandGitHub 9103fbbdde chore: Update schema files (#3438)
- removes the unintended table from schema files
2021-11-23 16:04:01 +05:30
Sivin VargheseandGitHub e182b59002 bug: fixes link icon doesn't work in the campaign editor (#3447) 2021-11-23 15:26:26 +05:30
Fayaz AhmedandGitHub 7f8204a9da fix: Required check for Conversation filters (#3442) 2021-11-23 09:42:47 +05:30
Sojan 0033a35ab8 Merge branch 'hotfix/1.22.1' into develop
# Conflicts:
#	db/schema.rb
2021-11-22 23:35:44 +05:30
Sojan 5db9d397c5 Merge branch 'hotfix/1.22.1' 2021-11-22 23:34:37 +05:30
791d90c6b7 chore: Migrate PubSub Token to contact inbox (#3434)
At present, the websocket pubsub tokens are present at the contact objects in chatwoot. A better approach would be to have these tokens at the contact_inbox object instead. This helps chatwoot to deliver the websocket events targetted to the specific widget connection, stop contact events from leaking into other chat sessions from the same contact.

Fixes #1682
Fixes #1664

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-11-22 23:32:17 +05:30
Pranav Raj SandGitHub 1a8b8f0900 chore: Move referrerHost to appConfig store (#3433) 2021-11-22 15:05:29 +05:30
Vishnu NarayananandGitHub 1be7c2d72c chore: add DigitialOcean 1-click deployment button (#3421) 2021-11-22 13:20:35 +05:30
Pranav Raj SandGitHub e93e43532a fix: Pass label title instead of id to filter API (#3432) 2021-11-22 12:06:43 +05:30
Sojan JoseandGitHub c332e2df12 chore: Add Code of Conduct 2021-11-20 12:08:45 +05:30
Pranav Raj SandGitHub da163cc1f7 chore: Move unscoped styles to global stylesheet (#3422) 2021-11-19 16:09:20 +05:30
Tejaswini ChileandGitHub 7b44bf5b78 Fix: Filter with label name (#3418) 2021-11-19 13:55:40 +05:30
Aswin Dev P.SandGitHub 24e6a92297 feat: IMAP Email Channel (#3298)
This change allows the user to configure both IMAP and SMTP for an email inbox. IMAP enables the user to see emails in Chatwoot. And user can use SMTP to reply to an email conversation.

Users can use the default settings to send and receive emails for email inboxes if both IMAP and SMTP are disabled.

Fixes #2520
2021-11-19 11:52:27 +05:30
Fayaz AhmedandGitHub 8384d0b38e chore: Update dropdown z-index to be on top of contact details pane (#3411) 2021-11-18 19:55:32 +05:30
c2333214af feat: Add Advanced Conversation Filters (#3239)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
Co-authored-by: Tejaswini <tejaswini@chatwoot.com>
2021-11-18 19:15:02 +05:30
Muhsin KelothandGitHub bf96e8b68d choore: Change values to attribute_values in custom attributes (#3413) 2021-11-18 18:59:28 +05:30
Pranav Raj SandGitHub a3ba8f9e35 feat: Remove ionicons v2 dependency on widget (#3402) 2021-11-18 15:18:51 +05:30
Muhsin KelothandGitHub c2b4991fd8 feat: Add automation route (#3410) 2021-11-18 14:09:55 +05:30
Akhil G KrishnanandGitHub b81a9f2010 Chore: Replaced dependent destroy with dependent destroy_async in all models (#3249) 2021-11-18 10:32:29 +05:30
VinayakandGitHub 4eeaadbd5b chore: Added SMTP_TLS and SMTP_SSL in .env.example
Added SMTP_TLS and SMTP_SSL in .env.example

Fixes #3396
2021-11-17 22:11:27 +05:30
Jan-DavidandGitHub e500d1216b Fix: Make swagger doc compliant to OpenAPI (#3394)
This fixes issues in the swagger.json file. The motivation to do so is to be able to generate API clients using https://openapi-generator.tech Doing so will require further changes to the api spec, but this seems like a good first step since it is now "valid" according to editor.swagger.io and openapi-generator validate.

Fixes #2806
2021-11-17 18:55:15 +05:30
Pranav Raj SandGitHub d227a56747 fix: Set default value of sortBy to empty string (#3406) 2021-11-17 18:27:14 +05:30
Shivam ChaharandGitHub fec4a29081 Feat: Include previous messages in mention/assign notifications email (#3385) 2021-11-17 18:05:53 +05:30
Muhsin KelothandGitHub 9ea42ebff2 chore: Add the support for list and checkbox in custom attribute model (#3400)
ref: #3399
2021-11-16 23:25:19 +05:30
Sojan e5a80195ab Merge branch 'master' into develop 2021-11-15 21:52:59 +05:30
Sojan 928580dd41 Merge branch 'release/1.22.0' into develop 2021-11-15 21:50:54 +05:30
1827 changed files with 77878 additions and 12796 deletions
+16 -4
View File
@@ -7,13 +7,13 @@ defaults: &defaults
working_directory: ~/build
docker:
# specify the version you desire here
- image: cimg/ruby:3.0.2-node
- image: cimg/ruby:3.0.2-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
# documented at https://circleci.com/docs/2.0/circleci-images/
- image: circleci/postgres:alpine
- image: circleci/redis:alpine
- image: cimg/postgres:14.1
- image: cimg/redis:6.2.6
environment:
- CC_TEST_REPORTER_ID: b1b5c4447bf93f6f0b06a64756e35afd0810ea83649f03971cbf303b4449456f
- RAILS_LOG_TO_STDOUT: false
@@ -77,6 +77,18 @@ jobs:
paths:
- cc-test-reporter
# verify swagger specification
- run:
name: Verify swagger API specification
command: |
bundle exec rake swagger:build
if [[ `git status swagger/swagger.json --porcelain` ]]
then
echo "ERROR: The swagger.json file is not in sync with the yaml specification. Run 'rake swagger:build' and commit 'swagger/swagger.json'."
exit 1
fi
curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/5.3.0/openapi-generator-cli-5.3.0.jar > ~/tmp/openapi-generator-cli-5.3.0.jar
java -jar ~/tmp/openapi-generator-cli-5.3.0.jar validate -i swagger/swagger.json
# Database setup
- run: yarn install --check-files
- run: bundle exec rake db:create
@@ -98,7 +110,7 @@ jobs:
- run:
name: Run backend tests
command: |
bundle exec rspec $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings) --profile=10
bundle exec rspec $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings) --profile=10 --format documentation
~/tmp/cc-test-reporter format-coverage -t simplecov -o ~/tmp/codeclimate.backend.json coverage/backend/.resultset.json
- persist_to_workspace:
root: ~/tmp
+32 -19
View File
@@ -1,4 +1,4 @@
version: "2"
version: '2'
plugins:
rubocop:
enabled: false
@@ -17,26 +17,39 @@ checks:
method-count:
enabled: true
config:
threshold: 30
threshold: 32
file-lines:
enabled: true
config:
threshold: 300
method-lines:
config:
threshold: 50
exclude_patterns:
- "spec/"
- "**/specs/"
- "db/*"
- "bin/**/*"
- "db/**/*"
- "config/**/*"
- "public/**/*"
- "vendor/**/*"
- "node_modules/**/*"
- "lib/tasks/auto_annotate_models.rake"
- "app/test-matchers.js"
- "docs/*"
- "**/*.md"
- "**/*.yml"
- "app/javascript/dashboard/i18n/locale"
- "**/*.stories.js"
- "stories/"
- 'spec/'
- '**/specs/'
- 'db/*'
- 'bin/**/*'
- 'db/**/*'
- 'config/**/*'
- 'public/**/*'
- 'vendor/**/*'
- 'node_modules/**/*'
- 'lib/tasks/auto_annotate_models.rake'
- 'app/test-matchers.js'
- 'docs/*'
- '**/*.md'
- '**/*.yml'
- 'app/javascript/dashboard/i18n/locale'
- '**/*.stories.js'
- 'stories/'
- 'app/javascript/dashboard/components/widgets/conversation/advancedFilterItems/index.js'
- 'app/javascript/shared/constants/countries.js'
- 'app/javascript/dashboard/components/widgets/conversation/advancedFilterItems/languages.js'
- 'app/javascript/dashboard/routes/dashboard/contacts/contactFilterItems/index.js'
- 'app/javascript/dashboard/routes/dashboard/settings/automation/constants.js'
- 'app/javascript/dashboard/components/widgets/FilterInput/FilterOperatorTypes.js'
- 'app/javascript/dashboard/routes/dashboard/settings/reports/constants.js'
- 'app/javascript/dashboard/i18n/index.js'
- 'app/javascript/widget/i18n/index.js'
- 'app/javascript/survey/i18n/index.js'
+8
View File
@@ -32,6 +32,11 @@ REDIS_SENTINELS=
# You can find list of master using "SENTINEL masters" command
REDIS_SENTINEL_MASTER_NAME=
# Redis premium breakage in heroku fix
# enable the following configuration
# ref: https://github.com/chatwoot/chatwoot/issues/2420
# REDIS_OPENSSL_VERIFY_MODE=none
# Postgres Database config variables
POSTGRES_HOST=postgres
POSTGRES_USERNAME=postgres
@@ -57,6 +62,9 @@ SMTP_AUTHENTICATION=
SMTP_ENABLE_STARTTLS_AUTO=true
# Can be: 'none', 'peer', 'client_once', 'fail_if_no_peer_cert', see http://api.rubyonrails.org/classes/ActionMailer/Base.html
SMTP_OPENSSL_VERIFY_MODE=peer
# Comment out the following environment variables if required by your SMTP server
# SMTP_TLS=
# SMTP_SSL=
# Mail Incoming
# This is the domain set for the reply emails when conversation continuity is enabled
+3 -2
View File
@@ -28,8 +28,9 @@ module.exports = {
}],
'vue/html-self-closing': 'off',
"vue/no-v-html": 'off',
'import/extensions': ['off']
'vue/singleline-html-element-content-newline': 'off',
'import/extensions': ['off'],
'no-console': 'error'
},
settings: {
'import/resolver': {
+62
View File
@@ -0,0 +1,62 @@
# #
# # This action will publish Chatwoot CE docker image.
# # This is set to run against merges to develop, master
# # and when tags are created.
# #
name: Publish Chatwoot CE docker images
on:
push:
branches:
- develop
- master
tags:
- v*
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
env:
GIT_REF: ${{ github.head_ref || github.ref_name }} # ref_name to get tags/branches
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Strip enterprise code
run: |
rm -rf enterprise
rm -rf spec/enterprise
- name: Set Chatwoot edition
run: |
echo -en '\nENV CW_EDITION="ce"' >> docker/Dockerfile
- name: set docker tag
run: |
echo "DOCKER_TAG=chatwoot/chatwoot:$GIT_REF-ce" >> $GITHUB_ENV
- name: replace docker tag if master
if: github.ref_name == 'master'
run: |
echo "DOCKER_TAG=chatwoot/chatwoot:latest-ce" >> $GITHUB_ENV
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: docker/Dockerfile
push: true
tags: ${{ env.DOCKER_TAG }}
+72
View File
@@ -0,0 +1,72 @@
# #
# # This action will strip the enterprise folder
# # and run the spec.
# # This is set to run against every PR.
# #
name: Run Chatwoot CE spec
on:
push:
branches:
- develop
- master
pull_request:
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:10.8
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ""
POSTGRES_DB: postgres
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
# tmpfs makes DB faster by using RAM
options: >-
--mount type=tmpfs,destination=/var/lib/postgresql/data
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis
ports:
- 6379:6379
options: --entrypoint redis-server
steps:
- uses: actions/checkout@v3
with:
ref: ${{ github.head_ref }}
- uses: ruby/setup-ruby@v1
with:
ruby-version: 3.0.2 # Not needed with a .ruby-version file
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: yarn
run: yarn install
- name: Strip enterprise code
run: |
rm -rf enterprise
rm -rf spec/enterprise
- name: Create database
run: bundle exec rake db:create
- name: Seed database
run: bundle exec rake db:schema:load
- name: yarn check-files
run: yarn install --check-files
# Run rails tests
- name: Run backend tests
run: |
bundle exec rspec --profile=10 --format documentation
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run eslint
bundle exec rubocop -a
git add
+4
View File
@@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
sh bin/validate_push
+17 -1
View File
@@ -11,10 +11,13 @@ Metrics/ClassLength:
Max: 125
Exclude:
- 'app/models/conversation.rb'
- 'app/models/contact.rb'
- 'app/mailers/conversation_reply_mailer.rb'
- 'app/models/message.rb'
- 'app/builders/messages/facebook/message_builder.rb'
- 'app/controllers/api/v1/accounts/contacts_controller.rb'
- 'app/listeners/action_cable_listener.rb'
- 'app/models/conversation.rb'
RSpec/ExampleLength:
Max: 25
Style/Documentation:
@@ -25,6 +28,8 @@ Style/FrozenStringLiteralComment:
Enabled: false
Style/SymbolArray:
Enabled: false
Style/OpenStructUse:
Enabled: false
Style/OptionalBooleanParameter:
Exclude:
- 'app/services/email_templates/db_resolver_service.rb'
@@ -57,7 +62,7 @@ Metrics/BlockLength:
- db/schema.rb
Metrics/ModuleLength:
Exclude:
- lib/woot_message_seeder.rb
- lib/seeders/message_seeder.rb
Rails/ApplicationController:
Exclude:
- 'app/controllers/api/v1/widget/messages_controller.rb'
@@ -67,14 +72,20 @@ Rails/ApplicationController:
- 'app/controllers/platform_controller.rb'
- 'app/controllers/public_controller.rb'
- 'app/controllers/survey/responses_controller.rb'
Rails/CompactBlank:
Enabled: false
Rails/EnvironmentVariableAccess:
Enabled: false
Rails/TimeZoneAssignment:
Enabled: false
Rails/RedundantPresenceValidationOnBelongsTo:
Enabled: false
Style/ClassAndModuleChildren:
EnforcedStyle: compact
Exclude:
- 'config/application.rb'
Style/MapToHash:
Enabled: false
RSpec/NestedGroups:
Enabled: true
Max: 4
@@ -82,11 +93,14 @@ RSpec/MessageSpies:
Enabled: false
RSpec/StubbedMock:
Enabled: false
RSpec/FactoryBot/SyntaxMethods:
Enabled: false
Naming/VariableNumber:
Enabled: false
Metrics/MethodLength:
Exclude:
- 'db/migrate/20161123131628_devise_token_auth_create_users.rb'
- 'db/migrate/20211219031453_update_foreign_keys_on_delete.rb'
Rails/CreateTableWithTimestamps:
Exclude:
- 'db/migrate/20170207092002_acts_as_taggable_on_migration.acts_as_taggable_on_engine.rb'
@@ -102,6 +116,7 @@ Metrics/AbcSize:
- 'db/migrate/20190819005836_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb'
- 'db/migrate/20161123131628_devise_token_auth_create_users.rb'
- 'app/controllers/api/v1/accounts/inboxes_controller.rb'
- 'db/migrate/20211219031453_update_foreign_keys_on_delete.rb'
Metrics/CyclomaticComplexity:
Max: 7
Exclude:
@@ -116,6 +131,7 @@ Rails/ReversibleMigration:
- 'db/migrate/20191020085608_rename_old_tables.rb'
- 'db/migrate/20191126185833_update_user_invite_foreign_key.rb'
- 'db/migrate/20191130164019_add_template_type_to_messages.rb'
- 'db/migrate/20210513083044_remove_not_null_from_webhook_url_channel_api.rb'
Rails/BulkChangeTable:
Exclude:
- 'db/migrate/20161025070152_removechannelsfrommodels.rb'
+128
View File
@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
hello@chatwoot.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
+5
View File
@@ -0,0 +1,5 @@
# Contributing to Chatwoot
Thanks for taking the time to contribute! :tada::+1:
Please refer to our [Contributing Guide](https://www.chatwoot.com/docs/contributing-guide) for detailed instructions on how to contribute.
+9 -2
View File
@@ -42,7 +42,7 @@ gem 'down', '~> 5.0'
gem 'aws-sdk-s3', require: false
gem 'azure-storage-blob', require: false
gem 'google-cloud-storage', require: false
gem 'image_processing'
gem 'image_processing', '~> 1.12.2'
##-- gems for database --#
gem 'groupdate'
@@ -102,7 +102,7 @@ gem 'sentry-ruby'
gem 'sentry-sidekiq'
##-- background job processing --##
gem 'sidekiq'
gem 'sidekiq', '~> 6.4.0'
# We want cron jobs
gem 'sidekiq-cron'
@@ -121,6 +121,13 @@ gem 'hairtrigger'
gem 'procore-sift'
# parse email
gem 'email_reply_trimmer'
gem 'html2text'
# to calculate working hours
gem 'working_hours'
group :production, :staging do
# we dont want request timing out in development while using byebug
gem 'rack-timeout'
+221 -211
View File
@@ -9,73 +9,73 @@ GIT
GEM
remote: https://rubygems.org/
specs:
actioncable (6.1.4.1)
actionpack (= 6.1.4.1)
activesupport (= 6.1.4.1)
actioncable (6.1.4.7)
actionpack (= 6.1.4.7)
activesupport (= 6.1.4.7)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailbox (6.1.4.1)
actionpack (= 6.1.4.1)
activejob (= 6.1.4.1)
activerecord (= 6.1.4.1)
activestorage (= 6.1.4.1)
activesupport (= 6.1.4.1)
actionmailbox (6.1.4.7)
actionpack (= 6.1.4.7)
activejob (= 6.1.4.7)
activerecord (= 6.1.4.7)
activestorage (= 6.1.4.7)
activesupport (= 6.1.4.7)
mail (>= 2.7.1)
actionmailer (6.1.4.1)
actionpack (= 6.1.4.1)
actionview (= 6.1.4.1)
activejob (= 6.1.4.1)
activesupport (= 6.1.4.1)
actionmailer (6.1.4.7)
actionpack (= 6.1.4.7)
actionview (= 6.1.4.7)
activejob (= 6.1.4.7)
activesupport (= 6.1.4.7)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (6.1.4.1)
actionview (= 6.1.4.1)
activesupport (= 6.1.4.1)
actionpack (6.1.4.7)
actionview (= 6.1.4.7)
activesupport (= 6.1.4.7)
rack (~> 2.0, >= 2.0.9)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (6.1.4.1)
actionpack (= 6.1.4.1)
activerecord (= 6.1.4.1)
activestorage (= 6.1.4.1)
activesupport (= 6.1.4.1)
actiontext (6.1.4.7)
actionpack (= 6.1.4.7)
activerecord (= 6.1.4.7)
activestorage (= 6.1.4.7)
activesupport (= 6.1.4.7)
nokogiri (>= 1.8.5)
actionview (6.1.4.1)
activesupport (= 6.1.4.1)
actionview (6.1.4.7)
activesupport (= 6.1.4.7)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
active_record_query_trace (1.8)
activejob (6.1.4.1)
activesupport (= 6.1.4.1)
activejob (6.1.4.7)
activesupport (= 6.1.4.7)
globalid (>= 0.3.6)
activemodel (6.1.4.1)
activesupport (= 6.1.4.1)
activerecord (6.1.4.1)
activemodel (= 6.1.4.1)
activesupport (= 6.1.4.1)
activerecord-import (1.2.0)
activerecord (>= 3.2)
activestorage (6.1.4.1)
actionpack (= 6.1.4.1)
activejob (= 6.1.4.1)
activerecord (= 6.1.4.1)
activesupport (= 6.1.4.1)
activemodel (6.1.4.7)
activesupport (= 6.1.4.7)
activerecord (6.1.4.7)
activemodel (= 6.1.4.7)
activesupport (= 6.1.4.7)
activerecord-import (1.3.0)
activerecord (>= 4.2)
activestorage (6.1.4.7)
actionpack (= 6.1.4.7)
activejob (= 6.1.4.7)
activerecord (= 6.1.4.7)
activesupport (= 6.1.4.7)
marcel (~> 1.0.0)
mini_mime (>= 1.1.0)
activesupport (6.1.4.1)
activesupport (6.1.4.7)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
acts-as-taggable-on (8.1.0)
activerecord (>= 5.0, < 6.2)
acts-as-taggable-on (9.0.1)
activerecord (>= 6.0, < 7.1)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
administrate (0.16.0)
administrate (0.17.0)
actionpack (>= 5.0)
actionview (>= 5.0)
activerecord (>= 5.0)
@@ -85,46 +85,46 @@ GEM
momentjs-rails (~> 2.8)
sassc-rails (~> 2.1)
selectize-rails (~> 0.6)
annotate (3.1.1)
activerecord (>= 3.2, < 7.0)
annotate (3.2.0)
activerecord (>= 3.2, < 8.0)
rake (>= 10.4, < 14.0)
ast (2.4.2)
attr_extras (6.2.4)
attr_extras (6.2.5)
aws-eventstream (1.2.0)
aws-partitions (1.513.0)
aws-sdk-core (3.121.1)
aws-partitions (1.556.0)
aws-sdk-core (3.126.2)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.239.0)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.49.0)
aws-sdk-core (~> 3, >= 3.120.0)
aws-sdk-kms (1.54.0)
aws-sdk-core (~> 3, >= 3.126.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.103.0)
aws-sdk-core (~> 3, >= 3.120.0)
aws-sdk-s3 (1.112.0)
aws-sdk-core (~> 3, >= 3.126.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.4.0)
aws-eventstream (~> 1, >= 1.0.2)
azure-storage-blob (2.0.1)
azure-storage-blob (2.0.3)
azure-storage-common (~> 2.0)
nokogiri (~> 1.11.0.rc2)
azure-storage-common (2.0.2)
nokogiri (~> 1, >= 1.10.8)
azure-storage-common (2.0.4)
faraday (~> 1.0)
faraday_middleware (~> 1.0.0.rc1)
faraday_middleware (~> 1.0, >= 1.0.0.rc1)
net-http-persistent (~> 4.0)
nokogiri (~> 1.11.0.rc2)
nokogiri (~> 1, >= 1.10.8)
barnes (0.0.9)
multi_json (~> 1)
statsd-ruby (~> 1.1)
bcrypt (3.1.16)
bindex (0.8.1)
bootsnap (1.9.1)
msgpack (~> 1.0)
brakeman (5.1.1)
bootsnap (1.10.3)
msgpack (~> 1.2)
brakeman (5.2.1)
browser (5.3.1)
builder (3.2.4)
bullet (6.1.5)
bullet (7.0.1)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
bundle-audit (0.1.0)
@@ -135,13 +135,13 @@ GEM
byebug (11.1.3)
climate_control (1.0.1)
coderay (1.1.3)
commonmarker (0.23.2)
commonmarker (0.23.4)
concurrent-ruby (1.1.9)
connection_pool (2.2.5)
crack (0.4.5)
rexml
crass (1.0.6)
cypress-on-rails (1.11.0)
cypress-on-rails (1.12.1)
rack
database_cleaner (2.0.1)
database_cleaner-active_record (~> 2.0.0)
@@ -151,11 +151,12 @@ GEM
database_cleaner-core (2.0.1)
datetime_picker_rails (0.0.7)
momentjs-rails (>= 2.8.1)
ddtrace (0.53.0)
ffi (~> 1.0)
ddtrace (0.54.2)
debase-ruby_core_source (<= 0.10.14)
msgpack
debase-ruby_core_source (0.10.14)
declarative (0.0.20)
devise (4.8.0)
devise (4.8.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
@@ -165,7 +166,7 @@ GEM
bcrypt (~> 3.0)
devise (> 3.5.2, < 5)
rails (>= 4.2.0, < 6.2)
diff-lcs (1.4.4)
diff-lcs (1.5.0)
digest-crc (0.6.4)
rake (>= 12.0.0, < 14.0.0)
docile (1.4.0)
@@ -175,13 +176,14 @@ GEM
dotenv-rails (2.7.6)
dotenv (= 2.7.6)
railties (>= 3.2)
down (5.2.4)
down (5.3.0)
addressable (~> 2.8)
ecma-re-validator (0.3.0)
regexp_parser (~> 2.0)
ecma-re-validator (0.4.0)
regexp_parser (~> 2.2)
email_reply_trimmer (0.1.13)
erubi (1.10.0)
erubis (2.7.0)
et-orbi (1.2.5)
et-orbi (1.2.6)
tzinfo
execjs (2.8.1)
facebook-messenger (2.0.1)
@@ -196,11 +198,11 @@ GEM
i18n (>= 1.6, < 2)
faraday (1.0.1)
multipart-post (>= 1.2, < 3)
faraday_middleware (1.0.0)
faraday_middleware (1.2.0)
faraday (~> 1.0)
fcm (1.0.3)
fcm (1.0.5)
faraday (~> 1)
ffi (1.15.4)
ffi (1.15.5)
flag_shih_tzu (0.3.23)
flay (2.12.1)
erubis (~> 2.7.0)
@@ -217,11 +219,11 @@ GEM
googleapis-common-protos-types (>= 1.0.4, < 2.0)
googleauth (~> 0.9)
grpc (~> 1.25)
geocoder (1.7.0)
gli (2.20.1)
globalid (0.5.2)
geocoder (1.7.3)
gli (2.21.0)
globalid (1.0.0)
activesupport (>= 5.0)
google-apis-core (0.4.1)
google-apis-core (0.4.2)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -230,9 +232,9 @@ GEM
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.7.0)
google-apis-iamcredentials_v1 (0.10.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-storage_v1 (0.8.0)
google-apis-storage_v1 (0.11.0)
google-apis-core (>= 0.4, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
@@ -246,22 +248,22 @@ GEM
google-cloud-env (1.5.0)
faraday (>= 0.17.3, < 2.0)
google-cloud-errors (1.2.0)
google-cloud-storage (1.34.1)
addressable (~> 2.5)
google-cloud-storage (1.36.1)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.1)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
google-protobuf (3.18.1)
google-protobuf (3.18.1-universal-darwin)
google-protobuf (3.18.1-x86_64-linux)
google-protobuf (3.19.4)
google-protobuf (3.19.4-x86_64-darwin)
google-protobuf (3.19.4-x86_64-linux)
googleapis-common-protos (1.3.12)
google-protobuf (~> 3.14)
googleapis-common-protos-types (~> 1.2)
grpc (~> 1.27)
googleapis-common-protos-types (1.2.0)
googleapis-common-protos-types (1.3.0)
google-protobuf (~> 3.14)
googleauth (0.17.1)
faraday (>= 0.17.3, < 2.0)
@@ -270,26 +272,28 @@ GEM
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (~> 0.15)
groupdate (5.2.2)
activesupport (>= 5)
grpc (1.41.0)
google-protobuf (~> 3.17)
groupdate (6.0.1)
activesupport (>= 5.2)
grpc (1.43.1)
google-protobuf (~> 3.18)
googleapis-common-protos-types (~> 1.0)
grpc (1.41.0-universal-darwin)
google-protobuf (~> 3.17)
grpc (1.43.1-universal-darwin)
google-protobuf (~> 3.18)
googleapis-common-protos-types (~> 1.0)
grpc (1.41.0-x86_64-linux)
google-protobuf (~> 3.17)
grpc (1.43.1-x86_64-linux)
google-protobuf (~> 3.18)
googleapis-common-protos-types (~> 1.0)
haikunator (1.1.1)
hairtrigger (0.2.24)
activerecord (>= 5.0, < 7)
hairtrigger (0.2.25)
activerecord (>= 5.0, < 8)
ruby2ruby (~> 2.4)
ruby_parser (~> 3.10)
hana (1.3.7)
hashdiff (1.0.1)
hashie (4.1.0)
hashie (5.0.0)
hkdf (0.3.0)
html2text (0.2.1)
nokogiri (~> 1.6)
http-accept (1.7.0)
http-cookie (1.0.4)
domain_name (~> 0.5)
@@ -297,53 +301,55 @@ GEM
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
i18n (1.8.10)
i18n (1.10.0)
concurrent-ruby (~> 1.0)
image_processing (1.12.1)
image_processing (1.12.2)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
jbuilder (2.11.2)
jbuilder (2.11.5)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
jmespath (1.4.0)
jmespath (1.6.0)
jquery-rails (4.4.0)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (2.5.1)
json_refs (0.1.6)
json (2.6.1)
json_refs (0.1.7)
hana
json_schemer (0.2.18)
json_schemer (0.2.19)
ecma-re-validator (~> 0.3)
hana (~> 1.3)
regexp_parser (~> 2.0)
uri_template (~> 0.7)
jwt (2.3.0)
kaminari (1.2.1)
kaminari (1.2.2)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.1)
kaminari-activerecord (= 1.2.1)
kaminari-core (= 1.2.1)
kaminari-actionview (1.2.1)
kaminari-actionview (= 1.2.2)
kaminari-activerecord (= 1.2.2)
kaminari-core (= 1.2.2)
kaminari-actionview (1.2.2)
actionview
kaminari-core (= 1.2.1)
kaminari-activerecord (1.2.1)
kaminari-core (= 1.2.2)
kaminari-activerecord (1.2.2)
activerecord
kaminari-core (= 1.2.1)
kaminari-core (1.2.1)
koala (3.0.0)
kaminari-core (= 1.2.2)
kaminari-core (1.2.2)
koala (3.1.0)
addressable
faraday
faraday (< 2)
json (>= 1.8)
rexml
launchy (2.5.0)
addressable (~> 2.7)
letter_opener (1.7.0)
launchy (~> 2.2)
line-bot-api (1.22.0)
line-bot-api (1.23.0)
liquid (5.1.0)
listen (3.7.0)
listen (3.7.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
loofah (2.12.0)
loofah (2.14.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
@@ -352,43 +358,43 @@ GEM
maxminddb (0.1.22)
memoist (0.16.2)
method_source (1.0.0)
mime-types (3.3.1)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2021.0901)
mime-types-data (3.2022.0105)
mini_magick (4.11.0)
mini_mime (1.1.2)
mini_portile2 (2.5.3)
minitest (5.14.4)
mock_redis (0.29.0)
mini_portile2 (2.8.0)
minitest (5.15.0)
mock_redis (0.30.0)
ruby2_keywords
momentjs-rails (2.20.1)
momentjs-rails (2.29.1.1)
railties (>= 3.1)
msgpack (1.4.2)
msgpack (1.4.5)
multi_json (1.15.0)
multi_xml (0.6.0)
multipart-post (2.1.1)
net-http-persistent (4.0.1)
connection_pool (~> 2.2)
netrc (0.11.0)
newrelic_rpm (8.0.0)
newrelic_rpm (8.4.0)
nio4r (2.5.8)
nokogiri (1.11.7)
mini_portile2 (~> 2.5.0)
nokogiri (1.13.4)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
nokogiri (1.11.7-arm64-darwin)
nokogiri (1.13.4-arm64-darwin)
racc (~> 1.4)
nokogiri (1.11.7-x86_64-darwin)
nokogiri (1.13.4-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.11.7-x86_64-linux)
nokogiri (1.13.4-x86_64-linux)
racc (~> 1.4)
oauth (0.5.6)
oauth (0.5.8)
orm_adapter (0.5.0)
os (1.1.1)
os (1.1.4)
parallel (1.21.0)
parser (3.0.2.0)
parser (3.1.1.0)
ast (~> 2.4.1)
path_expander (1.1.0)
pg (1.2.3)
pg (1.3.2)
procore-sift (0.16.0)
rails (> 4.2.0)
pry (0.14.1)
@@ -397,57 +403,57 @@ GEM
pry-rails (0.3.9)
pry (>= 0.10.4)
public_suffix (4.0.6)
puma (5.5.2)
puma (5.6.4)
nio4r (~> 2.0)
pundit (2.1.1)
pundit (2.2.0)
activesupport (>= 3.0.0)
raabro (1.4.0)
racc (1.5.2)
racc (1.6.0)
rack (2.2.3)
rack-attack (6.5.0)
rack-attack (6.6.0)
rack (>= 1.0, < 3)
rack-cors (1.1.1)
rack (>= 2.0.0)
rack-proxy (0.7.0)
rack-proxy (0.7.2)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
rack-timeout (0.6.0)
rails (6.1.4.1)
actioncable (= 6.1.4.1)
actionmailbox (= 6.1.4.1)
actionmailer (= 6.1.4.1)
actionpack (= 6.1.4.1)
actiontext (= 6.1.4.1)
actionview (= 6.1.4.1)
activejob (= 6.1.4.1)
activemodel (= 6.1.4.1)
activerecord (= 6.1.4.1)
activestorage (= 6.1.4.1)
activesupport (= 6.1.4.1)
rails (6.1.4.7)
actioncable (= 6.1.4.7)
actionmailbox (= 6.1.4.7)
actionmailer (= 6.1.4.7)
actionpack (= 6.1.4.7)
actiontext (= 6.1.4.7)
actionview (= 6.1.4.7)
activejob (= 6.1.4.7)
activemodel (= 6.1.4.7)
activerecord (= 6.1.4.7)
activestorage (= 6.1.4.7)
activesupport (= 6.1.4.7)
bundler (>= 1.15.0)
railties (= 6.1.4.1)
railties (= 6.1.4.7)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.4.2)
loofah (~> 2.3)
railties (6.1.4.1)
actionpack (= 6.1.4.1)
activesupport (= 6.1.4.1)
railties (6.1.4.7)
actionpack (= 6.1.4.7)
activesupport (= 6.1.4.7)
method_source
rake (>= 0.13)
thor (~> 1.0)
rainbow (3.0.0)
rainbow (3.1.1)
rake (13.0.6)
rb-fsevent (0.11.0)
rb-fsevent (0.11.1)
rb-inotify (0.10.1)
ffi (~> 1.0)
redis (4.4.0)
redis (4.6.0)
redis-namespace (1.8.1)
redis (>= 3.0.4)
regexp_parser (2.1.1)
regexp_parser (2.2.1)
representable (3.1.1)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
@@ -462,19 +468,19 @@ GEM
netrc (~> 0.8)
retriable (3.1.2)
rexml (3.2.5)
rspec (3.10.0)
rspec-core (~> 3.10.0)
rspec-expectations (~> 3.10.0)
rspec-mocks (~> 3.10.0)
rspec-core (3.10.1)
rspec-support (~> 3.10.0)
rspec-expectations (3.10.1)
rspec (3.11.0)
rspec-core (~> 3.11.0)
rspec-expectations (~> 3.11.0)
rspec-mocks (~> 3.11.0)
rspec-core (3.11.0)
rspec-support (~> 3.11.0)
rspec-expectations (3.11.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0)
rspec-mocks (3.10.2)
rspec-support (~> 3.11.0)
rspec-mocks (3.11.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0)
rspec-rails (5.0.2)
rspec-support (~> 3.11.0)
rspec-rails (5.0.3)
actionpack (>= 5.2)
activesupport (>= 5.2)
railties (>= 5.2)
@@ -482,36 +488,36 @@ GEM
rspec-expectations (~> 3.10)
rspec-mocks (~> 3.10)
rspec-support (~> 3.10)
rspec-support (3.10.2)
rubocop (1.22.1)
rspec-support (3.11.0)
rubocop (1.25.1)
parallel (~> 1.10)
parser (>= 3.0.0.0)
parser (>= 3.1.0.0)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml
rubocop-ast (>= 1.12.0, < 2.0)
rubocop-ast (>= 1.15.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.12.0)
parser (>= 3.0.1.1)
rubocop-performance (1.11.5)
rubocop-ast (1.16.0)
parser (>= 3.1.1.0)
rubocop-performance (1.13.2)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
rubocop-rails (2.12.3)
rubocop-rails (2.13.2)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.7.0, < 2.0)
rubocop-rspec (2.5.0)
rubocop-rspec (2.8.0)
rubocop (~> 1.19)
ruby-progressbar (1.11.0)
ruby-vips (2.1.3)
ruby-vips (2.1.4)
ffi (~> 1.12)
ruby2_keywords (0.0.5)
ruby2ruby (2.4.4)
ruby_parser (~> 3.1)
sexp_processor (~> 4.6)
ruby_parser (3.17.0)
sexp_processor (~> 4.15, >= 4.15.1)
ruby_parser (3.18.1)
sexp_processor (~> 4.16)
sassc (2.4.0)
ffi (~> 1.9)
sassc-rails (2.1.2)
@@ -520,30 +526,28 @@ GEM
sprockets (> 3.0)
sprockets-rails
tilt
scout_apm (4.1.2)
scout_apm (5.1.1)
parser
seed_dump (3.3.1)
activerecord (>= 4)
activesupport (>= 4)
selectize-rails (0.12.6)
semantic_range (3.0.0)
sentry-rails (4.7.3)
sentry-rails (5.1.0)
railties (>= 5.0)
sentry-ruby-core (~> 4.7.0)
sentry-ruby (4.7.3)
sentry-ruby-core (~> 5.1.0)
sentry-ruby (5.1.0)
concurrent-ruby (~> 1.0, >= 1.0.2)
faraday (>= 1.0)
sentry-ruby-core (= 4.7.3)
sentry-ruby-core (4.7.3)
sentry-ruby-core (= 5.1.0)
sentry-ruby-core (5.1.0)
concurrent-ruby
faraday
sentry-sidekiq (4.7.3)
sentry-ruby-core (~> 4.7.0)
sentry-sidekiq (5.1.0)
sentry-ruby-core (~> 5.1.0)
sidekiq (>= 3.0)
sexp_processor (4.15.3)
shoulda-matchers (5.0.0)
sexp_processor (4.16.0)
shoulda-matchers (5.1.0)
activesupport (>= 5.2.0)
sidekiq (6.2.2)
sidekiq (6.4.1)
connection_pool (>= 2.2.2)
rack (~> 2.0)
redis (>= 4.2.0)
@@ -560,7 +564,7 @@ GEM
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
slack-ruby-client (0.17.0)
slack-ruby-client (1.0.0)
faraday (>= 1.0)
faraday_middleware
gli
@@ -570,22 +574,22 @@ GEM
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
sprockets (4.0.2)
sprockets (4.0.3)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.2)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets-rails (3.4.2)
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
squasher (0.6.2)
statsd-ruby (1.5.0)
telephone_number (1.4.12)
thor (1.1.0)
telephone_number (1.4.13)
thor (1.2.1)
tilt (2.0.10)
time_diff (0.3.0)
activesupport
i18n
trailblazer-option (0.1.1)
trailblazer-option (0.1.2)
twilio-ruby (5.32.0)
faraday (~> 1.0.0)
jwt (>= 1.5, <= 2.5)
@@ -594,7 +598,7 @@ GEM
oauth
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
tzinfo-data (1.2021.3)
tzinfo-data (1.2021.5)
tzinfo (>= 1.0.0)
uber (0.1.0)
uglifier (4.2.0)
@@ -605,12 +609,12 @@ GEM
unicode-display_width (2.1.0)
uniform_notifier (1.14.2)
uri_template (0.7.0)
valid_email2 (4.0.0)
valid_email2 (4.0.3)
activemodel (>= 3.2)
mail (~> 2.5)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.1.0)
web-console (4.2.0)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
@@ -632,7 +636,10 @@ GEM
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
wisper (2.0.0)
zeitwerk (2.4.2)
working_hours (1.4.1)
activesupport (>= 3.2)
tzinfo
zeitwerk (2.5.4)
PLATFORMS
arm64-darwin-20
@@ -668,6 +675,7 @@ DEPENDENCIES
devise_token_auth
dotenv-rails
down (~> 5.0)
email_reply_trimmer
facebook-messenger
factory_bot_rails
faker
@@ -682,7 +690,8 @@ DEPENDENCIES
haikunator
hairtrigger
hashie
image_processing
html2text
image_processing (~> 1.12.2)
jbuilder
json_refs
json_schemer
@@ -721,7 +730,7 @@ DEPENDENCIES
sentry-ruby
sentry-sidekiq
shoulda-matchers
sidekiq
sidekiq (~> 6.4.0)
sidekiq-cron
simplecov (= 0.17.1)
slack-ruby-client
@@ -740,9 +749,10 @@ DEPENDENCIES
webpacker (~> 5.x)
webpush
wisper (= 2.0.0)
working_hours
RUBY VERSION
ruby 3.0.2p107
BUNDLED WITH
2.2.25
2.3.8
+6 -2
View File
@@ -1,7 +1,11 @@
The MIT License (MIT)
Copyright (c) 2017-2021 Chatwoot Inc.
Portions of this software are licensed as follows:
* All content that resides under the "enterprise/" directory of this repository, if that directory exists, is licensed under the license defined in "enterprise/LICENSE".
* All third party components incorporated into the Chatwoot Software are licensed under the original license provided by the owner of the applicable component.
* Content outside of the above mentioned directories or restrictions above is available under the "MIT Expat" license as defined below.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
+33 -17
View File
@@ -6,7 +6,10 @@
<p align="center">
<a href="https://heroku.com/deploy?template=https://github.com/chatwoot/chatwoot/tree/master" alt="Deploy to Heroku">
<img alt="Deploy" src="https://www.herokucdn.com/deploy/button.svg"/>
<img width="150" alt="Deploy" src="https://www.herokucdn.com/deploy/button.svg"/>
</a>
<a href="https://marketplace.digitalocean.com/apps/chatwoot?refcode=f2238426a2a8" alt="Deploy to DigitalOcean">
<img width="200" alt="Deploy to DO" src="https://www.deploytodo.com/do-btn-blue.svg"/>
</a>
</p>
@@ -17,7 +20,6 @@ ___
<img src="https://img.shields.io/circleci/build/github/chatwoot/chatwoot" alt="CircleCI Badge">
<a href="https://hub.docker.com/r/chatwoot/chatwoot/"><img src="https://img.shields.io/docker/pulls/chatwoot/chatwoot" alt="Docker Pull Badge"></a>
<a href="https://hub.docker.com/r/chatwoot/chatwoot/"><img src="https://img.shields.io/docker/cloud/build/chatwoot/chatwoot" alt="Docker Build Badge"></a>
<img src="https://img.shields.io/github/license/chatwoot/chatwoot" alt="License">
<img src="https://img.shields.io/github/commit-activity/m/chatwoot/chatwoot" alt="Commits-per-month">
<a title="Crowdin" target="_self" href="https://chatwoot.crowdin.com/chatwoot"><img src="https://badges.crowdin.net/e/37ced7eba411064bd792feb3b7a28b16/localized.svg"></a>
<a href="https://discord.gg/cJXdrwS"><img src="https://img.shields.io/discord/647412545203994635" alt="Discord"></a>
@@ -26,34 +28,39 @@ ___
<a href="https://status.chatwoot.com"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fchatwoot%2Fstatus%2Fmaster%2Fapi%2Fchatwoot%2Fresponse-time.json" alt="response time"></a>
</p>
<img src="https://s3.us-west-2.amazonaws.com/gh-assets.chatwoot.com/chatwoot-dashboard-assets.png" width="100%" alt="Chat dashboard"/>
<img src="https://chatwoot-public-assets.s3.amazonaws.com/github/screenshot.png" width="100%" alt="Chat dashboard"/>
Chatwoot is an open-source omnichannel customer support software. The development of Chatwoot started in 2016. It failed to succeed as a business and eventually shut up shop in 2017. During 2019 #Hacktoberfest, the maintainers decided to make it open-source, instead of letting the code rust in a private repo. With a pleasant surprise, Chatwoot became a trending project on Hacker News and best of all, got lots of love from the community.
Now, a failed project is back on track and the prospects are looking great. The team is back to working on the project and this time, we are building it in the open. Thanks to the ideas and contributions from the community.
Chatwoot is an open-source, self-hosted customer engagement suite. Chatwoot lets you view and manage your customer data, communicate with them irrespective of which medium they use, and re-engage them based on their profile.
## Features
Chatwoot gives an integrated view of conversations happening in different communication channels.
It supports the following conversation channels:
Chatwoot supports the following conversation channels:
- **Website**: Talk to your customers using our live chat widget and make use of our SDK to identify a user and provide contextual support.
- **Facebook**: Connect your Facebook pages and start replying to the direct messages to your page.
- **Instagram**: Connect your Instagram profile and start replying to the direct messages.
- **Twitter**: Connect your Twitter profiles and reply to direct messages or the tweets where you are mentioned.
- **Whatsapp**: Connect your Whatsapp business account and manage the conversation in Chatwoot
- **SMS**: Connect your Twilio SMS account and reply to the SMS queries in Chatwoot
- **Telegram**: Connect your Telegram bot and reply to your customers right from a single dashboard.
- **WhatsApp**: Connect your WhatsApp business account and manage the conversation in Chatwoot.
- **Line**: Connect your Line account and manage the conversations in Chatwoot.
- **SMS**: Connect your Twilio SMS account and reply to the SMS queries in Chatwoot.
- **API Channel**: Build custom communication channels using our API channel.
- **Email (beta)**: Forward all your email queries to Chatwoot and view it in our integrated dashboard.
- **Email**: Forward all your email queries to Chatwoot and view it in our integrated dashboard.
And more.
Other features include:
- **Multi-brand inboxes**: Manage multiple brands or pages using a single dashboard.
- **Private notes**: Inter team communication is possible using private notes in a conversation.
- **CRM**: Save all your customer information right inside Chatwoot, use contact notes to log emails, phone calls, or meeting notes.
- **Custom Attributes**: Define custom attribute attributes to store information about a contact or a conversation and extend the product to match your workflow.
- **Shared multi-brand inboxes**: Manage multiple brands or pages using a shared inbox.
- **Private notes**: Use @mentions and private notes to communicate internally about a conversation.
- **Canned responses (Saved replies)**: Improve the response rate by adding saved replies for frequently asked questions.
- **Conversation Labels**: Use conversation labelling to create custom workflows.
- **Conversation Labels**: Use conversation labels to create custom workflows.
- **Auto assignment**: Chatwoot intelligently assigns a ticket to the agents who have access to the inbox depending on their availability and load.
- **Conversation continuity**: If the user has provided an email address through the chat widget, Chatwoot would send an email to the customer under the agent name so that the user can continue the conversation over the email.
- **Conversation continuity**: If the user has provided an email address through the chat widget, Chatwoot will send an email to the customer under the agent name so that the user can continue the conversation over the email.
- **Multi-lingual support**: Chatwoot supports 10+ languages.
- **Powerful API & Webhooks**: Extend the capability of the software using Chatwoots webhooks and APIs.
- **Integrations**: Chatwoot natively integrates with Slack right now. Manage your conversations in Slack without logging into the dashboard.
@@ -81,9 +88,18 @@ Deploying Chatwoot to Heroku is a breeze. It's as simple as clicking this button
Follow this [link](https://www.chatwoot.com/docs/environment-variables) to understand setting the correct environment variables for the app to work with all the features. There might be breakages if you do not set the relevant environment variables.
### DigitalOcean 1-Click Kubernetes deployment
Chatwoot now supports 1-Click deployment to DigitalOcean as a kubernetes app.
<a href="https://marketplace.digitalocean.com/apps/chatwoot?refcode=f2238426a2a8" alt="Deploy to DigitalOcean">
<img width="200" alt="Deploy to DO" src="https://www.deploytodo.com/do-btn-blue.svg"/>
</a>
### Other deployment options
Please follow [deployment architecture guide](https://www.chatwoot.com/docs/deployment/architecture) to deploy with Docker or Caprover.
For other supported options, checkout our [deployment page](https://chatwoot.com/deploy).
## Security
@@ -102,4 +118,4 @@ Thanks goes to all these [wonderful people](https://www.chatwoot.com/docs/contri
<a href="https://github.com/chatwoot/chatwoot/graphs/contributors"><img src="https://opencollective.com/chatwoot/contributors.svg?width=890&button=false" /></a>
*Chatwoot* &copy; 2017-2021, Chatwoot Inc - Released under the MIT License.
*Chatwoot* &copy; 2017-2022, Chatwoot Inc - Released under the MIT License.
+4
View File
@@ -32,6 +32,10 @@
"INSTALLATION_ENV": {
"description": "Installation method used for Chatwoot.",
"value": "heroku"
},
"REDIS_OPENSSL_VERIFY_MODE":{
"description": "OpenSSL verification mode for Redis connections. ref https://help.heroku.com/HC0F8CUS/redis-connection-issues",
"value": "none"
}
},
"formation": {
+13 -2
View File
@@ -52,12 +52,11 @@ class ContactIdentifyAction
end
def update_contact
custom_attributes = params[:custom_attributes] ? @contact.custom_attributes.merge(params[:custom_attributes]) : @contact.custom_attributes
# blank identifier or email will throw unique index error
# TODO: replace reject { |_k, v| v.blank? } with compact_blank when rails is upgraded
@contact.update!(params.slice(:name, :email, :identifier, :phone_number).reject do |_k, v|
v.blank?
end.merge({ custom_attributes: custom_attributes }))
end.merge({ custom_attributes: custom_attributes, additional_attributes: additional_attributes }))
ContactAvatarJob.perform_later(@contact, params[:avatar_url]) if params[:avatar_url].present?
end
@@ -68,4 +67,16 @@ class ContactIdentifyAction
mergee_contact: merge_contact
).perform
end
def custom_attributes
params[:custom_attributes] ? @contact.custom_attributes.deep_merge(params[:custom_attributes].stringify_keys) : @contact.custom_attributes
end
def additional_attributes
if params[:additional_attributes]
@contact.additional_attributes.deep_merge(params[:additional_attributes].stringify_keys)
else
@contact.additional_attributes
end
end
end
+2 -3
View File
@@ -48,11 +48,10 @@ class ContactMergeAction
# attributes in base contact are given preference
merged_attributes = mergee_contact_attributes.deep_merge(base_contact_attributes)
# retaining old pubsub token to notify the contacts that are listening
mergee_pubsub_token = mergee_contact.pubsub_token
@mergee_contact.destroy!
Rails.configuration.dispatcher.dispatch(CONTACT_MERGED, Time.zone.now, contact: @base_contact, tokens: [mergee_pubsub_token])
Rails.configuration.dispatcher.dispatch(CONTACT_MERGED, Time.zone.now, contact: @base_contact,
tokens: [@base_contact.contact_inboxes.filter_map(&:pubsub_token)])
@base_contact.update!(merged_attributes)
end
end
+2 -1
View File
@@ -2,7 +2,7 @@
class AccountBuilder
include CustomExceptions::Account
pattr_initialize [:account_name!, :email!, :confirmed, :user, :user_full_name, :user_password]
pattr_initialize [:account_name!, :email!, :confirmed, :user, :user_full_name, :user_password, :super_admin]
def perform
if @user.nil?
@@ -65,6 +65,7 @@ class AccountBuilder
password: user_password,
password_confirmation: user_password,
name: @user_full_name)
@user.type = 'SuperAdmin' if @super_admin
@user.confirm if @confirmed
@user.save!
end
+3 -2
View File
@@ -33,7 +33,8 @@ class ContactBuilder
phone_number: contact_attributes[:phone_number],
email: contact_attributes[:email],
identifier: contact_attributes[:identifier],
additional_attributes: contact_attributes[:additional_attributes]
additional_attributes: contact_attributes[:additional_attributes],
custom_attributes: contact_attributes[:custom_attributes]
)
end
@@ -69,7 +70,7 @@ class ContactBuilder
update_contact_avatar(contact)
contact_inbox
rescue StandardError => e
Rails.logger.info e
Rails.logger.error e
raise e
end
end
+19 -5
View File
@@ -4,7 +4,7 @@ class ContactInboxBuilder
def perform
@contact = Contact.find(contact_id)
@inbox = @contact.account.inboxes.find(inbox_id)
return unless ['Channel::TwilioSms', 'Channel::Email', 'Channel::Api'].include? @inbox.channel_type
return unless ['Channel::TwilioSms', 'Channel::Sms', 'Channel::Email', 'Channel::Api', 'Channel::Whatsapp'].include? @inbox.channel_type
source_id = @source_id || generate_source_id
create_contact_inbox(source_id) if source_id.present?
@@ -13,11 +13,25 @@ class ContactInboxBuilder
private
def generate_source_id
return twilio_source_id if @inbox.channel_type == 'Channel::TwilioSms'
return @contact.email if @inbox.channel_type == 'Channel::Email'
return SecureRandom.uuid if @inbox.channel_type == 'Channel::Api'
case @inbox.channel_type
when 'Channel::TwilioSms'
twilio_source_id
when 'Channel::Whatsapp'
wa_source_id
when 'Channel::Email'
@contact.email
when 'Channel::Sms'
@contact.phone_number
when 'Channel::Api'
SecureRandom.uuid
end
end
nil
def wa_source_id
return unless @contact.phone_number
# whatsapp doesn't want the + in e164 format
"#{@contact.phone_number}.delete('+')"
end
def twilio_source_id
@@ -27,7 +27,7 @@ class Messages::Facebook::MessageBuilder < Messages::Messenger::MessageBuilder
end
ensure_contact_avatar
rescue Koala::Facebook::AuthenticationError
Rails.logger.info "Facebook Authorization expired for Inbox #{@inbox.id}"
Rails.logger.error "Facebook Authorization expired for Inbox #{@inbox.id}"
rescue StandardError => e
Sentry.capture_exception(e)
true
+6 -3
View File
@@ -8,9 +8,11 @@ class Messages::MessageBuilder
@conversation = conversation
@user = user
@message_type = params[:message_type] || 'outgoing'
@items = params.to_unsafe_h&.dig(:content_attributes, :items)
@attachments = params[:attachments]
return unless params.instance_of?(ActionController::Parameters)
@in_reply_to = params.to_unsafe_h&.dig(:content_attributes, :in_reply_to)
@items = params.to_unsafe_h&.dig(:content_attributes, :items)
end
def perform
@@ -27,11 +29,12 @@ class Messages::MessageBuilder
return if @attachments.blank?
@attachments.each do |uploaded_attachment|
@message.attachments.build(
attachment = @message.attachments.build(
account_id: @message.account_id,
file_type: file_type(uploaded_attachment&.content_type),
file: uploaded_attachment
)
attachment.file_type = file_type(uploaded_attachment&.content_type) if uploaded_attachment.is_a?(ActionDispatch::Http::UploadedFile)
end
end
@@ -1,10 +1,14 @@
class Messages::Messenger::MessageBuilder
include ::FileTypeHelper
def process_attachment(attachment)
return if attachment['type'].to_sym == :template
attachment_obj = @message.attachments.new(attachment_params(attachment).except(:remote_file_url))
attachment_obj.save!
attach_file(attachment_obj, attachment_params(attachment)[:remote_file_url]) if attachment_params(attachment)[:remote_file_url]
fetch_story_link(attachment_obj) if attachment_obj.file_type == 'story_mention'
update_attachment_file_type(attachment_obj)
end
def attach_file(attachment, file_url)
@@ -22,7 +26,7 @@ class Messages::Messenger::MessageBuilder
file_type = attachment['type'].to_sym
params = { file_type: file_type, account_id: @message.account_id }
if [:image, :file, :audio, :video].include? file_type
if [:image, :file, :audio, :video, :share, :story_mention].include? file_type
params.merge!(file_type_params(attachment))
elsif file_type == :location
params.merge!(location_params(attachment))
@@ -39,4 +43,31 @@ class Messages::Messenger::MessageBuilder
remote_file_url: attachment['payload']['url']
}
end
def update_attachment_file_type(attachment)
return unless attachment.file_type == 'share' || attachment.file_type == 'story_mention'
attachment.file_type = file_type(attachment.file&.content_type)
attachment.save!
end
def fetch_story_link(attachment)
message = attachment.message
begin
k = Koala::Facebook::API.new(@inbox.channel.page_access_token) if @inbox.facebook?
result = k.get_object(message.source_id, fields: %w[story from]) || {}
rescue Koala::Facebook::AuthenticationError
@inbox.channel.authorization_error!
raise
rescue StandardError => e
result = {}
Sentry.capture_exception(e)
end
story_id = result['story']['mention']['id']
story_sender = result['from']['username']
message.content_attributes[:story_sender] = story_sender
message.content_attributes[:story_id] = story_id
message.content = I18n.t('conversations.messages.instagram_story_content', story_sender: story_sender)
message.save!
end
end
+49 -63
View File
@@ -1,10 +1,16 @@
class V2::ReportBuilder
include DateRangeHelper
include ReportHelper
attr_reader :account, :params
DEFAULT_GROUP_BY = 'day'.freeze
def initialize(account, params)
@account = account
@params = params
timezone_offset = (params[:timezone_offset] || 0).to_f
@timezone = ActiveSupport::TimeZone[timezone_offset]&.name
end
def timeseries
@@ -13,8 +19,14 @@ class V2::ReportBuilder
# For backward compatible with old report
def build
timeseries.each_with_object([]) do |p, arr|
arr << { value: p[1], timestamp: p[0].to_time.to_i }
if %w[avg_first_response_time avg_resolution_time].include?(params[:metric])
timeseries.each_with_object([]) do |p, arr|
arr << { value: p[1], timestamp: p[0].in_time_zone(@timezone).to_i, count: @grouped_values.count[p[0]] }
end
else
timeseries.each_with_object([]) do |p, arr|
arr << { value: p[1], timestamp: p[0].in_time_zone(@timezone).to_i }
end
end
end
@@ -29,23 +41,16 @@ class V2::ReportBuilder
}
end
private
def scope
case params[:type]
when :account
account
when :inbox
inbox
when :agent
user
when :label
label
when :team
team
def conversation_metrics
if params[:type].equal?(:account)
conversations
else
agent_metrics
end
end
private
def inbox
@inbox ||= account.inboxes.find(params[:id])
end
@@ -62,56 +67,37 @@ class V2::ReportBuilder
@team ||= account.teams.find(params[:id])
end
def conversations_count
scope.conversations
.group_by_day(:created_at, range: range, default_value: 0)
.count
def get_grouped_values(object_scope)
@grouped_values = object_scope.group_by_period(
params[:group_by] || DEFAULT_GROUP_BY,
:created_at,
default_value: 0,
range: range,
permit: %w[day week month year],
time_zone: @timezone
)
end
def incoming_messages_count
scope.messages.incoming.unscope(:order)
.group_by_day(:created_at, range: range, default_value: 0)
.count
def agent_metrics
users = @account.users
users = users.where(id: params[:user_id]) if params[:user_id].present?
users.each_with_object([]) do |user, arr|
@user = user
arr << {
user: { id: user.id, name: user.name, thumbnail: user.avatar_url },
metric: conversations
}
end
end
def outgoing_messages_count
scope.messages.outgoing.unscope(:order)
.group_by_day(:created_at, range: range, default_value: 0)
.count
end
def resolutions_count
scope.conversations
.resolved
.group_by_day(:created_at, range: range, default_value: 0)
.count
end
def avg_first_response_time
scope.events
.where(name: 'first_response')
.group_by_day(:created_at, range: range, default_value: 0)
.average(:value)
end
def avg_resolution_time
scope.events.where(name: 'conversation_resolved')
.group_by_day(:created_at, range: range, default_value: 0)
.average(:value)
end
# Taking average of average is not too accurate
# https://en.wikipedia.org/wiki/Simpson's_paradox
# TODO: Will optimize this later
def avg_resolution_time_summary
return 0 if avg_resolution_time.values.empty?
(avg_resolution_time.values.sum / avg_resolution_time.values.length)
end
def avg_first_response_time_summary
return 0 if avg_first_response_time.values.empty?
(avg_first_response_time.values.sum / avg_first_response_time.values.length)
def conversations
@open_conversations = scope.conversations.open
first_response_count = scope.reporting_events.where(name: 'first_response', conversation_id: @open_conversations.pluck('id')).count
metric = {
open: @open_conversations.count,
unattended: @open_conversations.count - first_response_count
}
metric[:unassigned] = @open_conversations.unassigned.count if params[:type].equal?(:account)
metric
end
end
+8 -1
View File
@@ -1,5 +1,8 @@
class RoomChannel < ApplicationCable::Channel
def subscribed
# TODO: should we only do ensure stream if current account is present?
# for now going ahead with guard clauses in update_subscription and broadcast_presence
ensure_stream
current_user
current_account
@@ -15,6 +18,8 @@ class RoomChannel < ApplicationCable::Channel
private
def broadcast_presence
return if @current_account.blank?
data = { account_id: @current_account.id, users: ::OnlineStatusTracker.get_available_users(@current_account.id) }
data[:contacts] = ::OnlineStatusTracker.get_available_contacts(@current_account.id) if @current_user.is_a? User
ActionCable.server.broadcast(@pubsub_token, { event: 'presence.update', data: data })
@@ -26,12 +31,14 @@ class RoomChannel < ApplicationCable::Channel
end
def update_subscription
return if @current_account.blank?
::OnlineStatusTracker.update_presence(@current_account.id, @current_user.class.name, @current_user.id)
end
def current_user
@current_user ||= if params[:user_id].blank?
Contact.find_by!(pubsub_token: @pubsub_token)
ContactInbox.find_by!(pubsub_token: @pubsub_token).contact
else
User.find_by!(pubsub_token: @pubsub_token, id: params[:user_id])
end
@@ -18,7 +18,7 @@ class Api::V1::Accounts::AgentBotsController < Api::V1::Accounts::BaseController
end
def destroy
@agent_bot.destroy
@agent_bot.destroy!
head :ok
end
@@ -2,6 +2,7 @@ class Api::V1::Accounts::AgentsController < Api::V1::Accounts::BaseController
before_action :fetch_agent, except: [:create, :index]
before_action :check_authorization
before_action :find_user, only: [:create]
before_action :validate_limit, only: [:create]
before_action :create_user, only: [:create]
before_action :save_account_user, only: [:create]
@@ -17,7 +18,7 @@ class Api::V1::Accounts::AgentsController < Api::V1::Accounts::BaseController
end
def destroy
@agent.current_account_user.destroy
@agent.current_account_user.destroy!
head :ok
end
@@ -67,6 +68,10 @@ class Api::V1::Accounts::AgentsController < Api::V1::Accounts::BaseController
end
def agents
@agents ||= Current.account.users.order_by_full_name.includes({ avatar_attachment: [:blob] })
@agents ||= Current.account.users.order_by_full_name.includes(:account_users, { avatar_attachment: [:blob] })
end
def validate_limit
render_payment_required('Account limit exceeded. Upgrade to a higher plan') if agents.count >= Current.account.usage_limits[:agents]
end
end
@@ -0,0 +1,68 @@
class Api::V1::Accounts::AutomationRulesController < Api::V1::Accounts::BaseController
before_action :check_authorization
before_action :fetch_automation_rule, only: [:show, :update, :destroy, :clone]
def index
@automation_rules = Current.account.automation_rules
end
def create
@automation_rule = Current.account.automation_rules.new(automation_rules_permit)
@automation_rule.actions = params[:actions]
render json: { error: @automation_rule.errors.messages }, status: :unprocessable_entity and return unless @automation_rule.valid?
@automation_rule.save!
process_attachments
@automation_rule
end
def show; end
def update
ActiveRecord::Base.transaction do
@automation_rule.update!(automation_rules_permit)
@automation_rule.actions = params[:actions] if params[:actions]
@automation_rule.save!
process_attachments
rescue StandardError => e
Rails.logger.error e
render json: { error: @automation_rule.errors.messages }.to_json, status: :unprocessable_entity
end
end
def destroy
@automation_rule.destroy!
head :ok
end
def clone
automation_rule = Current.account.automation_rules.find_by(id: params[:automation_rule_id])
new_rule = automation_rule.dup
new_rule.save
@automation_rule = new_rule
end
private
def process_attachments
return if params[:attachments].blank?
params[:attachments].each do |uploaded_attachment|
@automation_rule.files.attach(uploaded_attachment)
end
@automation_rule
end
def automation_rules_permit
params.permit(
:name, :description, :event_name, :account_id, :active,
conditions: [:attribute_key, :filter_operator, :query_operator, { values: [] }],
actions: [:action_name, { action_params: [] }]
)
end
def fetch_automation_rule
@automation_rule = Current.account.automation_rules.find_by(id: params[:id])
end
end
@@ -1,32 +1,6 @@
class Api::V1::Accounts::BaseController < Api::BaseController
include SwitchLocale
include EnsureCurrentAccountHelper
before_action :current_account
around_action :switch_locale_using_account_locale
private
def current_account
@current_account ||= ensure_current_account
Current.account = @current_account
end
def ensure_current_account
account = Account.find(params[:account_id])
if current_user
account_accessible_for_user?(account)
elsif @resource.is_a?(AgentBot)
account_accessible_for_bot?(account)
end
account
end
def account_accessible_for_user?(account)
@current_account_user = account.account_users.find_by(user_id: current_user.id)
Current.account_user = @current_account_user
render_unauthorized('You are not authorized to access this account') unless @current_account_user
end
def account_accessible_for_bot?(account)
render_unauthorized('You are not authorized to access this account') unless @resource.agent_bot_inboxes.find_by(account_id: account.id)
end
end
@@ -0,0 +1,26 @@
class Api::V1::Accounts::BulkActionsController < Api::V1::Accounts::BaseController
before_action :type_matches?
def create
if type_matches?
::BulkActionsJob.perform_later(
account: @current_account,
user: current_user,
params: permitted_params
)
head :ok
else
render json: { success: false }, status: :unprocessable_entity
end
end
private
def type_matches?
['Conversation'].include?(params[:type])
end
def permitted_params
params.permit(:type, ids: [], fields: [:status, :assignee_id, :team_id], labels: [add: [], remove: []])
end
end
@@ -74,10 +74,10 @@ class Api::V1::Accounts::CallbacksController < Api::V1::Accounts::BaseController
end
def long_lived_token(omniauth_token)
koala = Koala::Facebook::OAuth.new(ENV['FB_APP_ID'], ENV['FB_APP_SECRET'])
koala = Koala::Facebook::OAuth.new(GlobalConfigService.load('FB_APP_ID', ''), GlobalConfigService.load('FB_APP_SECRET', ''))
koala.exchange_access_token_info(omniauth_token)['access_token']
rescue StandardError => e
Rails.logger.info e
Rails.logger.error e
end
def mark_already_existing_facebook_pages(data)
@@ -11,14 +11,14 @@ class Api::V1::Accounts::CampaignsController < Api::V1::Accounts::BaseController
end
def destroy
@campaign.destroy
@campaign.destroy!
head :ok
end
def show; end
def update
@campaign.update(campaign_params)
@campaign.update!(campaign_params)
end
private
@@ -17,7 +17,7 @@ class Api::V1::Accounts::CannedResponsesController < Api::V1::Accounts::BaseCont
end
def destroy
@canned_response.destroy
@canned_response.destroy!
head :ok
end
@@ -33,7 +33,7 @@ class Api::V1::Accounts::CannedResponsesController < Api::V1::Accounts::BaseCont
def canned_responses
if params[:search]
Current.account.canned_responses.where('short_code ILIKE ?', "#{params[:search]}%")
Current.account.canned_responses.where('short_code ILIKE :search OR content ILIKE :search', search: "%#{params[:search]}%")
else
Current.account.canned_responses
end
@@ -10,7 +10,7 @@ class Api::V1::Accounts::Contacts::NotesController < Api::V1::Accounts::Contacts
end
def destroy
@note.destroy
@note.destroy!
head :ok
end
@@ -11,9 +11,9 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
RESULTS_PER_PAGE = 15
before_action :check_authorization
before_action :set_current_page, only: [:index, :active, :search]
before_action :set_current_page, only: [:index, :active, :search, :filter]
before_action :fetch_contact, only: [:show, :update, :destroy, :contactable_inboxes, :destroy_custom_attributes]
before_action :set_include_contact_inboxes, only: [:index, :search]
before_action :set_include_contact_inboxes, only: [:index, :search, :filter]
def index
@contacts_count = resolved_contacts.count
@@ -81,11 +81,6 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
def update
@contact.assign_attributes(contact_update_params)
@contact.save!
rescue ActiveRecord::RecordInvalid => e
render json: {
message: e.record.errors.full_messages.join(', '),
contact: Current.account.contacts.find_by(email: contact_params[:email])
}, status: :unprocessable_entity
end
def destroy
@@ -1,4 +1,5 @@
class Api::V1::Accounts::Conversations::BaseController < Api::V1::Accounts::BaseController
include EnsureCurrentAccountHelper
before_action :conversation
private
@@ -0,0 +1,17 @@
class Api::V1::Accounts::Conversations::DirectUploadsController < ActiveStorage::DirectUploadsController
include EnsureCurrentAccountHelper
before_action :current_account
before_action :conversation
def create
return if @conversation.nil? || @current_account.nil?
super
end
private
def conversation
@conversation ||= Current.account.conversations.find_by(display_id: params[:conversation_id])
end
end
@@ -13,7 +13,7 @@ class Api::V1::Accounts::Conversations::MessagesController < Api::V1::Accounts::
def destroy
ActiveRecord::Base.transaction do
message.update!(content: I18n.t('conversations.messages.deleted'), deleted: true)
message.update!(content: I18n.t('conversations.messages.deleted'), content_attributes: { deleted: true })
message.attachments.destroy_all
end
end
@@ -61,6 +61,7 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
else
@status = @conversation.toggle_status
end
assign_conversation if @conversation.status == 'open' && Current.user.is_a?(User) && Current.user&.agent?
end
def toggle_typing_status
@@ -74,9 +75,10 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
end
def update_last_seen
@conversation.agent_last_seen_at = DateTime.now.utc
@conversation.assignee_last_seen_at = DateTime.now.utc if assignee?
@conversation.save!
# rubocop:disable Rails/SkipsModelValidations
@conversation.update_column(:agent_last_seen_at, DateTime.now.utc)
@conversation.update_column(:assignee_last_seen_at, DateTime.now.utc) if assignee?
# rubocop:enable Rails/SkipsModelValidations
end
def custom_attributes
@@ -92,6 +94,11 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
@conversation.snoozed_until = parse_date_time(params[:snoozed_until].to_s) if params[:snoozed_until]
end
def assign_conversation
@agent = Current.account.users.find(current_user.id)
@conversation.update_assignee(@agent)
end
def trigger_typing_event(event, is_private)
user = current_user.presence || @resource
Rails.configuration.dispatcher.dispatch(event, Time.zone.now, conversation: @conversation, user: user, is_private: is_private)
@@ -30,8 +30,7 @@ class Api::V1::Accounts::CsatSurveyResponsesController < Api::V1::Accounts::Base
def set_csat_survey_responses
@csat_survey_responses = filtrate(
Current.account.csat_survey_responses.includes([:conversation, :assigned_agent, :contact])
)
@csat_survey_responses = @csat_survey_responses.where(created_at: range) if range.present?
).filter_by_created_at(range).filter_by_assigned_agent_id(params[:user_ids])
end
def set_current_page_surveys
@@ -18,7 +18,7 @@ class Api::V1::Accounts::CustomAttributeDefinitionsController < Api::V1::Account
end
def destroy
@custom_attribute_definition.destroy
@custom_attribute_definition.destroy!
head :no_content
end
@@ -39,7 +39,7 @@ class Api::V1::Accounts::CustomAttributeDefinitionsController < Api::V1::Account
:attribute_display_type,
:attribute_key,
:attribute_model,
:default_value
attribute_values: []
)
end
@@ -18,7 +18,7 @@ class Api::V1::Accounts::CustomFiltersController < Api::V1::Accounts::BaseContro
end
def destroy
@custom_filter.destroy
@custom_filter.destroy!
head :no_content
end
@@ -1,11 +1,11 @@
class Api::V1::Accounts::InboxMembersController < Api::V1::Accounts::BaseController
before_action :fetch_inbox
before_action :current_agents_ids, only: [:update]
before_action :current_agents_ids, only: [:create, :update]
def create
authorize @inbox, :create?
ActiveRecord::Base.transaction do
params[:user_ids].map { |user_id| @inbox.add_member(user_id) }
agents_to_be_added_ids.map { |user_id| @inbox.add_member(user_id) }
end
fetch_updated_agents
end
@@ -1,6 +1,8 @@
class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
include Api::V1::InboxesHelper
before_action :fetch_inbox, except: [:index, :create]
before_action :fetch_agent_bot, only: [:set_agent_bot]
before_action :validate_limit, only: [:create]
# we are already handling the authorization in fetch inbox
before_action :check_authorization, except: [:show]
@@ -41,12 +43,16 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
def update
@inbox.update(permitted_params.except(:channel))
@inbox.update_working_hours(params.permit(working_hours: Inbox::OFFISABLE_ATTRS)[:working_hours]) if params[:working_hours]
channel_attributes = get_channel_attributes(@inbox.channel_type)
# Inbox update doesn't necessarily need channel attributes
return if permitted_params(channel_attributes)[:channel].blank?
if @inbox.inbox_type == 'Email'
validate_email_channel(channel_attributes)
@inbox.channel.reauthorized!
end
@inbox.channel.update!(permitted_params(channel_attributes)[:channel])
update_channel_feature_flags
end
@@ -67,7 +73,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
end
def destroy
@inbox.destroy
@inbox.destroy!
head :ok
end
@@ -89,20 +95,9 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
end
def create_channel
case permitted_params[:channel][:type]
when 'web_widget'
Current.account.web_widgets.create!(permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel].except(:type))
when 'api'
Current.account.api_channels.create!(permitted_params(Channel::Api::EDITABLE_ATTRS)[:channel].except(:type))
when 'email'
Current.account.email_channels.create!(permitted_params(Channel::Email::EDITABLE_ATTRS)[:channel].except(:type))
when 'line'
Current.account.line_channels.create!(permitted_params(Channel::Line::EDITABLE_ATTRS)[:channel].except(:type))
when 'telegram'
Current.account.telegram_channels.create!(permitted_params(Channel::Telegram::EDITABLE_ATTRS)[:channel].except(:type))
when 'whatsapp'
Current.account.whatsapp_channels.create!(permitted_params(Channel::Whatsapp::EDITABLE_ATTRS)[:channel].except(:type))
end
return unless %w[web_widget api email line telegram whatsapp sms].include?(permitted_params[:channel][:type])
account_channels_method.create!(permitted_params(channel_type_from_params::EDITABLE_ATTRS)[:channel].except(:type))
end
def update_channel_feature_flags
@@ -116,25 +111,46 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
def permitted_params(channel_attributes = [])
params.permit(
:name, :avatar, :greeting_enabled, :greeting_message, :enable_email_collect, :csat_survey_enabled,
:enable_auto_assignment, :working_hours_enabled, :out_of_office_message, :timezone,
:enable_auto_assignment, :working_hours_enabled, :out_of_office_message, :timezone, :allow_messages_after_resolved,
channel: [:type, *channel_attributes]
)
end
def channel_type_from_params
{
'web_widget' => Channel::WebWidget,
'api' => Channel::Api,
'email' => Channel::Email,
'line' => Channel::Line,
'telegram' => Channel::Telegram,
'whatsapp' => Channel::Whatsapp,
'sms' => Channel::Sms
}[permitted_params[:channel][:type]]
end
def account_channels_method
{
'web_widget' => Current.account.web_widgets,
'api' => Current.account.api_channels,
'email' => Current.account.email_channels,
'line' => Current.account.line_channels,
'telegram' => Current.account.telegram_channels,
'whatsapp' => Current.account.whatsapp_channels,
'sms' => Current.account.sms_channels
}[permitted_params[:channel][:type]]
end
def get_channel_attributes(channel_type)
case channel_type
when 'Channel::WebWidget'
Channel::WebWidget::EDITABLE_ATTRS
when 'Channel::Api'
Channel::Api::EDITABLE_ATTRS
when 'Channel::Email'
Channel::Email::EDITABLE_ATTRS
when 'Channel::Telegram'
Channel::Telegram::EDITABLE_ATTRS
when 'Channel::Line'
Channel::Line::EDITABLE_ATTRS
if channel_type.constantize.const_defined?(:EDITABLE_ATTRS)
channel_type.constantize::EDITABLE_ATTRS.presence
else
[]
end
end
def validate_limit
return unless Current.account.inboxes.count >= Current.account.usage_limits[:inboxes]
render_payment_required('Account limit exceeded. Upgrade to a higher plan')
end
end
@@ -11,7 +11,7 @@ class Api::V1::Accounts::Integrations::HooksController < Api::V1::Accounts::Base
end
def destroy
@hook.destroy
@hook.destroy!
head :ok
end
@@ -20,7 +20,7 @@ class Api::V1::Accounts::Integrations::SlackController < Api::V1::Accounts::Base
end
def destroy
@hook.destroy
@hook.destroy!
head :ok
end
@@ -14,7 +14,7 @@ class Api::V1::Accounts::Kbase::CategoriesController < Api::V1::Accounts::Kbase:
end
def destroy
@category.destroy
@category.destroy!
head :ok
end
@@ -14,7 +14,7 @@ class Api::V1::Accounts::Kbase::PortalsController < Api::V1::Accounts::Kbase::Ba
end
def destroy
@portal.destroy
@portal.destroy!
head :ok
end
@@ -18,7 +18,7 @@ class Api::V1::Accounts::LabelsController < Api::V1::Accounts::BaseController
end
def destroy
@label.destroy
@label.destroy!
head :ok
end
@@ -8,7 +8,7 @@ class Api::V1::Accounts::TeamMembersController < Api::V1::Accounts::BaseControll
def create
ActiveRecord::Base.transaction do
@team_members = params[:user_ids].map { |user_id| @team.add_member(user_id) }
@team_members = members_to_be_added_ids.map { |user_id| @team.add_member(user_id) }
end
end
@@ -18,7 +18,7 @@ class Api::V1::Accounts::TeamsController < Api::V1::Accounts::BaseController
end
def destroy
@team.destroy
@team.destroy!
head :ok
end
@@ -16,7 +16,7 @@ class Api::V1::Accounts::WebhooksController < Api::V1::Accounts::BaseController
end
def destroy
@webhook.destroy
@webhook.destroy!
head :ok
end
@@ -4,6 +4,7 @@ class Api::V1::AccountsController < Api::BaseController
skip_before_action :authenticate_user!, :set_current_user, :handle_with_exception,
only: [:create], raise: false
before_action :check_signup_enabled, only: [:create]
before_action :validate_captcha, only: [:create]
before_action :fetch_account, except: [:create]
before_action :check_authorization, except: [:create]
@@ -55,7 +56,11 @@ class Api::V1::AccountsController < Api::BaseController
end
def check_signup_enabled
raise ActionController::RoutingError, 'Not Found' if GlobalConfig.get_value('ENABLE_ACCOUNT_SIGNUP') == 'false'
raise ActionController::RoutingError, 'Not Found' if GlobalConfigService.load('ENABLE_ACCOUNT_SIGNUP', 'false') == 'false'
end
def validate_captcha
raise ActionController::InvalidAuthenticityToken, 'Invalid Captcha' unless ChatwootCaptcha.new(params[:h_captcha_client_response]).valid?
end
def pundit_user
@@ -7,6 +7,12 @@ class Api::V1::NotificationSubscriptionsController < Api::BaseController
render json: notification_subscription
end
def destroy
notification_subscription = NotificationSubscription.where(["subscription_attributes->>'push_token' = ?", params[:push_token]]).first
notification_subscription.destroy!
head :ok
end
private
def set_user
@@ -13,6 +13,11 @@ class Api::V1::ProfilesController < Api::BaseController
@user.update!(profile_params)
end
def avatar
@user.avatar.attachment.destroy! if @user.avatar.attached?
head :ok
end
def availability
@user.account_users.find_by!(account_id: availability_params[:account_id]).update!(availability: availability_params[:availability])
end
@@ -33,6 +38,7 @@ class Api::V1::ProfilesController < Api::BaseController
:name,
:display_name,
:avatar,
:message_signature,
ui_settings: {}
)
end
@@ -1,5 +1,6 @@
class Api::V1::Widget::BaseController < ApplicationController
include SwitchLocale
include WebsiteTokenHelper
before_action :set_web_widget
before_action :set_contact
@@ -19,23 +20,6 @@ class Api::V1::Widget::BaseController < ApplicationController
@conversation ||= conversations.last
end
def auth_token_params
@auth_token_params ||= ::Widget::TokenService.new(token: request.headers['X-Auth-Token']).decode_token
end
def set_web_widget
@web_widget = ::Channel::WebWidget.find_by!(website_token: permitted_params[:website_token])
@current_account = @web_widget.account
end
def set_contact
@contact_inbox = @web_widget.inbox.contact_inboxes.find_by(
source_id: auth_token_params[:source_id]
)
@contact = @contact_inbox&.contact
raise ActiveRecord::RecordNotFound unless @contact
end
def create_conversation
::Conversation.create!(conversation_params)
end
@@ -55,7 +39,8 @@ class Api::V1::Widget::BaseController < ApplicationController
browser: browser_params,
referer: permitted_params[:message][:referer_url],
initiated_at: timestamp_params
}
},
custom_attributes: permitted_params[:custom_attributes].presence || {}
}
end
@@ -68,16 +53,33 @@ class Api::V1::Widget::BaseController < ApplicationController
mergee_contact: @contact
).perform
else
@contact.update!(email: email, name: contact_name)
@contact.update!(email: email)
end
end
def update_contact_phone_number(phone_number)
contact_with_phone_number = @current_account.contacts.find_by(phone_number: phone_number)
if contact_with_phone_number
@contact = ::ContactMergeAction.new(
account: @current_account,
base_contact: contact_with_phone_number,
mergee_contact: @contact
).perform
else
@contact.update!(phone_number: phone_number)
end
end
def contact_email
permitted_params[:contact][:email].downcase
permitted_params[:contact][:email].downcase if permitted_params[:contact].present?
end
def contact_name
params[:contact][:name] || contact_email.split('@')[0]
params[:contact][:name] || contact_email.split('@')[0] if contact_email.present?
end
def contact_phone_number
params[:contact][:phone_number]
end
def browser_params
@@ -94,10 +96,6 @@ class Api::V1::Widget::BaseController < ApplicationController
{ timestamp: permitted_params[:message][:timestamp] }
end
def permitted_params
params.permit(:website_token)
end
def message_params
{
account_id: conversation.account_id,
@@ -1,5 +1,5 @@
class Api::V1::Widget::ContactsController < Api::V1::Widget::BaseController
before_action :process_hmac
before_action :process_hmac, only: [:update]
def show; end
@@ -8,7 +8,7 @@ class Api::V1::Widget::ContactsController < Api::V1::Widget::BaseController
contact: @contact,
params: permitted_params.to_h.deep_symbolize_keys
)
render json: contact_identify_action.perform
@contact = contact_identify_action.perform
end
# TODO : clean up this with proper routes delete contacts/custom_attributes
@@ -21,13 +21,22 @@ class Api::V1::Widget::ContactsController < Api::V1::Widget::BaseController
private
def process_hmac
return if params[:identifier_hash].blank? && !@web_widget.hmac_mandatory
return unless should_verify_hmac?
render json: { error: 'HMAC failed: Invalid Identifier Hash Provided' }, status: :unauthorized unless valid_hmac?
@contact_inbox.update(hmac_verified: true)
end
def should_verify_hmac?
return false if params[:identifier_hash].blank? && !@web_widget.hmac_mandatory
# Taking an extra caution that the hmac is triggered whenever identifier is present
return false if params[:custom_attributes].present? && params[:identifier].blank?
true
end
def valid_hmac?
params[:identifier_hash] == OpenSSL::HMAC.hexdigest(
'sha256',
@@ -37,6 +46,7 @@ class Api::V1::Widget::ContactsController < Api::V1::Widget::BaseController
end
def permitted_params
params.permit(:website_token, :identifier, :identifier_hash, :email, :name, :avatar_url, :phone_number, custom_attributes: {})
params.permit(:website_token, :identifier, :identifier_hash, :email, :name, :avatar_url, :phone_number, custom_attributes: {},
additional_attributes: {})
end
end
@@ -7,12 +7,18 @@ class Api::V1::Widget::ConversationsController < Api::V1::Widget::BaseController
def create
ActiveRecord::Base.transaction do
update_contact(contact_email) if @contact.email.blank? && contact_email.present?
process_update_contact
@conversation = create_conversation
conversation.messages.create(message_params)
end
end
def process_update_contact
update_contact(contact_email) if @contact.email.blank? && contact_email.present?
update_contact_phone_number(contact_phone_number) if @contact.phone_number.blank? && contact_phone_number.present?
@contact.update!(name: contact_name) if contact_name.present?
end
def update_last_seen
head :ok && return if conversation.nil?
@@ -44,6 +50,18 @@ class Api::V1::Widget::ConversationsController < Api::V1::Widget::BaseController
head :ok
end
def toggle_status
return head :not_found if conversation.nil?
return head :forbidden unless @web_widget.end_conversation?
unless conversation.resolved?
conversation.status = :resolved
conversation.save
end
head :ok
end
private
def trigger_typing_event(event)
@@ -51,6 +69,7 @@ class Api::V1::Widget::ConversationsController < Api::V1::Widget::BaseController
end
def permitted_params
params.permit(:id, :typing_status, :website_token, :email, contact: [:name, :email], message: [:content, :referer_url, :timestamp, :echo_id])
params.permit(:id, :typing_status, :website_token, :email, contact: [:name, :email], message: [:content, :referer_url, :timestamp, :echo_id],
custom_attributes: {})
end
end
@@ -0,0 +1,11 @@
class Api::V1::Widget::DirectUploadsController < ActiveStorage::DirectUploadsController
include WebsiteTokenHelper
before_action :set_web_widget
before_action :set_contact
def create
return if @contact.nil? || @current_account.nil?
super
end
end
@@ -29,11 +29,12 @@ class Api::V1::Widget::MessagesController < Api::V1::Widget::BaseController
return if params[:message][:attachments].blank?
params[:message][:attachments].each do |uploaded_attachment|
@message.attachments.new(
attachment = @message.attachments.new(
account_id: @message.account_id,
file_type: helpers.file_type(uploaded_attachment&.content_type),
file: uploaded_attachment
)
attachment.file_type = helpers.file_type(uploaded_attachment&.content_type) if uploaded_attachment.is_a?(ActionDispatch::Http::UploadedFile)
end
end
@@ -35,33 +35,77 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
render layout: false, template: 'api/v2/accounts/reports/teams.csv.erb', format: 'csv'
end
def conversations
return head :unprocessable_entity if params[:type].blank?
render json: conversation_metrics
end
private
def check_authorization
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
end
def summary_params
def common_params
{
type: params[:type].to_sym,
since: params[:since],
until: params[:until],
id: params[:id]
id: params[:id],
group_by: params[:group_by],
business_hours: ActiveModel::Type::Boolean.new.cast(params[:business_hours])
}
end
def current_summary_params
common_params.merge({
since: range[:current][:since],
until: range[:current][:until]
})
end
def previous_summary_params
common_params.merge({
since: range[:previous][:since],
until: range[:previous][:until]
})
end
def report_params
common_params.merge({
metric: params[:metric],
since: params[:since],
until: params[:until],
timezone_offset: params[:timezone_offset]
})
end
def conversation_params
{
metric: params[:metric],
type: params[:type].to_sym,
since: params[:since],
until: params[:until],
id: params[:id]
user_id: params[:user_id]
}
end
def range
{
current: {
since: params[:since],
until: params[:until]
},
previous: {
since: (params[:since].to_i - (params[:until].to_i - params[:since].to_i)).to_s,
until: params[:since]
}
}
end
def summary_metrics
builder = V2::ReportBuilder.new(Current.account, summary_params)
builder.summary
summary = V2::ReportBuilder.new(Current.account, current_summary_params).summary
summary[:previous] = V2::ReportBuilder.new(Current.account, previous_summary_params).summary
summary
end
def conversation_metrics
V2::ReportBuilder.new(Current.account, conversation_params).conversation_metrics
end
end
@@ -0,0 +1,28 @@
module EnsureCurrentAccountHelper
private
def current_account
@current_account ||= ensure_current_account
Current.account = @current_account
end
def ensure_current_account
account = Account.find(params[:account_id])
if current_user
account_accessible_for_user?(account)
elsif @resource.is_a?(AgentBot)
account_accessible_for_bot?(account)
end
account
end
def account_accessible_for_user?(account)
@current_account_user = account.account_users.find_by(user_id: current_user.id)
Current.account_user = @current_account_user
render_unauthorized('You are not authorized to access this account') unless @current_account_user
end
def account_accessible_for_bot?(account)
render_unauthorized('You are not authorized to access this account') unless @resource.agent_bot_inboxes.find_by(account_id: account.id)
end
end
@@ -31,13 +31,18 @@ module RequestExceptionHandler
render json: { error: message }, status: :unprocessable_entity
end
def render_payment_required(message)
render json: { error: message }, status: :payment_required
end
def render_internal_server_error(message)
render json: { error: message }, status: :internal_server_error
end
def render_record_invalid(exception)
render json: {
message: exception.record.errors.full_messages.join(', ')
message: exception.record.errors.full_messages.join(', '),
attributes: exception.record.errors.attribute_names
}, status: :unprocessable_entity
end
@@ -0,0 +1,24 @@
module WebsiteTokenHelper
def auth_token_params
@auth_token_params ||= ::Widget::TokenService.new(token: request.headers['X-Auth-Token']).decode_token
end
def set_web_widget
@web_widget = ::Channel::WebWidget.find_by!(website_token: permitted_params[:website_token])
@current_account = @web_widget.account
end
def set_contact
@contact_inbox = @web_widget.inbox.contact_inboxes.find_by(
source_id: auth_token_params[:source_id]
)
@contact = @contact_inbox&.contact
raise ActiveRecord::RecordNotFound unless @contact
Current.contact = @contact
end
def permitted_params
params.permit(:website_token)
end
end
+13 -6
View File
@@ -25,15 +25,22 @@ class DashboardController < ActionController::Base
'API_CHANNEL_NAME',
'API_CHANNEL_THUMBNAIL',
'ANALYTICS_TOKEN',
'ANALYTICS_HOST'
).merge(
APP_VERSION: Chatwoot.config[:version],
VAPID_PUBLIC_KEY: VapidService.public_key,
ENABLE_ACCOUNT_SIGNUP: GlobalConfigService.load('ENABLE_ACCOUNT_SIGNUP', 'false')
)
'ANALYTICS_HOST',
'DIRECT_UPLOADS_ENABLED',
'HCAPTCHA_SITE_KEY',
'LOGOUT_REDIRECT_LINK',
'DISABLE_USER_PROFILE_UPDATE'
).merge(app_config)
end
def ensure_installation_onboarding
redirect_to '/installation/onboarding' if ::Redis::Alfred.get(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING)
end
def app_config
{ APP_VERSION: Chatwoot.config[:version],
VAPID_PUBLIC_KEY: VapidService.public_key,
ENABLE_ACCOUNT_SIGNUP: GlobalConfigService.load('ENABLE_ACCOUNT_SIGNUP', 'false'),
FB_APP_ID: GlobalConfigService.load('FB_APP_ID', '') }
end
end
@@ -28,10 +28,7 @@ class DeviseOverrides::ConfirmationsController < Devise::ConfirmationsController
end
def create_reset_token_link(user)
raw, enc = Devise.token_generator.generate(user.class, :reset_password_token)
user.reset_password_token = enc
user.reset_password_sent_at = Time.now.utc
user.save(validate: false)
"/app/auth/password/edit?config=default&redirect_url=&reset_password_token=#{raw}"
token = user.send(:set_reset_password_token)
"/app/auth/password/edit?config=default&redirect_url=&reset_password_token=#{token}"
end
end
@@ -10,6 +10,7 @@ class Installation::OnboardingController < ApplicationController
user_full_name: onboarding_params.dig(:user, :name),
email: onboarding_params.dig(:user, :email),
user_password: params.dig(:user, :password),
super_admin: true,
confirmed: true
).perform
rescue StandardError => e
@@ -13,7 +13,7 @@ class Platform::Api::V1::AccountUsersController < PlatformController
end
def destroy
@resource.account_users.find_by(user_id: account_user_params[:user_id])&.destroy
@resource.account_users.find_by(user_id: account_user_params[:user_id])&.destroy!
head :ok
end
@@ -7,13 +7,14 @@ class Platform::Api::V1::UsersController < PlatformController
def create
@resource = (User.find_by(email: user_params[:email]) || User.new(user_params))
@resource.skip_confirmation!
@resource.save!
@resource.confirm
@platform_app.platform_app_permissibles.find_or_create_by(permissible: @resource)
@platform_app.platform_app_permissibles.find_or_create_by!(permissible: @resource)
end
def login
render json: { url: "#{ENV['FRONTEND_URL']}/app/login?email=#{@resource.email}&sso_auth_token=#{@resource.generate_sso_auth_token}" }
encoded_email = ERB::Util.url_encode(@resource.email)
render json: { url: "#{ENV['FRONTEND_URL']}/app/login?email=#{encoded_email}&sso_auth_token=#{@resource.generate_sso_auth_token}" }
end
def show; end
@@ -33,11 +33,11 @@ class SuperAdmin::AccountsController < SuperAdmin::ApplicationController
# empty values into nil values. It uses other APIs such as `resource_class`
# and `dashboard`:
#
# def resource_params
# params.require(resource_class.model_name.param_key).
# permit(dashboard.permitted_attributes).
# transform_values { |value| value == "" ? nil : value }
# end
def resource_params
permitted_params = super
permitted_params[:limits] = permitted_params[:limits].to_h.compact
permitted_params
end
# See https://administrate-prototype.herokuapp.com/customizing_controller_actions
# for more information
@@ -0,0 +1,21 @@
class SuperAdmin::AppConfigsController < SuperAdmin::ApplicationController
def show
@allowed_configs = %w[FB_APP_ID FB_VERIFY_TOKEN FB_APP_SECRET]
# ref: https://github.com/rubocop/rubocop/issues/7767
# rubocop:disable Style/HashTransformValues
@fb_config = InstallationConfig.where(name: @allowed_configs)
.pluck(:name, :serialized_value)
.map { |name, serialized_value| [name, serialized_value['value']] }
.to_h
# rubocop:enable Style/HashTransformValues
end
def create
params['app_config'].each do |key, value|
i = InstallationConfig.where(name: key).first_or_create(value: value, locked: false)
i.value = value
i.save!
end
redirect_to super_admin_app_config_url
end
end
@@ -8,7 +8,7 @@ class SuperAdmin::Devise::SessionsController < Devise::SessionsController
def create
redirect_to(super_admin_session_path, flash: { error: @error_message }) && return unless valid_credentials?
sign_in(@super_admin, scope: :super_admin)
sign_in(:super_admin, @super_admin)
flash.discard
redirect_to super_admin_users_path
end
@@ -1,44 +0,0 @@
class SuperAdmin::SuperAdminsController < SuperAdmin::ApplicationController
# Overwrite any of the RESTful controller actions to implement custom behavior
# For example, you may want to send an email after a foo is updated.
#
# def update
# super
# send_foo_updated_email(requested_resource)
# end
# Override this method to specify custom lookup behavior.
# This will be used to set the resource for the `show`, `edit`, and `update`
# actions.
#
# def find_resource(param)
# Foo.find_by!(slug: param)
# end
# The result of this lookup will be available as `requested_resource`
# Override this if you have certain roles that require a subset
# this will be used to set the records shown on the `index` action.
#
# def scoped_resource
# if current_user.super_admin?
# resource_class
# else
# resource_class.with_less_stuff
# end
# end
# Override `resource_params` if you want to transform the submitted
# data before it's persisted. For example, the following would turn all
# empty values into nil values. It uses other APIs such as `resource_class`
# and `dashboard`:
#
# def resource_params
# params.require(resource_class.model_name.param_key).
# permit(dashboard.permitted_attributes).
# transform_values { |value| value == "" ? nil : value }
# end
# See https://administrate-prototype.herokuapp.com/customizing_controller_actions
# for more information
end
@@ -33,12 +33,15 @@ class SuperAdmin::UsersController < SuperAdmin::ApplicationController
# empty values into nil values. It uses other APIs such as `resource_class`
# and `dashboard`:
#
# def resource_params
# params.require(resource_class.model_name.param_key).
# permit(dashboard.permitted_attributes).
# transform_values { |value| value == "" ? nil : value }
# end
def resource_params
permitted_params = super
permitted_params.delete(:password) if permitted_params[:password].blank?
permitted_params
end
# See https://administrate-prototype.herokuapp.com/customizing_controller_actions
# for more information
def find_resource(param)
super.becomes(User)
end
end
@@ -14,7 +14,7 @@ class Twitter::CallbacksController < Twitter::BaseController
redirect_to app_twitter_inbox_agents_url(account_id: account.id, inbox_id: inbox.id)
end
rescue StandardError => e
Rails.logger.info e
Rails.logger.error e
redirect_to twitter_app_redirect_url
end
@@ -17,7 +17,7 @@ class Webhooks::InstagramController < ApplicationController
::Webhooks::InstagramEventsJob.perform_later(params.to_unsafe_hash[:entry])
render json: :ok
else
Rails.logger.info("Message is not received from the instagram webhook event: #{params['object']}")
Rails.logger.warn("Message is not received from the instagram webhook event: #{params['object']}")
head :unprocessable_entity
end
end
@@ -25,6 +25,6 @@ class Webhooks::InstagramController < ApplicationController
private
def valid_instagram_token?(token)
token == ENV['IG_VERIFY_TOKEN']
token == GlobalConfigService.load('IG_VERIFY_TOKEN', '')
end
end
@@ -0,0 +1,6 @@
class Webhooks::SmsController < ActionController::API
def process_payload
Webhooks::SmsEventsJob.perform_later(params['_json']&.first&.to_unsafe_hash)
head :ok
end
end
+28 -3
View File
@@ -1,5 +1,9 @@
class WidgetTestsController < ActionController::Base
before_action :set_web_widget
before_action :ensure_web_widget
before_action :ensure_widget_position
before_action :ensure_widget_type
before_action :ensure_widget_style
before_action :ensure_dark_mode
def index
render
@@ -7,7 +11,28 @@ class WidgetTestsController < ActionController::Base
private
def set_web_widget
@web_widget = Channel::WebWidget.first
def ensure_widget_style
@widget_style = params[:widget_style] || 'standard'
end
def ensure_dark_mode
@dark_mode = params[:dark_mode] || 'light'
end
def ensure_widget_position
@widget_position = params[:position] || 'left'
end
def ensure_widget_type
@widget_type = params[:type] || 'expanded_bubble'
end
def inbox_id
@inbox_id ||= params[:inbox_id] || Channel::WebWidget.first.inbox.id
end
def ensure_web_widget
@inbox = Inbox.find(inbox_id)
@web_widget = @inbox.channel
end
end
+6 -6
View File
@@ -10,7 +10,7 @@ class WidgetsController < ActionController::Base
private
def set_global_config
@global_config = GlobalConfig.get('LOGO_THUMBNAIL', 'BRAND_NAME', 'WIDGET_BRAND_URL')
@global_config = GlobalConfig.get('LOGO_THUMBNAIL', 'BRAND_NAME', 'WIDGET_BRAND_URL', 'DIRECT_UPLOADS_ENABLED')
end
def set_web_widget
@@ -29,21 +29,21 @@ class WidgetsController < ActionController::Base
def set_contact
return if @auth_token_params[:source_id].nil?
contact_inbox = ::ContactInbox.find_by(
@contact_inbox = ::ContactInbox.find_by(
inbox_id: @web_widget.inbox.id,
source_id: @auth_token_params[:source_id]
)
@contact = contact_inbox ? contact_inbox.contact : nil
@contact = @contact_inbox ? @contact_inbox.contact : nil
end
def build_contact
return if @contact.present?
contact_inbox = @web_widget.create_contact_inbox(additional_attributes)
@contact = contact_inbox.contact
@contact_inbox = @web_widget.create_contact_inbox(additional_attributes)
@contact = @contact_inbox.contact
payload = { source_id: contact_inbox.source_id, inbox_id: @web_widget.inbox.id }
payload = { source_id: @contact_inbox.source_id, inbox_id: @web_widget.inbox.id }
@token = ::Widget::TokenService.new(payload: payload).generate_token
end
+13 -5
View File
@@ -7,6 +7,8 @@ class AccountDashboard < Administrate::BaseDashboard
# Each different type represents an Administrate::Field object,
# which determines how the attribute is displayed
# on pages throughout the dashboard.
enterprise_attribute_types = ChatwootApp.enterprise? ? { limits: Enterprise::AccountLimitsField } : {}
ATTRIBUTE_TYPES = {
id: Field::Number,
name: Field::String,
@@ -16,7 +18,7 @@ class AccountDashboard < Administrate::BaseDashboard
conversations: CountField,
locale: Field::Select.with_options(collection: LANGUAGES_CONFIG.map { |_x, y| y[:iso_639_1_code] }),
account_users: Field::HasMany
}.freeze
}.merge(enterprise_attribute_types).freeze
# COLLECTION_ATTRIBUTES
# an array of attributes that will be displayed on the model's index page.
@@ -33,7 +35,8 @@ class AccountDashboard < Administrate::BaseDashboard
# SHOW_PAGE_ATTRIBUTES
# an array of attributes that will be displayed on the model's show page.
SHOW_PAGE_ATTRIBUTES = %i[
enterprise_show_page_attributes = ChatwootApp.enterprise? ? %i[limits] : []
SHOW_PAGE_ATTRIBUTES = (%i[
id
name
created_at
@@ -41,15 +44,16 @@ class AccountDashboard < Administrate::BaseDashboard
locale
conversations
account_users
].freeze
] + enterprise_show_page_attributes).freeze
# FORM_ATTRIBUTES
# an array of attributes that will be displayed
# on the model's form (`new` and `edit`) pages.
FORM_ATTRIBUTES = %i[
enterprise_form_attributes = ChatwootApp.enterprise? ? %i[limits] : []
FORM_ATTRIBUTES = (%i[
name
locale
].freeze
] + enterprise_form_attributes).freeze
# COLLECTION_FILTERS
# a hash that defines filters that can be used while searching via the search
@@ -69,4 +73,8 @@ class AccountDashboard < Administrate::BaseDashboard
def display_resource(account)
"##{account.id} #{account.name}"
end
def permitted_attributes
super + [limits: {}]
end
end
+4 -1
View File
@@ -12,6 +12,7 @@ class AgentBotDashboard < Administrate::BaseDashboard
avatar_url: AvatarField,
id: Field::Number,
name: Field::String,
account: Field::BelongsTo.with_options(searchable: true, searchable_field: 'name', order: 'id DESC'),
description: Field::String,
outgoing_url: Field::String,
created_at: Field::DateTime,
@@ -26,6 +27,7 @@ class AgentBotDashboard < Administrate::BaseDashboard
COLLECTION_ATTRIBUTES = %i[
id
avatar_url
account
name
outgoing_url
].freeze
@@ -34,7 +36,7 @@ class AgentBotDashboard < Administrate::BaseDashboard
# an array of attributes that will be displayed on the model's show page.
SHOW_PAGE_ATTRIBUTES = %i[
id
avatar_url
account
name
description
outgoing_url
@@ -45,6 +47,7 @@ class AgentBotDashboard < Administrate::BaseDashboard
# on the model's form (`new` and `edit`) pages.
FORM_ATTRIBUTES = %i[
name
account
description
outgoing_url
].freeze
-75
View File
@@ -1,75 +0,0 @@
require 'administrate/base_dashboard'
class SuperAdminDashboard < Administrate::BaseDashboard
# ATTRIBUTE_TYPES
# a hash that describes the type of each of the model's fields.
#
# Each different type represents an Administrate::Field object,
# which determines how the attribute is displayed
# on pages throughout the dashboard.
ATTRIBUTE_TYPES = {
id: Field::Number,
email: Field::String,
password: Field::Password,
remember_created_at: Field::DateTime,
sign_in_count: Field::Number,
current_sign_in_at: Field::DateTime,
last_sign_in_at: Field::DateTime,
current_sign_in_ip: Field::String.with_options(searchable: false),
last_sign_in_ip: Field::String.with_options(searchable: false),
created_at: Field::DateTime,
updated_at: Field::DateTime
}.freeze
# COLLECTION_ATTRIBUTES
# an array of attributes that will be displayed on the model's index page.
#
# By default, it's limited to four items to reduce clutter on index pages.
# Feel free to add, remove, or rearrange items.
COLLECTION_ATTRIBUTES = %i[
id
email
].freeze
# SHOW_PAGE_ATTRIBUTES
# an array of attributes that will be displayed on the model's show page.
SHOW_PAGE_ATTRIBUTES = %i[
id
email
remember_created_at
sign_in_count
current_sign_in_at
last_sign_in_at
current_sign_in_ip
last_sign_in_ip
created_at
updated_at
].freeze
# FORM_ATTRIBUTES
# an array of attributes that will be displayed
# on the model's form (`new` and `edit`) pages.
FORM_ATTRIBUTES = %i[
email
password
].freeze
# COLLECTION_FILTERS
# a hash that defines filters that can be used while searching via the search
# field of the dashboard.
#
# For example to add an option to search for open resources by typing "open:"
# in the search field:
#
# COLLECTION_FILTERS = {
# open: ->(resources) { resources.where(open: true) }
# }.freeze
COLLECTION_FILTERS = {}.freeze
# Overwrite this method to customize how super admins are displayed
# across all pages of the admin dashboard.
#
# def display_resource(super_admin)
# "SuperAdmin ##{super_admin.id}"
# end
end
+6
View File
@@ -30,6 +30,7 @@ class UserDashboard < Administrate::BaseDashboard
created_at: Field::DateTime,
updated_at: Field::DateTime,
pubsub_token: Field::String,
type: Field::Select.with_options(collection: [nil, 'SuperAdmin']),
accounts: CountField
}.freeze
@@ -44,6 +45,7 @@ class UserDashboard < Administrate::BaseDashboard
name
email
accounts
type
].freeze
# SHOW_PAGE_ATTRIBUTES
@@ -53,10 +55,12 @@ class UserDashboard < Administrate::BaseDashboard
avatar_url
unconfirmed_email
name
type
display_name
email
created_at
updated_at
confirmed_at
account_users
].freeze
@@ -68,6 +72,8 @@ class UserDashboard < Administrate::BaseDashboard
display_name
email
password
confirmed_at
type
].freeze
# COLLECTION_FILTERS
+4 -2
View File
@@ -12,10 +12,12 @@ class AsyncDispatcher < BaseDispatcher
[
CampaignListener.instance,
CsatSurveyListener.instance,
EventListener.instance,
HookListener.instance,
InstallationWebhookListener.instance,
WebhookListener.instance
NotificationListener.instance,
ReportingEventListener.instance,
WebhookListener.instance,
AutomationRuleListener.instance
]
end
end
+1 -1
View File
@@ -5,6 +5,6 @@ class SyncDispatcher < BaseDispatcher
end
def listeners
[ActionCableListener.instance, AgentBotListener.instance, NotificationListener.instance]
[ActionCableListener.instance, AgentBotListener.instance]
end
end
+25
View File
@@ -1,5 +1,30 @@
class ConversationDrop < BaseDrop
include MessageFormatHelper
def display_id
@obj.try(:display_id)
end
def contact_name
@obj.try(:contact).name.capitalize || 'Customer'
end
def recent_messages
@obj.try(:recent_messages).map do |message|
{
'sender' => message_sender_name(message.sender),
'content' => render_message_content(transform_user_mention_content(message.content)),
'attachments' => message.attachments.map(&:file_url)
}
end
end
private
def message_sender_name(sender)
return 'Bot' if sender.blank?
return contact_name if sender.instance_of?(Contact)
sender&.available_name || sender&.name
end
end
+3
View File
@@ -1,2 +1,5 @@
class InboxDrop < BaseDrop
def name
@obj.try(:name)
end
end
+2 -2
View File
@@ -6,7 +6,7 @@ class MessageDrop < BaseDrop
end
def text_content
content = @obj.try(:content)
transform_user_mention_content content
content = @obj.try(:content) || ''
render_message_content(transform_user_mention_content(content))
end
end
+1 -1
View File
@@ -2,6 +2,6 @@ require 'administrate/field/base'
class AvatarField < Administrate::Field::Base
def avatar_url
data.presence || '/admin/avatar.png'
data.presence&.gsub('?d=404', '?d=mp')
end
end
@@ -0,0 +1,7 @@
require 'administrate/field/base'
class Enterprise::AccountLimitsField < Administrate::Field::Base
def to_s
data.present? ? data.to_json : { agents: nil, inboxes: nil }.to_json
end
end
+13 -4
View File
@@ -55,7 +55,7 @@ class ConversationFinder
def set_inboxes
@inbox_ids = if params[:inbox_id]
current_account.inboxes.where(id: params[:inbox_id])
@current_user.assigned_inboxes.where(id: params[:inbox_id])
else
@current_user.assigned_inboxes.pluck(:id)
end
@@ -70,7 +70,12 @@ class ConversationFinder
end
def find_all_conversations
@conversations = current_account.conversations.where(inbox_id: @inbox_ids)
if params[:conversation_type] == 'mention'
conversation_ids = current_account.mentions.where(user: current_user).pluck(:conversation_id)
@conversations = current_account.conversations.where(id: conversation_ids)
else
@conversations = current_account.conversations.where(inbox_id: @inbox_ids)
end
end
def filter_by_assignee_type
@@ -121,8 +126,12 @@ class ConversationFinder
def conversations
@conversations = @conversations.includes(
:taggings, :inbox, { assignee: { avatar_attachment: [:blob] } }, { contact: { avatar_attachment: [:blob] } }, :team
:taggings, :inbox, { assignee: { avatar_attachment: [:blob] } }, { contact: { avatar_attachment: [:blob] } }, :team, :contact_inbox
)
@conversations.latest.page(current_page)
if params[:conversation_type] == 'mention'
@conversations.page(current_page)
else
@conversations.latest.page(current_page)
end
end
end
+15
View File
@@ -0,0 +1,15 @@
class EmailChannelFinder
def initialize(email_object)
@email_object = email_object
end
def perform
channel = nil
recipient_mails = @email_object.to.to_a + @email_object.cc.to_a
recipient_mails.each do |email|
channel = Channel::Email.find_by('lower(email) = ? OR lower(forward_to_email) = ?', email.downcase, email.downcase)
break if channel.present?
end
channel
end
end
+77
View File
@@ -0,0 +1,77 @@
module Api::V1::InboxesHelper
def validate_email_channel(attributes)
channel_data = permitted_params(attributes)[:channel]
validate_imap(channel_data)
validate_smtp(channel_data)
end
private
def validate_imap(channel_data)
return unless channel_data.key?('imap_enabled') && channel_data[:imap_enabled]
Mail.defaults do
retriever_method :imap, { address: channel_data[:imap_address],
port: channel_data[:imap_port],
user_name: channel_data[:imap_login],
password: channel_data[:imap_password],
enable_ssl: channel_data[:imap_enable_ssl] }
end
Mail.connection do # rubocop:disable:block
end
end
def validate_smtp(channel_data)
return unless channel_data.key?('smtp_enabled') && channel_data[:smtp_enabled]
smtp = Net::SMTP.new(channel_data[:smtp_address], channel_data[:smtp_port])
set_smtp_encryption(channel_data, smtp)
check_smtp_connection(channel_data, smtp)
end
def check_smtp_connection(channel_data, smtp)
smtp.start(channel_data[:smtp_domain], channel_data[:smtp_login], channel_data[:smtp_password],
channel_data[:smtp_authentication]&.to_sym || :login)
smtp.finish unless smtp&.nil?
end
def set_smtp_encryption(channel_data, smtp)
if channel_data[:smtp_enable_ssl_tls]
set_enable_tls(channel_data, smtp)
elsif channel_data[:smtp_enable_starttls_auto]
set_enable_starttls_auto(channel_data, smtp)
end
end
def set_enable_starttls_auto(channel_data, smtp)
return unless smtp.respond_to?(:enable_starttls_auto)
if channel_data[:smtp_openssl_verify_mode]
context = enable_openssl_mode(channel_data[:smtp_openssl_verify_mode])
smtp.enable_starttls_auto(context)
else
smtp.enable_starttls_auto
end
end
def set_enable_tls(channel_data, smtp)
return unless smtp.respond_to?(:enable_tls)
if channel_data[:smtp_openssl_verify_mode]
context = enable_openssl_mode(channel_data[:smtp_openssl_verify_mode])
smtp.enable_tls(context)
else
smtp.enable_tls
end
end
def enable_openssl_mode(smtp_openssl_verify_mode)
openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{smtp_openssl_verify_mode.upcase}".constantize if smtp_openssl_verify_mode.is_a?(String)
context = Net::SMTP.default_ssl_context
context.verify_mode = openssl_verify_mode
context
end
end
-2
View File
@@ -1,2 +0,0 @@
module Api::V1::ReportsHelper
end
+25 -10
View File
@@ -1,16 +1,31 @@
module FileTypeHelper
# NOTE: video, audio, image, etc are filetypes previewable in frontend
def file_type(content_type)
return :image if [
'image/jpeg',
'image/png',
'image/gif',
'image/tiff',
'image/bmp'
].include?(content_type)
return :video if content_type.include?('video/')
return :audio if content_type.include?('audio/')
return :image if image_file?(content_type)
return :video if video_file?(content_type)
return :audio if content_type&.include?('audio/')
:file
end
def image_file?(content_type)
[
'image/jpeg',
'image/png',
'image/gif',
'image/bmp',
'image/webp',
'image'
].include?(content_type)
end
def video_file?(content_type)
[
'video/ogg',
'video/mp4',
'video/webm',
'video/quicktime',
'video'
].include?(content_type)
end
end
+7
View File
@@ -1,6 +1,13 @@
module MessageFormatHelper
include RegexHelper
def transform_user_mention_content(message_content)
message_content.gsub(MENTION_REGEX, '\1')
end
def render_message_content(message_content)
# rubocop:disable Rails/OutputSafety
CommonMarker.render_html(message_content).html_safe
# rubocop:enable Rails/OutputSafety
end
end
+68
View File
@@ -0,0 +1,68 @@
module ReportHelper
private
def scope
case params[:type]
when :account
account
when :inbox
inbox
when :agent
user
when :label
label
when :team
team
end
end
def conversations_count
(get_grouped_values scope.conversations).count
end
def incoming_messages_count
(get_grouped_values scope.messages.incoming.unscope(:order)).count
end
def outgoing_messages_count
(get_grouped_values scope.messages.outgoing.unscope(:order)).count
end
def resolutions_count
(get_grouped_values scope.conversations.resolved).count
end
def avg_first_response_time
grouped_reporting_events = (get_grouped_values scope.reporting_events.where(name: 'first_response'))
return grouped_reporting_events.average(:value_in_business_hours) if params[:business_hours]
grouped_reporting_events.average(:value)
end
def avg_resolution_time
grouped_reporting_events = (get_grouped_values scope.reporting_events.where(name: 'conversation_resolved'))
return grouped_reporting_events.average(:value_in_business_hours) if params[:business_hours]
grouped_reporting_events.average(:value)
end
def avg_resolution_time_summary
reporting_events = scope.reporting_events
.where(name: 'conversation_resolved', created_at: range)
avg_rt = params[:business_hours] ? reporting_events.average(:value_in_business_hours) : reporting_events.average(:value)
return 0 if avg_rt.blank?
avg_rt
end
def avg_first_response_time_summary
reporting_events = scope.reporting_events
.where(name: 'first_response', created_at: range)
avg_frt = params[:business_hours] ? reporting_events.average(:value_in_business_hours) : reporting_events.average(:value)
return 0 if avg_frt.blank?
avg_frt
end
end
+50
View File
@@ -0,0 +1,50 @@
module ReportingEventHelper
def business_hours(inbox, from, to)
return 0 unless inbox.working_hours_enabled?
inbox_working_hours = configure_working_hours(inbox.working_hours)
return 0 if inbox_working_hours.blank?
# Configure working hours
WorkingHours::Config.working_hours = inbox_working_hours
# Configure timezone
WorkingHours::Config.time_zone = inbox.timezone
# Use inbox timezone to change from & to values.
from_in_inbox_timezone = from.in_time_zone(inbox.timezone).to_time
to_in_inbox_timezone = to.in_time_zone(inbox.timezone).to_time
from_in_inbox_timezone.working_time_until(to_in_inbox_timezone)
end
private
def configure_working_hours(working_hours)
working_hours.each_with_object({}) do |working_hour, object|
object[day(working_hour.day_of_week)] = working_hour_range(working_hour) unless working_hour.closed_all_day?
end
end
def day(day_of_week)
week_days = {
0 => :sun,
1 => :mon,
2 => :tue,
3 => :wed,
4 => :thu,
5 => :fri,
6 => :sat
}
week_days[day_of_week]
end
def working_hour_range(working_hour)
{ format_time(working_hour.open_hour, working_hour.open_minutes) => format_time(working_hour.close_hour, working_hour.close_minutes) }
end
def format_time(hour, minute)
hour = hour < 10 ? "0#{hour}" : hour
minute = minute < 10 ? "0#{minute}" : minute
"#{hour}:#{minute}"
end
end
+46 -21
View File
@@ -1,5 +1,6 @@
<template>
<div id="app" class="app-wrapper app-root">
<div v-if="!authUIFlags.isFetching" id="app" class="app-wrapper app-root">
<update-banner :latest-chatwoot-version="latestChatwootVersion" />
<transition name="fade" mode="out-in">
<router-view></router-view>
</transition>
@@ -10,27 +11,37 @@
<woot-snackbar-box />
<network-notification />
</div>
<loading-state v-else />
</template>
<script>
import { mapGetters } from 'vuex';
import AddAccountModal from '../dashboard/components/layout/sidebarComponents/AddAccountModal';
import WootSnackbarBox from './components/SnackbarContainer';
import LoadingState from './components/widgets/LoadingState.vue';
import NetworkNotification from './components/NetworkNotification';
import { accountIdFromPathname } from './helper/URLHelper';
import UpdateBanner from './components/app/UpdateBanner.vue';
import vueActionCable from './helper/actionCable';
import WootSnackbarBox from './components/SnackbarContainer';
import {
registerSubscription,
verifyServiceWorkerExistence,
} from './helper/pushHelper';
export default {
name: 'App',
components: {
WootSnackbarBox,
AddAccountModal,
LoadingState,
NetworkNotification,
UpdateBanner,
WootSnackbarBox,
},
data() {
return {
showAddAccountModal: false,
latestChatwootVersion: null,
};
},
@@ -38,13 +49,13 @@ export default {
...mapGetters({
getAccount: 'accounts/getAccount',
currentUser: 'getCurrentUser',
globalConfig: 'globalConfig/get',
authUIFlags: 'getAuthUIFlags',
currentAccountId: 'getCurrentAccountId',
}),
hasAccounts() {
return (
this.currentUser &&
this.currentUser.accounts &&
this.currentUser.accounts.length !== 0
);
const { accounts = [] } = this.currentUser || {};
return accounts.length > 0;
},
},
@@ -53,28 +64,37 @@ export default {
if (!this.hasAccounts) {
this.showAddAccountModal = true;
}
verifyServiceWorkerExistence(registration =>
registration.pushManager.getSubscription().then(subscription => {
if (subscription) {
registerSubscription();
}
})
);
},
currentAccountId() {
if (this.currentAccountId) {
this.initializeAccount();
}
},
},
mounted() {
this.$store.dispatch('setUser');
this.setLocale(window.chatwootConfig.selectedLocale);
this.initializeAccount();
},
methods: {
setLocale(locale) {
this.$root.$i18n.locale = locale;
},
async initializeAccount() {
const { pathname } = window.location;
const accountId = accountIdFromPathname(pathname);
if (accountId) {
await this.$store.dispatch('accounts/get');
const { locale } = this.getAccount(accountId);
this.setLocale(locale);
}
await this.$store.dispatch('accounts/get');
const {
locale,
latest_chatwoot_version: latestChatwootVersion,
} = this.getAccount(this.currentAccountId);
const { pubsub_token: pubsubToken } = this.currentUser || {};
this.setLocale(locale);
this.latestChatwootVersion = latestChatwootVersion;
vueActionCable.init(pubsubToken);
},
},
};
@@ -82,6 +102,11 @@ export default {
<style lang="scss">
@import './assets/scss/app';
.update-banner {
height: var(--space-larger);
align-items: center;
font-size: var(--font-size-small) !important;
}
</style>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

Some files were not shown because too many files have changed in this diff Show More