Compare commits

...
547 Commits
Author SHA1 Message Date
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
Sojan 01577acb2e Merge branch 'release/1.22.0' 2021-11-15 21:50:36 +05:30
Sojan 52c850f8b6 Bump version to 1.22.0 2021-11-15 21:49:14 +05:30
Pranav Raj SandGitHub 809509404b fix: Set cc, bcc default to empty string if unavailable (#3387) 2021-11-15 21:05:24 +05:30
Sojan JoseandGitHub acb06e7df6 chore: Prevent notification email loop (#3386)
Configuring an agent email also as a support email inbox leads to conversations getting created in a loop if notifications were also configured to the same email.
2021-11-15 19:15:51 +05:30
e849759e15 feat: Add Command bar for improved productivity (#3352)
Co-authored-by: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com>
2021-11-15 17:22:44 +05:30
1e3f255ece chore: Update translations, fix Crowdin issues
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-11-15 17:18:56 +05:30
Muhsin KelothandGitHub a2764e5c1d chore: Update deleteCustomAttribute method in SDK (#3334) 2021-11-15 14:56:35 +05:30
Muhsin KelothandGitHub c2db8a1fd7 chore: Add the option to edit custom attribute display name (#3382) 2021-11-15 12:45:47 +05:30
Muhsin KelothandGitHub bb18516403 chore: Update conversation sidebar items default order (#3381) 2021-11-15 10:34:57 +05:30
Muhsin KelothandGitHub d1a62fe6ab feat: Add the option for changing the contact/conversation sidebar items order (#3362) 2021-11-13 12:32:53 +05:30
Sojan JoseandGitHub f68a4b55bb chore: Update the translations for CHAT_STATUS_FILTER_ITEMS (#3375) 2021-11-13 11:53:59 +05:30
Sojan JoseandGitHub 987c8f5c7c chore: Fix translations breaking the chat filter (#3374)
fixes: #2552
2021-11-13 11:45:18 +05:30
Sojan JoseandGitHub e011b4566b chore: New Translation updates (#3371) 2021-11-12 23:40:08 +05:30
Tejaswini ChileandGitHub 37a36349f2 feat: Update Swagger for the custom filter endpoint (#3367) 2021-11-12 19:28:03 +05:30
cf5f6d5a74 feat: enable Dialogflow integration all inboxes except email (#3285)
Fixes #2461

Co-authored-by: Sojan Jose <sojan@pepalo.com>
2021-11-12 17:53:03 +05:30
Sojan JoseandGitHub d78cb67a2a chore: Fix conversation status in webhooks (#3364)
- fix the wrong conversation status being sent in webhooks
- additional information in websocket events
- refactor activity messaging code
- move activity message generation to background job to stop the callback loop
2021-11-12 16:17:59 +05:30
b119d9e729 fix: Remove * as import from conversation module (#3366)
* fix: Remove * as import from conversation module

* Remove * as import from conversation test spec

Co-authored-by: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com>
2021-11-12 13:41:43 +05:30
Tejaswini ChileandGitHub 564fa5f392 feat: Update custom filter for present/not_present operator (#3361) 2021-11-12 11:30:39 +05:30
Vishnu NarayananandGitHub 58aae7a4a9 fix: make GlobalConfig migrated from .env editable from UI (#3360) 2021-11-11 19:31:25 +05:30
Muhsin KelothandGitHub c6326993df feat: Show pre-chat form before triggering the campaign (#3215) 2021-11-11 19:02:16 +05:30
Muhsin KelothandGitHub 76370267f3 feat: Render contact custom attributes in contact/conversation sidebar (#3310) 2021-11-11 15:23:33 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
e12edb51a2 chore: Bump axios from 0.21.1 to 0.21.2 (#3358)
Bumps [axios](https://github.com/axios/axios) from 0.21.1 to 0.21.2.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.21.1...v0.21.2)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-11 15:05:59 +05:30
JakobandGitHub 1dfa173b3a fix: Limit rails, postgres and redis container access to localhost (#3354)
This change limits the rails, redis and postgres container on `docker-compose.production.yaml` file to localhost only. 

The default docker-compose configuration will expose redis, postgres and rails directly to the internet when the service is started on a virtual machine.

In most cases that is not what you want, and especially for redis and postgres exposing the services could be a potential security risk. By adding 127.0.0.1 access is limited to localhost and access is only possible after nginx oder another web server is configured as reverse proxy.

Note: Moving forward, anyone using docker-compose.production.yaml need to have something like Nginxto proxy the requests to the container.

If you want to verify whether the installation is working, try curl -I localhost:3000 to see if it returns 200. Also, you could temporarily drop the 127:0.0.1:3000:3000 for rails to 3000:3000 to access your instance at http://:3000. It's recommended to revert this change back and use Nginx in front.

Approved-by: Vishnu Narayanan <vishnu@chatwoot.com>
2021-11-11 14:43:25 +05:30
Sojan JoseandGitHub a4c87f2052 chore: Handle attachments in Whatsapp Channel (#3299)
send and receive attachments in 360Dialog WhatsApp channels
2021-11-11 13:03:48 +05:30
sarzynskiandGitHub b3e313a200 fix: Ensure HMAC mandatory when enabled (#3350)
Add missing condition checking if HMAC is mandatory.

Fixes #3349
2021-11-11 09:48:38 +05:30
Tejaswini ChileandGitHub c0f5a59cf8 Bug: Instagram render template message twice (#3313) 2021-11-10 18:32:46 +05:30
Tejaswini ChileandGitHub 358171062e Feat: Add Null values at the last while sorting (#3292)
* Add Null values at the last while sorting
* Add contacts at last with special character in it
* Optimize SQL order and direction
2021-11-10 14:11:00 +05:30
6cfd7d3836 feat: autogenerate vapid keys for push notifications (#3128)
* feat: Autogenerate push notification keys
* add vapid service class and remove pushkey model
* add spec for vapid service
* unset vapid env keys
* Unset VAPID_PRIVATE_KEY env variable

Co-authored-by: Sojan Jose <sojan@chatwoot.com>
Co-authored-by: Vishnu Narayanan <vishnu@chatwoot.com>
2021-11-09 21:36:32 +05:30
Nithin David 0c9b682329 Revert "feat: Updates widget message state to support multiple conversations"
This reverts commit a34bb565af.
2021-11-09 18:34:55 +05:30
Nithin David a34bb565af feat: Updates widget message state to support multiple conversations 2021-11-09 18:23:20 +05:30
Pranav Raj SandGitHub d00b8df952 fix: Revert translated keys in conversation status (#3337) 2021-11-08 17:03:34 +04:00
Akhil G KrishnanandGitHub 4e01278ea8 TEAM_AVAILABILITY dutch translation issue fixed (#3324) 2021-11-08 17:44:02 +05:30
wsuffandGitHub 26f36548c2 chore: Update message limit to Twilio recommended 320 characters (#3333) 2021-11-08 10:27:00 +04:00
A. VerdeandGitHub 81708f92a8 chore: Fcm notification priority (#3319) 2021-11-08 11:32:07 +05:30
Vishnu NarayananandGitHub 97ee1bfa97 feat: add GlobalConfigService to support env vars migration (#3288) 2021-11-03 21:34:42 +04:00
Sivin VargheseandGitHub 03b1a3d045 feat: Adds support for paste attachment with keys. (#3293)
* copy paste files

* Minor fixes

* Adds support for pasting attachment

* Minor files

* Review fixes
2021-11-02 10:05:49 +05:30
Sivin VargheseandGitHub 0651b11fda bug: Fixes the height issue of attachment image preview. (#3296)
* bug: Fixes the height issue of attachment image preview

* fixes codeclimate issue
2021-11-01 21:00:14 +05:30
Tejaswini ChileandGitHub 372bd75028 feat: Add filter APIs for Contacts and Conversations (#3264) 2021-11-01 12:27:04 +04:00
Hugo SartiandGitHub 68fa694268 fix: Disable typing indicator for user when agent is typing a private note (#3303) 2021-11-01 12:20:07 +04:00
Tejaswini ChileandGitHub 000c7603d6 feat/3247 Escape html tags from the slack messages (#3306) 2021-11-01 12:08:10 +05:30
Muhsin KelothandGitHub a3b6e5655d Disallow editing attribute key and type (#3305) 2021-10-30 12:14:09 +05:30
Muhsin KelothandGitHub ab77e03c92 feat: Render conversation custom attributes (#3065) 2021-10-30 07:09:46 +05:30
Sojan JoseandGitHub 69f55a25b6 chore: Minor API fixes (#3290)
- Log whether web-hook was successful
- Inbox update shouldn't need channel params
2021-10-28 15:26:20 +05:30
Aswin Dev P.SandGitHub 46867e89cb feat: Ability to specify a subject line for outbound emails (#3168) 2021-10-27 13:09:29 +05:30
Sojan JoseandGitHub 2f2d2b4f73 chore: Update translations (#3289) 2021-10-26 23:01:52 +05:30
fcbe68141d fix: Show twilio channel name based on medium (#3284)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-10-26 16:00:00 +05:30
Vishnu NarayananandGitHub ac46d0c855 feat: add domain check prompt for linux installation script (#3282)
- move domain check to beginning to have all user input at the start
- notify user to point DNS if they plan to use a domain with Chatwoot
2021-10-25 21:56:26 +05:30
SanjuandGitHub 74db319a7c feat: Add video preview & player in conversation (#3201) 2021-10-25 19:46:37 +05:30
98e9fedfa6 fix: Resolve contacts filter when entered with contry code (#3241)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-10-25 19:26:11 +05:30
f2c6799444 feat: Update translations (#3279)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-10-25 19:23:58 +05:30
Jay ClarkandGitHub 5119e7a79e fix: Update z-index for chevron in contact sidepanel (#3268)
Signed-off-by: Jay Clark <jay@jayeclark.dev>
2021-10-25 19:14:13 +05:30
Pranav Raj SandGitHub 8e6ce3a813 feat: Add notes for Contacts (#3273)
Fixes #2275
2021-10-25 18:35:58 +05:30
Viraj BahulkarandGitHub e5e73a08fe fix: Render missing captions for telegram media attachments (#3257) 2021-10-25 15:52:06 +05:30
Akhil G KrishnanandGitHub 84df9c807d chore: Add climate-control gem for handling the test ENV vars (#3267) 2021-10-25 13:13:25 +05:30
Sojan JoseandGitHub 06289b03ea chore: Add Contact Note APIs (#3266) 2021-10-24 12:40:30 +05:30
Sivin VargheseandGitHub 19855a90e2 fix: Remove duplicate attachment downloads (#3262) 2021-10-22 19:23:05 +05:30
Jan-DavidandGitHub 09643b63b0 fix: Use correct German translation of 'disabled' (#3255) 2021-10-22 10:42:13 +05:30
Tejaswini ChileandGitHub 658a511b88 feat: Conversation and contact endpoint (#3198) 2021-10-20 18:14:56 +05:30
Muhsin KelothandGitHub b0041ccf3f fix: Close button click action in contact details sidepanel (#3245) 2021-10-20 09:05:08 +05:30
050df43789 feat: Adds sound alert notification for new messages on the widget (#3181)
* feat: Adds sound alert notification for new messages on the widget

* Review fixes

* uses absolute path

* Minor fixes

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-10-18 06:09:04 -07:00
Sojan 3b3ab39ca3 Merge branch 'release/1.21.1' into develop 2021-10-18 14:34:08 +05:30
Sojan 7015609577 Merge branch 'release/1.21.1' 2021-10-18 14:34:01 +05:30
Sojan 58ad0e6fd6 Bump version to 1.21.1 2021-10-18 14:33:46 +05:30
Sojan b8ea8e5b5e Merge branch 'master' into develop 2021-10-18 14:32:33 +05:30
Vishnu NarayananandGitHub eada8c9af2 chore: Fix puma http-parser error (#3236)
https://github.com/puma/puma/releases/tag/v5.5.2
2021-10-18 14:23:28 +05:30
Pranav Raj SandGitHub 6de964a0bd fix: HTTP parser error in linux installations (#3232) 2021-10-18 14:20:48 +05:30
lybrusandGitHub 9f9dd09985 chore: .env.example MAILER_SENDER_EMAIL put value in quotes (#3226)
Signed-off-by: Damir Rashidov <damir@rashidov.eu>
2021-10-18 14:15:04 +05:30
Sojan a9849e402e Merge branch 'master' into develop 2021-10-16 00:18:47 +05:30
Sojan a2ffcc4502 Merge branch 'release/1.21.0' into develop 2021-10-16 00:13:23 +05:30
Sojan c831bee0e3 Merge branch 'release/1.21.0' 2021-10-16 00:13:06 +05:30
Sojan JoseandGitHub 3b53ca157c chore: fix the failing user destroy for admin (#3223)
- fix the invitee association on the user
- handle Instagram events with inbox missing
2021-10-16 00:11:53 +05:30
Sojan de0702b679 Bump version to 1.21.0 2021-10-15 14:44:56 +05:30
Muhsin KelothandGitHub cd5c2c51d9 fix: Send notification to all the mentioned users in a private message (#3222) 2021-10-15 14:35:43 +05:30
Sojan JoseandGitHub cebd34053b chore: Use availability in dashboard presence toggle (#3212) 2021-10-15 00:30:48 +05:30
Pranav Raj SandGitHub ed25435ac2 fix: Render inbox icon properly (#3219) 2021-10-14 20:18:43 +05:30
0c65db925d chore: Fixes the missing gem warning (#3207)
* chore: Fixes the missing gem warning

fixes: #3143

* chore: rubocop fixes

Co-authored-by: Tejaswini Chile <tejaswini776@gmail.com>
2021-10-14 13:57:01 +05:30
Sojan JoseandGitHub 590001cca2 chore: New Translation updates (#3214) 2021-10-14 13:32:15 +05:30
Sojan JoseandGitHub e669f6766f chore: Fix Dialogflow issue (#3210) 2021-10-14 13:17:09 +05:30
Pranav Raj SandGitHub 99abbb8158 feat: Display sent status of emails in email channel (#3125) 2021-10-14 12:55:46 +05:30
Muhsin KelothandGitHub 5c30bc3e2b fix: Read message appears on page refresh in the widget (#3175) 2021-10-14 11:51:00 +05:30
Muhsin KelothandGitHub 5799b9fa26 chore: Fix the prop warning issue in contact merge modal (#3211) 2021-10-13 18:58:30 +05:30
Nithin David ThomasandGitHub b33701a666 feat: Create modal to merge two contacts (#2457) 2021-10-13 18:35:13 +05:30
WevrLabsandGitHub 6c3e2a0bd3 feat: Render sticker messages from Telegram (#3204)
Add support for rendering sticker messages thumbs in Telegram.
2021-10-13 17:16:14 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
a494afd0e7 chore: Bump puma from 5.4.0 to 5.5.1 (#3208)
Bumps [puma](https://github.com/puma/puma) from 5.4.0 to 5.5.1.
- [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.4.0...v5.5.1)

---
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>
2021-10-13 14:01:06 +05:30
6998e9aa2d fix: Update email message_id parsing order (#3073)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-10-12 20:46:00 +05:30
Muhsin KelothandGitHub 6bfa551c85 fix: Trigger campaigns only during business hours (#3085)
Fixes #2433
2021-10-12 17:58:33 +05:30
7c21cf2255 feat: Render audio, video and voice attachments in telegram. (#3155)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-10-12 12:58:30 +05:30
Tejaswini ChileandGitHub 5749d25ff8 feat: Update instagram webhooks URL (#3197) 2021-10-12 12:46:27 +05:30
c1d68cc8ae feat: Show refresh prompt on network disconnect (#3165)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-10-12 11:57:36 +05:30
Nithin David ThomasandGitHub 5237e51f2c chore: Fixes lint errors in mail component (#3200) 2021-10-12 10:14:09 +05:30
Manoj M JandGitHub 2c8bf00d38 chore: Use connection pooling for Redis
ref: #3199
2021-10-11 19:46:15 +05:30
Murtaza BagwalaandGitHub 3d3f0ff6ee feat: Ability to receive attachments from LINE messenger (#3094)
Add support to add videos, audio, and images from line to chatwoot.

Fixes #3039
2021-10-11 19:06:41 +05:30
2c3e37b157 fix: Disable triggering disabled ongoing campaigns (#3115)
* fixes: Triggering disabled ongoing campaigns.

* Fix the specs

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-10-11 18:18:11 +05:30
Aswin Dev P.SandGitHub a35269d275 chore: Create conversation API should accept assignee & team (#3166) 2021-10-11 15:17:30 +05:30
68e697c379 feat: Support cc and bcc in email replies (#3098)
Co-authored-by: Tejaswini <tejaswini@chatwoot.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-10-11 13:00:48 +05:30
Sojan JoseandGitHub 0e0632be22 chore: Minor Housekeeping tasks (#3169)
- Limit Rack attack to production environments
- Make the long-running data migration optional
2021-10-08 15:45:45 +05:30
1c4afb10df fix: Open live-chat widget clicking on any unread message (#3153)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-10-08 14:08:13 +05:30
SanjuandGitHub ec2dc1b61b fix: Update the styles for ol & li - lists in dashboard (#3110) 2021-10-08 13:55:21 +05:30
b9e85a628b Feat : Toggle to enforce user validation in Chatwoots web SDK (#3137)
* If enabled, enforces user validation with identifier_hash

* Fixes the hmac flag payload

* Adds missing i18n label for checkbox

* If enabled, Adds EOF on json file

* If applied, Handles HMAC Disable option

Co-authored-by: Tejaswini Chile <tejaswini776@gmail.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2021-10-08 12:53:24 +05:30
Vishnu NarayananandGitHub 5d3cce12d5 fix: Disable rack attack gem in circleCI (#3167) 2021-10-08 12:14:23 +05:30
Sojan JoseandGitHub 8c192559fe chore: Rate limits on widget conversation endpoints (#3162)
- Limit widget conversation creation to 6 per 12 hours
- Enable rack attack by default
2021-10-07 18:06:43 +05:30
Tejaswini ChileandGitHub 700721ea6d fix: Issue when Instagram response body is empty
Fixes #3138
2021-10-07 14:36:54 +05:30
Sojan JoseandGitHub c54aae21ff chore: Move agent availability to Account level (#3074)
- Move agent availability to the account level
2021-10-07 13:21:46 +05:30
1c6a539c0a feat: Add Reports for teams (#3116)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-10-06 23:53:51 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Sojan Jose
3e99088fe3 chore: Bump url-parse from 1.5.1 to 1.5.3 (#3146)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.1 to 1.5.3.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.1...1.5.3)

---
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: Sojan Jose <sojan@pepalo.com>
2021-10-06 22:16:14 +05:30
ec9903ae82 fix: Add background to inbox channel badges (#3152)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-10-06 19:34:34 +05:30
Sojan JoseandGitHub 219a8c4bc5 chore: Instagram reconnect fix (#3142) 2021-10-06 16:23:32 +05:30
Nithin David 271ca53c58 fix: Makes thumbnail images fill the wrap 2021-10-06 14:47:44 +05:30
Murtaza BagwalaandGitHub f874925f0e fix: set default content type as text for message (#3060)
Fixes #2974
2021-10-06 00:10:29 +05:30
bd7aeba484 chore: Provider API prototype (#3112)
Enabling Support for Whatsapp via 360Dialog as a prototype for the provider APIs. 

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-10-05 23:35:06 +05:30
Tejaswini ChileandGitHub 40d0b2faf3 feat: Add Instagram Channel (#2955) 2021-10-05 14:35:32 +05:30
Sivin VargheseandGitHub 30244f79a6 fixes: Reply box goes hidden and emoji input header section is broken. (#3121) 2021-10-03 21:49:44 -07:00
Sojan JoseandGitHub 1d94e65ca8 fix: CSAT reports page failing to load (#3123)
CSAT reports page was failing to load when there is an assigned agent is deleted.
2021-10-01 13:37:52 +05:30
Aswin Dev P.SandGitHub be9a055a3f feat: Ability to send attachments to telegram (#3108)
This feature allows the user to send and delete attachments in the telegram conversation.

Fixes #3037
2021-10-01 01:45:29 +05:30
Siddharth RameshandGitHub e6bcf24864 chore: Add readonly attribute to woot-input component (#3119) 2021-09-30 22:07:20 +05:30
Pranav Raj SandGitHub 1083a24a26 fix: Update Re-rendering behaviour for lists in conversation view (#3117)
* fix: Update Re-rendering behaviour for lists in conversation view

* Remove console.log
2021-09-30 15:11:00 +05:30
a1563917ba feat - Add filter for reports by agent, label and inboxes (#3084)
* Adds filter for agents, labels and inboxes

* Added Inboxes Reports Feature

* Fixed populating of filter dropdown issue

* If applied, fixes code climate style-lint warnings

* Fixes codeclimate warnings

* if applied, Refactors sidebar file to fix codclimate warnings

* if applied, fixes the download reports button for filtered report-data

* If applied, replaces native img tag with thumbnail component

* If applied, replaces hardcoded color string with variable

* If applied, adds a11y labels to multiselect dropdowns

* If applied, Renames reports methods to generic names

* If applied, Adds test cases for Labels and Inboxes

* If applied, write a test spec for fileDownload helper

* if applied, Moves fileDownload method to a utils folder

* If applied, Fixes the report file name type

* Test Spec for Reports Store module

* Fix specs - add restoreAllMocks

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-09-30 13:13:45 +05:30
Pranav Raj SandGitHub 57abdc4d5f feat: Display "Snoozed Until" time on conversation header (#3028) 2021-09-29 19:33:51 +05:30
Sojan JoseandGitHub 49ac4a4400 chore: Fix Twilio callback url not appearing until refresh (#3106)
The Twilio callback url wasn't being displayed until the page is refreshed

fixes: #3034
2021-09-29 18:29:13 +05:30
Pranav Raj SandGitHub cc244833d0 feat: Add all filter for conversations (#3102) 2021-09-29 16:23:39 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Muhsin Keloth
d55a48037a chore: Bump tmpl from 1.0.4 to 1.0.5 (#3059)
Bumps [tmpl](https://github.com/daaku/nodejs-tmpl) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/daaku/nodejs-tmpl/releases)
- [Commits](https://github.com/daaku/nodejs-tmpl/commits/v1.0.5)

---
updated-dependencies:
- dependency-name: tmpl
  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>
2021-09-29 13:00:56 +05:30
6f6bb91823 fix: Add meaningful alert error message if file upload fails (#3093)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-09-29 13:00:08 +05:30
a8f6eebd66 bug: Fixes Incorrect badge for Twilio SMS inbox and adds the ability to differentiate Twitter tweets and chats (#3003)
* bug: Fixes Incorrect badge in the thumbnail for Twilio SMS inbox

* Minor fixes

* Minor fixes

* Review fixes

* Minor fixes

* fixes codeclimate error

* Minor fixes

* Minor fixes

* Minor fixes

* Review fixes

* Minor fixes

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-09-29 12:56:45 +05:30
bba2750975 feat: Add ability to bulk import contacts (#3026)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-09-29 12:01:58 +05:30
6129edce08 fix: dialogflow integration in docker environments (#3072)
* natively compile ruby gems

* add missing compiler tools

* add bundler platform ruby to force native compilation

* fix bundler env in final docker stage

* add comments to DockerFile

Co-authored-by: Sojan Jose <sojan@pepalo.com>
2021-09-28 20:49:50 +05:30
Sojan JoseandGitHub ed22e7cad4 chore: mitigate CVE-2021-41098 (#3101)
ignoring CVE-2021-41098 as Chatwoot doesn't support JRuby at the moment

fixes: #3097
2021-09-28 19:34:11 +05:30
Aswin Dev P.SandGitHub edd0e2329f feat: Add the ability to close and reopen the chat window via SDK (#3080) 2021-09-28 19:25:44 +05:30
Sivin VargheseandGitHub 1761bec615 feat: Adds ability to edit out webhook URL of API Channel (#3013) 2021-09-28 12:33:08 +05:30
Aswin Dev P.SandGitHub 15aaa8883c feat: API to Filter reports by teams (#3066)
Add API to Filter reports by teams

Fixes: #2916
2021-09-27 21:12:08 +05:30
8b7f6c691a bug: fixes error in creating a new one off campaign (#3067)
* bug: fixes error in creating a new one off campaign

* Review fixes

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-09-24 08:07:30 -07:00
Akhil G KrishnanandGitHub 1cb2226dbc chore: Remove unused memoization in telegram incoming service (#3075) 2021-09-24 17:22:22 +05:30
Hugo SartiandGitHub 1f4685ae4b fix: offset issue for Business hours on timezones with DST 2021-09-24 00:20:08 +05:30
Tejaswini ChileandGitHub 54bdb2957f feat: Add assignee last seen to conversations (#3069)
- Adds assignee last seen attribute to conversations
2021-09-23 20:59:10 +05:30
Aswin Dev P.SandGitHub 4f51a46c2b feat: Ability to delete a contact (#2984)
This change allows the administrator user to delete a contact and its related data like conversations, contact inboxes, and reports.

Fixes #1929
2021-09-23 12:52:49 +05:30
Muhsin KelothandGitHub 0c24df96a8 chore: Conversation custom attribute APIs (#3024) 2021-09-22 10:46:48 +05:30
Tejaswini ChileandGitHub dddab0bbce chore: Handle the Twilio exception in sentry
Fix trying to extract the Sid from non created message.

Fixes #3029
2021-09-21 23:02:45 +05:30
Murtaza BagwalaandGitHub c504067e2b fix: Add blank check for file param in Import API (#3057) 2021-09-21 10:20:12 +05:30
Pranav Raj SandGitHub b59e73b10b fix: Update associations when a label is updated (#3046) 2021-09-21 10:16:32 +05:30
Sojan JoseandGitHub aaadd61e09 fix: Outbound messages triggering out of office (#3051) 2021-09-21 10:16:14 +05:30
dcbbb09ebd fix: Update widget option button style to handle long text (#3030)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-09-19 21:12:54 +05:30
Pranav Raj SandGitHub fa2db5a729 fix: Update title for out of office message (#3043) 2021-09-19 20:38:20 +05:30
Tejaswini ChileandGitHub b1b0268705 feat: Support sending and receiving attachments in Slack Integration (#3022)
- Process incoming slack attachments
- Send attachments from chatwoot to slack
2021-09-18 00:49:01 +05:30
Aswin Dev P.SandGitHub 794a56d4cc Feat: Out of office autoresponder (#2992)
This change allows the user to enable autoresponder during the out-of-office time.

Fixes: #2035
2021-09-17 22:17:11 +05:30
Tejaswini ChileandGitHub 6ad5a7452c fix: Emails not delivered when case does not match
Fixes #2504
2021-09-17 22:14:39 +05:30
Sojan JoseandGitHub 0c3e8b6dbd chore: Return medium in inbox APIs (#3025)
Return medium in inbox APIs
2021-09-16 16:51:06 +05:30
Tejaswini ChileandGitHub a0ffefad71 chore: Use the name of the sender from the mail object
if the sender email is Sony Mathew <Sony@chatwoot.com> Contact should be built with Sony Mathew

Fixes #2911
2021-09-16 13:26:52 +05:30
Sojan 799e0ed4f5 Merge branch 'master' into develop 2021-09-15 20:19:34 +05:30
Sojan 928766f07b Merge branch 'release/1.20.0' into develop 2021-09-15 20:19:09 +05:30
Sojan b474e39feb Merge branch 'release/1.20.0' 2021-09-15 20:18:57 +05:30
Pranav Raj SandGitHub 3abcadb5cb fix: Reject keyboard shortcut listeners if input box is active (#3019)
Reject keyboard shortcut listeners if input box is active
2021-09-15 20:15:06 +05:30
Sojan JoseandGitHub a14f4ede87 chore: Sidebar icons for new inboxes (#3016)
- Sidebar icons for line and telegram inboxes
- Sentry fix for contact IP lookup job
2021-09-15 18:12:56 +05:30
Sojan JoseandGitHub 2396b59f11 chore: API fixes (#3014)
- Minor API fixes
- Configuration screen for LINE inbox
2021-09-14 22:44:53 +05:30
Sojan JoseandGitHub 946a09928e Chore: Release Fixes (#3011)
- Fix super admin crashing
- Fix error on telegram group messages

fixes: #2856
2021-09-14 15:54:57 +05:30
Vishnu NarayananandGitHub 2c381d726d chore: Update installation env value for linux script (#3005) 2021-09-14 12:59:22 +05:30
Pranav Raj SandGitHub 11cbc4d952 fix: Revert key changes in it translation files (#3010) 2021-09-14 12:33:13 +05:30
Sojan d76455e840 Bump version to 1.20.0 2021-09-14 12:29:05 +05:30
Pranav Raj SandGitHub aa5d01b572 fix: Hide quoted replies by default from messages (#3009)
Fixes: #2009 , #2365
2021-09-14 11:55:48 +05:30
Sojan JoseandGitHub 22d1c8baf2 Chore: Inbox Members API improvements (#3008)
- New Inbox Member APIs
- Return JSON errors for Platform APIs
2021-09-14 11:55:02 +05:30
ccd0dc39ad chore: Update translations (#3004)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-09-13 19:19:59 +05:30
Fayaz AhmedandGitHub 84b96526db chore: Upgrade vue router to the 3.x (#2981) 2021-09-13 18:10:56 +05:30
Pranav Raj SandGitHub f2e2a0b7ed chore: Update contact sidebar with accordion (#3002) 2021-09-13 18:08:58 +05:30
Sojan JoseandGitHub 328edd24de chore: Move Facebook event processing to worker (#2988) 2021-09-13 18:05:14 +05:30
26a3150fd8 feat: Adds the ability to edit and delete custom attributes (#2982)
* feat: Adds the ability to edit and delete custom attributes

* Review fixes

* Minor fixes

* Adds specs

* Minor fixes

* Update settings.routes.js

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-09-13 03:26:18 -07:00
Brandon WilsonandGitHub 571fefd7cd fix: Selected agent profile picture in agent multi select (#2949) 2021-09-13 13:43:19 +05:30
Tejaswini ChileandGitHub b74261205d chore: Support for special characters in password
Fixes: #2919
2021-09-13 13:15:05 +05:30
Pranav Raj SandGitHub f79c52b8c3 chore: Update Changelog URL (#3001) 2021-09-13 12:54:26 +05:30
Sojan JoseandGitHub 0a38632f14 feat: Line Channel (#2904)
- Ability to configure line bots as a channel in chatwoot
- Receive a message sent to the line bot in chatwoot
- Ability to reply to line users from chatwoot

fixes: #2738
2021-09-11 01:31:17 +05:30
Sojan JoseandGitHub 671c5c931f feat: Telegram Channel (#2901)
- Ability to configure telegram bots as a channel in chatwoot
- Receive a message sent to the telegram bot in chatwoot
- Ability to reply to telegram users from chatwoot
- Receive attachment messages in chatwoot

fixes: #1843
2021-09-10 00:00:52 +05:30
Sojan JoseandGitHub 9c4ce9af35 chore: Strip unnecessary data from push payload (#2924) 2021-09-09 13:59:42 +05:30
Fayaz AhmedandGitHub 2821777e93 feat: Add multiline support for channel greeting message (#2952) 2021-09-08 15:07:24 +05:30
41314157c2 fix: Revert translated values in CHAT_STATUS_ITEMS (#2977)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-09-08 10:06:18 +05:30
Sivin VargheseandGitHub c80289e661 feat: Add custom attribute table (#2929) 2021-09-08 09:37:58 +05:30
39c4fa111a chore: Update translations (#2965)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-09-07 23:14:58 +05:30
Pranav Raj SandGitHub 4759730022 feat: Configure Chatwoot & Analytics for SaaS app (#2975)
* feat: Add Chatwoot support inside Chatwoot SaaS
* Fix identity issues with Chatwoot
2021-09-07 23:11:01 +05:30
Sojan JoseandGitHub 8de4ce0037 chore: attachment validation fix (#2976)
- Attachment validation was supposed to affect the web widget channel only. But it was validating for all channels
2021-09-07 22:59:02 +05:30
NoocandGitHub 7245e66b31 Mount local storage to host in docker-compose.production.yaml (#2953) 2021-09-07 19:52:14 +05:30
Tejaswini ChileandGitHub 772d4ae726 feat: Send MMS through Twilio Inbox (#2959)
Send MMS message to customer for Twilio integration inbox.

Fixes #2311
2021-09-07 00:05:14 +05:30
Pranav Raj SandGitHub 118c1458ab fix: Remove duplicate emit event (#2969) 2021-09-06 15:13:51 +05:30
Pranav Raj SandGitHub dace97b7b0 feat: Update design - CSAT survey page (#2964) 2021-09-06 11:42:02 +05:30
Pranav Raj SandGitHub 7b77bab18e fix: Update actions position if avatar image is unavailable (#2963) 2021-09-06 01:14:17 +05:30
7fc575a474 feat: Use accordion in conversation sidepanel (#2839)
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-09-06 00:19:09 +05:30
Sojan JoseandGitHub 9acac38635 chore: Update translations (#2958) 2021-09-05 19:12:18 +05:30
Sojan JoseandGitHub 2ebd38c3b7 Chore: API Improvements (#2956)
- API to fetch info of a single inbox
- Document passing custom_attributes in the API
- Ability to filter contacts with contact identifier in search API
2021-09-04 17:56:46 +05:30
Sojan JoseandGitHub b866c54ad5 chore: Bring updated translations (#2945) 2021-09-03 15:48:24 +05:30
Muhsin KelothandGitHub ff1625708e fix: Subscription attribute update issue (#2951) 2021-09-03 13:45:14 +05:30
SanjuandGitHub a03ed4eea0 feat: Update agent report filename to use generated date (#2934) 2021-09-03 11:58:26 +05:30
Sojan JoseandGitHub ad83d1bb71 feat: Platform API improvements (#2900)
- Platform APIs to add and update custom attributes to users
- Platform APIs to delete accounts
- Platform APIs to delete users
2021-09-02 18:29:45 +05:30
Nithin David ThomasandGitHub a60a33679f fix: Fixes messages jumping issue for newly created message (#2935)
* fix: Fixes messages jumping issue for newly created message

* Fixes border radius issue of messages

* Fixes bottom jumping issue

* Fixes code climate issue
2021-09-02 16:26:20 +05:30
af1d8c0ee5 feat: Fixes #1940 WCAG support for website widget (#2071)
Co-authored-by: Kaj Oudshoorn <kaj@milvum.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2021-09-02 12:13:53 +05:30
2ddd508aee Add missing conversation id for first response event (#2922)
- Add missing conversation id for first response event
- Fixing the flaky test

Fixes #2746

Co-authored-by: Tejaswini <tejaswini@chatwoot.com>
2021-09-02 00:16:09 +05:30
8b841596a5 feat: Creates pop out reply box (#2832)
* enhancement: Creates draggable pop out replay box

* Review fixes

* Minor fixes

* codeclimate fixes

* Update z-index.scss

* Minor fixes

* Review fixes

* Minor fixes

* Update MessagesView.vue

* Review fixes

* Review fixes

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>
2021-09-01 06:42:22 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
afdf1c70c1 chore: Bump tar from 6.1.3 to 6.1.11 (#2936)
Bumps [tar](https://github.com/npm/node-tar) from 6.1.3 to 6.1.11.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v6.1.3...v6.1.11)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-01 18:13:41 +05:30
Sojan JoseandGitHub 6fdd4a2996 chore: Security Improvements to the API (#2893)
- Devise auth tokens are reset on password update
- Avatar attachment file type is limited to jpeg,gif and png
- Avatar attachment file size is limited to 15 mb
- Widget Message attachments are limited to types ['image/png', 'image/jpeg', 'image/gif', 'image/bmp', 'image/tiff', 'application/pdf', 'audio/mpeg', 'video/mp4', 'audio/ogg', 'text/csv']
- Widget Message attachments are limited to 40Mb size limit.
2021-09-01 15:08:05 +05:30
Muhsin KelothandGitHub 06d8916341 fix: Handle more rest client exceptions (#2930) 2021-08-31 19:45:11 +05:30
Aswin Dev P.SandGitHub 6563cccf34 Add attachment button for email conversation (#2927) 2021-08-31 19:06:12 +05:30
5319af3dfc chore: Merge contact copy over information (#2812)
fixes: #2767, #2773

Co-authored-by: Nithin David <1277421+nithindavid@users.noreply.github.com>
2021-08-31 15:30:18 +05:30
1ff9939a80 feat: Ability to remove inbox avatar (#2885)
* Delete inbox avatar

1) New API endpoint added for deleting inbox avatar.
2) Delete avatar button in the inbox settings page.

Co-authored-by: Sojan Jose <sojan@pepalo.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-08-31 15:12:05 +05:30
Sivin VargheseandGitHub fdcc322660 feat: Add the ability to create custom attribute (#2903) 2021-08-31 13:54:34 +05:30
Pranav Raj SandGitHub 75329e5de1 fix: Add missing referer & initiated_at.timestamp to events (#2920) 2021-08-31 11:46:15 +05:30
Pranav Raj SandGitHub 588f49cc34 fix: Update param name for attachments (#2921) 2021-08-31 11:27:40 +05:30
Tejaswini ChileandGitHub 65f3e83afd feat: APIs to filter reports (#2889)
Fixes #2823
2021-08-27 22:46:32 +05:30
Brandon WilsonandGitHub f94abaef5f feat: Shows inbox identifier token for API inbox (#2894)
Fixes: #2605
2021-08-27 19:56:45 +05:30
Aswin Dev P.SandGitHub 9a8cbee470 chore: Display email channel configuration while editing (#2896) 2021-08-27 19:15:54 +05:30
Nithin David ThomasandGitHub 78646b44b8 fix: Fixes widget holder blocking page clicks (#2897) 2021-08-27 13:10:21 +05:30
0a08e1ffc0 feat: Adds async and defer attributes to chatwoot script tag (#2890)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2021-08-26 19:51:10 +05:30
Muhsin KelothandGitHub 5853531d9a fix: Disable attribute route from settings menu (#2891) 2021-08-26 18:51:59 +05:30
Sivin VargheseandGitHub d13c4ff8c5 feat: Keyboard shortcuts improvements (#2790) 2021-08-26 15:55:58 +05:30
Tejaswini ChileandGitHub 69b0434bb7 chore: Display available name in email (#2888) 2021-08-26 15:16:47 +05:30
1d5150e3a7 feat: Update activity message, email designs in Message bubble (#2886)
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2021-08-26 11:58:56 +05:30
Muhsin KelothandGitHub 7dd42f3fd7 chore: Add description in custom attributes CRUD API response (#2875) 2021-08-26 01:10:45 +05:30
Sivin VargheseandGitHub 4a23a393f7 feat: Creates custom attributes route (#2877) 2021-08-25 20:30:34 +05:30
Vishnu NarayananandGitHub 8d6b3efa2e fix: chatwoot_webpack failure due to missing git (#2878) 2021-08-25 14:51:35 +05:30
Muhsin KelothandGitHub a27ccc5866 fix: Disable "none" option from team dropdown If team is not selected (#2876) 2021-08-25 14:11:16 +05:30
Sojan JoseandGitHub a9ca76d9df chore: support for APMs (#2874)
Add the support for Newrelic and Datadog.
ref: https://www.chatwoot.com/docs/self-hosted/monitoring/apm-and-error-monitoring

fixes: #2861
2021-08-25 01:04:29 +05:30
Tejaswini ChileandGitHub 21e8a41206 fix: Update styles in email template for mention notifications (#2871) 2021-08-24 22:42:48 +05:30
Muhsin KelothandGitHub 1257f86f22 chore: Add description field in custom attribute model (#2872) 2021-08-24 21:17:23 +05:30
Tejaswini ChileandGitHub 09e3413d10 chore: consider X-original-sender to create contact in case of group mail (#2841)
For emails forwarded from google groups, Google rewrites the FROM address to the group email and the original email will be available under X-Original-Sender. This PR enables chatwoot to handle this case.

Fixes: #2715
2021-08-24 14:18:08 +05:30
Muhsin KelothandGitHub 6515b69560 feat: CSAT for all channels (#2749) 2021-08-23 22:00:47 +05:30
5debe9e8ee fix: Add agent typing notification on all channels (#2855)
Fixes CVE-2021-22881

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-08-23 21:34:23 +05:30
Vishnu NarayananandGitHub 7cd3cef0a2 chore: add uptime and response time badges (#2842) 2021-08-20 21:28:16 +05:30
Tejaswini ChileandGitHub eb80324eaa feat: Add message content to mention email template (#2838) 2021-08-18 15:28:45 +05:30
Sojan 20b96c7c60 Merge branch 'release/1.19.0' 2021-08-17 01:50:25 +05:30
Sojan 6a9c885926 Bump version to 1.19.0 2021-08-17 01:48:46 +05:30
Pranav Raj SandGitHub ed317c5bb3 feat: Use relay server for self-hosted mobile push notifications (#2757) 2021-08-17 01:44:16 +05:30
Vishnu NarayananandGitHub 319412f6dc feat: include installation method in data to cw hub (#2831) 2021-08-16 23:35:00 +05:30
Sivin VargheseandGitHub 0e4196c91a enhancement: Removes the focus of the first item in the dropdown when it is active. (#2833) 2021-08-16 22:11:20 +05:30
Nithin David ThomasandGitHub 70d41ffcdd fix: Smoothens out opening animation for widget (#2789) 2021-08-14 08:40:29 +05:30
Nithin David ThomasandGitHub e09941db1c fix: Use all: revert to avoid external css styles for widget bubble (#2809) 2021-08-13 20:16:33 +05:30
Pascal JuferandGitHub 37bf4b7dd8 fix: Use label for "Subscribe to updates" checkbox (#2788) 2021-08-13 19:10:47 +05:30
Aswin Dev P.SandGitHub 9e052fd5b2 chore: Set phone_number through Website SDK (#2803)
Fixes: #2599
2021-08-13 17:26:09 +05:30
dfcc33cbdd fix: Fixes error when dropdown button is focused (#2797)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-08-13 13:40:12 +05:30
0f148f7700 fix: Fixes parsing issue with custom attributes (#2796)
* fix: Fixes parsing issue with custom attributes

* Update app/javascript/dashboard/routes/dashboard/conversation/ContactCustomAttributes.vue

Co-authored-by: शैलेश कळमकर (Shailesh Kalamkar) <shailesh.kalamkar@gmail.com>

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: शैलेश कळमकर (Shailesh Kalamkar) <shailesh.kalamkar@gmail.com>
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2021-08-13 13:37:51 +05:30
Sojan JoseandGitHub acb39cbc8f chore: Ability to create contact with identifiers (#2802) 2021-08-13 13:02:46 +05:30
Nithin David ThomasandGitHub d492a65c24 fix: Checks JS window object for null before focusing (#2798) 2021-08-12 23:21:31 +05:30
3d807684bb fix: Reduce size of Docker image (#2779)
* fix: Ordering in Dockerfile

Folders node_modules & tmp/cache are currently not removed and thus the Docker image
size is pretty big.

I don't think we can remove app/assets & vendor/assets though as the
app won't work without those.

* Expose port 3000 in Docker image
* Further Dockerfile optimization

Co-authored-by: Vishnu Narayanan <vishnu@chatwoot.com>
2021-08-12 15:10:02 +05:30
21d2b4d918 chore: Consider inbox.timezone in open_at logic (#2183)
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2021-08-12 02:29:15 +05:30
Sojan JoseandGitHub 1f59205f20 chore: handle more exceptions (#2793) 2021-08-12 01:32:22 +05:30
a065165bcb fix: undefined method contact in support mailbox (#2678)
if chatwoot receives an email of already existing contact with a different case say "Care@example.com", before this fix, it will throw an error. Now it will retrieve existing contact

Fixes: #2553


Co-authored-by: Sojan Jose <sojan@pepalo.com>
2021-08-12 01:28:07 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
4907489ea8 chore: Bump path-parse from 1.0.6 to 1.0.7 (#2786)
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-12 00:28:14 +05:30
Muhsin KelothandGitHub 4d668d8db3 feat: Dedicated tab for campaigns (#2741) 2021-08-11 20:29:33 +05:30
Sojan JoseandGitHub 8daf1fe033 chore: Add down gem for Local file downloads (#2765)
- Add down gem to handle downloading files to host machine
- Remove the LocalResource class
- Introduce max limit for contact avatars send via SDK
2021-08-11 16:40:28 +05:30
29f54c1f26 chore: Removed the multi-select agent dropdown from the conversation header. (#2781)
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2021-08-10 23:25:55 -07:00
1a4faab381 feat: Creates story for cc bcc input component in reply box (#2763)
* feat: Creates cc bcc input component for reply box

* Adds email inputs for cc and bcc

* Cleans storybook code

* Fixes eslint issues

* Update app/javascript/dashboard/components/widgets/conversation/stories/ReplyEmailHead.stories.js

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>

* Review fixes

* Update app/javascript/dashboard/components/widgets/conversation/stories/ReplyEmailHead.stories.js

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>

* Update app/javascript/dashboard/components/widgets/conversation/stories/ReplyEmailHead.stories.js

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>

* Update app/javascript/dashboard/components/widgets/conversation/stories/ReplyEmailHead.stories.js

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-08-11 11:34:47 +05:30
c3314dd186 feat: Creates a modal showing all the available keyboard shortcuts (#2728)
* feat: Adds modal showing all the available keyboard shortcuts

* Minor fixes

* Minor fixes

* Spacing fixes

* fix translations

* Adds i18n

* Review fixes

* Review fixes

* spacing fixes

* Review fixes

* Minor fixes

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-08-09 21:23:40 -07:00
Pranav Raj SandGitHub bdc4ecffc1 fix: Save content_type, multipart information to email message model (#2774) 2021-08-09 18:04:34 +05:30
Nithin David ThomasandGitHub 462214aced fix: Reduces space for custom drop-downs (#2778) 2021-08-09 15:12:11 +05:30
c523a953f7 feat: Adds keyboard shortcuts for conversation actions (#2672)
* feat: Adds keyboard shortcuts for conversation actions

* Minor fixes

* Minor fixes

* Minor fixes and add new shortcut

* MInor fixes

* Review fixes

* Minor fixes

* Code cleanup

* Minor fixes

* Uses Alt or Option key instead of shift-key

* Review fixes

* Review fixes

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-08-09 00:38:52 -07:00
Sivin VargheseandGitHub c7482696d4 fix: Remove text retained in confirm delete modal (#2775) 2021-08-09 12:07:42 +05:30
2035d24cb8 enhancement: Show close button for unread view (#2758)
* enhancement: Show close button for unread view

* Fixes issue with button spacing

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-08-07 11:56:40 +05:30
9c257578b0 fix: Fixes unread view blocking page scroll (#2727)
* fix: Fixes unread view blocking page scroll

* Update sdk.js

* Fixes the height issue for unread view

* Fix unread message position issue

* Code climate fixes

* Fixes height issue for large messages

* Fixes height issue on unread view

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-08-07 11:56:15 +05:30
Vishnu NarayananandGitHub b58ca21f0b docs: Update README to add question/support sub-section (#2764)
- add questions sub-section and mention discord
- improve formatting
2021-08-07 00:44:07 +05:30
Sojan JoseandGitHub edec74c389 chore: Fix Twilio send message error (#2761) 2021-08-06 13:34:20 +05:30
f934a5eb04 fix: Broken Docker Builds (#2755)
Co-authored-by: Pascal Jufer <paescuj@users.noreply.github.com>
2021-08-06 01:21:44 +05:30
RaikasandGitHub f477c5281f chore: Fix Finnish translations (#2753) 2021-08-05 10:24:07 +05:30
Muhsin KelothandGitHub 6265c1c907 fix: Add brand color in CSAT card component (#2756) 2021-08-05 01:20:01 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
e834b545ef chore: Bump tar from 6.1.0 to 6.1.3 (#2750)
Bumps [tar](https://github.com/npm/node-tar) from 6.1.0 to 6.1.3.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v6.1.0...v6.1.3)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-04 10:23:13 +05:30
Pascal JuferandGitHub c37966744f fix: Fix and rename pg_database_url.sh helper script (#2747)
- Fix and rename pg_database_url helper script
- Use single-quote and remove trailing whitespace
2021-08-03 22:56:55 +05:30
Sojan JoseandGitHub ab54d9c629 chore: Upgrade rails and ruby versions (#2400)
ruby version: 3.0.2
rails version: 6.1.4
2021-08-03 20:11:52 +05:30
Sivin VargheseandGitHub 7e960b7c72 feat: Add support for rich content for message in ongoing campaigns (#2577) 2021-08-03 19:38:51 +05:30
Muhsin KelothandGitHub 92c14fa87d feat: CSAT response collection public page (#2685) 2021-08-03 18:22:50 +05:30
Vishnu NarayananandGitHub 9b01b82cc7 docs: update chatwoot VDP guidelines (#2740) 2021-08-03 16:13:44 +05:30
Nithin David ThomasandGitHub 0475060245 enhancement: Updates icons to show last message type (#2743) 2021-08-03 12:13:24 +05:30
Pranav Raj SandGitHub faf104c1fe fix: Update tweet character count logic (#2709) 2021-08-02 16:07:30 +05:30
Pranav Raj SandGitHub d88e3e3596 fix: Resolve conversation with id instead of current conversation (#2731) 2021-08-02 13:11:07 +05:30
Muhsin KelothandGitHub 9f3f238cb5 chore: Show new account modal if user accounts are empty (#2448) 2021-08-02 08:54:53 +05:30
Pranav Raj SandGitHub 5b3339cd33 fix: Render line-breaks properly in messages (#2699) 2021-08-02 08:24:08 +05:30
Pranav Raj SandGitHub bfa00cc12d fix: Avoid flicker while updating the view with new messages (#2730) 2021-08-02 08:03:12 +05:30
Sojan JoseandGitHub e46aa1aa64 chore: Mark Facebook accounts for reconnection (#2405)
fixes: #2037
2021-08-01 18:15:39 +05:30
Sojan JoseandGitHub 2890339734 chore: Limit objects returned by conversation API (#2721) 2021-07-31 21:19:42 +05:30
Pranav Raj SandGitHub 915366c472 fix: Rename identity_hash to identifier_hash (#2726) 2021-07-29 20:11:21 +05:30
f2b5e328bb feat: Update agent and team multi-select with new multi-select dropdown (#2516)
* feat: Update agent/team multiselect styles

* Component name fixes

* Adds key control for our multiselect dropdown and component name spell fix

* Minor fixes

* Review fixes

* Minor fixes

* Minor fixes

* Review fixes

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2021-07-29 17:44:37 +05:30
Nithin David ThomasandGitHub 672e5874fb fix: Appending markdown as HTML into editor (#2720) 2021-07-29 11:53:28 +05:30
Nithin David ThomasandGitHub 8f30abb98b feat: Show links for custom attributes (#2723) 2021-07-28 21:36:35 +05:30
223385d134 fix: Specify external db with non-standard port (#2711)
POSTGRES_PORT was not taking effect if provided separately
instead of using DATABASE_URL. This adds support for using
databases running on non-standard ports.

#1145
#1147

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-07-28 19:36:51 +05:30
Muhsin KelothandGitHub 7662fdce47 feat: CSAT response public APIs (#2670) 2021-07-28 14:59:13 +05:30
a47ca9cf4b feat: Show e-mail meta data for conversations (#2708)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-07-28 14:43:44 +05:30
b44f9b792b chore: Block & throttle abusive requests (#2706)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-07-27 21:27:23 +05:30
SanjuandGitHub 359c3c8ccb Fix: type error trim of undefined#2595 (#2702) 2021-07-27 07:38:27 +05:30
sbreiler-workandGitHub d7da6fbfb5 fix: Make "Search Results" in PopOverSearch translateable (#2705) 2021-07-26 14:33:42 +05:30
Pranav Raj SandGitHub 7664006625 chore: Improve search, list performance of contact/conversation APIs (#2696) 2021-07-23 18:39:24 +05:30
Pranav Raj SandGitHub 6e1493501a feat: Add APIs for custom attribute definitions (#2689) 2021-07-23 17:04:33 +05:30
SanjuandGitHub 7e0937f3ed chore: Cypress test case for create label flow 2021-07-23 16:38:44 +05:30
d955d8e7dc feat: Ability to snooze conversations (#2682)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-07-23 15:24:07 +05:30
Vishnu NarayananandGitHub 4d45ac3bfc chore: Switch from addgroup to adduser (#2688) 2021-07-22 19:49:12 +05:30
ecdf977de7 Live chat widget preview #2441 (#2523)
* update widget preview on storybook

* removed default value for logo

* add online dot

* resolve PR comments

- split widget to head, body & footer
- updated reply time to a select box

* update spacing with variables

* update reply-time with i18

* update with spacing variables

* update padding with space variable

* resolved PR comments

* update background color

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2021-07-22 18:36:33 +05:30
Muhsin KelothandGitHub 6b6df7a70d fix: Disable "none" option from agent dropdown If agent is not selected (#2687) 2021-07-22 16:31:53 +05:30
Sojan JoseandGitHub a7ca55c080 chore: Change the conversation bot status to pending (#2677)
fixes: #2649
2021-07-21 22:02:43 +05:30
Sojan JoseandGitHub a0886d37bc chore: Expose widget config via an API (#2645)
Expose widget config via an API so that the UI could be detached from the rails Application.
2021-07-21 01:26:32 +05:30
Sojan caf8669db5 Merge branch 'release/1.18.1' 2021-07-20 00:51:08 +05:30
Sojan d1619bdc87 Bump version to 1.18.1 2021-07-20 00:50:38 +05:30
Sojan JoseandGitHub 217dd8a6f0 chore: Add assigned_count to conversation APIs (#2665) 2021-07-19 19:10:58 +05:30
Pranav Raj SandGitHub a235e82a02 fix: Update attribute name to conversationsCount (#2662) 2021-07-19 14:41:16 +05:30
Pranav Raj SandGitHub a2fca2edb8 fix: Fix HTML only email rendering (#2644) 2021-07-16 19:56:54 +05:30
Sojan 9de36f2b9e Merge branch 'release/1.18.0' 2021-07-16 00:08:30 +05:30
Sojan fa3cc40059 Bump version to 1.18.0 2021-07-16 00:07:18 +05:30
Sojan JoseandGitHub 3941c6f32b chore: Translation updates (#2639) 2021-07-16 00:04:09 +05:30
Sojan JoseandGitHub eda52930be chore: Add Telemetry (#2631)
ref: https://www.chatwoot.com/docs/self-hosted/telemetry
2021-07-15 23:58:54 +05:30
Pranav Raj SandGitHub 5aac2acf56 fix: Improve mail content parsing (#2638) 2021-07-15 22:50:32 +05:30
Muhsin KelothandGitHub 85ea56b765 fix: Disable sender tooltip and copy button in deleted messages (#2637) 2021-07-15 21:06:54 +05:30
Pranav Raj S 72069e45ef fix: Use mail.decoded as fallback for text content to fix char-rendering 2021-07-15 20:06:43 +05:30
Mrunal SelokarandGitHub e0535168a0 chore: Removing duplicate callback to create auth token (#2624)
Removed after create callback in user model to create a new access token. This is already being taken care of by AccessTokenable module.

Fixes #2620
2021-07-15 15:24:38 +05:30
Muhsin KelothandGitHub b56512eb56 fix: Hide deleted messages on widget side (#2614) 2021-07-15 14:27:37 +05:30
Muhsin KelothandGitHub cf785123a5 feat: One off campaign UI (#2621) 2021-07-15 13:31:43 +05:30
Pranav Raj SandGitHub aa7db90cd2 fix: Use Dompurify to strip style characters (#2632) 2021-07-15 12:54:31 +05:30
Sojan JoseandGitHub d7982a6ffd chore: Add assigned option to conversation finder API (#2630)
- Adds the ability to filter all the conversations which are assigned
- Add rack timeout gem
- Remove size attribute from Sidekiq config
2021-07-14 22:51:27 +05:30
Pranav Raj SandGitHub 3d18ec9e40 feat: Add date-range filter on CSAT Reports (#2622) 2021-07-14 20:15:57 +05:30
Sojan JoseandGitHub a5bc81b304 chore: Suppress the unnecessary CSRF warning (#2606)
Suppress the unnecessary CSRF warning
2021-07-14 18:40:24 +05:30
Sojan JoseandGitHub dfddf9cacc chore: one off SMS campaign APIs (#2589) 2021-07-14 12:24:09 +05:30
Pranav Raj SandGitHub cb44eb2964 feat: Add CSAT reports (#2608) 2021-07-14 10:20:06 +05:30
Pranav Raj SandGitHub b7806fc210 fix: Update styles to fix the image resolution on smaller devices (#2618) 2021-07-13 18:54:33 +05:30
f9b55944ad feat: Adds custom date range component for reports (#2602)
* feat: Adds custom date range for reports

* Review fixes

* Minor fixes

* Review fixes

* Use computed property

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-07-13 03:41:03 -07:00
dependabot[bot]andGitHub fae8466a6c chore: Bump addressable from 2.7.0 to 2.8.0 (#2610) 2021-07-13 13:58:54 +05:30
Nithin David ThomasandGitHub deb4513584 bug: Fixes alignment issue with deleted messages (#2613) 2021-07-13 12:00:29 +05:30
Muhsin KelothandGitHub 15085cfb98 feat: Conversation transcript in widget (#2549) 2021-07-13 11:31:21 +05:30
Siddharth RameshandGitHub fc4ef1595b chore: Twilio to individual(SMS/Whatsapp) channels (#2566) 2021-07-12 22:33:39 +05:30
Muhsin KelothandGitHub ba547b3f60 chore: Delete related notifications if a conversation is deleted (#2592) 2021-07-12 12:28:16 +05:30
Pranav Raj SandGitHub 5726447e47 fix: Unescape Slack incoming messages (#2604) 2021-07-09 17:45:02 +05:30
a9ccded62b feat: Creates custom date range picker component (#2597)
* feat: Adds custom date range in reports

* error fixes

* Creates new component for date range and adds stories

* Revert files

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-07-09 14:16:55 +05:30
Muhsin KelothandGitHub 64e69a85f8 chore: Update availability status everywhere if the user changes the status from the account menu (#2581)
* add agent mixin

* apply agent mixin in components

* review fixes

* fix specs
2021-07-09 13:20:54 +05:30
Muhsin KelothandGitHub 4a2195aeda chore: Disable delete option for deleted messages (#2600)
* disable delete option for deleted message

* review fixes
2021-07-09 12:34:09 +05:30
Nithin David ThomasandGitHub efd6f735dc fix: Align delete message menu on twitter bubble correctly (#2591)
* fix: Aligns delete message menu on twitter bubble correctly

* Fixes alignment issues
2021-07-09 10:53:28 +05:30
38cce3c1c0 chore: New translation updates (#2585)
* New translations contact.json (Vietnamese)

* New translations conversation.json (Vietnamese)

* New translations inboxMgmt.json (Vietnamese)

* New translations settings.json (Vietnamese)

* New translations en.json (Vietnamese)

* New translations inboxMgmt.json (Chinese Traditional)

* New translations contact.json (Chinese Traditional)

* New translations conversation.json (Chinese Traditional)

* New translations settings.json (Chinese Traditional)

* New translations en.json (Chinese Traditional)

* New translations en.yml (Chinese Simplified)

* New translations settings.json (Indonesian)

* New translations en.json (Indonesian)

* New translations contact.json (Persian)

* New translations conversation.json (Persian)

* New translations inboxMgmt.json (Persian)

* New translations inboxMgmt.json (Indonesian)

* New translations contact.json (Portuguese, Brazilian)

* New translations conversation.json (Portuguese, Brazilian)

* New translations inboxMgmt.json (Portuguese, Brazilian)

* New translations integrations.json (Portuguese, Brazilian)

* New translations settings.json (Portuguese, Brazilian)

* New translations en.json (Portuguese, Brazilian)

* New translations contact.json (Indonesian)

* New translations conversation.json (Indonesian)

* New translations en.json (Chinese Simplified)

* New translations devise.en.yml (Chinese Simplified)

* New translations inboxMgmt.json (Swedish)

* New translations settings.json (Swedish)

* New translations conversation.json (Swedish)

* New translations en.json (Swedish)

* New translations contact.json (Turkish)

* New translations conversation.json (Turkish)

* New translations contact.json (Swedish)

* New translations conversation.json (Slovak)

* New translations inboxMgmt.json (Slovak)

* New translations settings.json (Slovak)

* New translations en.json (Slovak)

* New translations inboxMgmt.json (Turkish)

* New translations en.json (Ukrainian)

* New translations contact.json (Chinese Simplified)

* New translations settings.json (Ukrainian)

* New translations conversation.json (Chinese Simplified)

* New translations inboxMgmt.json (Chinese Simplified)

* New translations settings.json (Chinese Simplified)

* New translations settings.json (Turkish)

* New translations en.json (Turkish)

* New translations contact.json (Ukrainian)

* New translations conversation.json (Ukrainian)

* New translations inboxMgmt.json (Ukrainian)

* New translations settings.json (Persian)

* New translations integrationApps.json (French)

* New translations en.json (Hebrew)

* New translations contact.json (Hebrew)

* New translations en.json (Nepali)

* New translations conversation.json (Hebrew)

* New translations inboxMgmt.json (Hebrew)

* New translations settings.json (Hebrew)

* New translations settings.json (Nepali)

* New translations csatMgmt.json (French)

* New translations contact.json (Thai)

* New translations conversation.json (Thai)

* New translations inboxMgmt.json (Thai)

* New translations settings.json (Thai)

* New translations en.json (Thai)

* New translations en.json (Tamil)

* New translations contact.json (Tamil)

* New translations en.json (Persian)

* New translations conversation.json (Tamil)

* New translations inboxMgmt.json (Tamil)

* New translations settings.json (Tamil)

* New translations settings.json (Malayalam)

* New translations en.json (Malayalam)

* New translations contact.json (Nepali)

* New translations conversation.json (Nepali)

* New translations inboxMgmt.json (Nepali)

* New translations inboxMgmt.json (Malayalam)

* New translations contact.json (Hindi)

* New translations conversation.json (Hindi)

* New translations inboxMgmt.json (Hindi)

* New translations settings.json (Hindi)

* New translations en.json (Hindi)

* New translations contact.json (Malayalam)

* New translations conversation.json (Malayalam)

* New translations contact.json (Slovak)

* New translations contact.json (Danish)

* New translations conversation.json (Danish)

* New translations inboxMgmt.json (Danish)

* New translations settings.json (Danish)

* New translations en.json (Danish)

* New translations inboxMgmt.json (Czech)

* New translations contact.json (Czech)

* New translations conversation.json (Czech)

* New translations settings.json (Czech)

* New translations en.json (Czech)

* New translations contact.json (German)

* New translations settings.json (Greek)

* New translations en.json (Greek)

* New translations contact.json (Finnish)

* New translations conversation.json (Finnish)

* New translations inboxMgmt.json (Finnish)

* New translations inboxMgmt.json (Greek)

* New translations conversation.json (German)

* New translations inboxMgmt.json (German)

* New translations integrations.json (German)

* New translations settings.json (German)

* New translations en.yml (German)

* New translations en.json (German)

* New translations contact.json (Greek)

* New translations conversation.json (Greek)

* New translations en.json (Catalan)

* New translations inboxMgmt.json (French)

* New translations integrations.json (French)

* New translations report.json (French)

* New translations settings.json (French)

* New translations en.yml (French)

* New translations conversation.json (French)

* New translations en.json (French)

* New translations labelsMgmt.json (French)

* New translations teamsSettings.json (French)

* New translations campaign.json (French)

* New translations contact.json (Spanish)

* New translations conversation.json (Spanish)

* New translations contact.json (French)

* New translations contact.json (Romanian)

* New translations conversation.json (Romanian)

* New translations inboxMgmt.json (Romanian)

* New translations settings.json (Romanian)

* New translations chatlist.json (French)

* New translations en.json (Romanian)

* New translations inboxMgmt.json (Spanish)

* New translations en.json (Arabic)

* New translations contact.json (Catalan)

* New translations settings.json (Arabic)

* New translations conversation.json (Catalan)

* New translations inboxMgmt.json (Catalan)

* New translations settings.json (Catalan)

* New translations settings.json (Spanish)

* New translations en.json (Spanish)

* New translations contact.json (Arabic)

* New translations conversation.json (Arabic)

* New translations inboxMgmt.json (Arabic)

* New translations settings.json (Norwegian)

* New translations en.json (Norwegian)

* New translations contact.json (Polish)

* New translations conversation.json (Polish)

* New translations inboxMgmt.json (Polish)

* New translations inboxMgmt.json (Norwegian)

* New translations conversation.json (Dutch)

* New translations inboxMgmt.json (Dutch)

* New translations settings.json (Dutch)

* New translations en.json (Dutch)

* New translations contact.json (Norwegian)

* New translations conversation.json (Norwegian)

* New translations settings.json (Finnish)

* New translations contact.json (Russian)

* New translations conversation.json (Russian)

* New translations inboxMgmt.json (Russian)

* New translations settings.json (Russian)

* New translations en.json (Russian)

* New translations en.json (Portuguese)

* New translations settings.json (Polish)

* New translations en.json (Polish)

* New translations contact.json (Portuguese)

* New translations conversation.json (Portuguese)

* New translations inboxMgmt.json (Portuguese)

* New translations settings.json (Portuguese)

* New translations contact.json (Dutch)

* New translations en.json (Hungarian)

* New translations contact.json (Italian)

* New translations conversation.json (Italian)

* New translations inboxMgmt.json (Italian)

* New translations settings.json (Italian)

* New translations en.json (Italian)

* New translations en.json (Finnish)

* New translations contact.json (Hungarian)

* New translations conversation.json (Hungarian)

* New translations inboxMgmt.json (Hungarian)

* New translations settings.json (Hungarian)

* New translations contact.json (Korean)

* New translations conversation.json (Korean)

* New translations inboxMgmt.json (Korean)

* New translations settings.json (Korean)

* New translations en.json (Korean)

* New translations en.json (Japanese)

* New translations contact.json (Japanese)

* New translations conversation.json (Japanese)

* New translations inboxMgmt.json (Japanese)

* New translations settings.json (Japanese)

* New translations en.yml (Portuguese, Brazilian)

* chore: revert key name

* Update zh_CN.yml

* New translations contact.json (Russian)

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-07-07 21:25:04 +05:30
e89e184d3b chore: Add loader for email and csat submit buttons (#2569)
* fix the loader issue in submit button

* review fixes

Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2021-07-07 11:24:08 +05:30
Pranav Raj SandGitHub 0d02142925 feat: Support messages along with the actions in Dialogflow response (#2579) 2021-07-07 10:04:48 +05:30
Sojan JoseandGitHub bbc47971d7 chore: Reduce steps to spin up Codespaces (#2576) 2021-07-06 21:21:40 +05:30
104ae8de2e feat: Create component to merge contacts (#2412)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-07-06 13:02:37 +05:30
Sojan JoseandGitHub e11b3c4f17 chore: Expose contact custom attributes in events (#2562)
Expose contact custom attributes in events so the external system can behave accordingly without triggering an additional API call.
2021-07-05 14:35:53 +05:30
0bd48129b9 feat: Add settings for audio alert notifications (#2415)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-07-05 12:01:54 +05:30
Muhsin KelothandGitHub 48127e00d7 feat: Enable/disable CSAT in web widget settings (#2531) 2021-07-05 11:07:02 +05:30
Sivin VargheseandGitHub abda86f9a7 bug: fixes typing indicator out of position in widget (#2551)
Fixes typing indicator out of position in the widget when the agent did not send the last message.
2021-07-02 15:28:32 +05:30
Muhsin KelothandGitHub 8341a43143 chore: Update CSAT submit action behaviour (#2556)
* update behaviour of CSAT submit

* code cleanup
2021-07-02 14:52:20 +05:30
f0f66c7da6 feat: Add ability to create a new conversation if the previous conversation is resolved (#2512)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-30 21:09:44 +05:30
Sivin VargheseandGitHub e6e9916fdb feat: Add drag and drop for images/files in the agent input box (#2546) 2021-06-30 20:32:17 +05:30
dd9d5e410c feat: Add CSAT response APIs (#2503)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-29 20:59:41 +05:30
Nithin David ThomasandGitHub 2e71006f9d feat: Add option to delete message content (#2532) 2021-06-29 20:06:40 +05:30
Pranav Raj SandGitHub 30832d8a34 feat: Add APIs to create custom views on the dashboard (#2498) 2021-06-29 19:29:57 +05:30
Sojan JoseandGitHub fa37f8e185 chore: Support Github Codespaces (#2510)
Note: Update the ruby version 2.7.3. For production Linux VM, install 2.7.3 and follow the upgrade steps as shown in https://www.chatwoot.com/docs/self-hosted/deployment/linux-vm#upgrading-to-a-newer-version-of-chatwoot
2021-06-29 19:18:10 +05:30
07a422219a chore: New translation updates (#2533)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-06-29 18:12:33 +05:30
Muhsin KelothandGitHub 8027c69c1c chore: Change the notification text for mention notification type (#2534) 2021-06-29 14:32:57 +05:30
Nithin David ThomasandGitHub 044b6872a4 feat: Add actions and API for deleting message via API (#2519) 2021-06-29 11:19:08 +05:30
Pranav Raj SandGitHub b705eb39e2 fix: Add missing Cache-Control headers in the production config (#2518) 2021-06-28 18:32:01 +05:30
Pranav Raj SandGitHub ac657e3bf9 fix: Remove style tags from email content (#2515) 2021-06-26 11:50:40 +05:30
Vishnu NarayananandGitHub bed1979986 fix: rvm gpg key issue (#2514)
sks-keyserver gpg pool is now deprecated due to GDPR issues and is
no longer reliable. Switching to use ubuntu keyserver for the time
being as this is the only server returning rvm maintainers gpg keys.
2021-06-25 21:19:08 +05:30
Sivin VargheseandGitHub 151bfbd1dd feat: Creates new component for multiselect. (#2446) 2021-06-25 17:41:24 +05:30
d840b7b13d feat: Adds storybook for search component. (#2444)
* feat: Adds storybook for search component.

* Review fixes

* Uses woot-label for conv-id

Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2021-06-25 17:14:37 +05:30
Pranav Raj SandGitHub bd1b17baf3 feat: Show the CSAT response to the agent (#2511) 2021-06-25 13:37:51 +05:30
b769fc87d0 chore: Adds storybook for woot textarea (#2451)
* chore: Adds storybook for woot textarea

* Review fixes

* Minor fixes

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2021-06-25 13:18:24 +05:30
Sivin VargheseandGitHub ad431c2008 chore: fixes gutter space between settings page content and sidebar (#2505)
* chore: fixes no gutter space between the settings page content and right content.

* Review fixes
2021-06-25 12:56:10 +05:30
dbddb1ece4 feat: Add CSAT response submit action (#2506)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-25 12:00:49 +05:30
Sivin VargheseandGitHub 2f9637bde5 feat: Adds time zone in Business Hours (#2497) 2021-06-24 17:47:56 +05:30
Sivin VargheseandGitHub ae53aa6cfb feat: Add inbox info to previous conversations (#2491) 2021-06-23 19:29:50 +05:30
Sojan JoseandGitHub cd11efea1d feat: Add CSAT Message Template Hooks (#2494) 2021-06-23 19:29:27 +05:30
Sojan JoseandGitHub 640e028bde chore: Add help-text for slack integration (#2409) 2021-06-23 11:52:06 +05:30
Sojan JoseandGitHub bd9bac75ad fix: Adds condition to handle base and mergee contact being same (#2485)
When an agent updates a contact email in the dashboard and the contact also update his email via the email collect box,
Merge action receives the same base and mergee contacts which could cause data corruption.
2021-06-22 15:57:48 +05:30
Muhsin KelothandGitHub 29b9915d3b feat: Add customer satisfaction component (#2456) 2021-06-22 13:01:19 +05:30
Sivin VargheseandGitHub a357b657a8 chore: Adds story for woot input (#2449) 2021-06-22 07:05:23 +05:30
Muhsin KelothandGitHub 3d748aa8d4 chore: Add contact note model (#2462) 2021-06-21 15:16:26 +05:30
Sivin VargheseandGitHub f809431074 chore: Update the design of the attachments preview (#2447) 2021-06-20 19:54:57 +05:30
Muhsin KelothandGitHub e34fe1c614 fix: Fix the sender tooltip getting undefined in bot messages (#2453) 2021-06-20 19:25:36 +05:30
e45abebe39 feat: Improve scrolling for last message on agent side (#2421)
* Improve chat widget scrolling

* refactor the class names to snake-case

* refactor the scrollTop calculations to a helper

* Add tests for scrollTopCalculationHelper

Co-authored-by: Nithin David Thomas <webofnithin@gmail.com>
Co-authored-by: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com>
2021-06-18 20:12:43 +05:30
6c49e58ff8 feat: Add contact label filter (#2454)
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2021-06-18 20:08:58 +05:30
Sojan JoseandGitHub 50e4bb3e63 chore: Add CSAT survey toggle attribute to Inboxes (#2455)
ref: #1890
2021-06-18 15:55:48 +05:30
Nithin David ThomasandGitHub 6cdefb19a2 chore: Add multiselect support in stories (#2427) 2021-06-18 14:29:43 +05:30
Sojan 0a96ded5bd Merge branch 'release/1.17.1' 2021-06-16 00:48:15 +05:30
Sojan 6b997c6804 Bump version to 1.17.1 2021-06-16 00:47:21 +05:30
Sojan JoseandGitHub af8223545e chore: Swagger documentation for public APIs (#2417) 2021-06-16 00:14:09 +05:30
Pranav Raj SandGitHub 2b9c93a1b3 chore: Disallow unread/campaign view if widget is active (#2432) 2021-06-15 11:35:31 -07:00
Sojan 2d2382a3f8 Merge branch 'release/1.17.0' 2021-06-15 23:21:02 +05:30
Sojan a0331b40d4 Bump version to 1.17.0 2021-06-15 23:20:28 +05:30
7a7f6234b1 chore: Enable Polish (pl), update translations (#2403)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-15 22:15:18 +05:30
Muhsin KelothandGitHub e41957ae02 fix: Campaign message is hiding the conversation view after opening the widget (#2428)
* Fix the widget triggered- campain collision

* fix spelling mistakes
2021-06-15 08:53:16 -07:00
fb2f3ff89f feat: Create campaign conversation only if user interacts with the bubble (#2335)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-15 20:09:42 +05:30
Sojan JoseandGitHub 853db60f8e feat: Add Public APIs for API Channel (#2375) 2021-06-15 20:09:17 +05:30
0f377da109 feat: Add an option to delete campaigns (#2402)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-15 14:14:59 +05:30
Nithin David ThomasandGitHub a56aa5656d chore: Fixes contact panel scroll issue (#2424) 2021-06-14 16:48:33 +05:30
Nithin David ThomasandGitHub fe3f1c3a40 Chore: Update style for new message buton (#2423)
- Changes button style for new message and edit contact in contact page side panel
2021-06-14 10:37:01 +05:30
d21c1c773b feat: Ability to add label for contact page (#2350)
* feat: Ability to add label for contact page

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
Co-authored-by: Nithin David Thomas <webofnithin@gmail.com>
2021-06-14 10:36:00 +05:30
fe2af370e0 Feat: Show notes panel on crm page (#2320)
* Feat: Show notes panel on CRM page

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-06-14 09:49:17 +05:30
Nithin David ThomasandGitHub 75d05e55ae Chore: Refactors sidebar styles (#2416)
* Chore: Refactors sidebar styles

* Removes unused i18n
2021-06-11 17:11:13 +05:30
Sivin VargheseandGitHub e9fa9e5eff feat: Add assign to me button next to assign agents. (#2414) 2021-06-11 15:38:46 +05:30
534acfbf96 chore: Ensure privilege validations for API endpoints (#2224)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-11 11:44:31 +05:30
Muhsin KelothandGitHub 5a95c74bf6 fix: Add missing translation in inbox settings page (#2411) 2021-06-10 03:41:55 -07:00
Muhsin KelothandGitHub b9e40d1452 feat: Add an option to enable/disable email collect box (#2399)
* add email collect enabled migration

* migrations

* expose enable_email_collect field

* add select for email collect

* add enable_email condition on new conversation

* add default value true for enable_email_collect

* add specs for email collect enabled

* rereun migration

* code cleanup

* update token life span to 2 months

* revert uuid column
2021-06-10 02:34:03 -07:00
Sivin VargheseandGitHub 8ca63f0b79 chore: Cleanup page-top-bar style conflicts (#2407)
* chore: Class name cleanup page-top-bar.

* prettier spacing fixes

* Review fixes and adds storybook

* Circleci fixes
2021-06-10 09:35:15 +05:30
Muhsin KelothandGitHub 174886671d feat: Add the ability to edit inbox name (#2406) 2021-06-09 21:26:23 +05:30
Nithin David ThomasandGitHub 77d4f86ec9 chore: Clean up contact note styles (#2404) 2021-06-09 18:25:05 +05:30
f79e489a0a chore: Use button component in ReplyBox
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2021-06-09 14:01:43 +05:30
8a0afb912c chore: Add validation error for label create/edit modal (#2381)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-09 13:57:42 +05:30
1bf7227843 chore: Fix emails being sent with the wrong translations (#2236)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-08 22:45:01 +05:30
67ce6f5704 feat: Add regex validation on form message inputs (#2317)
Co-authored-by: Nithin David Thomas <webofnithin@gmail.com>
Co-authored-by: Sojan <sojan@pepalo.com>
2021-06-08 16:32:01 +05:30
0a087c95fd chore: Message API improvements (#2396)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-08 01:11:06 +05:30
Pranav Raj SandGitHub 1ebab21cfa chore: Configure API channel name and thumbnail (#2398) 2021-06-08 00:22:36 +05:30
9e56565a30 chore: Add status param in conversation APIs (#2394)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-07 20:04:31 +05:30
467b45b427 feat: Improved password security policy (#2345)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-07 17:26:08 +05:30
Sojan JoseandGitHub d1b3c7b0c2 chore: Update Facebook Messenger gem (#2342) 2021-06-07 13:58:01 +05:30
Sojan JoseandGitHub ae3cbf4f79 chore: Expose contact identifier in API (#2391) 2021-06-07 11:46:47 +05:30
Pranav Raj SandGitHub 1155b49e42 fix: Add swagger definition for platform_user_id (#2385) 2021-06-06 21:18:47 +05:30
94a83ea995 feat: Add an option to edit webhook URL (#2316)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-06 16:59:47 +05:30
Muhsin KelothandGitHub 14b51e108a feat: Add Integration hooks UI (#2301) 2021-06-06 16:59:05 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c6487877bf chore: Bump ws from 6.2.1 to 6.2.2 (#2382)
Bumps [ws](https://github.com/websockets/ws) from 6.2.1 to 6.2.2.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/commits)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-05 18:58:59 +05:30
c028f30f82 chore: Add a different color for messages from bot (#2374)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-04 21:54:06 +05:30
Muhsin KelothandGitHub 8a283a7783 feat: Ask to confirm with name before inbox/team deletion (#2370) 2021-06-04 13:17:44 +05:30
Nithin David ThomasandGitHub 562a65a70d chore: Cleanup unused components (#2379) 2021-06-04 12:54:16 +05:30
Nithin David ThomasandGitHub 58846e7ad8 chore: Add new color shade + tint for violet (#2373) 2021-06-03 23:21:39 +05:30
f731002b70 fix: Retain focus after sending message in rich content editor (#2372)
Co-authored-by: Nithin David Thomas <webofnithin@gmail.com>
2021-06-03 23:20:30 +05:30
b1228f805e feat: Creates event timeline card component for CRM (#2291)
* feat: Creates event timeline card component for CRM


Co-authored-by: Nithin David Thomas <webofnithin@gmail.com>
2021-06-02 23:09:43 +05:30
9a9bcf8153 feat: Create add reminder component for CRM (#2264)
* feat: Creates add reminder component for CRM

Co-authored-by: Nithin David Thomas <webofnithin@gmail.com>
2021-06-02 22:53:13 +05:30
2fca87e3e7 Feat: Creates reminder list component for CRM (#2258)
* Feat: Creates reminder list component for CRM


Co-authored-by: Nithin David Thomas <webofnithin@gmail.com>
2021-06-02 22:48:09 +05:30
Pranav Raj SandGitHub 75fe851345 fix: Update the translation key for Custom Attributes (#2364) 2021-06-02 21:29:53 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Pranav Raj S
b8aaf6c90d chore: Bump dns-packet from 1.3.1 to 1.3.4 (#2346)
Bumps [dns-packet](https://github.com/mafintosh/dns-packet) from 1.3.1 to 1.3.4.
- [Release notes](https://github.com/mafintosh/dns-packet/releases)
- [Changelog](https://github.com/mafintosh/dns-packet/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mafintosh/dns-packet/compare/v1.3.1...v1.3.4)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
2021-06-02 21:21:20 +05:30
49be9e21c3 chore: Universal Linking for Android (#2324)
* android assetlinks.json config

* try renaming html to json

* update env example

* chore: fix styling

* chore: styling part 2

* test: add spec for android assetlinks

* minor fixes

* minor fixes

* remove android sha256 value from env example

* add default sh256 value

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2021-06-02 08:46:45 -07:00
b0b4d9d6f5 enhancement: Current password confirmation in change password (#2108)
* add current password field in change password form

* locale changes

* chore: update password API

* chore: rubocop fixes

* replace currentPassword with current_password

* code cleanup

* replace input with woot-input

* code cleanup

Co-authored-by: Sojan <sojan@pepalo.com>
2021-06-02 05:22:24 -07:00
Nithin David ThomasandGitHub 2c42e70637 feat: Add support for canned response command anywhere on rich text editor (#2356) 2021-06-02 10:20:40 +05:30
Sojan JoseandGitHub 22965be6dc feat: Add AgentBot APIs (#2323) 2021-06-01 22:34:25 +05:30
Sojan JoseandGitHub 9d16e52e33 chore: Add Swagger docs for Platform APIs (#2349) 2021-05-31 10:58:43 +05:30
Sivin VargheseandGitHub cc75a668cb feat: Create section header component (#2296) 2021-05-31 10:07:07 +05:30
Pranav Raj SandGitHub 25ba852b68 chore: Adjust Chatwoot Config to deploy frontend as a separate app (#2347) 2021-05-28 19:21:16 +05:30
Sojan JoseandGitHub 3b39eb3e33 chore: ability to run Chatwoot as API only server (#2344)
- Ability to run chatwoot as an API only server
- Removes action cable testing gem since it is merged to rails 6
2021-05-27 20:07:21 +05:30
Nithin David ThomasandGitHub 9c555e70c9 fix: Uses label component for add label button (#2337)
* fix: Uses label component for add label button

* Use button instead of span
2021-05-27 08:24:29 +05:30
Sojan JoseandGitHub 9ffdb0ec70 chore: Add select field example to WootMessageSeeder (#2338)
Fixes: #2076
2021-05-25 21:41:53 +05:30
Pranav Raj SandGitHub 12c68e8a3c chore: Upgrade @sentry/vue to 6.4.1 (#2332) 2021-05-25 14:10:09 +05:30
Muhsin KelothandGitHub cfdf4a12c8 chore: Add missing frontend specs (#2329)
* complete dshboard api specs

* code cleanup

* add conversation mixin spec

* add isadmin mixin spec

* add agent details component spec

* add notification badge spec

* spec for thumbnail exist in agent details

* fix the deprecation warnings

* add agent details spec

* add account selector specs

* code cleanup

* refactor contact spec

* review fixes

* review fixes

* add shared spec helper

* update api spec helper

* review fixes
2021-05-25 01:30:21 -07:00
Nithin David ThomasandGitHub 652d988993 fix: Fixes email overflow issue in conversation. (#2331) 2021-05-25 12:53:00 +05:30
Muhsin KelothandGitHub 62d19911be chore: Add chatwoot utils package (#2307)
* add chatwoot utils package

* remove color helper

* replace contrasting text color  with chatwoot util
2021-05-24 00:13:03 -07:00
Sojan JoseandGitHub 58dd6d37e0 chore: Update language translations (#2321) 2021-05-21 23:52:38 +05:30
Nithin David ThomasandGitHub ac2c5c93b9 chore: Update webhook delete button styles(#2322)
* Chore: Fixes style issue of webhook button

* Review fixes
2021-05-21 07:19:57 -07:00
26ba8e6ff7 feat: Create custom attributes for a contact from CRM (#2299)
* feat: Creates cutom attributes for a contact from CRM

* Review fixes

* Change inline forms edit icon size

* Review fixes

* Fix validation labels color

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2021-05-21 19:22:47 +05:30
Sojan JoseandGitHub 64718eb879 fix: Broken Docker production config (#2319)
fixes: #2110
2021-05-21 18:55:42 +05:30
Sojan JoseandGitHub bb1c028926 fix: Slack integration redirect url missing the client ID (#2309)
Fixes: #2304
2021-05-21 00:03:09 +05:30
Nithin David ThomasandGitHub 2a492b4162 Chore: Refactors view note component (#2310) 2021-05-20 23:41:15 +05:30
Nithin David ThomasandGitHub 047617713e Chore: Refactor add note to use foundation card classes (#2308) 2021-05-20 23:08:05 +05:30
Sojan JoseandGitHub 46356d0bf9 docs: Add documentation for integration APIs (#2300) 2021-05-20 20:46:45 +05:30
Nithin David ThomasandGitHub c681e8a01b chore: Refactor button styles (#2259) 2021-05-20 13:51:46 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Sojan Jose
af8e681f2a chore: Bump puma from 4.3.6 to 4.3.8 (#2294)
Bumps [puma](https://github.com/puma/puma) from 4.3.6 to 4.3.8.
- [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/v4.3.6...v4.3.8)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2021-05-19 17:14:15 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Sojan Jose
71d1f229f0 chore: Bump nokogiri from 1.11.3 to 1.11.4 (#2293)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.11.3 to 1.11.4.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.11.3...v1.11.4)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sojan Jose <sojan@pepalo.com>
2021-05-19 16:37:05 +05:30
Sojan 090b5f46e8 Merge branch 'release/1.16.2' 2021-05-18 16:05:18 +05:30
Sojan 10c18aa7f1 Bump version to 1.16.2 2021-05-18 16:04:26 +05:30
20a0d381a7 fix: Resolve infinite loop with campaign API call (#2290)
Co-authored-by: Muhsin <muhsinkeramam@gmail.com>
2021-05-18 12:15:23 +05:30
2205 changed files with 106706 additions and 15861 deletions
+3
View File
@@ -0,0 +1,3 @@
---
ignore:
- CVE-2021-41098 # https://github.com/chatwoot/chatwoot/issues/3097 (update once azure blob storage is updated)
+17 -5
View File
@@ -7,7 +7,7 @@ defaults: &defaults
working_directory: ~/build
docker:
# specify the version you desire here
- image: circleci/ruby:2.7.2-node-browsers
- image: cimg/ruby:3.0.2-browsers
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
@@ -40,20 +40,20 @@ jobs:
- restore_cache:
keys:
- chatwoot-bundle-{{ checksum "Gemfile.lock" }}
- chatwoot-bundle-{{ .Environment.CACHE_VERSION }}-{{ checksum "Gemfile.lock" }}
- chatwoot-bundle
- run: bundle install --frozen --path ~/.bundle
- save_cache:
paths:
- ~/.bundle
key: chatwoot-bundle-{{ checksum "Gemfile.lock" }}
key: chatwoot-bundle-{{ .Environment.CACHE_VERSION }}-{{ checksum "Gemfile.lock" }}
# Only necessary if app uses webpacker or yarn in some other way
- restore_cache:
keys:
- chatwoot-yarn-{{ checksum "yarn.lock" }}
- chatwoot-yarn-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }}
- chatwoot-yarn-
- run:
@@ -62,7 +62,7 @@ jobs:
# Store yarn / webpacker cache
- save_cache:
key: chatwoot-yarn-{{ checksum "yarn.lock" }}
key: chatwoot-yarn-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
@@ -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
+30 -19
View File
@@ -1,4 +1,4 @@
version: "2"
version: '2'
plugins:
rubocop:
enabled: false
@@ -14,22 +14,33 @@ plugins:
checks:
similar-code:
enabled: false
method-count:
enabled: true
config:
threshold: 32
file-lines:
enabled: true
config:
threshold: 300
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/**/*"
- "**/*.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'
+4 -47
View File
@@ -1,51 +1,8 @@
# pre-build stage
ARG VARIANT=2.7
FROM mcr.microsoft.com/vscode/devcontainers/ruby:${VARIANT}
# Update args in docker-compose.yaml to set the UID/GID of the "vscode" user.
ARG USER_UID=1000
ARG USER_GID=$USER_UID
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
groupmod --gid $USER_GID vscode \
&& usermod --uid $USER_UID --gid $USER_GID vscode \
&& chmod -R $USER_UID:$USER_GID /home/vscode; \
fi
# [Option] Install Node.js
ARG INSTALL_NODE="true"
ARG NODE_VERSION="lts/*"
RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
# tmux is for overmind
# TODO : install foreman in future
# packages: postgresql-server-dev-all
# may be postgres in same machine
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends \
libssl-dev \
tar \
tzdata \
postgresql-client \
yarn \
git \
imagemagick \
tmux \
zsh
# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
# The below image is created out of the Dockerfile.base
# It has the dependencies already installed so that codespace will boot up fast
FROM ghcr.io/chatwoot/chatwoot_codespace:latest
# Do the set up required for chatwoot app
WORKDIR /workspace
COPY . /workspace
# TODO: figure out installing rvm
# RUN rvm install
COPY Gemfile Gemfile.lock ./
RUN gem install bundler
RUN bundle install
COPY package.json yarn.lock ./
RUN yarn install
RUN yarn && gem install bundler && bundle install
+45
View File
@@ -0,0 +1,45 @@
# pre-build stage
ARG VARIANT=3
FROM mcr.microsoft.com/vscode/devcontainers/ruby:${VARIANT}
# Update args in docker-compose.yaml to set the UID/GID of the "vscode" user.
ARG USER_UID=1000
ARG USER_GID=$USER_UID
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
groupmod --gid $USER_GID vscode \
&& usermod --uid $USER_UID --gid $USER_GID vscode \
&& chmod -R $USER_UID:$USER_GID /home/vscode; \
fi
# [Option] Install Node.js
ARG INSTALL_NODE="true"
ARG NODE_VERSION="lts/*"
RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends \
libssl-dev \
tar \
tzdata \
postgresql-client \
yarn \
git \
imagemagick \
tmux \
zsh
# Install overmind
RUN curl -L https://github.com/DarthSim/overmind/releases/download/v2.1.0/overmind-v2.1.0-linux-amd64.gz > overmind.gz \
&& gunzip overmind.gz \
&& sudo mv overmind /usr/local/bin \
&& chmod +x /usr/local/bin/overmind
# Do the set up required for chatwoot app
WORKDIR /workspace
COPY . /workspace
RUN yarn
COPY Gemfile Gemfile.lock ./
RUN gem install bundler && bundle install
+15 -9
View File
@@ -12,22 +12,28 @@
"extensions": [
"rebornix.Ruby",
"misogi.ruby-rubocop",
"wingrunr21.vscode-ruby"
"wingrunr21.vscode-ruby",
"davidpallinder.rails-test-runner",
"eamodio.gitlens",
"github.copilot",
"mrmlnc.vscode-duplicate"
],
// TODO: figure whether we can get all this ports work properly
// 3000 rails
// 3035 webpacker
// 5432 postgres
// 6379 redis
// 1025,8025 mailhog
"forwardPorts": [5432, 6379, 1025, 8025],
"forwardPorts": [8025],
//your application may need to listen on all interfaces (0.0.0.0) not just localhost for it to be available externally. Defaults to []
"appPort": [3000, 3035],
// Use 'postCreateCommand' to run commands after the container is created.
// #TODO: can we move logic of copy env file into dockerfile ?
"postCreateCommand": "cp .env.example .env",
"postCreateCommand": ".devcontainer/scripts/setup.sh && bundle exec rake db:chatwoot_prepare && yarn",
"portsAttributes": {
"3000": {
"label": "Rails Server"
},
"8025": {
"label": "Mailhog UI"
}
},
}
+2 -2
View File
@@ -10,8 +10,8 @@ services:
context: ..
dockerfile: .devcontainer/Dockerfile
args:
# Update 'VARIANT' to pick a Ruby version: 2, 2.7, 2.6, 2.5
VARIANT: 2.7
# Update 'VARIANT' to pick a Ruby version: https://github.com/microsoft/vscode-dev-containers/tree/main/containers/ruby
VARIANT: 3
# [Choice] Install Node.js
INSTALL_NODE: "true"
NODE_VERSION: "lts/*"
+8
View File
@@ -0,0 +1,8 @@
cp .env.example .env
sed -i -e '/REDIS_URL/ s/=.*/=redis:\/\/localhost:6379/' .env
sed -i -e '/POSTGRES_HOST/ s/=.*/=localhost/' .env
sed -i -e '/SMTP_ADDRESS/ s/=.*/=localhost/' .env
sed -i -e "/FRONTEND_URL/ s/=.*/=https:\/\/$CODESPACE_NAME-3000.githubpreview.dev/" .env
sed -i -e "/WEBPACKER_DEV_SERVER_PUBLIC/ s/=.*/=https:\/\/$CODESPACE_NAME-3035.githubpreview.dev/" .env
# uncomment the webpacker env variable
sed -i -e '/WEBPACKER_DEV_SERVER_PUBLIC/s/^# //' .env
+46 -4
View File
@@ -41,7 +41,7 @@ RAILS_MAX_THREADS=5
# The email from which all outgoing emails are sent
# could user either `email@yourdomain.com` or `BrandName <email@yourdomain.com>`
MAILER_SENDER_EMAIL=Chatwoot <accounts@chatwoot.com>
MAILER_SENDER_EMAIL="Chatwoot <accounts@chatwoot.com>"
#SMTP domain key is set up for HELO checking
@@ -57,6 +57,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
@@ -85,8 +88,6 @@ AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
# Sentry
SENTRY_DSN=
# Log settings
# Disable if you want to write logs to a file
@@ -102,6 +103,9 @@ FB_VERIFY_TOKEN=
FB_APP_SECRET=
FB_APP_ID=
# https://developers.facebook.com/docs/messenger-platform/instagram/get-started#app-dashboard
IG_VERIFY_TOKEN=
# Twitter
# documentation: https://www.chatwoot.com/docs/twitter-app-setup
TWITTER_APP_ID=
@@ -115,7 +119,11 @@ SLACK_CLIENT_SECRET=
### Change this env variable only if you are using a custom build mobile app
## Mobile app env variables
IOS_APP_ID=6C953F3RX2.com.chatwoot.app
IOS_APP_ID=L7YLMN4634.com.chatwoot.app
ANDROID_BUNDLE_ID=com.chatwoot.app
# https://developers.google.com/android/guides/client-auth (use keytool to print the fingerprint in the first section)
ANDROID_SHA256_CERT_FINGERPRINT=AC:73:8E:DE:EB:56:EA:CC:10:87:02:A7:65:37:7B:38:D4:5D:D4:53:F8:3B:FB:D3:C6:28:64:1D:AA:08:1E:D8
### Smart App Banner
@@ -135,6 +143,25 @@ IOS_APP_ID=6C953F3RX2.com.chatwoot.app
USE_INBOX_AVATAR_FOR_BOT=true
### APM and Error Monitoring configurations
## Sentry
# SENTRY_DSN=
## Scout
## https://scoutapm.com/docs/ruby/configuration
# SCOUT_KEY=YOURKEY
# SCOUT_NAME=YOURAPPNAME (Production)
# SCOUT_MONITOR=true
## NewRelic
# https://docs.newrelic.com/docs/agents/ruby-agent/configuration/ruby-agent-configuration/
# NEW_RELIC_LICENSE_KEY=
## Datadog
## https://github.com/DataDog/dd-trace-rb/blob/master/docs/GettingStarted.md#environment-variables
# DD_TRACE_AGENT_URL=
## IP look up configuration
## ref https://github.com/alexreisner/geocoder/blob/master/README_API_GUIDE.md
@@ -143,6 +170,21 @@ USE_INBOX_AVATAR_FOR_BOT=true
# maxmindb api key to use geoip2 service
# IP_LOOKUP_API_KEY=
## Rack Attack configuration
## To prevent and throttle abusive requests
# ENABLE_RACK_ATTACK=true
## Running chatwoot as an API only server
## setting this value to true will disable the frontend dashboard endpoints
# CW_API_ONLY_SERVER=false
## Development Only Config
# if you want to use letter_opener for local emails
# LETTER_OPENER=true
# meant to be used in github codespaces
# WEBPACKER_DEV_SERVER_PUBLIC=
# If you want to use official mobile app,
# the notifications would be relayed via a Chatwoot server
ENABLE_PUSH_RELAY_SERVER=true
+3
View File
@@ -28,6 +28,9 @@ module.exports = {
}],
'vue/html-self-closing': 'off',
"vue/no-v-html": 'off',
'vue/singleline-html-element-content-newline': 'warn',
'vue/require-default-prop': 'warn',
'vue/require-prop-types': 'warn',
'import/extensions': ['off']
},
@@ -0,0 +1,23 @@
name: Publish Codespace Base Image
on:
workflow_dispatch:
jobs:
publish-code-space-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build the Codespace Base Image
run: |
docker build . -t ghcr.io/chatwoot/chatwoot_codespace:latest -f .devcontainer/Dockerfile.base
docker push ghcr.io/chatwoot/chatwoot_codespace:latest
+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
+1 -1
View File
@@ -1 +1 @@
12.16.1
14.17.4
+44 -5
View File
@@ -13,6 +13,8 @@ Metrics/ClassLength:
- 'app/models/conversation.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'
RSpec/ExampleLength:
Max: 25
Style/Documentation:
@@ -24,12 +26,13 @@ Style/FrozenStringLiteralComment:
Style/SymbolArray:
Enabled: false
Style/OptionalBooleanParameter:
Exclude:
Exclude:
- 'app/services/email_templates/db_resolver_service.rb'
- 'app/dispatchers/dispatcher.rb'
Style/GlobalVars:
Exclude:
- 'config/initializers/redis.rb'
- 'config/initializers/01_redis.rb'
- 'config/initializers/rack_attack.rb'
- 'lib/redis/alfred.rb'
- 'lib/global_config.rb'
Style/ClassVars:
@@ -38,12 +41,23 @@ Style/ClassVars:
Lint/MissingSuper:
Exclude:
- 'app/drops/base_drop.rb'
Lint/SymbolConversion:
Enabled: false
Lint/EmptyBlock:
Exclude:
- 'app/views/api/v1/accounts/conversations/toggle_status.json.jbuilder'
Lint/OrAssignmentToConstant:
Exclude:
- 'lib/redis/config.rb'
Metrics/BlockLength:
Exclude:
- spec/**/*
- '**/routes.rb'
- 'config/environments/*'
- db/schema.rb
Metrics/ModuleLength:
Exclude:
- lib/seeders/message_seeder.rb
Rails/ApplicationController:
Exclude:
- 'app/controllers/api/v1/widget/messages_controller.rb'
@@ -51,6 +65,12 @@ Rails/ApplicationController:
- 'app/controllers/widget_tests_controller.rb'
- 'app/controllers/widgets_controller.rb'
- 'app/controllers/platform_controller.rb'
- 'app/controllers/public_controller.rb'
- 'app/controllers/survey/responses_controller.rb'
Rails/EnvironmentVariableAccess:
Enabled: false
Rails/TimeZoneAssignment:
Enabled: false
Style/ClassAndModuleChildren:
EnforcedStyle: compact
Exclude:
@@ -60,9 +80,14 @@ RSpec/NestedGroups:
Max: 4
RSpec/MessageSpies:
Enabled: false
RSpec/StubbedMock:
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'
@@ -73,10 +98,12 @@ Style/GuardClause:
- 'app/models/message.rb'
- 'db/migrate/20190819005836_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb'
Metrics/AbcSize:
Exclude:
Exclude:
- 'app/controllers/concerns/auth_helper.rb'
- '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:
@@ -102,19 +129,24 @@ Rails/BulkChangeTable:
- 'db/migrate/20191027054756_create_contact_inboxes.rb'
- 'db/migrate/20191130164019_add_template_type_to_messages.rb'
- 'db/migrate/20210425093724_convert_integration_hook_settings_field.rb'
Rails/UniqueValidationWithoutIndex:
Rails/UniqueValidationWithoutIndex:
Exclude:
- 'app/models/channel/twitter_profile.rb'
- 'app/models/webhook.rb'
- 'app/models/contact.rb'
- 'app/models/integrations/hook.rb'
Rails/RenderInline:
Exclude:
- 'app/controllers/swagger_controller.rb'
Performance/CollectionLiteralInLoop:
Exclude:
- 'db/migrate/20210315101919_enable_email_channel.rb'
RSpec/NamedSubject:
Enabled: false
# we should bring this down
RSpec/MultipleMemoizedHelpers:
Max: 12
AllCops:
NewCops: enable
Exclude:
@@ -129,4 +161,11 @@ AllCops:
- 'tmp/**/*'
- 'storage/**/*'
- 'db/migrate/20200225162150_init_schema.rb'
- 'config/initializers/azure_storage_service_patch.rb'
- 'db/migrate/20210611180222_create_active_storage_variant_records.active_storage.rb'
- 'db/migrate/20210611180221_add_service_name_to_active_storage_blobs.active_storage.rb'
- db/migrate/20200309213132_add_account_id_to_agent_bot_inboxes.rb
- db/migrate/20200331095710_add_identifier_to_contact.rb
- db/migrate/20200429082655_add_medium_to_twilio_sms.rb
- db/migrate/20200503151130_add_account_feature_flag.rb
- db/migrate/20200927135222_add_last_activity_at_to_conversation.rb
- db/migrate/20210306170117_add_last_activity_at_to_contacts.rb
+1 -1
View File
@@ -1 +1 @@
2.7.2
3.0.2
+4
View File
@@ -2,6 +2,8 @@ import { addDecorator } from '@storybook/vue';
import Vue from 'vue';
import Vuex from 'vuex';
import VueI18n from 'vue-i18n';
import Vuelidate from 'vuelidate';
import Multiselect from 'vue-multiselect';
import WootUiKit from '../app/javascript/dashboard/components';
import i18n from '../app/javascript/dashboard/i18n';
@@ -9,8 +11,10 @@ import i18n from '../app/javascript/dashboard/i18n';
import '../app/javascript/dashboard/assets/scss/storybook.scss';
Vue.use(VueI18n);
Vue.use(Vuelidate);
Vue.use(WootUiKit);
Vue.use(Vuex);
Vue.component('multiselect', Multiselect);
const store = new Vuex.Store({});
const i18nConfig = new VueI18n({
+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.
+37 -13
View File
@@ -1,6 +1,6 @@
source 'https://rubygems.org'
ruby '2.7.2'
ruby '3.0.2'
##-- base gems for rails --##
gem 'rack-cors', require: 'rack/cors'
@@ -33,19 +33,22 @@ gem 'liquid'
gem 'commonmarker'
# Validate Data against JSON Schema
gem 'json_schemer'
# Rack middleware for blocking & throttling abusive requests
gem 'rack-attack'
# a utility tool for streaming, flexible and safe downloading of remote files
gem 'down', '~> 5.0'
##-- for active storage --##
gem 'aws-sdk-s3', require: false
gem 'azure-storage-blob', require: false
gem 'google-cloud-storage', require: false
gem 'mini_magick'
gem 'image_processing'
##-- gems for database --#
gem 'groupdate'
gem 'pg'
gem 'redis'
gem 'redis-namespace'
gem 'redis-rack-cache'
# super fast record imports in bulk
gem 'activerecord-import'
@@ -59,6 +62,7 @@ gem 'barnes'
##--- gems for authentication & authorization ---##
gem 'devise'
gem 'devise-secure_password', '~> 2.0', git: 'https://github.com/chatwoot/devise-secure_password'
gem 'devise_token_auth'
# authorization
gem 'jwt'
@@ -72,8 +76,8 @@ gem 'wisper', '2.0.0'
##--- gems for channels ---##
# TODO: bump up gem to 2.0
gem 'facebook-messenger', '1.5.0'
gem 'telegram-bot-ruby'
gem 'facebook-messenger'
gem 'line-bot-api'
gem 'twilio-ruby', '~> 5.32.0'
# twitty will handle subscription of twitter account events
# gem 'twitty', git: 'https://github.com/chatwoot/twitty'
@@ -88,8 +92,14 @@ gem 'google-cloud-dialogflow'
##--- gems for debugging and error reporting ---##
# static analysis
gem 'brakeman'
##-- apm and error monitoring ---#
gem 'ddtrace'
gem 'newrelic_rpm'
gem 'scout_apm'
gem 'sentry-raven'
gem 'sentry-rails'
gem 'sentry-ruby'
gem 'sentry-sidekiq'
##-- background job processing --##
gem 'sidekiq'
@@ -111,6 +121,15 @@ gem 'hairtrigger'
gem 'procore-sift'
# parse email
gem 'email_reply_trimmer'
gem 'html2text'
group :production, :staging do
# we dont want request timing out in development while using byebug
gem 'rack-timeout'
end
group :development do
gem 'annotate'
gem 'bullet'
@@ -118,7 +137,7 @@ group :development do
gem 'web-console'
# used in swagger build
gem 'json_refs', git: 'https://github.com/tzmfreedom/json_refs', ref: '131b11294fd6af9c428171f38516e6222a58c874'
gem 'json_refs'
# When we want to squash migrations
gem 'squasher'
@@ -129,28 +148,33 @@ group :test do
gem 'cypress-on-rails', '~> 1.0'
# fast cleaning of database
gem 'database_cleaner'
# mock http calls
gem 'webmock'
end
group :development, :test do
# locking until https://github.com/codeclimate/test-reporter/issues/418 is resolved
gem 'action-cable-testing'
# TODO: is this needed ?
# errors thrown by devise password gem
gem 'flay'
gem 'rspec'
# for error thrown by devise password gem
gem 'active_record_query_trace'
gem 'bundle-audit', require: false
gem 'byebug', platform: :mri
gem 'climate_control'
gem 'factory_bot_rails'
gem 'faker'
gem 'listen'
gem 'mock_redis', git: 'https://github.com/sds/mock_redis', ref: '16d00789f0341a3aac35126c0ffe97a596753ff9'
gem 'mock_redis'
gem 'pry-rails'
gem 'rspec-rails', '~> 4.0.0.beta2'
gem 'rspec-rails', '~> 5.0.0'
gem 'rubocop', require: false
gem 'rubocop-performance', require: false
gem 'rubocop-rails', require: false
gem 'rubocop-rspec', require: false
gem 'scss_lint', require: false
gem 'seed_dump'
gem 'shoulda-matchers'
gem 'simplecov', '0.17.1', require: false
gem 'spring'
gem 'spring-watcher-listen'
gem 'webmock'
end
+344 -300
View File
@@ -1,83 +1,79 @@
GIT
remote: https://github.com/sds/mock_redis
revision: 16d00789f0341a3aac35126c0ffe97a596753ff9
ref: 16d00789f0341a3aac35126c0ffe97a596753ff9
remote: https://github.com/chatwoot/devise-secure_password
revision: de11e8765654b8242d42101ee9c8ffc8126f7975
specs:
mock_redis (0.22.0)
GIT
remote: https://github.com/tzmfreedom/json_refs
revision: 131b11294fd6af9c428171f38516e6222a58c874
ref: 131b11294fd6af9c428171f38516e6222a58c874
specs:
json_refs (0.1.6)
hana
devise-secure_password (2.0.1)
devise (>= 4.0.0, < 5.0.0)
railties (>= 5.0.0, < 7.0.0)
GEM
remote: https://rubygems.org/
specs:
action-cable-testing (0.6.1)
actioncable (>= 5.0)
actioncable (6.0.3.7)
actionpack (= 6.0.3.7)
actioncable (6.1.4.3)
actionpack (= 6.1.4.3)
activesupport (= 6.1.4.3)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailbox (6.0.3.7)
actionpack (= 6.0.3.7)
activejob (= 6.0.3.7)
activerecord (= 6.0.3.7)
activestorage (= 6.0.3.7)
activesupport (= 6.0.3.7)
actionmailbox (6.1.4.3)
actionpack (= 6.1.4.3)
activejob (= 6.1.4.3)
activerecord (= 6.1.4.3)
activestorage (= 6.1.4.3)
activesupport (= 6.1.4.3)
mail (>= 2.7.1)
actionmailer (6.0.3.7)
actionpack (= 6.0.3.7)
actionview (= 6.0.3.7)
activejob (= 6.0.3.7)
actionmailer (6.1.4.3)
actionpack (= 6.1.4.3)
actionview (= 6.1.4.3)
activejob (= 6.1.4.3)
activesupport (= 6.1.4.3)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (6.0.3.7)
actionview (= 6.0.3.7)
activesupport (= 6.0.3.7)
rack (~> 2.0, >= 2.0.8)
actionpack (6.1.4.3)
actionview (= 6.1.4.3)
activesupport (= 6.1.4.3)
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.0.3.7)
actionpack (= 6.0.3.7)
activerecord (= 6.0.3.7)
activestorage (= 6.0.3.7)
activesupport (= 6.0.3.7)
actiontext (6.1.4.3)
actionpack (= 6.1.4.3)
activerecord (= 6.1.4.3)
activestorage (= 6.1.4.3)
activesupport (= 6.1.4.3)
nokogiri (>= 1.8.5)
actionview (6.0.3.7)
activesupport (= 6.0.3.7)
actionview (6.1.4.3)
activesupport (= 6.1.4.3)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
activejob (6.0.3.7)
activesupport (= 6.0.3.7)
active_record_query_trace (1.8)
activejob (6.1.4.3)
activesupport (= 6.1.4.3)
globalid (>= 0.3.6)
activemodel (6.0.3.7)
activesupport (= 6.0.3.7)
activerecord (6.0.3.7)
activemodel (= 6.0.3.7)
activesupport (= 6.0.3.7)
activerecord-import (1.0.7)
activemodel (6.1.4.3)
activesupport (= 6.1.4.3)
activerecord (6.1.4.3)
activemodel (= 6.1.4.3)
activesupport (= 6.1.4.3)
activerecord-import (1.2.0)
activerecord (>= 3.2)
activestorage (6.0.3.7)
actionpack (= 6.0.3.7)
activejob (= 6.0.3.7)
activerecord (= 6.0.3.7)
activestorage (6.1.4.3)
actionpack (= 6.1.4.3)
activejob (= 6.1.4.3)
activerecord (= 6.1.4.3)
activesupport (= 6.1.4.3)
marcel (~> 1.0.0)
activesupport (6.0.3.7)
mini_mime (>= 1.1.0)
activesupport (6.1.4.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.2, >= 2.2.2)
acts-as-taggable-on (6.5.0)
activerecord (>= 5.0, < 6.1)
addressable (2.7.0)
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)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
administrate (0.16.0)
actionpack (>= 5.0)
@@ -92,28 +88,24 @@ GEM
annotate (3.1.1)
activerecord (>= 3.2, < 7.0)
rake (>= 10.4, < 14.0)
ast (2.4.1)
ast (2.4.2)
attr_extras (6.2.4)
aws-eventstream (1.1.0)
aws-partitions (1.360.0)
aws-sdk-core (3.105.0)
aws-eventstream (1.2.0)
aws-partitions (1.513.0)
aws-sdk-core (3.121.1)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.37.0)
aws-sdk-core (~> 3, >= 3.99.0)
aws-sdk-kms (1.49.0)
aws-sdk-core (~> 3, >= 3.120.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.79.1)
aws-sdk-core (~> 3, >= 3.104.3)
aws-sdk-s3 (1.103.0)
aws-sdk-core (~> 3, >= 3.120.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
aws-sigv4 (1.2.2)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.4.0)
aws-eventstream (~> 1, >= 1.0.2)
axiom-types (0.1.1)
descendants_tracker (~> 0.0.4)
ice_nine (~> 0.11.0)
thread_safe (~> 0.3, >= 0.3.1)
azure-storage-blob (2.0.1)
azure-storage-common (~> 2.0)
nokogiri (~> 1.11.0.rc2)
@@ -122,92 +114,102 @@ GEM
faraday_middleware (~> 1.0.0.rc1)
net-http-persistent (~> 4.0)
nokogiri (~> 1.11.0.rc2)
barnes (0.0.8)
barnes (0.0.9)
multi_json (~> 1)
statsd-ruby (~> 1.1)
bcrypt (3.1.15)
bcrypt (3.1.16)
bindex (0.8.1)
bootsnap (1.4.8)
bootsnap (1.9.1)
msgpack (~> 1.0)
brakeman (4.9.0)
brakeman (5.1.1)
browser (5.3.1)
builder (3.2.4)
bullet (6.1.0)
bullet (6.1.5)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
bundle-audit (0.1.0)
bundler-audit
bundler-audit (0.7.0.1)
bundler-audit (0.9.0.1)
bundler (>= 1.2.0, < 3)
thor (>= 0.18, < 2)
thor (~> 1.0)
byebug (11.1.3)
climate_control (1.0.1)
coderay (1.1.3)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
commonmarker (0.21.1)
ruby-enum (~> 0.5)
concurrent-ruby (1.1.8)
connection_pool (2.2.3)
crack (0.4.3)
safe_yaml (~> 1.0.0)
commonmarker (0.23.2)
concurrent-ruby (1.1.9)
connection_pool (2.2.5)
crack (0.4.5)
rexml
crass (1.0.6)
cypress-on-rails (1.8.0)
cypress-on-rails (1.11.0)
rack
database_cleaner (1.8.5)
database_cleaner (2.0.1)
database_cleaner-active_record (~> 2.0.0)
database_cleaner-active_record (2.0.1)
activerecord (>= 5.a)
database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1)
datetime_picker_rails (0.0.7)
momentjs-rails (>= 2.8.1)
ddtrace (0.53.0)
ffi (~> 1.0)
msgpack
declarative (0.0.20)
declarative-option (0.1.0)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devise (4.7.2)
devise (4.8.0)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
devise_token_auth (1.1.4)
devise_token_auth (1.2.0)
bcrypt (~> 3.0)
devise (> 3.5.2, < 5)
rails (>= 4.2.0, < 6.1)
sprockets (= 3.7.2)
rails (>= 4.2.0, < 6.2)
diff-lcs (1.4.4)
digest-crc (0.6.1)
rake (~> 13.0)
docile (1.3.2)
digest-crc (0.6.4)
rake (>= 12.0.0, < 14.0.0)
docile (1.4.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6)
dotenv-rails (2.7.6)
dotenv (= 2.7.6)
railties (>= 3.2)
ecma-re-validator (0.2.1)
regexp_parser (~> 1.2)
equalizer (0.0.11)
down (5.2.4)
addressable (~> 2.8)
ecma-re-validator (0.3.0)
regexp_parser (~> 2.0)
email_reply_trimmer (0.1.13)
erubi (1.10.0)
et-orbi (1.2.4)
erubis (2.7.0)
et-orbi (1.2.5)
tzinfo
execjs (2.7.0)
facebook-messenger (1.5.0)
execjs (2.8.1)
facebook-messenger (2.0.1)
httparty (~> 0.13, >= 0.13.7)
rack (>= 1.4.5)
factory_bot (6.1.0)
factory_bot (6.2.0)
activesupport (>= 5.0.0)
factory_bot_rails (6.1.0)
factory_bot (~> 6.1.0)
factory_bot_rails (6.2.0)
factory_bot (~> 6.2.0)
railties (>= 5.0.0)
faker (2.13.0)
faker (2.19.0)
i18n (>= 1.6, < 2)
faraday (1.0.1)
multipart-post (>= 1.2, < 3)
faraday_middleware (1.0.0)
faraday (~> 1.0)
fcm (1.0.2)
faraday (~> 1.0.0)
ffi (1.15.0)
fcm (1.0.3)
faraday (~> 1)
ffi (1.15.4)
flag_shih_tzu (0.3.23)
flay (2.12.1)
erubis (~> 2.7.0)
path_expander (~> 1.0)
ruby_parser (~> 3.0)
sexp_processor (~> 4.0)
foreman (0.87.2)
fugit (1.4.1)
fugit (1.5.2)
et-orbi (~> 1.1, >= 1.1.8)
raabro (~> 1.4)
gapic-common (0.3.4)
@@ -216,18 +218,23 @@ GEM
googleapis-common-protos-types (>= 1.0.4, < 2.0)
googleauth (~> 0.9)
grpc (~> 1.25)
geocoder (1.6.3)
gli (2.19.2)
globalid (0.4.2)
activesupport (>= 4.2.0)
google-api-client (0.43.0)
geocoder (1.7.0)
gli (2.20.1)
globalid (1.0.0)
activesupport (>= 5.0)
google-apis-core (0.4.1)
addressable (~> 2.5, >= 2.5.1)
googleauth (~> 0.9)
httpclient (>= 2.8.1, < 3.0)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
mini_mime (~> 1.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
signet (~> 0.12)
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.7.0)
google-apis-core (>= 0.4, < 2.a)
google-apis-storage_v1 (0.8.0)
google-apis-core (>= 0.4, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
@@ -239,35 +246,44 @@ GEM
google-cloud-errors (~> 1.0)
google-cloud-env (1.5.0)
faraday (>= 0.17.3, < 2.0)
google-cloud-errors (1.1.0)
google-cloud-storage (1.28.0)
google-cloud-errors (1.2.0)
google-cloud-storage (1.34.1)
addressable (~> 2.5)
digest-crc (~> 0.4)
google-api-client (~> 0.33)
google-cloud-core (~> 1.2)
googleauth (~> 0.9)
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.15.8)
googleapis-common-protos (1.3.11)
google-protobuf (3.18.1)
google-protobuf (3.18.1-universal-darwin)
google-protobuf (3.18.1-x86_64-linux)
googleapis-common-protos (1.3.12)
google-protobuf (~> 3.14)
googleapis-common-protos-types (>= 1.0.6, < 2.0)
googleapis-common-protos-types (~> 1.2)
grpc (~> 1.27)
googleapis-common-protos-types (1.0.6)
googleapis-common-protos-types (1.2.0)
google-protobuf (~> 3.14)
googleauth (0.16.2)
googleauth (0.17.1)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (~> 0.14)
groupdate (5.1.0)
signet (~> 0.15)
groupdate (5.2.2)
activesupport (>= 5)
grpc (1.37.1)
google-protobuf (~> 3.15)
grpc (1.41.0)
google-protobuf (~> 3.17)
googleapis-common-protos-types (~> 1.0)
haikunator (1.1.0)
hairtrigger (0.2.23)
grpc (1.41.0-universal-darwin)
google-protobuf (~> 3.17)
googleapis-common-protos-types (~> 1.0)
grpc (1.41.0-x86_64-linux)
google-protobuf (~> 3.17)
googleapis-common-protos-types (~> 1.0)
haikunator (1.1.1)
hairtrigger (0.2.24)
activerecord (>= 5.0, < 7)
ruby2ruby (~> 2.4)
ruby_parser (~> 3.10)
@@ -275,31 +291,36 @@ GEM
hashdiff (1.0.1)
hashie (4.1.0)
hkdf (0.3.0)
html2text (0.2.1)
nokogiri (~> 1.6)
http-accept (1.7.0)
http-cookie (1.0.3)
http-cookie (1.0.4)
domain_name (~> 0.5)
httparty (0.18.1)
httparty (0.20.0)
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
i18n (1.8.10)
i18n (1.8.11)
concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
inflecto (0.0.2)
jbuilder (2.10.0)
image_processing (1.12.1)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
jbuilder (2.11.2)
activesupport (>= 5.0.0)
jmespath (1.4.0)
jquery-rails (4.4.0)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (2.3.1)
json_schemer (0.2.16)
ecma-re-validator (~> 0.2)
json (2.5.1)
json_refs (0.1.6)
hana
json_schemer (0.2.18)
ecma-re-validator (~> 0.3)
hana (~> 1.3)
regexp_parser (~> 1.5)
regexp_parser (~> 2.0)
uri_template (~> 0.7)
jwt (2.2.3)
jwt (2.3.0)
kaminari (1.2.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.1)
@@ -320,112 +341,119 @@ GEM
addressable (~> 2.7)
letter_opener (1.7.0)
launchy (~> 2.2)
liquid (4.0.3)
listen (3.3.3)
line-bot-api (1.22.0)
liquid (5.1.0)
listen (3.7.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
loofah (2.9.1)
loofah (2.13.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (1.0.1)
marcel (1.0.2)
maxminddb (0.1.22)
memoist (0.16.2)
method_source (1.0.0)
mime-types (3.3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2020.0512)
mini_magick (4.10.1)
mini_mime (1.1.0)
mini_portile2 (2.5.1)
minitest (5.14.4)
mime-types-data (3.2021.0901)
mini_magick (4.11.0)
mini_mime (1.1.2)
mini_portile2 (2.5.3)
minitest (5.15.0)
mock_redis (0.29.0)
ruby2_keywords
momentjs-rails (2.20.1)
railties (>= 3.1)
msgpack (1.3.3)
msgpack (1.4.2)
multi_json (1.15.0)
multi_xml (0.6.0)
multipart-post (2.1.1)
net-http-persistent (4.0.0)
net-http-persistent (4.0.1)
connection_pool (~> 2.2)
netrc (0.11.0)
nio4r (2.5.7)
nokogiri (1.11.3)
newrelic_rpm (8.0.0)
nio4r (2.5.8)
nokogiri (1.11.7)
mini_portile2 (~> 2.5.0)
racc (~> 1.4)
nokogiri (1.11.7-arm64-darwin)
racc (~> 1.4)
nokogiri (1.11.7-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.11.7-x86_64-linux)
racc (~> 1.4)
oauth (0.5.6)
orm_adapter (0.5.0)
os (1.1.1)
parallel (1.19.2)
parser (2.7.1.4)
parallel (1.21.0)
parser (3.0.2.0)
ast (~> 2.4.1)
path_expander (1.1.0)
pg (1.2.3)
procore-sift (0.15.0)
procore-sift (0.16.0)
rails (> 4.2.0)
pry (0.13.1)
pry (0.14.1)
coderay (~> 1.1)
method_source (~> 1.0)
pry-rails (0.3.9)
pry (>= 0.10.4)
public_suffix (4.0.6)
puma (4.3.6)
puma (5.5.2)
nio4r (~> 2.0)
pundit (2.1.0)
pundit (2.1.1)
activesupport (>= 3.0.0)
raabro (1.4.0)
racc (1.5.2)
racc (1.6.0)
rack (2.2.3)
rack-cache (1.12.0)
rack (>= 0.4)
rack-attack (6.5.0)
rack (>= 1.0, < 3)
rack-cors (1.1.1)
rack (>= 2.0.0)
rack-proxy (0.6.5)
rack-proxy (0.7.0)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails (6.0.3.7)
actioncable (= 6.0.3.7)
actionmailbox (= 6.0.3.7)
actionmailer (= 6.0.3.7)
actionpack (= 6.0.3.7)
actiontext (= 6.0.3.7)
actionview (= 6.0.3.7)
activejob (= 6.0.3.7)
activemodel (= 6.0.3.7)
activerecord (= 6.0.3.7)
activestorage (= 6.0.3.7)
activesupport (= 6.0.3.7)
bundler (>= 1.3.0)
railties (= 6.0.3.7)
rack-timeout (0.6.0)
rails (6.1.4.3)
actioncable (= 6.1.4.3)
actionmailbox (= 6.1.4.3)
actionmailer (= 6.1.4.3)
actionpack (= 6.1.4.3)
actiontext (= 6.1.4.3)
actionview (= 6.1.4.3)
activejob (= 6.1.4.3)
activemodel (= 6.1.4.3)
activerecord (= 6.1.4.3)
activestorage (= 6.1.4.3)
activesupport (= 6.1.4.3)
bundler (>= 1.15.0)
railties (= 6.1.4.3)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0)
rails-html-sanitizer (1.4.2)
loofah (~> 2.3)
railties (6.0.3.7)
actionpack (= 6.0.3.7)
activesupport (= 6.0.3.7)
railties (6.1.4.3)
actionpack (= 6.1.4.3)
activesupport (= 6.1.4.3)
method_source
rake (>= 0.8.7)
thor (>= 0.20.3, < 2.0)
rake (>= 0.13)
thor (~> 1.0)
rainbow (3.0.0)
rake (13.0.3)
rb-fsevent (0.10.4)
rake (13.0.6)
rb-fsevent (0.11.0)
rb-inotify (0.10.1)
ffi (~> 1.0)
redis (4.2.1)
redis-namespace (1.8.0)
redis (4.4.0)
redis-namespace (1.8.1)
redis (>= 3.0.4)
redis-rack-cache (2.2.1)
rack-cache (>= 1.10, < 2)
redis-store (>= 1.6, < 2)
redis-store (1.9.0)
redis (>= 4, < 5)
regexp_parser (1.7.1)
representable (3.0.4)
regexp_parser (2.1.1)
representable (3.1.1)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
responders (3.0.1)
actionpack (>= 5.0)
@@ -437,57 +465,56 @@ GEM
netrc (~> 0.8)
retriable (3.1.2)
rexml (3.2.5)
rspec-core (3.9.2)
rspec-support (~> 3.9.3)
rspec-expectations (3.9.2)
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)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-mocks (3.9.1)
rspec-support (~> 3.10.0)
rspec-mocks (3.10.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-rails (4.0.1)
actionpack (>= 4.2)
activesupport (>= 4.2)
railties (>= 4.2)
rspec-core (~> 3.9)
rspec-expectations (~> 3.9)
rspec-mocks (~> 3.9)
rspec-support (~> 3.9)
rspec-support (3.9.3)
rubocop (0.89.1)
rspec-support (~> 3.10.0)
rspec-rails (5.0.2)
actionpack (>= 5.2)
activesupport (>= 5.2)
railties (>= 5.2)
rspec-core (~> 3.10)
rspec-expectations (~> 3.10)
rspec-mocks (~> 3.10)
rspec-support (~> 3.10)
rspec-support (3.10.2)
rubocop (1.22.1)
parallel (~> 1.10)
parser (>= 2.7.1.1)
parser (>= 3.0.0.0)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.7)
regexp_parser (>= 1.8, < 3.0)
rexml
rubocop-ast (>= 0.3.0, < 1.0)
rubocop-ast (>= 1.12.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 2.0)
rubocop-ast (0.3.0)
parser (>= 2.7.1.4)
rubocop-performance (1.7.1)
rubocop (>= 0.82.0)
rubocop-rails (2.8.1)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.12.0)
parser (>= 3.0.1.1)
rubocop-performance (1.11.5)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
rubocop-rails (2.12.3)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 0.87.0)
rubocop-rspec (1.43.2)
rubocop (~> 0.87)
ruby-enum (0.9.0)
i18n
ruby-progressbar (1.10.1)
rubocop (>= 1.7.0, < 2.0)
rubocop-rspec (2.5.0)
rubocop (~> 1.19)
ruby-progressbar (1.11.0)
ruby-vips (2.1.3)
ffi (~> 1.12)
ruby2_keywords (0.0.5)
ruby2ruby (2.4.4)
ruby_parser (~> 3.1)
sexp_processor (~> 4.6)
ruby_parser (3.15.0)
rubocop (>= 0.87.0)
sexp_processor (~> 4.9)
safe_yaml (1.0.5)
sass (3.7.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_parser (3.17.0)
sexp_processor (~> 4.15, >= 4.15.1)
sassc (2.4.0)
ffi (~> 1.9)
sassc-rails (2.1.2)
@@ -496,29 +523,38 @@ GEM
sprockets (> 3.0)
sprockets-rails
tilt
scout_apm (2.6.9)
scout_apm (4.1.2)
parser
scss_lint (0.59.0)
sass (~> 3.5, >= 3.5.5)
seed_dump (3.3.1)
activerecord (>= 4)
activesupport (>= 4)
selectize-rails (0.12.6)
semantic_range (2.3.0)
sentry-raven (3.0.3)
semantic_range (3.0.0)
sentry-rails (4.7.3)
railties (>= 5.0)
sentry-ruby-core (~> 4.7.0)
sentry-ruby (4.7.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
faraday (>= 1.0)
sexp_processor (4.15.1)
shoulda-matchers (4.4.1)
activesupport (>= 4.2.0)
sidekiq (6.1.1)
sentry-ruby-core (= 4.7.3)
sentry-ruby-core (4.7.3)
concurrent-ruby
faraday
sentry-sidekiq (4.7.3)
sentry-ruby-core (~> 4.7.0)
sidekiq (>= 3.0)
sexp_processor (4.15.3)
shoulda-matchers (5.0.0)
activesupport (>= 5.2.0)
sidekiq (6.2.2)
connection_pool (>= 2.2.2)
rack (~> 2.0)
redis (>= 4.2.0)
sidekiq-cron (1.2.0)
fugit (~> 1.1)
sidekiq (>= 4.2.1)
signet (0.15.0)
addressable (~> 2.3)
signet (0.16.0)
addressable (~> 2.8)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
@@ -527,7 +563,7 @@ GEM
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
slack-ruby-client (0.15.0)
slack-ruby-client (0.17.0)
faraday (>= 1.0)
faraday_middleware
gli
@@ -537,83 +573,80 @@ GEM
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
sprockets (3.7.2)
sprockets (4.0.2)
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.4.0)
telegram-bot-ruby (0.12.0)
faraday
inflecto
virtus
telephone_number (1.4.9)
statsd-ruby (1.5.0)
telephone_number (1.4.12)
thor (1.1.0)
thread_safe (0.3.6)
tilt (2.0.10)
time_diff (0.3.0)
activesupport
i18n
trailblazer-option (0.1.1)
twilio-ruby (5.32.0)
faraday (~> 1.0.0)
jwt (>= 1.5, <= 2.5)
nokogiri (>= 1.6, < 2.0)
twitty (0.1.1)
twitty (0.1.4)
oauth
tzinfo (1.2.9)
thread_safe (~> 0.1)
tzinfo-data (1.2020.1)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
tzinfo-data (1.2021.3)
tzinfo (>= 1.0.0)
uber (0.1.0)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
uniform_notifier (1.13.0)
unf_ext (0.0.8)
unicode-display_width (2.1.0)
uniform_notifier (1.14.2)
uri_template (0.7.0)
valid_email2 (3.3.1)
valid_email2 (4.0.0)
activemodel (>= 3.2)
mail (~> 2.5)
virtus (1.0.5)
axiom-types (~> 0.1)
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9)
warden (1.2.8)
rack (>= 2.0.6)
web-console (4.0.4)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.1.0)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
webmock (3.8.3)
addressable (>= 2.3.6)
webmock (3.14.0)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
webpacker (5.2.1)
webpacker (5.4.3)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
semantic_range (>= 2.3.0)
webpush (1.0.0)
webpush (1.1.0)
hkdf (~> 0.2)
jwt (~> 2.0)
websocket-driver (0.7.3)
webrick (1.7.0)
websocket-driver (0.7.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
wisper (2.0.0)
zeitwerk (2.4.2)
zeitwerk (2.5.1)
PLATFORMS
arm64-darwin-20
ruby
x86_64-darwin-18
x86_64-darwin-20
x86_64-darwin-21
x86_64-linux
DEPENDENCIES
action-cable-testing
active_record_query_trace
activerecord-import
acts-as-taggable-on
administrate
@@ -628,17 +661,23 @@ DEPENDENCIES
bullet
bundle-audit
byebug
climate_control
commonmarker
cypress-on-rails (~> 1.0)
database_cleaner
ddtrace
devise
devise-secure_password (~> 2.0)!
devise_token_auth
dotenv-rails
facebook-messenger (= 1.5.0)
down (~> 5.0)
email_reply_trimmer
facebook-messenger
factory_bot_rails
faker
fcm
flag_shih_tzu
flay
foreman
geocoder
google-cloud-dialogflow
@@ -647,39 +686,45 @@ DEPENDENCIES
haikunator
hairtrigger
hashie
html2text
image_processing
jbuilder
json_refs!
json_refs
json_schemer
jwt
kaminari
koala
letter_opener
line-bot-api
liquid
listen
maxminddb
mini_magick
mock_redis!
mock_redis
newrelic_rpm
pg
procore-sift
pry-rails
puma
pundit
rack-attack
rack-cors
rack-timeout
rails
redis
redis-namespace
redis-rack-cache
responders
rest-client
rspec-rails (~> 4.0.0.beta2)
rspec
rspec-rails (~> 5.0.0)
rubocop
rubocop-performance
rubocop-rails
rubocop-rspec
scout_apm
scss_lint
seed_dump
sentry-raven
sentry-rails
sentry-ruby
sentry-sidekiq
shoulda-matchers
sidekiq
sidekiq-cron
@@ -688,7 +733,6 @@ DEPENDENCIES
spring
spring-watcher-listen
squasher
telegram-bot-ruby
telephone_number
time_diff
twilio-ruby (~> 5.32.0)
@@ -703,7 +747,7 @@ DEPENDENCIES
wisper (= 2.0.0)
RUBY VERSION
ruby 2.7.2p137
ruby 3.0.2p107
BUNDLED WITH
2.1.4
2.2.25
+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
+51 -32
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,68 +20,67 @@ ___
<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>
<a href="https://huntr.dev/bounties/disclose"><img src="https://cdn.huntr.dev/huntr_security_badge_mono.svg" alt="Huntr"></a>
<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%2Fuptime.json" alt="uptime"></a>
<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.
---
### Features
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.
Chatwoot gives an integrated view of conversations happening in different communication channels.
## Features
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.
---
## Documentation
### Documentation
Detailed documentation is available at [chatwoot.com/help-center](https://www.chatwoot.com/help-center).
Detailed documentation is available at [www.chatwoot.com/help-center](https://www.chatwoot.com/help-center).
### Translation process
## Translation process
The translation process for Chatwoot web and mobile app is managed at [https://translate.chatwoot.com](https://translate.chatwoot.com) using Crowdin. Please read the [translation guide](https://www.chatwoot.com/docs/contributing/translating-chatwoot-to-your-language) for contributing to Chatwoot.
---
### Branching model
## Branching model
We use the [git-flow](https://nvie.com/posts/a-successful-git-branching-model/) branching model. The base branch is `develop`.
If you are looking for a stable version, please use the `master` or tags labelled as `v1.x.x`.
---
## Deployment
### Deployment
#### Heroku one-click deploy
### Heroku one-click deploy
Deploying Chatwoot to Heroku is a breeze. It's as simple as clicking this button:
@@ -86,13 +88,30 @@ 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.
#### Other deployment options
Please follow [deployment architecture guide](https://www.chatwoot.com/docs/deployment/architecture) to deploy with Docker or Caprover.
### DigitalOcean 1-Click Kubernetes deployment
---
Chatwoot now supports 1-Click deployment to DigitalOcean as a kubernetes app.
### Contributors ✨
<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
For other supported options, checkout our [deployment page](https://chatwoot.com/deploy).
## Security
Looking to report a vulnerability? Please refer our [SECURITY.md](./SECURITY.md) file.
## Community? Questions? Support ?
If you need help or just want to hang out, come, say hi on our [Discord](https://discord.gg/cJXdrwS) server.
## Contributors ✨
Thanks goes to all these [wonderful people](https://www.chatwoot.com/docs/contributors):
+24 -1
View File
@@ -1,8 +1,31 @@
# Security Policy
Chatwoot is looking forward to working with security researchers across the world to keep Chatwoot and our users safe. If you have found an issue in our systems/applications, please reach out to us.
## Reporting a Vulnerability
We use [huntr.dev](https://huntr.dev/) for security issues that affect our project. If you believe you have found a vulnerability, please disclose it via this [form](https://huntr.dev/bounties/disclose).
This will enable us to review the vulnerability, fix it promptly, and reward you for your efforts.
If you have any questions about the process, feel free to reach out to hello@chatwoot.com.
If you have any questions about the process, feel free to reach out to security@chatwoot.com.
## Out of scope
Please do not perform testing against Chatwoot production services. Use a self hosted instance to perform tests.
We consider the following to be out of scope, though there may be exceptions.
- Missing HTTP security headers
- Self XSS
- HTTP Host Header XSS without working proof-of-concept
- Incomplete/Missing SPF/DKIM
- Denial of Service attacks
- DNSSEC
- Social Engineering attacks
If you are not sure about the scope, please create a report.
## Thanks
Thank you for keeping Chatwoot and our users safe. 🙇
+4
View File
@@ -28,6 +28,10 @@
"FRONTEND_URL": {
"description": "Public root URL of the Chatwoot installation. This will be used in the emails.",
"value": "https://CHANGE.herokuapp.com"
},
"INSTALLATION_ENV": {
"description": "Installation method used for Chatwoot.",
"value": "heroku"
}
},
"formation": {
+24 -3
View File
@@ -3,8 +3,9 @@ class ContactIdentifyAction
def perform
ActiveRecord::Base.transaction do
@contact = merge_contact(existing_identified_contact, @contact) if merge_contacts?(existing_identified_contact, @contact)
@contact = merge_contact(existing_email_contact, @contact) if merge_contacts?(existing_email_contact, @contact)
merge_if_existing_identified_contact
merge_if_existing_email_contact
merge_if_existing_phone_number_contact
update_contact
end
@contact
@@ -16,6 +17,18 @@ class ContactIdentifyAction
@account ||= @contact.account
end
def merge_if_existing_identified_contact
@contact = merge_contact(existing_identified_contact, @contact) if merge_contacts?(existing_identified_contact, @contact)
end
def merge_if_existing_email_contact
@contact = merge_contact(existing_email_contact, @contact) if merge_contacts?(existing_email_contact, @contact)
end
def merge_if_existing_phone_number_contact
@contact = merge_contact(existing_phone_number_contact, @contact) if merge_contacts?(existing_phone_number_contact, @contact)
end
def existing_identified_contact
return if params[:identifier].blank?
@@ -28,6 +41,12 @@ class ContactIdentifyAction
@existing_email_contact ||= Contact.where(account_id: account.id).find_by(email: params[:email])
end
def existing_phone_number_contact
return if params[:phone_number].blank?
@existing_phone_number_contact ||= Contact.where(account_id: account.id).find_by(phone_number: params[:phone_number])
end
def merge_contacts?(existing_contact, _contact)
existing_contact && existing_contact.id != @contact.id
end
@@ -36,7 +55,9 @@ class ContactIdentifyAction
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).reject { |_k, v| v.blank? }.merge({ custom_attributes: custom_attributes }))
@contact.update!(params.slice(:name, :email, :identifier, :phone_number).reject do |_k, v|
v.blank?
end.merge({ custom_attributes: custom_attributes }))
ContactAvatarJob.perform_later(@contact, params[:avatar_url]) if params[:avatar_url].present?
end
+17 -2
View File
@@ -1,13 +1,18 @@
class ContactMergeAction
include Events::Types
pattr_initialize [:account!, :base_contact!, :mergee_contact!]
def perform
# This case happens when an agent updates a contact email in dashboard,
# while the contact also update his email via email collect box
return @base_contact if base_contact.id == mergee_contact.id
ActiveRecord::Base.transaction do
validate_contacts
merge_conversations
merge_messages
merge_contact_inboxes
remove_mergee_contact
merge_and_remove_mergee_contact
end
@base_contact
end
@@ -36,7 +41,17 @@ class ContactMergeAction
ContactInbox.where(contact_id: @mergee_contact.id).update(contact_id: @base_contact.id)
end
def remove_mergee_contact
def merge_and_remove_mergee_contact
mergable_attribute_keys = %w[identifier name email phone_number additional_attributes custom_attributes]
base_contact_attributes = base_contact.attributes.slice(*mergable_attribute_keys).compact_blank
mergee_contact_attributes = mergee_contact.attributes.slice(*mergable_attribute_keys).compact_blank
# attributes in base contact are given preference
merged_attributes = mergee_contact_attributes.deep_merge(base_contact_attributes)
@mergee_contact.destroy!
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
@@ -43,7 +43,7 @@ $woot-logo-padding: $space-large $space-two;
// Colors
$color-woot: #1f93ff;
$color-gray: #6e6f73;
$color-light-gray: #999a9b;
$color-light-gray: #747677;
$color-border: #e0e6ed;
$color-border-light: #f0f4f5;
$color-background: #f4f6fb;
-28
View File
@@ -1,28 +0,0 @@
require 'facebook/messenger'
class FacebookBot
include Facebook::Messenger
Bot.on :message do |message|
Rails.logger.info "MESSAGE_RECIEVED #{message}"
response = ::Integrations::Facebook::MessageParser.new(message)
::Integrations::Facebook::MessageCreator.new(response).perform
end
Bot.on :delivery do |delivery|
# delivery.ids # => 'mid.1457764197618:41d102a3e1ae206a38'
# delivery.sender # => { 'id' => '1008372609250235' }
# delivery.recipient # => { 'id' => '2015573629214912' }
# delivery.at # => 2016-04-22 21:30:36 +0200
# delivery.seq # => 37
updater = Integrations::Facebook::DeliveryStatus.new(delivery)
updater.perform
Rails.logger.info "Human was online at #{delivery.at}"
end
Bot.on :message_echo do |message|
Rails.logger.info "MESSAGE_ECHO #{message}"
response = ::Integrations::Facebook::MessageParser.new(message)
::Integrations::Facebook::MessageCreator.new(response).perform
end
end
+3 -5
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]
def perform
if @user.nil?
@@ -61,11 +61,9 @@ class AccountBuilder
end
def create_user
password = user_password || SecureRandom.alphanumeric(12)
@user = User.new(email: @email,
password: password,
password_confirmation: password,
password: user_password,
password_confirmation: user_password,
name: @user_full_name)
@user.confirm if @confirmed
@user.save!
+28 -12
View File
@@ -1,5 +1,5 @@
class ContactBuilder
pattr_initialize [:source_id!, :inbox!, :contact_attributes!]
pattr_initialize [:source_id!, :inbox!, :contact_attributes!, :hmac_verified]
def perform
contact_inbox = inbox.contact_inboxes.find_by(source_id: source_id)
@@ -18,7 +18,8 @@ class ContactBuilder
::ContactInbox.create!(
contact_id: contact.id,
inbox_id: inbox.id,
source_id: source_id
source_id: source_id,
hmac_verified: hmac_verified || false
)
end
@@ -28,26 +29,40 @@ class ContactBuilder
def create_contact
account.contacts.create!(
name: contact_attributes[:name],
name: contact_attributes[:name] || ::Haikunator.haikunate(1000),
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
def find_contact
contact = nil
contact = account.contacts.find_by(identifier: contact_attributes[:identifier]) if contact_attributes[:identifier].present?
contact ||= account.contacts.find_by(email: contact_attributes[:email]) if contact_attributes[:email].present?
contact ||= account.contacts.find_by(phone_number: contact_attributes[:phone_number]) if contact_attributes[:phone_number].present?
contact = find_contact_by_identifier(contact_attributes[:identifier])
contact ||= find_contact_by_email(contact_attributes[:email])
contact ||= find_contact_by_phone_number(contact_attributes[:phone_number])
contact
end
def find_contact_by_identifier(identifier)
return if identifier.blank?
account.contacts.find_by(identifier: identifier)
end
def find_contact_by_email(email)
return if email.blank?
account.contacts.find_by(email: email.downcase)
end
def find_contact_by_phone_number(phone_number)
return if phone_number.blank?
account.contacts.find_by(phone_number: phone_number)
end
def build_contact_inbox
ActiveRecord::Base.transaction do
contact = find_contact || create_contact
@@ -56,6 +71,7 @@ class ContactBuilder
contact_inbox
rescue StandardError => e
Rails.logger.info e
raise e
end
end
end
+9 -1
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::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?
@@ -14,12 +14,20 @@ class ContactInboxBuilder
def generate_source_id
return twilio_source_id if @inbox.channel_type == 'Channel::TwilioSms'
return wa_source_id if @inbox.channel_type == 'Channel::Whatsapp'
return @contact.email if @inbox.channel_type == 'Channel::Email'
return SecureRandom.uuid if @inbox.channel_type == 'Channel::Api'
nil
end
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
return unless @contact.phone_number
@@ -0,0 +1,28 @@
class CsatSurveys::ResponseBuilder
pattr_initialize [:message]
def perform
raise 'Invalid Message' unless message.input_csat?
conversation = message.conversation
rating = message.content_attributes.dig('submitted_values', 'csat_survey_response', 'rating')
feedback_message = message.content_attributes.dig('submitted_values', 'csat_survey_response', 'feedback_message')
return if rating.blank?
process_csat_response(conversation, rating, feedback_message)
end
private
def process_csat_response(conversation, rating, feedback_message)
csat_survey_response = message.csat_survey_response || CsatSurveyResponse.new(
message_id: message.id, account_id: message.account_id, conversation_id: message.conversation_id,
contact_id: conversation.contact_id, assigned_agent: conversation.assignee
)
csat_survey_response.rating = rating
csat_survey_response.feedback_message = feedback_message
csat_survey_response.save!
csat_survey_response
end
end
@@ -4,24 +4,32 @@
# based on this we are showing "not sent from chatwoot" message in frontend
# Hence there is no need to set user_id in message for outgoing echo messages.
class Messages::Facebook::MessageBuilder
class Messages::Facebook::MessageBuilder < Messages::Messenger::MessageBuilder
attr_reader :response
def initialize(response, inbox, outgoing_echo: false)
super()
@response = response
@inbox = inbox
@outgoing_echo = outgoing_echo
@sender_id = (@outgoing_echo ? @response.recipient_id : @response.sender_id)
@message_type = (@outgoing_echo ? :outgoing : :incoming)
@attachments = (@response.attachments || [])
end
def perform
# This channel might require reauthorization, may be owner might have changed the fb password
return if @inbox.channel.reauthorization_required?
ActiveRecord::Base.transaction do
build_contact
build_message
end
ensure_contact_avatar
rescue Koala::Facebook::AuthenticationError
Rails.logger.info "Facebook Authorization expired for Inbox #{@inbox.id}"
rescue StandardError => e
Raven.capture_exception(e)
Sentry.capture_exception(e)
true
end
@@ -35,24 +43,22 @@ class Messages::Facebook::MessageBuilder
return if contact.present?
@contact = Contact.create!(contact_params.except(:remote_avatar_url))
ContactAvatarJob.perform_later(@contact, contact_params[:remote_avatar_url]) if contact_params[:remote_avatar_url]
@contact_inbox = ContactInbox.create(contact: contact, inbox: @inbox, source_id: @sender_id)
end
def build_message
@message = conversation.messages.create!(message_params)
(response.attachments || []).each do |attachment|
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]
@attachments.each do |attachment|
process_attachment(attachment)
end
end
def attach_file(attachment, file_url)
file_resource = LocalResource.new(file_url)
attachment.file.attach(io: file_resource.file, filename: file_resource.filename, content_type: file_resource.encoding)
rescue *ExceptionList::URI_EXCEPTIONS => e
Rails.logger.info "invalid url #{file_url} : #{e.message}"
def ensure_contact_avatar
return if contact_params[:remote_avatar_url].blank?
return if @contact.avatar.attached?
ContactAvatarJob.perform_later(@contact, contact_params[:remote_avatar_url])
end
def conversation
@@ -66,28 +72,6 @@ class Messages::Facebook::MessageBuilder
))
end
def attachment_params(attachment)
file_type = attachment['type'].to_sym
params = { file_type: file_type, account_id: @message.account_id }
if [:image, :file, :audio, :video].include? file_type
params.merge!(file_type_params(attachment))
elsif file_type == :location
params.merge!(location_params(attachment))
elsif file_type == :fallback
params.merge!(fallback_params(attachment))
end
params
end
def file_type_params(attachment)
{
external_url: attachment['payload']['url'],
remote_file_url: attachment['payload']['url']
}
end
def location_params(attachment)
lat = attachment['payload']['coordinates']['lat']
long = attachment['payload']['coordinates']['long']
@@ -125,18 +109,30 @@ class Messages::Facebook::MessageBuilder
}
end
def contact_params
begin
k = Koala::Facebook::API.new(@inbox.channel.page_access_token) if @inbox.facebook?
result = k.get_object(@sender_id) || {}
rescue StandardError => e
result = {}
Raven.capture_exception(e)
end
def process_contact_params_result(result)
{
name: "#{result['first_name'] || 'John'} #{result['last_name'] || 'Doe'}",
account_id: @inbox.account_id,
remote_avatar_url: result['profile_pic'] || ''
}
end
def contact_params
begin
k = Koala::Facebook::API.new(@inbox.channel.page_access_token) if @inbox.facebook?
result = k.get_object(@sender_id) || {}
rescue Koala::Facebook::AuthenticationError
@inbox.channel.authorization_error!
raise
rescue Koala::Facebook::ClientError => e
result = {}
# OAuthException, code: 100, error_subcode: 2018218, message: (#100) No profile available for this user
# We don't need to capture this error as we don't care about contact params in case of echo messages
Sentry.capture_exception(e) unless @outgoing_echo
rescue StandardError => e
result = {}
Sentry.capture_exception(e)
end
process_contact_params_result(result)
end
end
@@ -0,0 +1,145 @@
# This class creates both outgoing messages from chatwoot and echo outgoing messages based on the flag `outgoing_echo`
# Assumptions
# 1. Incase of an outgoing message which is echo, source_id will NOT be nil,
# based on this we are showing "not sent from chatwoot" message in frontend
# Hence there is no need to set user_id in message for outgoing echo messages.
class Messages::Instagram::MessageBuilder < Messages::Messenger::MessageBuilder
attr_reader :messaging
def initialize(messaging, inbox, outgoing_echo: false)
super()
@messaging = messaging
@inbox = inbox
@outgoing_echo = outgoing_echo
end
def perform
return if @inbox.channel.reauthorization_required?
ActiveRecord::Base.transaction do
build_message
end
rescue Koala::Facebook::AuthenticationError
@inbox.channel.authorization_error!
raise
rescue StandardError => e
Sentry.capture_exception(e)
true
end
private
def attachments
@messaging[:message][:attachments] || {}
end
def message_type
@outgoing_echo ? :outgoing : :incoming
end
def message_identifier
message[:mid]
end
def message_source_id
@outgoing_echo ? recipient_id : sender_id
end
def sender_id
@messaging[:sender][:id]
end
def recipient_id
@messaging[:recipient][:id]
end
def message
@messaging[:message]
end
def contact
@contact ||= @inbox.contact_inboxes.find_by(source_id: message_source_id)&.contact
end
def conversation
@conversation ||= Conversation.find_by(conversation_params) || build_conversation
end
def message_content
@messaging[:message][:text]
end
def build_message
return if @outgoing_echo && already_sent_from_chatwoot?
@message = conversation.messages.create!(message_params)
attachments.each do |attachment|
process_attachment(attachment)
end
end
def build_conversation
@contact_inbox ||= contact.contact_inboxes.find_by!(source_id: message_source_id)
Conversation.create!(conversation_params.merge(
contact_inbox_id: @contact_inbox.id
))
end
def conversation_params
{
account_id: @inbox.account_id,
inbox_id: @inbox.id,
contact_id: contact.id,
additional_attributes: {
type: 'instagram_direct_message'
}
}
end
def message_params
{
account_id: conversation.account_id,
inbox_id: conversation.inbox_id,
message_type: message_type,
source_id: message_identifier,
content: message_content,
sender: @outgoing_echo ? nil : contact
}
end
def already_sent_from_chatwoot?
cw_message = conversation.messages.where(
source_id: @messaging[:message][:mid]
).first
cw_message.present?
end
### Sample response
# {
# "object": "instagram",
# "entry": [
# {
# "id": "<IGID>",// ig id of the business
# "time": 1569262486134,
# "messaging": [
# {
# "sender": {
# "id": "<IGSID>"
# },
# "recipient": {
# "id": "<IGID>"
# },
# "timestamp": 1569262485349,
# "message": {
# "mid": "<MESSAGE_ID>",
# "text": "<MESSAGE_CONTENT>"
# }
# }
# ]
# }
# ],
# }
end
+37 -12
View File
@@ -15,21 +15,36 @@ class Messages::MessageBuilder
def perform
@message = @conversation.messages.build(message_params)
if @attachments.present?
@attachments.each do |uploaded_attachment|
attachment = @message.attachments.new(
account_id: @message.account_id,
file_type: file_type(uploaded_attachment&.content_type)
)
attachment.file.attach(uploaded_attachment)
end
end
@message.save
process_attachments
process_emails
@message.save!
@message
end
private
def process_attachments
return if @attachments.blank?
@attachments.each do |uploaded_attachment|
@message.attachments.build(
account_id: @message.account_id,
file_type: file_type(uploaded_attachment&.content_type),
file: uploaded_attachment
)
end
end
def process_emails
return unless @conversation.inbox&.inbox_type == 'Email'
cc_emails = @params[:cc_emails].split(',') if @params[:cc_emails]
bcc_emails = @params[:bcc_emails].split(',') if @params[:bcc_emails]
@message.content_attributes[:cc_emails] = cc_emails
@message.content_attributes[:bcc_emails] = bcc_emails
end
def message_type
if @conversation.inbox.channel_type != 'Channel::Api' && @message_type == 'incoming'
raise StandardError, 'Incoming messages are only allowed in Api inboxes'
@@ -39,7 +54,17 @@ class Messages::MessageBuilder
end
def sender
message_type == 'outgoing' ? @user : @conversation.contact
message_type == 'outgoing' ? (message_sender || @user) : @conversation.contact
end
def external_created_at
@params[:external_created_at].present? ? { external_created_at: @params[:external_created_at] } : {}
end
def message_sender
return if @params[:sender_type] != 'AgentBot'
AgentBot.where(account_id: [nil, @conversation.account.id]).find_by(id: @params[:sender_id])
end
def message_params
@@ -54,6 +79,6 @@ class Messages::MessageBuilder
items: @items,
in_reply_to: @in_reply_to,
echo_id: @params[:echo_id]
}
}.merge(external_created_at)
end
end
@@ -0,0 +1,42 @@
class Messages::Messenger::MessageBuilder
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]
end
def attach_file(attachment, file_url)
attachment_file = Down.download(
file_url
)
attachment.file.attach(
io: attachment_file,
filename: attachment_file.original_filename,
content_type: attachment_file.content_type
)
end
def attachment_params(attachment)
file_type = attachment['type'].to_sym
params = { file_type: file_type, account_id: @message.account_id }
if [:image, :file, :audio, :video].include? file_type
params.merge!(file_type_params(attachment))
elsif file_type == :location
params.merge!(location_params(attachment))
elsif file_type == :fallback
params.merge!(fallback_params(attachment))
end
params
end
def file_type_params(attachment)
{
external_url: attachment['payload']['url'],
remote_file_url: attachment['payload']['url']
}
end
end
@@ -4,7 +4,7 @@ class NotificationSubscriptionBuilder
def perform
# if multiple accounts were used to login in same browser
move_subscription_to_user if identifier_subscription && identifier_subscription.user_id != user.id
build_identifier_subscription if identifier_subscription.blank?
identifier_subscription.blank? ? build_identifier_subscription : update_identifier_subscription
identifier_subscription
end
@@ -25,6 +25,10 @@ class NotificationSubscriptionBuilder
end
def build_identifier_subscription
user.notification_subscriptions.create(params.merge(identifier: identifier))
@identifier_subscription = user.notification_subscriptions.create(params.merge(identifier: identifier))
end
def update_identifier_subscription
identifier_subscription.update(params.merge(identifier: identifier))
end
end
+25 -19
View File
@@ -1,4 +1,5 @@
class V2::ReportBuilder
include DateRangeHelper
attr_reader :account, :params
def initialize(account, params)
@@ -31,17 +32,34 @@ class V2::ReportBuilder
private
def scope
return account if params[:type].match?('account')
return inbox if params[:type].match?('inbox')
return user if params[:type].match?('agent')
case params[:type]
when :account
account
when :inbox
inbox
when :agent
user
when :label
label
when :team
team
end
end
def inbox
@inbox ||= account.inboxes.where(id: params[:id]).first
@inbox ||= account.inboxes.find(params[:id])
end
def user
@user ||= account.users.where(id: params[:id]).first
@user ||= account.users.find(params[:id])
end
def label
@label ||= account.labels.find(params[:id])
end
def team
@team ||= account.teams.find(params[:id])
end
def conversations_count
@@ -50,15 +68,14 @@ class V2::ReportBuilder
.count
end
# unscoped removes all scopes added to a model previously
def incoming_messages_count
scope.messages.unscoped.where(account_id: account.id).incoming
scope.messages.incoming.unscope(:order)
.group_by_day(:created_at, range: range, default_value: 0)
.count
end
def outgoing_messages_count
scope.messages.unscoped.where(account_id: account.id).outgoing
scope.messages.outgoing.unscope(:order)
.group_by_day(:created_at, range: range, default_value: 0)
.count
end
@@ -83,10 +100,6 @@ class V2::ReportBuilder
.average(:value)
end
def range
parse_date_time(params[:since])..parse_date_time(params[:until])
end
# Taking average of average is not too accurate
# https://en.wikipedia.org/wiki/Simpson's_paradox
# TODO: Will optimize this later
@@ -101,11 +114,4 @@ class V2::ReportBuilder
(avg_first_response_time.values.sum / avg_first_response_time.values.length)
end
def parse_date_time(datetime)
return datetime if datetime.is_a?(DateTime)
return datetime.to_datetime if datetime.is_a?(Time) || datetime.is_a?(Date)
DateTime.strptime(datetime, '%s')
end
end
+1 -1
View File
@@ -31,7 +31,7 @@ class RoomChannel < ApplicationCable::Channel
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
@@ -0,0 +1,5 @@
class AndroidAppController < ApplicationController
def assetlinks
render layout: false
end
end
+4
View File
@@ -16,4 +16,8 @@ class Api::BaseController < ApplicationController
authorize(model)
end
def check_admin_authorization?
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
end
end
@@ -0,0 +1,35 @@
class Api::V1::Accounts::AgentBotsController < Api::V1::Accounts::BaseController
before_action :current_account
before_action :check_authorization
before_action :agent_bot, except: [:index, :create]
def index
@agent_bots = AgentBot.where(account_id: [nil, Current.account.id])
end
def show; end
def create
@agent_bot = Current.account.agent_bots.create!(permitted_params)
end
def update
@agent_bot.update!(permitted_params)
end
def destroy
@agent_bot.destroy
head :ok
end
private
def agent_bot
@agent_bot = AgentBot.where(account_id: [nil, Current.account.id]).find(params[:id]) if params[:action] == 'show'
@agent_bot ||= Current.account.agent_bots.find(params[:id])
end
def permitted_params
params.permit(:name, :description, :outgoing_url)
end
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]
@@ -9,21 +10,18 @@ class Api::V1::Accounts::AgentsController < Api::V1::Accounts::BaseController
@agents = agents
end
def create; end
def update
@agent.update!(agent_params.slice(:name).compact)
@agent.current_account_user.update!(agent_params.slice(:role, :availability, :auto_offline).compact)
end
def destroy
@agent.current_account_user.destroy
head :ok
end
def update
@agent.update!(agent_params.except(:role))
@agent.current_account_user.update!(role: agent_params[:role]) if agent_params[:role]
render partial: 'api/v1/models/agent.json.jbuilder', locals: { resource: @agent }
end
def create
render partial: 'api/v1/models/agent.json.jbuilder', locals: { resource: @user }
end
private
def check_authorization
@@ -38,6 +36,8 @@ class Api::V1::Accounts::AgentsController < Api::V1::Accounts::BaseController
@user = User.find_by(email: new_agent_params[:email])
end
# TODO: move this to a builder and combine the save account user method into a builder
# ensure the account user association is also created in a single transaction
def create_user
return if @user
@@ -45,25 +45,33 @@ class Api::V1::Accounts::AgentsController < Api::V1::Accounts::BaseController
end
def save_account_user
AccountUser.create!(
AccountUser.create!({
account_id: Current.account.id,
user_id: @user.id,
role: new_agent_params[:role],
inviter_id: current_user.id
)
}.merge({
role: new_agent_params[:role],
availability: new_agent_params[:availability],
auto_offline: new_agent_params[:auto_offline]
}.compact))
end
def agent_params
params.require(:agent).permit(:email, :name, :role)
params.require(:agent).permit(:name, :email, :name, :role, :availability, :auto_offline)
end
def new_agent_params
time = Time.now.to_i
params.require(:agent).permit(:email, :name, :role)
.merge!(password: time, password_confirmation: time, inviter: current_user)
# intial string ensures the password requirements are met
temp_password = "1!aA#{SecureRandom.alphanumeric(12)}"
params.require(:agent).permit(:email, :name, :role, :availability, :auto_offline)
.merge!(password: temp_password, password_confirmation: temp_password, inviter: current_user)
end
def agents
@agents ||= Current.account.users.order_by_full_name.includes({ 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
@@ -14,7 +14,7 @@ class Api::V1::Accounts::BaseController < Api::BaseController
account = Account.find(params[:account_id])
if current_user
account_accessible_for_user?(account)
elsif @resource&.is_a?(AgentBot)
elsif @resource.is_a?(AgentBot)
account_accessible_for_bot?(account)
end
account
@@ -12,9 +12,10 @@ class Api::V1::Accounts::CallbacksController < Api::V1::Accounts::BaseController
page_access_token: page_access_token
)
@facebook_inbox = Current.account.inboxes.create!(name: inbox_name, channel: facebook_channel)
set_instagram_id(page_access_token, facebook_channel)
set_avatar(@facebook_inbox, page_id)
rescue StandardError => e
Rails.logger.info e
Sentry.capture_exception(e)
end
end
@@ -22,6 +23,15 @@ class Api::V1::Accounts::CallbacksController < Api::V1::Accounts::BaseController
@page_details = mark_already_existing_facebook_pages(fb_object.get_connections('me', 'accounts'))
end
def set_instagram_id(page_access_token, facebook_channel)
fb_object = Koala::Facebook::API.new(page_access_token)
response = fb_object.get_connections('me', '', { fields: 'instagram_business_account' })
return if response['instagram_business_account'].blank?
instagram_id = response['instagram_business_account']['id']
facebook_channel.update(instagram_id: instagram_id)
end
# get params[:inbox_id], current_account. params[:omniauth_token]
def reauthorize_page
if @inbox&.facebook?
@@ -45,8 +55,13 @@ class Api::V1::Accounts::CallbacksController < Api::V1::Accounts::BaseController
def update_fb_page(fb_page_id, access_token)
fb_page = get_fb_page(fb_page_id)
fb_page&.update!(user_access_token: @user_access_token, page_access_token: access_token)
fb_page&.reauthorized!
ActiveRecord::Base.transaction do
fb_page&.update!(user_access_token: @user_access_token, page_access_token: access_token)
set_instagram_id(access_token, fb_page)
fb_page&.reauthorized!
rescue StandardError => e
Sentry.capture_exception(e)
end
end
def get_fb_page(fb_page_id)
@@ -59,7 +74,7 @@ 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
@@ -69,39 +84,15 @@ class Api::V1::Accounts::CallbacksController < Api::V1::Accounts::BaseController
return [] if data.empty?
data.inject([]) do |result, page_detail|
page_detail[:exists] = Current.account.facebook_pages.exists?(page_id: page_detail['id']) ? true : false
page_detail[:exists] = Current.account.facebook_pages.exists?(page_id: page_detail['id'])
result << page_detail
end
end
def set_avatar(facebook_inbox, page_id)
uri = get_avatar_url(page_id)
return unless uri
avatar_resource = LocalResource.new(uri)
facebook_inbox.avatar.attach(io: avatar_resource.file, filename: avatar_resource.tmp_filename, content_type: avatar_resource.encoding)
rescue *ExceptionList::URI_EXCEPTIONS => e
Rails.logger.info "invalid url #{file_url} : #{e.message}"
end
def get_avatar_url(page_id)
begin
url = 'http://graph.facebook.com/' << page_id << '/picture?type=large'
uri = URI.parse(url)
tries = 3
begin
response = uri.open(redirect: false)
rescue OpenURI::HTTPRedirect => e
uri = e.uri # assigned from the "Location" response header
retry if (tries -= 1).positive?
raise
end
pic_url = response.base_uri.to_s
rescue StandardError => e
Rails.logger.debug "Rescued: #{e.inspect}"
pic_url = nil
end
pic_url
avatar_file = Down.download(
"http://graph.facebook.com/#{page_id}/picture?type=large"
)
facebook_inbox.avatar.attach(io: avatar_file, filename: avatar_file.original_filename, content_type: avatar_file.content_type)
end
end
@@ -10,6 +10,11 @@ class Api::V1::Accounts::CampaignsController < Api::V1::Accounts::BaseController
@campaign = Current.account.campaigns.create!(campaign_params)
end
def destroy
@campaign.destroy
head :ok
end
def show; end
def update
@@ -23,6 +28,7 @@ class Api::V1::Accounts::CampaignsController < Api::V1::Accounts::BaseController
end
def campaign_params
params.require(:campaign).permit(:title, :description, :message, :enabled, :inbox_id, :sender_id, trigger_rules: {})
params.require(:campaign).permit(:title, :description, :message, :enabled, :trigger_only_during_business_hours, :inbox_id, :sender_id,
:scheduled_at, audience: [:type, :id], trigger_rules: {})
end
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
@@ -6,9 +6,8 @@ class Api::V1::Accounts::Channels::TwilioChannelsController < Api::V1::Accounts:
authenticate_twilio
build_inbox
setup_webhooks if @twilio_channel.sms?
rescue Twilio::REST::TwilioError => e
render_could_not_create_error(e.message)
rescue StandardError => e
Sentry.capture_exception(e)
render_could_not_create_error(e.message)
end
end
@@ -0,0 +1,9 @@
class Api::V1::Accounts::Contacts::BaseController < Api::V1::Accounts::BaseController
before_action :ensure_contact
private
def ensure_contact
@contact = Current.account.contacts.find(params[:contact_id])
end
end
@@ -1,5 +1,4 @@
class Api::V1::Accounts::Contacts::ContactInboxesController < Api::V1::Accounts::BaseController
before_action :ensure_contact
class Api::V1::Accounts::Contacts::ContactInboxesController < Api::V1::Accounts::Contacts::BaseController
before_action :ensure_inbox, only: [:create]
def create
@@ -11,9 +10,6 @@ class Api::V1::Accounts::Contacts::ContactInboxesController < Api::V1::Accounts:
def ensure_inbox
@inbox = Current.account.inboxes.find(params[:inbox_id])
end
def ensure_contact
@contact = Current.account.contacts.find(params[:contact_id])
authorize @inbox, :show?
end
end
@@ -1,23 +1,17 @@
class Api::V1::Accounts::Contacts::ConversationsController < Api::V1::Accounts::BaseController
class Api::V1::Accounts::Contacts::ConversationsController < Api::V1::Accounts::Contacts::BaseController
def index
@conversations = Current.account.conversations.includes(
:assignee, :contact, :inbox, :taggings
).where(inbox_id: inbox_ids, contact_id: permitted_params[:contact_id])
).where(inbox_id: inbox_ids, contact_id: @contact.id)
end
private
def inbox_ids
if Current.user.administrator?
Current.account.inboxes.pluck(:id)
elsif Current.user.agent?
if Current.user.administrator? || Current.user.agent?
Current.user.assigned_inboxes.pluck(:id)
else
[]
end
end
def permitted_params
params.permit(:contact_id)
end
end
@@ -1,13 +1,13 @@
class Api::V1::Accounts::Contacts::LabelsController < Api::V1::Accounts::BaseController
class Api::V1::Accounts::Contacts::LabelsController < Api::V1::Accounts::Contacts::BaseController
include LabelConcern
private
def model
@model ||= Current.account.contacts.find(permitted_params[:contact_id])
@model ||= @contact
end
def permitted_params
params.permit(:contact_id, labels: [])
params.permit(labels: [])
end
end
@@ -0,0 +1,32 @@
class Api::V1::Accounts::Contacts::NotesController < Api::V1::Accounts::Contacts::BaseController
before_action :note, except: [:index, :create]
def index
@notes = @contact.notes.latest.includes(:user)
end
def create
@note = @contact.notes.create!(note_params)
end
def destroy
@note.destroy
head :ok
end
def show; end
def update
@note.update(note_params)
end
private
def note
@note ||= @contact.notes.find(params[:id])
end
def note_params
params.require(:note).permit(:content).merge({ contact_id: @contact.id, user_id: Current.user.id })
end
end
@@ -1,39 +1,44 @@
class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
include Sift
sort_on :email, type: :string
sort_on :name, type: :string
sort_on :name, internal_name: :order_on_name, type: :scope, scope_params: [:direction]
sort_on :phone_number, type: :string
sort_on :last_activity_at, type: :datetime
sort_on :last_activity_at, internal_name: :order_on_last_activity_at, type: :scope, scope_params: [:direction]
sort_on :company, internal_name: :order_on_company_name, type: :scope, scope_params: [:direction]
sort_on :city, internal_name: :order_on_city, type: :scope, scope_params: [:direction]
sort_on :country, internal_name: :order_on_country_name, type: :scope, scope_params: [:direction]
RESULTS_PER_PAGE = 15
protect_from_forgery with: :null_session
before_action :check_authorization
before_action :set_current_page, only: [:index, :active, :search]
before_action :fetch_contact, only: [:show, :update, :contactable_inboxes]
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, :filter]
def index
@contacts_count = resolved_contacts.count
@contacts = fetch_contact_last_seen_at(resolved_contacts)
@contacts = fetch_contacts_with_conversation_count(resolved_contacts)
end
def search
render json: { error: 'Specify search string with parameter q' }, status: :unprocessable_entity if params[:q].blank? && return
contacts = resolved_contacts.where(
'name ILIKE :search OR email ILIKE :search OR phone_number ILIKE :search',
'name ILIKE :search OR email ILIKE :search OR phone_number ILIKE :search OR contacts.identifier LIKE :search',
search: "%#{params[:q]}%"
)
@contacts_count = contacts.count
@contacts = fetch_contact_last_seen_at(contacts)
@contacts = fetch_contacts_with_conversation_count(contacts)
end
def import
render json: { error: I18n.t('errors.contacts.import.failed') }, status: :unprocessable_entity and return if params[:import_file].blank?
ActiveRecord::Base.transaction do
import = Current.account.data_imports.create!(data_type: 'contacts')
import.import_file.attach(params[:import_file])
end
head :ok
end
@@ -47,8 +52,22 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
def show; end
def filter
result = ::Contacts::FilterService.new(params.permit!, current_user).perform
contacts = result[:contacts]
@contacts_count = result[:count]
@contacts = fetch_contacts_with_conversation_count(contacts)
end
def contactable_inboxes
@contactable_inboxes = Contacts::ContactableInboxesService.new(contact: @contact).get
@all_contactable_inboxes = Contacts::ContactableInboxesService.new(contact: @contact).get
@contactable_inboxes = @all_contactable_inboxes.select { |contactable_inbox| policy(contactable_inbox[:inbox]).show? }
end
# TODO : refactor this method into dedicated contacts/custom_attributes controller class and routes
def destroy_custom_attributes
@contact.custom_attributes = @contact.custom_attributes.excluding(params[:custom_attributes])
@contact.save!
end
def create
@@ -62,31 +81,46 @@ 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
if ::OnlineStatusTracker.get_presence(
@contact.account.id, 'Contact', @contact.id
)
return render_error({ message: I18n.t('contacts.online.delete', contact_name: @contact.name.capitalize) },
:unprocessable_entity)
end
@contact.destroy!
head :ok
end
private
# TODO: Move this to a finder class
def resolved_contacts
@resolved_contacts ||= Current.account.contacts
.where.not(email: [nil, ''])
.or(Current.account.contacts.where.not(phone_number: [nil, '']))
return @resolved_contacts if @resolved_contacts
@resolved_contacts = Current.account.contacts.resolved_contacts
@resolved_contacts = @resolved_contacts.tagged_with(params[:labels], any: true) if params[:labels].present?
@resolved_contacts
end
def set_current_page
@current_page = params[:page] || 1
end
def fetch_contact_last_seen_at(contacts)
filtrate(contacts).left_outer_joins(:conversations)
.select('contacts.*, COUNT(conversations.id) as conversations_count')
.group('contacts.id')
.includes([{ avatar_attachment: [:blob] }, { contact_inboxes: [:inbox] }])
.page(@current_page).per(RESULTS_PER_PAGE)
def fetch_contacts_with_conversation_count(contacts)
contacts_with_conversation_count = filtrate(contacts).left_outer_joins(:conversations)
.select('contacts.*, COUNT(conversations.id) as conversations_count')
.group('contacts.id')
.includes([{ avatar_attachment: [:blob] }])
.page(@current_page).per(RESULTS_PER_PAGE)
return contacts_with_conversation_count.includes([{ contact_inboxes: [:inbox] }]) if @include_contact_inboxes
contacts_with_conversation_count
end
def build_contact_inbox
@@ -98,7 +132,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
end
def contact_params
params.require(:contact).permit(:name, :email, :phone_number, additional_attributes: {}, custom_attributes: {})
params.require(:contact).permit(:name, :identifier, :email, :phone_number, additional_attributes: {}, custom_attributes: {})
end
def contact_custom_attributes
@@ -112,7 +146,19 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
contact_params.except(:custom_attributes).merge({ custom_attributes: contact_custom_attributes })
end
def set_include_contact_inboxes
@include_contact_inboxes = if params[:include_contact_inboxes].present?
params[:include_contact_inboxes] == 'true'
else
true
end
end
def fetch_contact
@contact = Current.account.contacts.includes(contact_inboxes: [:inbox]).find(params[:id])
end
def render_error(error, error_status)
render json: error, status: error_status
end
end
@@ -1,20 +1,34 @@
class Api::V1::Accounts::Conversations::AssignmentsController < Api::V1::Accounts::Conversations::BaseController
# assigns agent/team to a conversation
def create
set_assignee
render json: @assignee
if params.key?(:assignee_id)
set_agent
elsif params.key?(:team_id)
set_team
else
render json: nil
end
end
private
def set_assignee
# if params[:assignee_id] is not a valid id, it will set to nil, hence unassigning the conversation
if params.key?(:assignee_id)
@assignee = Current.account.users.find_by(id: params[:assignee_id])
@conversation.update_assignee(@assignee)
elsif params.key?(:team_id)
@assignee = Current.account.teams.find_by(id: params[:team_id])
@conversation.update!(team: @assignee)
def set_agent
@agent = Current.account.users.find_by(id: params[:assignee_id])
@conversation.update_assignee(@agent)
render_agent
end
def render_agent
if @agent.nil?
render json: nil
else
render partial: 'api/v1/models/agent', formats: [:json], locals: { resource: @agent }
end
end
def set_team
@team = Current.account.teams.find_by(id: params[:team_id])
@conversation.update!(team: @team)
render json: @team
end
end
@@ -5,5 +5,6 @@ class Api::V1::Accounts::Conversations::BaseController < Api::V1::Accounts::Base
def conversation
@conversation ||= Current.account.conversations.find_by(display_id: params[:conversation_id])
authorize @conversation.inbox, :show?
end
end
@@ -1,7 +1,8 @@
class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseController
include Events::Types
include DateRangeHelper
before_action :conversation, except: [:index]
before_action :conversation, except: [:index, :meta, :search, :create, :filter]
before_action :contact_inbox, only: [:create]
def index
@@ -30,6 +31,12 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
def show; end
def filter
result = ::Conversations::FilterService.new(params.permit!, current_user).perform
@conversations = result[:conversations]
@conversations_count = result[:count]
end
def mute
@conversation.mute!
head :ok
@@ -41,14 +48,16 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
end
def transcript
ConversationReplyMailer.conversation_transcript(@conversation, params[:email])&.deliver_later if params[:email].present?
render json: { error: 'email param missing' }, status: :unprocessable_entity and return if params[:email].blank?
ConversationReplyMailer.with(account: @conversation.account).conversation_transcript(@conversation, params[:email])&.deliver_later
head :ok
end
def toggle_status
if params[:status]
@conversation.status = params[:status]
@status = @conversation.save
set_conversation_status
@status = @conversation.save!
else
@status = @conversation.toggle_status
end
@@ -57,57 +66,88 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
def toggle_typing_status
case params[:typing_status]
when 'on'
trigger_typing_event(CONVERSATION_TYPING_ON)
trigger_typing_event(CONVERSATION_TYPING_ON, params[:is_private])
when 'off'
trigger_typing_event(CONVERSATION_TYPING_OFF)
trigger_typing_event(CONVERSATION_TYPING_OFF, params[:is_private])
end
head :ok
end
def update_last_seen
@conversation.agent_last_seen_at = DateTime.now.utc
# 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
@conversation.custom_attributes = params.permit(custom_attributes: {})[:custom_attributes]
@conversation.save!
end
private
def trigger_typing_event(event)
def set_conversation_status
status = params[:status] == 'bot' ? 'pending' : params[:status]
@conversation.status = status
@conversation.snoozed_until = parse_date_time(params[:snoozed_until].to_s) if params[:snoozed_until]
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)
Rails.configuration.dispatcher.dispatch(event, Time.zone.now, conversation: @conversation, user: user, is_private: is_private)
end
def conversation
@conversation ||= Current.account.conversations.find_by(display_id: params[:id])
@conversation ||= Current.account.conversations.find_by!(display_id: params[:id])
authorize @conversation.inbox, :show?
end
def contact_inbox
@contact_inbox = build_contact_inbox
@contact_inbox ||= ::ContactInbox.find_by!(source_id: params[:source_id])
authorize @contact_inbox.inbox, :show?
end
def build_contact_inbox
return if params[:contact_id].blank? || params[:inbox_id].blank?
inbox = Current.account.inboxes.find(params[:inbox_id])
authorize inbox, :show?
ContactInboxBuilder.new(
contact_id: params[:contact_id],
inbox_id: params[:inbox_id],
inbox_id: inbox.id,
source_id: params[:source_id]
).perform
end
def conversation_params
additional_attributes = params[:additional_attributes]&.permit! || {}
custom_attributes = params[:custom_attributes]&.permit! || {}
status = params[:status].present? ? { status: params[:status] } : {}
# TODO: temporary fallback for the old bot status in conversation, we will remove after couple of releases
status = { status: 'pending' } if status[:status] == 'bot'
{
account_id: Current.account.id,
inbox_id: @contact_inbox.inbox_id,
contact_id: @contact_inbox.contact_id,
contact_inbox_id: @contact_inbox.id,
additional_attributes: additional_attributes
}
additional_attributes: additional_attributes,
custom_attributes: custom_attributes,
snoozed_until: params[:snoozed_until],
assignee_id: params[:assignee_id],
team_id: params[:team_id]
}.merge(status)
end
def conversation_finder
@conversation_finder ||= ConversationFinder.new(current_user, params)
end
def assignee?
@conversation.assignee_id? && current_user == @conversation.assignee
end
end
@@ -0,0 +1,44 @@
class Api::V1::Accounts::CsatSurveyResponsesController < Api::V1::Accounts::BaseController
include Sift
include DateRangeHelper
RESULTS_PER_PAGE = 25
before_action :check_authorization
before_action :set_csat_survey_responses, only: [:index, :metrics]
before_action :set_current_page, only: [:index]
before_action :set_current_page_surveys, only: [:index]
before_action :set_total_sent_messages_count, only: [:metrics]
sort_on :created_at, type: :datetime
def index; end
def metrics
@total_count = @csat_survey_responses.count
@ratings_count = @csat_survey_responses.group(:rating).count
end
private
def set_total_sent_messages_count
@csat_messages = Current.account.messages.input_csat
@csat_messages = @csat_messages.where(created_at: range) if range.present?
@total_sent_messages_count = @csat_messages.count
end
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?
end
def set_current_page_surveys
@csat_survey_responses = @csat_survey_responses.page(@current_page).per(RESULTS_PER_PAGE)
end
def set_current_page
@current_page = params[:page] || 1
end
end
@@ -0,0 +1,49 @@
class Api::V1::Accounts::CustomAttributeDefinitionsController < Api::V1::Accounts::BaseController
before_action :fetch_custom_attributes_definitions, except: [:create]
before_action :fetch_custom_attribute_definition, only: [:show, :update, :destroy]
DEFAULT_ATTRIBUTE_MODEL = 'conversation_attribute'.freeze
def index; end
def show; end
def create
@custom_attribute_definition = Current.account.custom_attribute_definitions.create!(
permitted_payload
)
end
def update
@custom_attribute_definition.update!(permitted_payload)
end
def destroy
@custom_attribute_definition.destroy
head :no_content
end
private
def fetch_custom_attributes_definitions
@custom_attribute_definitions = Current.account.custom_attribute_definitions.with_attribute_model(permitted_params[:attribute_model])
end
def fetch_custom_attribute_definition
@custom_attribute_definition = Current.account.custom_attribute_definitions.find(permitted_params[:id])
end
def permitted_payload
params.require(:custom_attribute_definition).permit(
:attribute_display_name,
:attribute_description,
:attribute_display_type,
:attribute_key,
:attribute_model,
attribute_values: []
)
end
def permitted_params
params.permit(:id, :filter_type, :attribute_model)
end
end
@@ -0,0 +1,49 @@
class Api::V1::Accounts::CustomFiltersController < Api::V1::Accounts::BaseController
before_action :fetch_custom_filters, except: [:create]
before_action :fetch_custom_filter, only: [:show, :update, :destroy]
DEFAULT_FILTER_TYPE = 'conversation'.freeze
def index; end
def show; end
def create
@custom_filter = current_user.custom_filters.create!(
permitted_payload.merge(account_id: Current.account.id)
)
end
def update
@custom_filter.update!(permitted_payload)
end
def destroy
@custom_filter.destroy
head :no_content
end
private
def fetch_custom_filters
@custom_filters = current_user.custom_filters.where(
account_id: Current.account.id,
filter_type: permitted_params[:filter_type] || DEFAULT_FILTER_TYPE
)
end
def fetch_custom_filter
@custom_filter = @custom_filters.find(permitted_params[:id])
end
def permitted_payload
params.require(:custom_filter).permit(
:name,
:filter_type,
query: {}
)
end
def permitted_params
params.permit(:id, :filter_type)
end
end
@@ -1,55 +0,0 @@
class Api::V1::Accounts::FacebookIndicatorsController < Api::V1::Accounts::BaseController
before_action :set_access_token
around_action :handle_with_exception
def mark_seen
fb_bot.deliver(payload('mark_seen'), access_token: @access_token)
head :ok
end
def typing_on
fb_bot.deliver(payload('typing_on'), access_token: @access_token)
head :ok
end
def typing_off
fb_bot.deliver(payload('typing_off'), access_token: @access_token)
head :ok
end
private
def fb_bot
::Facebook::Messenger::Bot
end
def handle_with_exception
yield
rescue Facebook::Messenger::Error => e
Rails.logger.debug "Rescued: #{e.inspect}"
true
end
def payload(action)
{
recipient: { id: contact.source_id },
sender_action: action
}
end
def inbox
@inbox ||= Current.account.inboxes.find(permitted_params[:inbox_id])
end
def set_access_token
@access_token = inbox.channel.page_access_token
end
def contact
@contact ||= inbox.contact_inboxes.find_by!(contact_id: permitted_params[:contact_id])
end
def permitted_params
params.permit(:inbox_id, :contact_id)
end
end
@@ -1,22 +1,40 @@
class Api::V1::Accounts::InboxMembersController < Api::V1::Accounts::BaseController
before_action :fetch_inbox, only: [:create, :show]
before_action :current_agents_ids, only: [:create]
before_action :fetch_inbox
before_action :current_agents_ids, only: [:create, :update]
def create
# update also done via same action
update_agents_list
head :ok
rescue StandardError => e
Rails.logger.debug "Rescued: #{e.inspect}"
render_could_not_create_error('Could not add agents to inbox')
authorize @inbox, :create?
ActiveRecord::Base.transaction do
agents_to_be_added_ids.map { |user_id| @inbox.add_member(user_id) }
end
fetch_updated_agents
end
def show
@agents = Current.account.users.where(id: @inbox.members.select(:user_id))
authorize @inbox, :show?
fetch_updated_agents
end
def update
authorize @inbox, :update?
update_agents_list
fetch_updated_agents
end
def destroy
authorize @inbox, :destroy?
ActiveRecord::Base.transaction do
params[:user_ids].map { |user_id| @inbox.remove_member(user_id) }
end
head :ok
end
private
def fetch_updated_agents
@agents = Current.account.users.where(id: @inbox.members.select(:user_id))
end
def update_agents_list
# get all the user_ids which the inbox currently has as members.
# get the list of user_ids from params
@@ -1,12 +1,16 @@
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 :check_authorization
# we are already handling the authorization in fetch inbox
before_action :check_authorization, except: [:show]
def index
@inboxes = policy_scope(Current.account.inboxes.order_by_name.includes(:channel, { avatar_attachment: [:blob] }))
end
def show; end
def assignable_agents
@assignable_agents = (Current.account.users.where(id: @inbox.members.select(:user_id)) + Current.account.administrators).uniq
end
@@ -15,29 +19,44 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
@campaigns = @inbox.campaigns
end
def avatar
@inbox.avatar.attachment.destroy! if @inbox.avatar.attached?
head :ok
end
def create
ActiveRecord::Base.transaction do
channel = create_channel
@inbox = Current.account.inboxes.build(
name: permitted_params[:name],
greeting_message: permitted_params[:greeting_message],
greeting_enabled: permitted_params[:greeting_enabled],
channel: channel
{
name: inbox_name(channel),
channel: channel
}.merge(
permitted_params.except(:channel)
)
)
@inbox.avatar.attach(permitted_params[:avatar])
@inbox.save!
end
end
def update
@inbox.update(inbox_update_params.except(:channel))
@inbox.update(permitted_params.except(:channel))
@inbox.update_working_hours(params.permit(working_hours: Inbox::OFFISABLE_ATTRS)[:working_hours]) if params[:working_hours]
return unless @inbox.channel.is_a?(Channel::WebWidget) && inbox_update_params[:channel].present?
channel_attributes = get_channel_attributes(@inbox.channel_type)
@inbox.channel.update!(inbox_update_params[:channel])
# Inbox update doesn't necessarily need channel attributes
return if permitted_params(channel_attributes)[:channel].blank?
validate_email_channel(channel_attributes) if @inbox.inbox_type == 'Email'
@inbox.channel.update!(permitted_params(channel_attributes)[:channel])
update_channel_feature_flags
end
def agent_bot
@agent_bot = @inbox.agent_bot
end
def set_agent_bot
if @agent_bot
agent_bot_inbox = @inbox.agent_bot_inbox || AgentBotInbox.new(inbox: @inbox)
@@ -58,49 +77,57 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
def fetch_inbox
@inbox = Current.account.inboxes.find(params[:id])
authorize @inbox, :show?
end
def fetch_agent_bot
@agent_bot = AgentBot.find(params[:agent_bot]) if params[:agent_bot]
end
def inbox_name(channel)
return channel.try(:bot_name) if channel.is_a?(Channel::Telegram)
permitted_params[:name]
end
def create_channel
case permitted_params[:channel][:type]
when 'web_widget'
Current.account.web_widgets.create!(permitted_params[:channel].except(:type))
Current.account.web_widgets.create!(permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel].except(:type))
when 'api'
Current.account.api_channels.create!(permitted_params[:channel].except(:type))
Current.account.api_channels.create!(permitted_params(Channel::Api::EDITABLE_ATTRS)[:channel].except(:type))
when 'email'
Current.account.email_channels.create!(permitted_params[:channel].except(:type))
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
end
def update_channel_feature_flags
return unless inbox_update_params[:channel].key? :selected_feature_flags
return unless @inbox.web_widget?
return unless permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel].key? :selected_feature_flags
@inbox.channel.selected_feature_flags = inbox_update_params[:channel][:selected_feature_flags]
@inbox.channel.selected_feature_flags = permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel][:selected_feature_flags]
@inbox.channel.save!
end
def permitted_params
params.permit(:id, :avatar, :name, :greeting_message, :greeting_enabled, channel:
[:type, :website_url, :widget_color, :welcome_title, :welcome_tagline, :webhook_url, :email, :reply_time])
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,
channel: [:type, *channel_attributes]
)
end
def inbox_update_params
params.permit(:enable_auto_assignment, :name, :avatar, :greeting_message, :greeting_enabled,
:working_hours_enabled, :out_of_office_message, :timezone,
channel: [
:website_url,
:widget_color,
:welcome_title,
:welcome_tagline,
:webhook_url,
:email,
:reply_time,
:pre_chat_form_enabled,
{ pre_chat_form_options: [:pre_chat_message, :require_email] },
{ selected_feature_flags: [] }
])
def get_channel_attributes(channel_type)
if channel_type.constantize.const_defined?('EDITABLE_ATTRS')
channel_type.constantize::EDITABLE_ATTRS.presence
else
[]
end
end
end
@@ -1,4 +1,5 @@
class Api::V1::Accounts::Integrations::AppsController < Api::V1::Accounts::BaseController
before_action :check_admin_authorization?
before_action :fetch_apps, only: [:index]
before_action :fetch_app, only: [:show]
@@ -1,4 +1,5 @@
class Api::V1::Accounts::Integrations::SlackController < Api::V1::Accounts::BaseController
before_action :check_admin_authorization?
before_action :fetch_hook, only: [:update, :destroy]
def create
@@ -1,7 +1,6 @@
class Api::V1::Accounts::NotificationsController < Api::V1::Accounts::BaseController
RESULTS_PER_PAGE = 15
protect_from_forgery with: :null_session
before_action :fetch_notification, only: [:update]
before_action :set_primary_actor, only: [:read_all]
before_action :set_current_page, only: [:index]
@@ -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
@@ -1,7 +1,6 @@
class Api::V1::AccountsController < Api::BaseController
include AuthHelper
skip_before_action :verify_authenticity_token, only: [:create]
skip_before_action :authenticate_user!, :set_current_user, :handle_with_exception,
only: [:create], raise: false
before_action :check_signup_enabled, only: [:create]
@@ -18,7 +17,7 @@ class Api::V1::AccountsController < Api::BaseController
account_name: account_params[:account_name],
user_full_name: account_params[:user_full_name],
email: account_params[:email],
confirmed: confirmed?,
user_password: account_params[:password],
user: current_user
).perform
if @user
@@ -46,21 +45,17 @@ class Api::V1::AccountsController < Api::BaseController
private
def confirmed?
super_admin? && params[:confirmed]
end
def fetch_account
@account = current_user.accounts.find(params[:id])
@current_account_user = @account.account_users.find_by(user_id: current_user.id)
end
def account_params
params.permit(:account_name, :email, :name, :locale, :domain, :support_email, :auto_resolve_duration, :user_full_name)
params.permit(:account_name, :email, :name, :password, :locale, :domain, :support_email, :auto_resolve_duration, :user_full_name)
end
def check_signup_enabled
raise ActionController::RoutingError, 'Not Found' if ENV.fetch('ENABLE_ACCOUNT_SIGNUP', true) == 'false'
raise ActionController::RoutingError, 'Not Found' if GlobalConfig.get_value('ENABLE_ACCOUNT_SIGNUP') == 'false'
end
def pundit_user
@@ -1,7 +0,0 @@
class Api::V1::AgentBotsController < Api::BaseController
skip_before_action :authenticate_user!
def index
render json: AgentBot.all
end
end
+28 -6
View File
@@ -1,30 +1,52 @@
class Api::V1::ProfilesController < Api::BaseController
before_action :set_user
def show
render partial: 'api/v1/models/user.json.jbuilder', locals: { resource: @user }
end
def show; end
def update
if password_params[:password].present?
render_could_not_create_error('Invalid current password') and return unless @user.valid_password?(password_params[:current_password])
@user.update!(password_params.except(:current_password))
end
@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
private
def set_user
@user = current_user
end
def availability_params
params.require(:profile).permit(:account_id, :availability)
end
def profile_params
params.require(:profile).permit(
:email,
:name,
:display_name,
:password,
:password_confirmation,
:avatar,
:availability,
ui_settings: {}
)
end
def password_params
params.require(:profile).permit(
:current_password,
:password,
:password_confirmation
)
end
end
@@ -10,7 +10,7 @@ class Api::V1::WebhooksController < ApplicationController
twitter_consumer.consume
head :ok
rescue StandardError => e
Raven.capture_exception(e)
Sentry.capture_exception(e)
head :ok
end
@@ -94,6 +94,10 @@ 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,
@@ -4,10 +4,4 @@ class Api::V1::Widget::CampaignsController < Api::V1::Widget::BaseController
def index
@campaigns = @web_widget.inbox.campaigns.where(enabled: true)
end
private
def permitted_params
params.permit(:website_token)
end
end
@@ -0,0 +1,41 @@
class Api::V1::Widget::ConfigsController < Api::V1::Widget::BaseController
before_action :set_global_config
def create
build_contact
set_token
end
private
def set_global_config
@global_config = GlobalConfig.get('LOGO_THUMBNAIL', 'BRAND_NAME', 'WIDGET_BRAND_URL')
end
def set_contact
@contact_inbox = @web_widget.inbox.contact_inboxes.find_by(
source_id: auth_token_params[:source_id]
)
@contact = @contact_inbox&.contact
end
def build_contact
return if @contact.present?
@contact_inbox = @web_widget.create_contact_inbox(additional_attributes)
@contact = @contact_inbox.contact
end
def set_token
payload = { source_id: @contact_inbox.source_id, inbox_id: @web_widget.inbox.id }
@token = ::Widget::TokenService.new(payload: payload).generate_token
end
def additional_attributes
if @web_widget.inbox.account.feature_enabled?('ip_lookup')
{ created_at_ip: request.remote_ip }
else
{}
end
end
end
@@ -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,18 +8,35 @@ 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
def destroy_custom_attributes
@contact.custom_attributes = @contact.custom_attributes.excluding(params[:custom_attributes])
@contact.save!
render json: @contact
end
private
def process_hmac
return if params[:identifier_hash].blank?
raise StandardError, 'HMAC failed: Invalid Identifier Hash Provided' unless valid_hmac?
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',
@@ -29,6 +46,6 @@ class Api::V1::Widget::ContactsController < Api::V1::Widget::BaseController
end
def permitted_params
params.permit(:website_token, :identifier, :identifier_hash, :email, :name, :avatar_url, custom_attributes: {})
params.permit(:website_token, :identifier, :identifier_hash, :email, :name, :avatar_url, :phone_number, custom_attributes: {})
end
end
@@ -23,7 +23,7 @@ class Api::V1::Widget::ConversationsController < Api::V1::Widget::BaseController
def transcript
if permitted_params[:email].present? && conversation.present?
ConversationReplyMailer.conversation_transcript(
ConversationReplyMailer.with(account: conversation.account).conversation_transcript(
conversation,
permitted_params[:email]
)&.deliver_later
@@ -4,10 +4,4 @@ class Api::V1::Widget::InboxMembersController < Api::V1::Widget::BaseController
def index
@inbox_members = @web_widget.inbox.inbox_members.includes(:user)
end
private
def permitted_params
params.permit(:website_token)
end
end
@@ -8,8 +8,8 @@ class Api::V1::Widget::MessagesController < Api::V1::Widget::BaseController
def create
@message = conversation.messages.new(message_params)
@message.save
build_attachment
@message.save!
end
def update
@@ -20,7 +20,7 @@ class Api::V1::Widget::MessagesController < Api::V1::Widget::BaseController
@message.update!(message_update_params[:message])
end
rescue StandardError => e
render json: { error: @contact.errors, message: e.message }.to_json, status: 500
render json: { error: @contact.errors, message: e.message }.to_json, status: :internal_server_error
end
private
@@ -29,13 +29,12 @@ class Api::V1::Widget::MessagesController < Api::V1::Widget::BaseController
return if params[:message][:attachments].blank?
params[:message][:attachments].each do |uploaded_attachment|
attachment = @message.attachments.new(
@message.attachments.new(
account_id: @message.account_id,
file_type: helpers.file_type(uploaded_attachment&.content_type)
file_type: helpers.file_type(uploaded_attachment&.content_type),
file: uploaded_attachment
)
attachment.file.attach(uploaded_attachment)
end
@message.save!
end
def set_conversation
@@ -54,10 +53,11 @@ class Api::V1::Widget::MessagesController < Api::V1::Widget::BaseController
end
def message_update_params
params.permit(message: [{ submitted_values: [:name, :title, :value] }])
params.permit(message: [{ submitted_values: [:name, :title, :value, { csat_survey_response: [:feedback_message, :rating] }] }])
end
def permitted_params
# timestamp parameter is used in create conversation method
params.permit(:id, :before, :website_token, contact: [:name, :email], message: [:content, :referer_url, :timestamp, :echo_id])
end
@@ -1,12 +1,14 @@
class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
def account
builder = V2::ReportBuilder.new(Current.account, account_report_params)
before_action :check_authorization
def index
builder = V2::ReportBuilder.new(Current.account, report_params)
data = builder.build
render json: data
end
def account_summary
render json: account_summary_metrics
def summary
render json: summary_metrics
end
def agents
@@ -21,27 +23,45 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
render layout: false, template: 'api/v2/accounts/reports/inboxes.csv.erb', format: 'csv'
end
def labels
response.headers['Content-Type'] = 'text/csv'
response.headers['Content-Disposition'] = 'attachment; filename=labels_report.csv'
render layout: false, template: 'api/v2/accounts/reports/labels.csv.erb', format: 'csv'
end
def teams
response.headers['Content-Type'] = 'text/csv'
response.headers['Content-Disposition'] = 'attachment; filename=teams_report.csv'
render layout: false, template: 'api/v2/accounts/reports/teams.csv.erb', format: 'csv'
end
private
def account_summary_params
def check_authorization
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
end
def summary_params
{
type: :account,
type: params[:type].to_sym,
since: params[:since],
until: params[:until]
until: params[:until],
id: params[:id]
}
end
def account_report_params
def report_params
{
metric: params[:metric],
type: :account,
type: params[:type].to_sym,
since: params[:since],
until: params[:until]
until: params[:until],
id: params[:id]
}
end
def account_summary_metrics
builder = V2::ReportBuilder.new(Current.account, account_summary_params)
def summary_metrics
builder = V2::ReportBuilder.new(Current.account, summary_params)
builder.summary
end
end
+2 -42
View File
@@ -1,31 +1,17 @@
class ApplicationController < ActionController::Base
include DeviseTokenAuth::Concerns::SetUserByToken
include RequestExceptionHandler
include Pundit
include SwitchLocale
protect_from_forgery with: :null_session
skip_before_action :verify_authenticity_token
before_action :set_current_user, unless: :devise_controller?
around_action :switch_locale
around_action :handle_with_exception, unless: :devise_controller?
# after_action :verify_authorized
rescue_from ActiveRecord::RecordInvalid, with: :render_record_invalid
private
def handle_with_exception
yield
rescue ActiveRecord::RecordNotFound => e
Raven.capture_exception(e)
render_not_found_error('Resource could not be found')
rescue Pundit::NotAuthorizedError
render_unauthorized('You are not authorized to do this action')
ensure
# to address the thread variable leak issues in Puma/Thin webserver
Current.reset
end
def set_current_user
@user ||= current_user
Current.user = @user
@@ -35,32 +21,6 @@ class ApplicationController < ActionController::Base
@subscription ||= Current.account.subscription
end
def render_unauthorized(message)
render json: { error: message }, status: :unauthorized
end
def render_not_found_error(message)
render json: { error: message }, status: :not_found
end
def render_could_not_create_error(message)
render json: { error: message }, status: :unprocessable_entity
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(', ')
}, status: :unprocessable_entity
end
def render_error_response(exception)
render json: exception.to_hash, status: exception.http_status
end
def pundit_user
{
user: Current.user,
@@ -17,13 +17,8 @@ module AccessTokenAuthHelper
Current.user = @resource if current_user.is_a?(User)
end
def super_admin?
@resource.present? && @resource.is_a?(SuperAdmin)
end
def validate_bot_access_token!
return if Current.user.is_a?(User)
return if super_admin?
return if agent_bot_accessible?
render_unauthorized('Access to this endpoint is not authorized for bots')
+2 -2
View File
@@ -1,8 +1,8 @@
module AuthHelper
def send_auth_headers(user)
data = user.create_new_auth_token
response.headers[DeviseTokenAuth.headers_names[:"access-token"]] = data['access-token']
response.headers[DeviseTokenAuth.headers_names[:"token-type"]] = 'Bearer'
response.headers[DeviseTokenAuth.headers_names[:'access-token']] = data['access-token']
response.headers[DeviseTokenAuth.headers_names[:'token-type']] = 'Bearer'
response.headers[DeviseTokenAuth.headers_names[:client]] = data['client']
response.headers[DeviseTokenAuth.headers_names[:expiry]] = data['expiry']
response.headers[DeviseTokenAuth.headers_names[:uid]] = data['uid']
@@ -0,0 +1,52 @@
module RequestExceptionHandler
extend ActiveSupport::Concern
included do
rescue_from ActiveRecord::RecordInvalid, with: :render_record_invalid
end
private
def handle_with_exception
yield
rescue ActiveRecord::RecordNotFound => e
Sentry.capture_exception(e)
render_not_found_error('Resource could not be found')
rescue Pundit::NotAuthorizedError
render_unauthorized('You are not authorized to do this action')
ensure
# to address the thread variable leak issues in Puma/Thin webserver
Current.reset
end
def render_unauthorized(message)
render json: { error: message }, status: :unauthorized
end
def render_not_found_error(message)
render json: { error: message }, status: :not_found
end
def render_could_not_create_error(message)
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(', '),
attributes: exception.record.errors.attribute_names
}, status: :unprocessable_entity
end
def render_error_response(exception)
render json: exception.to_hash, status: exception.http_status
end
end
+13 -4
View File
@@ -21,13 +21,22 @@ class DashboardController < ActionController::Base
'PRIVACY_URL',
'DISPLAY_MANIFEST',
'CREATE_NEW_ACCOUNT_FROM_DASHBOARD',
'CHATWOOT_INBOX_TOKEN'
).merge(
APP_VERSION: Chatwoot.config[:version]
)
'CHATWOOT_INBOX_TOKEN',
'API_CHANNEL_NAME',
'API_CHANNEL_THUMBNAIL',
'ANALYTICS_TOKEN',
'ANALYTICS_HOST'
).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
@@ -1,42 +1,34 @@
class DeviseOverrides::ConfirmationsController < Devise::ConfirmationsController
include AuthHelper
skip_before_action :require_no_authentication, raise: false
skip_before_action :authenticate_user!, raise: false
def create
@confirmable = User.find_by(confirmation_token: params[:confirmation_token])
render_confirmation_success and return if @confirmable&.confirm
if confirm
render_confirmation_success
else
render_confirmation_error
end
render_confirmation_error
end
protected
def confirm
@confirmable&.confirm || (@confirmable&.confirmed_at && @confirmable&.reset_password_token)
end
private
def render_confirmation_success
render json: { "message": 'Success', "redirect_url": create_reset_token_link(@confirmable) }, status: :ok
send_auth_headers(@confirmable)
render partial: 'devise/auth.json', locals: { resource: @confirmable }
end
def render_confirmation_error
if @confirmable.blank?
render json: { "message": 'Invalid token', "redirect_url": '/' }, status: 422
render json: { message: 'Invalid token', redirect_url: '/' }, status: :unprocessable_entity
elsif @confirmable.confirmed_at
render json: { "message": 'Already confirmed', "redirect_url": '/' }, status: 422
render json: { message: 'Already confirmed', redirect_url: '/' }, status: :unprocessable_entity
else
render json: { "message": 'Failure', "redirect_url": '/' }, status: 422
render json: { message: 'Failure', redirect_url: '/' }, status: :unprocessable_entity
end
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
@@ -13,7 +13,7 @@ class DeviseOverrides::PasswordsController < Devise::PasswordsController
send_auth_headers(@recoverable)
render partial: 'devise/auth.json', locals: { resource: @recoverable }
else
render json: { "message": 'Invalid token', "redirect_url": '/' }, status: 422
render json: { message: 'Invalid token', redirect_url: '/' }, status: :unprocessable_entity
end
end
@@ -27,7 +27,7 @@ class DeviseOverrides::PasswordsController < Devise::PasswordsController
end
end
protected
private
def reset_password_and_confirmation(recoverable)
recoverable.confirm unless recoverable.confirmed? # confirm if user resets password without confirming anytime before
@@ -40,7 +40,7 @@ class DeviseOverrides::PasswordsController < Devise::PasswordsController
def build_response(message, status)
render json: {
"message": message
message: message
}, status: status
end
end
@@ -27,7 +27,13 @@ class Installation::OnboardingController < ApplicationController
def finish_onboarding
::Redis::Alfred.delete(::Redis::Alfred::CHATWOOT_INSTALLATION_ONBOARDING)
ChatwootHub.register_instance(onboarding_params) if onboarding_params[:subscribe_to_updates]
return if onboarding_params[:subscribe_to_updates].blank?
ChatwootHub.register_instance(
onboarding_params.dig(:user, :company),
onboarding_params.dig(:user, :name),
onboarding_params.dig(:user, :email)
)
end
def ensure_installation_onboarding
@@ -16,7 +16,7 @@ class Platform::Api::V1::AccountsController < PlatformController
end
def destroy
# TODO: obfusicate account
DeleteObjectJob.perform_later(@resource)
head :ok
end
@@ -0,0 +1,35 @@
class Platform::Api::V1::AgentBotsController < PlatformController
before_action :set_resource, except: [:index, :create]
before_action :validate_platform_app_permissible, except: [:index, :create]
def index
@resources = @platform_app.platform_app_permissibles.where(permissible_type: 'AgentBot').all
end
def create
@resource = AgentBot.new(agent_bot_params)
@resource.save!
@platform_app.platform_app_permissibles.find_or_create_by(permissible: @resource)
end
def show; end
def update
@resource.update!(agent_bot_params)
end
def destroy
@resource.destroy!
head :ok
end
private
def set_resource
@resource = AgentBot.find(params[:id])
end
def agent_bot_params
params.permit(:name, :description, :account_id, :outgoing_url)
end
end
@@ -7,8 +7,8 @@ class Platform::Api::V1::UsersController < PlatformController
def create
@resource = (User.find_by(email: user_params[:email]) || User.new(user_params))
@resource.confirm
@resource.save!
@resource.confirm
@platform_app.platform_app_permissibles.find_or_create_by(permissible: @resource)
end
@@ -19,21 +19,33 @@ class Platform::Api::V1::UsersController < PlatformController
def show; end
def update
@resource.update!(user_params)
@resource.assign_attributes(user_update_params)
@resource.save!
end
def destroy
# TODO: obfusicate user
DeleteObjectJob.perform_later(@resource)
head :ok
end
private
def user_custom_attributes
return @resource.custom_attributes.merge(user_params[:custom_attributes]) if user_params[:custom_attributes]
@resource.custom_attributes
end
def user_update_params
# we want the merged custom attributes not the original one
user_params.except(:custom_attributes).merge({ custom_attributes: user_custom_attributes })
end
def set_resource
@resource = User.find(params[:id])
end
def user_params
params.permit(:name, :email, :password)
params.permit(:name, :email, :password, custom_attributes: {})
end
end
+2 -2
View File
@@ -1,5 +1,5 @@
class PlatformController < ActionController::Base
protect_from_forgery with: :null_session
class PlatformController < ActionController::API
include RequestExceptionHandler
before_action :ensure_access_token
before_action :set_platform_app
@@ -0,0 +1,32 @@
class Public::Api::V1::CsatSurveyController < PublicController
before_action :set_conversation
before_action :set_message
def show; end
def update
render json: { error: 'You cannot update the CSAT survey after 14 days' }, status: :unprocessable_entity and return if check_csat_locked
@message.update!(message_update_params[:message])
end
private
def set_conversation
return if params[:id].blank?
@conversation = Conversation.find_by!(uuid: params[:id])
end
def set_message
@message = @conversation.messages.find_by!(content_type: 'input_csat')
end
def message_update_params
params.permit(message: [{ submitted_values: [:name, :title, :value, { csat_survey_response: [:feedback_message, :rating] }] }])
end
def check_csat_locked
(Time.zone.now.to_date - @message.created_at.to_date).to_i > 14
end
end
@@ -0,0 +1,48 @@
class Public::Api::V1::Inboxes::ContactsController < Public::Api::V1::InboxesController
before_action :contact_inbox, except: [:create]
before_action :process_hmac
def create
source_id = params[:source_id] || SecureRandom.uuid
@contact_inbox = ::ContactBuilder.new(
source_id: source_id,
inbox: @inbox_channel.inbox,
contact_attributes: permitted_params.except(:identifier, :identifier_hash)
).perform
end
def show; end
def update
contact_identify_action = ContactIdentifyAction.new(
contact: @contact_inbox.contact,
params: permitted_params.to_h.deep_symbolize_keys.except(:identifier)
)
render json: contact_identify_action.perform
end
private
def contact_inbox
@contact_inbox = @inbox_channel.inbox.contact_inboxes.find_by!(source_id: params[:id])
end
def process_hmac
return if params[:identifier_hash].blank? && !@inbox_channel.hmac_mandatory
raise StandardError, 'HMAC failed: Invalid Identifier Hash Provided' unless valid_hmac?
@contact_inbox.update(hmac_verified: true) if @contact_inbox.present?
end
def valid_hmac?
params[:identifier_hash] == OpenSSL::HMAC.hexdigest(
'sha256',
@inbox_channel.hmac_token,
params[:identifier].to_s
)
end
def permitted_params
params.permit(:identifier, :identifier_hash, :email, :name, :avatar_url, custom_attributes: {})
end
end
@@ -0,0 +1,24 @@
class Public::Api::V1::Inboxes::ConversationsController < Public::Api::V1::InboxesController
def index
@conversations = @contact_inbox.hmac_verified? ? @contact.conversations : @contact_inbox.conversations
end
def create
@conversation = create_conversation
end
private
def create_conversation
::Conversation.create!(conversation_params)
end
def conversation_params
{
account_id: @contact_inbox.contact.account_id,
inbox_id: @contact_inbox.inbox_id,
contact_id: @contact_inbox.contact_id,
contact_inbox_id: @contact_inbox.id
}
end
end
@@ -0,0 +1,67 @@
class Public::Api::V1::Inboxes::MessagesController < Public::Api::V1::InboxesController
before_action :set_message, only: [:update]
def index
@messages = @conversation.nil? ? [] : message_finder.perform
end
def create
@message = @conversation.messages.new(message_params)
build_attachment
@message.save!
end
def update
@message.update!(message_update_params)
rescue StandardError => e
render json: { error: @contact.errors, message: e.message }.to_json, status: :internal_server_error
end
private
def build_attachment
return if params[:attachments].blank?
params[:attachments].each do |uploaded_attachment|
@message.attachments.new(
account_id: @message.account_id,
file_type: helpers.file_type(uploaded_attachment&.content_type),
file: uploaded_attachment
)
end
end
def message_finder_params
{
filter_internal_messages: true,
before: params[:before]
}
end
def message_finder
@message_finder ||= MessageFinder.new(@conversation, message_finder_params)
end
def message_update_params
params.permit(submitted_values: [:name, :title, :value])
end
def permitted_params
params.permit(:content, :echo_id)
end
def set_message
@message = @conversation.messages.find(params[:id])
end
def message_params
{
account_id: @conversation.account_id,
sender: @contact_inbox.contact,
content: permitted_params[:content],
inbox_id: @conversation.inbox_id,
echo_id: permitted_params[:echo_id],
message_type: :incoming
}
end
end
@@ -0,0 +1,23 @@
class Public::Api::V1::InboxesController < PublicController
before_action :set_inbox_channel
before_action :set_contact_inbox
before_action :set_conversation
private
def set_inbox_channel
@inbox_channel = ::Channel::Api.find_by!(identifier: params[:inbox_id])
end
def set_contact_inbox
return if params[:contact_id].blank?
@contact_inbox = @inbox_channel.inbox.contact_inboxes.find_by!(source_id: params[:contact_id])
end
def set_conversation
return if params[:conversation_id].blank?
@conversation = @contact_inbox.contact.conversations.find_by!(display_id: params[:conversation_id])
end
end
+6
View File
@@ -0,0 +1,6 @@
# TODO: we should switch to ActionController::API for the base classes
# One of the specs is failing when I tried doing that, lets revisit in future
class PublicController < ActionController::Base
include RequestExceptionHandler
skip_before_action :verify_authenticity_token
end
@@ -3,10 +3,9 @@ class SuperAdmin::DashboardController < SuperAdmin::ApplicationController
def index
@data = Conversation.unscoped.group_by_day(:created_at, range: 30.days.ago..2.seconds.ago).count.to_a
@accounts_count = number_with_delimiter(Account.all.length)
@users_count = number_with_delimiter(User.all.length)
@inboxes_count = number_with_delimiter(Inbox.all.length)
@conversations_count = number_with_delimiter(Conversation.all.length)
@messages_count = number_with_delimiter(Message.all.length)
@accounts_count = number_with_delimiter(Account.count)
@users_count = number_with_delimiter(User.count)
@inboxes_count = number_with_delimiter(Inbox.count)
@conversations_count = number_with_delimiter(Conversation.count)
end
end
@@ -0,0 +1,10 @@
class Survey::ResponsesController < ActionController::Base
before_action :set_global_config
def show; end
private
def set_global_config
@global_config = GlobalConfig.get('LOGO_THUMBNAIL', 'BRAND_NAME', 'WIDGET_BRAND_URL')
end
end

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