diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 0672350829fbc..aa990adb6ee7f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -18,10 +18,10 @@ __Note:__ If there's a feature you'd like, there's a bug you'd like to fix, or y ## Development Guidelines -Check out our Handbook for the [Development Guidelines](https://handbook.rocket.chat/product/development/development-guidelines) on how to setup your enviroment, do code, test and push your code. There you find our patterns on how to compose your Pull Requests' titles to have your contribution accepted. +Check out our Handbook for the [Development Guidelines](https://handbook.rocket.chat/product/development/development-guidelines) on how to set up your environment, do code, test and push your code. There you find our patterns on how to compose your Pull Requests' titles to have your contribution accepted. ## Contributor License Agreement -To have your contribution accepted you must sign our [Contributor License Agreement](https://cla-assistant.io/RocketChat/Rocket.Chat). In case you submit a Pull Request before sign the CLA GitHub will alert you with a new comment asking you to sign and will block the Pull Request from be merged by us. +To have your contribution accepted you must sign our [Contributor License Agreement](https://cla-assistant.io/RocketChat/Rocket.Chat). In case you submit a Pull Request before signing the CLA GitHub will alert you with a new comment asking you to sign and will block the Pull Request from being merged by us. Please review and sign our CLA at https://cla-assistant.io/RocketChat/Rocket.Chat diff --git a/.github/ISSUE_TEMPLATE/release.md b/.github/ISSUE_TEMPLATE/release.md index 03f57fcab160b..98bdf88ad7981 100644 --- a/.github/ISSUE_TEMPLATE/release.md +++ b/.github/ISSUE_TEMPLATE/release.md @@ -7,14 +7,14 @@ about: Internal release checklist template # Release {version} We are releasing a new version, this issue will keep track of the progress between the first release candidate (20th of each month) to the final release (27th of each month). -Beginning on the 20th of each month, we will start the release process which ends 7 days later (the 27th). During this period of time, we will enter a "Feature Freeze". This Feature Freeze means that we will only be merging pull requests which fix bugs and not ones which add new features. +Beginning on the 20th of each month, we will start the release process which ends 7 days later (the 27th). During this period of time, we will enter a "Feature Freeze". This Feature Freeze means that we will only be merging pull requests which fix bugs and not ones that add new features. When you find a bug that is a regression, please open a new issue and link it to this one. ## Before Release - Preparation - 1 business day before the day 20th - [x] Create the issue to track the release progress -- [ ] Define the highlights from release PRs as suggestion to be included on Blog Post +- [ ] Define the highlights from release PRs as a suggestion to be included on Blog Post - [ ] Talk to the Marketing Team about starting the release Blog Post - [ ] Talk to the Documentation Team about ensuring the Docs are up to date and all pull requests are merged - [ ] Sync translations from [LingoHub](https://translate.lingohub.com/rocketchat/rocket-dot-chat/dashboard) @@ -41,19 +41,19 @@ When you find a bug that is a regression, please open a new issue and link it to - [ ] Check if the release was created as **draft** and contains the history - [ ] Check if the release Pull Request was created and contains the history - [ ] Ensure the **Pull Request** build is passing on [CircleCI](https://circleci.com/gh/RocketChat/Rocket.Chat) -- [ ] When build is passing ask for Pull Request approval -- [ ] When approved merge it! +- [ ] When the build is passing ask for Pull Request approval +- [ ] When approved, merge it! - [ ] Ensure the **Tag** build is passing on [CircleCI](https://circleci.com/gh/RocketChat/Rocket.Chat) - [ ] Ensure the image was sent to [Docker Hub](https://hub.docker.com/r/rocketchat/rocket.chat/tags/) - [ ] After all edit the release/tag and publish it ## After Release - Conclusion - 1 business day after the 27th - [ ] Ensure all of the related issues were closed -- [ ] Determine if all of the related issues were correctly assigned to the this version's milestone -- [ ] Get an update from Marketing Team about the release Blog Post +- [ ] Determine if all of the related issues were correctly assigned to this version's milestone +- [ ] Get an update from Marketing Team about the release of Blog Post - [ ] Check with the Documentation Team about the Docs release - [ ] Sync develop - [ ] Execute action `Develop Sync` via [Houston CLI](https://github.com/RocketChat/Rocket.Chat.Houston) (`houston release`) - [ ] Ensure the **Pull Request** build is passing on [CircleCI](https://circleci.com/gh/RocketChat/Rocket.Chat) - - [ ] When build has passed, ask for approval and wait + - [ ] When the build has passed, ask for approval and wait - [ ] Merge Sync PR diff --git a/.github/actions/setup-node/action.yml b/.github/actions/setup-node/action.yml new file mode 100644 index 0000000000000..47da65a57144e --- /dev/null +++ b/.github/actions/setup-node/action.yml @@ -0,0 +1,46 @@ +name: 'Setup Node' + +inputs: + node-version: + required: true + type: string + cache-modules: + required: false + type: boolean + install: + required: false + type: boolean + +outputs: + node-version: + value: ${{ steps.node-version.outputs.node-version }} + +runs: + using: composite + + steps: + # - name: Cache Node Modules + # if: inputs.cache-modules + # id: cache-node-modules + # uses: actions/cache@v3 + # with: + # path: | + # node_modules + # **/node_modules + # key: node-modules-${{ hashFiles('yarn.lock') }} + # + # Could use this command to list all paths to save: + # find . -name 'node_modules' -prune | grep -v "/\.meteor/" | grep -v "/meteor/packages/" + + - name: Use Node.js ${{ inputs.node-version }} + id: node-version + uses: actions/setup-node@v3 + with: + node-version: ${{ inputs.node-version }} + cache: ${{ steps.cache-node-modules.outputs.cache-hit != 'true' && 'yarn' || '' }} + + - name: yarn install + # if: inputs.install && steps.cache-node-modules.outputs.cache-hit != 'true' + if: inputs.install + shell: bash + run: yarn diff --git a/.github/auto-label-action-config.json b/.github/auto-label-action-config.json deleted file mode 100644 index 0967ef424bce6..0000000000000 --- a/.github/auto-label-action-config.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/.github/history-manual.json b/.github/history-manual.json index a951279b0465f..3089a4beec30f 100644 --- a/.github/history-manual.json +++ b/.github/history-manual.json @@ -196,5 +196,26 @@ "contributors": [ "sampaiodiego" ] + }], + "5.1.2": [{ + "title": "[FIX] Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }], + "5.3.3": [{ + "title": "[FIX] Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }], + "5.4.3": [{ + "title": "[FIX] Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] }] } diff --git a/.github/history.json b/.github/history.json index 75cc0523ea4d4..7f8345d5e1cd5 100644 --- a/.github/history.json +++ b/.github/history.json @@ -57155,7 +57155,7 @@ "pr": "20945", "title": "[NEW][Enterprise] Omnichannel On-Hold Queue", "userLogin": "murtaza98", - "description": "### About this feature\r\nThis feature has been introduced to deal with Inactive chats. A chat is considered Inactive if an Omnichannel End User (aka Visitor) has not replied back to an agent in some time. These types of inactive chats become very important when an organisation has a limit set for `Max Simultaneous Chats per agent` which is defined by the following setting :point_down: , as more number of Inactive chats would directly affect an agent's productivity.\r\n![image](https://user-images.githubusercontent.com/34130764/111533003-4d7ad980-878c-11eb-8c1c-2796678a07db.png)\r\n\r\nBefore this feature, we only had one option to deal with such Inactive/Abandoned chats - which was to auto close abandoned chats via this setting :point_down: \r\n![image](https://user-images.githubusercontent.com/34130764/111534353-e65e2480-878d-11eb-82a5-71368064ef45.png)\r\n\r\nhowever closing a chat isn't a best option for some cases. Let me take an example to explain a scenario\r\n\r\n> An agent is assisting a customer for installing a very huge software which is likely to take more than 20-30 minutes to download. In such scenarios closing a chat isn't the best approach since even after the lengthy download the customer might still need some assist from the agent.\r\n> So basically this chat is going to block the agent's queue until the customer is able to finish his time-consuming download task in which he/she doesn't require any agent's assistance. Due to the `Max Simultaneous Chats per agent` limit, the agent is also not able to use this extra time to help other customer thus affecting his overall productivity.\r\n\r\n**So how does the On-Hold feature solve this problem?**\r\nWith the On-Hold feature, an agent is now able to place a chat on-hold. On-Hold chats **don’t count towards the maximum number of concurrent chats** an agent can have. So in our above example, the agent can simply now place the customer on-hold for 20-30 minutes until the customer downloads the software and within this time, the agent can serve other customers - hence increasing the productivity of an agent.\r\n\r\n----------------------------------------\r\n### Working of the new On-Hold feature\r\n\r\n#### How can you place a chat on Hold ?\r\n\r\nA chat can be placed on-hold via 2 means\r\n1. Automatically place Abandoned chats On-hold\r\n ![image](https://user-images.githubusercontent.com/34130764/111537074-06431780-8791-11eb-8d23-99f5d9f8ec45.png)\r\n Via this :top: option you can define a timer which will get started when a customer sends a message. If we don't receive any message from the customer within this timer, the timer will get expired and the chat will be considered as Abandoned. \r\n ![image](https://user-images.githubusercontent.com/34130764/111537346-53bf8480-8791-11eb-8dc7-260633b4e98f.png)\r\n The via this :top: setting you can choose to automatically place this abandoned chat On Hold\r\n2. Manually place a chat On Hold \r\n As an admin, you can allow an agent to manually place a chat on-hold. To do so, you'll need to turn on this :point_down: setting\r\n ![image](https://user-images.githubusercontent.com/34130764/111537545-97b28980-8791-11eb-86fd-db45b87e9cc1.png)\r\n Now an agent will be able to see a new `On Hold` button within their `Visitor Info Panel` like this :point_down: , provided the agent has sent the last message\r\n ![image](https://user-images.githubusercontent.com/34130764/111537853-f24be580-8791-11eb-9561-d77ba430c625.png)\r\n\r\n#### How can you resume a On Hold chat ?\r\nAn On Hold chat can be resumed via 2 means\r\n\r\n1. If the Customer sends a message\r\n If the Customer / Omnichannel End User sends a message to the On Hold chat, the On Hold chat will get automatically resumed.\r\n2. Manually by agent\r\n An Agent can manually resume the On Hold chat via clicking the `Resume` button in the bottom of a chat room. \r\n ![image](https://user-images.githubusercontent.com/34130764/111538666-f88e9180-8792-11eb-8d14-01453b8e3db0.png)\r\n\r\n#### What would happen if the agent already reached maximum chats, and a On-Hold chat gets resumed ?\r\nBased on how the chat was resumed, there are multiple cases are each case is dealt differently\r\n\r\n- If an agent manually tries to resume the On Hold chat, he/she will get an error saying `Maximum Simultaneous chat limit reached`\r\n- If a customer replies back on an On Hold chat and the last serving agent has reached maximum capacity, then this customer will be placed on the queue again from where based on the Routing Algorithm selected, the chat will get transferred to any available agent", + "description": "### About this feature\r\nThis feature has been introduced to deal with Inactive chats. A chat is considered Inactive if an Omnichannel End User (aka Visitor) has not replied back to an agent in some time. These types of inactive chats become very important when an organisation has a limit set for `Max Simultaneous Chats per agent` which is defined by the following setting :point_down: , as more number of Inactive chats would directly affect an agent's productivity.\r\n![image](https://user-images.githubusercontent.com/34130764/111533003-4d7ad980-878c-11eb-8c1c-2796678a07db.png)\r\n\r\nBefore this feature, we only had one option to deal with such Inactive/Abandoned chats - which was to auto close abandoned chats via this setting :point_down: \r\n![image](https://user-images.githubusercontent.com/34130764/111534353-e65e2480-878d-11eb-82a5-71368064ef45.png)\r\n\r\nhowever closing a chat isn't a best option for some cases. Let me take an example to explain a scenario\r\n\r\n> An agent is assisting a customer for installing a very huge software which is likely to take more than 20-30 minutes to download. In such scenarios closing a chat isn't the best approach since even after the lengthy download the customer might still need some assist from the agent.\r\n> So basically this chat is going to block the agent's queue until the customer is able to finish his time-consuming download task in which he/she doesn't require any agent's assistance. Due to the `Max Simultaneous Chats per agent` limit, the agent is also not able to use this extra time to help other customer thus affecting his overall productivity.\r\n\r\n**So how does the On-Hold feature solve this problem?**\r\nWith the On-Hold feature, an agent is now able to place a chat on-hold. On-Hold chats **don’t count towards the maximum number of concurrent chats** an agent can have. So in our above example, the agent can simply now place the customer on-hold for 20-30 minutes until the customer downloads the software and within this time, the agent can serve other customers - hence increasing the productivity of an agent.\r\n\r\n----------------------------------------\r\n### Working of the new On-Hold feature\r\n\r\n#### How can you place a chat on Hold ?\r\n\r\nA chat can be placed on-hold via 2 means\r\n1. Automatically place Abandoned chats On-hold\r\n ![image](https://user-images.githubusercontent.com/34130764/111537074-06431780-8791-11eb-8d23-99f5d9f8ec45.png)\r\n Via this :top: option you can define a timer which will get started when a customer sends a message. If we don't receive any message from the customer within this timer, the timer will get expired and the chat will be considered as Abandoned. \r\n ![image](https://user-images.githubusercontent.com/34130764/111537346-53bf8480-8791-11eb-8dc7-260633b4e98f.png)\r\n The via this :top: setting you can choose to automatically place this abandoned chat On Hold\r\n2. Manually place a chat On Hold \r\n As an admin, you can allow an agent to manually place a chat on-hold. To do so, you'll need to turn on this :point_down: setting\r\n ![image](https://user-images.githubusercontent.com/34130764/111537545-97b28980-8791-11eb-86fd-db45b87e9cc1.png)\r\n Now an agent will be able to see a new `On Hold` button within their `Visitor Info Panel` like this :point_down: , provided the agent has sent the last message\r\n ![image](https://user-images.githubusercontent.com/34130764/111537853-f24be580-8791-11eb-9561-d77ba430c625.png)\r\n\r\n#### How can you resume a On Hold chat ?\r\nAn On Hold chat can be resumed via 2 means\r\n\r\n1. If the Customer sends a message\r\n If the Customer / Omnichannel End User sends a message to the On Hold chat, the On Hold chat will get automatically resumed.\r\n2. Manually by agent\r\n An Agent can manually resume the On Hold chat via clicking the `Resume` button in the bottom of a chat room. \r\n ![image](https://user-images.githubusercontent.com/34130764/111538666-f88e9180-8792-11eb-8d14-01453b8e3db0.png)\r\n\r\n#### What would happen if the agent already reached maximum chats, and a On-Hold chat gets resumed ?\r\nBased on how the chat was resumed, there are multiple cases are each case is dealt differently\r\n\r\n- If an agent manually tries to resume the On Hold chat, he/she will get an error saying `Maximum Simultaneous chat limit reached`\r\n- If a customer replies back on an On Hold chat and the last serving agent has reached maximum capacity, then this customer will be placed on the queue again from where based on the Routing Algorithm selected, the chat will get transferred to any available agent", "milestone": "3.13.0", "contributors": [ "murtaza98", @@ -93678,6 +93678,10538 @@ "5.0" ], "pull_requests": [] + }, + "5.1.1": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "26776", + "title": "[FIX] Livechat trigger messages covering all the website", + "userLogin": "tiagoevanp", + "milestone": "5.1.1", + "contributors": [ + "tiagoevanp", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26808", + "title": "[FIX] Restore current chats default table order", + "userLogin": "MartinSchoeler", + "milestone": "5.1.1", + "contributors": [ + "MartinSchoeler", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26819", + "title": "[FIX] Fix broken legacy message view", + "userLogin": "hugocostadev", + "description": "Fixed `messagesHistory` function, it was filtering messages only with existing threads.", + "milestone": "5.1.1", + "contributors": [ + "hugocostadev" + ] + } + ] + }, + "4.8.5": { + "node_version": "14.18.3", + "npm_version": "6.14.15", + "mongo_versions": [ + "3.6", + "4.0", + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [] + }, + "5.0.6": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [] + }, + "5.1.2": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [] + }, + "4.8.6": { + "node_version": "14.18.3", + "npm_version": "6.14.15", + "mongo_versions": [ + "3.6", + "4.0", + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [] + }, + "5.0.7": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [] + }, + "5.2.0-rc.0": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "26940", + "title": "Chore: Bump vm2 to 3.9.11", + "userLogin": "ggazzo", + "milestone": "5.2.0", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "26705", + "title": "[NEW] Matrix Federation events coverage expansion (support for 5 more events)", + "userLogin": "MarcosSpessatto", + "description": "The goal of this PR is to add support for more events on Matrix Federation feature. The new supported events are:\r\n\r\n- Edit Messages;\r\n- Delete Messages\r\n- File Upload (including video and audio/voice messages);\r\n- Send emojis on messages;\r\n- Reactions.", + "milestone": "5.2.0", + "contributors": [ + "MarcosSpessatto", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26867", + "title": "[NEW] Move administration links to an exclusive kebab menu", + "userLogin": "filipemarins", + "description": "Move administration links to an exclusive kebab menu.\r\n\r\n\"Screen", + "milestone": "5.2.0", + "contributors": [ + "filipemarins", + "web-flow" + ] + }, + { + "pr": "26880", + "title": "[FIX] `MongoInvalidArgumentError` on overwriting existing setting", + "userLogin": "debdutdeb", + "milestone": "5.1.3", + "contributors": [ + "debdutdeb", + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26930", + "title": "Regression: Fix open room from current chats", + "userLogin": "ggazzo", + "milestone": "5.2.0", + "contributors": [ + "ggazzo", + "web-flow", + "tassoevan" + ] + }, + { + "pr": "26924", + "title": "Chore: Updating apps engine", + "userLogin": "AllanPazRibeiro", + "milestone": "5.2.0", + "contributors": [ + "AllanPazRibeiro", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26931", + "title": "Chore: Convert current-chats to useQuery", + "userLogin": "ggazzo", + "milestone": "5.2.0", + "contributors": [ + "ggazzo", + "tassoevan", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26855", + "title": "Chore: Introduce `useQuery` as data source for the `Room` component", + "userLogin": "tassoevan", + "milestone": "5.2.0", + "contributors": [ + "tassoevan", + "ggazzo" + ] + }, + { + "pr": "26928", + "title": "Regression: wrong permission on livechat/tags endpoints", + "userLogin": "KevLehman", + "milestone": "5.2.0", + "contributors": [ + "KevLehman", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "25003", + "title": "Bump actions/cache from 2 to 3.0.1", + "userLogin": "dependabot[bot]", + "contributors": [ + "dependabot[bot]", + "web-flow" + ] + }, + { + "pr": "26929", + "title": "Chore: Refactor omnichannel livechat tests", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "26884", + "title": "Chore: Move micro services to packages", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "web-flow" + ] + }, + { + "pr": "26912", + "title": "Chore: fix regressions for omnichannel due room refactor", + "userLogin": "ggazzo", + "milestone": "5.2.0", + "contributors": [ + "ggazzo", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26900", + "title": "[FIX] Message sequential after message thread preview", + "userLogin": "filipemarins", + "milestone": "5.2.0", + "contributors": [ + "filipemarins", + "ggazzo", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26812", + "title": "[FIX] Ephemeral messages not respecting katex setting", + "userLogin": "gabriellsh", + "milestone": "5.2.0", + "contributors": [ + "gabriellsh", + "ggazzo", + "web-flow", + "tassoevan" + ] + }, + { + "pr": "26685", + "title": "[FIX] Old rooms without the associated unit will not be displayed on the current chats", + "userLogin": "murtaza98", + "milestone": "5.2.0", + "contributors": [ + "murtaza98", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26548", + "title": "[IMPROVE] VideoConference Messages UI", + "userLogin": "dougfabris", + "description": "\r\n\r\n\r\n\r\n", + "milestone": "5.2.0", + "contributors": [ + "dougfabris", + "ggazzo", + "tassoevan", + "pierre-lehnen-rc" + ] + }, + { + "pr": "26829", + "title": "Chore: Omnichannel endpoints to ts", + "userLogin": "KevLehman", + "milestone": "5.2.0", + "contributors": [ + "KevLehman", + "web-flow" + ] + }, + { + "pr": "26751", + "title": "[NEW] Add Markup to QuoteAttachment", + "userLogin": "hugocostadev", + "milestone": "5.2.0", + "contributors": [ + "hugocostadev", + "filipemarins", + "web-flow", + "gabriellsh" + ] + }, + { + "pr": "26921", + "title": "[FIX] MIME Type fallback for .mov File Extensions", + "userLogin": "hugocostadev", + "description": "Some browsers don't support the MIME type for QuickTime video encoder (.mov), so we had to create a fallback to 'video/mp4'. There are other fallbacks for other browsers, but this is the only one we need for now.\r\n\r\nThe fallback func was used in the MediaPreview and VideoAttachments components", + "milestone": "5.2.0", + "contributors": [ + "hugocostadev" + ] + }, + { + "pr": "26843", + "title": "[FIX] [Livechat] Unread messages badge", + "userLogin": "tiagoevanp", + "description": "OC-169\r\n\r\nEven if the page was reopening, Livechat will inform unread messages", + "milestone": "5.2.0", + "contributors": [ + "tiagoevanp", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26917", + "title": "[FIX] Error when mentioning a non-member of a public channel", + "userLogin": "debdutdeb", + "milestone": "5.1.3", + "contributors": [ + "debdutdeb", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26831", + "title": "[IMPROVE] Setting for login email notifications", + "userLogin": "yash-rajpal", + "milestone": "5.2.0", + "contributors": [ + "yash-rajpal", + "web-flow" + ] + }, + { + "pr": "26674", + "title": "[NEW] Get moderators, owners and leaders from room scope via apps-engine", + "userLogin": "debdutdeb", + "milestone": "5.2.0", + "contributors": [ + "debdutdeb", + "d-gubert", + "web-flow" + ] + }, + { + "pr": "26877", + "title": "[IMPROVE] Better descriptions for VoIP Settings", + "userLogin": "MartinSchoeler", + "milestone": "5.2.0", + "contributors": [ + "MartinSchoeler", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26822", + "title": "Release 5.1.1", + "userLogin": "tassoevan", + "contributors": [ + "hugocostadev", + "tassoevan", + "MartinSchoeler", + "tiagoevanp" + ] + }, + { + "pr": "26896", + "title": "i18n: Language update from LingoHub 🤖 on 2022-09-19Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "yash-rajpal", + "web-flow" + ] + }, + { + "pr": "26711", + "title": "[FIX] Upload fails when using WebDav as file storage", + "userLogin": "pierre-lehnen-rc", + "contributors": [ + "pierre-lehnen-rc", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26834", + "title": "[IMPROVE] Updating voip tooltips and icons", + "userLogin": "aleksandernsilva", + "description": "### This PR includes the following tooltip expression changes:\r\nCall toggle button\r\n* Enabled -> Turn off answer calls\r\n* Disabled -> Turn on answer calls\r\n* Signaling connection disconnected -> Waiting for server connection\r\n\r\n\r\nChat toggle button\r\n* Available -> Turn off answer chats\r\n* Not available -> Turn on answer chats\r\n\r\nHold button\r\n* Hold call -> Hold call / Resume call\r\n\r\nMute button\r\n* Mute -> Turn on microphone / Turn off microphone\r\n\r\n### Also includes the following icon changes:\r\n\r\nOld:\r\n![new-1](https://user-images.githubusercontent.com/6494543/189218303-144671cb-6533-46a0-be18-52d62b3701d3.png)\r\n![new-2](https://user-images.githubusercontent.com/6494543/189218307-8f24797b-bef6-4d8a-9e25-98e96fa59155.png)\r\n![new-3](https://user-images.githubusercontent.com/6494543/189218309-05a836a3-5c17-4370-9cc6-fd7a6da3d8c2.png)\r\n\r\n\r\nNew: \r\n\r\n![old-1](https://user-images.githubusercontent.com/6494543/189217735-3d9cde83-8e54-421e-b57a-ac9bda748416.png)\r\n![old-2](https://user-images.githubusercontent.com/6494543/189217738-d4bb2bfb-ddfd-4830-a2e8-a9937e93826a.png)\r\n![old-3](https://user-images.githubusercontent.com/6494543/189217740-988295bf-9112-4cea-93da-402ea7e82247.png)", + "milestone": "5.2.0", + "contributors": [ + "aleksandernsilva", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26686", + "title": "Chore: Change BundleChips component appearance", + "userLogin": "rique223", + "description": "# [MKP-44](https://rocketchat.atlassian.net/browse/MKP-44?atlOrigin=eyJpIjoiOTBiNzQ4NzE1ZTJiNDBjMGE0NjQxNmQ2MWNkMTI4YjgiLCJwIjoiaiJ9)\r\nChanged the appearance of the marketplace app bundle chips (E.G.: The blue Enterprise tag in the images bellow).\r\n\r\nDemo image for app details page:\r\n![image](https://user-images.githubusercontent.com/43561537/190232209-939d29f5-bcdb-4ce4-99d1-1b061d170ab0.png)\r\n\r\nDemo image for list view:\r\n![image](https://user-images.githubusercontent.com/43561537/190232168-ab898d8a-6a73-4e34-9f47-a5af01bf29fc.png)", + "contributors": [ + "rique223", + "web-flow" + ] + }, + { + "pr": "26886", + "title": "Chore: merge all functions using autorun x useSubscription pattern", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "26860", + "title": "Chore: Fix API tests retry", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "web-flow" + ] + }, + { + "pr": "26601", + "title": "[FIX] Check admin setting for whether to display roles or not", + "userLogin": "debdutdeb", + "milestone": "5.2.0", + "contributors": [ + "debdutdeb", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26864", + "title": "Chore: Move Omnichannel Room Footer to react", + "userLogin": "ggazzo", + "contributors": [ + "yash-rajpal", + "MartinSchoeler", + "ggazzo" + ] + }, + { + "pr": "25541", + "title": "Chore: Move presence to package", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "26863", + "title": "[IMPROVE] Changed dial pad appearance to match original design", + "userLogin": "aleksandernsilva", + "description": "Before:\r\n![Screen Shot 2022-09-13 at 15 00 34](https://user-images.githubusercontent.com/6494543/189976766-6d085795-a832-4189-898b-4bd631cb4309.png)\r\n\r\nAfter:\r\n![Screen Shot 2022-09-13 at 14 59 23](https://user-images.githubusercontent.com/6494543/189976804-c419ac33-6a90-464e-8792-feb0d0ae33e5.png)", + "milestone": "5.2.0", + "contributors": [ + "aleksandernsilva", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26757", + "title": "Chore: Move Header to ui-client", + "userLogin": "dougfabris", + "description": "\"Screen", + "milestone": "5.2.0", + "contributors": [ + "dougfabris", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "26755", + "title": "[FIX] Asset settings description not showing on admin", + "userLogin": "filipemarins", + "milestone": "5.2.0", + "contributors": [ + "filipemarins", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26813", + "title": "[FIX] Incorrect filter on contact history search", + "userLogin": "neo-clon", + "contributors": [ + "neo-clon", + "web-flow", + "debdutdeb", + "KevLehman" + ] + }, + { + "pr": "26669", + "title": "[FIX] Unable to send native video recording to Whatsapp", + "userLogin": "murtaza98", + "milestone": "5.2.0", + "contributors": [ + "murtaza98", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "26876", + "title": "Chore: Bump fuselage dependencies and implement new tabs variant in marketplace", + "userLogin": "rique223", + "description": "Bumped the necessary dependencies of fuselage and implemented the new tabs component underline variant.\r\nDemo image:\r\n![image](https://user-images.githubusercontent.com/43561537/190252796-cd4ad872-90e6-413e-92cb-13c0354399da.png)", + "contributors": [ + "rique223", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "26852", + "title": "[FIX] Expanded thread behind sidebar on small screens", + "userLogin": "hugocostadev", + "description": "Sidebar overlapping expanded threads in window sizes between **1135px and 780px** and but the expanded threads should be limited to sidebar size and should not go through it\r\n\r\n### **Actual behavior**\r\n![image](https://user-images.githubusercontent.com/20212776/189692618-b1c0ebdf-36e1-49cb-9179-29b842260a18.png)\r\n\r\n\r\n### **Expected behavior**\r\n![image](https://user-images.githubusercontent.com/20212776/189692714-0cce9947-8f72-48af-9a81-04cc521a9833.png)", + "milestone": "5.2.0", + "contributors": [ + "hugocostadev", + "sampaiodiego", + "web-flow", + "yash-rajpal" + ] + }, + { + "pr": "26709", + "title": "Chore: Upgrading livechat's ui-kit package to latest version", + "userLogin": "aleksandernsilva", + "description": "This PR upgrades Livechat's UiKit package to the version 0.31.16. and adjusts the renderer to be compatible with said version.", + "milestone": "5.2.0", + "contributors": [ + "aleksandernsilva", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26873", + "title": "Chore: fix wrong `test.step` usage", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "26841", + "title": "Chore: Update fuselage to next version.", + "userLogin": "gabriellsh", + "milestone": "5.2.0", + "contributors": [ + "gabriellsh", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "26836", + "title": "[FIX] Importer fails when file includes user without an email.", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.1.3", + "contributors": [ + "pierre-lehnen-rc", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26845", + "title": "Chore: Rewrite apps WarningModal component to typescript", + "userLogin": "rique223", + "description": "Translated the admin apps WarningModal component from Javascript to Typescript", + "contributors": [ + "rique223", + "web-flow", + "juliajforesti" + ] + }, + { + "pr": "26793", + "title": "Chore: Add RocketChatDesktop function to open video calls when using Electron", + "userLogin": "jeanfbrito", + "contributors": [ + "jeanfbrito", + "pierre-lehnen-rc", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26652", + "title": "[FIX] Check if messsage.replies exist on new message template", + "userLogin": "filipemarins", + "milestone": "5.1.3", + "contributors": [ + "filipemarins", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26849", + "title": "i18n: Language update from LingoHub 🤖 on 2022-09-12Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26832", + "title": "[IMPROVE] Rounded video attachment", + "userLogin": "yash-rajpal", + "milestone": "5.2.0", + "contributors": [ + "yash-rajpal", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26824", + "title": "[IMPROVE] Include `syncAvatars` on `ldap.syncNow`", + "userLogin": "LucianoPierdona", + "description": "This PR includes a new call for the method `syncAvatars` when `ldap.syncNow` is called", + "milestone": "5.2.0", + "contributors": [ + "LucianoPierdona", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26839", + "title": "Chore: Deprecate some omnichannel meteor methods which aren't getting used", + "userLogin": "murtaza98", + "contributors": [ + "murtaza98", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26846", + "title": "Chore: Configure Prettier for `@rocket.chat/livechat`", + "userLogin": "tiagoevanp", + "contributors": [ + "tiagoevanp", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26675", + "title": "Chore: `refactor/room`", + "userLogin": "tassoevan", + "description": "Replaces `room` Blaze template with React components.", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "26514", + "title": "[NEW] Sections layout and featured apps for marketplace", + "userLogin": "rique223", + "description": "### [MKP??+ - Featured Apps](https://app.clickup.com/t/2t1w9x3)\r\nImplemented a new layout for marketplace's apps list page. Now the page has an All apps section and a \"featured apps\" section in which pre-selected and pre-categorized apps are dynamically shown on the top area of the page to make them stand out.\r\nDemo gif:\r\n![featured_apps](https://user-images.githubusercontent.com/43561537/184385727-4f44c1d5-d7f7-43bf-a93d-2bc582bd3159.gif)\r\n\r\nClickUp Task link: https://app.clickup.com/t/2t1w9x3", + "milestone": "5.2.0", + "contributors": [ + "rique223", + "web-flow" + ] + }, + { + "pr": "26714", + "title": "Chore: first non-aggressive CSS removal", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "tassoevan", + "web-flow" + ] + }, + { + "pr": "26749", + "title": "Chore: Cleanup endpoint handlers", + "userLogin": "KevLehman", + "contributors": [ + "KevLehman", + "web-flow", + "murtaza98" + ] + }, + { + "pr": "26826", + "title": "Chore: add aria hidden if modal is open", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26827", + "title": "[FIX] Sign in with Apple on mobile", + "userLogin": "sampaiodiego", + "description": "Our mobile app uses a different method to log in that was removed at #24879 .\r\n\r\nYou can also make it available only on mobile:\r\n![image](https://user-images.githubusercontent.com/8591547/188752062-bef03f01-d995-4422-8a24-984ebed49ce2.png)\r\n\r\nRemoves the \"Sign in with Apple\" text from the log in button. This was something we thought were required by Apple, but it is actually allowed to have just the logo as all others OAuth we have. Source: https://developer.apple.com/design/human-interface-guidelines/technologies/sign-in-with-apple/buttons/#creating-a-custom-sign-in-with-apple-button", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "26673", + "title": "[IMPROVE] Allow delete attachment description on message edit", + "userLogin": "yash-rajpal", + "milestone": "5.2.0", + "contributors": [ + "yash-rajpal", + "hugocostadev", + "web-flow", + "matheusbsilva137", + "kodiakhq[bot]" + ] + }, + { + "pr": "24297", + "title": "[IMPROVE] OTR Message", + "userLogin": "albuquerquefabio", + "milestone": "5.2.0", + "contributors": [ + "yash-rajpal", + "albuquerquefabio", + "web-flow" + ] + }, + { + "pr": "26130", + "title": "[IMPROVE] System messages' consistency", + "userLogin": "matheusbsilva137", + "milestone": "5.2.0", + "contributors": [ + "matheusbsilva137", + "LucianoPierdona", + "web-flow", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "26775", + "title": "[FIX] Menu options margin spacing", + "userLogin": "guijun13", + "description": "- Change margin spacing from 16-4px to 12-8px\r\n\r\n| before | after |\r\n|--------|-------|\r\n| ![before](https://user-images.githubusercontent.com/48109548/187940409-903eede8-9ade-448d-9211-0e004ccd0ff2.png) | ![after](https://user-images.githubusercontent.com/48109548/187940513-3189ca2a-5f18-4e39-93bb-5843f13fce27.png) |", + "milestone": "5.2.0", + "contributors": [ + "guijun13", + "web-flow", + "gabriellsh", + "kodiakhq[bot]" + ] + }, + { + "pr": "26805", + "title": "i18n: Language update from LingoHub 🤖 on 2022-09-05Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26819", + "title": "[FIX] Fix broken legacy message view", + "userLogin": "hugocostadev", + "description": "Fixed `messagesHistory` function, it was filtering messages only with existing threads.", + "milestone": "5.1.1", + "contributors": [ + "hugocostadev" + ] + }, + { + "pr": "26808", + "title": "[FIX] Restore current chats default table order", + "userLogin": "MartinSchoeler", + "milestone": "5.1.1", + "contributors": [ + "MartinSchoeler", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26776", + "title": "[FIX] Livechat trigger messages covering all the website", + "userLogin": "tiagoevanp", + "milestone": "5.1.1", + "contributors": [ + "tiagoevanp", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26748", + "title": "Chore: Refactor message list context usage", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "26767", + "title": "Chore: Add tests to cover issue fixed in #26720", + "userLogin": "murtaza98", + "contributors": [ + "murtaza98" + ] + }, + { + "pr": "26724", + "title": "Chore: Test/improve reliability", + "userLogin": "souzaramon", + "contributors": [ + "souzaramon", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26768", + "title": "[FIX] Typo on new homepage", + "userLogin": "filipemarins", + "contributors": [ + "filipemarins", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26722", + "title": "i18n: Language update from LingoHub 🤖 on 2022-08-29Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26730", + "title": "Chore: Add E2E tests to missing omnichannel endpoints", + "userLogin": "KevLehman", + "milestone": "5.2.0", + "contributors": [ + "KevLehman", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26792", + "title": "Merge master into develop & Set version to 5.2.0-develop", + "userLogin": "murtaza98", + "contributors": [ + "murtaza98", + "sampaiodiego", + "web-flow" + ] + } + ] + }, + "5.1.3": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "26914", + "title": "Release 5.1.3", + "userLogin": "tassoevan", + "contributors": [ + "filipemarins", + "tassoevan", + "pierre-lehnen-rc", + "debdutdeb" + ] + }, + { + "pr": "26880", + "title": "[FIX] `MongoInvalidArgumentError` on overwriting existing setting", + "userLogin": "debdutdeb", + "milestone": "5.1.3", + "contributors": [ + "debdutdeb", + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26917", + "title": "[FIX] Error when mentioning a non-member of a public channel", + "userLogin": "debdutdeb", + "milestone": "5.1.3", + "contributors": [ + "debdutdeb", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26836", + "title": "[FIX] Importer fails when file includes user without an email.", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.1.3", + "contributors": [ + "pierre-lehnen-rc", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26652", + "title": "[FIX] Check if messsage.replies exist on new message template", + "userLogin": "filipemarins", + "milestone": "5.1.3", + "contributors": [ + "filipemarins", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26822", + "title": "Release 5.1.1", + "userLogin": "tassoevan", + "contributors": [ + "hugocostadev", + "tassoevan", + "MartinSchoeler", + "tiagoevanp" + ] + } + ] + }, + "5.2.0-rc.1": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "26909", + "title": "[FIX] Adjusted livechat fallbacks to take null values into account", + "userLogin": "aleksandernsilva", + "milestone": "5.1.4", + "contributors": [ + "aleksandernsilva", + "tassoevan", + "web-flow" + ] + }, + { + "pr": "26950", + "title": "Regression: Sidebar Room List not working properly.", + "userLogin": "gabriellsh", + "description": "The CachedCollection Class was assuming that the passed parameter would be modified, instead of using the callback return.", + "contributors": [ + "gabriellsh" + ] + }, + { + "pr": "26939", + "title": "Chore: Tests for EE features", + "userLogin": "KevLehman", + "contributors": [ + "KevLehman", + "web-flow" + ] + }, + { + "pr": "26926", + "title": "Chore: Missing Also_send_thread_message_to_channel setting translation", + "userLogin": "yash-rajpal", + "contributors": [ + "yash-rajpal", + "web-flow", + "kodiakhq[bot]", + "dougfabris" + ] + }, + { + "pr": "26948", + "title": "i18n: Language update from LingoHub 🤖 on 2022-09-26Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "yash-rajpal" + ] + } + ] + }, + "5.1.4": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "26965", + "title": "Release 5.1.4 ", + "userLogin": "tassoevan", + "contributors": [ + "aleksandernsilva", + "tassoevan" + ] + } + ] + }, + "5.2.0-rc.2": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "26986", + "title": "Regression: Remove section and replace icon on administration kebab menu", + "userLogin": "filipemarins", + "milestone": "5.2.0", + "contributors": [ + "filipemarins", + "tassoevan", + "web-flow" + ] + }, + { + "pr": "26975", + "title": "Regression: Omnichannel Contact Center empty on no filter search", + "userLogin": "tiagoevanp", + "milestone": "5.2.0", + "contributors": [ + "tiagoevanp", + "KevLehman", + "tassoevan", + "web-flow" + ] + }, + { + "pr": "26987", + "title": "[IMPROVE] Use cached EE Cloud license on startup", + "userLogin": "sampaiodiego", + "milestone": "5.2.0", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "26976", + "title": "Regression: Fixed takeInquiry method not displaying error messages on the client", + "userLogin": "aleksandernsilva", + "description": "This pull request brings back the toast message \"The maximum number of simultaneous chats per agent has been reached.\" that should be displayed when an agent tries to take more chats than the maximum allowed.\r\n\r\n![image](https://user-images.githubusercontent.com/6494543/192891486-8720a5e3-f0c8-4863-b0dc-fa3b922d776b.png)", + "milestone": "5.2.0", + "contributors": [ + "aleksandernsilva" + ] + }, + { + "pr": "26988", + "title": "Regression: Handle `undefined` values on `useReactiveQuery`'s query function", + "userLogin": "tassoevan", + "description": "According to https://tanstack.com/query/v4/docs/reference/useQuery, the query function must **not** return `undefined` values, a quirk that we've been ignoring.", + "milestone": "5.2.0", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "26983", + "title": "Regression: Composer not reactive when omnichannel room closed", + "userLogin": "MartinSchoeler", + "milestone": "5.2.0", + "contributors": [ + "MartinSchoeler", + "tassoevan", + "web-flow" + ] + }, + { + "pr": "26687", + "title": "[IMPROVE] Results of user auto complete", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.2.0", + "contributors": [ + "pierre-lehnen-rc", + "web-flow", + "sampaiodiego" + ] + }, + { + "pr": "26935", + "title": "Regression: Incorrect on-hold chat resume message", + "userLogin": "murtaza98", + "milestone": "5.2.0", + "contributors": [ + "murtaza98", + "web-flow", + "KevLehman", + "tassoevan" + ] + }, + { + "pr": "26964", + "title": "Regression: Event handler blocking mention links", + "userLogin": "tassoevan", + "description": "Fixes mention links being irresponsive to clicks.\r\nJira: [TC-55]\r\n\r\n[TC-55]: https://rocketchat.atlassian.net/browse/TC-55?atlOrigin=eyJpIjoiMmQ3ZmE0MWE2NGQwNDIzZThkMzc5NGNhMzU1MjExMGMiLCJwIjoiaiJ9", + "milestone": "5.2.0", + "contributors": [ + "tassoevan", + "yash-rajpal", + "web-flow" + ] + }, + { + "pr": "26969", + "title": "Regression: Remove symbols from number before storing PBX event", + "userLogin": "KevLehman", + "milestone": "5.2.0", + "contributors": [ + "KevLehman", + "tassoevan", + "web-flow" + ] + }, + { + "pr": "26962", + "title": "Regression: Typo on livechat/queue endpoint client call", + "userLogin": "KevLehman", + "milestone": "5.2.0", + "contributors": [ + "KevLehman", + "tassoevan", + "web-flow" + ] + }, + { + "pr": "26961", + "title": "Revert: \"[IMPROVE] VideoConference Messages UI (#26548)\"", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.2.0", + "contributors": [ + "pierre-lehnen-rc", + "debdutdeb", + "web-flow", + "tassoevan" + ] + }, + { + "pr": "26958", + "title": "[FIX] Admin sidebar navigation", + "userLogin": "juliajforesti", + "description": "## [MKP-125](https://rocketchat.atlassian.net/browse/MKP-125?atlOrigin=eyJpIjoiMThlMTIwYmFkZWI5NDBlYjhlMWI3YTc1ZDliYTY3NDUiLCJwIjoiaiJ9)\r\nFix the behavior of the admin sidebar, it didn't activate its options properly on pages that had sub-routes.\r\nDemo gif:\r\n![sidebar-bug](https://user-images.githubusercontent.com/43561537/192585542-ddd8fd37-e833-4960-ae67-fb408595c7ba.gif)", + "contributors": [ + "juliajforesti", + "rique223", + "web-flow" + ] + } + ] + }, + "5.2.0-rc.3": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27002", + "title": "Regression: Use raw models instead of meteor ones on visitor inactivity processing", + "userLogin": "KevLehman", + "milestone": "5.2.0", + "contributors": [ + "KevLehman", + "tassoevan", + "web-flow" + ] + }, + { + "pr": "26426", + "title": "Chore: `improve/media-recorder`", + "userLogin": "tassoevan", + "contributors": [ + "tassoevan", + "ggazzo" + ] + } + ] + }, + "5.2.0-rc.4": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "26994", + "title": "Chore: break LDAP manager into smaller pieces to improve unit tests", + "userLogin": "ggazzo", + "milestone": "5.2.0", + "contributors": [ + "ggazzo", + "web-flow", + "tassoevan" + ] + } + ] + }, + "5.2.0-rc.5": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27009", + "title": "Regression: VideoConf Actions Reactivity in SidebarItem", + "userLogin": "dougfabris", + "description": "Jira Issue: [VC-10]", + "milestone": "5.2.0", + "contributors": [ + "dougfabris", + "tassoevan", + "web-flow" + ] + }, + { + "pr": "27008", + "title": "Regression: Double Table Cell Causing extra padding on Current Chats", + "userLogin": "MartinSchoeler", + "milestone": "5.2.0", + "contributors": [ + "MartinSchoeler", + "KevLehman", + "web-flow", + "tassoevan" + ] + }, + { + "pr": "27023", + "title": "Regression: Cannot edit messages in some environments.", + "userLogin": "gabriellsh", + "description": "An empty `$unset` object was being used and causes exceptions in some mongo versions.", + "milestone": "5.2.0", + "contributors": [ + "gabriellsh" + ] + } + ] + }, + "5.2.0-rc.6": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27042", + "title": "Chore: Bump fuselage to latest", + "userLogin": "gabriellsh", + "milestone": "5.2.0", + "contributors": [ + "gabriellsh" + ] + } + ] + }, + "5.2.0": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27059", + "title": "Chore: Bump Apps-Engine version", + "userLogin": "d-gubert", + "milestone": "5.2.0", + "contributors": [ + "d-gubert" + ] + }, + { + "pr": "26965", + "title": "Release 5.1.4 ", + "userLogin": "tassoevan", + "contributors": [ + "aleksandernsilva", + "tassoevan" + ] + }, + { + "pr": "26914", + "title": "Release 5.1.3", + "userLogin": "tassoevan", + "contributors": [ + "filipemarins", + "tassoevan", + "pierre-lehnen-rc", + "debdutdeb" + ] + }, + { + "pr": "26880", + "title": "[FIX] `MongoInvalidArgumentError` on overwriting existing setting", + "userLogin": "debdutdeb", + "milestone": "5.1.3", + "contributors": [ + "debdutdeb", + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26917", + "title": "[FIX] Error when mentioning a non-member of a public channel", + "userLogin": "debdutdeb", + "milestone": "5.1.3", + "contributors": [ + "debdutdeb", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26836", + "title": "[FIX] Importer fails when file includes user without an email.", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.1.3", + "contributors": [ + "pierre-lehnen-rc", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26652", + "title": "[FIX] Check if messsage.replies exist on new message template", + "userLogin": "filipemarins", + "milestone": "5.1.3", + "contributors": [ + "filipemarins", + "web-flow", + "kodiakhq[bot]" + ] + } + ] + }, + "5.3.0-rc.0": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27076", + "title": "[FIX] Livechat CurrentChats infinity re-rendering", + "userLogin": "tiagoevanp", + "milestone": "5.3.0", + "contributors": [ + "tiagoevanp", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26789", + "title": "[NEW] Add new endpoint 'livechat/room.saveInfo' & deprecate 'livechat:saveInfo' meteor method", + "userLogin": "murtaza98", + "milestone": "5.3.0", + "contributors": [ + "murtaza98", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27091", + "title": "[IMPROVE] Better /health response when service not healthy", + "userLogin": "sampaiodiego", + "description": "Not healthy services will send a HTTP 500 response when not healthy.", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27089", + "title": "Chore: Apply correct fuselage color tokens", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "26974", + "title": "Chore: Tests for EE dashboards", + "userLogin": "KevLehman", + "milestone": "5.3.0", + "contributors": [ + "KevLehman", + "cauefcr", + "web-flow" + ] + }, + { + "pr": "27012", + "title": "Chore: Remove Unused CSS", + "userLogin": "MartinSchoeler", + "milestone": "5.3.0", + "contributors": [ + "MartinSchoeler" + ] + }, + { + "pr": "27050", + "title": "[FIX] Preview message not showing when reply direct message", + "userLogin": "filipemarins", + "milestone": "5.3.0", + "contributors": [ + "filipemarins", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27026", + "title": "[NEW] Health check for data stream", + "userLogin": "sampaiodiego", + "milestone": "5.3.0", + "contributors": [ + "sampaiodiego", + "web-flow", + "casalsgh", + "kodiakhq[bot]" + ] + }, + { + "pr": "26796", + "title": "Chore: Email Inbox Sanitization", + "userLogin": "dougfabris", + "description": "Jira Issue [UFR-3]\r\n\r\n- Rewrite Email Inbox to typescript\r\n- Replace `useForm`\r\n- Fix: return an error if there are no email inboxes in `email-inbox` endpoint \r\n**documentation update**: https://github.com/RocketChat/developer-docs/pull/132\r\n- Add e2e test cases for creating email inboxes and deleting email inboxes", + "milestone": "5.3.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27020", + "title": "[FIX] Uncaught error by listening stream-notify-room without subscription", + "userLogin": "tiagoevanp", + "description": "fix this:\r\n\"image\"", + "milestone": "5.3.0", + "contributors": [ + "tiagoevanp", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27040", + "title": "[FIX] check if message block has item to show message body", + "userLogin": "filipemarins", + "milestone": "5.3.0", + "contributors": [ + "filipemarins", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27068", + "title": "Chore: UserCard loader tweaks", + "userLogin": "dougfabris", + "description": "### before\r\n![Kapture 2022-10-14 at 12 47 43](https://user-images.githubusercontent.com/27704687/195888045-6fd900ab-feb1-4dc7-924c-a0fd7634eab6.gif)\r\n\r\n\r\n### after\r\n![Kapture 2022-10-14 at 12 45 30](https://user-images.githubusercontent.com/27704687/195887641-652f388b-cf9f-413d-9c07-c0df9a3f7287.gif)", + "milestone": "5.3.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27086", + "title": "[FIX] Warning about livechat/inquiries.queuedForUser", + "userLogin": "MartinSchoeler", + "milestone": "5.3.0", + "contributors": [ + "MartinSchoeler", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26682", + "title": "Chore: Use a single notification listener for all videoconf messages", + "userLogin": "pierre-lehnen-rc", + "description": "Task: [VC-1]", + "milestone": "5.3.0", + "contributors": [ + "pierre-lehnen-rc", + "sampaiodiego", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27052", + "title": "[FIX] Actionable messages are now sent to integrations webhook", + "userLogin": "cauefcr", + "description": "Actionable messages, with buttons and similar, (saved as blocks internally) were not being sent to external integrations, so CRMs and the like had no visibility on what was the actionable message sent, this PR adds a yaml version of the actions, as well as a proper json object with the same data on the webhook output, so that our clients can have more visibility in their process", + "milestone": "5.3.0", + "contributors": [ + "cauefcr", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27035", + "title": "i18n: Language update from LingoHub 🤖 on 2022-10-10Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "yash-rajpal", + "dougfabris", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27053", + "title": "[FIX] Remove contact mananger always to support old servers", + "userLogin": "KevLehman", + "milestone": "5.3.0", + "contributors": [ + "KevLehman", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27082", + "title": "i18n: Language update from LingoHub 🤖 on 2022-10-17Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "yash-rajpal", + "web-flow" + ] + }, + { + "pr": "26963", + "title": "[IMPROVE] Automatically open call info contextual bar when voip room is opened", + "userLogin": "aleksandernsilva", + "description": "This pull request adds the logic necessary to automatically open the call information contextual bar when entering a voip room. This mirrors the behavior we already have for livechat rooms.\r\n\r\n**Before:**\r\n![before-voip-480p-speed](https://user-images.githubusercontent.com/6494543/192610275-a81ab19e-2b60-4466-9e04-81b2e938afda.gif)\r\n\r\n**After:**\r\n![after-voip-480p-speed](https://user-images.githubusercontent.com/6494543/192610356-896ccd48-8c26-4fb9-8fb4-f792ab63e6d5.gif)", + "milestone": "5.3.0", + "contributors": [ + "aleksandernsilva", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26938", + "title": "Chore: Refactor AppLogs to TS", + "userLogin": "rique223", + "description": "Rewrote the AppLogs component to TS. Also, improved some error handling logic.", + "milestone": "5.3.0", + "contributors": [ + "rique223", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26960", + "title": "[FIX] Remove voip extension when agent is removed or deactivated", + "userLogin": "KevLehman", + "milestone": "5.3.0", + "contributors": [ + "KevLehman", + "cauefcr", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26995", + "title": "Chore: Remove default value from custom home content setting", + "userLogin": "gabriellsh", + "description": "Remove content from `Custom body` setting so that new workspaces don't have initial unstyled HTML in their homepages.", + "milestone": "5.3.0", + "contributors": [ + "gabriellsh", + "web-flow", + "guijun13", + "kodiakhq[bot]" + ] + }, + { + "pr": "27043", + "title": "Chore: remove excess space from html preview", + "userLogin": "yash-rajpal", + "milestone": "5.3.0", + "contributors": [ + "yash-rajpal", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26992", + "title": "i18n: Language update from LingoHub 🤖 on 2022-10-03Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26850", + "title": "[FIX] Email inbox memory leak on connection failure", + "userLogin": "cauefcr", + "description": "- Properly removing event listeners on re-connection.\r\n - Attachments handling changed from beforeMessageSent to afterMessageSent, as the id of the message was needed, now rocket.cat will send the \"Send Attachment To Email\" button.\r\n - Self-disable email inbox when reaching max re-connection attempts", + "milestone": "5.3.0", + "contributors": [ + "cauefcr", + "web-flow", + "KevLehman" + ] + }, + { + "pr": "27013", + "title": "[FIX] On hold reactivity for Omnichannel rooms", + "userLogin": "tiagoevanp", + "description": "- Fix instabilities from room when changed from on-hold to resume\r\n- Fix gray messages when resume from on-hold", + "milestone": "5.3.0", + "contributors": [ + "tiagoevanp", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27038", + "title": "[IMPROVE] Respect convert ascii to emoji preference for new message template", + "userLogin": "yash-rajpal", + "milestone": "5.3.0", + "contributors": [ + "yash-rajpal", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27025", + "title": "Chore: Switch deprecated fields for projection", + "userLogin": "tiagoevanp", + "milestone": "5.3.0", + "contributors": [ + "tiagoevanp", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27030", + "title": "Chore: Implement short description for marketplace apps", + "userLogin": "rique223", + "description": "## Jira task: [MKP-126](https://rocketchat.atlassian.net/browse/MKP-126)\r\nImplemented the shortDescription field in the marketplace app details header. Now apps have either a shorter description or nothing, in case it doesn't have a shortDescription registered, in their headers description section.\r\nDemo image: \r\n![image](https://user-images.githubusercontent.com/43561537/194640492-9942f6d9-66ad-4df9-97e8-98c7d51a724c.png)", + "milestone": "5.3.0", + "contributors": [ + "rique223", + "web-flow" + ] + }, + { + "pr": "27044", + "title": "[IMPROVE] Change status/price badge to fuselage tag", + "userLogin": "rique223", + "description": "## Jira task: [MKP-131](https://rocketchat.atlassian.net/browse/MKP-131?atlOrigin=eyJpIjoiODRjOTk4OGYyZDAwNDIzNmI5N2EyZGRhNTUxOGY2NGEiLCJwIjoiaiJ9)\r\nChanged the custom component that showed prices and statuses to a fuselage Tag component for maintainability reasons since after this PR every general design change to the tag component will be automatically reflected in the marketplace UI.\r\nDemo image (App List):\r\n![image](https://user-images.githubusercontent.com/43561537/194942430-ba4153f1-2315-4117-85e6-01832cc09d91.png)\r\n\r\nDemo Image (App price):\r\n![image](https://user-images.githubusercontent.com/43561537/194942498-5ff64a27-7232-47b8-a686-2fda2289e491.png)", + "milestone": "5.3.0", + "contributors": [ + "rique223", + "dougfabris", + "web-flow" + ] + }, + { + "pr": "27067", + "title": "Merge master into develop & Set version to 5.3.0-develop", + "userLogin": "tassoevan", + "contributors": [ + "filipemarins", + "tassoevan", + "pierre-lehnen-rc", + "debdutdeb", + "sampaiodiego", + "web-flow", + "d-gubert" + ] + }, + { + "pr": "27059", + "title": "Chore: Bump Apps-Engine version", + "userLogin": "d-gubert", + "milestone": "5.2.0", + "contributors": [ + "d-gubert" + ] + } + ] + }, + "5.3.0-rc.1": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27107", + "title": "[FIX] CSS vars usage", + "userLogin": "ggazzo", + "contributors": [ + "juliajforesti", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27100", + "title": "Regression: Remove margin-bottom inside UserCard actions", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27019", + "title": "Chore: Update Image and link previews", + "userLogin": "filipemarins", + "description": "- Add message generic cover image preview component to OEmbed Links\r\n- Add new functionalities to URL Image preview, like click to open preview and arrows to move between images in the current chat\r\n- Design changes to keep the original aspect ratio of the image to prevent loss of important image pieces of information \r\n- Add fallback to common issues related to meta tags like `og:image` and others", + "milestone": "5.3.0", + "contributors": [ + "filipemarins", + "hugocostadev", + "web-flow", + "gabriellsh" + ] + } + ] + }, + "5.3.0-rc.2": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "26859", + "title": "[NEW] Matrix federation events coverage expansion (adding support for 3 extra events)", + "userLogin": "MarcosSpessatto", + "description": "FED-17\r\nFED-25\r\nFED-27\r\nFED-28\r\nFED-30\r\nThe goal of this PR is to add support for more events on Matrix Federation feature. The new supported events are:\r\n\r\n- Mentions\r\n- User avatar sync\r\n- Quotes", + "milestone": "5.3.0", + "contributors": [ + "MarcosSpessatto" + ] + }, + { + "pr": "27110", + "title": "Regression: Quote colors", + "userLogin": "gabriellsh", + "description": "Before\r\n![image](https://user-images.githubusercontent.com/40830821/196947705-f1b2edf9-7341-4d2a-b8e8-4e3720ab7289.png)\r\n\r\n\r\nAfter\r\n![image](https://user-images.githubusercontent.com/40830821/196947512-1267f992-11c7-4ff4-b7a2-9f0b3534f69d.png)", + "contributors": [ + "gabriellsh" + ] + }, + { + "pr": "27116", + "title": "Regression: Toolbox Divider Color", + "userLogin": "dougfabris", + "description": "![image](https://user-images.githubusercontent.com/27704687/197018407-d591d6bc-e390-4bcd-9b6a-0bf0a1420bc2.png)", + "contributors": [ + "dougfabris" + ] + } + ] + }, + "5.3.0-rc.3": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27157", + "title": "Chore: bump fuselage packages", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27122", + "title": "Chore: bump fuselage packages", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "ggazzo" + ] + }, + { + "pr": "27123", + "title": "[FIX] Microphone icon alignment issue (# 27073)", + "userLogin": "mani-rsg", + "description": "Aligned microphone icon to its respective position on screen widths <= 500 (mobile screens)\r\n\r\n\"image\"\r\n\"image\"", + "contributors": [ + "mani-rsg" + ] + }, + { + "pr": "27120", + "title": "Regression: Unify `isLastDocDelayed` logic", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "26966", + "title": "[FIX] starting conferences with mic and cam on their default states do not sync the state with the provider", + "userLogin": "dougfabris", + "description": "Task: [VC-3]", + "milestone": "5.4.0", + "contributors": [ + "dougfabris" + ] + } + ] + }, + "5.3.0": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [] + }, + "5.3.1": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27243", + "title": "[FIX] Multi instance error message", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27240", + "title": "[FIX] Next schedule check for Apps", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27151", + "title": "[FIX] Hide system messages setting not being respected.", + "userLogin": "gabriellsh", + "description": "There was a query missing the parameters in the client.\r\n\r\nAlso added a few tests to help reduce the risk of this happening again.", + "milestone": "5.3.1", + "contributors": [ + "gabriellsh", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27229", + "title": "Chore: Check for Cloud client secret to check if workspace is registered", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27105", + "title": "[FIX] File upload receiving whole file to apply limits", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego", + "web-flow", + "ggazzo", + "casalsgh" + ] + }, + { + "pr": "27167", + "title": "[FIX] User merge by e-mail on OAuth is case-sensitive", + "userLogin": "matheusbsilva137", + "description": "- Ignore case when searching for a user by email.", + "milestone": "5.3.1", + "contributors": [ + "matheusbsilva137", + "kodiakhq[bot]", + "web-flow" + ] + } + ] + }, + "5.3.2": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27259", + "title": "[FIX] Sidebar Room list extended preview not updating on new messages.", + "userLogin": "gabriellsh", + "milestone": "5.3.2", + "contributors": [ + "gabriellsh" + ] + }, + { + "pr": "27294", + "title": "[FIX] Replace regex not compatible with safari", + "userLogin": "filipemarins", + "milestone": "5.3.2", + "contributors": [ + "filipemarins" + ] + } + ] + }, + "4.8.7": { + "node_version": "14.18.3", + "npm_version": "6.14.15", + "mongo_versions": [ + "3.6", + "4.0", + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [] + }, + "5.0.8": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [] + }, + "5.1.5": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [] + }, + "5.2.1": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [] + }, + "5.3.3": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [] + }, + "5.3.4": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27391", + "title": "[FIX] Thread messages being included in the room history even though they are not displayed", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27340", + "title": "Release 5.3.3", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + } + ] + }, + "5.3.5": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27435", + "title": "[FIX] Fix watch db being started on Micro Services env", + "userLogin": "ggazzo", + "milestone": "5.4.0", + "contributors": [ + "ggazzo" + ] + } + ] + }, + "5.4.0-rc.0": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27437", + "title": "Release 5.3.5", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27435", + "title": "[FIX] Fix watch db being started on Micro Services env", + "userLogin": "ggazzo", + "milestone": "5.4.0", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27392", + "title": "Release 5.3.4", + "userLogin": "ggazzo", + "contributors": [ + "dougfabris", + "ggazzo" + ] + }, + { + "pr": "27391", + "title": "[FIX] Thread messages being included in the room history even though they are not displayed", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27340", + "title": "Release 5.3.3", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27297", + "title": "Release 5.3.2", + "userLogin": "ggazzo", + "contributors": [ + "filipemarins", + "ggazzo", + "gabriellsh" + ] + }, + { + "pr": "27261", + "title": "Release 5.3.1", + "userLogin": "ggazzo", + "contributors": [ + "matheusbsilva137", + "ggazzo", + "sampaiodiego", + "gabriellsh" + ] + }, + { + "pr": "27243", + "title": "[FIX] Multi instance error message", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27240", + "title": "[FIX] Next schedule check for Apps", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27151", + "title": "[FIX] Hide system messages setting not being respected.", + "userLogin": "gabriellsh", + "description": "There was a query missing the parameters in the client.\r\n\r\nAlso added a few tests to help reduce the risk of this happening again.", + "milestone": "5.3.1", + "contributors": [ + "gabriellsh", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27229", + "title": "Chore: Check for Cloud client secret to check if workspace is registered", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27105", + "title": "[FIX] File upload receiving whole file to apply limits", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego", + "web-flow", + "ggazzo", + "casalsgh" + ] + }, + { + "pr": "27167", + "title": "[FIX] User merge by e-mail on OAuth is case-sensitive", + "userLogin": "matheusbsilva137", + "description": "- Ignore case when searching for a user by email.", + "milestone": "5.3.1", + "contributors": [ + "matheusbsilva137", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27333", + "title": "[NEW] Custom MessageType for video conference messages", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.4.0", + "contributors": [ + "pierre-lehnen-rc", + "web-flow" + ] + }, + { + "pr": "27148", + "title": "[FIX] User email address does not change when provisioned by OAuth", + "userLogin": "carlosrodrigues94", + "milestone": "5.4.0", + "contributors": [ + "carlosrodrigues94", + "matheusbsilva137", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27334", + "title": "Regression: Fix sidebar token highlighted usage", + "userLogin": "ggazzo", + "milestone": "5.4.0", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27332", + "title": "Regression: videoconf block showing a zero when no user has joined the call", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.4.0", + "contributors": [ + "pierre-lehnen-rc" + ] + }, + { + "pr": "27331", + "title": "Regression: Restore fuselage-ui-kit version", + "userLogin": "dougfabris", + "milestone": "5.4.0", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27324", + "title": "Chore: Beta Dark Theme switch", + "userLogin": "juliajforesti", + "description": "Add RadioButton on UserDropDown to toggle between light and dark theme.", + "contributors": [ + "juliajforesti", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27326", + "title": "Chore: change apps-engine version", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.4.0", + "contributors": [ + "pierre-lehnen-rc" + ] + }, + { + "pr": "27310", + "title": "[NEW] Video Conference Message blocks and info action", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "ggazzo", + "tassoevan", + "pierre-lehnen-rc" + ] + }, + { + "pr": "27316", + "title": "Chore: Fixed typo in a comment", + "userLogin": "xareyli", + "contributors": [ + "xareyli", + "web-flow" + ] + }, + { + "pr": "27306", + "title": "i18n: Language update from LingoHub 🤖 on 2022-11-21Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "yash-rajpal", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27312", + "title": "[FIX] LDAP groups to channel mapping attempts to create a new room instead of using an existing one", + "userLogin": "matheusbsilva137", + "description": "- Check rooms' name and **display name** in order to confirm they don't exist (and then try to create a new room).", + "milestone": "5.4.0", + "contributors": [ + "matheusbsilva137", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27280", + "title": "[NEW] Incompatible Apps", + "userLogin": "matheuslc", + "milestone": "5.4.0", + "contributors": [ + "matheuslc", + "casalsgh", + "web-flow", + "rique223", + "dougfabris" + ] + }, + { + "pr": "27320", + "title": "Regression: Fix custom oauth undefined clientConfig", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27307", + "title": "[FIX] Upgrading fuselage package and fix quote message prepend ", + "userLogin": "hugocostadev", + "description": "Adding heading styles to message\r\n\r\n\r\n### [OLD] As it was before this change:\r\n\"image\"\r\n\r\n### [NEW] As it is NOW:\r\n\"image\"\r\n\r\n---\r\n\r\nFix heading style in quote messages\r\n\r\nBefore:\r\n\"Screen\r\n\r\nAfter:\r\n\"Screen", + "milestone": "5.4.0", + "contributors": [ + "hugocostadev", + "web-flow", + "guijun13" + ] + }, + { + "pr": "27319", + "title": "Regression: fix contact chat history borders", + "userLogin": "MartinSchoeler", + "contributors": [ + "MartinSchoeler" + ] + }, + { + "pr": "27318", + "title": "[FIX] Adjust read only toggle on create channel based on permissions", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27181", + "title": "[FIX] Featured apps disappearing, install toast config and save changes button behavior", + "userLogin": "rique223", + "description": "## Jira tasks\r\nFeatured apps disappearing: [MKP-161](https://rocketchat.atlassian.net/browse/MKP-161?atlOrigin=eyJpIjoiYjI4MWMyODJkZjlkNDEwMjhkZWFhNjkxZjBiZTJiOGMiLCJwIjoiaiJ9)\r\nInstall toast config: [MKP-162](https://rocketchat.atlassian.net/browse/MKP-162?atlOrigin=eyJpIjoiNjNhNDJjZGE5YWQ5NDJiMWIyZjM4MjMwNmI1MmE5NjUiLCJwIjoiaiJ9)\r\nSave changes button behavior: [MKP-163](https://rocketchat.atlassian.net/browse/MKP-163?atlOrigin=eyJpIjoiZjc3MzUwZTNmYjU3NDJiZjhlOWI0OGIzMGY3ZWQ5ODUiLCJwIjoiaiJ9)\r\n\r\nFixed three bugs: In the first one featured apps would disappear from the apps list after installation, in the second one the install toast wasn't correctly configured, and in the third one the app details page save button would render even when the current app wasn't installed.\r\nDemo gif:\r\n\r\n![featured_disappearing](https://user-images.githubusercontent.com/43561537/199850435-ca9e8ba1-7924-414e-96f4-dfb373fdd754.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223", + "web-flow", + "casalsgh" + ] + }, + { + "pr": "23580", + "title": "[NEW] Bugsnag client", + "userLogin": "ggazzo", + "milestone": "5.4.0", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27246", + "title": "[IMPROVE] Add update option to apps list kebab menu and implement new update badge on apps list", + "userLogin": "rique223", + "description": "Added a new update option to the app menu to follow the removal of the CTA buttons from the apps list. Also implemented the new update badge that will replace the old update button.\r\nDemo gif:\r\n![update_badge](https://user-images.githubusercontent.com/43561537/202225372-c0369bea-12d4-4ea3-8996-8d4edab00722.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223", + "web-flow", + "dougfabris", + "kodiakhq[bot]" + ] + }, + { + "pr": "27302", + "title": "Chore: Convert chat history react", + "userLogin": "MartinSchoeler", + "milestone": "5.4.0", + "contributors": [ + "MartinSchoeler", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27311", + "title": "[FIX] Ensure onetime job runs according to 'startupSetting' everytime", + "userLogin": "thassiov", + "description": "- Fixes the condition of not running a _onetime job_ at the app's startup scheduled to run by using the [`startupSetting`](https://github.com/RocketChat/Rocket.Chat.Apps-engine/blob/04f5930244836043040a8c42beff0690a2359a53/src/definition/scheduler/IProcessor.ts#L8) if the job was run previously at another app startup (Agenda does not remove already run jobs from the database, preventing the app from scheduling the job a second time as it thinks the job is already scheduled);\r\n- Declutters the scheduler's collection by removing _onetime jobs_ documents after they are run.", + "milestone": "5.4.0", + "contributors": [ + "thassiov" + ] + }, + { + "pr": "21790", + "title": "[IMPROVE] Sorting functionality in team channel while leaving a team", + "userLogin": "sumukhah", + "milestone": "5.4.0", + "contributors": [ + "sumukhah", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27004", + "title": "[FIX] Modifying userActionIndicator syntax for translations", + "userLogin": "TBG-FR", + "milestone": "5.4.0", + "contributors": [ + "TBG-FR", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "21297", + "title": "Chore: Fix grammatical typos in release.md", + "userLogin": "sumukhah", + "milestone": "5.4.0", + "contributors": [ + "sumukhah", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "26742", + "title": "Chore: create MailerRoute endpoints", + "userLogin": "felipe-rod123", + "description": "Created 'email-inbox.sendMail' endpoint for the `apps/meteor/client/views/admin/mailer/MailerRoute.tsx` file.", + "milestone": "5.4.0", + "contributors": [ + "felipe-rod123", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "23136", + "title": "[FIX] Thread view expand command in wide screens", + "userLogin": "edward-raven", + "milestone": "5.4.0", + "contributors": [ + "edward-raven", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "21976", + "title": "[FIX] Show Favorite icon only if user has joined room", + "userLogin": "shrinish123", + "description": "Before: There was a favorite button even if the user hasn't joined the room\r\n\r\nAfter:\r\n\r\n![favorite new](https://user-images.githubusercontent.com/56491104/117336514-e8a14d00-aeb9-11eb-8c06-618bdaefa35f.png)", + "milestone": "5.4.0", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "26853", + "title": "[FIX] Scrollable report message", + "userLogin": "yasemincidem", + "milestone": "5.4.0", + "contributors": [ + "yasemincidem", + "web-flow", + "yash-rajpal", + "ggazzo" + ] + }, + { + "pr": "27184", + "title": "[IMPROVE] Add message name container component to message name header and system message", + "userLogin": "filipemarins", + "description": "Add `MessageNameContainer` wrapper to display `name` and `username` inline and separate them with a blank space.\r\n\r\nUpdate font size of system message:\r\n\r\nBefore:\r\n![Screenshot 2022-11-08 at 13 51 58](https://user-images.githubusercontent.com/9275105/200626484-bfcf3eb2-ac36-4b6c-8158-b84bf93023bd.png)\r\n\r\n\r\nAfter:\r\n\"Screenshot\r\n\r\n\r\nAdd removed message variation to `ThreadMessageOrigin` component\r\nBefore:\r\n![Screenshot 2022-11-08 at 13 35 45](https://user-images.githubusercontent.com/9275105/200622876-5e5bd7a2-2df1-453a-9e81-96635390648e.png)\r\n\r\nAfter:\r\n\"Screenshot", + "milestone": "5.4.0", + "contributors": [ + "filipemarins", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "20476", + "title": "[FIX] Archived channels reappearing permanently", + "userLogin": "im-adithya", + "milestone": "5.4.0", + "contributors": [ + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27290", + "title": "[FIX] Integration history breaking when there's more than 49 records", + "userLogin": "gabriellsh", + "description": "Aditionally, fixed example data for incoming webhooks and converted some files to TS.", + "milestone": "5.4.0", + "contributors": [ + "gabriellsh" + ] + }, + { + "pr": "27245", + "title": "[FIX] MarkdownText component not respecting `Markdown_SupportSchemesForLink` setting", + "userLogin": "gabriellsh", + "milestone": "5.4.0", + "contributors": [ + "gabriellsh" + ] + }, + { + "pr": "27153", + "title": "[IMPROVE] VideoConf Miss Config Modal", + "userLogin": "dougfabris", + "description": "Jira Issue: [VC-9]\r\n\r\n", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27314", + "title": "Chore: Updates rocket.cat's logo to match colors of our new logo", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27262", + "title": "[IMPROVE] Improve searchChats endpoint to have source filter support", + "userLogin": "KevLehman", + "milestone": "5.4.0", + "contributors": [ + "KevLehman" + ] + }, + { + "pr": "26415", + "title": "Chore: create AccountProfileForm endpoints", + "userLogin": "felipe-rod123", + "description": "Created the '/v1/users.checkUsernameAvailability' and other endpoints for the `apps/meteor/client/views/account/profile/AccountProfileForm.tsx` file, and added Ajv validations.", + "milestone": "5.4.0", + "contributors": [ + "felipe-rod123", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27160", + "title": "Chore: Create new endpoint for test webhooks and deprecate meteor method", + "userLogin": "KevLehman", + "milestone": "5.4.0", + "contributors": [ + "KevLehman", + "web-flow" + ] + }, + { + "pr": "26754", + "title": "[IMPROVE] Read threads when marking a room as read", + "userLogin": "LucianoPierdona", + "description": "This PR changes the functionality of `subscription.read` to add read threads when endpoint is called", + "milestone": "5.4.0", + "contributors": [ + "LucianoPierdona", + "web-flow", + "debdutdeb", + "matheusbsilva137", + "ggazzo" + ] + }, + { + "pr": "21974", + "title": "Chore: README.md", + "userLogin": "satishp962", + "milestone": "5.4.0", + "contributors": [ + "satishp962", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "26956", + "title": "Chore: deprecate refreshClients methods", + "userLogin": "felipe-rod123", + "description": "Created the 'assets.refreshClients' endpoint for the `apps/meteor/client/views/admin/settings/groups/AssetsGroupPage.tsx` file.", + "milestone": "5.4.0", + "contributors": [ + "felipe-rod123", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27239", + "title": "[IMPROVE] Marketplace feedback toasts", + "userLogin": "rique223", + "description": "## Jira tasks\r\nSave app changes toast: [MKP-160](https://rocketchat.atlassian.net/browse/MKP-160?atlOrigin=eyJpIjoiMjM1YmZjMTVjZGU2NGUwMGIxNTRlYTEwODgwMDk2ZDkiLCJwIjoiaiJ9)\r\nUninstall app toast: [MKP-168](https://rocketchat.atlassian.net/browse/MKP-168?atlOrigin=eyJpIjoiOThkMjEwOTk5NjhiNDE2OGEwY2MyNWEyNWM5YzNkMTUiLCJwIjoiaiJ9)\r\nEnable/disable app feedback toast: [MKP-169](https://rocketchat.atlassian.net/browse/MKP-169?atlOrigin=eyJpIjoiN2VjODIzOGMwNmJkNGU3N2JhOWEzMDU3Y2IxZjZkNWMiLCJwIjoiaiJ9)\r\n\r\n\r\nImplemented/refactored four toast notifications and refactored another two in marketplace. The first one happens after the user saves the settings of an app, the second one when the user successfully uninstalls an app and the third and fourth ones happen when the user enables and disables an app respectfully.\r\nDemo gif:\r\n![feedback_toasts](https://user-images.githubusercontent.com/43561537/202277707-a3b38536-e090-4c4f-96b4-8e21bcd10070.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26187", + "title": "Chore: Replace all saveUserPreferences method calls", + "userLogin": "yash-rajpal", + "milestone": "5.4.0", + "contributors": [ + "yash-rajpal", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27205", + "title": "Chore: Convert omni libs to typescript ", + "userLogin": "KevLehman", + "milestone": "5.4.0", + "contributors": [ + "KevLehman" + ] + }, + { + "pr": "23632", + "title": "[IMPROVE] Adding a noscript tag for letting users know if they have JS disabled", + "userLogin": "sidmohanty11", + "milestone": "5.4.0", + "contributors": [ + "sidmohanty11", + "gabriellsh" + ] + }, + { + "pr": "26957", + "title": "[FIX] Change GridFS error message validation", + "userLogin": "tapiarafael", + "description": "Allow uninstalling an app even if source files cannot be found. This validation was already done in the past, but since the error message was changed, the validation was broken.", + "milestone": "5.4.0", + "contributors": [ + "tapiarafael", + "casalsgh", + "web-flow" + ] + }, + { + "pr": "21655", + "title": "[FIX] The parent room icon is now clickable", + "userLogin": "shrinish123", + "description": "The parent room icon as shown in the video was not clickable but the cursor type on the icon was a pointer. Now even clicking on the icon or anywhere on the parent room tag will redirect you to the parent room. \r\n\r\nBefore : \r\n\r\nhttps://user-images.githubusercontent.com/56491104/115318759-06717100-a19c-11eb-85e6-f3ad4d788721.mp4\r\n\r\n\r\nAfter: \r\n\r\n\r\nhttps://user-images.githubusercontent.com/56491104/115318784-15582380-a19c-11eb-9aca-b40b872774ad.mp4", + "milestone": "5.4.0", + "contributors": [ + "shrinish123", + "web-flow", + "juliajforesti" + ] + }, + { + "pr": "27117", + "title": "[FIX] Delete first message when initializing thread returns black screen", + "userLogin": "filipemarins", + "milestone": "5.4.0", + "contributors": [ + "filipemarins", + "guijun13", + "web-flow" + ] + }, + { + "pr": "27214", + "title": "[IMPROVE] Add searchTerm support for livechat/rid/messages API", + "userLogin": "KevLehman", + "milestone": "5.4.0", + "contributors": [ + "KevLehman" + ] + }, + { + "pr": "27265", + "title": "[FIX] Improper grammar when converting channel member to owner", + "userLogin": "JoshMcCullough", + "milestone": "5.4.0", + "contributors": [ + "JoshMcCullough", + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27299", + "title": "Chore: Deprecation warning on 'typing' stream event.", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.4.0", + "contributors": [ + "pierre-lehnen-rc" + ] + }, + { + "pr": "26634", + "title": "Chore: removing useEndpointData from license api", + "userLogin": "hugocostadev", + "description": "The deprecated hook `useEndpointData` was removed and changed to `useMethod` + `useQuery`separated in a hook.\r\n\r\nIn `useQuery` options we added an option to keep the cache as `Infinity` until the queries are invalidated or the page refreshes, also the query keys were changed to consolidate the keys and manage the cache in the best way possible to avoid unnecessary API calls. \r\n\r\nIn settings changed or user action that impact the License status was added a method to invalidate the cache for license query keys\r\n\r\nE.g: `queryClient.invalidateQueries(['licenses']);`", + "milestone": "5.4.0", + "contributors": [ + "hugocostadev" + ] + }, + { + "pr": "27301", + "title": "Chore: Create unique index for `E2EKey` field", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26842", + "title": "[FIX] LDAP \"Sync Roles\" option doesn't work for custom roles", + "userLogin": "LucianoPierdona", + "description": "Previously the sync of custom fields on LDAP wasn't working because the check was assuming that the `name` of the role is the same value from `_id`, which is the same for initial roles, but different for custom.", + "milestone": "5.4.0", + "contributors": [ + "LucianoPierdona", + "matheusbsilva137", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27300", + "title": "Chore: UserAvatar wrapper missing key in RoomForeword", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27295", + "title": "Chore: Add deprecation warning to settings", + "userLogin": "gabriellsh", + "description": "![image](https://user-images.githubusercontent.com/40830821/202707905-dc7e2b02-35ec-4abd-9b91-26b6e66a7124.png)\r\n\r\nList of settings:\r\n- Show edited status\r\n- Allow Message snippeting\r\n- Show formating Tips\r\n- Disable Embeded for Users\r\n- Issue tracker links\r\n- Message attachments > Group Attachment Buttons\r\n- Markdown > All settings inside Group\r\n- Autolinker > All settings inside Group\r\n\r\nEdited Message for old federation.", + "milestone": "5.4.0", + "contributors": [ + "gabriellsh", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27197", + "title": "Chore: Refactor LeaveTeam to Typescript", + "userLogin": "dougfabris", + "description": "Additionally, it fixes: \r\n- Users would be able to select team channels that they want to leave while leaving the team.\r\n- Users would now automatically leave from team channels he/she selected.\r\n\r\nBEFORE\r\n\r\n\r\n\r\nhttps://user-images.githubusercontent.com/55157259/116005794-24205980-a626-11eb-888e-59e42ca21f9a.mp4\r\n\r\n\r\n\r\n\r\n\r\nBEFORE\r\n\r\nhttps://user-images.githubusercontent.com/55157259/115970150-4babef00-a55e-11eb-97c9-45683ac16cc1.mp4\r\n\r\nAFTER\r\n\r\nhttps://user-images.githubusercontent.com/55157259/116005344-21bd0000-a624-11eb-8e58-a956579a08b4.mp4\r\n\r\n\r\nAFTER\r\n\r\nhttps://user-images.githubusercontent.com/55157259/115970155-5070a300-a55e-11eb-877f-862dd9a974d7.mp4", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "23830", + "title": "[FIX] Sidebar context menu in searchList", + "userLogin": "Aman-Maheshwari", + "description": "Removed onClose function from the Box Component inside `searchList.js` as this component wraps the complete list which is rendered and when clicked on the any rendered row inside the component it closes the searchList preventing the context menu to be displayed.\r\nAlso added `usePreventDefault` hook.\r\n## Before\r\n\r\nhttps://user-images.githubusercontent.com/50165440/144127826-9b6d3e5e-9442-49dc-89c8-b604b910be4c.mp4\r\n\r\n## After\r\n\r\nhttps://user-images.githubusercontent.com/50165440/144127815-d60e1026-a0eb-4e9b-a7f3-fe80dd06a2d8.mp4", + "milestone": "5.4.0", + "contributors": [ + "Aman-Maheshwari", + "web-flow", + "dougfabris", + "kodiakhq[bot]" + ] + }, + { + "pr": "27119", + "title": "[NEW] Federation events coverage expansion", + "userLogin": "MarcosSpessatto", + "description": "This PR adds the following features for the Matrix Federation feature:\r\n- Ability to sync Users' real names (since they have at least one room in common with other users);\r\n- User typing event;", + "milestone": "5.4.0", + "contributors": [ + "MarcosSpessatto" + ] + }, + { + "pr": "27284", + "title": "[FIX] Message Parser version upgrade", + "userLogin": "hugocostadev", + "milestone": "5.4.0", + "contributors": [ + "hugocostadev", + "gabriellsh", + "web-flow" + ] + }, + { + "pr": "27294", + "title": "[FIX] Replace regex not compatible with safari", + "userLogin": "filipemarins", + "milestone": "5.3.2", + "contributors": [ + "filipemarins" + ] + }, + { + "pr": "27003", + "title": "[NEW] Emphasis Elements (italic, strike and bold) in Message Parser Components", + "userLogin": "hugocostadev", + "description": "Currently the message parser does not accept Emphasis elements mixed with plain text\r\n\r\n`[Normal Link - *Bold*, _Italic_ and ~strike~ Styles](https://rocket.chat/)` return plain text → Should return a Lin with bold/italic/strike\r\n\r\nTo fix this behavior it was necessary to edit LinkSpan component in gazzodown package (changes included in this PR) and the grammar/utils files in the `fuselage/message-parser` repository\r\n\r\nFuselage Pull Request: https://github.com/RocketChat/fuselage/pull/887/", + "milestone": "5.4.0", + "contributors": [ + "hugocostadev", + "web-flow", + "guijun13", + "kodiakhq[bot]" + ] + }, + { + "pr": "25568", + "title": "[FIX] Set default value \"false\" for global search.", + "userLogin": "ivan1kazantsev", + "description": "If we disable the \"global search\", then the \"global search\" checkbox removes from the UI. It's not what we want. I think, we should set the default to \"false\", because the default is to search inside the channel/dialog.", + "milestone": "5.4.0", + "contributors": [ + "ivan1kazantsev", + "web-flow", + "debdutdeb", + "tassoevan", + "dougfabris", + "sampaiodiego", + "kodiakhq[bot]" + ] + }, + { + "pr": "27244", + "title": "Regression: Custom fields form not showing in user profile nor admin", + "userLogin": "gabriellsh", + "milestone": "5.4.0", + "contributors": [ + "gabriellsh", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27201", + "title": "[FIX] Sort RecordList items in REVERSE chronological order, not FORWARD", + "userLogin": "nmagedman", + "description": "Sort items in the Files sidebar in *reverse* chronological order (newest at top, oldest at bottom), as it did _before_ RC v3.11.0.", + "milestone": "5.4.0", + "contributors": [ + "nmagedman" + ] + }, + { + "pr": "27289", + "title": "Chore: Remove unused css", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27242", + "title": "Chore: also send thread to channel translations", + "userLogin": "yash-rajpal", + "description": "\"image\"", + "milestone": "5.4.0", + "contributors": [ + "yash-rajpal", + "web-flow" + ] + }, + { + "pr": "27062", + "title": "[FIX] Marketplace app details page back-button behavior", + "userLogin": "rique223", + "description": "Jira task: [MKP-26](https://rocketchat.atlassian.net/browse/MKP-26?atlOrigin=eyJpIjoiM2I4MzVhYmQ2OWRkNDE0ZGI4NWZkMzE3MDQwNmIxMzMiLCJwIjoiaiJ9)\r\n\r\nFixed the behavior of the marketplace app details page back button. Now it will return the user to the page they accessed the app details from. Also, refactored the overall routing of the marketplace and removed the admin-apps route as everything is now handled by the admin-marketplace route.\r\n\r\nDemo gif:\r\n![apps-back-button](https://user-images.githubusercontent.com/43561537/195709074-a886472e-5462-474e-8f65-5cfa33d30263.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223", + "web-flow", + "dougfabris", + "juliajforesti" + ] + }, + { + "pr": "27048", + "title": "Chore: Add tests for omni-jobs & add more context in system messages for jobs", + "userLogin": "murtaza98", + "contributors": [ + "murtaza98", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27258", + "title": "Chore: Fix missing license for forks", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27255", + "title": "i18n: Language update from LingoHub 🤖 on 2022-11-14Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "yash-rajpal", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27213", + "title": "[FIX] User auto complete breaks on enter key press", + "userLogin": "yash-rajpal", + "milestone": "5.4.0", + "contributors": [ + "yash-rajpal", + "debdutdeb", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27111", + "title": "[FIX] User approval email doesn't display username and e-mail when user logs in with OAuth", + "userLogin": "carlosrodrigues94", + "milestone": "5.4.0", + "contributors": [ + "carlosrodrigues94", + "matheusbsilva137", + "web-flow", + "gabriellsh" + ] + }, + { + "pr": "27259", + "title": "[FIX] Sidebar Room list extended preview not updating on new messages.", + "userLogin": "gabriellsh", + "milestone": "5.3.2", + "contributors": [ + "gabriellsh" + ] + }, + { + "pr": "27163", + "title": "[FIX] Avg response time calculation", + "userLogin": "KevLehman", + "milestone": "5.4.0", + "contributors": [ + "KevLehman", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27198", + "title": "Chore: Rewrite AutoCompleteDepartment to TypeScript", + "userLogin": "tiagoevanp", + "description": "Department field inside of current chats is one of the places who uses AutoCompleteDeparment:\r\n![image](https://user-images.githubusercontent.com/17487063/200659774-9db7b19d-1e5f-471b-8b7d-540ef3aa59fb.png)", + "milestone": "5.4.0", + "contributors": [ + "tiagoevanp", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26782", + "title": "[IMPROVE] Login rewrite in react", + "userLogin": "ggazzo", + "milestone": "5.4.0", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27243", + "title": "[FIX] Multi instance error message", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27240", + "title": "[FIX] Next schedule check for Apps", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27056", + "title": "[IMPROVE] Move app list install logic to app menu", + "userLogin": "rique223", + "description": "## Jira task: [MKP-136](https://rocketchat.atlassian.net/browse/MKP-136?atlOrigin=eyJpIjoiM2M0ODhkZDc0YjQ2NGE5OGE4YTBkZDJhY2M0NGVmZDgiLCJwIjoiaiJ9)\r\nMoved the install/buy/subscribe logic from the CTA buttons that existed in the app list to the app menu. Now the user can install apps by clicking in the kebab menu in the right of the app list entry. Also solved a little undefined bug happening in the app permissions modal.\r\nDemo gif:\r\n![app_menu](https://user-images.githubusercontent.com/43561537/195204630-e66c7859-028f-4654-8367-96029a855b42.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27229", + "title": "Chore: Check for Cloud client secret to check if workspace is registered", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "20459", + "title": "[FIX] Use name if fname is undefined", + "userLogin": "aKn1ghtOut", + "description": "In the default general room(and possibly in other cases), the fname property is not set. The site should use the \"name\" property as a fallback in such cases.\r\n\r\n### After fix\r\n![Screenshot from 2021-01-28 03-47-19](https://user-images.githubusercontent.com/38764067/106062371-b0e97300-611c-11eb-97de-1ff4c668a4c8.png)\r\n![Screenshot from 2021-01-28 03-47-55](https://user-images.githubusercontent.com/38764067/106062374-b21aa000-611c-11eb-83db-93a3d0858d46.png)", + "milestone": "5.4.0", + "contributors": [ + "aKn1ghtOut", + "tassoevan", + "web-flow", + "juliajforesti" + ] + }, + { + "pr": "21602", + "title": "[FIX] Navigate to home after deleting a channel from edit screen", + "userLogin": "sumukhah", + "milestone": "5.4.0", + "contributors": [ + "sumukhah", + "juliajforesti", + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27233", + "title": "[FIX] Shrug missing backslash character", + "userLogin": "hugocostadev", + "description": "Previously the escape character `\\` was escaping everything.\r\n\r\nTo avoid unexpected text formatting errors it was restricted to only escape curtains chars like: * _ ~ ` # . \r\nDoing so the Shrug had to change in the code to display the correct ASCII Art", + "contributors": [ + "hugocostadev", + "gabriellsh", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27230", + "title": "[FIX] Display Edit Team instead of Edit Room when in a team", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27232", + "title": "Chore: Improve configurations related to Typescript in Livechat", + "userLogin": "MartinSchoeler", + "contributors": [ + "MartinSchoeler" + ] + }, + { + "pr": "27223", + "title": "Chore: Make it easier to run micro services", + "userLogin": "sampaiodiego", + "description": "You can now run a microservices environment with `yarn turbo run ms`", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27225", + "title": "[FIX] UiKit modals taking 5 seconds to close", + "userLogin": "pierre-lehnen-rc", + "contributors": [ + "pierre-lehnen-rc", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27222", + "title": "[FIX] AttachmentDescription color token", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti" + ] + }, + { + "pr": "27196", + "title": "[FIX] RoomForeword design", + "userLogin": "juliajforesti", + "description": "Before\r\n![image](https://user-images.githubusercontent.com/60678893/200065803-aaafe740-62f6-4d11-b9a4-c4f394f00291.png)\r\n\r\n\r\nAfter\r\n\"image\"", + "contributors": [ + "juliajforesti", + "web-flow" + ] + }, + { + "pr": "27215", + "title": "Chore: Remove SoundRow.js", + "userLogin": "dougfabris", + "milestone": "5.4.0", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "23741", + "title": "[FIX] multiple user assigned for a role", + "userLogin": "Aman-Maheshwari", + "milestone": "5.4.0", + "contributors": [ + "Aman-Maheshwari", + "tassoevan", + "juliajforesti", + "web-flow", + "dougfabris", + "kodiakhq[bot]" + ] + }, + { + "pr": "21675", + "title": "[FIX] Add sorting channels on teams", + "userLogin": "sumukhah", + "milestone": "5.4.0", + "contributors": [ + "sumukhah", + "web-flow", + "juliajforesti" + ] + }, + { + "pr": "27202", + "title": "i18n: Language update from LingoHub 🤖 on 2022-11-07Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "yash-rajpal", + "web-flow" + ] + }, + { + "pr": "27092", + "title": "[FIX] Always parse encrypted messages on client", + "userLogin": "yash-rajpal", + "milestone": "5.4.0", + "contributors": [ + "yash-rajpal", + "web-flow" + ] + }, + { + "pr": "27047", + "title": "[NEW] Add new endpoint 'livechat/agent.status' & deprecate changeLivechatStatus meteor method ", + "userLogin": "murtaza98", + "milestone": "5.4.0", + "contributors": [ + "murtaza98", + "web-flow", + "KevLehman", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "27136", + "title": "Chore: Rewrite the label/description of the Push_request_content_from_server setting", + "userLogin": "nmagedman", + "description": "Documentation: Clarify the meaning/effect of the setting Push_request_content_from_server (\"Fetch full message content from the server on receipt\"), which can lead to unexpected \"You have a new message\" notifications", + "contributors": [ + "nmagedman" + ] + }, + { + "pr": "24043", + "title": "Chore: Added tooltip to options of message-actions", + "userLogin": "aswinidev", + "description": "https://user-images.githubusercontent.com/76481696/147604643-253d0577-65d6-4bfe-b67e-49a7cc67c03e.mp4", + "milestone": "5.4.0", + "contributors": [ + "aswinidev", + "web-flow", + "juliajforesti", + "ggazzo" + ] + }, + { + "pr": "27167", + "title": "[FIX] User merge by e-mail on OAuth is case-sensitive", + "userLogin": "matheusbsilva137", + "description": "- Ignore case when searching for a user by email.", + "milestone": "5.3.1", + "contributors": [ + "matheusbsilva137", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27105", + "title": "[FIX] File upload receiving whole file to apply limits", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego", + "web-flow", + "ggazzo", + "casalsgh" + ] + }, + { + "pr": "27191", + "title": "Chore: Restrict `ChatMessages` API - Phase 1", + "userLogin": "tassoevan", + "description": "It prepares `ChatMessages` to be splitted into smaller components to handle the interaction of a list of messages and the message composer.", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "27037", + "title": "[FIX] Adjusted form validation to disallow duplicated emails", + "userLogin": "aleksandernsilva", + "description": "This pull request revisits the user info form, fixing a bug that allowed the form to be saved with an already existing e-mail. Taking advantage of this opportunity this PR also refactors the file to typescript and adds new libs like `useForm` and `useQuery`.", + "milestone": "5.4.0", + "contributors": [ + "aleksandernsilva" + ] + }, + { + "pr": "20312", + "title": "Chore: subscriptions.read accepts both \"roomId\" and \"rid\" as payload", + "userLogin": "lucassartor", + "description": "Adding `roomId` as another option of payload in the `subscriptions.read` endpoint besides from `rid`.", + "milestone": "5.4.0", + "contributors": [ + "lucassartor", + "web-flow", + "sampaiodiego", + "kodiakhq[bot]" + ] + }, + { + "pr": "24361", + "title": "[FIX] Add pause functionality to Custom Sounds", + "userLogin": "nishant23122000", + "milestone": "5.4.0", + "contributors": [ + "nishant23122000", + "debdutdeb", + "web-flow", + "dougfabris", + "ggazzo" + ] + }, + { + "pr": "27170", + "title": "Chore(deps): Bump felixmosh/turborepo-gh-artifacts from 1 to 2", + "userLogin": "dependabot[bot]", + "contributors": [ + "dependabot[bot]", + "web-flow" + ] + }, + { + "pr": "21677", + "title": "[FIX] Adding error message for wrong dates", + "userLogin": "shrinish123", + "description": "Before : \r\n![before](https://user-images.githubusercontent.com/56491104/115405052-85ea5900-a20b-11eb-9c78-5e98de6c454c.png)\r\n\r\nAfter: \r\n\r\n![after export](https://user-images.githubusercontent.com/56491104/115405085-8da9fd80-a20b-11eb-8b72-de9ef7c2217b.png)", + "milestone": "5.4.0", + "contributors": [ + "KevLehman", + "ggazzo", + "web-flow", + "shrinish123" + ] + }, + { + "pr": "21603", + "title": "[FIX] Show a consistent name on information screen", + "userLogin": "sumukhah", + "milestone": "5.4.0", + "contributors": [ + "sumukhah", + "web-flow", + "dougfabris", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "20338", + "title": "Chore: New Password field is confusing", + "userLogin": "im-adithya", + "milestone": "5.4.0", + "contributors": [ + "im-adithya", + "web-flow", + "gabriellsh" + ] + }, + { + "pr": "21766", + "title": "Chore: Remove blank owner field from rooms ", + "userLogin": "Kartik18g", + "milestone": "5.4.0", + "contributors": [ + "Kartik18g", + "web-flow", + "gabriellsh" + ] + }, + { + "pr": "20324", + "title": "[FIX] Fixed Allow reacting toggle button in Edit room", + "userLogin": "Darshilp326", + "description": "Users can now see changes for toggling allow reacting button after changes.\r\nUsers do not need to come back for changing allow reacting button.\r\n\r\nhttps://user-images.githubusercontent.com/55157259/105572410-f274c980-5d7c-11eb-806a-e23c2abd37de.mp4", + "milestone": "5.4.0", + "contributors": [ + "Darshilp326", + "web-flow", + "dougfabris", + "kodiakhq[bot]", + "ggazzo" + ] + }, + { + "pr": "27199", + "title": "Chore: Remove turborepo if env is not set", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "24605", + "title": "[IMPROVE] Removed tool tip from sidebar menu", + "userLogin": "Himanshu664", + "milestone": "5.4.0", + "contributors": [ + "Himanshu664", + "juliajforesti" + ] + }, + { + "pr": "27046", + "title": "Chore: Migrate EE LivechatRooms model to typescript", + "userLogin": "murtaza98", + "milestone": "5.4.0", + "contributors": [ + "murtaza98", + "KevLehman" + ] + }, + { + "pr": "27189", + "title": "[FIX] Add condition to createUser button on UsersPage", + "userLogin": "juliajforesti", + "description": "Hide the create user button in admin if the user doesn't have the permission to do so. It was not the case before.\r\n\r\n\r\nhttps://user-images.githubusercontent.com/45966964/115802514-5ab86300-a3df-11eb-98d8-7aba696bfa7e.mp4", + "contributors": [ + "juliajforesti", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26973", + "title": "[FIX] Install private apps modal behavior marketplace", + "userLogin": "rique223", + "description": "Fixed two bugs in the private app install page: \r\n- The first one is a lack of pt-br translation to the agree button of the apps permission modal \r\n- The second one is that the review modal did not show the default permission list when the app being installed did not provide a permissions list.\r\n\r\n**Demo gif**:\r\n![AppsPermissionModal](https://user-images.githubusercontent.com/43561537/193342594-5516b557-948a-4d9d-ade3-65bb1600e458.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223", + "web-flow", + "dougfabris" + ] + }, + { + "pr": "27190", + "title": "[FIX] Add condition to invite user if user doesn't have permission", + "userLogin": "juliajforesti", + "description": "If you deactivated the permission to send links, the button was always there and led to an error message.\r\nBefore: \r\n\r\nhttps://user-images.githubusercontent.com/45966964/115801057-23948280-a3dc-11eb-83c2-b3e16f66ddd5.mp4\r\n\r\nAfter:\r\n\r\nhttps://user-images.githubusercontent.com/45966964/115801253-956ccc00-a3dc-11eb-95d0-9baa69410fe1.mp4", + "contributors": [ + "juliajforesti" + ] + }, + { + "pr": "27195", + "title": "Chore: Remove js-preventer Action", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27151", + "title": "[FIX] Hide system messages setting not being respected.", + "userLogin": "gabriellsh", + "description": "There was a query missing the parameters in the client.\r\n\r\nAlso added a few tests to help reduce the risk of this happening again.", + "milestone": "5.3.1", + "contributors": [ + "gabriellsh", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27192", + "title": "Chore: remove auto label action", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27176", + "title": "Chore: Remove secrets.RC_TURBO_GH_TOKEN dep from build", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27183", + "title": "[FIX] Missing React When Read Only setting on Admin Rooms Edit", + "userLogin": "dougfabris", + "description": "When the user was editing a room in the admin, he could not set React When Read Only because the option was not there unlike a normal room edit. So i added the option.", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26871", + "title": "Chore: Test for import ", + "userLogin": "weslley543", + "contributors": [ + "weslley543", + "web-flow" + ] + }, + { + "pr": "27166", + "title": "[FIX] ThreadRow hover color", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27027", + "title": "Chore: CreateTeamModal Refactor", + "userLogin": "dougfabris", + "description": "Jira Issue: [UFR-36]\r\n\r\n- Replace `useForm`\r\n- Improve UI validations on Modal\r\n- Add ToastBar message on creating a team", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27180", + "title": "[FIX] Discussion list timestamp and Edit room system messages", + "userLogin": "gabriellsh", + "contributors": [ + "gabriellsh", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27178", + "title": "[FIX] Discussions list divider on contextualBar", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27177", + "title": "[FIX] Uploading Custom Sound files not working, but showing success", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27156", + "title": "Chore: Show better error logs", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "20878", + "title": "[FIX] Message search breaking URL, usertags and emojis", + "userLogin": "TBG-FR", + "contributors": [ + "TBG-FR", + "sampaiodiego", + "web-flow" + ] + }, + { + "pr": "27054", + "title": "[NEW] REST API endpoint `/v1/oauth-apps.create`", + "userLogin": "felipe-rod123", + "description": "Created the 'oauth-apps.addOAuthApp' endpoint for the `apps/meteor/client/views/admin/oauthApps/OAuthAddApp.tsx` file, and added Ajv validation.", + "contributors": [ + "felipe-rod123", + "sampaiodiego", + "debdutdeb", + "web-flow" + ] + }, + { + "pr": "27150", + "title": "i18n: Language update from LingoHub 🤖 on 2022-10-31Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "dougfabris" + ] + }, + { + "pr": "26936", + "title": "Chore: Convert client/views/directory/hooks to ts", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "web-flow", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "26937", + "title": "Chore: Convert client/views/directory/RoomTags to ts", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27096", + "title": "[FIX] UserCard not opening inside Threads", + "userLogin": "dougfabris", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27165", + "title": "[FIX] Gap between message content and message header when there's no text.", + "userLogin": "gabriellsh", + "description": "Before:\r\n![image](https://user-images.githubusercontent.com/40830821/199314585-f09920bd-efea-4767-824a-783aca2a229a.png)\r\n![image](https://user-images.githubusercontent.com/40830821/199320275-cd32a96c-36a2-4c5b-ac3c-0db6aa57fdf7.png)\r\n\r\nAfter:\r\n![image](https://user-images.githubusercontent.com/40830821/199314648-b6b48512-b8c0-4c11-81bc-d6b97700bf7a.png)\r\n![image](https://user-images.githubusercontent.com/40830821/199320172-c6f986b8-29cd-4b2a-95e6-ffe9d51a8eaa.png)\r\n\r\nAdditionaly removed a component that was being rendered inside itself, causing spacing issues.", + "milestone": "5.4.0", + "contributors": [ + "gabriellsh", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26894", + "title": "Chore: docs grammar fix", + "userLogin": "tusharxoxoxo", + "contributors": [ + "tusharxoxoxo" + ] + }, + { + "pr": "26968", + "title": "[FIX] Removed mobile requirement for showing real name", + "userLogin": "TedsCabin", + "description": "Removed the mobile requirement for allowing real names to be used in message headers.", + "contributors": [ + "TedsCabin", + "web-flow" + ] + }, + { + "pr": "24440", + "title": "Chore: Cursor pointer to all the action buttons", + "userLogin": "sidmohanty11", + "description": "https://user-images.githubusercontent.com/73601258/152863890-88035cbb-ba14-45c4-92ca-22ab4f566281.mp4", + "milestone": "5.4.0", + "contributors": [ + "sidmohanty11", + "dougfabris" + ] + }, + { + "pr": "27109", + "title": "Chore: Bump actions/upload-artifact from 2 to 3", + "userLogin": "rettinghaus", + "description": "Bump actions/upload-artifact from 2 to 3 (no changes in behavior expected)", + "contributors": [ + "rettinghaus", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27144", + "title": "Chore: Enable PR Title Checker for forks", + "userLogin": "tassoevan", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "26915", + "title": "Chore: Converting game center to typescript", + "userLogin": "AllanPazRibeiro", + "contributors": [ + "AllanPazRibeiro", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27127", + "title": "i18n: Language update from LingoHub 🤖 on 2022-10-24Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "yash-rajpal", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27106", + "title": "Chore: Add info log to remove all rooms method", + "userLogin": "KevLehman", + "milestone": "5.4.0", + "contributors": [ + "KevLehman", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26303", + "title": "[IMPROVE] Quotes on E2EE Messages", + "userLogin": "yash-rajpal", + "description": "This PR provides basic quoting to E2EE messages, it doesn't support multiple chaining of quotes messages.\r\n\r\n\"Screenshot", + "contributors": [ + "yash-rajpal", + "web-flow", + "gabriellsh", + "kodiakhq[bot]" + ] + }, + { + "pr": "26866", + "title": "[NEW] REST API endpoint `/v1/rooms.delete`", + "userLogin": "felipe-rod123", + "milestone": "5.4.0", + "contributors": [ + "felipe-rod123", + "web-flow", + "ggazzo", + "sampaiodiego" + ] + }, + { + "pr": "27060", + "title": "[FIX] Room Avatar being deleted after upload.", + "userLogin": "gabriellsh", + "description": "Remove avatar before updating it. S3 already overwrites the old image, but since this part of the code is shared among many other File Storage providers, we need to make this deletion before the upload.", + "milestone": "5.4.0", + "contributors": [ + "gabriellsh", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27061", + "title": "Chore: Apps/Marketplace code organization", + "userLogin": "dougfabris", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "rique223", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27162", + "title": "Merge master into develop & Set version to 5.4.0-develop", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + } + ] + }, + "5.4.0-rc.1": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27281", + "title": "Chore: Remove role requirement to use change streams", + "userLogin": "sampaiodiego", + "description": "We used to require the `clusterMonitor` role to be able to use Change Streams because we performed a `serverStatus` command, to be able to check if the requirements for change streams are met (like using wired tiger for example). But since our minimum MongoDB supported version is now 4.2, and MMAPv1 [was removed on this version](https://www.mongodb.com/docs/v4.2/core/storage-engines/), there is no need to check that.\r\n\r\nThe new approach is just try to use change streams, if it fails for any reason, fallback to oplog.\r\n\r\nIf oplog fails as well, we're now halting the process, since it wasn't able to establish a connection for reading real time data, something that is crucial for the application. An additional check was added to make sure `$MONGO_OPLOG_URL` is pointing to the `local` database.", + "milestone": "5.4.0", + "contributors": [ + "sampaiodiego", + "web-flow" + ] + }, + { + "pr": "27344", + "title": "Regression: Remove actions from VideoConf Message Block", + "userLogin": "dougfabris", + "contributors": [ + "gabriellsh", + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26717", + "title": "Chore: Fix typo in pa-in.js", + "userLogin": "eltociear", + "contributors": [ + "eltociear", + "web-flow", + "debdutdeb", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "27345", + "title": "Regression: Team name validation on Create Team Modal", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + } + ] + }, + "5.4.0-rc.2": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27391", + "title": "[FIX] Thread messages being included in the room history even though they are not displayed", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27386", + "title": "Chore: Update dark theme tokens", + "userLogin": "juliajforesti", + "description": "Update dark theme tokens: \r\n- surface-tint \r\n- button-background-secondary-disabled \r\n- button-background-secondary-danger-disabled\r\n- all status-background\r\n- all status-font", + "contributors": [ + "juliajforesti", + "dougfabris" + ] + }, + { + "pr": "26858", + "title": "[FIX] `channels.convertToTeam` endpoint doesn't work when only the `channelName` param is provided", + "userLogin": "matheusbsilva137", + "description": "- Fix the `channels.convertToTeam` endpoint not working when the `channelName` is sent as parameter.", + "contributors": [ + "matheusbsilva137", + "web-flow", + "sampaiodiego" + ] + }, + { + "pr": "27363", + "title": "Chore: Update badge tokens", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti" + ] + }, + { + "pr": "27382", + "title": "Regression: VideoConf default info modal not showing meeting URL as a link", + "userLogin": "pierre-lehnen-rc", + "description": "Before:\r\n![image](https://user-images.githubusercontent.com/55164754/204304308-87f6e6d3-8411-4974-8628-d81fd9aa07e5.png)\r\n\r\n\r\nAfter:\r\n![image](https://user-images.githubusercontent.com/55164754/204303619-6bc7b014-7b11-40a5-a1de-1530e76fff8b.png)", + "milestone": "5.4.0", + "contributors": [ + "pierre-lehnen-rc", + "web-flow" + ] + }, + { + "pr": "27375", + "title": "i18n: Language update from LingoHub 🤖 on 2022-11-28Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "dougfabris" + ] + }, + { + "pr": "27365", + "title": "Regression: Update VideoConf components colors", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + } + ] + }, + "5.4.0-rc.3": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27410", + "title": "i18n: Language update from LingoHub 🤖 on 2022-11-29Z", + "userLogin": "lingohub[bot]", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27369", + "title": "Regression: Quoting Issue", + "userLogin": "henit-chobisa", + "milestone": "5.4.0", + "contributors": [ + "henit-chobisa", + "yash-rajpal", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27402", + "title": "Regression: Update VideoConfListItem Color Tokens", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27384", + "title": "Regression: Old threads not opening", + "userLogin": "yash-rajpal", + "milestone": "5.4.0", + "contributors": [ + "yash-rajpal", + "web-flow", + "kodiakhq[bot]" + ] + } + ] + }, + "5.4.0-rc.4": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27408", + "title": "Chore: Update tokens", + "userLogin": "juliajforesti", + "description": "Add/update tokens on light and dark palette:\r\n- update stroke-extra-light color\r\n- add status-warning-2\r\n- add status-service-3\r\n- add font-pure-white\r\n- add font-pure-black", + "contributors": [ + "juliajforesti", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27411", + "title": "Regression: Login and Registration UI Tweaks", + "userLogin": "dougfabris", + "milestone": "5.4.0", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27406", + "title": "Regression: Fix issues with ContactHistoryItem", + "userLogin": "MartinSchoeler", + "milestone": "5.4.0", + "contributors": [ + "MartinSchoeler", + "kodiakhq[bot]", + "web-flow" + ] + } + ] + }, + "5.4.0-rc.5": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27435", + "title": "[FIX] Fix watch db being started on Micro Services env", + "userLogin": "ggazzo", + "milestone": "5.4.0", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "26951", + "title": "[FIX] Unable to set idleTimeLimit for users", + "userLogin": "debdutdeb", + "milestone": "5.4.0", + "contributors": [ + "debdutdeb", + "yash-rajpal" + ] + }, + { + "pr": "27421", + "title": "Regression: Elevation and components z-index fixes", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "ggazzo" + ] + }, + { + "pr": "27433", + "title": "Chore: Update Apps-Engine to latest", + "userLogin": "d-gubert", + "milestone": "5.4.0", + "contributors": [ + "d-gubert" + ] + }, + { + "pr": "27359", + "title": "[FIX] Threads replied message not clickable on new message template", + "userLogin": "filipemarins", + "description": "Add the link to the parent message on the `ThreadMessagePreview` component;\r\nAdd `message ignored` status to the parent message too;\r\nAlso, allow clicking the message when is ignored status.", + "contributors": [ + "filipemarins", + "guijun13", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27387", + "title": "[FIX] Livechat: Allow resolving external image and media blocks ", + "userLogin": "cauefcr", + "description": "Allow external urls to be viewed on livechat.", + "milestone": "5.5.0", + "contributors": [ + "cauefcr", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27414", + "title": "Chore: bumping apps engine version", + "userLogin": "AllanPazRibeiro", + "milestone": "5.4.0", + "contributors": [ + "AllanPazRibeiro", + "d-gubert", + "web-flow" + ] + }, + { + "pr": "27420", + "title": "Regression: message-box-editing-color", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti" + ] + }, + { + "pr": "27422", + "title": "Regression: Admin menu apps option not working", + "userLogin": "rique223", + "description": "Solved a bug caused by the RC production build steps breaking the flow router triggersEnter event that did some rerouting for marketplace. Removed the cited function from the routes.tsx file, and now the rerouting is done directly inside the AppsRoute file.\r\nDemo gif:\r\n![apps_rerouting_issue](https://user-images.githubusercontent.com/43561537/205097014-644be3fd-913e-48d6-8e2b-c082bd8f80cf.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223" + ] + }, + { + "pr": "27416", + "title": "[FIX] Fix Piwik and add extra setting to allow workarounds", + "userLogin": "ggazzo", + "milestone": "5.4.0", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27368", + "title": "Regression: Bad words Filtering not working on new Message Parser", + "userLogin": "xareyli", + "description": "Was\r\n![forGH](https://user-images.githubusercontent.com/118266546/204087809-fca6152b-63db-4873-88b8-d86aeb324531.png)\r\n\r\nNow\r\n![forGH2](https://user-images.githubusercontent.com/118266546/204087822-e3273127-a4f0-4a45-a73e-910eb48c9b6f.png)", + "milestone": "5.4.0", + "contributors": [ + "xareyli", + "kodiakhq[bot]", + "web-flow", + "ggazzo" + ] + } + ] + }, + "5.4.0-rc.6": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27443", + "title": "Regression: fix small issues before release", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "pierre-lehnen-rc", + "web-flow" + ] + }, + { + "pr": "27439", + "title": "Bump version to 5.4.0-develop", + "userLogin": "ggazzo", + "contributors": [ + "matheusbsilva137", + "ggazzo", + "sampaiodiego", + "gabriellsh", + "web-flow", + "dougfabris" + ] + }, + { + "pr": "27437", + "title": "Release 5.3.5", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27435", + "title": "[FIX] Fix watch db being started on Micro Services env", + "userLogin": "ggazzo", + "milestone": "5.4.0", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27392", + "title": "Release 5.3.4", + "userLogin": "ggazzo", + "contributors": [ + "dougfabris", + "ggazzo" + ] + }, + { + "pr": "27391", + "title": "[FIX] Thread messages being included in the room history even though they are not displayed", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27340", + "title": "Release 5.3.3", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27297", + "title": "Release 5.3.2", + "userLogin": "ggazzo", + "contributors": [ + "filipemarins", + "ggazzo", + "gabriellsh" + ] + }, + { + "pr": "27261", + "title": "Release 5.3.1", + "userLogin": "ggazzo", + "contributors": [ + "matheusbsilva137", + "ggazzo", + "sampaiodiego", + "gabriellsh" + ] + }, + { + "pr": "27243", + "title": "[FIX] Multi instance error message", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27240", + "title": "[FIX] Next schedule check for Apps", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27151", + "title": "[FIX] Hide system messages setting not being respected.", + "userLogin": "gabriellsh", + "description": "There was a query missing the parameters in the client.\r\n\r\nAlso added a few tests to help reduce the risk of this happening again.", + "milestone": "5.3.1", + "contributors": [ + "gabriellsh", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27229", + "title": "Chore: Check for Cloud client secret to check if workspace is registered", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27105", + "title": "[FIX] File upload receiving whole file to apply limits", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego", + "web-flow", + "ggazzo", + "casalsgh" + ] + }, + { + "pr": "27167", + "title": "[FIX] User merge by e-mail on OAuth is case-sensitive", + "userLogin": "matheusbsilva137", + "description": "- Ignore case when searching for a user by email.", + "milestone": "5.3.1", + "contributors": [ + "matheusbsilva137", + "kodiakhq[bot]", + "web-flow" + ] + } + ] + }, + "5.4.0": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [] + }, + "5.4.1": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27557", + "title": "[FIX] Custom languages not being applied to i18next", + "userLogin": "ggazzo", + "milestone": "5.4.1", + "contributors": [ + "ggazzo", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27558", + "title": "[FIX] Registration and Login placeholders not being used", + "userLogin": "ggazzo", + "milestone": "5.4.1", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27475", + "title": "[FIX] Fix Login with Show default form disabled", + "userLogin": "ggazzo", + "milestone": "5.4.1", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27328", + "title": "[FIX] Message Actions menu does not close upon choosing an action", + "userLogin": "filipemarins", + "milestone": "5.4.1", + "contributors": [ + "filipemarins", + "yash-rajpal", + "hugocostadev", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27538", + "title": "Chore: Deprecate unused omnichannel API", + "userLogin": "murtaza98", + "milestone": "5.4.1", + "contributors": [ + "murtaza98" + ] + }, + { + "pr": "27432", + "title": "[FIX] Pagination not working on current chats", + "userLogin": "MartinSchoeler", + "milestone": "5.4.1", + "contributors": [ + "MartinSchoeler", + "aleksandernsilva", + "kodiakhq[bot]", + "web-flow" + ] + } + ] + }, + "5.4.2": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27740", + "title": "[FIX] OmnichannelRoomIconProvider order breaking VideoConfPopup", + "userLogin": "dougfabris", + "description": "Jira Issue [VC-39]", + "milestone": "5.4.2", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27617", + "title": "[FIX] `*.files` endpoints returning hidden files", + "userLogin": "sampaiodiego", + "milestone": "5.4.2", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "23301", + "title": "[FIX] Showing thumbnails on files list", + "userLogin": "sampaiodiego", + "milestone": "5.4.2", + "contributors": [ + "carlosrodrigues94", + "ostjen", + "sampaiodiego" + ] + }, + { + "pr": "27000", + "title": "[FIX] New users aren't mapped to rooms with OAuth groups/channels map", + "userLogin": "carlosrodrigues94", + "description": "This change deals with the problem with the new users coming from key cloak, this users were not being mapped to the correct channels on RC.", + "milestone": "5.4.2", + "contributors": [ + "carlosrodrigues94", + "matheusbsilva137", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27816", + "title": "[FIX] Not all messages in chat conversations are available when forwarding between agents or departments.", + "userLogin": "filipemarins", + "milestone": "5.3.6", + "contributors": [ + "filipemarins", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27745", + "title": "[IMPROVE] Emoji picker for large amount of custom emojis", + "userLogin": "sampaiodiego", + "milestone": "5.2.2", + "contributors": [ + "sampaiodiego", + "web-flow", + "kodiakhq[bot]" + ] + } + ] + }, + "5.2.2": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27745", + "title": "[IMPROVE] Emoji picker for large amount of custom emojis", + "userLogin": "sampaiodiego", + "milestone": "5.2.2", + "contributors": [ + "sampaiodiego", + "web-flow", + "kodiakhq[bot]" + ] + } + ] + }, + "5.3.6": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27816", + "title": "[FIX] Not all messages in chat conversations are available when forwarding between agents or departments.", + "userLogin": "filipemarins", + "milestone": "5.3.6", + "contributors": [ + "filipemarins", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27745", + "title": "[IMPROVE] Emoji picker for large amount of custom emojis", + "userLogin": "sampaiodiego", + "milestone": "5.2.2", + "contributors": [ + "sampaiodiego", + "web-flow", + "kodiakhq[bot]" + ] + } + ] + }, + "5.4.3": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "28028", + "title": "Release 5.4.3", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow", + "sampaiodiego" + ] + }, + { + "pr": "27874", + "title": "Chore: Do not rely on external service on tests", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego" + ] + } + ] + }, + "6.0.0-rc.0": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [ + { + "pr": "28073", + "title": "Regression: Disable video message when composer is in use", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "web-flow" + ] + }, + { + "pr": "28098", + "title": "[BREAK] Upgrade to version 6.0 can be done only from version 5.x ", + "userLogin": "sampaiodiego", + "milestone": "6.0.0", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27389", + "title": "[BREAK] Marketplace standalone page and app request flow", + "userLogin": "rique223", + "description": "Remove marketplace from the admin menu (on both the file system and the UI), change it into a standalone page, expose its use to end-users, and create an app request flow that allows end-users to ask for app installations in their workspaces directly through Rocket Chats UI.\r\n\r\nDemo loom: https://www.loom.com/share/643ba3432225418e96c10041f386ff48\r\n\r\n## Jira tasks and ADRs\r\nAll tasks, descriptions, and designs of work done in this PR can be found on the tasks below, which also double down as simplified ADRs.\r\n\r\n### [MKP-147](https://rocketchat.atlassian.net/browse/MKP-147?atlOrigin=eyJpIjoiNDJjNjBlNjU1MjI3NGI0M2I0NDZiZTRkMjkyYjcyZWMiLCJwIjoiaiJ9) - Remove marketplace from the admin menu and put it on its own page\r\n\r\n### [MKP-68](https://rocketchat.atlassian.net/browse/MKP-68?atlOrigin=eyJpIjoiMGRhMmExYTViNDNlNGI0Y2FjY2ViNDc3MDgyNWUxNDciLCJwIjoiaiJ9) - Create an enterprise option on the new marketplace sidebar\r\n\r\n### [MKP-150](https://rocketchat.atlassian.net/browse/MKP-150?atlOrigin=eyJpIjoiOGIyOWZlMWRhNmFmNDhlODhhMmNlOWE0MmMzOTYwMTgiLCJwIjoiaiJ9) - Implement the SideNav of the new marketplace page\r\n\r\n### [MKP-151](https://rocketchat.atlassian.net/browse/MKP-151?atlOrigin=eyJpIjoiN2Y2OTc3MzhlZTAzNGJkOTgwYWVmZjFmMGY0MjA0ZmEiLCJwIjoiaiJ9) - Brainstorm and implement the new marketplace routes\r\n\r\n### [MKP-179](https://rocketchat.atlassian.net/browse/MKP-179?atlOrigin=eyJpIjoiYjBmMDgxOGE4OTAxNDgzYTgwMDkxZmQxZGQwZTliNDQiLCJwIjoiaiJ9) - Retrieve number of requested apps and make it available for components\r\n\r\n### [MKP-181](https://rocketchat.atlassian.net/browse/MKP-181?atlOrigin=eyJpIjoiNzRiNGM0MTM5NjNjNGVlNmFhZmIyZmQ1MGFhZTkzMjgiLCJwIjoiaiJ9) - Implement requested option on marketplace sidebar\r\n\r\n### [MKP-184](https://rocketchat.atlassian.net/browse/MKP-184?atlOrigin=eyJpIjoiY2RkYjJhODc2MTcyNDlkOTllNzc1ZGU4OWIyNTMwYmIiLCJwIjoiaiJ9) - Create requested apps page\r\n\r\n### [MKP-185](https://rocketchat.atlassian.net/browse/MKP-185?atlOrigin=eyJpIjoiY2M4ZjVmMzZlODA3NDBkZWE3NTU3YTQ2NWMyYWFjYTAiLCJwIjoiaiJ9) - Implement requested apps list layout and logic\r\n\r\n### [MKP-180](https://rocketchat.atlassian.net/browse/MKP-180?atlOrigin=eyJpIjoiYjQwOTVkOTQ4YmYyNDlmN2JlNWI5YzcwYmMzYTEzZmIiLCJwIjoiaiJ9) - Implement requested apps option to home screen kebab menu\r\n\r\n### [MKP-188](https://rocketchat.atlassian.net/browse/MKP-188?atlOrigin=eyJpIjoiYTkzNWMwMzdlODBlNDMwOGIzOGQ1MGJhMzFkNzhjYmMiLCJwIjoiaiJ9) - Implement the requested apps tab on app details page\r\n\r\n### [MKP-187](https://rocketchat.atlassian.net/browse/MKP-187?atlOrigin=eyJpIjoiYmUzMjI2YTE4Njc1NGFjMThjYjUxNDlhYjMwMTc2MDgiLCJwIjoiaiJ9) - Implement visualized requests system on apps list tags and app requests tab\r\n\r\n### [MKP-164](https://rocketchat.atlassian.net/browse/MKP-164?atlOrigin=eyJpIjoiMDUxOTJmNzVlNmZjNGQ4ZTljNzY2NDI4YjU5MjU0N2EiLCJwIjoiaiJ9) - ALL view the app's technical documentation page\r\n\r\n### [MKP-197](https://rocketchat.atlassian.net/browse/MKP-197) - Rocket.cat notification for admins when an app is requested\r\n\r\n### [MKP-224](https://rocketchat.atlassian.net/browse/MKP-224) - After i click submit request in the modal the modal is not closing", + "milestone": "6.0.0", + "contributors": [ + "rique223", + "web-flow", + "dougfabris", + "tiagoevanp" + ] + }, + { + "pr": "28082", + "title": "Chore: test turbo cache action", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "rodrigok", + "web-flow", + "sampaiodiego" + ] + }, + { + "pr": "28097", + "title": "Chore: fix e2e Omnichannel tests", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "28075", + "title": "Chore: QoL improvements to Omnichannel E2E tests", + "userLogin": "KevLehman", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "28091", + "title": "Regression: Scroll bars in sidebar", + "userLogin": "tassoevan", + "milestone": "6.0.0", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "28087", + "title": "Chore: improve global setup e2e", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "28074", + "title": "Chore: Add Eslint rules to tests", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow", + "tassoevan" + ] + }, + { + "pr": "28017", + "title": "Regression: Fix presence broadcast not re-enabling", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "web-flow", + "KevLehman" + ] + }, + { + "pr": "28083", + "title": "Chore: RoomAutocomplete Debounce Query", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "28086", + "title": "Chore: move PaletteStyleTag", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "28085", + "title": "Chore: OAuth authorization pages reconditioned", + "userLogin": "tassoevan", + "milestone": "6.0.0", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "28064", + "title": "Chore: Remove `body` template", + "userLogin": "tassoevan", + "contributors": [ + "tassoevan", + "web-flow" + ] + }, + { + "pr": "28040", + "title": "Regression: Message > `messageActionDefault`> Copy and Report", + "userLogin": "hugocostadev", + "description": "This regression was probably generated by the Attachments rewrite.\r\n\r\nIssue 1: When selecting the action `Copy` on the message toolbox with Attachment Messages (messages with files/images)\r\nThe copied content was empty because was getting from an empty prop.\r\n\r\n**Previous output:**\r\n![output2](https://user-images.githubusercontent.com/20212776/218820716-e5c6b9cf-8968-4ee7-9e87-f958edcc7fdf.jpg)\r\n\r\n**Current output:**\r\n![output1](https://user-images.githubusercontent.com/20212776/218820706-c26ff106-1eb9-4e07-bb71-a4f97cc21d97.jpg)\r\n\r\n\r\nIssue 2: When selecting the action `Report` the reported message was showing an unformatted message (with markdown tokens)\r\n\r\n**Previous output:**\r\n![output4](https://user-images.githubusercontent.com/20212776/218821154-2090a79d-58ee-4717-8646-e1eb2b5ad46e.jpg)\r\n\r\n**Current output:**\r\n![output3](https://user-images.githubusercontent.com/20212776/218821189-e820b58e-1128-4a34-80d8-0aadeb880830.jpg)", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "guijun13", + "web-flow", + "rodrigok" + ] + }, + { + "pr": "24205", + "title": "[IMPROVE] Play selected notification sounds as preview while changing sound settings ", + "userLogin": "try-catch-stack", + "milestone": "6.0.0", + "contributors": [ + "try-catch-stack", + "debdutdeb", + "web-flow", + "ggazzo", + "casalsgh", + "kodiakhq[bot]", + "rodrigok" + ] + }, + { + "pr": "28062", + "title": "Regression: Client crashing when updating CachedChatSubscription", + "userLogin": "gabriellsh", + "description": "Currently the typing of 'ISubscription' is a little off from reality. The property `ts` is optional, and this can cause crashes when trying to access `ts`'s properties.\r\n\r\nI decided to avoid changing the type definitions for ISubscription this time, since it will probably impact many other places, and that's not the scope of this task.", + "milestone": "6.0.0", + "contributors": [ + "gabriellsh", + "web-flow", + "tassoevan" + ] + }, + { + "pr": "27627", + "title": "[FIX] Access to localStorage in Livechat", + "userLogin": "jschirrmacher", + "description": "This fixes access to localStorage in LiveChat, if the user has third party coockies disabled.", + "milestone": "6.0.0", + "contributors": [ + "jschirrmacher", + "web-flow", + "murtaza98", + "debdutdeb", + "KevLehman", + "kodiakhq[bot]", + "rodrigok" + ] + }, + { + "pr": "28015", + "title": "Regression: DateRangePicker errors", + "userLogin": "hugocostadev", + "description": "The date range picker for `Yesterday`, `This Week`, `Previous Week`, and `This Month` in the Message Audit page, was not selecting the correct date range and it was causing form validation issues.\r\n\r\n**Error Evidence:** \r\n![Clipboard - February 10, 2023 6_12 PM](https://user-images.githubusercontent.com/20212776/218519404-f8ab1e02-7b95-452f-8433-374b2208b02a.png)\r\n![Clipboard - February 10, 2023 6_10 PM](https://user-images.githubusercontent.com/20212776/218519412-4392b3cd-7e21-42f0-aac5-4c30a980b9af.png)\r\n![Clipboard - February 10, 2023 6_09 PM](https://user-images.githubusercontent.com/20212776/218519417-6726fea6-34bd-41fc-b7fb-e7e3c5ba53cd.png)\r\n![Clipboard - February 10, 2023 6_08 PM](https://user-images.githubusercontent.com/20212776/218519423-8ec8f0b2-6ad6-4d3c-b678-5383792d4ff3.png)", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "web-flow", + "rodrigok" + ] + }, + { + "pr": "28071", + "title": "Regression: Fix file upload on collapsed composer menu", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "28076", + "title": "Chore: CI improvements", + "userLogin": "rodrigok", + "milestone": "6.0.0", + "contributors": [ + "rodrigok", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27763", + "title": "[NEW] Matrix federation events coverage expansion + bug fixes", + "userLogin": "MarcosSpessatto", + "description": "- Disables not supported features in federated channels (#27204)\r\n- Add support for the whole Matrix Markdown spec (#27725)\r\n- Allow federated rooms with the same name per different servers when they have a contact between them (#27559)\r\n- Matrix Federation send message when multiple users are involved was not working (#27327)\r\n- Allow the room owner to set roles on federated rooms, following a specific and different approach as normal rooms (available on docs) (https://github.com/RocketChat/Rocket.Chat/pull/27633)\r\n- E2E Tests (PS: they don't run on CI) (#27578 #27282 #27115)\r\n- Disables admin actions disallowed for federated users/rooms (https://github.com/RocketChat/Rocket.Chat/pull/27251)\r\n\r\nFED-81", + "milestone": "6.0.0", + "contributors": [ + "MarcosSpessatto", + "web-flow" + ] + }, + { + "pr": "28065", + "title": "Chore: SlashCommands Preview", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "tassoevan", + "web-flow" + ] + }, + { + "pr": "28061", + "title": "Chore: Fix e2e EE tests not working reliably", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "tassoevan" + ] + }, + { + "pr": "28066", + "title": "Chore: E2E tests small corrections", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "28067", + "title": "Regression: fix api tests", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "28060", + "title": "Regression: Formatted text rendered by UI Kit", + "userLogin": "tassoevan", + "milestone": "6.0.0", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "28063", + "title": "Chore: Refactor useThemeMode in favor of userPreferences", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "28056", + "title": "Regression: 0 appearing on sidebar on specific occasions", + "userLogin": "gabriellsh", + "description": "Fixed faulty logic", + "milestone": "6.0.0", + "contributors": [ + "gabriellsh" + ] + }, + { + "pr": "28049", + "title": "Chore: EmojiPicker Wrapper Styles", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "ggazzo" + ] + }, + { + "pr": "28029", + "title": "Chore: Fix babel config related to TypeScript `declare` usage", + "userLogin": "tiagoevanp", + "contributors": [ + "tiagoevanp", + "web-flow", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "28031", + "title": "[FIX] Custom fields does not appear on the registration form", + "userLogin": "murtaza98", + "milestone": "6.0.0", + "contributors": [ + "murtaza98", + "web-flow", + "KevLehman" + ] + }, + { + "pr": "28046", + "title": "Regression: Emoji picker styling", + "userLogin": "yash-rajpal", + "description": "### Before\r\n\"image\"\r\n\r\n### After\r\n\"image\"", + "milestone": "6.0.0", + "contributors": [ + "yash-rajpal", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27413", + "title": "Chore: Add E2E tests to Triggers view", + "userLogin": "Harmeet221", + "milestone": "6.0.0", + "contributors": [ + "Harmeet221", + "web-flow", + "KevLehman", + "ggazzo", + "kodiakhq[bot]", + "murtaza98" + ] + }, + { + "pr": "28037", + "title": "[BREAK] Limit `underscore` usage and remove `underscore.string` (even from integration script sandboxes)", + "userLogin": "tassoevan", + "description": "[Underscore.js](https://underscorejs.org/) is quite outdated and we're not using it in a way that take advantage of modularization, bloating the client bundle. This PR aims to limit its usage across the application.\r\n\r\nbreak: if you are used to have scripts, and they are using underscore, please pay attention probably you need to update them", + "milestone": "6.0.0", + "contributors": [ + "tassoevan", + "web-flow" + ] + }, + { + "pr": "27540", + "title": "[NEW] Homepage new block", + "userLogin": "guijun13", + "description": "- Create a new admin homepage block that includes:\r\n - Button to go to /admin/Layout setting\r\n - Button to show and hide the custom content to the user (a badge on top indicates if the custom content is hidden or not)\r\n - Button to show and hide the other blocks (add users, create channel) on the homepage (EE only button)\r\n \r\nNew homepage block admin view:\r\n\"Screen\r\n\r\nNormal user view:\r\n\"Screen\r\n\r\n\r\n - Changes on the /admin/Layout settings:\r\n - text and homepage settings small changes\r\n - add Layout_Home_Custom_Block_Visible setting to show or hide custom content\r\n \r\nAdmin Homepage Content settings page:\r\n\r\n\"Screen", + "milestone": "6.0.0", + "contributors": [ + "guijun13", + "web-flow", + "gabriellsh" + ] + }, + { + "pr": "28038", + "title": "Chore: Add quote message option back on live chat rooms", + "userLogin": "filipemarins", + "milestone": "6.0.0", + "contributors": [ + "filipemarins", + "web-flow", + "murtaza98" + ] + }, + { + "pr": "27912", + "title": "[FIX] Empty DMs go to sidebar's top after updating user preferences", + "userLogin": "matheusbsilva137", + "description": "- Do not use `_updatedAt` as `lm` field when merging info from subscriptions and rooms (since this field is updated along with the user preferences).", + "milestone": "6.0.0-prep", + "contributors": [ + "matheusbsilva137", + "tassoevan", + "LucianoPierdona", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27083", + "title": "[NEW][EE] Omnichannel Priorities & SLAs", + "userLogin": "KevLehman", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "MartinSchoeler", + "sampaiodiego", + "murtaza98" + ] + }, + { + "pr": "28044", + "title": "Regression: Fix missing Formatting items", + "userLogin": "ggazzo", + "milestone": "6.0.0", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27074", + "title": "[BREAK] Move read-receipts to EE and threads check marks improvements", + "userLogin": "matheusbsilva137", + "description": "- Improvement: add read receipts for messages in threads only when the thread is open;\r\n- Move read-receipts feature to EE (under the `message-read-receipt` module). The `chat.getMessageReadReceipts` endpoint and `getReadReceipts` Meteor method are now EE only.", + "milestone": "6.0.0", + "contributors": [ + "sampaiodiego", + "matheusbsilva137", + "web-flow" + ] + }, + { + "pr": "28043", + "title": "Chore: Sync `develop` with `master`", + "userLogin": "ggazzo", + "contributors": [ + "sampaiodiego", + "filipemarins", + "carlosrodrigues94", + "ostjen", + "dougfabris", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "28025", + "title": "Chore: Remove unused Blaze templates after message rewrite", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27891", + "title": "[BREAK] Drop support for MongoDB 4.2 and deprecate MongoDB 4.4", + "userLogin": "KevLehman", + "description": "As per MongoDB Lifecycle Schedules ([mongodb.com/support-policy/lifecycles](https://www.mongodb.com/support-policy/lifecycles)) we're removing official support to MongoDB version 4.2 that is close to reach end of life (April 2023).\r\n\r\nWe recommend upgrading to MongoDB 5.0+, though 4.4 is still a supported version.\r\n\r\nHere are official docs on how to upgrade to some of the supported versions:\r\n\r\n[mongodb.com/docs/v4.4/release-notes/4.4-upgrade-replica-set](https://www.mongodb.com/docs/v4.4/release-notes/4.4-upgrade-replica-set/)\r\n[mongodb.com/docs/manual/release-notes/5.0-upgrade-replica-set](https://www.mongodb.com/docs/manual/release-notes/5.0-upgrade-replica-set/)\r\n[mongodb.com/docs/manual/release-notes/6.0-upgrade-replica-set](https://www.mongodb.com/docs/manual/release-notes/6.0-upgrade-replica-set/)", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "sampaiodiego", + "web-flow" + ] + }, + { + "pr": "28039", + "title": "Chore: Refactor Composer Collapsed Formatters and Actions", + "userLogin": "dougfabris", + "description": "[DSA-19]\r\n\r\n![Kapture 2023-02-14 at 14 05 19](https://user-images.githubusercontent.com/27704687/218807178-4c280e92-67f2-48ec-afa3-e5b2948120f2.gif)", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "28021", + "title": "[FIX] Register Workspace UI fixes and fix doc link", + "userLogin": "csuadev", + "milestone": "6.0.0", + "contributors": [ + "csuadev", + "yash-rajpal", + "web-flow" + ] + }, + { + "pr": "27572", + "title": "[NEW] [EE] PDF Chat transcript for Omnichannel conversations", + "userLogin": "filipemarins", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "web-flow", + "filipemarins", + "murtaza98" + ] + }, + { + "pr": "28013", + "title": "Chore: Refactor Composer Popup", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "28018", + "title": "[IMPROVE] Setup Wizard Flow for airgapped environment", + "userLogin": "gabriellsh", + "description": "![image](https://user-images.githubusercontent.com/40830821/217655867-ddfbd99f-e0b8-4c71-9a33-b06555bb97dc.png)\r\n![image](https://user-images.githubusercontent.com/40830821/217655885-b84a92b6-da9f-4f57-b4ef-297e8541ded3.png)", + "milestone": "6.0.0", + "contributors": [ + "gabriellsh", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28001", + "title": "Chore: Message search changes", + "userLogin": "tassoevan", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "27561", + "title": "[FIX] IPostMessageReacted return field named isReacted instead isRemoved", + "userLogin": "Nabhag8848", + "milestone": "6.0.0", + "contributors": [ + "Nabhag8848", + "web-flow", + "debdutdeb", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "28022", + "title": "Chore: Service cap", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti" + ] + }, + { + "pr": "27488", + "title": "[FIX] Option to Join Read-Only Channels", + "userLogin": "henit-chobisa", + "milestone": "6.0.0", + "contributors": [ + "henit-chobisa", + "debdutdeb", + "web-flow", + "murtaza98", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "27941", + "title": "[FIX] \"Jump to first unread\" banner does not always appear when the first unread message is outside of the visible screen", + "userLogin": "Educg550", + "milestone": "6.0.0", + "contributors": [ + "Educg550", + "hugocostadev", + "web-flow", + "kodiakhq[bot]", + "ggazzo" + ] + }, + { + "pr": "28020", + "title": "[FIX] Move Omni startup to be EE wrapped", + "userLogin": "KevLehman", + "contributors": [ + "KevLehman", + "sampaiodiego", + "web-flow" + ] + }, + { + "pr": "27779", + "title": "[FIX] Broken settings check for updates", + "userLogin": "geekgonecrazy", + "milestone": "6.0.0", + "contributors": [ + "geekgonecrazy", + "web-flow", + "debdutdeb" + ] + }, + { + "pr": "27959", + "title": "Chore: `desktop` icon instead of `computer` icon", + "userLogin": "tassoevan", + "milestone": "6.0.0", + "contributors": [ + "tassoevan", + "ggazzo" + ] + }, + { + "pr": "28019", + "title": "Chore: Refactor `AudioMessageRecorder`", + "userLogin": "dougfabris", + "description": "[DSA-11]\r\n\r\n![Kapture 2023-02-13 at 17 24 54](https://user-images.githubusercontent.com/27704687/218567103-1090cf5c-61d1-4bd9-8c0a-d582d614ef85.gif)", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27942", + "title": "[FIX] Invalid regex on search fields crashes UI", + "userLogin": "totoi690", + "milestone": "6.0.0", + "contributors": [ + "totoi690", + "matheusbsilva137", + "web-flow", + "debdutdeb", + "kodiakhq[bot]" + ] + }, + { + "pr": "28012", + "title": "[BREAK] Remove Chatpal", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27753", + "title": "[BREAK] Move Multiple Department Creation to EE & [NEW] Department Archive", + "userLogin": "MartinSchoeler", + "description": "[BREAK] **Move Multiple Department Creation to EE**: Limit max department creation to 1 in Community edition, existing departments will still function as before.\r\n\r\n[NEW] 📁 **Department archival**: Adds the ability to archive departments, archived departments are disabled and cannot be edited, but will still show in historical data (current chats, directory, chat info, etc...). This offers an alternative to department deletion.", + "milestone": "6.0.0", + "contributors": [ + "sampaiodiego", + "MartinSchoeler", + "web-flow", + "tassoevan" + ] + }, + { + "pr": "27969", + "title": "[BREAK] Unify monolith and microservices intercommunication on same technology and limit to Enterprise only ", + "userLogin": "sampaiodiego", + "description": "This change removes the old DDP Matrix communication by Moleculer based breaker over TCP, simplifying code maintenance, allowing better reliability, performance and monitoring.\r\n\r\nIt requires a license to enable communication among servers as the rest of the Moleculer implementation.\r\n\r\nCommunity Edition will loose ephemeral events as Typing indication and others when running multiple instances.", + "contributors": [ + "sampaiodiego", + "rodrigok", + "web-flow" + ] + }, + { + "pr": "27972", + "title": "[NEW] Emojis rendering properly on quote message previews", + "userLogin": "Educg550", + "description": "![image](https://user-images.githubusercontent.com/47800334/217540055-de7cdc29-5478-4a23-a884-4476318bd83d.png)", + "milestone": "6.0.0", + "contributors": [ + "Educg550", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28000", + "title": "Chore: Wait message to not be Busy", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27987", + "title": "Chore: e2e changes tests", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27994", + "title": "[IMPROVE] Audit", + "userLogin": "tassoevan", + "milestone": "6.0.0", + "contributors": [ + "tassoevan", + "hugocostadev", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27820", + "title": "[IMPROVE] Registration Experience", + "userLogin": "csuadev", + "description": "If you didn't register when you initially setup your server. Its now easier to register.\r\n\r\nDisconnecting and reconnecting your workspace from the cloud is now also easier", + "milestone": "6.0.0", + "contributors": [ + "csuadev", + "PedroRorato", + "web-flow", + "geekgonecrazy", + "AlenDavid" + ] + }, + { + "pr": "27854", + "title": "[BREAK][ENTERPRISE] Limit presence statuses to 200 concurrent users when running monolith to keep performance", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "web-flow", + "juliajforesti", + "rodrigok", + "ggazzo" + ] + }, + { + "pr": "27902", + "title": "[BREAK] Removed deprecated settings for Legacy Messages, Marked, Snippet Messages, Autolinker and IssueLinks", + "userLogin": "LucianoPierdona", + "description": "Removed Settings:\r\n\r\n- Markdown_Parser\r\n- Markdown_Headers\r\n- Markdown_SupportSchemesForLink\r\n- Markdown_Marked_GFM\r\n- Markdown_Marked_Tables\r\n- Markdown_Marked_Breaks\r\n- Markdown_Marked_Pedantic\r\n- Markdown_Marked_SmartLists\r\n- Markdown_Marked_Smartypants\r\n- Message_AllowSnippeting\r\n- Message_Attachments_GroupAttach\r\n- Message_ShowEditedStatus\r\n- Message_ShowFormattingTips\r\n- Accounts_Default_User_Preferences_useLegacyMessageTemplate\r\n- AutoLinker\r\n- AutoLinker_StripPrefix\r\n- AutoLinker_Urls_Scheme\r\n- AutoLinker_Urls_www\r\n- AutoLinker_Urls_TLD\r\n- AutoLinker_UrlsRegExp\r\n- AutoLinker_Email\r\n- AutoLinker_Phone\r\n- IssueLinks_Enabled\r\n- IssueLinks_Template\r\n- API_EmbedDisabledFor", + "milestone": "6.0.0", + "contributors": [ + "LucianoPierdona", + "web-flow" + ] + }, + { + "pr": "27644", + "title": "[NEW] Permission to bypass message editing and removing limits", + "userLogin": "LucianoPierdona", + "description": "This PR adds a new permission called `bypass-time-limit-edit-and-delete`, to bypass the time limit when editing or deleting a message, the purpose of this PR is to remove the limitation for bots that cannot change the message after the specified time.", + "milestone": "6.0.0", + "contributors": [ + "LucianoPierdona", + "web-flow", + "matheusbsilva137", + "sampaiodiego", + "hugocostadev", + "rodrigok", + "kodiakhq[bot]", + "ggazzo" + ] + }, + { + "pr": "27764", + "title": "[FIX] Video Conf Message Blocks not always updating when running on micro services", + "userLogin": "pierre-lehnen-rc", + "contributors": [ + "pierre-lehnen-rc", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27817", + "title": "Chore: Set missing colors", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27867", + "title": "[BREAK] Remove message view mode from User Preferences", + "userLogin": "hugocostadev", + "description": "Since the view mode setting in `User preferences -> Messages -> View Mode` does not work with the new messages template it will be removed\r\n\r\nIt was removed from every file and it was created a migration to remove from user obj in DB", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "sampaiodiego", + "web-flow", + "yash-rajpal", + "rodrigok", + "kodiakhq[bot]" + ] + }, + { + "pr": "27978", + "title": "Chore: Aria busy indicators", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27931", + "title": "Chore: Refactor Composer Dropdown", + "userLogin": "dougfabris", + "description": "![Screen Shot 2023-02-01 at 17 59 31](https://user-images.githubusercontent.com/27704687/216162082-ea258bb8-5629-4898-a410-6162a0fa008e.png)", + "contributors": [ + "dougfabris", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27855", + "title": "Chore: Added Enterprise Options to Login customization", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow", + "dougfabris", + "kodiakhq[bot]" + ] + }, + { + "pr": "27279", + "title": "[FIX] Ignored messages reactivity", + "userLogin": "yash-rajpal", + "milestone": "6.0.0", + "contributors": [ + "yash-rajpal", + "gabriellsh", + "web-flow", + "tassoevan", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "27707", + "title": "[BREAK] [NEW] Custom roles upsell modal", + "userLogin": "gabriellsh", + "description": "![image](https://user-images.githubusercontent.com/40830821/211393807-2dd4ad76-cc98-4950-99a6-93d6c2087406.png)\r\n\r\nAlso changed the `edit role` button:\r\n![image](https://user-images.githubusercontent.com/40830821/211393881-980293fa-a3af-46a5-8bfe-48f99872333a.png)", + "milestone": "6.0.0", + "contributors": [ + "gabriellsh", + "yash-rajpal", + "web-flow", + "rodrigok", + "kodiakhq[bot]" + ] + }, + { + "pr": "27661", + "title": "Chore: Settings regenerator on migration", + "userLogin": "KevLehman", + "milestone": "6.0.0-prep", + "contributors": [ + "KevLehman", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27947", + "title": "[FIX] Message-parser link issues", + "userLogin": "hugocostadev", + "description": "The changes were made in the fuselage repository. This PR just update the message-parser package version\r\nCheck the changes in this PR: \r\nhttps://github.com/RocketChat/fuselage/pull/962", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27898", + "title": "[IMPROVE] Spanish home translation", + "userLogin": "nYCSTs", + "description": "Update translation of home page to Spanish. The page had some untranslated texts.\r\n![image](https://user-images.githubusercontent.com/63932475/215656626-5fbeb5b6-e398-4dd4-a150-ec69305ebb56.png)", + "milestone": "6.0.0", + "contributors": [ + "nYCSTs", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27760", + "title": "[BREAK] Remove legacy FB Messenger integration", + "userLogin": "murtaza98", + "description": "Legacy FB messenger integration has been removed in favour of the new and enhanced FB App integration. [Click here](https://docs.rocket.chat/guides/app-guides/omnichannel-apps/facebook-app) for more info", + "milestone": "6.0.0", + "contributors": [ + "murtaza98", + "web-flow", + "KevLehman", + "rodrigok", + "kodiakhq[bot]" + ] + }, + { + "pr": "27965", + "title": "Regression: upserting data into cached collections", + "userLogin": "tassoevan", + "description": "This one should get rid of \"grey\" (temporary) messages.", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "27876", + "title": "[FIX] Comunity users accessing exclusive ee endpoints in omnichannel section", + "userLogin": "FabioCavaleti", + "milestone": "6.0.0", + "contributors": [ + "FabioCavaleti", + "KevLehman", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27877", + "title": "[NEW] Bridge to get all users crated by app and also delete them", + "userLogin": "albuquerquefabio", + "description": "We're working on [MS Teams bridge](https://github.com/RocketChat/Apps.teams.bridge), to make it usable we have created a new method for the apps engine to [create new users](https://github.com/RocketChat/Rocket.Chat.Apps-engine/pull/536) and we'll also need to delete all when we uninstall the app. Therefore, we created this bridge to cover the action of deleting users on the app side.", + "milestone": "6.0.0", + "contributors": [ + "albuquerquefabio", + "web-flow", + "d-gubert", + "AllanPazRibeiro" + ] + }, + { + "pr": "27713", + "title": "[BREAK] [IMPROVE] SMTP warning for invitations ", + "userLogin": "yash-rajpal", + "description": "- TC-347 - SMTP warning for invitations flow\r\n- Create rest endpoint for sendInvitationEmail\r\n- Use endpoint in-place of removed Meteor method", + "milestone": "6.0.0", + "contributors": [ + "yash-rajpal", + "web-flow", + "hugocostadev", + "kodiakhq[bot]" + ] + }, + { + "pr": "27609", + "title": "[FIX] Black screen when try to open a chat with a non-existent department", + "userLogin": "murtaza98", + "milestone": "6.0.0", + "contributors": [ + "murtaza98", + "web-flow" + ] + }, + { + "pr": "27481", + "title": "[BREAK] Freeze Custom Roles", + "userLogin": "LucianoPierdona", + "description": "This PR moves role creation and update to enterprise folder\r\n\r\n--\r\n- Removed method `authorization:saveRole`\r\n- Moved `/v1/roles.create/` and `/v1/roles.update` to enterprise edition\r\n- Changed message for delete a custom role in community edition", + "milestone": "6.0.0", + "contributors": [ + "LucianoPierdona", + "web-flow", + "gabriellsh" + ] + }, + { + "pr": "27843", + "title": "Chore: Add hint (description) to CodeSettingInput after label", + "userLogin": "hugocostadev", + "description": "- Added hint (description) to CodeSettingInput after label\r\n- Created a storybook story for that scenario\r\n- add a checker to not add hint to`` if the inputType is `code`\r\n\r\n**Before:**\r\n![image](https://user-images.githubusercontent.com/20212776/214575455-f2073084-bc10-4e55-9eb2-99bc9fcb71a3.png)\r\n\r\n**After:**\r\n![image](https://user-images.githubusercontent.com/20212776/214622377-eb706c31-909f-4b25-ae2e-71cff70f80b2.png)", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "yash-rajpal", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27892", + "title": "[FIX] Embedded layout opening sidebar", + "userLogin": "hugocostadev", + "description": "In the embedded layout view, certain actions were opening the sidebar due to the missing query param mandatory to the embedded layout view (`?layout=embedded`)\r\n\r\nIn addition to this issue, the user was able to navigate to different pages in the embedded layout causing them to get stuck on some other pages other than the Room page. Because of the reported issue, I removed some actions that redirect the user to other pages such as: \"Reply in Direct Message\"", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "web-flow" + ] + }, + { + "pr": "27927", + "title": "Chore: Refactor other kinds of message - Phase 2", + "userLogin": "tassoevan", + "description": "Migrate \"Starred Messages\", \"Pinned Messages\", and \"Mentions\" from Blaze templates to React components.", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "27936", + "title": "Chore: improve some e2e selectors", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27744", + "title": "[NEW] Warning Popup reinforcing Zapier deprecation on Integrations Admin settings", + "userLogin": "Educg550", + "description": "#### Warning being displayed on Zapier settings, above Zapier itself:\r\n![warning](https://user-images.githubusercontent.com/47800334/213696834-be7ac8e0-7249-4d02-93ba-e4c5e34b67da.png)", + "milestone": "6.0.0", + "contributors": [ + "Educg550", + "yash-rajpal", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27925", + "title": "Chore: Notify Marketplace on App Install", + "userLogin": "graywolf336", + "description": "Notifies Rocket.Chat's Marketplace of an app install action. This correlates with the app request flow.", + "contributors": [ + "graywolf336", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27814", + "title": "i18n: Language update from LingoHub 🤖 on 2023-01-23Z", + "userLogin": "lingohub[bot]", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27929", + "title": "[FIX][ENTERPRISE] DDP streamer sending data to destroyed streams", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27909", + "title": "Chore: Migrate cached collections to TypeScript", + "userLogin": "tassoevan", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "27705", + "title": "i18n: Language update from LingoHub 🤖 on 2023-01-09Z", + "userLogin": "lingohub[bot]", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27911", + "title": "[FIX] Reduce re-subscription on `notify-room/user-activity` stream event", + "userLogin": "tassoevan", + "description": "Whenever something changed the room subscription, it would trigger a re-subscription to `notify-room/user-activity`.", + "milestone": "6.0.0", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "27539", + "title": "[FIX] Unread Message count not displayed for new messages in Omni-Rooms", + "userLogin": "murtaza98", + "milestone": "6.0.0", + "contributors": [ + "murtaza98", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27872", + "title": "Chore: Improve service's licence check", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27825", + "title": "[IMPROVE] Livechat Persian translation", + "userLogin": "pouyadarabi", + "contributors": [ + "pouyadarabi", + "web-flow" + ] + }, + { + "pr": "27884", + "title": "Chore(deps): Bump thehanimo/pr-title-checker from 1.3.4 to 1.3.6", + "userLogin": "dependabot[bot]", + "contributors": [ + "dependabot[bot]", + "web-flow" + ] + }, + { + "pr": "27673", + "title": "Chore: use useQuery in place of deprecated useEndpointData", + "userLogin": "Dnouv", + "description": "Chore done:\r\nuseEndpointData -> useEndpoint for:\r\n\r\n- `/apps/meteor/client/views/admin/`\r\n - `apps`\r\n - `customEmoji`\r\n - `customSounds`\r\n - `customUserStatus`\r\n - `integrations`\r\n - `invites`\r\n - `oauthApps`\r\n - `permissions`\r\n - `rooms`\r\n - `users`", + "milestone": "6.0.0", + "contributors": [ + "Dnouv", + "debdutdeb", + "web-flow" + ] + }, + { + "pr": "27862", + "title": "Chore: Update Some Composer Icons", + "userLogin": "dougfabris", + "description": "Jira Issue [DSA-20]\r\n\r\n### before\r\n![Screen Shot 2023-01-26 at 18 09 19](https://user-images.githubusercontent.com/27704687/214950981-794d1f23-b33f-4fcf-9ab1-f042925e5639.png)\r\n\r\n### after\r\n![Screen Shot 2023-01-26 at 18 08 28](https://user-images.githubusercontent.com/27704687/214950829-357ea6eb-9fde-4144-8819-5052e21ae604.png)", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27870", + "title": "Regression: Undefined default message context", + "userLogin": "tassoevan", + "description": "It fixes some contextual bar tabs (e.g. \"Mentions\").", + "milestone": "6.0.0", + "contributors": [ + "tassoevan", + "web-flow" + ] + }, + { + "pr": "27786", + "title": "Chore: Remove OS version for device management", + "userLogin": "LucianoPierdona", + "description": "This PR removes the OS version from the device management page, this is because the `user-agent` is returning the wrong version.", + "milestone": "6.0.0", + "contributors": [ + "LucianoPierdona", + "kodiakhq[bot]", + "web-flow", + "hugocostadev" + ] + }, + { + "pr": "27647", + "title": "[BREAK] Remove less theming", + "userLogin": "ggazzo", + "milestone": "6.0.0", + "contributors": [ + "ggazzo", + "web-flow", + "tassoevan" + ] + }, + { + "pr": "27874", + "title": "Chore: Do not rely on external service on tests", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27857", + "title": "Regression: fix close flextab on click outside the container", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27646", + "title": "Chore: Refactor Directory Tables", + "userLogin": "dougfabris", + "description": "It also replaces `useEndpointData` in favor of `useQuery`", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow", + "tassoevan" + ] + }, + { + "pr": "27863", + "title": "[FIX] Emoji rendering on reactions", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27789", + "title": "[FIX] Disable video call on read-only rooms for not allowed users", + "userLogin": "dougfabris", + "description": "Jira Issue [VC-58]", + "milestone": "6.0.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27850", + "title": "Chore: Refactor `VideoMessageRecorder`", + "userLogin": "dougfabris", + "description": "Jira Issue: [DSA-2]\r\n### before\r\n\r\n\r\n### after\r\n", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27786", + "title": "Chore: Remove OS version for device management", + "userLogin": "LucianoPierdona", + "description": "This PR removes the OS version from the device management page, this is because the `user-agent` is returning the wrong version.", + "milestone": "6.0.0", + "contributors": [ + "LucianoPierdona", + "kodiakhq[bot]", + "web-flow", + "hugocostadev" + ] + }, + { + "pr": "27786", + "title": "Chore: Remove OS version for device management", + "userLogin": "LucianoPierdona", + "description": "This PR removes the OS version from the device management page, this is because the `user-agent` is returning the wrong version.", + "milestone": "6.0.0", + "contributors": [ + "LucianoPierdona", + "kodiakhq[bot]", + "web-flow", + "hugocostadev" + ] + }, + { + "pr": "27832", + "title": "Chore: Adjust ProgressBar usage", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27712", + "title": "Chore: Refactor other kinds of message - Phase 1", + "userLogin": "tassoevan", + "description": "It pays some technical debts on APIs consumed by message-related components.", + "contributors": [ + "tassoevan", + "web-flow" + ] + }, + { + "pr": "27716", + "title": "[FIX] Unintended \"Reply on thread\" button showing on thread's first message", + "userLogin": "Educg550", + "description": "Referent to TC-128\r\n\r\n#### Before:\r\n![image](https://user-images.githubusercontent.com/47800334/211622867-5d24a4c9-172b-4b36-aac9-cea1af3f925a.png)\r\n\r\n#### After:\r\n![image](https://user-images.githubusercontent.com/47800334/211622729-14e8c552-615c-44e3-b5ae-8e815909e5ac.png)", + "milestone": "6.0.0", + "contributors": [ + "Educg550", + "web-flow", + "kodiakhq[bot]", + "hugocostadev" + ] + }, + { + "pr": "27740", + "title": "[FIX] OmnichannelRoomIconProvider order breaking VideoConfPopup", + "userLogin": "dougfabris", + "description": "Jira Issue [VC-39]", + "milestone": "5.4.2", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27624", + "title": "[FIX] Toast notification ignoring 403 errors", + "userLogin": "murtaza98", + "contributors": [ + "murtaza98", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27816", + "title": "[FIX] Not all messages in chat conversations are available when forwarding between agents or departments.", + "userLogin": "filipemarins", + "milestone": "5.3.6", + "contributors": [ + "filipemarins", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27745", + "title": "[IMPROVE] Emoji picker for large amount of custom emojis", + "userLogin": "sampaiodiego", + "milestone": "5.2.2", + "contributors": [ + "sampaiodiego", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27690", + "title": "Chore: Move service shutdown logic to each service", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27532", + "title": "Chore: change colors to dark theme on Marketplace", + "userLogin": "felipe-rod123", + "description": "Fixed some bugs on the new dark theme in the Marketplace page. The new version looks like this now:\r\n\r\n![new-version](https://user-images.githubusercontent.com/84182706/207443296-b9466105-7dfb-46eb-8f71-eee113c3532b.png)", + "contributors": [ + "felipe-rod123", + "web-flow", + "juliajforesti", + "kodiakhq[bot]" + ] + }, + { + "pr": "27704", + "title": "Chore: Update color tokens", + "userLogin": "juliajforesti", + "description": "Jira issues: \r\n[DSA-25](https://rocketchat.atlassian.net/browse/DSA-25)\r\n[DSA-26](https://rocketchat.atlassian.net/browse/DSA-26)\r\n[DSA-27](https://rocketchat.atlassian.net/browse/DSA-27)\r\n[DSA-28](https://rocketchat.atlassian.net/browse/DSA-28)\r\n[DSA-30](https://rocketchat.atlassian.net/browse/DSA-30)\r\n\r\n- [x] Fix ScreenshotCarousel tokens\r\n- [x] Replace ScreenshotCarousel Button with IconButton secondary\r\n- [x] Fix UsagePieGraph tokens\r\n- [x] Fix Page.tsx tokens\r\n- [x] Fix VoipFooter tokens\r\n- [x] Fix DeviceIcon token\r\n- [x] Fix SidebarFooterWatermark token\r\n- [x] Fix PaletteDark button hover bg color\r\n- [x] Fix MessageComposerActionsDivider token\r\n- [x] Fix room Announcement colors\r\n- [x] Apply surface-room\r\n- [x] Replace all deprecated Box color tokens usage\r\n- [x] Replace all deprecated Box bg tokens usage", + "contributors": [ + "juliajforesti", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27784", + "title": "Chore: Remove medium prop from ButtonGroup ", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27767", + "title": "Regression: Add support for 2FA errors to `Meteor.callAsync`", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27470", + "title": "[NEW] Attachment Files Redesign", + "userLogin": "hugocostadev", + "description": "- Replace File attachments to use `MessageGenericPreview`\r\n- Move File attachments to the` /MessageList` folder\r\n- Refactor Video, Image, and Audio Attachments to use `MessageGenericPreview` \r\n- New component MessageCollapsible \r\n- Refactored the `OEmbedCollpsible` component to use `MessageCollapsible` \r\n- Refactored the `AttachmentSize` component to include different style\r\n- Added `descriptionMd` property to the `MessageAttachment` object to use the new parser in descriptions\r\n- Added size and format to attachment object at `sendFileMessage.ts`\r\n- Changed maxWidth and maxHeight of AttachmentContext to be the same as the OEmbed sizes\r\n\r\n**OLD:**\r\n\"image\"\r\n\r\n\r\n**NEW:**\r\n\"image\"", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "gabriellsh", + "web-flow", + "tassoevan", + "casalsgh" + ] + }, + { + "pr": "27766", + "title": "[FIX] App page showing version undefined for apps not in marketplace", + "userLogin": "d-gubert", + "description": "The app page is not showing the correct version of apps that are installed in the workspace but not in the Marketplace.\n\nThis PR changes the behavior so that the page shows the version that is installed in the workspace; otherwise, it shows the version in the marketplace", + "milestone": "6.0.0", + "contributors": [ + "d-gubert", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27765", + "title": "Chore: Add surface-light background to AppRow", + "userLogin": "rique223", + "description": "In light of the recent changes to the fuselage color system, the AppRow went from having a default background color of white to not having a color. Because of this, I've added the bg='surface-light' prop to the Wrapper box of the component.\r\nBefore:\r\n![image](https://user-images.githubusercontent.com/43561537/212754530-ab847cc2-9026-45e3-a138-14c3c657f373.png)\r\n\r\nAfter: \r\n![image](https://user-images.githubusercontent.com/43561537/212754573-010bb538-7a2d-4db2-889d-933cc907a9f1.png)", + "contributors": [ + "rique223", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27729", + "title": "Chore: Show different labels based on the call originator on direct calls", + "userLogin": "dougfabris", + "description": "Jira Issue: [VC-26]", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27293", + "title": "Chore: Change bundle tags color and refactor app details page header styles", + "userLogin": "rique223", + "description": "Increased the right side margin of the app avatar, removed the 'by' substring from the app author metadata, and changed the font scale and colors for the metadata section and short description.\r\nDemo image:\r\n![image](https://user-images.githubusercontent.com/43561537/202550456-41bc5216-5f6f-4a15-a38e-2e220f8ab3b5.png)", + "contributors": [ + "rique223", + "felipe-rod123", + "web-flow", + "juliajforesti", + "dougfabris", + "kodiakhq[bot]" + ] + }, + { + "pr": "27317", + "title": "[FIX] Auto Translate not working on new message template", + "userLogin": "filipemarins", + "description": "- Fix auto translate not working on new message template; \r\n- Fix a bug that the auto-translate icon was showing for users who didn't have enabled. \r\n- Show translated quote messages;\r\n- Remove translation provider for end users.\r\n- Translate the ThreadMessagePreview component", + "milestone": "6.0.0", + "contributors": [ + "filipemarins", + "hugocostadev", + "gabriellsh", + "web-flow" + ] + }, + { + "pr": "27632", + "title": "Chore: Custom Sounds Empty State", + "userLogin": "dougfabris", + "description": "It also replace `useEndpointData` in favor of `useQuery`\r\n\r\n### before\r\n![Screen Shot 2022-12-23 at 17 32 35](https://user-images.githubusercontent.com/27704687/209403136-791a8196-93f3-4fa6-8519-1d48a1d17430.png)\r\n\r\n### after\r\n![Screen Shot 2022-12-23 at 17 31 50](https://user-images.githubusercontent.com/27704687/209403089-8f426d3e-c09d-447a-93a7-0e50ea97c0ca.png)", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27556", + "title": "[IMPROVE] Require acceptance when setting new E2E Encryption key for another user", + "userLogin": "rodrigok", + "description": "Change the end to end encryption flow to require an acceptance from the user when receiving a new key.\r\n\r\n1. Changes API `e2e.updateGroupKey` to set the new key to an auxiliary property named `E2ESuggestedKey`\r\n2. Adds new API `e2e.acceptSuggestedGroupKey` to be called to accept the suggested key and save it to the final property `E2EKey`\r\n3. Adds new API `e2e.rejectSuggestedGroupKey` to be called to reject the suggested key and clear the `E2ESuggestedKey`", + "milestone": "6.0.0", + "contributors": [ + "rodrigok", + "web-flow", + "sampaiodiego" + ] + }, + { + "pr": "27754", + "title": "Regression: Broken room and message composer events", + "userLogin": "tassoevan", + "description": "It hotfixes two issues:\r\n1. user card not opening on clicking in user mentions;\r\n2. slash commands inside threads sending results to the main room.", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "27699", + "title": "[FIX] Missing placeholders from encrypted channel preview messages now with expected behavior", + "userLogin": "Educg550", + "description": "Referent to [TC-259]\r\n\r\n![Clipboard screenshot](https://user-images.githubusercontent.com/47800334/211094753-30434b6d-46aa-490a-9b27-59770cf0ff24.png)\r\nNote that now the file uses `isE2EEMessage()` function and the `useTranslation` internal hook.", + "milestone": "6.0.0", + "contributors": [ + "Educg550", + "web-flow", + "hugocostadev" + ] + }, + { + "pr": "27405", + "title": "[IMPROVE] SAML and OAuth role sync to support id and name", + "userLogin": "LucianoPierdona", + "description": "This PR allows the sync of roles by either `name` or `id`.", + "milestone": "6.0.0", + "contributors": [ + "LucianoPierdona", + "matheusbsilva137", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27075", + "title": "Chore: add e2e test coverage for Video Conference", + "userLogin": "weslley543", + "description": "Jira Issue: [VC-49]", + "milestone": "6.0.0", + "contributors": [ + "weslley543", + "web-flow", + "cauefcr", + "engelgabriel", + "lingohub[bot]", + "yash-rajpal", + "gabriellsh", + "KevLehman", + "rique223", + "aleksandernsilva" + ] + }, + { + "pr": "27631", + "title": "Chore: Invites Empty State", + "userLogin": "dougfabris", + "description": "It also replace `useEndpointData` in favor of `useQuery`\r\n### before\r\n![Screen Shot 2022-12-23 at 16 49 45](https://user-images.githubusercontent.com/27704687/209399990-95b15ba3-0ba9-4ae4-92fa-fed4c1d39d31.png)\r\n\r\n### after\r\n![Screen Shot 2022-12-23 at 16 48 27](https://user-images.githubusercontent.com/27704687/209399874-1c38f206-c385-49f5-8050-7b4f7b55bd7a.png)", + "contributors": [ + "dougfabris", + "juliajforesti", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27330", + "title": "[FIX] Marketplace app status initially disabled", + "userLogin": "rique223", + "description": "## Jira task: [MKP-20](https://rocketchat.atlassian.net/browse/MKP-20?atlOrigin=eyJpIjoiZTA3YWU5MGYwMDU1NDQ0MGJiNzQyMjYxZmMwMWVmMWQiLCJwIjoiaiJ9)\r\n\r\nCurrently, the only apps engine statuses considered enabled in the UI are the auto-enabled and manually-enabled statuses, this causes a UX problem in which the app will be considered disabled for the first few seconds of its lifecycle, upon the first installation in a workspace, since it will have the apps engine status of initialized. This PR adds the initialized status to the appEnabledStatuses list and solves this problem.\r\nDemo gif:\r\n![disabled_status_issue_solution](https://user-images.githubusercontent.com/43561537/204306496-961384c3-ec24-4959-90cd-03f4638be948.gif)\\", + "contributors": [ + "rique223", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27734", + "title": "Regression: Missing contexts on contextual bar", + "userLogin": "tassoevan", + "description": "It should fixes crashes on starred, pinned, and mentioned messages while those are migrating from Blaze to React.", + "milestone": "6.0.0", + "contributors": [ + "tassoevan", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27513", + "title": "[FIX] Save button does not stay disabled in Notification Preferences for no change on mute group option", + "userLogin": "xareyli", + "description": "Added default value for \"Mute @all and @here mentions\" option", + "milestone": "6.0.0", + "contributors": [ + "xareyli", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27672", + "title": "[NEW] Rocket.cat message for users when an app previously requested is installed", + "userLogin": "matheuslc", + "milestone": "6.0.0", + "contributors": [ + "matheuslc", + "graywolf336", + "web-flow", + "tassoevan" + ] + }, + { + "pr": "27714", + "title": "Regression: Composer Toolbox overlapping borders", + "userLogin": "dougfabris", + "milestone": "6.0.0", + "contributors": [ + "dougfabris", + "casalsgh", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27533", + "title": "[FIX] Add the possibility of danger style prop to close button on UiKit contextual-bar component", + "userLogin": "tiagoevanp", + "description": "\"image\"", + "milestone": "6.0.0", + "contributors": [ + "tiagoevanp", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27601", + "title": "[FIX] Discussion visibility when inside a private team.", + "userLogin": "gabriellsh", + "description": "Create discussions as private when the public channel is inside a private team.", + "milestone": "6.0.0", + "contributors": [ + "gabriellsh", + "web-flow", + "sampaiodiego", + "kodiakhq[bot]" + ] + }, + { + "pr": "27691", + "title": "Chore: Restrict legacy message events", + "userLogin": "tassoevan", + "description": "This PR aims to fix conflicts between the legacy messages and the new ones, specially click events on threads.", + "milestone": "6.0.0-prep", + "contributors": [ + "tassoevan", + "web-flow" + ] + }, + { + "pr": "27551", + "title": "[FIX] Anonymous user buttons", + "userLogin": "hugocostadev", + "description": "When the server accepts an anonymous user to join and chat without login, two buttons appears: one for Login and the other to send messages without login.\r\n\r\nThe component was rewritten to use the fuselage Design System and native hooks to perform actions.\r\n\r\n![image](https://user-images.githubusercontent.com/20212776/207855313-97d0e2dc-b24d-4baf-b6b5-214aed4be6f1.png)", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "web-flow", + "gabriellsh", + "kodiakhq[bot]" + ] + }, + { + "pr": "27703", + "title": "[BREAK] [FIX] VideoConference Ringer working intermittently on microservices", + "userLogin": "pierre-lehnen-rc", + "contributors": [ + "pierre-lehnen-rc", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27639", + "title": "[BREAK] Update Meteor to 2.9.1 and NodeJS to 14.21.2", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "tassoevan", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27575", + "title": "i18n: Update Hungarian translation", + "userLogin": "urbalazs", + "contributors": [ + "urbalazs", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27329", + "title": "[FIX] Remove unnecessary permissions check on app permissions review modal", + "userLogin": "rique223", + "description": "## Jira task: [MKP-166](https://rocketchat.atlassian.net/browse/MKP-166?atlOrigin=eyJpIjoiYzdjNzVhMThkOThjNGEzMmIyYTE2YmY2ZDA1MzA4YjEiLCJwIjoiaiJ9)\r\nRemoved an unnecessary check that verified if the app permissions list was an array and threw an error if it wasn't. This check has become unnecessary ever since the app permission review modal changed to show a default list of permissions in case the app happened to not have one and that's what caused those \"random\" undefined toasts that showed every once in a while.\r\nDemo gif:\r\n![undefined_toast](https://user-images.githubusercontent.com/43561537/203644331-be9583e1-a92d-46a8-ab3b-add875e7a646.gif)", + "contributors": [ + "rique223", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27689", + "title": "Chore: Reduce Less usage in theming", + "userLogin": "tassoevan", + "description": "This PR is a preparation for a coming breaking change on layout colors.", + "milestone": "6.0.0-prep", + "contributors": [ + "tassoevan", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27665", + "title": "[IMPROVE] Increase read receipt size", + "userLogin": "gabriellsh", + "description": "increase from 11px to 1rem (16px)\r\n![image](https://user-images.githubusercontent.com/40830821/209961616-3198b51a-ff7e-49eb-9627-15b53fbfe16a.png)", + "milestone": "6.0.0", + "contributors": [ + "gabriellsh" + ] + }, + { + "pr": "27686", + "title": "Chore: Improve `ts-node` startup time with `swc`", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27683", + "title": "Regression: Fix write stream error on user data export", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27680", + "title": "Regression: Rectifying thread layout", + "userLogin": "tassoevan", + "description": "This PR fixes:\r\n- the size and scrolling area of the list of messages;\r\n- the margin and general style of \"Also send to channel\" checkbox;\r\n- the size of link previews.", + "milestone": "6.0.0-prep", + "contributors": [ + "tassoevan", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27188", + "title": "[FIX] Showing Workspace Section For User Having LiveChat Manager Permission", + "userLogin": "nishant23122000", + "contributors": [ + "nishant23122000", + "filipemarins", + "web-flow", + "tassoevan", + "kodiakhq[bot]" + ] + }, + { + "pr": "27493", + "title": "[FIX] Team mention highlight EE", + "userLogin": "hugocostadev", + "description": "The team Mentioned highlighted with the char `@` was not working in Enterprise Edition using the new message parser.\r\n\r\nI added validation to the filter by `type: 'team'` and fixed the title to include the team name on mouse hover. \r\n\r\n**Previous:** \r\n\"image\"\r\n\r\n\r\n**NOW:**\r\n\"image\"", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27656", + "title": "[IMPROVE] Save toPhone when receiving SMSs", + "userLogin": "KevLehman", + "milestone": "6.0.0-prep", + "contributors": [ + "KevLehman", + "kodiakhq[bot]", + "web-flow", + "murtaza98" + ] + }, + { + "pr": "27682", + "title": "Chore: Upgrade EE license for CI", + "userLogin": "murtaza98", + "contributors": [ + "sampaiodiego", + "murtaza98" + ] + }, + { + "pr": "27667", + "title": "Chore: Replace borders to `default`", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27630", + "title": "Chore: Refactor message subcomponents", + "userLogin": "tassoevan", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "27663", + "title": "Regression: Fix go to ThreadList hook", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27582", + "title": "Chore: Refactor e2e selectors to use roles", + "userLogin": "ggazzo", + "milestone": "6.0.0", + "contributors": [ + "rodrigok", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27658", + "title": "Chore: Composer wrapper around the textarea", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27653", + "title": "[FIX] Remove invalid settings at startup", + "userLogin": "KevLehman", + "contributors": [ + "KevLehman" + ] + }, + { + "pr": "27655", + "title": "Chore: Token refactor", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27657", + "title": "Regression: Composer fix join room action", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27651", + "title": "Regression: Sidebar collapsing on extra small views", + "userLogin": "dougfabris", + "description": "### before\r\n\"Screen\r\n\r\n\r\n### after\r\n\"Screen", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27652", + "title": "Chore: Composer missing Slash Command preview", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27641", + "title": "Chore: Custom emoji empty state", + "userLogin": "dougfabris", + "description": "It also replace `useEndpointData` in favor of `useQuery`\r\n### before\r\n![Screen Shot 2022-12-26 at 15 43 59](https://user-images.githubusercontent.com/27704687/209576037-93744632-a74f-4b0c-926d-b444cf4601e2.png)\r\n\r\n### after\r\n![Screen Shot 2022-12-26 at 15 43 08](https://user-images.githubusercontent.com/27704687/209576006-4f2f1928-3532-4f42-88fa-ba661a2b7715.png)", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27628", + "title": "Chore: ExportMessages missing icon", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27617", + "title": "[FIX] `*.files` endpoints returning hidden files", + "userLogin": "sampaiodiego", + "milestone": "5.4.2", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27546", + "title": "Chore: Move service definitions to core services package", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "web-flow" + ] + }, + { + "pr": "27643", + "title": "Chore: Bump message-parser version and fix typerrors", + "userLogin": "hugocostadev", + "description": "Bumping message-parser version and fix gazzodown package errors.", + "contributors": [ + "hugocostadev", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27604", + "title": "Chore: Composer Quote Component", + "userLogin": "dougfabris", + "description": "### before\r\n\"Screen\r\n\r\n### after\r\n![image](https://user-images.githubusercontent.com/27704687/209555642-ca6bdda0-a3f8-4dc1-a34c-d1fb57539b47.png)", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27642", + "title": "Regression: Fix composer restore", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27640", + "title": "Regression: Open Thread", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27552", + "title": "Chore: Update tsconfig base target to es2020", + "userLogin": "sampaiodiego", + "description": "The base files are not split into two other files, a \"client\" and a \"server\" file. Both extends the new base one. Packages should extend either \"client\" or \"server\" ones:\r\n\r\n```mermaid\r\ngraph TD;\r\n base[tsconfig.base.json]-->client[tsconfig.base.client.json];\r\n base-->server[tsconfig.base.server.json];\r\n server-->s1[\"@rocket.chat/models\"];\r\n server-->s2[\"@rocket.chat/ddp-streamer\"];\r\n server-->s3[...];\r\n client-->c1[\"@rocket.chat/ui-theming\"];\r\n client-->c2[\"@rocket.chat/fuselage-ui-kit\"];\r\n client-->c3[...];\r\n```\r\n\r\nImportant changes:\r\n\r\n- The client config `target` have been bumped to `es2015` (it was `es5` before)\r\n- The server config `target` have been bumped to `es2020`\r\n- The default value for `jsx` is `react-jsx`\r\n- Raised `\"noUnusedLocals\": true` to a base config, so had to remove a bunch of imports to `React` that were not being used", + "contributors": [ + "sampaiodiego", + "web-flow" + ] + }, + { + "pr": "27541", + "title": "[FIX] Tokens usage", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "web-flow" + ] + }, + { + "pr": "27466", + "title": "[FIX] Omnichannel call provider option", + "userLogin": "dougfabris", + "description": "Jira Issue: [VC-38]", + "milestone": "6.0.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27629", + "title": "Chore: AppsTable UI Tweaks", + "userLogin": "dougfabris", + "description": "### before\r\n![Kapture 2022-12-23 at 16 00 51](https://user-images.githubusercontent.com/27704687/209394897-0217725b-25b2-4d70-a7eb-404b7f158a31.gif)\r\n\r\n\r\n### after\r\n![Kapture 2022-12-23 at 15 59 21](https://user-images.githubusercontent.com/27704687/209394759-0e703463-3d19-43b5-9aa7-b18c4c4cbdef.gif)", + "contributors": [ + "dougfabris", + "juliajforesti", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27626", + "title": "[FIX] Message for VideoConf on SidebarItemExtended", + "userLogin": "dougfabris", + "description": "Jitsi Issue: [VC-30]\r\n\r\n### before\r\n![Screen Shot 2022-12-23 at 11 38 24](https://user-images.githubusercontent.com/27704687/209353143-bef571c6-c79d-4489-828b-0f33ecddb5b7.png)\r\n\r\n### after\r\n![Screen Shot 2022-12-23 at 11 36 09](https://user-images.githubusercontent.com/27704687/209352853-c977ae04-3074-47bd-842b-70f3118a175b.png)", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27618", + "title": "i18n: Language update from LingoHub 🤖 on 2022-12-22Z", + "userLogin": "lingohub[bot]", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27620", + "title": "Chore: Composer Styling", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27534", + "title": "Chore: Convert UserTable on Directory to TS", + "userLogin": "nYCSTs", + "description": "Rewrote the UserTable component to TS.", + "milestone": "6.0.0", + "contributors": [ + "nYCSTs", + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27606", + "title": "Chore: Remove unused templates and bump fuselage", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "24982", + "title": "[FIX] Fix typo when create discussion modal opens", + "userLogin": "Amit91848", + "description": "Fixed typo when discussion modal opens. Now it says - Help keep an overview of what's going on!\r\n\r\n![Screenshot 2022-03-29 at 6 59 45 PM](https://user-images.githubusercontent.com/74371312/160625549-8de71046-07bd-493f-ab7b-066d3653c16f.png)", + "milestone": "6.0.0-prep", + "contributors": [ + null, + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27600", + "title": "Chore: FileItem hover color", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27599", + "title": "Chore: KeyboardShortCut color", + "userLogin": "dougfabris", + "description": "\r\n\r\n", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27574", + "title": "[FIX] E2EE initial banner not showing", + "userLogin": "rodrigok", + "milestone": "6.0.0", + "contributors": [ + "rodrigok", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27571", + "title": "Chore: Remove Sidebar from Blaze", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27602", + "title": "Regression: Add tshow to composer params", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27000", + "title": "[FIX] New users aren't mapped to rooms with OAuth groups/channels map", + "userLogin": "carlosrodrigues94", + "description": "This change deals with the problem with the new users coming from key cloak, this users were not being mapped to the correct channels on RC.", + "milestone": "5.4.2", + "contributors": [ + "carlosrodrigues94", + "matheusbsilva137", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27566", + "title": "[NEW] New Message Composer", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow", + "dougfabris" + ] + }, + { + "pr": "27527", + "title": "Chore: Fix homepage grid items style", + "userLogin": "guijun13", + "description": "- Change homepage card border-radius from 4px to 8px", + "contributors": [ + "guijun13", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27591", + "title": "Chore: TwoFactorPass Modals icon misalignment", + "userLogin": "dougfabris", + "description": "### before \r\n\"Screen\r\n\r\n### after\r\n\"Screen", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "26882", + "title": "Chore: Remove old tooltip usage", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27598", + "title": "Bump version to 6.0.0-develop", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27590", + "title": "Regression: Client-side checks for message deletion", + "userLogin": "tassoevan", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "27573", + "title": "Chore: fix EmailInbox intermittent e2e tests", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow", + "dougfabris" + ] + }, + { + "pr": "27423", + "title": "[IMPROVE] Authorize search of custom fields on `users.list` ", + "userLogin": "LucianoPierdona", + "description": "This PR allows users to filter and search for custom fields on the `users.list` endpoint", + "milestone": "6.0.0", + "contributors": [ + "LucianoPierdona", + "matheusbsilva137", + "web-flow" + ] + }, + { + "pr": "27524", + "title": "Chore: Threads as React components", + "userLogin": "tassoevan", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "27543", + "title": "[NEW] Upload service", + "userLogin": "KevLehman", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27580", + "title": "[FIX] Fix emoji appearance on sidebar", + "userLogin": "dougfabris", + "description": "The emojis appear in plain text format in the side-bar (As seen in the below issues)\r\nBy this PR, it should be fixed\r\n\r\nThis is how it looks now (As shown on the sidebar, it's appearing as an emoji not plaintext)\r\n![image](https://user-images.githubusercontent.com/34144004/163888602-7df27713-0a82-443e-8944-f48525232ca8.png)", + "milestone": "6.0.0-prep", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27576", + "title": "[FIX] RoomLeader status not working ", + "userLogin": "dougfabris", + "description": "It also fixes some visual issues\r\n\r\n### before\r\n![image](https://user-images.githubusercontent.com/27704687/208500278-85c705a2-e10a-416f-a4e5-afda34e2650f.png)\r\n\r\n### after\r\n![image](https://user-images.githubusercontent.com/27704687/208500309-d4aaa116-268b-4240-9422-abff98da898c.png)", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27554", + "title": "[FIX] Announcement banner link opening in the same page", + "userLogin": "hugocostadev", + "description": "Channel Announcements that contain links are opening on the same page instead of a new page/tab causing render issues, especially on the desktop client.\r\n\r\nThe fix was simple to add a hook for the `dompurify` library to add the `target` and `rel` attributes to keep the _blank behavior.\r\n\r\nAlso, it introduced some parsers settings to `inlineWithoutBreaks` variant to avoid breaking messages at Announcements and other places that uses this variant.", + "contributors": [ + "hugocostadev", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27557", + "title": "[FIX] Custom languages not being applied to i18next", + "userLogin": "ggazzo", + "milestone": "5.4.1", + "contributors": [ + "ggazzo", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27558", + "title": "[FIX] Registration and Login placeholders not being used", + "userLogin": "ggazzo", + "milestone": "5.4.1", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27328", + "title": "[FIX] Message Actions menu does not close upon choosing an action", + "userLogin": "filipemarins", + "milestone": "5.4.1", + "contributors": [ + "filipemarins", + "yash-rajpal", + "hugocostadev", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27538", + "title": "Chore: Deprecate unused omnichannel API", + "userLogin": "murtaza98", + "milestone": "5.4.1", + "contributors": [ + "murtaza98" + ] + }, + { + "pr": "27522", + "title": "Regression: Add button-icon-disabled-color to the palette", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27469", + "title": "Chore: Refactor CreateChannelModal", + "userLogin": "dougfabris", + "description": "Jira Issue: [UFR-11]\r\n\r\n- Replace `useForm`\r\n- Improve UI validations on Modal\r\n- Add ToastBar message on creating a channel\r\n- Fixes `topic` field not being added properly", + "milestone": "6.0.0", + "contributors": [ + "dougfabris", + "juliajforesti" + ] + }, + { + "pr": "23301", + "title": "[FIX] Showing thumbnails on files list", + "userLogin": "ostjen", + "milestone": "6.0.0", + "contributors": [ + "carlosrodrigues94", + "sampaiodiego", + "web-flow", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "27519", + "title": "Chore: Create service template", + "userLogin": "KevLehman", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27501", + "title": "Chore: Omnichannel Sidebar icons alignment", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27475", + "title": "[FIX] Fix Login with Show default form disabled", + "userLogin": "ggazzo", + "milestone": "5.4.1", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27426", + "title": "Chore: Sidebar theme", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27499", + "title": "Regression: more message box issues", + "userLogin": "tassoevan", + "description": "It handles issues regarding editing messages.", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "26851", + "title": "[FIX] Google Cloud Storage storage type", + "userLogin": "carlosrodrigues94", + "description": "Google Cloud Storage now requires a \"project ID\" to be filled. \r\n\r\nUseful links:\r\n\r\nhttps://googleapis.dev/nodejs/storage/latest/global.html#StorageOptions\r\nhttps://support.google.com/googleapi/answer/7014113?hl=en", + "milestone": "6.0.0", + "contributors": [ + "carlosrodrigues94", + "web-flow", + "matheusbsilva137", + null, + "sampaiodiego" + ] + }, + { + "pr": "27495", + "title": "Regression: message box issues", + "userLogin": "tassoevan", + "description": "It fixes some problems introduced/exposed after refactoring the `ChatMessages` API.", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "27432", + "title": "[FIX] Pagination not working on current chats", + "userLogin": "MartinSchoeler", + "milestone": "5.4.1", + "contributors": [ + "MartinSchoeler", + "aleksandernsilva", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "25346", + "title": "Chore: Change Omnichannel aggregations to run on a secondary", + "userLogin": "KevLehman", + "milestone": "6.0.0-prep", + "contributors": [ + "KevLehman", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27450", + "title": "i18n: Language update from LingoHub 🤖 on 2022-12-05Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27367", + "title": "Chore: Add spacing adjustments Home page", + "userLogin": "guijun13", + "description": "- Spacings adjustments in homepage", + "contributors": [ + "guijun13", + "web-flow" + ] + }, + { + "pr": "26213", + "title": "Chore: Remove method meteor call on message action", + "userLogin": "filipemarins", + "milestone": "6.0.0-prep", + "contributors": [ + "ggazzo", + "yash-rajpal", + "web-flow", + "filipemarins", + "dougfabris" + ] + }, + { + "pr": "27425", + "title": "Chore: Livechat convert emoji to ts", + "userLogin": "MartinSchoeler", + "contributors": [ + "MartinSchoeler", + "tassoevan", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27427", + "title": "Chore: Update ESlint rules of client code", + "userLogin": "tassoevan", + "contributors": [ + "tassoevan", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "26358", + "title": "[IMPROVE] User data download overhaul", + "userLogin": "tassoevan", + "description": "It migrates modules to TypeScript, as well adapts the code to the current version of Node.", + "milestone": "6.0.0", + "contributors": [ + "tassoevan", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27457", + "title": "Chore: Restrict `ChatMessages API` - Phase 2", + "userLogin": "tassoevan", + "description": "It split `ChatMessages` service class into a collection of smaller objects, in a composition pattern fashion. Additionally, it loosens its dependency on the DOM tree and assumes almost all methods are asynchronous.", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "27424", + "title": "Chore: Upgrade `mongodb` typings", + "userLogin": "tassoevan", + "description": "It upgrades the `mongodb` package to overcome the circular reference issue of `IMessage`.", + "contributors": [ + "tassoevan", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27452", + "title": "Merge master into develop & Set version to 5.5.0-develop", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + } + ] + }, + "6.0.0-rc.1": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [ + { + "pr": "28122", + "title": "Regression: Video Recorder \"record\" button alignment", + "userLogin": "tassoevan", + "description": "### Before\r\n\"image\"\r\n\"image\"\r\n\r\n### After\r\n\"image\"\r\n\"image\"", + "milestone": "6.0.0", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "28107", + "title": "Regression: Re-add app signature migration to fix the faulty previous one", + "userLogin": "d-gubert", + "description": "Previously merged migration files ended up in a faulty migration", + "milestone": "6.0.0", + "contributors": [ + "d-gubert" + ] + }, + { + "pr": "28121", + "title": "Regression: Gracefully stop DDP Streamer publication and close WS", + "userLogin": "sampaiodiego", + "milestone": "6.0.0", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28051", + "title": "Regression: Change wording on department removal setting", + "userLogin": "KevLehman", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "web-flow", + "murtaza98", + "kodiakhq[bot]" + ] + }, + { + "pr": "28053", + "title": "Regression: Fix department edit breaking", + "userLogin": "MartinSchoeler", + "milestone": "6.0.0", + "contributors": [ + "MartinSchoeler", + "web-flow", + "KevLehman", + "kodiakhq[bot]" + ] + }, + { + "pr": "28095", + "title": "Regression: Broken message jump onto threads", + "userLogin": "tassoevan", + "milestone": "6.0.0", + "contributors": [ + "tassoevan", + "web-flow", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "28077", + "title": "Regression: Fix agent departments select value", + "userLogin": "MartinSchoeler", + "milestone": "6.0.0", + "contributors": [ + "MartinSchoeler", + "web-flow", + "murtaza98", + "kodiakhq[bot]" + ] + }, + { + "pr": "28106", + "title": "Chore: Move all variables to first step and reduce code duplication", + "userLogin": "rodrigok", + "contributors": [ + "rodrigok" + ] + }, + { + "pr": "27706", + "title": "[FIX] Filtering users by status username is broken in Administration -> Users", + "userLogin": "totoi690", + "milestone": "6.1.0", + "contributors": [ + "totoi690", + "web-flow", + "LucianoPierdona", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "28036", + "title": "i18n: Language update from LingoHub 🤖 on 2023-02-14Z", + "userLogin": "lingohub[bot]", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow", + "rodrigok" + ] + }, + { + "pr": "28100", + "title": "Chore: Playwright test improvements", + "userLogin": "rodrigok", + "contributors": [ + "rodrigok" + ] + } + ] + }, + "6.0.0-rc.2": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "apps_engine_version": "1.37.0-alpha.157", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [ + { + "pr": "28050", + "title": "Regression: Fix improper usage of useEndpointData", + "userLogin": "KevLehman", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "rodrigok", + "web-flow", + "murtaza98", + "MartinSchoeler" + ] + }, + { + "pr": "28120", + "title": "Regression: View mode preferences without the selected option by default", + "userLogin": "hugocostadev", + "description": "After removing all Meteor Blaze templates from the project, the View mode preferences started presenting the issue:\r\n\r\nNo option is selected by default when the view mode preferences are open.\r\n\r\nPossible reason: React does allow you to use name attributes in the input tag, but it may cause some issues with radio buttons. One possible reason is that React uses a synthetic event system that does not rely on native HTML attributes, since we had the wrapper and several blaze templates in the project, this could be effecting this behavior ignoring the name attribute in the inputs.\r\n\r\n\r\n**Previous:**\r\n![image](https://user-images.githubusercontent.com/20212776/220721444-51e32397-5106-4f16-8af9-7b7e5d7209ea.png)\r\n\r\n\r\n**Current:**\r\n![image](https://user-images.githubusercontent.com/20212776/220721529-77af023b-951a-44f6-82a8-b2c18a7d0950.png)", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "sampaiodiego", + "web-flow" + ] + }, + { + "pr": "28129", + "title": "Chore: Fix fetching Apps-Engine and MongoDB versions for release notes", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "28142", + "title": "Regression: Slash commands detected at any line", + "userLogin": "tassoevan", + "milestone": "6.0.0", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "28111", + "title": "Regression: App requests notify admin function generating wrong link", + "userLogin": "rique223", + "description": "Fixed a development oversight in which the link of the app request Rocket.Cat message was generated without the marketplace version of the app nor the requests tab param.\r\nDemo gif (before):\r\n![notify-admin-before](https://user-images.githubusercontent.com/43561537/220368522-084a171c-52ab-48b4-aa43-f73f6cc12ca6.gif)\r\n\r\nDemo gif (after):\r\n![notify-admin-after](https://user-images.githubusercontent.com/43561537/220368591-93c6e157-922f-4b48-b474-f5c65c2b04b8.gif)", + "contributors": [ + "rique223", + "web-flow", + "sampaiodiego" + ] + }, + { + "pr": "28128", + "title": "Chore: Improve time of meteor build", + "userLogin": "rodrigok", + "contributors": [ + "rodrigok", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "28079", + "title": "Chore: Update tokens", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "web-flow" + ] + }, + { + "pr": "28125", + "title": "Regression: Fix sidebar horizontal scrolling", + "userLogin": "ggazzo", + "milestone": "6.0.0", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "28058", + "title": "Chore: Presence cap tweaks", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "web-flow" + ] + }, + { + "pr": "27993", + "title": "Regression: Fix Custom CSS ", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "ggazzo", + "web-flow", + "dougfabris" + ] + }, + { + "pr": "28138", + "title": "Chore: Fix CI Docker Alpine build missing", + "userLogin": "rodrigok", + "contributors": [ + "rodrigok" + ] + }, + { + "pr": "28134", + "title": "Chore: Fix CI docker publish", + "userLogin": "rodrigok", + "contributors": [ + "rodrigok" + ] + }, + { + "pr": "28108", + "title": "Chore: Refactor CI to improve code reusability and organization", + "userLogin": "rodrigok", + "contributors": [ + "rodrigok", + "web-flow" + ] + }, + { + "pr": "28127", + "title": "Regression: Fix slash command with preview", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "28126", + "title": "Chore: Purge styles of the legacy `message` template", + "userLogin": "tassoevan", + "milestone": "6.0.0", + "contributors": [ + "tassoevan" + ] + } + ] + }, + "6.0.0-rc.3": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "apps_engine_version": "1.37.0-alpha.157", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [ + { + "pr": "28132", + "title": "Regression: \"Enable unlimited apps\" button on installation modal doesn't do anything", + "userLogin": "AllanPazRibeiro", + "milestone": "6.0.0", + "contributors": [ + "AllanPazRibeiro", + "felipe-rod123", + "web-flow", + "casalsgh", + "d-gubert", + "kodiakhq[bot]" + ] + }, + { + "pr": "28048", + "title": "Regression: Avoid rendering unsupported media on PDFs & update quote styling", + "userLogin": "KevLehman", + "description": "- Fix faulty logic when deciding which attachment to render based on the mime type of it\r\n\r\n- Replace media query syntax `(width < 767px)` with `(max-width: 767px)` since the first one isn't supported on safari\r\n- Fix a bug when has bold text in multiple rows.", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "filipemarins", + "murtaza98", + "aleksandernsilva", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "28133", + "title": "Regression: Denied Microphone permission disables composer", + "userLogin": "yash-rajpal", + "description": "![Kapture 2023-02-23 at 13 10 38](https://user-images.githubusercontent.com/27704687/220964655-b2a3b69c-9b32-4f82-b585-49ac0118297a.gif)", + "milestone": "6.0.0", + "contributors": [ + "yash-rajpal", + "dougfabris", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "28206", + "title": "Regression: Fix mentioning rooms with special chars", + "userLogin": "ggazzo", + "milestone": "6.0.0", + "contributors": [ + "ggazzo", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28151", + "title": "Regression: Incorrect system message upon adding/editing SLA policy for a room.", + "userLogin": "murtaza98", + "milestone": "6.0.0", + "contributors": [ + "murtaza98", + "web-flow", + "KevLehman", + "kodiakhq[bot]" + ] + }, + { + "pr": "28171", + "title": "Chore: anonymous e2e test dispatch error", + "userLogin": "ggazzo", + "milestone": "6.0.0", + "contributors": [ + "ggazzo", + "tassoevan", + "web-flow" + ] + }, + { + "pr": "28165", + "title": "Regression: Remove unnecessary messages from Email transcript", + "userLogin": "KevLehman", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28197", + "title": "Regression: Update color tokens for voip footer", + "userLogin": "KevLehman", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28149", + "title": "Regression: Image Attachment Description size", + "userLogin": "hugocostadev", + "description": "The Image Attachment is breaking lines to match the size of the image, should follow the same size of the normal message.\r\n\r\n**Previous:** \r\n![image](https://user-images.githubusercontent.com/20212776/221175529-e574fbdb-9069-48ae-9946-d6ea475ba4bf.png)\r\n\r\n**Current:** \r\n![image](https://user-images.githubusercontent.com/20212776/221175349-486b4c40-16a2-40ab-9593-089963b6315b.png)", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "web-flow", + "sampaiodiego", + "kodiakhq[bot]" + ] + }, + { + "pr": "28117", + "title": "Regression: Fix omnichannel chat forwarding not working", + "userLogin": "murtaza98", + "milestone": "6.0.0", + "contributors": [ + "murtaza98", + "MartinSchoeler", + "web-flow", + "KevLehman", + "kodiakhq[bot]" + ] + }, + { + "pr": "28162", + "title": "Regression: Support generating pdfs from queue", + "userLogin": "KevLehman", + "description": "This removes a code validation that prevented PDF files from being generated for rooms that were closed directly from the queue.\r\n\r\nAfter discussing with product, this is a behavior we want and so we're removing the code preventing it and updating the translation keys.", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "web-flow" + ] + }, + { + "pr": "28148", + "title": "Regression: Regular users were not able to leave federated rooms", + "userLogin": "MarcosSpessatto", + "description": "When regular users (not owners, nor moderators) tried to leave federated rooms, they were not allowed to do so due to a bad permission check.\r\n\r\nJira: FED-88", + "milestone": "6.0.0", + "contributors": [ + "MarcosSpessatto", + "web-flow" + ] + }, + { + "pr": "28168", + "title": "Regression: Fix slash commands", + "userLogin": "ggazzo", + "milestone": "6.0.0", + "contributors": [ + "ggazzo", + "web-flow", + "tassoevan" + ] + }, + { + "pr": "28173", + "title": "Regression: Incorrect installation flow on app detail and upload app pages", + "userLogin": "d-gubert", + "description": "The install button displayed in the App detail page of an app from the Marketplace that hasn't been installed in the workspace didn't follow the same installation steps performed in the app list on Explore or Enterprise pages.\r\n\r\nThis PR isolates the installation handler so the exact same functions are used in both places.\r\n\r\nThe same problem was solved in the Upload App page", + "milestone": "6.0.0", + "contributors": [ + "d-gubert", + "casalsgh", + "web-flow" + ] + }, + { + "pr": "28164", + "title": "Chore: Replace deprecated color tokens", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "web-flow" + ] + }, + { + "pr": "28161", + "title": "Regression: Fix toggle theme breaking UI", + "userLogin": "juliajforesti", + "milestone": "6.0.0", + "contributors": [ + "juliajforesti" + ] + }, + { + "pr": "28170", + "title": "Chore: Remove `meteor build --debug` option", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "28154", + "title": "Regression: Hide Workspace registration feature for non-admin users", + "userLogin": "csuadev", + "milestone": "6.0.0", + "contributors": [ + "csuadev" + ] + }, + { + "pr": "28156", + "title": "Regression: Fix RegisterForm Translations", + "userLogin": "dougfabris", + "milestone": "6.0.0", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "28152", + "title": "Chore: e2e omnichannel tests - Close every opened page after the test", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "28153", + "title": "Chore: Remove fail-fast from matrix strategy", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + } + ] + }, + "6.0.0-rc.4": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "apps_engine_version": "1.37.0-alpha.157", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [ + { + "pr": "28234", + "title": "[BREAK] Remove support to deprecated typing event", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "28198", + "title": "Regression: Fix app status filter not working in private apps page", + "userLogin": "rique223", + "description": "## Jira task: [MKP-266](https://rocketchat.atlassian.net/browse/MKP-266?atlOrigin=eyJpIjoiMzlhNmRhZDNmOGZkNDBmZGEyY2FkNTQ5ZTVlZjUzNzkiLCJwIjoiaiJ9)\r\nFixed a bug in which the app status filter didn't work because of the new 'enabled*' and 'disabled*' app status.\r\nDemo gif:\r\n![private-apps-status-filter](https://user-images.githubusercontent.com/43561537/221709473-633f6866-e921-438d-9a20-e6b341823cbf.gif)", + "milestone": "6.0.0", + "contributors": [ + "rique223", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "28213", + "title": "Regression: UiKit message surface styles", + "userLogin": "tassoevan", + "milestone": "6.0.0", + "contributors": [ + "tassoevan", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28230", + "title": "[FIX] Search list missing key parameter", + "userLogin": "gabriellsh", + "milestone": "6.0.0", + "contributors": [ + "gabriellsh", + "casalsgh", + "web-flow" + ] + }, + { + "pr": "28180", + "title": "Regression: broken message exhibition when edited", + "userLogin": "tassoevan", + "description": "Sometimes a message will have the fields `editedBy` and `editedAt` present but set to `null`. This PR handle this situation.", + "milestone": "6.0.0", + "contributors": [ + "tassoevan", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "28221", + "title": "Regression: EnableUnlimitedApps button action", + "userLogin": "felipe-rod123", + "description": "\"Enable unlimited apps\" button on installation modal doesn't do anything. Now it redirects to the `'go-fully-featured-registered'` page.", + "milestone": "6.0.0", + "contributors": [ + "felipe-rod123", + "rique223", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28228", + "title": "Regression: Update Composer Formatters Translation Keys", + "userLogin": "dougfabris", + "milestone": "6.0.0", + "contributors": [ + "dougfabris", + "filipemarins", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "28236", + "title": "Regression: EmojiPicker missing shadow on dark mode", + "userLogin": "dougfabris", + "description": "#### before\r\n![Screen Shot 2023-03-01 at 18 23 18](https://user-images.githubusercontent.com/27704687/222267993-3958de34-5f28-4550-ae93-ef81af034b21.png)\r\n\r\n#### after\r\n![Screen Shot 2023-03-01 at 18 22 14](https://user-images.githubusercontent.com/27704687/222267788-e39d292b-5dc2-4797-b227-1b47008075e7.png)", + "milestone": "6.0.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28110", + "title": "Chore: More E2E tests for PDF transcript feature of Omnichannel", + "userLogin": "murtaza98", + "milestone": "6.0.0", + "contributors": [ + "murtaza98", + "web-flow", + "KevLehman", + "kodiakhq[bot]" + ] + }, + { + "pr": "28235", + "title": "Regression: Fixed triggers edit form not being properly updated", + "userLogin": "aleksandernsilva", + "milestone": "6.0.0", + "contributors": [ + "aleksandernsilva", + "filipemarins", + "web-flow" + ] + }, + { + "pr": "28139", + "title": "Regression: Add auto translate option back to live chat room", + "userLogin": "filipemarins", + "description": "Add the `translation` option to the live chat room;\r\nThe behavior of this feature in live chat rooms is quite different from direct and group messages. In these rooms, you need to activate and set up the language, while in the live chat room, the `translate` option should always appear for every room and should use the application language to translate.", + "milestone": "6.0.0", + "contributors": [ + "filipemarins", + "web-flow" + ] + }, + { + "pr": "28143", + "title": "[FIX] User registration with EmailConfirmation not working", + "userLogin": "ggazzo", + "milestone": "6.0.0", + "contributors": [ + "ggazzo", + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28200", + "title": "Regression: Show mention instead of the name of the user in app request messages", + "userLogin": "rique223", + "description": "## Jira task: [MKP-249](https://rocketchat.atlassian.net/browse/MKP-249?atlOrigin=eyJpIjoiYmNmMjBjOGI5OGUwNGVhMTg1NGMyNDZhMGYzMGY4YWMiLCJwIjoiaiJ9)\r\nStopped using the name of users that requested apps and now the app request messages directly mention the users.\r\nDemo image:\r\n![image](https://user-images.githubusercontent.com/43561537/221995968-c6e4dc7e-9052-4121-b5d0-610a1fbe7ea1.png)", + "milestone": "6.0.0", + "contributors": [ + "rique223", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "28225", + "title": "Regression: SendFileLivechatMessage using deprecated prop affecting PDF transcript", + "userLogin": "KevLehman", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28201", + "title": "Regression: Tooltip for More options dont disappear after click.", + "userLogin": "ggazzo", + "milestone": "6.0.0", + "contributors": [ + "ggazzo", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28214", + "title": "Chore: Add dark theme assets", + "userLogin": "juliajforesti", + "milestone": "6.0.0", + "contributors": [ + "juliajforesti", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "28212", + "title": "[FIX] File upload modal not opening after too long message modal", + "userLogin": "guijun13", + "description": "- Close the 'too long message to attachment' modal before opening the 'file upload' modal", + "milestone": "6.0.0", + "contributors": [ + "guijun13", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "28210", + "title": "Regression: Denied Camera permission do not disable VideoMessageAction", + "userLogin": "dougfabris", + "description": "#### before\r\n![Kapture 2023-02-28 at 16 12 58](https://user-images.githubusercontent.com/27704687/221955658-2c733275-e193-4029-ba9e-777caf3f03ba.gif)\r\n\r\n#### after\r\n![Kapture 2023-02-28 at 16 09 20](https://user-images.githubusercontent.com/27704687/221954849-f4379294-0189-4466-a523-ab71e1a8d0af.gif)", + "milestone": "6.0.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28209", + "title": "Regression: Visitor abandonment job not working properly", + "userLogin": "KevLehman", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28199", + "title": "Regression: Fix private apps already in marketplace not shown properly on app details page", + "userLogin": "rique223", + "description": "## Jira task: [MKP-267](https://rocketchat.atlassian.net/browse/MKP-267?atlOrigin=eyJpIjoiMDVmNDJjYjFjZDNiNGU4NTk4NGQ4ODZjMjM3NDYwNDciLCJwIjoiaiJ9)\r\nFixed a bug in which apps that already existed in the marketplace would not show properly when installed via the private apps page.\r\nDemo gif:\r\n![private-apps-same-app](https://user-images.githubusercontent.com/43561537/221710893-004adb81-2dd7-4ad4-b0c6-18b644415ac0.gif)", + "milestone": "6.0.0", + "contributors": [ + "rique223", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28145", + "title": "Regression: New messages not reflected in the chat window for queued chats.", + "userLogin": "murtaza98", + "milestone": "6.0.0", + "contributors": [ + "murtaza98", + "web-flow", + "filipemarins" + ] + }, + { + "pr": "28078", + "title": "Regression: Fixed room edit custom field validation", + "userLogin": "aleksandernsilva", + "description": "This PR fixes custom fields validations not being properly triggered/cleared on the room edit page.", + "milestone": "6.0.0", + "contributors": [ + "aleksandernsilva", + "KevLehman", + "web-flow", + "sampaiodiego", + "kodiakhq[bot]" + ] + }, + { + "pr": "28157", + "title": "Regression: fix a wrong behavior with the Department table row", + "userLogin": "MartinSchoeler", + "milestone": "6.0.0", + "contributors": [ + "MartinSchoeler", + "aleksandernsilva", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28183", + "title": "Regression: Save button is not enable while trying to save contact manager", + "userLogin": "FabioCavaleti", + "milestone": "6.0.0", + "contributors": [ + "FabioCavaleti", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28093", + "title": "Regression: Show messages instead of the composer when there is no action available on federated rooms", + "userLogin": "MarcosSpessatto", + "description": "Rules:\r\nIf the federation module is disabled within the workspace: **do not show the composer and show a message instead**;\r\n\r\nIf the federation module is enabled, the user is not part of the room, and the workspace is a CE environment: **do not show the composer and show a message instead.**\r\n\r\nIf the federation module is enabled, the is not part of the room, but the workspace is an EE environment: **show the composer with the Join button**\r\n\r\nIf everything is enabled, and the user is already part of the room: **show the normal composer**\r\n\r\nJira: [FED-82]", + "milestone": "6.0.0", + "contributors": [ + "MarcosSpessatto", + "web-flow", + "ggazzo", + "dougfabris", + "kodiakhq[bot]" + ] + }, + { + "pr": "28160", + "title": "Regression: Small fixes to installation flow", + "userLogin": "d-gubert", + "description": "Some UI fixes on app installation flow:\r\n* Some apps were being incorrectly shown as \"Enabled\"\r\n App status `INITIALIZED` was wrongly considered as meaning an app was \"Enabled\". That's not the case.\r\n\r\n It was introduced there to mark apps as \"installed\", but this is not the case anymore. #27330 wanted to solve the situation where an app was initially shown as disabled right after it was installed, and a different solution to this will be provided by changing how Apps-Engine communicates status changes to the UI.\r\n\r\n* Some installed apps in the \"Installed\" screen incorrectly not being displayed as grandfathered\r\n* Installation modal being shown in EE where it shouldn't\r\n* Installation modal showed wrong label when installing apps from Marketplace", + "milestone": "6.0.0", + "contributors": [ + "d-gubert", + "casalsgh", + "web-flow", + "rique223", + "kodiakhq[bot]" + ] + } + ] + }, + "6.0.0-rc.5": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "apps_engine_version": "1.37.0-alpha.157", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [ + { + "pr": "28246", + "title": "Regression: Adjusted departments upsell modal to check for licence and modules", + "userLogin": "aleksandernsilva", + "description": "This PR fixes a regression on the departments upsell modal, for the rare cases where the workspace has an enterprise licence but has no active modules. This changes improves the check to also consider modules.", + "milestone": "6.0.0", + "contributors": [ + "aleksandernsilva", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28245", + "title": "Regression: message-parse version update", + "userLogin": "hugocostadev", + "description": "Regression to fix URL parsing issues\r\n![image](https://user-images.githubusercontent.com/20212776/222496497-17ee54be-0c45-403f-97b9-95d7428328d8.png)", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28169", + "title": "[FIX] Notify apps engine event through ms api", + "userLogin": "thassiov", + "description": "The Apps-Engine must drop the current Streamer utilization and start using the Service APIs to correctly communicate between instances and client-server.", + "milestone": "6.0.0", + "contributors": [ + "thassiov", + "debdutdeb", + "web-flow", + "d-gubert", + "casalsgh", + "ggazzo" + ] + }, + { + "pr": "28211", + "title": "Chore: Add extra stats for omnichannel video calling", + "userLogin": "KevLehman", + "milestone": "6.0.0", + "contributors": [ + "KevLehman", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "28233", + "title": "Regression: Adjusted components using PaginatedMultiSelected to be compatible with new Fuselage version", + "userLogin": "aleksandernsilva", + "milestone": "6.0.0", + "contributors": [ + "aleksandernsilva", + "tassoevan" + ] + }, + { + "pr": "28094", + "title": "Regression: Change text of buttons tooltips on custom content homepage block", + "userLogin": "guijun13", + "description": "### Show to workspace Button:\r\n\r\n* No custom content added:\r\n\r\n“This action will become available after the custom content has been added”\r\n\r\n* W/ custom content:\r\n\r\n\"Not it's visible for everyone\"\r\n\"Not it's visible only for admins\"\r\n\r\n---\r\n\r\n### Show only this content Button:\r\n\r\n* if CE → “Enterprise only”\r\n* if EE and disabled → \"This action will become available after the custom content has been added and made visible to everyone”\r\n* if EE and enabled → “It will hide…\" or “It will show…\"", + "milestone": "6.0.0", + "contributors": [ + "guijun13", + "web-flow" + ] + }, + { + "pr": "27962", + "title": "Regression: run clientMessageRecieved hooks on thread main message", + "userLogin": "yash-rajpal", + "milestone": "6.0.0", + "contributors": [ + "yash-rajpal", + "web-flow" + ] + }, + { + "pr": "28163", + "title": "Regression: Jump to message not working", + "userLogin": "gabriellsh", + "milestone": "6.0.0", + "contributors": [ + "gabriellsh", + "web-flow", + "casalsgh", + "tassoevan", + "ggazzo" + ] + }, + { + "pr": "28188", + "title": "Regression: Hide price and category filters when inside of private apps page", + "userLogin": "rique223", + "description": "## Jira task: [MKP-265](https://rocketchat.atlassian.net/browse/MKP-265?atlOrigin=eyJpIjoiMGUyMjI0ZTJjNjg1NDc5ZWE0Y2U4NDVkMzk4MmRmYmEiLCJwIjoiaiJ9)\r\nThe price and category filters dont make sense for private apps so when inside of the private apps page these filters will now be hidden.\r\nDemo image:\r\n![image](https://user-images.githubusercontent.com/43561537/221595718-c812861a-672e-44ac-bb03-6046064e420a.png)", + "milestone": "6.0.0", + "contributors": [ + "rique223", + "kodiakhq[bot]", + "web-flow" + ] + } + ] + }, + "6.0.0-rc.6": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "apps_engine_version": "1.37.0-alpha.157", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [ + { + "pr": "28248", + "title": "Regression: Client is not loading new settings from server", + "userLogin": "pierre-lehnen-rc", + "milestone": "6.0.0", + "contributors": [ + "pierre-lehnen-rc", + "kodiakhq[bot]", + "web-flow" + ] + } + ] + }, + "6.0.0-rc.7": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "apps_engine_version": "1.37.0-alpha.157", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [ + { + "pr": "28298", + "title": "Regression: Scrolling on threads", + "userLogin": "yash-rajpal", + "milestone": "6.0.0", + "contributors": [ + "yash-rajpal", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28257", + "title": "Regression: OAuthApps are added with empty string `_id` field", + "userLogin": "matheusbsilva137", + "description": "- Fix OAuthApps added to the database with a empty string `_id` field.", + "milestone": "6.0.0", + "contributors": [ + "matheusbsilva137", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "28247", + "title": "Regression: Fix remove user from room shows skeleton", + "userLogin": "hugocostadev", + "description": "When the user is removed from a public channel and has it open it will show a grey placeholder screen\r\n\r\nNow, it appears the Join button as usual", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "guijun13", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28262", + "title": "Regression: Decrypt thread main message for room", + "userLogin": "yash-rajpal", + "milestone": "6.0.0", + "contributors": [ + "yash-rajpal", + "web-flow", + "gabriellsh" + ] + }, + { + "pr": "28292", + "title": "Regression: Creating Custom status ", + "userLogin": "hugocostadev", + "description": "User is not able to create a custom status from the admin section. Workspace > User Status > New\r\n\r\nThe SAVE button is not performing any action\r\n![image](https://user-images.githubusercontent.com/20212776/223121583-769a571a-365d-4f72-8d0b-f43016d31546.png)", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28294", + "title": "Chore: Fix Email Inbox flaky test", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "28266", + "title": "Regression: Disabled grandfathered apps must have the option to be enabled", + "userLogin": "d-gubert", + "description": "Grandfathered apps will not follow the new enabling flow and it should always be possible to enable them", + "milestone": "6.0.0", + "contributors": [ + "d-gubert", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28258", + "title": "Regression: Adjusted departments upsell modal message", + "userLogin": "aleksandernsilva", + "description": "This PR adjusts the logic to display the correct message on the departments upsell modal. This affects users with a trial license, expired expired licence, as well as no licence.", + "milestone": "6.0.0", + "contributors": [ + "aleksandernsilva", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28265", + "title": "Regression: Installation of some apps fail", + "userLogin": "d-gubert", + "description": "Installation was failing for apps that did not include a set o permissions required because the process was short circuiting in those cases. However, they are valid as they signify apps that function with the default permission set", + "milestone": "6.0.0", + "contributors": [ + "d-gubert", + "casalsgh", + "web-flow" + ] + }, + { + "pr": "28264", + "title": "Regression: Apps provider not handling apps lists correctly", + "userLogin": "rique223", + "description": "## Jira tasks: [MKP-272](https://rocketchat.atlassian.net/browse/MKP-272?atlOrigin=eyJpIjoiNDQzMmY4NmYyYTEyNDJjMmJmZmY3ZGUyYmQ3Y2Y2Y2EiLCJwIjoiaiJ9) [MKP-270](https://rocketchat.atlassian.net/browse/MKP-270?atlOrigin=eyJpIjoiOWRhYWM5N2VmY2UwNDAyMjlhY2ZiM2IwYjMwYWQxOWUiLCJwIjoiaiJ9)\r\nFixed a bug in which the AppsProvider would not handle the marketplace, installed, and private apps lists correctly when running the install, update, and delete listeners. This also solved related bugs of app duplication during installation and loss of reactivity during uninstalls and status changes(private apps only).\r\nDemo gif: ![apps-provider-behavior](https://user-images.githubusercontent.com/43561537/222833328-1d9836c0-738c-41d5-ac17-a5d86452ea83.gif)", + "milestone": "6.0.0", + "contributors": [ + "rique223", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28254", + "title": "Regression: Fix intermitent apps engine startup", + "userLogin": "thassiov", + "description": "Makes the apps limitation functionality depend on methods from the Apps Engine's service instead of a dynamic import of the apps orchestrator, making the engine's load process deterministic.", + "milestone": "6.0.0", + "contributors": [ + "thassiov", + "web-flow" + ] + } + ] + }, + "6.0.0-rc.8": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "apps_engine_version": "1.37.0-alpha.157", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [ + { + "pr": "28315", + "title": "Chore: Manually define shared secrets to reusable workflows", + "userLogin": "sampaiodiego", + "milestone": "6.0.0", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "28261", + "title": "[BREAK] Update livechat:saveDepartment to accept a string array in departmentsAllowedToForward", + "userLogin": "aleksandernsilva", + "description": "**Breaking change:** There have been some changes to `livechat:saveDepartment` meteor method's `departmentsAllowedToForward` parameter. Previously it used to accept a string which was a comma-separated list of departmentIds. The new type is an array of strings.\r\n\r\nDue to recent changes to the `useDepartmentList` hook the component `AutoCompleteDepartment` became incompatible with many of our existing pages, causing them to break. This PR makes them work again.", + "milestone": "6.0.0", + "contributors": [ + "aleksandernsilva", + "murtaza98", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "28310", + "title": "Regression: Remove duplicated broadcast App events", + "userLogin": "sampaiodiego", + "milestone": "6.0.0", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28311", + "title": "Regression: Zapier Callout using wrong props", + "userLogin": "ggazzo", + "milestone": "6.0.0", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27970", + "title": "Regression: `Admin UI -> Rooms` Search filter not working", + "userLogin": "totoi690", + "milestone": "6.0.0", + "contributors": [ + "totoi690", + "guijun13", + "web-flow", + "gabriellsh", + "LucianoPierdona", + "hugocostadev", + "kodiakhq[bot]" + ] + }, + { + "pr": "28304", + "title": "Regression: Fix hasLicense failing due call stack limit reasons", + "userLogin": "ggazzo", + "milestone": "6.0.0", + "contributors": [ + "ggazzo" + ] + } + ] + }, + "5.4.4": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [], + "pull_requests": [ + { + "pr": "28333", + "title": "Release 5.4.4", + "userLogin": "sampaiodiego", + "contributors": [ + "rodrigok", + "sampaiodiego" + ] + }, + { + "pr": "28319", + "title": "Chore: New temporary settings to limit access to files and outside room members", + "userLogin": "rodrigok", + "contributors": [ + "rodrigok" + ] + } + ] + }, + "6.0.0-rc.9": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [ + { + "pr": "28333", + "title": "Release 5.4.4", + "userLogin": "sampaiodiego", + "contributors": [ + "rodrigok", + "sampaiodiego" + ] + }, + { + "pr": "28319", + "title": "Chore: New temporary settings to limit access to files and outside room members", + "userLogin": "rodrigok", + "contributors": [ + "rodrigok" + ] + }, + { + "pr": "28331", + "title": "Regression: Fix emojiPicker reactivity on load-more", + "userLogin": "juliajforesti", + "milestone": "6.0.0", + "contributors": [ + "juliajforesti", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "28327", + "title": "Regression: fix Thread horizontal scrolling", + "userLogin": "ggazzo", + "milestone": "6.0.0", + "contributors": [ + "ggazzo", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28319", + "title": "Chore: New temporary settings to limit access to files and outside room members", + "userLogin": "rodrigok", + "contributors": [ + "rodrigok" + ] + }, + { + "pr": "28322", + "title": "Regression: Apps-Engine startup process was faulty", + "userLogin": "tapiarafael", + "description": "* App loading routine was forcing apps to be enabled, even if they were previously disabled\r\n* Isolated Apps startup routine for more granular control", + "milestone": "6.0.0", + "contributors": [ + "tapiarafael", + "d-gubert", + "thassiov", + "web-flow" + ] + }, + { + "pr": "28303", + "title": "Regression: OAuth Login", + "userLogin": "d-gubert", + "description": "Login flow with Rocket.Chat as an OAuth provider was broken", + "milestone": "6.0.0", + "contributors": [ + "d-gubert", + "albuquerquefabio", + "web-flow", + "rodrigok", + "ggazzo" + ] + }, + { + "pr": "28312", + "title": "Regression: Change names of requested apps sorting options", + "userLogin": "rique223", + "description": "## Jira task: [MKP-253](https://rocketchat.atlassian.net/browse/MKP-253)\r\nChanged the name of the requested app-related sorting options to cause less confusion regarding their expected behavior and solved some UX problems with the initial state of the sorting filter when on different marketplace pages. Also fixed some typos.\r\nDemo image:\r\n![image](https://user-images.githubusercontent.com/43561537/223466309-60f02a71-c21e-4607-a2b4-5de81c3b3cd5.png)", + "milestone": "6.0.0", + "contributors": [ + "rique223", + "web-flow", + "dougfabris" + ] + } + ] + }, + "6.0.0-rc.10": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [ + { + "pr": "27886", + "title": "[FIX] room data is not erased after deleting rooms by app", + "userLogin": "cuonghuunguyen", + "milestone": "6.0.0", + "contributors": [ + null + ] + }, + { + "pr": "28332", + "title": "Regression: Attachment auto size", + "userLogin": "hugocostadev", + "description": "Attachment Image or Image Preview size in small screens are not respecting container boundaries\r\n \r\n **Before:**\r\n![image](https://user-images.githubusercontent.com/20212776/223826977-507e0b57-aba1-471d-a901-30198a51d82f.png)\r\n\r\n\r\n**NOW:**\r\n![image](https://user-images.githubusercontent.com/20212776/223826829-7c6006bd-0738-4cd4-acc6-ba8b8c274e3b.png)", + "milestone": "6.0.0", + "contributors": [ + "hugocostadev", + "ggazzo", + "web-flow", + "dougfabris" + ] + } + ] + }, + "6.0.0-rc.11": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [ + { + "pr": "28336", + "title": "Chore: Remove duplicated functions in tests", + "userLogin": "sampaiodiego", + "milestone": "6.0.0", + "contributors": [ + "sampaiodiego" + ] + } + ] + }, + "6.0.0-rc.12": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [ + { + "pr": "28342", + "title": "Regression: Fix not showing global search option", + "userLogin": "sampaiodiego", + "milestone": "6.0.0", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "28341", + "title": "Regression: Added anchors elements to the allowed list to be clicked", + "userLogin": "ggazzo", + "milestone": "6.0.0", + "contributors": [ + "ggazzo", + "kodiakhq[bot]", + "web-flow" + ] + } + ] + }, + "6.0.0": { + "node_version": "14.21.2", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.4", + "5.0", + "6.0" + ], + "pull_requests": [] } + }, + "5.4.0-rc.0": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27333", + "title": "[NEW] Custom MessageType for video conference messages", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.4.0", + "contributors": [ + "pierre-lehnen-rc", + "web-flow" + ] + }, + { + "pr": "27148", + "title": "[FIX] User email address does not change when provisioned by OAuth", + "userLogin": "carlosrodrigues94", + "milestone": "5.4.0", + "contributors": [ + "carlosrodrigues94", + "matheusbsilva137", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27334", + "title": "Regression: Fix sidebar token highlighted usage", + "userLogin": "ggazzo", + "milestone": "5.4.0", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27332", + "title": "Regression: videoconf block showing a zero when no user has joined the call", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.4.0", + "contributors": [ + "pierre-lehnen-rc" + ] + }, + { + "pr": "27331", + "title": "Regression: Restore fuselage-ui-kit version", + "userLogin": "dougfabris", + "milestone": "5.4.0", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27324", + "title": "Chore: Beta Dark Theme switch", + "userLogin": "juliajforesti", + "description": "Add RadioButton on UserDropDown to toggle between light and dark theme.", + "contributors": [ + "juliajforesti", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27326", + "title": "Chore: change apps-engine version", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.4.0", + "contributors": [ + "pierre-lehnen-rc" + ] + }, + { + "pr": "27310", + "title": "[NEW] Video Conference Message blocks and info action", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "ggazzo", + "tassoevan", + "pierre-lehnen-rc" + ] + }, + { + "pr": "27316", + "title": "Chore: Fixed typo in a comment", + "userLogin": "xareyli", + "contributors": [ + "xareyli", + "web-flow" + ] + }, + { + "pr": "27306", + "title": "i18n: Language update from LingoHub 🤖 on 2022-11-21Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "yash-rajpal", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27312", + "title": "[FIX] LDAP groups to channel mapping attempts to create a new room instead of using an existing one", + "userLogin": "matheusbsilva137", + "description": "- Check rooms' name and **display name** in order to confirm they don't exist (and then try to create a new room).", + "milestone": "5.4.0", + "contributors": [ + "matheusbsilva137", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27280", + "title": "[NEW] Incompatible Apps", + "userLogin": "matheuslc", + "milestone": "5.4.0", + "contributors": [ + "matheuslc", + "casalsgh", + "web-flow", + "rique223", + "dougfabris" + ] + }, + { + "pr": "27320", + "title": "Regression: Fix custom oauth undefined clientConfig", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27307", + "title": "[FIX] Upgrading fuselage package and fix quote message prepend ", + "userLogin": "hugocostadev", + "description": "Adding heading styles to message\r\n\r\n\r\n### [OLD] As it was before this change:\r\n\"image\"\r\n\r\n### [NEW] As it is NOW:\r\n\"image\"\r\n\r\n---\r\n\r\nFix heading style in quote messages\r\n\r\nBefore:\r\n\"Screen\r\n\r\nAfter:\r\n\"Screen", + "milestone": "5.4.0", + "contributors": [ + "hugocostadev", + "web-flow", + "guijun13" + ] + }, + { + "pr": "27319", + "title": "Regression: fix contact chat history borders", + "userLogin": "MartinSchoeler", + "contributors": [ + "MartinSchoeler" + ] + }, + { + "pr": "27318", + "title": "[FIX] Adjust read only toggle on create channel based on permissions", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27181", + "title": "[FIX] Featured apps disappearing, install toast config and save changes button behavior", + "userLogin": "rique223", + "description": "## Jira tasks\r\nFeatured apps disappearing: [MKP-161](https://rocketchat.atlassian.net/browse/MKP-161?atlOrigin=eyJpIjoiYjI4MWMyODJkZjlkNDEwMjhkZWFhNjkxZjBiZTJiOGMiLCJwIjoiaiJ9)\r\nInstall toast config: [MKP-162](https://rocketchat.atlassian.net/browse/MKP-162?atlOrigin=eyJpIjoiNjNhNDJjZGE5YWQ5NDJiMWIyZjM4MjMwNmI1MmE5NjUiLCJwIjoiaiJ9)\r\nSave changes button behavior: [MKP-163](https://rocketchat.atlassian.net/browse/MKP-163?atlOrigin=eyJpIjoiZjc3MzUwZTNmYjU3NDJiZjhlOWI0OGIzMGY3ZWQ5ODUiLCJwIjoiaiJ9)\r\n\r\nFixed three bugs: In the first one featured apps would disappear from the apps list after installation, in the second one the install toast wasn't correctly configured, and in the third one the app details page save button would render even when the current app wasn't installed.\r\nDemo gif:\r\n\r\n![featured_disappearing](https://user-images.githubusercontent.com/43561537/199850435-ca9e8ba1-7924-414e-96f4-dfb373fdd754.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223", + "web-flow", + "casalsgh" + ] + }, + { + "pr": "23580", + "title": "[NEW] Bugsnag client", + "userLogin": "ggazzo", + "milestone": "5.4.0", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27246", + "title": "[IMPROVE] Add update option to apps list kebab menu and implement new update badge on apps list", + "userLogin": "rique223", + "description": "Added a new update option to the app menu to follow the removal of the CTA buttons from the apps list. Also implemented the new update badge that will replace the old update button.\r\nDemo gif:\r\n![update_badge](https://user-images.githubusercontent.com/43561537/202225372-c0369bea-12d4-4ea3-8996-8d4edab00722.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223", + "web-flow", + "dougfabris", + "kodiakhq[bot]" + ] + }, + { + "pr": "27302", + "title": "Chore: Convert chat history react", + "userLogin": "MartinSchoeler", + "milestone": "5.4.0", + "contributors": [ + "MartinSchoeler", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27311", + "title": "[FIX] Ensure onetime job runs according to 'startupSetting' everytime", + "userLogin": "thassiov", + "description": "- Fixes the condition of not running a _onetime job_ at the app's startup scheduled to run by using the [`startupSetting`](https://github.com/RocketChat/Rocket.Chat.Apps-engine/blob/04f5930244836043040a8c42beff0690a2359a53/src/definition/scheduler/IProcessor.ts#L8) if the job was run previously at another app startup (Agenda does not remove already run jobs from the database, preventing the app from scheduling the job a second time as it thinks the job is already scheduled);\r\n- Declutters the scheduler's collection by removing _onetime jobs_ documents after they are run.", + "milestone": "5.4.0", + "contributors": [ + "thassiov" + ] + }, + { + "pr": "21790", + "title": "[IMPROVE] Sorting functionality in team channel while leaving a team", + "userLogin": "sumukhah", + "milestone": "5.4.0", + "contributors": [ + "sumukhah", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27004", + "title": "[FIX] Modifying userActionIndicator syntax for translations", + "userLogin": "TBG-FR", + "milestone": "5.4.0", + "contributors": [ + "TBG-FR", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "21297", + "title": "Chore: Fix grammatical typos in release.md", + "userLogin": "sumukhah", + "milestone": "5.4.0", + "contributors": [ + "sumukhah", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "26742", + "title": "Chore: create MailerRoute endpoints", + "userLogin": "felipe-rod123", + "description": "Created 'email-inbox.sendMail' endpoint for the `apps/meteor/client/views/admin/mailer/MailerRoute.tsx` file.", + "milestone": "5.4.0", + "contributors": [ + "felipe-rod123", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "23136", + "title": "[FIX] Thread view expand command in wide screens", + "userLogin": "edward-raven", + "milestone": "5.4.0", + "contributors": [ + "edward-raven", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "21976", + "title": "[FIX] Show Favorite icon only if user has joined room", + "userLogin": "shrinish123", + "description": "Before: There was a favorite button even if the user hasn't joined the room\r\n\r\nAfter:\r\n\r\n![favorite new](https://user-images.githubusercontent.com/56491104/117336514-e8a14d00-aeb9-11eb-8c06-618bdaefa35f.png)", + "milestone": "5.4.0", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "26853", + "title": "[FIX] Scrollable report message", + "userLogin": "yasemincidem", + "milestone": "5.4.0", + "contributors": [ + "yasemincidem", + "web-flow", + "yash-rajpal", + "ggazzo" + ] + }, + { + "pr": "27184", + "title": "[IMPROVE] Add message name container component to message name header and system message", + "userLogin": "filipemarins", + "description": "Add `MessageNameContainer` wrapper to display `name` and `username` inline and separate them with a blank space.\r\n\r\nUpdate font size of system message:\r\n\r\nBefore:\r\n![Screenshot 2022-11-08 at 13 51 58](https://user-images.githubusercontent.com/9275105/200626484-bfcf3eb2-ac36-4b6c-8158-b84bf93023bd.png)\r\n\r\n\r\nAfter:\r\n\"Screenshot\r\n\r\n\r\nAdd removed message variation to `ThreadMessageOrigin` component\r\nBefore:\r\n![Screenshot 2022-11-08 at 13 35 45](https://user-images.githubusercontent.com/9275105/200622876-5e5bd7a2-2df1-453a-9e81-96635390648e.png)\r\n\r\nAfter:\r\n\"Screenshot", + "milestone": "5.4.0", + "contributors": [ + "filipemarins", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "20476", + "title": "[FIX] Archived channels reappearing permanently", + "userLogin": "im-adithya", + "milestone": "5.4.0", + "contributors": [ + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27290", + "title": "[FIX] Integration history breaking when there's more than 49 records", + "userLogin": "gabriellsh", + "description": "Aditionally, fixed example data for incoming webhooks and converted some files to TS.", + "milestone": "5.4.0", + "contributors": [ + "gabriellsh" + ] + }, + { + "pr": "27245", + "title": "[FIX] MarkdownText component not respecting `Markdown_SupportSchemesForLink` setting", + "userLogin": "gabriellsh", + "milestone": "5.4.0", + "contributors": [ + "gabriellsh" + ] + }, + { + "pr": "27153", + "title": "[IMPROVE] VideoConf Miss Config Modal", + "userLogin": "dougfabris", + "description": "Jira Issue: [VC-9]\r\n\r\n", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27314", + "title": "Chore: Updates rocket.cat's logo to match colors of our new logo", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27262", + "title": "[IMPROVE] Improve searchChats endpoint to have source filter support", + "userLogin": "KevLehman", + "milestone": "5.4.0", + "contributors": [ + "KevLehman" + ] + }, + { + "pr": "26415", + "title": "Chore: create AccountProfileForm endpoints", + "userLogin": "felipe-rod123", + "description": "Created the '/v1/users.checkUsernameAvailability' and other endpoints for the `apps/meteor/client/views/account/profile/AccountProfileForm.tsx` file, and added Ajv validations.", + "milestone": "5.4.0", + "contributors": [ + "felipe-rod123", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27160", + "title": "Chore: Create new endpoint for test webhooks and deprecate meteor method", + "userLogin": "KevLehman", + "milestone": "5.4.0", + "contributors": [ + "KevLehman", + "web-flow" + ] + }, + { + "pr": "26754", + "title": "[IMPROVE] Read threads when marking a room as read", + "userLogin": "LucianoPierdona", + "description": "This PR changes the functionality of `subscription.read` to add read threads when endpoint is called", + "milestone": "5.4.0", + "contributors": [ + "LucianoPierdona", + "web-flow", + "debdutdeb", + "matheusbsilva137", + "ggazzo" + ] + }, + { + "pr": "21974", + "title": "Chore: README.md", + "userLogin": "satishp962", + "milestone": "5.4.0", + "contributors": [ + "satishp962", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "26956", + "title": "Chore: deprecate refreshClients methods", + "userLogin": "felipe-rod123", + "description": "Created the 'assets.refreshClients' endpoint for the `apps/meteor/client/views/admin/settings/groups/AssetsGroupPage.tsx` file.", + "milestone": "5.4.0", + "contributors": [ + "felipe-rod123", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27239", + "title": "[IMPROVE] Marketplace feedback toasts", + "userLogin": "rique223", + "description": "## Jira tasks\r\nSave app changes toast: [MKP-160](https://rocketchat.atlassian.net/browse/MKP-160?atlOrigin=eyJpIjoiMjM1YmZjMTVjZGU2NGUwMGIxNTRlYTEwODgwMDk2ZDkiLCJwIjoiaiJ9)\r\nUninstall app toast: [MKP-168](https://rocketchat.atlassian.net/browse/MKP-168?atlOrigin=eyJpIjoiOThkMjEwOTk5NjhiNDE2OGEwY2MyNWEyNWM5YzNkMTUiLCJwIjoiaiJ9)\r\nEnable/disable app feedback toast: [MKP-169](https://rocketchat.atlassian.net/browse/MKP-169?atlOrigin=eyJpIjoiN2VjODIzOGMwNmJkNGU3N2JhOWEzMDU3Y2IxZjZkNWMiLCJwIjoiaiJ9)\r\n\r\n\r\nImplemented/refactored four toast notifications and refactored another two in marketplace. The first one happens after the user saves the settings of an app, the second one when the user successfully uninstalls an app and the third and fourth ones happen when the user enables and disables an app respectfully.\r\nDemo gif:\r\n![feedback_toasts](https://user-images.githubusercontent.com/43561537/202277707-a3b38536-e090-4c4f-96b4-8e21bcd10070.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26187", + "title": "Chore: Replace all saveUserPreferences method calls", + "userLogin": "yash-rajpal", + "milestone": "5.4.0", + "contributors": [ + "yash-rajpal", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27205", + "title": "Chore: Convert omni libs to typescript ", + "userLogin": "KevLehman", + "milestone": "5.4.0", + "contributors": [ + "KevLehman" + ] + }, + { + "pr": "23632", + "title": "[IMPROVE] Adding a noscript tag for letting users know if they have JS disabled", + "userLogin": "sidmohanty11", + "milestone": "5.4.0", + "contributors": [ + "sidmohanty11", + "gabriellsh" + ] + }, + { + "pr": "26957", + "title": "[FIX] Change GridFS error message validation", + "userLogin": "tapiarafael", + "description": "Allow uninstalling an app even if source files cannot be found. This validation was already done in the past, but since the error message was changed, the validation was broken.", + "milestone": "5.4.0", + "contributors": [ + "tapiarafael", + "casalsgh", + "web-flow" + ] + }, + { + "pr": "21655", + "title": "[FIX] The parent room icon is now clickable", + "userLogin": "shrinish123", + "description": "The parent room icon as shown in the video was not clickable but the cursor type on the icon was a pointer. Now even clicking on the icon or anywhere on the parent room tag will redirect you to the parent room. \r\n\r\nBefore : \r\n\r\nhttps://user-images.githubusercontent.com/56491104/115318759-06717100-a19c-11eb-85e6-f3ad4d788721.mp4\r\n\r\n\r\nAfter: \r\n\r\n\r\nhttps://user-images.githubusercontent.com/56491104/115318784-15582380-a19c-11eb-9aca-b40b872774ad.mp4", + "milestone": "5.4.0", + "contributors": [ + "shrinish123", + "web-flow", + "juliajforesti" + ] + }, + { + "pr": "27117", + "title": "[FIX] Delete first message when initializing thread returns black screen", + "userLogin": "filipemarins", + "milestone": "5.4.0", + "contributors": [ + "filipemarins", + "guijun13", + "web-flow" + ] + }, + { + "pr": "27214", + "title": "[IMPROVE] Add searchTerm support for livechat/rid/messages API", + "userLogin": "KevLehman", + "milestone": "5.4.0", + "contributors": [ + "KevLehman" + ] + }, + { + "pr": "27265", + "title": "[FIX] Improper grammar when converting channel member to owner", + "userLogin": "JoshMcCullough", + "milestone": "5.4.0", + "contributors": [ + "JoshMcCullough", + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27299", + "title": "Chore: Deprecation warning on 'typing' stream event.", + "userLogin": "pierre-lehnen-rc", + "milestone": "5.4.0", + "contributors": [ + "pierre-lehnen-rc" + ] + }, + { + "pr": "26634", + "title": "Chore: removing useEndpointData from license api", + "userLogin": "hugocostadev", + "description": "The deprecated hook `useEndpointData` was removed and changed to `useMethod` + `useQuery`separated in a hook.\r\n\r\nIn `useQuery` options we added an option to keep the cache as `Infinity` until the queries are invalidated or the page refreshes, also the query keys were changed to consolidate the keys and manage the cache in the best way possible to avoid unnecessary API calls. \r\n\r\nIn settings changed or user action that impact the License status was added a method to invalidate the cache for license query keys\r\n\r\nE.g: `queryClient.invalidateQueries(['licenses']);`", + "milestone": "5.4.0", + "contributors": [ + "hugocostadev" + ] + }, + { + "pr": "27301", + "title": "Chore: Create unique index for `E2EKey` field", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26842", + "title": "[FIX] LDAP \"Sync Roles\" option doesn't work for custom roles", + "userLogin": "LucianoPierdona", + "description": "Previously the sync of custom fields on LDAP wasn't working because the check was assuming that the `name` of the role is the same value from `_id`, which is the same for initial roles, but different for custom.", + "milestone": "5.4.0", + "contributors": [ + "LucianoPierdona", + "matheusbsilva137", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27300", + "title": "Chore: UserAvatar wrapper missing key in RoomForeword", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27295", + "title": "Chore: Add deprecation warning to settings", + "userLogin": "gabriellsh", + "description": "![image](https://user-images.githubusercontent.com/40830821/202707905-dc7e2b02-35ec-4abd-9b91-26b6e66a7124.png)\r\n\r\nList of settings:\r\n- Show edited status\r\n- Allow Message snippeting\r\n- Show formating Tips\r\n- Disable Embeded for Users\r\n- Issue tracker links\r\n- Message attachments > Group Attachment Buttons\r\n- Markdown > All settings inside Group\r\n- Autolinker > All settings inside Group\r\n\r\nEdited Message for old federation.", + "milestone": "5.4.0", + "contributors": [ + "gabriellsh", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27197", + "title": "Chore: Refactor LeaveTeam to Typescript", + "userLogin": "dougfabris", + "description": "Additionally, it fixes: \r\n- Users would be able to select team channels that they want to leave while leaving the team.\r\n- Users would now automatically leave from team channels he/she selected.\r\n\r\nBEFORE\r\n\r\n\r\n\r\nhttps://user-images.githubusercontent.com/55157259/116005794-24205980-a626-11eb-888e-59e42ca21f9a.mp4\r\n\r\n\r\n\r\n\r\n\r\nBEFORE\r\n\r\nhttps://user-images.githubusercontent.com/55157259/115970150-4babef00-a55e-11eb-97c9-45683ac16cc1.mp4\r\n\r\nAFTER\r\n\r\nhttps://user-images.githubusercontent.com/55157259/116005344-21bd0000-a624-11eb-8e58-a956579a08b4.mp4\r\n\r\n\r\nAFTER\r\n\r\nhttps://user-images.githubusercontent.com/55157259/115970155-5070a300-a55e-11eb-877f-862dd9a974d7.mp4", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "23830", + "title": "[FIX] Sidebar context menu in searchList", + "userLogin": "Aman-Maheshwari", + "description": "Removed onClose function from the Box Component inside `searchList.js` as this component wraps the complete list which is rendered and when clicked on the any rendered row inside the component it closes the searchList preventing the context menu to be displayed.\r\nAlso added `usePreventDefault` hook.\r\n## Before\r\n\r\nhttps://user-images.githubusercontent.com/50165440/144127826-9b6d3e5e-9442-49dc-89c8-b604b910be4c.mp4\r\n\r\n## After\r\n\r\nhttps://user-images.githubusercontent.com/50165440/144127815-d60e1026-a0eb-4e9b-a7f3-fe80dd06a2d8.mp4", + "milestone": "5.4.0", + "contributors": [ + "Aman-Maheshwari", + "web-flow", + "dougfabris", + "kodiakhq[bot]" + ] + }, + { + "pr": "27119", + "title": "[NEW] Federation events coverage expansion", + "userLogin": "MarcosSpessatto", + "description": "This PR adds the following features for the Matrix Federation feature:\r\n- Ability to sync Users' real names (since they have at least one room in common with other users);\r\n- Search for public channels given a server name;", + "milestone": "5.4.0", + "contributors": [ + "MarcosSpessatto" + ] + }, + { + "pr": "27284", + "title": "[FIX] Message Parser version upgrade", + "userLogin": "hugocostadev", + "milestone": "5.4.0", + "contributors": [ + "hugocostadev", + "gabriellsh", + "web-flow" + ] + }, + { + "pr": "27294", + "title": "[FIX] Replace regex not compatible with safari", + "userLogin": "filipemarins", + "milestone": "5.3.2", + "contributors": [ + "filipemarins" + ] + }, + { + "pr": "27003", + "title": "[NEW] Emphasis Elements (italic, strike and bold) in Message Parser Components", + "userLogin": "hugocostadev", + "description": "Currently the message parser does not accept Emphasis elements mixed with plain text\r\n\r\n`[Normal Link - *Bold*, _Italic_ and ~strike~ Styles](https://rocket.chat/)` return plain text → Should return a Lin with bold/italic/strike\r\n\r\nTo fix this behavior it was necessary to edit LinkSpan component in gazzodown package (changes included in this PR) and the grammar/utils files in the `fuselage/message-parser` repository\r\n\r\nFuselage Pull Request: https://github.com/RocketChat/fuselage/pull/887/", + "milestone": "5.4.0", + "contributors": [ + "hugocostadev", + "web-flow", + "guijun13", + "kodiakhq[bot]" + ] + }, + { + "pr": "25568", + "title": "[FIX] Set default value \"false\" for global search.", + "userLogin": "ivan1kazantsev", + "description": "If we disable the \"global search\", then the \"global search\" checkbox removes from the UI. It's not what we want. I think, we should set the default to \"false\", because the default is to search inside the channel/dialog.", + "milestone": "5.4.0", + "contributors": [ + "ivan1kazantsev", + "web-flow", + "debdutdeb", + "tassoevan", + "dougfabris", + "sampaiodiego", + "kodiakhq[bot]" + ] + }, + { + "pr": "27244", + "title": "Regression: Custom fields form not showing in user profile nor admin", + "userLogin": "gabriellsh", + "milestone": "5.4.0", + "contributors": [ + "gabriellsh", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27201", + "title": "[FIX] Sort RecordList items in REVERSE chronological order, not FORWARD", + "userLogin": "nmagedman", + "description": "Sort items in the Files sidebar in *reverse* chronological order (newest at top, oldest at bottom), as it did _before_ RC v3.11.0.", + "milestone": "5.4.0", + "contributors": [ + "nmagedman" + ] + }, + { + "pr": "27289", + "title": "Chore: Remove unused css", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27242", + "title": "Chore: also send thread to channel translations", + "userLogin": "yash-rajpal", + "description": "\"image\"", + "milestone": "5.4.0", + "contributors": [ + "yash-rajpal", + "web-flow" + ] + }, + { + "pr": "27062", + "title": "[FIX] Marketplace app details page back-button behavior", + "userLogin": "rique223", + "description": "Jira task: [MKP-26](https://rocketchat.atlassian.net/browse/MKP-26?atlOrigin=eyJpIjoiM2I4MzVhYmQ2OWRkNDE0ZGI4NWZkMzE3MDQwNmIxMzMiLCJwIjoiaiJ9)\r\n\r\nFixed the behavior of the marketplace app details page back button. Now it will return the user to the page they accessed the app details from. Also, refactored the overall routing of the marketplace and removed the admin-apps route as everything is now handled by the admin-marketplace route.\r\n\r\nDemo gif:\r\n![apps-back-button](https://user-images.githubusercontent.com/43561537/195709074-a886472e-5462-474e-8f65-5cfa33d30263.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223", + "web-flow", + "dougfabris", + "juliajforesti" + ] + }, + { + "pr": "27048", + "title": "Chore: Add tests for omni-jobs & add more context in system messages for jobs", + "userLogin": "murtaza98", + "contributors": [ + "murtaza98", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27258", + "title": "Chore: Fix missing license for forks", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27255", + "title": "i18n: Language update from LingoHub 🤖 on 2022-11-14Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "yash-rajpal", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27213", + "title": "[FIX] User auto complete breaks on enter key press", + "userLogin": "yash-rajpal", + "milestone": "5.4.0", + "contributors": [ + "yash-rajpal", + "debdutdeb", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27111", + "title": "[FIX] User approval email doesn't display username and e-mail when user logs in with OAuth", + "userLogin": "carlosrodrigues94", + "milestone": "5.4.0", + "contributors": [ + "carlosrodrigues94", + "matheusbsilva137", + "web-flow", + "gabriellsh" + ] + }, + { + "pr": "27259", + "title": "[FIX] Sidebar Room list extended preview not updating on new messages.", + "userLogin": "gabriellsh", + "milestone": "5.3.2", + "contributors": [ + "gabriellsh" + ] + }, + { + "pr": "27163", + "title": "[FIX] Avg response time calculation", + "userLogin": "KevLehman", + "milestone": "5.4.0", + "contributors": [ + "KevLehman", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27198", + "title": "Chore: Rewrite AutoCompleteDepartment to TypeScript", + "userLogin": "tiagoevanp", + "description": "Department field inside of current chats is one of the places who uses AutoCompleteDeparment:\r\n![image](https://user-images.githubusercontent.com/17487063/200659774-9db7b19d-1e5f-471b-8b7d-540ef3aa59fb.png)", + "milestone": "5.4.0", + "contributors": [ + "tiagoevanp", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26782", + "title": "[IMPROVE] Login rewrite in react", + "userLogin": "ggazzo", + "milestone": "5.4.0", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27243", + "title": "[FIX] Multi instance error message", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27240", + "title": "[FIX] Next schedule check for Apps", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "27056", + "title": "[IMPROVE] Move app list install logic to app menu", + "userLogin": "rique223", + "description": "## Jira task: [MKP-136](https://rocketchat.atlassian.net/browse/MKP-136?atlOrigin=eyJpIjoiM2M0ODhkZDc0YjQ2NGE5OGE4YTBkZDJhY2M0NGVmZDgiLCJwIjoiaiJ9)\r\nMoved the install/buy/subscribe logic from the CTA buttons that existed in the app list to the app menu. Now the user can install apps by clicking in the kebab menu in the right of the app list entry. Also solved a little undefined bug happening in the app permissions modal.\r\nDemo gif:\r\n![app_menu](https://user-images.githubusercontent.com/43561537/195204630-e66c7859-028f-4654-8367-96029a855b42.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27229", + "title": "Chore: Check for Cloud client secret to check if workspace is registered", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego" + ] + }, + { + "pr": "20459", + "title": "[FIX] Use name if fname is undefined", + "userLogin": "aKn1ghtOut", + "description": "In the default general room(and possibly in other cases), the fname property is not set. The site should use the \"name\" property as a fallback in such cases.\r\n\r\n### After fix\r\n![Screenshot from 2021-01-28 03-47-19](https://user-images.githubusercontent.com/38764067/106062371-b0e97300-611c-11eb-97de-1ff4c668a4c8.png)\r\n![Screenshot from 2021-01-28 03-47-55](https://user-images.githubusercontent.com/38764067/106062374-b21aa000-611c-11eb-83db-93a3d0858d46.png)", + "milestone": "5.4.0", + "contributors": [ + "aKn1ghtOut", + "tassoevan", + "web-flow", + "juliajforesti" + ] + }, + { + "pr": "21602", + "title": "[FIX] Navigate to home after deleting a channel from edit screen", + "userLogin": "sumukhah", + "milestone": "5.4.0", + "contributors": [ + "sumukhah", + "juliajforesti", + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27233", + "title": "[FIX] Shrug missing backslash character", + "userLogin": "hugocostadev", + "description": "Previously the escape character `\\` was escaping everything.\r\n\r\nTo avoid unexpected text formatting errors it was restricted to only escape curtains chars like: * _ ~ ` # . \r\nDoing so the Shrug had to change in the code to display the correct ASCII Art", + "contributors": [ + "hugocostadev", + "gabriellsh", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27230", + "title": "[FIX] Display Edit Team instead of Edit Room when in a team", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27232", + "title": "Chore: Improve configurations related to Typescript in Livechat", + "userLogin": "MartinSchoeler", + "contributors": [ + "MartinSchoeler" + ] + }, + { + "pr": "27223", + "title": "Chore: Make it easier to run micro services", + "userLogin": "sampaiodiego", + "description": "You can now run a microservices environment with `yarn turbo run ms`", + "contributors": [ + "sampaiodiego", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27225", + "title": "[FIX] UiKit modals taking 5 seconds to close", + "userLogin": "pierre-lehnen-rc", + "contributors": [ + "pierre-lehnen-rc", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27222", + "title": "[FIX] AttachmentDescription color token", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti" + ] + }, + { + "pr": "27196", + "title": "[FIX] RoomForeword design", + "userLogin": "juliajforesti", + "description": "Before\r\n![image](https://user-images.githubusercontent.com/60678893/200065803-aaafe740-62f6-4d11-b9a4-c4f394f00291.png)\r\n\r\n\r\nAfter\r\n\"image\"", + "contributors": [ + "juliajforesti", + "web-flow" + ] + }, + { + "pr": "27215", + "title": "Chore: Remove SoundRow.js", + "userLogin": "dougfabris", + "milestone": "5.4.0", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "23741", + "title": "[FIX] multiple user assigned for a role", + "userLogin": "Aman-Maheshwari", + "milestone": "5.4.0", + "contributors": [ + "Aman-Maheshwari", + "tassoevan", + "juliajforesti", + "web-flow", + "dougfabris", + "kodiakhq[bot]" + ] + }, + { + "pr": "21675", + "title": "[FIX] Add sorting channels on teams", + "userLogin": "sumukhah", + "milestone": "5.4.0", + "contributors": [ + "sumukhah", + "web-flow", + "juliajforesti" + ] + }, + { + "pr": "27202", + "title": "i18n: Language update from LingoHub 🤖 on 2022-11-07Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "yash-rajpal", + "web-flow" + ] + }, + { + "pr": "27092", + "title": "[FIX] Always parse encrypted messages on client", + "userLogin": "yash-rajpal", + "milestone": "5.4.0", + "contributors": [ + "yash-rajpal", + "web-flow" + ] + }, + { + "pr": "27047", + "title": "[NEW] Add new endpoint 'livechat/agent.status' & deprecate changeLivechatStatus meteor method ", + "userLogin": "murtaza98", + "milestone": "5.4.0", + "contributors": [ + "murtaza98", + "web-flow", + "KevLehman", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "27136", + "title": "Chore: Rewrite the label/description of the Push_request_content_from_server setting", + "userLogin": "nmagedman", + "description": "Documentation: Clarify the meaning/effect of the setting Push_request_content_from_server (\"Fetch full message content from the server on receipt\"), which can lead to unexpected \"You have a new message\" notifications", + "contributors": [ + "nmagedman" + ] + }, + { + "pr": "24043", + "title": "Chore: Added tooltip to options of message-actions", + "userLogin": "aswinidev", + "description": "https://user-images.githubusercontent.com/76481696/147604643-253d0577-65d6-4bfe-b67e-49a7cc67c03e.mp4", + "milestone": "5.4.0", + "contributors": [ + "aswinidev", + "web-flow", + "juliajforesti", + "ggazzo" + ] + }, + { + "pr": "27167", + "title": "[FIX] User merge by e-mail on OAuth is case-sensitive", + "userLogin": "matheusbsilva137", + "description": "- Ignore case when searching for a user by email.", + "milestone": "5.3.1", + "contributors": [ + "matheusbsilva137", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27105", + "title": "[FIX] File upload receiving whole file to apply limits", + "userLogin": "sampaiodiego", + "milestone": "5.3.1", + "contributors": [ + "sampaiodiego", + "web-flow", + "ggazzo", + "casalsgh" + ] + }, + { + "pr": "27191", + "title": "Chore: Restrict `ChatMessages` API - Phase 1", + "userLogin": "tassoevan", + "description": "It prepares `ChatMessages` to be splitted into smaller components to handle the interaction of a list of messages and the message composer.", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "27037", + "title": "[FIX] Adjusted form validation to disallow duplicated emails", + "userLogin": "aleksandernsilva", + "description": "This pull request revisits the user info form, fixing a bug that allowed the form to be saved with an already existing e-mail. Taking advantage of this opportunity this PR also refactors the file to typescript and adds new libs like `useForm` and `useQuery`.", + "milestone": "5.4.0", + "contributors": [ + "aleksandernsilva" + ] + }, + { + "pr": "20312", + "title": "Chore: subscriptions.read accepts both \"roomId\" and \"rid\" as payload", + "userLogin": "lucassartor", + "description": "Adding `roomId` as another option of payload in the `subscriptions.read` endpoint besides from `rid`.", + "milestone": "5.4.0", + "contributors": [ + "lucassartor", + "web-flow", + "sampaiodiego", + "kodiakhq[bot]" + ] + }, + { + "pr": "24361", + "title": "[FIX] Add pause functionality to Custom Sounds", + "userLogin": "nishant23122000", + "milestone": "5.4.0", + "contributors": [ + "nishant23122000", + "debdutdeb", + "web-flow", + "dougfabris", + "ggazzo" + ] + }, + { + "pr": "27170", + "title": "Chore(deps): Bump felixmosh/turborepo-gh-artifacts from 1 to 2", + "userLogin": "dependabot[bot]", + "contributors": [ + "dependabot[bot]", + "web-flow" + ] + }, + { + "pr": "21677", + "title": "[FIX] Adding error message for wrong dates", + "userLogin": "shrinish123", + "description": "Before : \r\n![before](https://user-images.githubusercontent.com/56491104/115405052-85ea5900-a20b-11eb-9c78-5e98de6c454c.png)\r\n\r\nAfter: \r\n\r\n![after export](https://user-images.githubusercontent.com/56491104/115405085-8da9fd80-a20b-11eb-8b72-de9ef7c2217b.png)", + "milestone": "5.4.0", + "contributors": [ + "KevLehman", + "ggazzo", + "web-flow", + "shrinish123" + ] + }, + { + "pr": "21603", + "title": "[FIX] Show a consistent name on information screen", + "userLogin": "sumukhah", + "milestone": "5.4.0", + "contributors": [ + "sumukhah", + "web-flow", + "dougfabris", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "20338", + "title": "Chore: New Password field is confusing", + "userLogin": "im-adithya", + "milestone": "5.4.0", + "contributors": [ + "im-adithya", + "web-flow", + "gabriellsh" + ] + }, + { + "pr": "21766", + "title": "Chore: Remove blank owner field from rooms ", + "userLogin": "Kartik18g", + "milestone": "5.4.0", + "contributors": [ + "Kartik18g", + "web-flow", + "gabriellsh" + ] + }, + { + "pr": "20324", + "title": "[FIX] Fixed Allow reacting toggle button in Edit room", + "userLogin": "Darshilp326", + "description": "Users can now see changes for toggling allow reacting button after changes.\r\nUsers do not need to come back for changing allow reacting button.\r\n\r\nhttps://user-images.githubusercontent.com/55157259/105572410-f274c980-5d7c-11eb-806a-e23c2abd37de.mp4", + "milestone": "5.4.0", + "contributors": [ + "Darshilp326", + "web-flow", + "dougfabris", + "kodiakhq[bot]", + "ggazzo" + ] + }, + { + "pr": "27199", + "title": "Chore: Remove turborepo if env is not set", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "24605", + "title": "[IMPROVE] Removed tool tip from sidebar menu", + "userLogin": "Himanshu664", + "milestone": "5.4.0", + "contributors": [ + "Himanshu664", + "juliajforesti" + ] + }, + { + "pr": "27046", + "title": "Chore: Migrate EE LivechatRooms model to typescript", + "userLogin": "murtaza98", + "milestone": "5.4.0", + "contributors": [ + "murtaza98", + "KevLehman" + ] + }, + { + "pr": "27189", + "title": "[FIX] Add condition to createUser button on UsersPage", + "userLogin": "juliajforesti", + "description": "Hide the create user button in admin if the user doesn't have the permission to do so. It was not the case before.\r\n\r\n\r\nhttps://user-images.githubusercontent.com/45966964/115802514-5ab86300-a3df-11eb-98d8-7aba696bfa7e.mp4", + "contributors": [ + "juliajforesti", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26973", + "title": "[FIX] Install private apps modal behavior marketplace", + "userLogin": "rique223", + "description": "Fixed two bugs in the private app install page: \r\n- The first one is a lack of pt-br translation to the agree button of the apps permission modal \r\n- The second one is that the review modal did not show the default permission list when the app being installed did not provide a permissions list.\r\n\r\n**Demo gif**:\r\n![AppsPermissionModal](https://user-images.githubusercontent.com/43561537/193342594-5516b557-948a-4d9d-ade3-65bb1600e458.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223", + "web-flow", + "dougfabris" + ] + }, + { + "pr": "27190", + "title": "[FIX] Add condition to invite user if user doesn't have permission", + "userLogin": "juliajforesti", + "description": "If you deactivated the permission to send links, the button was always there and led to an error message.\r\nBefore: \r\n\r\nhttps://user-images.githubusercontent.com/45966964/115801057-23948280-a3dc-11eb-83c2-b3e16f66ddd5.mp4\r\n\r\nAfter:\r\n\r\nhttps://user-images.githubusercontent.com/45966964/115801253-956ccc00-a3dc-11eb-95d0-9baa69410fe1.mp4", + "contributors": [ + "juliajforesti" + ] + }, + { + "pr": "27195", + "title": "Chore: Remove js-preventer Action", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27151", + "title": "[FIX] Hide system messages setting not being respected.", + "userLogin": "gabriellsh", + "description": "There was a query missing the parameters in the client.\r\n\r\nAlso added a few tests to help reduce the risk of this happening again.", + "milestone": "5.3.1", + "contributors": [ + "gabriellsh", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27192", + "title": "Chore: remove auto label action", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27176", + "title": "Chore: Remove secrets.RC_TURBO_GH_TOKEN dep from build", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27183", + "title": "[FIX] Missing React When Read Only setting on Admin Rooms Edit", + "userLogin": "dougfabris", + "description": "When the user was editing a room in the admin, he could not set React When Read Only because the option was not there unlike a normal room edit. So i added the option.", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26871", + "title": "Chore: Test for import ", + "userLogin": "weslley543", + "contributors": [ + "weslley543", + "web-flow" + ] + }, + { + "pr": "27166", + "title": "[FIX] ThreadRow hover color", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27027", + "title": "Chore: CreateTeamModal Refactor", + "userLogin": "dougfabris", + "description": "Jira Issue: [UFR-36]\r\n\r\n- Replace `useForm`\r\n- Improve UI validations on Modal\r\n- Add ToastBar message on creating a team", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27180", + "title": "[FIX] Discussion list timestamp and Edit room system messages", + "userLogin": "gabriellsh", + "contributors": [ + "gabriellsh", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27178", + "title": "[FIX] Discussions list divider on contextualBar", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27177", + "title": "[FIX] Uploading Custom Sound files not working, but showing success", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27156", + "title": "Chore: Show better error logs", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego", + "ggazzo", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "20878", + "title": "[FIX] Message search breaking URL, usertags and emojis", + "userLogin": "TBG-FR", + "contributors": [ + "TBG-FR", + "sampaiodiego", + "web-flow" + ] + }, + { + "pr": "27054", + "title": "[NEW] REST API endpoint `/v1/oauth-apps.create`", + "userLogin": "felipe-rod123", + "description": "Created the 'oauth-apps.addOAuthApp' endpoint for the `apps/meteor/client/views/admin/oauthApps/OAuthAddApp.tsx` file, and added Ajv validation.", + "contributors": [ + "felipe-rod123", + "sampaiodiego", + "debdutdeb", + "web-flow" + ] + }, + { + "pr": "27150", + "title": "i18n: Language update from LingoHub 🤖 on 2022-10-31Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "dougfabris" + ] + }, + { + "pr": "26936", + "title": "Chore: Convert client/views/directory/hooks to ts", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "web-flow", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "26937", + "title": "Chore: Convert client/views/directory/RoomTags to ts", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27096", + "title": "[FIX] UserCard not opening inside Threads", + "userLogin": "dougfabris", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27165", + "title": "[FIX] Gap between message content and message header when there's no text.", + "userLogin": "gabriellsh", + "description": "Before:\r\n![image](https://user-images.githubusercontent.com/40830821/199314585-f09920bd-efea-4767-824a-783aca2a229a.png)\r\n![image](https://user-images.githubusercontent.com/40830821/199320275-cd32a96c-36a2-4c5b-ac3c-0db6aa57fdf7.png)\r\n\r\nAfter:\r\n![image](https://user-images.githubusercontent.com/40830821/199314648-b6b48512-b8c0-4c11-81bc-d6b97700bf7a.png)\r\n![image](https://user-images.githubusercontent.com/40830821/199320172-c6f986b8-29cd-4b2a-95e6-ffe9d51a8eaa.png)\r\n\r\nAdditionaly removed a component that was being rendered inside itself, causing spacing issues.", + "milestone": "5.4.0", + "contributors": [ + "gabriellsh", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "26894", + "title": "Chore: docs grammar fix", + "userLogin": "tusharxoxoxo", + "contributors": [ + "tusharxoxoxo" + ] + }, + { + "pr": "26968", + "title": "[FIX] Removed mobile requirement for showing real name", + "userLogin": "TedsCabin", + "description": "Removed the mobile requirement for allowing real names to be used in message headers.", + "contributors": [ + "TedsCabin", + "web-flow" + ] + }, + { + "pr": "24440", + "title": "Chore: Cursor pointer to all the action buttons", + "userLogin": "sidmohanty11", + "description": "https://user-images.githubusercontent.com/73601258/152863890-88035cbb-ba14-45c4-92ca-22ab4f566281.mp4", + "milestone": "5.4.0", + "contributors": [ + "sidmohanty11", + "dougfabris" + ] + }, + { + "pr": "27109", + "title": "Chore: Bump actions/upload-artifact from 2 to 3", + "userLogin": "rettinghaus", + "description": "Bump actions/upload-artifact from 2 to 3 (no changes in behavior expected)", + "contributors": [ + "rettinghaus", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27144", + "title": "Chore: Enable PR Title Checker for forks", + "userLogin": "tassoevan", + "contributors": [ + "tassoevan" + ] + }, + { + "pr": "26915", + "title": "Chore: Converting game center to typescript", + "userLogin": "AllanPazRibeiro", + "contributors": [ + "AllanPazRibeiro", + "ggazzo", + "web-flow" + ] + }, + { + "pr": "27127", + "title": "i18n: Language update from LingoHub 🤖 on 2022-10-24Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "yash-rajpal", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27106", + "title": "Chore: Add info log to remove all rooms method", + "userLogin": "KevLehman", + "milestone": "5.4.0", + "contributors": [ + "KevLehman", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26303", + "title": "[IMPROVE] Quotes on E2EE Messages", + "userLogin": "yash-rajpal", + "description": "This PR provides basic quoting to E2EE messages, it doesn't support multiple chaining of quotes messages.\r\n\r\n\"Screenshot", + "contributors": [ + "yash-rajpal", + "web-flow", + "gabriellsh", + "kodiakhq[bot]" + ] + }, + { + "pr": "26866", + "title": "[NEW] REST API endpoint `/v1/rooms.delete`", + "userLogin": "felipe-rod123", + "milestone": "5.4.0", + "contributors": [ + "felipe-rod123", + "web-flow", + "ggazzo", + "sampaiodiego" + ] + }, + { + "pr": "27060", + "title": "[FIX] Room Avatar being deleted after upload.", + "userLogin": "gabriellsh", + "description": "Remove avatar before updating it. S3 already overwrites the old image, but since this part of the code is shared among many other File Storage providers, we need to make this deletion before the upload.", + "milestone": "5.4.0", + "contributors": [ + "gabriellsh", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27061", + "title": "Chore: Apps/Marketplace code organization", + "userLogin": "dougfabris", + "milestone": "5.4.0", + "contributors": [ + "dougfabris", + "rique223", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27162", + "title": "Merge master into develop & Set version to 5.4.0-develop", + "userLogin": "ggazzo", + "contributors": [ + "ggazzo", + "web-flow" + ] + } + ] + }, + "5.4.0-rc.1": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27281", + "title": "Chore: Remove role requirement to use change streams", + "userLogin": "sampaiodiego", + "description": "We used to require the `clusterMonitor` role to be able to use Change Streams because we performed a `serverStatus` command, to be able to check if the requirements for change streams are met (like using wired tiger for example). But since our minimum MongoDB supported version is now 4.2, and MMAPv1 [was removed on this version](https://www.mongodb.com/docs/v4.2/core/storage-engines/), there is no need to check that.\r\n\r\nThe new approach is just try to use change streams, if it fails for any reason, fallback to oplog.\r\n\r\nIf oplog fails as well, we're now halting the process, since it wasn't able to establish a connection for reading real time data, something that is crucial for the application. An additional check was added to make sure `$MONGO_OPLOG_URL` is pointing to the `local` database.", + "milestone": "5.4.0", + "contributors": [ + "sampaiodiego", + "web-flow" + ] + }, + { + "pr": "27344", + "title": "Regression: Remove actions from VideoConf Message Block", + "userLogin": "dougfabris", + "contributors": [ + "gabriellsh", + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "26717", + "title": "Chore: Fix typo in pa-in.js", + "userLogin": "eltociear", + "contributors": [ + "eltociear", + "web-flow", + "debdutdeb", + "ggazzo", + "kodiakhq[bot]" + ] + }, + { + "pr": "27345", + "title": "Regression: Team name validation on Create Team Modal", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + } + ] + }, + "5.4.0-rc.2": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27391", + "title": "[FIX] Thread messages being included in the room history even though they are not displayed", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27386", + "title": "Chore: Update dark theme tokens", + "userLogin": "juliajforesti", + "description": "Update dark theme tokens: \r\n- surface-tint \r\n- button-background-secondary-disabled \r\n- button-background-secondary-danger-disabled\r\n- all status-background\r\n- all status-font", + "contributors": [ + "juliajforesti", + "dougfabris" + ] + }, + { + "pr": "26858", + "title": "[FIX] `channels.convertToTeam` endpoint doesn't work when only the `channelName` param is provided", + "userLogin": "matheusbsilva137", + "description": "- Fix the `channels.convertToTeam` endpoint not working when the `channelName` is sent as parameter.", + "contributors": [ + "matheusbsilva137", + "web-flow", + "sampaiodiego" + ] + }, + { + "pr": "27363", + "title": "Chore: Update badge tokens", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti" + ] + }, + { + "pr": "27382", + "title": "Regression: VideoConf default info modal not showing meeting URL as a link", + "userLogin": "pierre-lehnen-rc", + "description": "Before:\r\n![image](https://user-images.githubusercontent.com/55164754/204304308-87f6e6d3-8411-4974-8628-d81fd9aa07e5.png)\r\n\r\n\r\nAfter:\r\n![image](https://user-images.githubusercontent.com/55164754/204303619-6bc7b014-7b11-40a5-a1de-1530e76fff8b.png)", + "milestone": "5.4.0", + "contributors": [ + "pierre-lehnen-rc", + "web-flow" + ] + }, + { + "pr": "27375", + "title": "i18n: Language update from LingoHub 🤖 on 2022-11-28Z", + "userLogin": "lingohub[bot]", + "contributors": [ + null, + "dougfabris" + ] + }, + { + "pr": "27365", + "title": "Regression: Update VideoConf components colors", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris" + ] + } + ] + }, + "5.4.0-rc.3": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27410", + "title": "i18n: Language update from LingoHub 🤖 on 2022-11-29Z", + "userLogin": "lingohub[bot]", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27369", + "title": "Regression: Quoting Issue", + "userLogin": "henit-chobisa", + "milestone": "5.4.0", + "contributors": [ + "henit-chobisa", + "yash-rajpal", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27402", + "title": "Regression: Update VideoConfListItem Color Tokens", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27384", + "title": "Regression: Old threads not opening", + "userLogin": "yash-rajpal", + "milestone": "5.4.0", + "contributors": [ + "yash-rajpal", + "web-flow", + "kodiakhq[bot]" + ] + } + ] + }, + "5.4.0-rc.4": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27408", + "title": "Chore: Update tokens", + "userLogin": "juliajforesti", + "description": "Add/update tokens on light and dark palette:\r\n- update stroke-extra-light color\r\n- add status-warning-2\r\n- add status-service-3\r\n- add font-pure-white\r\n- add font-pure-black", + "contributors": [ + "juliajforesti", + "web-flow", + "ggazzo" + ] + }, + { + "pr": "27411", + "title": "Regression: Login and Registration UI Tweaks", + "userLogin": "dougfabris", + "milestone": "5.4.0", + "contributors": [ + "dougfabris" + ] + }, + { + "pr": "27406", + "title": "Regression: Fix issues with ContactHistoryItem", + "userLogin": "MartinSchoeler", + "milestone": "5.4.0", + "contributors": [ + "MartinSchoeler", + "kodiakhq[bot]", + "web-flow" + ] + } + ] + }, + "5.4.0-rc.5": { + "node_version": "14.19.3", + "npm_version": "6.14.17", + "mongo_versions": [ + "4.2", + "4.4", + "5.0" + ], + "pull_requests": [ + { + "pr": "27435", + "title": "[FIX] Fix watch db being started on Micro Services env", + "userLogin": "ggazzo", + "milestone": "5.4.0", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "26951", + "title": "[FIX] Unable to set idleTimeLimit for users", + "userLogin": "debdutdeb", + "milestone": "5.4.0", + "contributors": [ + "debdutdeb", + "yash-rajpal" + ] + }, + { + "pr": "27421", + "title": "Regression: Elevation and components z-index fixes", + "userLogin": "dougfabris", + "contributors": [ + "dougfabris", + "ggazzo" + ] + }, + { + "pr": "27433", + "title": "Chore: Update Apps-Engine to latest", + "userLogin": "d-gubert", + "milestone": "5.4.0", + "contributors": [ + "d-gubert" + ] + }, + { + "pr": "27359", + "title": "[FIX] Threads replied message not clickable on new message template", + "userLogin": "filipemarins", + "description": "Add the link to the parent message on the `ThreadMessagePreview` component;\r\nAdd `message ignored` status to the parent message too;\r\nAlso, allow clicking the message when is ignored status.", + "contributors": [ + "filipemarins", + "guijun13", + "kodiakhq[bot]", + "web-flow" + ] + }, + { + "pr": "27387", + "title": "[FIX] Livechat: Allow resolving external image and media blocks ", + "userLogin": "cauefcr", + "description": "Allow external urls to be viewed on livechat.", + "milestone": "5.5.0", + "contributors": [ + "cauefcr", + "web-flow", + "kodiakhq[bot]" + ] + }, + { + "pr": "27414", + "title": "Chore: bumping apps engine version", + "userLogin": "AllanPazRibeiro", + "milestone": "5.4.0", + "contributors": [ + "AllanPazRibeiro", + "d-gubert", + "web-flow" + ] + }, + { + "pr": "27420", + "title": "Regression: message-box-editing-color", + "userLogin": "juliajforesti", + "contributors": [ + "juliajforesti" + ] + }, + { + "pr": "27422", + "title": "Regression: Admin menu apps option not working", + "userLogin": "rique223", + "description": "Solved a bug caused by the RC production build steps breaking the flow router triggersEnter event that did some rerouting for marketplace. Removed the cited function from the routes.tsx file, and now the rerouting is done directly inside the AppsRoute file.\r\nDemo gif:\r\n![apps_rerouting_issue](https://user-images.githubusercontent.com/43561537/205097014-644be3fd-913e-48d6-8e2b-c082bd8f80cf.gif)", + "milestone": "5.4.0", + "contributors": [ + "rique223" + ] + }, + { + "pr": "27416", + "title": "[FIX] Fix Piwik and add extra setting to allow workarounds", + "userLogin": "ggazzo", + "milestone": "5.4.0", + "contributors": [ + "ggazzo" + ] + }, + { + "pr": "27368", + "title": "Regression: Bad words Filtering not working on new Message Parser", + "userLogin": "xareyli", + "description": "Was\r\n![forGH](https://user-images.githubusercontent.com/118266546/204087809-fca6152b-63db-4873-88b8-d86aeb324531.png)\r\n\r\nNow\r\n![forGH2](https://user-images.githubusercontent.com/118266546/204087822-e3273127-a4f0-4a45-a73e-910eb48c9b6f.png)", + "milestone": "5.4.0", + "contributors": [ + "xareyli", + "kodiakhq[bot]", + "web-flow", + "ggazzo" + ] + } + ] } } diff --git a/.github/no-js-action-config.json b/.github/no-js-action-config.json deleted file mode 100644 index 45e82790b82e8..0000000000000 --- a/.github/no-js-action-config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "added": { - "ignore": [ - "packages/node-poplib/**/*", - "packages/accounts-linkedin/**/*", - "packages/linkedin-oauth/**/*", - "tests/cypress/integration/08-resolutions.spec.js", - "**/.eslintrc.js", - "packages/eslint-config/**", - "**/babel.config.js" - ] - } -} diff --git a/.github/workflows/auto-label.yml b/.github/workflows/auto-label.yml deleted file mode 100644 index 09b1dfb917360..0000000000000 --- a/.github/workflows/auto-label.yml +++ /dev/null @@ -1,12 +0,0 @@ - name: 'Auto label QA' - on: - pull_request: - types: [opened, synchronize, labeled, unlabeled] - jobs: - build: - runs-on: ubuntu-latest - if: github.event_name == 'DEACTIVATED' - steps: - - uses: ggazzo/gh-action-auto-label@beta-5 - with: - GITHUB_TOKEN: ${{ secrets.RC_AUTOLABEL_TOKEN }} diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml deleted file mode 100644 index d01551c08ee93..0000000000000 --- a/.github/workflows/build_and_test.yml +++ /dev/null @@ -1,767 +0,0 @@ -name: Build and Test - -on: - release: - types: [published] - pull_request: - branches: '**' - push: - branches: - - develop - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - CI: true - MONGO_URL: mongodb://localhost:27017/rocketchat?replicaSet=rs0&directConnection=true - MONGO_OPLOG_URL: mongodb://mongodb:27017/local?replicaSet=rs0&directConnection=true - TOOL_NODE_FLAGS: --max_old_space_size=8192 --optimize_for_size --gc-interval=100 - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - -jobs: - release-versions: - runs-on: ubuntu-latest - outputs: - release: ${{ steps.by-tag.outputs.release }} - latest-release: ${{ steps.latest.outputs.latest-release }} - docker-tag: ${{ steps.docker.outputs.docker-tag }} - gh-docker-tag: ${{ steps.docker.outputs.gh-docker-tag }} - steps: - - id: by-tag - run: | - if echo "$GITHUB_REF_NAME" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' ; then - RELEASE="latest" - elif echo "$GITHUB_REF_NAME" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$' ; then - RELEASE="release-candidate" - fi - echo "RELEASE: ${RELEASE}" - echo "release=${RELEASE}" >> $GITHUB_OUTPUT - - id: latest - run: | - LATEST_RELEASE="$( - git -c 'versionsort.suffix=-' ls-remote -t --exit-code --refs --sort=-v:refname "https://github.com/$GITHUB_REPOSITORY" '*' | - awk -F/ '$NF !~ /rc|beta/ { print $NF; exit }' - )" - echo "LATEST_RELEASE: ${LATEST_RELEASE}" - echo "latest-release=${LATEST_RELEASE}" >> $GITHUB_OUTPUT - - id: docker - run: | - if [[ '${{ github.event_name }}' == 'pull_request' ]]; then - DOCKER_TAG="pr-${{ github.event.number }}" - else - DOCKER_TAG="gh-${{ github.run_id }}" - fi - echo "DOCKER_TAG: ${DOCKER_TAG}" - echo "gh-docker-tag=${DOCKER_TAG}" >> $GITHUB_OUTPUT - build: - runs-on: ubuntu-20.04 - - steps: - - name: Github Info - run: | - echo "GITHUB_ACTION: $GITHUB_ACTION" - echo "GITHUB_ACTOR: $GITHUB_ACTOR" - echo "GITHUB_REF: $GITHUB_REF" - echo "GITHUB_HEAD_REF: $GITHUB_HEAD_REF" - echo "GITHUB_BASE_REF: $GITHUB_BASE_REF" - echo "github.event_name: ${{ github.event_name }}" - cat $GITHUB_EVENT_PATH - - name: Set Swap Space - uses: pierotofy/set-swap-space@master - with: - swap-size-gb: 4 - - - uses: actions/checkout@v3 - - - name: Use Node.js 14.19.3 - uses: actions/setup-node@v3 - with: - node-version: '14.19.3' - cache: 'yarn' - - - name: Free disk space - run: | - sudo apt clean - docker rmi $(docker image ls -aq) - df -h - - name: Cache meteor local - uses: actions/cache@v2 - with: - path: ./apps/meteor/.meteor/local - key: meteor-local-cache-${{ runner.OS }}-${{ hashFiles('apps/meteor/.meteor/versions') }} - restore-keys: | - meteor-local-cache-${{ runner.os }}- - - name: Cache meteor - uses: actions/cache@v2 - with: - path: ~/.meteor - key: meteor-cache-${{ runner.OS }}-${{ hashFiles('apps/meteor/.meteor/release') }} - restore-keys: | - meteor-cache-${{ runner.os }}- - - name: Install Meteor - run: | - # Restore bin from cache - set +e - METEOR_SYMLINK_TARGET=$(readlink ~/.meteor/meteor) - METEOR_TOOL_DIRECTORY=$(dirname "$METEOR_SYMLINK_TARGET") - set -e - LAUNCHER=$HOME/.meteor/$METEOR_TOOL_DIRECTORY/scripts/admin/launch-meteor - if [ -e $LAUNCHER ] - then - echo "Cached Meteor bin found, restoring it" - sudo cp "$LAUNCHER" "/usr/local/bin/meteor" - else - echo "No cached Meteor bin found." - fi - # only install meteor if bin isn't found - command -v meteor >/dev/null 2>&1 || curl https://install.meteor.com | sed s/--progress-bar/-sL/g | /bin/sh - - name: Versions - run: | - npm --versions - yarn -v - node -v - meteor --version - meteor npm --versions - meteor node -v - git version - - name: yarn install - run: | - git config --global url."https://".insteadOf git:// - yarn - - - name: TurboRepo local server - uses: felixmosh/turborepo-gh-artifacts@v1 - with: - repo-token: ${{ secrets.RC_TURBO_GH_TOKEN }} - server-token: ${{ secrets.TURBO_SERVER_TOKEN }} - - - name: Lint - run: yarn lint --api="http://127.0.0.1:9080" --token="${{ secrets.TURBO_SERVER_TOKEN }}" --team='rc' - - - name: Translation check - run: yarn turbo run translation-check --api="http://127.0.0.1:9080" --token="${{ secrets.TURBO_SERVER_TOKEN }}" --team='rc' - - # - name: TS typecheck - # run: yarn turbo run typecheck --api="http://127.0.0.1:9080" --token="${{ secrets.TURBO_SERVER_TOKEN }}" --team='rc' - - - name: Reset Meteor - if: startsWith(github.ref, 'refs/tags/') == 'true' || github.ref == 'refs/heads/develop' - run: | - cd ./apps/meteor - meteor reset - - name: Build Rocket.Chat From Pull Request - if: startsWith(github.ref, 'refs/pull/') == true - env: - METEOR_PROFILE: 1000 - run: yarn build:ci --api="http://127.0.0.1:9080" -- --debug --directory dist - - - name: Build Rocket.Chat - if: startsWith(github.ref, 'refs/pull/') != true - run: yarn build:ci --api="http://127.0.0.1:9080" -- --directory dist - - - name: Prepare build - run: | - cd apps/meteor/dist - tar czf /tmp/Rocket.Chat.tar.gz bundle - - name: Store build - uses: actions/upload-artifact@v2 - with: - name: build - path: /tmp/Rocket.Chat.tar.gz - - build-docker-preview: - runs-on: ubuntu-20.04 - needs: [build, release-versions] - if: github.event_name == 'DEACTIVATED' - # if: github.event_name == 'release' || github.ref == 'refs/heads/develop' - steps: - - uses: actions/checkout@v3 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'yarn' - - - name: Restore build - uses: actions/download-artifact@v2 - with: - name: build - path: /tmp/build - - - name: Unpack build - run: | - cd /tmp/build - tar xzf Rocket.Chat.tar.gz - rm Rocket.Chat.tar.gz - - name: Build Docker image - id: build-docker-image-preview - uses: ./.github/actions/build-docker-image - with: - root-dir: /tmp/build - docker-tag: ${{ needs.release-versions.outputs.gh-docker-tag }} - release: preview - username: ${{ secrets.CR_USER }} - password: ${{ secrets.CR_PAT }} - - test: - runs-on: ubuntu-20.04 - needs: [build, release-versions] - - strategy: - matrix: - node-version: ['14.19.3'] - mongodb-version: ['4.2', '4.4', '5.0'] - - steps: - - name: Launch MongoDB - uses: supercharge/mongodb-github-action@1.7.0 - with: - mongodb-version: ${{ matrix.mongodb-version }} - mongodb-replica-set: rs0 - - - uses: actions/checkout@v3 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'yarn' - - - name: yarn install - run: | - git config --global url."https://".insteadOf git:// - yarn - - - name: TurboRepo local server - uses: felixmosh/turborepo-gh-artifacts@v1 - with: - repo-token: ${{ secrets.RC_TURBO_GH_TOKEN }} - server-token: ${{ secrets.TURBO_SERVER_TOKEN }} - - - name: Unit Test - run: yarn testunit --api="http://127.0.0.1:9080" --token="${{ secrets.TURBO_SERVER_TOKEN }}" --team='rc' - - - name: Restore build - uses: actions/download-artifact@v2 - with: - name: build - path: /tmp/build - - - name: Unpack build - run: | - cd /tmp/build - tar xzf Rocket.Chat.tar.gz - rm Rocket.Chat.tar.gz - - name: Start containers - env: - MONGO_URL: 'mongodb://host.docker.internal:27017/rocketchat?replicaSet=rs0&directConnection=true' - MONGO_OPLOG_URL: 'mongodb://mongodb:27017/local?replicaSet=rs0&directConnection=true' - run: | - export LOWERCASE_REPOSITORY=$(echo "${{ github.repository_owner }}" | tr "[:upper:]" "[:lower:]") - # test alpine image on mongo 5.0 (no special reason to be mongo 5.0 but we need to test alpine at least once) - if [[ '${{ matrix.mongodb-version }}' = '5.0' ]]; then - export RC_DOCKERFILE="${{ github.workspace }}/apps/meteor/.docker/Dockerfile.alpine" - export RC_DOCKER_TAG="${{ needs.release-versions.outputs.gh-docker-tag }}.alpine" - else - export RC_DOCKERFILE="${{ github.workspace }}/apps/meteor/.docker/Dockerfile" - export RC_DOCKER_TAG="${{ needs.release-versions.outputs.gh-docker-tag }}.official" - fi; - docker compose -f docker-compose-ci.yml up -d --build rocketchat - sleep 10 - until echo "$(docker compose -f docker-compose-ci.yml logs rocketchat)" | grep -q "SERVER RUNNING"; do - echo "Waiting Rocket.Chat to start up" - ((c++)) && ((c==10)) && docker compose -f docker-compose-ci.yml logs rocketchat && exit 1 - sleep 10 - done - - name: Login to GitHub Container Registry - if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop' - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ secrets.CR_USER }} - password: ${{ secrets.CR_PAT }} - - - name: Publish Docker images to GitHub Container Registry - if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop' - run: | - export LOWERCASE_REPOSITORY=$(echo "${{ github.repository_owner }}" | tr "[:upper:]" "[:lower:]") - # test alpine image on mongo 5.0 (no special reason to be mongo 5.0 but we need to test alpine at least once) - if [[ '${{ matrix.mongodb-version }}' = '5.0' ]]; then - export RC_DOCKER_TAG="${{ needs.release-versions.outputs.gh-docker-tag }}.alpine" - else - export RC_DOCKER_TAG="${{ needs.release-versions.outputs.gh-docker-tag }}.official" - fi; - docker compose -f docker-compose-ci.yml push rocketchat - if [[ '${{ matrix.mongodb-version }}' = '4.4' ]]; then - IMAGE_NAME_BASE="ghcr.io/${LOWERCASE_REPOSITORY}/rocket.chat:${{ needs.release-versions.outputs.gh-docker-tag }}" - echo "Push Docker image: ${IMAGE_NAME_BASE}" - docker tag ${IMAGE_NAME_BASE}.official $IMAGE_NAME_BASE - docker push $IMAGE_NAME_BASE - fi; - - name: E2E Test API - run: | - docker ps - docker compose -f docker-compose-ci.yml logs rocketchat --tail=50 - cd ./apps/meteor - for i in $(seq 1 5); do - npm run testapi && s=0 && break || s=$? - docker compose -f ../../docker-compose-ci.yml logs rocketchat --tail=100 - docker compose -f ../../docker-compose-ci.yml stop rocketchat - docker exec mongodb mongo rocketchat --eval 'db.dropDatabase()' - NOW=$(date "+%Y-%m-%dT%H:%M:%SZ") - docker compose -f ../../docker-compose-ci.yml start rocketchat - until echo "$(docker compose -f ../../docker-compose-ci.yml logs rocketchat --since $NOW)" | grep -q "SERVER RUNNING"; do - echo "Waiting Rocket.Chat to start up" - ((c++)) && ((c==10)) && exit 1 - sleep 10 - done; - done; - exit $s - - name: Cache Playwright binaries - uses: actions/cache@v3 - id: cache-playwright - with: - path: | - ~/.cache/ms-playwright - # This is the version of Playwright that we are using, if you are willing to upgrade, you should update this. - key: playwright-1.23.1 - - - name: Install Playwright - if: steps.cache-playwright.outputs.cache-hit != 'true' - run: | - cd ./apps/meteor - npx playwright install --with-deps - - name: E2E Test UI - run: | - docker ps - docker compose -f docker-compose-ci.yml logs rocketchat --tail=50 - docker exec mongodb mongo rocketchat --eval 'db.dropDatabase()' - NOW=$(date "+%Y-%m-%dT%H:%M:%SZ") - docker compose -f docker-compose-ci.yml restart rocketchat - until echo "$(docker compose -f docker-compose-ci.yml logs rocketchat --since $NOW)" | grep -q "SERVER RUNNING"; do - echo "Waiting Rocket.Chat to start up" - ((c++)) && ((c==10)) && exit 1 - sleep 10 - done - cd ./apps/meteor - yarn test:e2e - - name: Store playwright test trace - uses: actions/upload-artifact@v2 - if: always() - with: - name: playwright-test-trace - path: ./apps/meteor/tests/e2e/.playwright* - - test-ee: - runs-on: ubuntu-20.04 - needs: [build, release-versions] - - strategy: - matrix: - node-version: ['14.19.3'] - mongodb-version-ee: ['4.4'] - - steps: - - name: Launch MongoDB - uses: supercharge/mongodb-github-action@1.7.0 - with: - mongodb-version: ${{ matrix.mongodb-version-ee }} - mongodb-replica-set: rs0 - - - uses: actions/checkout@v3 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'yarn' - - - name: TurboRepo local server - uses: felixmosh/turborepo-gh-artifacts@v1 - with: - repo-token: ${{ secrets.RC_TURBO_GH_TOKEN }} - server-token: ${{ secrets.TURBO_SERVER_TOKEN }} - - - name: yarn install - run: | - git config --global url."https://".insteadOf git:// - yarn - - - name: Unit Test - run: yarn testunit --api="http://127.0.0.1:9080" --token="${{ secrets.TURBO_SERVER_TOKEN }}" --team='rc' - - - name: Restore build - uses: actions/download-artifact@v2 - with: - name: build - path: /tmp/build - - - name: Unpack build - run: | - cd /tmp/build - tar xzf Rocket.Chat.tar.gz - rm Rocket.Chat.tar.gz - - name: Start containers - env: - MONGO_URL: 'mongodb://host.docker.internal:27017/rocketchat?replicaSet=rs0&directConnection=true' - RC_DOCKERFILE: '${{ github.workspace }}/apps/meteor/.docker/Dockerfile' - RC_DOCKER_TAG: '${{ needs.release-versions.outputs.gh-docker-tag }}.official' - DOCKER_TAG: ${{ needs.release-versions.outputs.gh-docker-tag }} - TRANSPORTER: nats://nats:4222 - ENTERPRISE_LICENSE: Z2Dg0RC3kyxjuklSE6qfqyvD2xSD+oTYcS9OesJG0523r7rSPjv59LTQqPcp5E61qQYM3MOKoW3mDrurw4h78nVbsfrF2DoJZeNjRFQfIbgwcdPwtmnqPpDvAslszHY16VzM7O7EYqAqp/9mlnRzs1iJY+W3w1r6HWBlVMb9u41bl5HBSpX6Nxw8YxL4mizwOpjxewQbPQvNTLJNAW6w0nCzF5A3CKBhD9fziadedVMLOuXBuR8kIl8zbIAfqpHmL8SvakvQAbZEjWWQshmH+C9CKA5PppkmA8Q1DNWQoVtHSiYDK8RRjAEx+0oGflklzFyhJFDvD+ohZduNtNCgrJmxP5VFrVrLSK4BXgTSwwnaSKa2N+Qx0CmuRfu7nCPc1Cf6h6+k2TXvzkE4Z0ZJnDV1khu611glAr99bHdwF+bMX3XZI66bS8KqnHEukCt5xei25iKJ2xrfmGuiAkAuKHKzBmTEmXM0pGhkfDhA9jhxG3Atoj1A5y8vdrs88voF+UuNFZ6k9sKtdvrWIWClnkatPE+41ggbzCsOhFz07BvRWaEtw2Kenipl4Vtag4qmFpUaUfsuouH99M3gDlysDZO3x5aH8yfzvFeL5WDMvsmdEHNLpHl89WsPCONvx0JjRSdwcCA1NrRuVy1Ncu0S0bRByn7HZqoY9u6HPkXKBxQ= - run: | - export LOWERCASE_REPOSITORY=$(echo "${{ github.repository_owner }}" | tr "[:upper:]" "[:lower:]") - docker compose -f docker-compose-ci.yml up -d --build - sleep 10 - until echo "$(docker compose -f docker-compose-ci.yml logs ddp-streamer-service)" | grep -q "NetworkBroker started successfully"; do - echo "Waiting 'ddp-streamer' to start up" - ((c++)) && ((c==10)) && docker compose -f docker-compose-ci.yml logs ddp-streamer-service && exit 1 - sleep 10 - done - until echo "$(docker compose -f docker-compose-ci.yml logs rocketchat)" | grep -q "SERVER RUNNING"; do - echo "Waiting Rocket.Chat to start up" - ((c++)) && ((c==10)) && docker compose -f docker-compose-ci.yml logs rocketchat && exit 1 - sleep 10 - done - - name: Login to GitHub Container Registry - if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop' - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ secrets.CR_USER }} - password: ${{ secrets.CR_PAT }} - - - name: Publish Docker images to GitHub Container Registry - if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop' - env: - DOCKER_TAG: ${{ needs.release-versions.outputs.gh-docker-tag }} - run: | - export LOWERCASE_REPOSITORY=$(echo "${{ github.repository_owner }}" | tr "[:upper:]" "[:lower:]") - docker compose -f docker-compose-ci.yml push \ - authorization-service \ - account-service \ - ddp-streamer-service \ - presence-service \ - stream-hub-service - - name: E2E Test API - run: | - docker ps - docker compose -f docker-compose-ci.yml logs --tail=50 - cd ./apps/meteor - for i in $(seq 1 5); do - IS_EE=true npm run testapi && s=0 && break || s=$?; - docker compose -f ../../docker-compose-ci.yml logs --tail=100 - docker compose -f ../../docker-compose-ci.yml stop - docker exec mongodb mongo rocketchat --eval 'db.dropDatabase()' - NOW=$(date "+%Y-%m-%dT%H:%M:%SZ") - docker compose -f ../../docker-compose-ci.yml start - until echo "$(docker compose -f ../../docker-compose-ci.yml logs rocketchat --since $NOW)" | grep -q "SERVER RUNNING"; do - echo "Waiting Rocket.Chat to start up" - ((c++)) && ((c==10)) && exit 1 - sleep 10 - done; - done; - exit $s - - name: Cache Playwright binaries - uses: actions/cache@v3 - id: cache-playwright - with: - path: | - ~/.cache/ms-playwright - # This is the version of Playwright that we are using, if you are willing to upgrade, you should update this. - key: playwright-1.23.1 - - - name: Install Playwright - run: | - cd ./apps/meteor - npx playwright install --with-deps - - name: E2E Test UI - run: | - docker ps - docker compose -f docker-compose-ci.yml logs rocketchat --tail=50 - docker exec mongodb mongo rocketchat --eval 'db.dropDatabase()' - NOW=$(date "+%Y-%m-%dT%H:%M:%SZ") - docker compose -f docker-compose-ci.yml restart - until echo "$(docker compose -f docker-compose-ci.yml logs rocketchat --since $NOW)" | grep -q "SERVER RUNNING"; do - echo "Waiting Rocket.Chat to start up" - ((c++)) && ((c==10)) && exit 1 - sleep 10 - done - cd ./apps/meteor - E2E_COVERAGE=true IS_EE=true yarn test:e2e - - name: Store playwright test trace - uses: actions/upload-artifact@v2 - if: always() - with: - name: e2e-ee-testtrace - path: ./apps/meteor/tests/e2e/.playwright* - - - name: Extract e2e:ee:coverage - run: | - cd ./apps/meteor - yarn test:e2e:nyc - - uses: codecov/codecov-action@v3 - with: - directory: ./apps/meteor - flags: e2e - verbose: true - - - name: Store e2e-ee-coverage - uses: actions/upload-artifact@v2 - with: - name: e2e-ee-coverage - path: ./apps/meteor/coverage* - - deploy: - runs-on: ubuntu-20.04 - if: github.event_name == 'DEACTIVATED' - # if: github.event_name == 'release' || github.ref == 'refs/heads/develop' - needs: [test, release-versions] - - steps: - - uses: actions/checkout@v3 - - - name: Restore build - uses: actions/download-artifact@v2 - with: - name: build - path: /tmp/build - - - name: Publish assets - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: 'us-east-1' - GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }} - REDHAT_REGISTRY_PID: ${{ secrets.REDHAT_REGISTRY_PID }} - REDHAT_REGISTRY_KEY: ${{ secrets.REDHAT_REGISTRY_KEY }} - UPDATE_TOKEN: ${{ secrets.UPDATE_TOKEN }} - run: | - REPO_VERSION=$(node -p "require('./package.json').version") - if [[ '${{ github.event_name }}' = 'release' ]]; then - GIT_TAG="${GITHUB_REF#*tags/}" - GIT_BRANCH="" - ARTIFACT_NAME="${REPO_VERSION}" - RC_VERSION=$GIT_TAG - if [[ '${{ needs.release-versions.outputs.release }}' = 'release-candidate' ]]; then - SNAP_CHANNEL=candidate - RC_RELEASE=candidate - elif [[ '${{ needs.release-versions.outputs.release }}' = 'latest' ]]; then - SNAP_CHANNEL=stable - RC_RELEASE=stable - fi - else - GIT_TAG="" - GIT_BRANCH="${GITHUB_REF#*heads/}" - ARTIFACT_NAME="${REPO_VERSION}.$GITHUB_SHA" - RC_VERSION="${REPO_VERSION}" - SNAP_CHANNEL=edge - RC_RELEASE=develop - fi; - ROCKET_DEPLOY_DIR="/tmp/deploy" - FILENAME="$ROCKET_DEPLOY_DIR/rocket.chat-$ARTIFACT_NAME.tgz"; - aws s3 cp s3://rocketchat/sign.key.gpg .github/sign.key.gpg - mkdir -p $ROCKET_DEPLOY_DIR - cp .github/sign.key.gpg /tmp - gpg --yes --batch --passphrase=$GPG_PASSWORD /tmp/sign.key.gpg - gpg --allow-secret-key-import --import /tmp/sign.key - rm /tmp/sign.key - ln -s /tmp/build/Rocket.Chat.tar.gz "$FILENAME" - gpg --armor --detach-sign "$FILENAME" - aws s3 cp $ROCKET_DEPLOY_DIR/ s3://download.rocket.chat/build/ --recursive - curl -H "Content-Type: application/json" -H "X-Update-Token: $UPDATE_TOKEN" -d \ - "{\"nodeVersion\": \"14.19.3\", \"compatibleMongoVersions\": [\"4.2\", \"4.4\", \"5.0\"], \"commit\": \"$GITHUB_SHA\", \"tag\": \"$RC_VERSION\", \"branch\": \"$GIT_BRANCH\", \"artifactName\": \"$ARTIFACT_NAME\", \"releaseType\": \"$RC_RELEASE\"}" \ - https://releases.rocket.chat/update - # Makes build fail if the release isn't there - curl --fail https://releases.rocket.chat/$RC_VERSION/info - if [[ $GIT_TAG ]]; then - curl -X POST \ - https://connect.redhat.com/api/v2/projects/$REDHAT_REGISTRY_PID/build \ - -H "Authorization: Bearer $REDHAT_REGISTRY_KEY" \ - -H 'Cache-Control: no-cache' \ - -H 'Content-Type: application/json' \ - -d '{"tag":"'$GIT_TAG'"}' - fi - docker-image-publish: - runs-on: ubuntu-20.04 - needs: [deploy, build-docker-preview, release-versions] - - strategy: - matrix: - # this is currently a mix of variants and different images - release: ['official', 'preview', 'alpine'] - - env: - IMAGE_NAME: 'rocketchat/rocket.chat' - - steps: - - name: Login to DockerHub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PASS }} - - - name: Login to GitHub Container Registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ secrets.CR_USER }} - password: ${{ secrets.CR_PAT }} - - - name: Get Docker image name - id: gh-docker - run: | - LOWERCASE_REPOSITORY=$(echo "${{ github.repository_owner }}" | tr "[:upper:]" "[:lower:]") - GH_IMAGE_NAME="ghcr.io/${LOWERCASE_REPOSITORY}/rocket.chat:${{ needs.release-versions.outputs.gh-docker-tag }}.${{ matrix.release }}" - echo "GH_IMAGE_NAME: $GH_IMAGE_NAME" - echo "gh-image-name=${GH_IMAGE_NAME}" >> $GITHUB_OUTPUT - - name: Pull Docker image - run: docker pull ${{ steps.gh-docker.outputs.gh-image-name }} - - - name: Publish Docker image - run: | - if [[ '${{ matrix.release }}' = 'preview' ]]; then - IMAGE_NAME="${IMAGE_NAME}.preview" - fi; - # 'develop' or 'tag' - DOCKER_TAG=$GITHUB_REF_NAME - # append the variant name to docker tag - if [[ '${{ matrix.release }}' = 'alpine' ]]; then - DOCKER_TAG="${DOCKER_TAG}-${{ matrix.release }}" - fi; - echo "IMAGE_NAME: $IMAGE_NAME" - echo "DOCKER_TAG: $DOCKER_TAG" - # tag and push the specific tag version - docker tag ${{ steps.gh-docker.outputs.gh-image-name }} $IMAGE_NAME:$DOCKER_TAG - docker push $IMAGE_NAME:$DOCKER_TAG - if [[ $GITHUB_REF == refs/tags/* ]]; then - RELEASE="${{ needs.release-versions.outputs.release }}" - if [[ '${{ matrix.release }}' = 'alpine' ]]; then - RELEASE="${RELEASE}-${{ matrix.release }}" - fi; - echo "RELEASE: $RELEASE" - if [[ $RELEASE == 'latest' ]]; then - if [[ '${{ needs.release-versions.outputs.latest-release }}' == $GITHUB_REF_NAME ]]; then - docker tag ${{ steps.gh-docker.outputs.gh-image-name }} $IMAGE_NAME:$RELEASE - docker push $IMAGE_NAME:$RELEASE - fi - else - docker tag ${{ steps.gh-docker.outputs.gh-image-name }} $IMAGE_NAME:$RELEASE - docker push $IMAGE_NAME:$RELEASE - fi - fi - services-docker-image-publish: - runs-on: ubuntu-20.04 - needs: [deploy, release-versions] - - strategy: - matrix: - service: ['account', 'authorization', 'ddp-streamer', 'presence', 'stream-hub'] - - steps: - - name: Login to DockerHub - uses: docker/login-action@v2 - with: - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PASS }} - - - name: Login to GitHub Container Registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ secrets.CR_USER }} - password: ${{ secrets.CR_PAT }} - - - name: Get Docker image name - id: gh-docker - run: | - LOWERCASE_REPOSITORY=$(echo "${{ github.repository_owner }}" | tr "[:upper:]" "[:lower:]") - GH_IMAGE_NAME="ghcr.io/${LOWERCASE_REPOSITORY}/${{ matrix.service }}-service:${{ needs.release-versions.outputs.gh-docker-tag }}" - echo "GH_IMAGE_NAME: $GH_IMAGE_NAME" - echo "gh-image-name=${GH_IMAGE_NAME}" >> $GITHUB_OUTPUT - - name: Pull Docker image - run: docker pull ${{ steps.gh-docker.outputs.gh-image-name }} - - - name: Publish Docker images - run: | - DH_IMAGE_NAME="rocketchat/${{ matrix.service }}-service" - # 'develop' or 'tag' - DOCKER_TAG=$GITHUB_REF_NAME - echo "DH_IMAGE_NAME: $DH_IMAGE_NAME" - echo "DOCKER_TAG: $DOCKER_TAG" - # tag and push the specific tag version - docker tag ${{ steps.gh-docker.outputs.gh-image-name }} $DH_IMAGE_NAME:$DOCKER_TAG - docker push $DH_IMAGE_NAME:$DOCKER_TAG - if [[ $GITHUB_REF == refs/tags/* ]]; then - RELEASE="${{ needs.release-versions.outputs.release }}" - echo "RELEASE: $RELEASE" - if [[ $RELEASE == 'latest' ]]; then - if [[ '${{ needs.release-versions.outputs.latest-release }}' == $GITHUB_REF_NAME ]]; then - docker tag ${{ steps.gh-docker.outputs.gh-image-name }} $DH_IMAGE_NAME:$RELEASE - docker push $DH_IMAGE_NAME:$RELEASE - fi - else - docker tag ${{ steps.gh-docker.outputs.gh-image-name }} $DH_IMAGE_NAME:$RELEASE - docker push $DH_IMAGE_NAME:$RELEASE - fi - fi - - acc-ecr-push: - runs-on: ubuntu-latest - if: ${{ github.ref == 'refs/heads/develop' && github.event_name == 'push' }} - needs: test - - steps: - - uses: actions/checkout@v2 - - - name: Use Node.js 14.18.3 - uses: actions/setup-node@v2 - with: - node-version: "14.18.3" - - - name: Parse for branch - run: | - git_hash=$(git rev-parse --short "$GITHUB_SHA") - rocket_version=$(node -pe "require('./package.json').version") - echo "PR_TAG=v$rocket_version.$git_hash" >> $GITHUB_ENV - - name: Restore build - uses: actions/download-artifact@v1 - with: - name: build - path: /tmp/build - - - name: Unpack build - run: | - cd /tmp/build - tar xzf Rocket.Chat.tar.gz - rm Rocket.Chat.tar.gz - cp "${GITHUB_WORKSPACE}/apps/meteor/.docker/Dockerfile" . - ## Push to ACC:rocketchat - - name: Configure AWS credentials in ACC - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.ACC_ACCESS_KEY }} - aws-secret-access-key: ${{ secrets.ACC_SECRET_ACCESS_KEY }} - aws-region: us-east-1 - - - name: Login to Amazon ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@v1 - - - name: Build, tag, and push image to Amazon ECR in ACC - id: build-image-acc - env: - ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} - ECR_REPOSITORY: rocketchat - IMAGE_TAG: ${{ env.PR_TAG }} - - run: | - # Build a docker container and push it to ECR - cd /tmp/build - docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . - docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG - echo "name=ACC_IMAGE::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT - \ No newline at end of file diff --git a/.github/workflows/ci-code-check.yml b/.github/workflows/ci-code-check.yml new file mode 100644 index 0000000000000..fbfd8b6e0f048 --- /dev/null +++ b/.github/workflows/ci-code-check.yml @@ -0,0 +1,53 @@ +name: Code Checks + +on: + workflow_call: + inputs: + node-version: + required: true + type: string + +env: + TOOL_NODE_FLAGS: ${{ vars.TOOL_NODE_FLAGS }} + +jobs: + code-check: + runs-on: ubuntu-20.04 + + name: ${{ matrix.check == 'ts' && 'TypeScript' || 'Code Lint' }} + + strategy: + fail-fast: false + matrix: + check: ['ts', 'lint'] + + steps: + # - name: Set Swap Space + # uses: pierotofy/set-swap-space@master + # with: + # swap-size-gb: 4 + + - uses: actions/checkout@v3 + + - name: Setup NodeJS + uses: ./.github/actions/setup-node + with: + node-version: ${{ inputs.node-version }} + cache-modules: true + install: true + + # - name: Free disk space + # run: | + # sudo apt clean + # docker rmi $(docker image ls -aq) + # df -h + + - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + + - name: TS TypeCheck + if: matrix.check == 'ts' + run: yarn turbo run typecheck + + - name: Lint + if: matrix.check == 'lint' + run: yarn lint diff --git a/.github/workflows/ci-test-e2e.yml b/.github/workflows/ci-test-e2e.yml new file mode 100644 index 0000000000000..f7af24391d5cb --- /dev/null +++ b/.github/workflows/ci-test-e2e.yml @@ -0,0 +1,257 @@ +name: Tests E2E + +on: + workflow_call: + inputs: + node-version: + required: true + type: string + lowercase-repo: + required: true + type: string + rc-dockerfile: + required: true + type: string + rc-docker-tag: + required: true + type: string + rc-dockerfile-alpine: + required: true + type: string + rc-docker-tag-alpine: + required: true + type: string + gh-docker-tag: + required: true + type: string + enterprise-license: + type: string + transporter: + type: string + mongodb-version: + default: "['4.4', '6.0']" + required: false + type: string + release: + required: true + type: string + publish-container: + default: false + type: boolean + shard: + default: '[1]' + required: false + type: string + total-shard: + default: 1 + required: false + type: number + type: + required: true + type: string + secrets: + CR_USER: + required: true + CR_PAT: + required: true + +env: + MONGO_URL: mongodb://localhost:27017/rocketchat?replicaSet=rs0&directConnection=true + TOOL_NODE_FLAGS: ${{ vars.TOOL_NODE_FLAGS }} + LOWERCASE_REPOSITORY: ${{ inputs.lowercase-repo }} + DOCKER_TAG: ${{ inputs.gh-docker-tag }} + +jobs: + test: + runs-on: ubuntu-20.04 + env: + RC_DOCKERFILE: ${{ matrix.mongodb-version == '6.0' && inputs.rc-dockerfile-alpine || inputs.rc-dockerfile }} + RC_DOCKER_TAG: ${{ matrix.mongodb-version == '6.0' && inputs.rc-docker-tag-alpine || inputs.rc-docker-tag }} + + strategy: + fail-fast: false + matrix: + mongodb-version: ${{ fromJSON(inputs.mongodb-version) }} + shard: ${{ fromJSON(inputs.shard) }} + + name: MongoDB ${{ matrix.mongodb-version }} (${{ matrix.shard }}/${{ inputs.total-shard }}) + + steps: + - name: Launch MongoDB + uses: supercharge/mongodb-github-action@1.8.0 + with: + mongodb-version: ${{ matrix.mongodb-version }} + mongodb-replica-set: rs0 + + - uses: actions/checkout@v3 + + - name: Setup NodeJS + uses: ./.github/actions/setup-node + with: + node-version: ${{ inputs.node-version }} + cache-modules: true + install: true + + - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + + - name: yarn build + run: yarn build + + - name: Restore build + uses: actions/download-artifact@v3 + with: + name: build + path: /tmp/build + + - name: Unpack build + run: | + cd /tmp/build + tar xzf Rocket.Chat.tar.gz + rm Rocket.Chat.tar.gz + + - name: Start containers + if: inputs.release == 'ce' + env: + MONGO_URL: 'mongodb://host.docker.internal:27017/rocketchat?replicaSet=rs0&directConnection=true' + run: | + docker compose -f docker-compose-ci.yml up -d --build rocketchat + + - name: Start containers + if: inputs.release == 'ee' + env: + MONGO_URL: 'mongodb://host.docker.internal:27017/rocketchat?replicaSet=rs0&directConnection=true' + ENTERPRISE_LICENSE: ${{ inputs.enterprise-license }} + TRANSPORTER: ${{ inputs.transporter }} + run: | + docker compose -f docker-compose-ci.yml up -d --build + + - name: Login to GitHub Container Registry + if: inputs.publish-container == true && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ secrets.CR_USER }} + password: ${{ secrets.CR_PAT }} + + - name: Publish Docker images to GitHub Container Registry + if: inputs.publish-container == true && inputs.release == 'ce' && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') + run: | + docker compose -f docker-compose-ci.yml push rocketchat + + if [[ '${{ matrix.mongodb-version }}' = '4.4' ]]; then + IMAGE_NAME_BASE="ghcr.io/${LOWERCASE_REPOSITORY}/rocket.chat:${{ inputs.gh-docker-tag }}" + + echo "Push Docker image: ${IMAGE_NAME_BASE}" + + docker tag ${IMAGE_NAME_BASE}.official $IMAGE_NAME_BASE + docker push $IMAGE_NAME_BASE + fi; + + - name: Publish Docker images (services) to GitHub Container Registry + if: inputs.publish-container == true && inputs.release == 'ee' && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop') + run: | + docker compose -f docker-compose-ci.yml push \ + authorization-service \ + account-service \ + ddp-streamer-service \ + presence-service \ + stream-hub-service + + - name: Cache Playwright binaries + if: inputs.type == 'ui' + uses: actions/cache@v3 + id: cache-playwright + with: + path: | + ~/.cache/ms-playwright + # This is the version of Playwright that we are using, if you are willing to upgrade, you should update this. + key: playwright-1.23.1 + + - name: Install Playwright + if: inputs.type == 'ui' && steps.cache-playwright.outputs.cache-hit != 'true' + working-directory: ./apps/meteor + run: npx playwright install --with-deps + + - name: Wait for Rocket.Chat to start up + uses: cygnetdigital/wait_for_response@v2.0.0 + with: + url: 'http://localhost:3000/health' + responseCode: '200' + timeout: 60000 + interval: 1000 + + - name: Wait services to start up + if: inputs.release == 'ee' + run: | + docker ps + + until echo "$(docker compose -f docker-compose-ci.yml logs ddp-streamer-service)" | grep -q "NetworkBroker started successfully"; do + echo "Waiting 'ddp-streamer' to start up" + ((c++)) && ((c==10)) && docker compose -f docker-compose-ci.yml logs ddp-streamer-service && exit 1 + sleep 10 + done; + + - name: E2E Test API + if: inputs.type == 'api' + working-directory: ./apps/meteor + env: + IS_EE: ${{ inputs.release == 'ee' && 'true' || '' }} + run: | + for i in $(seq 1 5); do + npm run testapi && s=0 && break || s=$? + + docker compose -f ../../docker-compose-ci.yml logs --tail=100 + + docker compose -f ../../docker-compose-ci.yml stop + + docker exec mongodb bash -c 'if command -v mongosh ; then mongosh --eval "use rocketchat" --eval "db.dropDatabase()" rocketchat; else mongo rocketchat --eval "db.dropDatabase()"; fi' + + NOW=$(date "+%Y-%m-%dT%H:%M:%S.000Z") + + docker compose -f ../../docker-compose-ci.yml restart + + until echo "$(docker compose -f ../../docker-compose-ci.yml logs rocketchat --since $NOW)" | grep -q "SERVER RUNNING"; do + echo "Waiting Rocket.Chat to start up" + ((c++)) && ((c==10)) && exit 1 + sleep 10 + done; + done; + exit $s + + - name: E2E Test UI (${{ matrix.shard }}/${{ inputs.total-shard }}) + if: inputs.type == 'ui' + env: + E2E_COVERAGE: ${{ inputs.release == 'ee' && 'true' || '' }} + IS_EE: ${{ inputs.release == 'ee' && 'true' || '' }} + working-directory: ./apps/meteor + run: yarn test:e2e --shard=${{ matrix.shard }}/${{ inputs.total-shard }} + + - name: Store playwright test trace + if: inputs.type == 'ui' && always() + uses: actions/upload-artifact@v3 + with: + name: playwright-test-trace${{ inputs.release }} + path: ./apps/meteor/tests/e2e/.playwright* + + - name: Show server logs if E2E test failed + if: inputs.type == 'ui' && failure() + run: docker compose -f docker-compose-ci.yml logs rocketchat + + - name: Extract e2e:ee:coverage + if: inputs.type == 'ui' && inputs.release == 'ee' + working-directory: ./apps/meteor + run: yarn test:e2e:nyc + + - uses: codecov/codecov-action@v3 + if: inputs.type == 'ui' && inputs.release == 'ee' + with: + directory: ./apps/meteor + flags: e2e + verbose: true + + - name: Store e2e-ee-coverage + if: inputs.type == 'ui' && inputs.release == 'ee' + uses: actions/upload-artifact@v3 + with: + name: e2e-ee-coverage + path: ./apps/meteor/coverage* diff --git a/.github/workflows/ci-test-unit.yml b/.github/workflows/ci-test-unit.yml new file mode 100644 index 0000000000000..b4776e0b75c07 --- /dev/null +++ b/.github/workflows/ci-test-unit.yml @@ -0,0 +1,48 @@ +name: Tests Unit + +on: + workflow_call: + inputs: + node-version: + required: true + type: string + mongodb-version: + default: "['4.4', '6.0']" + required: false + type: string + +env: + MONGO_URL: mongodb://localhost:27017/rocketchat?replicaSet=rs0&directConnection=true + TOOL_NODE_FLAGS: ${{ vars.TOOL_NODE_FLAGS }} + +jobs: + test: + runs-on: ubuntu-20.04 + + strategy: + fail-fast: false + matrix: + mongodb-version: ${{ fromJSON(inputs.mongodb-version) }} + + name: MongoDB ${{ matrix.mongodb-version }} + + steps: + - name: Launch MongoDB + uses: supercharge/mongodb-github-action@1.8.0 + with: + mongodb-version: ${{ matrix.mongodb-version }} + mongodb-replica-set: rs0 + + - uses: actions/checkout@v3 + + - name: Setup NodeJS + uses: ./.github/actions/setup-node + with: + node-version: ${{ inputs.node-version }} + cache-modules: true + install: true + + - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + + - name: Unit Test + run: yarn testunit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000000..12a79b5be9180 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,562 @@ +name: CI + +on: + release: + types: [published] + pull_request: + branches: '**' + push: + branches: + - develop + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +env: + TOOL_NODE_FLAGS: ${{ vars.TOOL_NODE_FLAGS }} + +jobs: + release-versions: + name: ⚙️ Variables Setup + runs-on: ubuntu-latest + outputs: + release: ${{ steps.by-tag.outputs.release }} + latest-release: ${{ steps.latest.outputs.latest-release }} + docker-tag: ${{ steps.docker.outputs.docker-tag }} + gh-docker-tag: ${{ steps.docker.outputs.gh-docker-tag }} + lowercase-repo: ${{ steps.var.outputs.lowercase-repo }} + rc-dockerfile: '${{ github.workspace }}/apps/meteor/.docker/Dockerfile' + rc-docker-tag: '${{ steps.docker.outputs.gh-docker-tag }}.official' + rc-dockerfile-alpine: '${{ github.workspace }}/apps/meteor/.docker/Dockerfile.alpine' + rc-docker-tag-alpine: '${{ steps.docker.outputs.gh-docker-tag }}.alpine' + node-version: ${{ steps.var.outputs.node-version }} + # this is 100% intentional, secrets are not available for forks, so ee-tests will always fail + # to avoid this, we are using a dummy license, expiring at 2023-06-30 + enterprise-license: Z2Dg0RC3kyxjuklSE6qfqyvD2xSD+oTYcS9OesJG0523r7rSPjv59LTQqPcp5E61qQYM3MOKoW3mDrurw4h78nVbsfrF2DoJZeNjRFQfIbgwcdPwtmnqPpDvAslszHY16VzM7O7EYqAqp/9mlnRzs1iJY+W3w1r6HWBlVMb9u41bl5HBSpX6Nxw8YxL4mizwOpjxewQbPQvNTLJNAW6w0nCzF5A3CKBhD9fziadedVMLOuXBuR8kIl8zbIAfqpHmL8SvakvQAbZEjWWQshmH+C9CKA5PppkmA8Q1DNWQoVtHSiYDK8RRjAEx+0oGflklzFyhJFDvD+ohZduNtNCgrJmxP5VFrVrLSK4BXgTSwwnaSKa2N+Qx0CmuRfu7nCPc1Cf6h6+k2TXvzkE4Z0ZJnDV1khu611glAr99bHdwF+bMX3XZI66bS8KqnHEukCt5xei25iKJ2xrfmGuiAkAuKHKzBmTEmXM0pGhkfDhA9jhxG3Atoj1A5y8vdrs88voF+UuNFZ6k9sKtdvrWIWClnkatPE+41ggbzCsOhFz07BvRWaEtw2Kenipl4Vtag4qmFpUaUfsuouH99M3gDlysDZO3x5aH8yfzvFeL5WDMvsmdEHNLpHl89WsPCONvx0JjRSdwcCA1NrRuVy1Ncu0S0bRByn7HZqoY9u6HPkXKBxQ= + steps: + - uses: Bhacaz/checkout-files@v2 + with: + files: package.json + + - id: var + run: | + LOWERCASE_REPOSITORY=$(echo "${{ github.repository_owner }}" | tr "[:upper:]" "[:lower:]") + + echo "LOWERCASE_REPOSITORY: ${LOWERCASE_REPOSITORY}" + echo "lowercase-repo=${LOWERCASE_REPOSITORY}" >> $GITHUB_OUTPUT + + NODE_VERSION=$(node -p "require('./package.json').volta.node") + echo "NODE_VERSION: ${NODE_VERSION}" + echo "node-version=${NODE_VERSION}" >> $GITHUB_OUTPUT + + - id: by-tag + run: | + if echo "$GITHUB_REF_NAME" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' ; then + RELEASE="latest" + elif echo "$GITHUB_REF_NAME" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$' ; then + RELEASE="release-candidate" + fi + echo "RELEASE: ${RELEASE}" + echo "release=${RELEASE}" >> $GITHUB_OUTPUT + + - id: latest + run: | + LATEST_RELEASE="$( + git -c 'versionsort.suffix=-' ls-remote -t --exit-code --refs --sort=-v:refname "https://github.com/$GITHUB_REPOSITORY" '*' | + awk -F/ '$NF !~ /rc|beta/ { print $NF; exit }' + )" + echo "LATEST_RELEASE: ${LATEST_RELEASE}" + echo "latest-release=${LATEST_RELEASE}" >> $GITHUB_OUTPUT + + - id: docker + run: | + if [[ '${{ github.event_name }}' == 'pull_request' ]]; then + DOCKER_TAG="pr-${{ github.event.number }}" + else + DOCKER_TAG="gh-${{ github.run_id }}" + fi + echo "DOCKER_TAG: ${DOCKER_TAG}" + echo "gh-docker-tag=${DOCKER_TAG}" >> $GITHUB_OUTPUT + + build: + name: 📦 Build + needs: [release-versions] + runs-on: ubuntu-20.04 + + steps: + - name: Github Info + run: | + echo "GITHUB_ACTION: $GITHUB_ACTION" + echo "GITHUB_ACTOR: $GITHUB_ACTOR" + echo "GITHUB_REF: $GITHUB_REF" + echo "GITHUB_HEAD_REF: $GITHUB_HEAD_REF" + echo "GITHUB_BASE_REF: $GITHUB_BASE_REF" + echo "github.event_name: ${{ github.event_name }}" + cat $GITHUB_EVENT_PATH + + - name: Set Swap Space + uses: pierotofy/set-swap-space@master + with: + swap-size-gb: 4 + + - uses: actions/checkout@v3 + + - name: Setup NodeJS + uses: ./.github/actions/setup-node + with: + node-version: ${{ needs.release-versions.outputs.node-version }} + cache-modules: true + install: true + + # - name: Free disk space + # run: | + # sudo apt clean + # docker rmi $(docker image ls -aq) + # df -h + + - name: Cache meteor local + uses: actions/cache@v3 + with: + path: ./apps/meteor/.meteor/local + key: meteor-local-cache-${{ runner.OS }}-${{ hashFiles('apps/meteor/.meteor/versions') }} + restore-keys: | + meteor-local-cache-${{ runner.os }}- + + - name: Cache meteor + uses: actions/cache@v3 + with: + path: ~/.meteor + key: meteor-cache-${{ runner.OS }}-${{ hashFiles('apps/meteor/.meteor/release') }} + restore-keys: | + meteor-cache-${{ runner.os }}- + + - name: Install Meteor + run: | + # Restore bin from cache + set +e + METEOR_SYMLINK_TARGET=$(readlink ~/.meteor/meteor) + METEOR_TOOL_DIRECTORY=$(dirname "$METEOR_SYMLINK_TARGET") + set -e + LAUNCHER=$HOME/.meteor/$METEOR_TOOL_DIRECTORY/scripts/admin/launch-meteor + if [ -e $LAUNCHER ] + then + echo "Cached Meteor bin found, restoring it" + sudo cp "$LAUNCHER" "/usr/local/bin/meteor" + else + echo "No cached Meteor bin found." + fi + + # only install meteor if bin isn't found + command -v meteor >/dev/null 2>&1 || curl https://install.meteor.com | sed s/--progress-bar/-sL/g | /bin/sh + + - name: Versions + run: | + npm --versions + yarn -v + node -v + meteor --version + meteor npm --versions + meteor node -v + git version + + - uses: dtinth/setup-github-actions-caching-for-turbo@v1 + + - name: Translation check + run: yarn turbo run translation-check + + - name: Reset Meteor + if: startsWith(github.ref, 'refs/tags/') == 'true' || github.ref == 'refs/heads/develop' + working-directory: ./apps/meteor + run: meteor reset + + - name: Build Rocket.Chat From Pull Request + if: startsWith(github.ref, 'refs/pull/') == true + env: + METEOR_PROFILE: 1000 + run: yarn build:ci -- --directory /tmp/dist + + - name: Build Rocket.Chat + if: startsWith(github.ref, 'refs/pull/') != true + run: yarn build:ci -- --directory /tmp/dist + + - name: Prepare build + run: | + cd /tmp/dist + tar czf /tmp/Rocket.Chat.tar.gz bundle + + - name: Store build + uses: actions/upload-artifact@v3 + with: + name: build + path: /tmp/Rocket.Chat.tar.gz + + checks: + needs: [release-versions] + + name: 🔎 Code Check + uses: ./.github/workflows/ci-code-check.yml + with: + node-version: ${{ needs.release-versions.outputs.node-version }} + + test-unit: + name: 🔨 Test Unit + needs: [build, checks, release-versions] + + uses: ./.github/workflows/ci-test-unit.yml + with: + node-version: ${{ needs.release-versions.outputs.node-version }} + + test-api: + name: 🔨 Test API (CE) + needs: [build, checks, release-versions] + + uses: ./.github/workflows/ci-test-e2e.yml + with: + type: api + release: ce + publish-container: true + node-version: ${{ needs.release-versions.outputs.node-version }} + lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }} + rc-dockerfile: ${{ needs.release-versions.outputs.rc-dockerfile }} + rc-docker-tag: ${{ needs.release-versions.outputs.rc-docker-tag }} + rc-dockerfile-alpine: ${{ needs.release-versions.outputs.rc-dockerfile-alpine }} + rc-docker-tag-alpine: ${{ needs.release-versions.outputs.rc-docker-tag-alpine }} + gh-docker-tag: ${{ needs.release-versions.outputs.gh-docker-tag }} + secrets: + CR_USER: ${{ secrets.CR_USER }} + CR_PAT: ${{ secrets.CR_PAT }} + + test-ui: + name: 🔨 Test UI (CE) + needs: [build, checks, release-versions] + + uses: ./.github/workflows/ci-test-e2e.yml + with: + type: ui + release: ce + transporter: 'nats://nats:4222' + enterprise-license: ${{ needs.release-versions.outputs.enterprise-license }} + shard: '[1, 2, 3, 4]' + total-shard: 4 + node-version: ${{ needs.release-versions.outputs.node-version }} + lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }} + rc-dockerfile: ${{ needs.release-versions.outputs.rc-dockerfile }} + rc-docker-tag: ${{ needs.release-versions.outputs.rc-docker-tag }} + rc-dockerfile-alpine: ${{ needs.release-versions.outputs.rc-dockerfile-alpine }} + rc-docker-tag-alpine: ${{ needs.release-versions.outputs.rc-docker-tag-alpine }} + gh-docker-tag: ${{ needs.release-versions.outputs.gh-docker-tag }} + secrets: + CR_USER: ${{ secrets.CR_USER }} + CR_PAT: ${{ secrets.CR_PAT }} + + test-api-ee: + name: 🔨 Test API (EE) + needs: [build, checks, release-versions] + + uses: ./.github/workflows/ci-test-e2e.yml + with: + type: api + release: ee + transporter: 'nats://nats:4222' + enterprise-license: ${{ needs.release-versions.outputs.enterprise-license }} + publish-container: true + mongodb-version: "['4.4']" + node-version: ${{ needs.release-versions.outputs.node-version }} + lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }} + rc-dockerfile: ${{ needs.release-versions.outputs.rc-dockerfile }} + rc-docker-tag: ${{ needs.release-versions.outputs.rc-docker-tag }} + rc-dockerfile-alpine: ${{ needs.release-versions.outputs.rc-dockerfile-alpine }} + rc-docker-tag-alpine: ${{ needs.release-versions.outputs.rc-docker-tag-alpine }} + gh-docker-tag: ${{ needs.release-versions.outputs.gh-docker-tag }} + secrets: + CR_USER: ${{ secrets.CR_USER }} + CR_PAT: ${{ secrets.CR_PAT }} + + test-ui-ee: + name: 🔨 Test UI (EE) + needs: [build, checks, release-versions] + + uses: ./.github/workflows/ci-test-e2e.yml + with: + type: ui + release: ee + transporter: 'nats://nats:4222' + enterprise-license: ${{ needs.release-versions.outputs.enterprise-license }} + shard: '[1, 2, 3, 4, 5]' + total-shard: 5 + mongodb-version: "['4.4']" + node-version: ${{ needs.release-versions.outputs.node-version }} + lowercase-repo: ${{ needs.release-versions.outputs.lowercase-repo }} + rc-dockerfile: ${{ needs.release-versions.outputs.rc-dockerfile }} + rc-docker-tag: ${{ needs.release-versions.outputs.rc-docker-tag }} + rc-dockerfile-alpine: ${{ needs.release-versions.outputs.rc-dockerfile-alpine }} + rc-docker-tag-alpine: ${{ needs.release-versions.outputs.rc-docker-tag-alpine }} + gh-docker-tag: ${{ needs.release-versions.outputs.gh-docker-tag }} + secrets: + CR_USER: ${{ secrets.CR_USER }} + CR_PAT: ${{ secrets.CR_PAT }} + + tests-done: + name: ✅ Tests Done + runs-on: ubuntu-20.04 + needs: [test-unit, test-api, test-ui, test-api-ee, test-ui-ee] + + steps: + - name: Test finish aggregation + run: | + echo finished + + deploy: + name: 🚀 Publish build and update our registry + runs-on: ubuntu-20.04 + if: github.event_name == 'release' || github.ref == 'refs/heads/develop' + needs: [tests-done, release-versions] + + steps: + - uses: actions/checkout@v3 + + - name: Restore build + uses: actions/download-artifact@v3 + with: + name: build + path: /tmp/build + + - name: Publish assets + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: 'us-east-1' + GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }} + REDHAT_REGISTRY_PID: ${{ secrets.REDHAT_REGISTRY_PID }} + REDHAT_REGISTRY_KEY: ${{ secrets.REDHAT_REGISTRY_KEY }} + UPDATE_TOKEN: ${{ secrets.UPDATE_TOKEN }} + run: | + REPO_VERSION=$(node -p "require('./package.json').version") + if [[ '${{ github.event_name }}' = 'release' ]]; then + GIT_TAG="${GITHUB_REF#*tags/}" + GIT_BRANCH="" + ARTIFACT_NAME="${REPO_VERSION}" + RC_VERSION=$GIT_TAG + + if [[ '${{ needs.release-versions.outputs.release }}' = 'release-candidate' ]]; then + SNAP_CHANNEL=candidate + RC_RELEASE=candidate + elif [[ '${{ needs.release-versions.outputs.release }}' = 'latest' ]]; then + SNAP_CHANNEL=stable + RC_RELEASE=stable + fi + else + GIT_TAG="" + GIT_BRANCH="${GITHUB_REF#*heads/}" + ARTIFACT_NAME="${REPO_VERSION}.$GITHUB_SHA" + RC_VERSION="${REPO_VERSION}" + SNAP_CHANNEL=edge + RC_RELEASE=develop + fi; + ROCKET_DEPLOY_DIR="/tmp/deploy" + FILENAME="$ROCKET_DEPLOY_DIR/rocket.chat-$ARTIFACT_NAME.tgz"; + + aws s3 cp s3://rocketchat/sign.key.gpg .github/sign.key.gpg + + mkdir -p $ROCKET_DEPLOY_DIR + + cp .github/sign.key.gpg /tmp + gpg --yes --batch --passphrase=$GPG_PASSWORD /tmp/sign.key.gpg + gpg --allow-secret-key-import --import /tmp/sign.key + rm /tmp/sign.key + + ln -s /tmp/build/Rocket.Chat.tar.gz "$FILENAME" + gpg --armor --detach-sign "$FILENAME" + + aws s3 cp $ROCKET_DEPLOY_DIR/ s3://download.rocket.chat/build/ --recursive + + curl -H "Content-Type: application/json" -H "X-Update-Token: $UPDATE_TOKEN" -d \ + "{\"nodeVersion\": \"${{ needs.release-versions.outputs.node-version }}\", \"compatibleMongoVersions\": [\"4.4\", \"5.0\", \"6.0\"], \"commit\": \"$GITHUB_SHA\", \"tag\": \"$RC_VERSION\", \"branch\": \"$GIT_BRANCH\", \"artifactName\": \"$ARTIFACT_NAME\", \"releaseType\": \"$RC_RELEASE\"}" \ + https://releases.rocket.chat/update + + # Makes build fail if the release isn't there + curl --fail https://releases.rocket.chat/$RC_VERSION/info + + if [[ $GIT_TAG ]]; then + curl -X POST \ + https://connect.redhat.com/api/v2/projects/$REDHAT_REGISTRY_PID/build \ + -H "Authorization: Bearer $REDHAT_REGISTRY_KEY" \ + -H 'Cache-Control: no-cache' \ + -H 'Content-Type: application/json' \ + -d '{"tag":"'$GIT_TAG'"}' + fi + + build-docker-preview: + name: 🚢 Build Docker Image (preview) + runs-on: ubuntu-20.04 + needs: [build, checks, release-versions] + if: github.event_name == 'release' || github.ref == 'refs/heads/develop' + steps: + - uses: actions/checkout@v3 + + - name: Restore build + uses: actions/download-artifact@v3 + with: + name: build + path: /tmp/build + + - name: Unpack build + run: | + cd /tmp/build + tar xzf Rocket.Chat.tar.gz + rm Rocket.Chat.tar.gz + + - name: Build Docker image + id: build-docker-image-preview + uses: ./.github/actions/build-docker-image + with: + root-dir: /tmp/build + docker-tag: ${{ needs.release-versions.outputs.gh-docker-tag }} + release: preview + username: ${{ secrets.CR_USER }} + password: ${{ secrets.CR_PAT }} + + docker-image-publish: + name: 🚀 Publish Docker Image (main) + runs-on: ubuntu-20.04 + needs: [deploy, build-docker-preview, release-versions] + + strategy: + matrix: + # this is currently a mix of variants and different images + release: ['official', 'preview', 'alpine'] + + env: + IMAGE_NAME: 'rocketchat/rocket.chat' + + steps: + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_PASS }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ secrets.CR_USER }} + password: ${{ secrets.CR_PAT }} + + - name: Get Docker image name + id: gh-docker + run: | + GH_IMAGE_NAME="ghcr.io/${{ needs.release-versions.outputs.lowercase-repo }}/rocket.chat:${{ needs.release-versions.outputs.gh-docker-tag }}.${{ matrix.release }}" + + echo "GH_IMAGE_NAME: $GH_IMAGE_NAME" + + echo "gh-image-name=${GH_IMAGE_NAME}" >> $GITHUB_OUTPUT + + - name: Pull Docker image + run: docker pull ${{ steps.gh-docker.outputs.gh-image-name }} + + - name: Publish Docker image + run: | + if [[ '${{ matrix.release }}' = 'preview' ]]; then + IMAGE_NAME="${IMAGE_NAME}.preview" + fi; + + # 'develop' or 'tag' + DOCKER_TAG=$GITHUB_REF_NAME + + # append the variant name to docker tag + if [[ '${{ matrix.release }}' = 'alpine' ]]; then + DOCKER_TAG="${DOCKER_TAG}-${{ matrix.release }}" + fi; + + echo "IMAGE_NAME: $IMAGE_NAME" + echo "DOCKER_TAG: $DOCKER_TAG" + + # tag and push the specific tag version + docker tag ${{ steps.gh-docker.outputs.gh-image-name }} $IMAGE_NAME:$DOCKER_TAG + docker push $IMAGE_NAME:$DOCKER_TAG + + if [[ $GITHUB_REF == refs/tags/* ]]; then + RELEASE="${{ needs.release-versions.outputs.release }}" + + if [[ '${{ matrix.release }}' = 'alpine' ]]; then + RELEASE="${RELEASE}-${{ matrix.release }}" + fi; + + echo "RELEASE: $RELEASE" + + if [[ $RELEASE == 'latest' ]]; then + if [[ '${{ needs.release-versions.outputs.latest-release }}' == $GITHUB_REF_NAME ]]; then + docker tag ${{ steps.gh-docker.outputs.gh-image-name }} $IMAGE_NAME:$RELEASE + docker push $IMAGE_NAME:$RELEASE + fi + else + docker tag ${{ steps.gh-docker.outputs.gh-image-name }} $IMAGE_NAME:$RELEASE + docker push $IMAGE_NAME:$RELEASE + fi + fi + + services-docker-image-publish: + name: 🚀 Publish Docker Image (services) + runs-on: ubuntu-20.04 + needs: [deploy, release-versions] + + strategy: + matrix: + service: ['account', 'authorization', 'ddp-streamer', 'presence', 'stream-hub'] + + steps: + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_PASS }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ secrets.CR_USER }} + password: ${{ secrets.CR_PAT }} + + - name: Get Docker image name + id: gh-docker + run: | + GH_IMAGE_NAME="ghcr.io/${{ needs.release-versions.outputs.lowercase-repo }}/${{ matrix.service }}-service:${{ needs.release-versions.outputs.gh-docker-tag }}" + + echo "GH_IMAGE_NAME: $GH_IMAGE_NAME" + + echo "gh-image-name=${GH_IMAGE_NAME}" >> $GITHUB_OUTPUT + + - name: Pull Docker image + run: docker pull ${{ steps.gh-docker.outputs.gh-image-name }} + + - name: Publish Docker images + run: | + DH_IMAGE_NAME="rocketchat/${{ matrix.service }}-service" + + # 'develop' or 'tag' + DOCKER_TAG=$GITHUB_REF_NAME + + echo "DH_IMAGE_NAME: $DH_IMAGE_NAME" + echo "DOCKER_TAG: $DOCKER_TAG" + + # tag and push the specific tag version + docker tag ${{ steps.gh-docker.outputs.gh-image-name }} $DH_IMAGE_NAME:$DOCKER_TAG + docker push $DH_IMAGE_NAME:$DOCKER_TAG + + if [[ $GITHUB_REF == refs/tags/* ]]; then + RELEASE="${{ needs.release-versions.outputs.release }}" + echo "RELEASE: $RELEASE" + + if [[ $RELEASE == 'latest' ]]; then + if [[ '${{ needs.release-versions.outputs.latest-release }}' == $GITHUB_REF_NAME ]]; then + docker tag ${{ steps.gh-docker.outputs.gh-image-name }} $DH_IMAGE_NAME:$RELEASE + docker push $DH_IMAGE_NAME:$RELEASE + fi + else + docker tag ${{ steps.gh-docker.outputs.gh-image-name }} $DH_IMAGE_NAME:$RELEASE + docker push $DH_IMAGE_NAME:$RELEASE + fi + fi diff --git a/.github/workflows/no-new-js-files.yml b/.github/workflows/no-new-js-files.yml deleted file mode 100644 index 77045946b52c3..0000000000000 --- a/.github/workflows/no-new-js-files.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: 'JS file preventer' -on: - pull_request: - types: [opened, synchronize] -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: ggazzo/no-js-action@1.0.2 - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pr-title-checker.yml b/.github/workflows/pr-title-checker.yml index 06cd2439ef812..6b8a81efc6c39 100644 --- a/.github/workflows/pr-title-checker.yml +++ b/.github/workflows/pr-title-checker.yml @@ -1,12 +1,12 @@ name: 'PR Title Checker' on: - pull_request: + pull_request_target: types: [opened, edited] jobs: check: runs-on: ubuntu-latest steps: - - uses: thehanimo/pr-title-checker@v1.3.4 + - uses: thehanimo/pr-title-checker@v1.3.6 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 310be7ef939d6..48ff4ff6ce007 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,6 @@ yarn-error.log* .nvmrc .idea/ +.exrc +.history +.envrc diff --git a/.houston/metadata.js b/.houston/metadata.js index 411cff5106c5a..7ba50b7ba2bfc 100644 --- a/.houston/metadata.js +++ b/.houston/metadata.js @@ -1,13 +1,15 @@ +const { execSync } = require('child_process'); + const getMongoVersion = async function({ version, git }) { try { - const workflows = await git.show([`${ version }:.github/workflows/build_and_test.yml`]); + const workflows = await git.show([`${ version }:.github/workflows/ci.yml`]); - const mongoMatch = workflows.match(/mongodb\-version: \[([^\]]+)\]/); + const mongoMatch = workflows.match(/compatibleMongoVersions\\": \[([^\]]+)\]/); if (!mongoMatch) { return []; } - return mongoMatch[1].replace(/["' ]/g, '').split(','); + return mongoMatch[1].replace(/["'\\ ]/g, '').split(','); } catch (e) { console.error(e); } @@ -38,11 +40,14 @@ const getNodeNpmVersions = async function({ version, git, request }) { const getAppsEngineVersion = async function({ version, git }) { try { - const packageJson = await git.show([`${ version }:apps/meteor/package-lock.json`]); - const { dependencies } = JSON.parse(packageJson); - const { version: appsEngineVersion } = dependencies['@rocket.chat/apps-engine']; + const result = execSync('yarn why @rocket.chat/apps-engine --json'); + + const resultString = result.toString(); - return appsEngineVersion; + const match = resultString.match(/"@rocket.chat\/meteor@workspace:apps\/meteor".*"@rocket\.chat\/apps\-engine@npm:([^"]+)"/); + if (match) { + return match[1]; + } } catch (e) { console.error(e); } diff --git a/.hygen.js b/.hygen.js new file mode 100644 index 0000000000000..6a43ecb7808d5 --- /dev/null +++ b/.hygen.js @@ -0,0 +1,5 @@ +module.exports = { + helpers: { + random: () => Math.floor(3000 + (5000 - 3000) * Math.random()), + }, +}; diff --git a/.kodiak.toml b/.kodiak.toml index b2f9e45da47ec..884f356a17125 100644 --- a/.kodiak.toml +++ b/.kodiak.toml @@ -7,6 +7,7 @@ automerge_label = ["stat: ready to merge", "automerge"] block_on_neutral_required_check_runs = true blocking_labels = ["stat: needs QA", "Invalid PR Title"] prioritize_ready_to_merge = true +merge.do_not_merge=true [merge.message] title = "pull_request_title" @@ -16,4 +17,3 @@ include_coauthors=true [merge.automerge_dependencies] versions = ["minor", "patch"] usernames = ["dependabot"] - diff --git a/.vscode/client.code-snippets b/.vscode/client.code-snippets new file mode 100644 index 0000000000000..f0f7ddcdc8845 --- /dev/null +++ b/.vscode/client.code-snippets @@ -0,0 +1,36 @@ +{ + "Storybook stories module for React component": { + "scope": "typescriptreact", + "prefix": "sbmodule", + "body": [ + "import type { ComponentMeta, ComponentStory } from '@storybook/react';", + "import React from 'react';", + "", + "import $1 from './$1';", + "", + "export default {", + "\ttitle: '$2',", + "\tcomponent: $1,", + "} as ComponentMeta;", + "", + "export const Example: ComponentStory = (args) => <$1 {...args} />;", + ] + }, + "Storybook meta": { + "scope": "typescriptreact", + "prefix": "sbmeta", + "body": [ + "export default {", + "\ttitle: '$1',", + "\tcomponent: $2,", + "} as ComponentMeta;" + ] + }, + "Storybook story": { + "scope": "typescriptreact", + "prefix": "sbstory", + "body": [ + "export const $1: ComponentStory = (args) => <$2 {...args} />;" + ] + } +} diff --git a/.vscode/settings.json b/.vscode/settings.json index a32489e34a647..3fb8fa0aeba02 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,9 +15,16 @@ ], "typescript.tsdk": "./node_modules/typescript/lib", "cSpell.words": [ + "autotranslate", + "fname", + "katex", + "listbox", "livechat", + "oauthapps", "omnichannel", "photoswipe", - "tmid" + "searchbox", + "tmid", + "tshow" ] } diff --git a/HISTORY.md b/HISTORY.md index f045b88ef99c7..56516868b6576 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,3320 @@ +# 6.0.0 +`2023-03-09 · 20 ️️️⚠️ · 12 🎉 · 13 🚀 · 60 🐛 · 238 🔍 · 56 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.21.2` +- NPM: `6.14.17` +- MongoDB: `4.4, 5.0, 6.0` + +### ⚠️ BREAKING CHANGES + + +- **ENTERPRISE:** Limit presence statuses to 200 concurrent users when running monolith to keep performance ([#27854](https://github.com/RocketChat/Rocket.Chat/pull/27854)) + +- **FIX:** VideoConference Ringer working intermittently on microservices ([#27703](https://github.com/RocketChat/Rocket.Chat/pull/27703)) + +- **IMPROVE:** SMTP warning for invitations ([#27713](https://github.com/RocketChat/Rocket.Chat/pull/27713)) + + - TC-347 - SMTP warning for invitations flow + - Create rest endpoint for sendInvitationEmail + - Use endpoint in-place of removed Meteor method + +- **NEW:** Custom roles upsell modal ([#27707](https://github.com/RocketChat/Rocket.Chat/pull/27707)) + + ![image](https://user-images.githubusercontent.com/40830821/211393807-2dd4ad76-cc98-4950-99a6-93d6c2087406.png) + + Also changed the `edit role` button: + ![image](https://user-images.githubusercontent.com/40830821/211393881-980293fa-a3af-46a5-8bfe-48f99872333a.png) + +- Drop support for MongoDB 4.2 and deprecate MongoDB 4.4 ([#27891](https://github.com/RocketChat/Rocket.Chat/pull/27891)) + + As per MongoDB Lifecycle Schedules ([mongodb.com/support-policy/lifecycles](https://www.mongodb.com/support-policy/lifecycles)) we're removing official support to MongoDB version 4.2 that is close to reach end of life (April 2023). + + We recommend upgrading to MongoDB 5.0+, though 4.4 is still a supported version. + + Here are official docs on how to upgrade to some of the supported versions: + + [mongodb.com/docs/v4.4/release-notes/4.4-upgrade-replica-set](https://www.mongodb.com/docs/v4.4/release-notes/4.4-upgrade-replica-set/) + [mongodb.com/docs/manual/release-notes/5.0-upgrade-replica-set](https://www.mongodb.com/docs/manual/release-notes/5.0-upgrade-replica-set/) + [mongodb.com/docs/manual/release-notes/6.0-upgrade-replica-set](https://www.mongodb.com/docs/manual/release-notes/6.0-upgrade-replica-set/) + +- Freeze Custom Roles ([#27481](https://github.com/RocketChat/Rocket.Chat/pull/27481)) + + This PR moves role creation and update to enterprise folder + + -- + - Removed method `authorization:saveRole` + - Moved `/v1/roles.create/` and `/v1/roles.update` to enterprise edition + - Changed message for delete a custom role in community edition + +- Limit `underscore` usage and remove `underscore.string` (even from integration script sandboxes) ([#28037](https://github.com/RocketChat/Rocket.Chat/pull/28037)) + + [Underscore.js](https://underscorejs.org/) is quite outdated and we're not using it in a way that take advantage of modularization, bloating the client bundle. This PR aims to limit its usage across the application. + + break: if you are used to have scripts, and they are using underscore, please pay attention probably you need to update them + +- Marketplace standalone page and app request flow ([#27389](https://github.com/RocketChat/Rocket.Chat/pull/27389)) + + Remove marketplace from the admin menu (on both the file system and the UI), change it into a standalone page, expose its use to end-users, and create an app request flow that allows end-users to ask for app installations in their workspaces directly through Rocket Chats UI. + + Demo loom: https://www.loom.com/share/643ba3432225418e96c10041f386ff48 + + ## Jira tasks and ADRs + All tasks, descriptions, and designs of work done in this PR can be found on the tasks below, which also double down as simplified ADRs. + + ### [MKP-147](https://rocketchat.atlassian.net/browse/MKP-147?atlOrigin=eyJpIjoiNDJjNjBlNjU1MjI3NGI0M2I0NDZiZTRkMjkyYjcyZWMiLCJwIjoiaiJ9) - Remove marketplace from the admin menu and put it on its own page + + ### [MKP-68](https://rocketchat.atlassian.net/browse/MKP-68?atlOrigin=eyJpIjoiMGRhMmExYTViNDNlNGI0Y2FjY2ViNDc3MDgyNWUxNDciLCJwIjoiaiJ9) - Create an enterprise option on the new marketplace sidebar + + ### [MKP-150](https://rocketchat.atlassian.net/browse/MKP-150?atlOrigin=eyJpIjoiOGIyOWZlMWRhNmFmNDhlODhhMmNlOWE0MmMzOTYwMTgiLCJwIjoiaiJ9) - Implement the SideNav of the new marketplace page + + ### [MKP-151](https://rocketchat.atlassian.net/browse/MKP-151?atlOrigin=eyJpIjoiN2Y2OTc3MzhlZTAzNGJkOTgwYWVmZjFmMGY0MjA0ZmEiLCJwIjoiaiJ9) - Brainstorm and implement the new marketplace routes + + ### [MKP-179](https://rocketchat.atlassian.net/browse/MKP-179?atlOrigin=eyJpIjoiYjBmMDgxOGE4OTAxNDgzYTgwMDkxZmQxZGQwZTliNDQiLCJwIjoiaiJ9) - Retrieve number of requested apps and make it available for components + + ### [MKP-181](https://rocketchat.atlassian.net/browse/MKP-181?atlOrigin=eyJpIjoiNzRiNGM0MTM5NjNjNGVlNmFhZmIyZmQ1MGFhZTkzMjgiLCJwIjoiaiJ9) - Implement requested option on marketplace sidebar + + ### [MKP-184](https://rocketchat.atlassian.net/browse/MKP-184?atlOrigin=eyJpIjoiY2RkYjJhODc2MTcyNDlkOTllNzc1ZGU4OWIyNTMwYmIiLCJwIjoiaiJ9) - Create requested apps page + + ### [MKP-185](https://rocketchat.atlassian.net/browse/MKP-185?atlOrigin=eyJpIjoiY2M4ZjVmMzZlODA3NDBkZWE3NTU3YTQ2NWMyYWFjYTAiLCJwIjoiaiJ9) - Implement requested apps list layout and logic + + ### [MKP-180](https://rocketchat.atlassian.net/browse/MKP-180?atlOrigin=eyJpIjoiYjQwOTVkOTQ4YmYyNDlmN2JlNWI5YzcwYmMzYTEzZmIiLCJwIjoiaiJ9) - Implement requested apps option to home screen kebab menu + + ### [MKP-188](https://rocketchat.atlassian.net/browse/MKP-188?atlOrigin=eyJpIjoiYTkzNWMwMzdlODBlNDMwOGIzOGQ1MGJhMzFkNzhjYmMiLCJwIjoiaiJ9) - Implement the requested apps tab on app details page + + ### [MKP-187](https://rocketchat.atlassian.net/browse/MKP-187?atlOrigin=eyJpIjoiYmUzMjI2YTE4Njc1NGFjMThjYjUxNDlhYjMwMTc2MDgiLCJwIjoiaiJ9) - Implement visualized requests system on apps list tags and app requests tab + + ### [MKP-164](https://rocketchat.atlassian.net/browse/MKP-164?atlOrigin=eyJpIjoiMDUxOTJmNzVlNmZjNGQ4ZTljNzY2NDI4YjU5MjU0N2EiLCJwIjoiaiJ9) - ALL view the app's technical documentation page + + ### [MKP-197](https://rocketchat.atlassian.net/browse/MKP-197) - Rocket.cat notification for admins when an app is requested + + ### [MKP-224](https://rocketchat.atlassian.net/browse/MKP-224) - After i click submit request in the modal the modal is not closing + +- Move Multiple Department Creation to EE & [NEW] Department Archive ([#27753](https://github.com/RocketChat/Rocket.Chat/pull/27753)) + + [BREAK] **Move Multiple Department Creation to EE**: Limit max department creation to 1 in Community edition, existing departments will still function as before. + + [NEW] 📁 **Department archival**: Adds the ability to archive departments, archived departments are disabled and cannot be edited, but will still show in historical data (current chats, directory, chat info, etc...). This offers an alternative to department deletion. + +- Move read-receipts to EE and threads check marks improvements ([#27074](https://github.com/RocketChat/Rocket.Chat/pull/27074)) + + - Improvement: add read receipts for messages in threads only when the thread is open; + - Move read-receipts feature to EE (under the `message-read-receipt` module). The `chat.getMessageReadReceipts` endpoint and `getReadReceipts` Meteor method are now EE only. + +- Remove Chatpal ([#28012](https://github.com/RocketChat/Rocket.Chat/pull/28012)) + +- Remove legacy FB Messenger integration ([#27760](https://github.com/RocketChat/Rocket.Chat/pull/27760)) + + Legacy FB messenger integration has been removed in favour of the new and enhanced FB App integration. [Click here](https://docs.rocket.chat/guides/app-guides/omnichannel-apps/facebook-app) for more info + +- Remove less theming ([#27647](https://github.com/RocketChat/Rocket.Chat/pull/27647)) + +- Remove message view mode from User Preferences ([#27867](https://github.com/RocketChat/Rocket.Chat/pull/27867)) + + Since the view mode setting in `User preferences -> Messages -> View Mode` does not work with the new messages template it will be removed + + It was removed from every file and it was created a migration to remove from user obj in DB + +- Remove support to deprecated typing event ([#28234](https://github.com/RocketChat/Rocket.Chat/pull/28234)) + +- Removed deprecated settings for Legacy Messages, Marked, Snippet Messages, Autolinker and IssueLinks ([#27902](https://github.com/RocketChat/Rocket.Chat/pull/27902)) + + Removed Settings: + + - Markdown_Parser + - Markdown_Headers + - Markdown_SupportSchemesForLink + - Markdown_Marked_GFM + - Markdown_Marked_Tables + - Markdown_Marked_Breaks + - Markdown_Marked_Pedantic + - Markdown_Marked_SmartLists + - Markdown_Marked_Smartypants + - Message_AllowSnippeting + - Message_Attachments_GroupAttach + - Message_ShowEditedStatus + - Message_ShowFormattingTips + - Accounts_Default_User_Preferences_useLegacyMessageTemplate + - AutoLinker + - AutoLinker_StripPrefix + - AutoLinker_Urls_Scheme + - AutoLinker_Urls_www + - AutoLinker_Urls_TLD + - AutoLinker_UrlsRegExp + - AutoLinker_Email + - AutoLinker_Phone + - IssueLinks_Enabled + - IssueLinks_Template + - API_EmbedDisabledFor + +- Unify monolith and microservices intercommunication on same technology and limit to Enterprise only ([#27969](https://github.com/RocketChat/Rocket.Chat/pull/27969)) + + This change removes the old DDP Matrix communication by Moleculer based breaker over TCP, simplifying code maintenance, allowing better reliability, performance and monitoring. + + It requires a license to enable communication among servers as the rest of the Moleculer implementation. + + Community Edition will loose ephemeral events as Typing indication and others when running multiple instances. + +- Update livechat:saveDepartment to accept a string array in departmentsAllowedToForward ([#28261](https://github.com/RocketChat/Rocket.Chat/pull/28261)) + + **Breaking change:** There have been some changes to `livechat:saveDepartment` meteor method's `departmentsAllowedToForward` parameter. Previously it used to accept a string which was a comma-separated list of departmentIds. The new type is an array of strings. + + Due to recent changes to the `useDepartmentList` hook the component `AutoCompleteDepartment` became incompatible with many of our existing pages, causing them to break. This PR makes them work again. + +- Update Meteor to 2.9.1 and NodeJS to 14.21.2 ([#27639](https://github.com/RocketChat/Rocket.Chat/pull/27639)) + +- Upgrade to version 6.0 can be done only from version 5.x ([#28098](https://github.com/RocketChat/Rocket.Chat/pull/28098)) + +### 🎉 New features + + +- **EE:** Omnichannel Priorities & SLAs ([#27083](https://github.com/RocketChat/Rocket.Chat/pull/27083)) + +- **EE:** PDF Chat transcript for Omnichannel conversations ([#27572](https://github.com/RocketChat/Rocket.Chat/pull/27572)) + +- Attachment Files Redesign ([#27470](https://github.com/RocketChat/Rocket.Chat/pull/27470)) + + - Replace File attachments to use `MessageGenericPreview` + - Move File attachments to the` /MessageList` folder + - Refactor Video, Image, and Audio Attachments to use `MessageGenericPreview` + - New component MessageCollapsible + - Refactored the `OEmbedCollpsible` component to use `MessageCollapsible` + - Refactored the `AttachmentSize` component to include different style + - Added `descriptionMd` property to the `MessageAttachment` object to use the new parser in descriptions + - Added size and format to attachment object at `sendFileMessage.ts` + - Changed maxWidth and maxHeight of AttachmentContext to be the same as the OEmbed sizes + + **OLD:** + image + + + **NEW:** + image + +- Bridge to get all users crated by app and also delete them ([#27877](https://github.com/RocketChat/Rocket.Chat/pull/27877)) + + We're working on [MS Teams bridge](https://github.com/RocketChat/Apps.teams.bridge), to make it usable we have created a new method for the apps engine to [create new users](https://github.com/RocketChat/Rocket.Chat.Apps-engine/pull/536) and we'll also need to delete all when we uninstall the app. Therefore, we created this bridge to cover the action of deleting users on the app side. + +- Emojis rendering properly on quote message previews ([#27972](https://github.com/RocketChat/Rocket.Chat/pull/27972)) + + ![image](https://user-images.githubusercontent.com/47800334/217540055-de7cdc29-5478-4a23-a884-4476318bd83d.png) + +- Homepage new block ([#27540](https://github.com/RocketChat/Rocket.Chat/pull/27540)) + + - Create a new admin homepage block that includes: + - Button to go to /admin/Layout setting + - Button to show and hide the custom content to the user (a badge on top indicates if the custom content is hidden or not) + - Button to show and hide the other blocks (add users, create channel) on the homepage (EE only button) + + New homepage block admin view: + Screen Shot 2023-02-10 at 14 28 40 + + Normal user view: + Screen Shot 2023-02-10 at 17 12 39 + + + - Changes on the /admin/Layout settings: + - text and homepage settings small changes + - add Layout_Home_Custom_Block_Visible setting to show or hide custom content + + Admin Homepage Content settings page: + + Screen Shot 2023-02-10 at 15 29 18 + +- Matrix federation events coverage expansion + bug fixes ([#27763](https://github.com/RocketChat/Rocket.Chat/pull/27763)) + + - Disables not supported features in federated channels (#27204) + - Add support for the whole Matrix Markdown spec (#27725) + - Allow federated rooms with the same name per different servers when they have a contact between them (#27559) + - Matrix Federation send message when multiple users are involved was not working (#27327) + - Allow the room owner to set roles on federated rooms, following a specific and different approach as normal rooms (available on docs) (https://github.com/RocketChat/Rocket.Chat/pull/27633) + - E2E Tests (PS: they don't run on CI) (#27578 #27282 #27115) + - Disables admin actions disallowed for federated users/rooms (https://github.com/RocketChat/Rocket.Chat/pull/27251) + + FED-81 + +- New Message Composer ([#27566](https://github.com/RocketChat/Rocket.Chat/pull/27566)) + +- Permission to bypass message editing and removing limits ([#27644](https://github.com/RocketChat/Rocket.Chat/pull/27644)) + + This PR adds a new permission called `bypass-time-limit-edit-and-delete`, to bypass the time limit when editing or deleting a message, the purpose of this PR is to remove the limitation for bots that cannot change the message after the specified time. + +- Rocket.cat message for users when an app previously requested is installed ([#27672](https://github.com/RocketChat/Rocket.Chat/pull/27672)) + +- Upload service ([#27543](https://github.com/RocketChat/Rocket.Chat/pull/27543)) + +- Warning Popup reinforcing Zapier deprecation on Integrations Admin settings ([#27744](https://github.com/RocketChat/Rocket.Chat/pull/27744)) + + #### Warning being displayed on Zapier settings, above Zapier itself: + ![warning](https://user-images.githubusercontent.com/47800334/213696834-be7ac8e0-7249-4d02-93ba-e4c5e34b67da.png) + +### 🚀 Improvements + + +- Audit ([#27994](https://github.com/RocketChat/Rocket.Chat/pull/27994)) + +- Authorize search of custom fields on `users.list` ([#27423](https://github.com/RocketChat/Rocket.Chat/pull/27423)) + + This PR allows users to filter and search for custom fields on the `users.list` endpoint + +- Emoji picker for large amount of custom emojis ([#27745](https://github.com/RocketChat/Rocket.Chat/pull/27745)) + +- Increase read receipt size ([#27665](https://github.com/RocketChat/Rocket.Chat/pull/27665)) + + increase from 11px to 1rem (16px) + ![image](https://user-images.githubusercontent.com/40830821/209961616-3198b51a-ff7e-49eb-9627-15b53fbfe16a.png) + +- Livechat Persian translation ([#27825](https://github.com/RocketChat/Rocket.Chat/pull/27825) by [@pouyadarabi](https://github.com/pouyadarabi)) + +- Play selected notification sounds as preview while changing sound settings ([#24205](https://github.com/RocketChat/Rocket.Chat/pull/24205) by [@try-catch-stack](https://github.com/try-catch-stack)) + +- Registration Experience ([#27820](https://github.com/RocketChat/Rocket.Chat/pull/27820)) + + If you didn't register when you initially setup your server. Its now easier to register. + + Disconnecting and reconnecting your workspace from the cloud is now also easier + +- Require acceptance when setting new E2E Encryption key for another user ([#27556](https://github.com/RocketChat/Rocket.Chat/pull/27556)) + + Change the end to end encryption flow to require an acceptance from the user when receiving a new key. + + 1. Changes API `e2e.updateGroupKey` to set the new key to an auxiliary property named `E2ESuggestedKey` + 2. Adds new API `e2e.acceptSuggestedGroupKey` to be called to accept the suggested key and save it to the final property `E2EKey` + 3. Adds new API `e2e.rejectSuggestedGroupKey` to be called to reject the suggested key and clear the `E2ESuggestedKey` + +- SAML and OAuth role sync to support id and name ([#27405](https://github.com/RocketChat/Rocket.Chat/pull/27405)) + + This PR allows the sync of roles by either `name` or `id`. + +- Save toPhone when receiving SMSs ([#27656](https://github.com/RocketChat/Rocket.Chat/pull/27656)) + +- Setup Wizard Flow for airgapped environment ([#28018](https://github.com/RocketChat/Rocket.Chat/pull/28018)) + + ![image](https://user-images.githubusercontent.com/40830821/217655867-ddfbd99f-e0b8-4c71-9a33-b06555bb97dc.png) + ![image](https://user-images.githubusercontent.com/40830821/217655885-b84a92b6-da9f-4f57-b4ef-297e8541ded3.png) + +- Spanish home translation ([#27898](https://github.com/RocketChat/Rocket.Chat/pull/27898) by [@nYCSTs](https://github.com/nYCSTs)) + + Update translation of home page to Spanish. The page had some untranslated texts. + ![image](https://user-images.githubusercontent.com/63932475/215656626-5fbeb5b6-e398-4dd4-a150-ec69305ebb56.png) + +- User data download overhaul ([#26358](https://github.com/RocketChat/Rocket.Chat/pull/26358)) + + It migrates modules to TypeScript, as well adapts the code to the current version of Node. + +### 🐛 Bug fixes + + +- "Jump to first unread" banner does not always appear when the first unread message is outside of the visible screen ([#27941](https://github.com/RocketChat/Rocket.Chat/pull/27941)) + +- **ENTERPRISE:** DDP streamer sending data to destroyed streams ([#27929](https://github.com/RocketChat/Rocket.Chat/pull/27929)) + +- `*.files` endpoints returning hidden files ([#27617](https://github.com/RocketChat/Rocket.Chat/pull/27617)) + +- Access to localStorage in Livechat ([#27627](https://github.com/RocketChat/Rocket.Chat/pull/27627) by [@jschirrmacher](https://github.com/jschirrmacher)) + + This fixes access to localStorage in LiveChat, if the user has third party coockies disabled. + +- Add the possibility of danger style prop to close button on UiKit contextual-bar component ([#27533](https://github.com/RocketChat/Rocket.Chat/pull/27533)) + + image + +- Announcement banner link opening in the same page ([#27554](https://github.com/RocketChat/Rocket.Chat/pull/27554)) + + Channel Announcements that contain links are opening on the same page instead of a new page/tab causing render issues, especially on the desktop client. + + The fix was simple to add a hook for the `dompurify` library to add the `target` and `rel` attributes to keep the _blank behavior. + + Also, it introduced some parsers settings to `inlineWithoutBreaks` variant to avoid breaking messages at Announcements and other places that uses this variant. + +- Anonymous user buttons ([#27551](https://github.com/RocketChat/Rocket.Chat/pull/27551)) + + When the server accepts an anonymous user to join and chat without login, two buttons appears: one for Login and the other to send messages without login. + + The component was rewritten to use the fuselage Design System and native hooks to perform actions. + + ![image](https://user-images.githubusercontent.com/20212776/207855313-97d0e2dc-b24d-4baf-b6b5-214aed4be6f1.png) + +- App page showing version undefined for apps not in marketplace ([#27766](https://github.com/RocketChat/Rocket.Chat/pull/27766)) + + The app page is not showing the correct version of apps that are installed in the workspace but not in the Marketplace. + + This PR changes the behavior so that the page shows the version that is installed in the workspace; otherwise, it shows the version in the marketplace + +- Auto Translate not working on new message template ([#27317](https://github.com/RocketChat/Rocket.Chat/pull/27317)) + + - Fix auto translate not working on new message template; + - Fix a bug that the auto-translate icon was showing for users who didn't have enabled. + - Show translated quote messages; + - Remove translation provider for end users. + - Translate the ThreadMessagePreview component + +- Black screen when try to open a chat with a non-existent department ([#27609](https://github.com/RocketChat/Rocket.Chat/pull/27609)) + +- Broken settings check for updates ([#27779](https://github.com/RocketChat/Rocket.Chat/pull/27779)) + +- Comunity users accessing exclusive ee endpoints in omnichannel section ([#27876](https://github.com/RocketChat/Rocket.Chat/pull/27876)) + +- Custom fields does not appear on the registration form ([#28031](https://github.com/RocketChat/Rocket.Chat/pull/28031)) + +- Custom languages not being applied to i18next ([#27557](https://github.com/RocketChat/Rocket.Chat/pull/27557)) + +- Disable video call on read-only rooms for not allowed users ([#27789](https://github.com/RocketChat/Rocket.Chat/pull/27789)) + + Jira Issue [VC-58] + +- Discussion visibility when inside a private team. ([#27601](https://github.com/RocketChat/Rocket.Chat/pull/27601)) + + Create discussions as private when the public channel is inside a private team. + +- E2EE initial banner not showing ([#27574](https://github.com/RocketChat/Rocket.Chat/pull/27574)) + +- Embedded layout opening sidebar ([#27892](https://github.com/RocketChat/Rocket.Chat/pull/27892)) + + In the embedded layout view, certain actions were opening the sidebar due to the missing query param mandatory to the embedded layout view (`?layout=embedded`) + + In addition to this issue, the user was able to navigate to different pages in the embedded layout causing them to get stuck on some other pages other than the Room page. Because of the reported issue, I removed some actions that redirect the user to other pages such as: "Reply in Direct Message" + +- Emoji rendering on reactions ([#27863](https://github.com/RocketChat/Rocket.Chat/pull/27863)) + +- Empty DMs go to sidebar's top after updating user preferences ([#27912](https://github.com/RocketChat/Rocket.Chat/pull/27912)) + + - Do not use `_updatedAt` as `lm` field when merging info from subscriptions and rooms (since this field is updated along with the user preferences). + +- File upload modal not opening after too long message modal ([#28212](https://github.com/RocketChat/Rocket.Chat/pull/28212)) + + - Close the 'too long message to attachment' modal before opening the 'file upload' modal + +- Filtering users by status username is broken in Administration -> Users ([#27706](https://github.com/RocketChat/Rocket.Chat/pull/27706)) + +- Fix emoji appearance on sidebar ([#27580](https://github.com/RocketChat/Rocket.Chat/pull/27580)) + + The emojis appear in plain text format in the side-bar (As seen in the below issues) + By this PR, it should be fixed + + This is how it looks now (As shown on the sidebar, it's appearing as an emoji not plaintext) + ![image](https://user-images.githubusercontent.com/34144004/163888602-7df27713-0a82-443e-8944-f48525232ca8.png) + +- Fix Login with Show default form disabled ([#27475](https://github.com/RocketChat/Rocket.Chat/pull/27475)) + +- Fix typo when create discussion modal opens ([#24982](https://github.com/RocketChat/Rocket.Chat/pull/24982)) + + Fixed typo when discussion modal opens. Now it says - Help keep an overview of what's going on! + + ![Screenshot 2022-03-29 at 6 59 45 PM](https://user-images.githubusercontent.com/74371312/160625549-8de71046-07bd-493f-ab7b-066d3653c16f.png) + +- Google Cloud Storage storage type ([#26851](https://github.com/RocketChat/Rocket.Chat/pull/26851) by [@carlosrodrigues94](https://github.com/carlosrodrigues94)) + + Google Cloud Storage now requires a "project ID" to be filled. + + Useful links: + + https://googleapis.dev/nodejs/storage/latest/global.html#StorageOptions + https://support.google.com/googleapi/answer/7014113?hl=en + +- Ignored messages reactivity ([#27279](https://github.com/RocketChat/Rocket.Chat/pull/27279)) + +- Invalid regex on search fields crashes UI ([#27942](https://github.com/RocketChat/Rocket.Chat/pull/27942)) + +- IPostMessageReacted return field named isReacted instead isRemoved ([#27561](https://github.com/RocketChat/Rocket.Chat/pull/27561) by [@Nabhag8848](https://github.com/Nabhag8848)) + +- Marketplace app status initially disabled ([#27330](https://github.com/RocketChat/Rocket.Chat/pull/27330)) + + ## Jira task: [MKP-20](https://rocketchat.atlassian.net/browse/MKP-20?atlOrigin=eyJpIjoiZTA3YWU5MGYwMDU1NDQ0MGJiNzQyMjYxZmMwMWVmMWQiLCJwIjoiaiJ9) + + Currently, the only apps engine statuses considered enabled in the UI are the auto-enabled and manually-enabled statuses, this causes a UX problem in which the app will be considered disabled for the first few seconds of its lifecycle, upon the first installation in a workspace, since it will have the apps engine status of initialized. This PR adds the initialized status to the appEnabledStatuses list and solves this problem. + Demo gif: + ![disabled_status_issue_solution](https://user-images.githubusercontent.com/43561537/204306496-961384c3-ec24-4959-90cd-03f4638be948.gif)\ + +- Message Actions menu does not close upon choosing an action ([#27328](https://github.com/RocketChat/Rocket.Chat/pull/27328)) + +- Message for VideoConf on SidebarItemExtended ([#27626](https://github.com/RocketChat/Rocket.Chat/pull/27626)) + + Jitsi Issue: [VC-30] + + ### before + ![Screen Shot 2022-12-23 at 11 38 24](https://user-images.githubusercontent.com/27704687/209353143-bef571c6-c79d-4489-828b-0f33ecddb5b7.png) + + ### after + ![Screen Shot 2022-12-23 at 11 36 09](https://user-images.githubusercontent.com/27704687/209352853-c977ae04-3074-47bd-842b-70f3118a175b.png) + +- Message-parser link issues ([#27947](https://github.com/RocketChat/Rocket.Chat/pull/27947)) + + The changes were made in the fuselage repository. This PR just update the message-parser package version + Check the changes in this PR: + https://github.com/RocketChat/fuselage/pull/962 + +- Missing placeholders from encrypted channel preview messages now with expected behavior ([#27699](https://github.com/RocketChat/Rocket.Chat/pull/27699)) + + Referent to [TC-259] + + ![Clipboard screenshot](https://user-images.githubusercontent.com/47800334/211094753-30434b6d-46aa-490a-9b27-59770cf0ff24.png) + Note that now the file uses `isE2EEMessage()` function and the `useTranslation` internal hook. + +- Move Omni startup to be EE wrapped ([#28020](https://github.com/RocketChat/Rocket.Chat/pull/28020)) + +- New users aren't mapped to rooms with OAuth groups/channels map ([#27000](https://github.com/RocketChat/Rocket.Chat/pull/27000) by [@carlosrodrigues94](https://github.com/carlosrodrigues94)) + + This change deals with the problem with the new users coming from key cloak, this users were not being mapped to the correct channels on RC. + +- Not all messages in chat conversations are available when forwarding between agents or departments. ([#27816](https://github.com/RocketChat/Rocket.Chat/pull/27816)) + +- Notify apps engine event through ms api ([#28169](https://github.com/RocketChat/Rocket.Chat/pull/28169)) + + The Apps-Engine must drop the current Streamer utilization and start using the Service APIs to correctly communicate between instances and client-server. + +- Omnichannel call provider option ([#27466](https://github.com/RocketChat/Rocket.Chat/pull/27466)) + + Jira Issue: [VC-38] + +- OmnichannelRoomIconProvider order breaking VideoConfPopup ([#27740](https://github.com/RocketChat/Rocket.Chat/pull/27740)) + + Jira Issue [VC-39] + +- Option to Join Read-Only Channels ([#27488](https://github.com/RocketChat/Rocket.Chat/pull/27488) by [@henit-chobisa](https://github.com/henit-chobisa)) + +- Pagination not working on current chats ([#27432](https://github.com/RocketChat/Rocket.Chat/pull/27432)) + +- Reduce re-subscription on `notify-room/user-activity` stream event ([#27911](https://github.com/RocketChat/Rocket.Chat/pull/27911)) + + Whenever something changed the room subscription, it would trigger a re-subscription to `notify-room/user-activity`. + +- Register Workspace UI fixes and fix doc link ([#28021](https://github.com/RocketChat/Rocket.Chat/pull/28021)) + +- Registration and Login placeholders not being used ([#27558](https://github.com/RocketChat/Rocket.Chat/pull/27558)) + +- Remove invalid settings at startup ([#27653](https://github.com/RocketChat/Rocket.Chat/pull/27653)) + +- Remove unnecessary permissions check on app permissions review modal ([#27329](https://github.com/RocketChat/Rocket.Chat/pull/27329)) + + ## Jira task: [MKP-166](https://rocketchat.atlassian.net/browse/MKP-166?atlOrigin=eyJpIjoiYzdjNzVhMThkOThjNGEzMmIyYTE2YmY2ZDA1MzA4YjEiLCJwIjoiaiJ9) + Removed an unnecessary check that verified if the app permissions list was an array and threw an error if it wasn't. This check has become unnecessary ever since the app permission review modal changed to show a default list of permissions in case the app happened to not have one and that's what caused those "random" undefined toasts that showed every once in a while. + Demo gif: + ![undefined_toast](https://user-images.githubusercontent.com/43561537/203644331-be9583e1-a92d-46a8-ab3b-add875e7a646.gif) + +- room data is not erased after deleting rooms by app ([#27886](https://github.com/RocketChat/Rocket.Chat/pull/27886)) + +- RoomLeader status not working ([#27576](https://github.com/RocketChat/Rocket.Chat/pull/27576)) + + It also fixes some visual issues + + ### before + ![image](https://user-images.githubusercontent.com/27704687/208500278-85c705a2-e10a-416f-a4e5-afda34e2650f.png) + + ### after + ![image](https://user-images.githubusercontent.com/27704687/208500309-d4aaa116-268b-4240-9422-abff98da898c.png) + +- Save button does not stay disabled in Notification Preferences for no change on mute group option ([#27513](https://github.com/RocketChat/Rocket.Chat/pull/27513) by [@xareyli](https://github.com/xareyli)) + + Added default value for "Mute @all and @here mentions" option + +- Search list missing key parameter ([#28230](https://github.com/RocketChat/Rocket.Chat/pull/28230)) + +- Showing thumbnails on files list ([#23301](https://github.com/RocketChat/Rocket.Chat/pull/23301) by [@carlosrodrigues94](https://github.com/carlosrodrigues94)) + +- Showing Workspace Section For User Having LiveChat Manager Permission ([#27188](https://github.com/RocketChat/Rocket.Chat/pull/27188)) + +- Team mention highlight EE ([#27493](https://github.com/RocketChat/Rocket.Chat/pull/27493)) + + The team Mentioned highlighted with the char `@` was not working in Enterprise Edition using the new message parser. + + I added validation to the filter by `type: 'team'` and fixed the title to include the team name on mouse hover. + + **Previous:** + image + + + **NOW:** + image + +- Toast notification ignoring 403 errors ([#27624](https://github.com/RocketChat/Rocket.Chat/pull/27624)) + +- Tokens usage ([#27541](https://github.com/RocketChat/Rocket.Chat/pull/27541)) + +- Unintended "Reply on thread" button showing on thread's first message ([#27716](https://github.com/RocketChat/Rocket.Chat/pull/27716)) + + Referent to TC-128 + + #### Before: + ![image](https://user-images.githubusercontent.com/47800334/211622867-5d24a4c9-172b-4b36-aac9-cea1af3f925a.png) + + #### After: + ![image](https://user-images.githubusercontent.com/47800334/211622729-14e8c552-615c-44e3-b5ae-8e815909e5ac.png) + +- Unread Message count not displayed for new messages in Omni-Rooms ([#27539](https://github.com/RocketChat/Rocket.Chat/pull/27539)) + +- User registration with EmailConfirmation not working ([#28143](https://github.com/RocketChat/Rocket.Chat/pull/28143)) + +- Video Conf Message Blocks not always updating when running on micro services ([#27764](https://github.com/RocketChat/Rocket.Chat/pull/27764)) + +
+🔍 Minor changes + + +- Bump version to 6.0.0-develop ([#27598](https://github.com/RocketChat/Rocket.Chat/pull/27598)) + +- Chore: Threads as React components ([#27524](https://github.com/RocketChat/Rocket.Chat/pull/27524)) + +- Chore: `desktop` icon instead of `computer` icon ([#27959](https://github.com/RocketChat/Rocket.Chat/pull/27959)) + +- Chore: Add dark theme assets ([#28214](https://github.com/RocketChat/Rocket.Chat/pull/28214)) + +- Chore: add e2e test coverage for Video Conference ([#27075](https://github.com/RocketChat/Rocket.Chat/pull/27075) by [@lingohub[bot]](https://github.com/lingohub[bot])) + + Jira Issue: [VC-49] + +- Chore: Add E2E tests to Triggers view ([#27413](https://github.com/RocketChat/Rocket.Chat/pull/27413)) + +- Chore: Add Eslint rules to tests ([#28074](https://github.com/RocketChat/Rocket.Chat/pull/28074)) + +- Chore: Add extra stats for omnichannel video calling ([#28211](https://github.com/RocketChat/Rocket.Chat/pull/28211)) + +- Chore: Add hint (description) to CodeSettingInput after label ([#27843](https://github.com/RocketChat/Rocket.Chat/pull/27843)) + + - Added hint (description) to CodeSettingInput after label + - Created a storybook story for that scenario + - add a checker to not add hint to`` if the inputType is `code` + + **Before:** + ![image](https://user-images.githubusercontent.com/20212776/214575455-f2073084-bc10-4e55-9eb2-99bc9fcb71a3.png) + + **After:** + ![image](https://user-images.githubusercontent.com/20212776/214622377-eb706c31-909f-4b25-ae2e-71cff70f80b2.png) + +- Chore: Add quote message option back on live chat rooms ([#28038](https://github.com/RocketChat/Rocket.Chat/pull/28038)) + +- Chore: Add spacing adjustments Home page ([#27367](https://github.com/RocketChat/Rocket.Chat/pull/27367)) + + - Spacings adjustments in homepage + +- Chore: Add surface-light background to AppRow ([#27765](https://github.com/RocketChat/Rocket.Chat/pull/27765)) + + In light of the recent changes to the fuselage color system, the AppRow went from having a default background color of white to not having a color. Because of this, I've added the bg='surface-light' prop to the Wrapper box of the component. + Before: + ![image](https://user-images.githubusercontent.com/43561537/212754530-ab847cc2-9026-45e3-a138-14c3c657f373.png) + + After: + ![image](https://user-images.githubusercontent.com/43561537/212754573-010bb538-7a2d-4db2-889d-933cc907a9f1.png) + +- Chore: Added Enterprise Options to Login customization ([#27855](https://github.com/RocketChat/Rocket.Chat/pull/27855)) + +- Chore: Adjust ProgressBar usage ([#27832](https://github.com/RocketChat/Rocket.Chat/pull/27832)) + +- Chore: anonymous e2e test dispatch error ([#28171](https://github.com/RocketChat/Rocket.Chat/pull/28171)) + +- Chore: AppsTable UI Tweaks ([#27629](https://github.com/RocketChat/Rocket.Chat/pull/27629)) + + ### before + ![Kapture 2022-12-23 at 16 00 51](https://user-images.githubusercontent.com/27704687/209394897-0217725b-25b2-4d70-a7eb-404b7f158a31.gif) + + + ### after + ![Kapture 2022-12-23 at 15 59 21](https://user-images.githubusercontent.com/27704687/209394759-0e703463-3d19-43b5-9aa7-b18c4c4cbdef.gif) + +- Chore: Aria busy indicators ([#27978](https://github.com/RocketChat/Rocket.Chat/pull/27978)) + +- Chore: Bump message-parser version and fix typerrors ([#27643](https://github.com/RocketChat/Rocket.Chat/pull/27643)) + + Bumping message-parser version and fix gazzodown package errors. + +- Chore: Change bundle tags color and refactor app details page header styles ([#27293](https://github.com/RocketChat/Rocket.Chat/pull/27293)) + + Increased the right side margin of the app avatar, removed the 'by' substring from the app author metadata, and changed the font scale and colors for the metadata section and short description. + Demo image: + ![image](https://user-images.githubusercontent.com/43561537/202550456-41bc5216-5f6f-4a15-a38e-2e220f8ab3b5.png) + +- Chore: change colors to dark theme on Marketplace ([#27532](https://github.com/RocketChat/Rocket.Chat/pull/27532)) + + Fixed some bugs on the new dark theme in the Marketplace page. The new version looks like this now: + + ![new-version](https://user-images.githubusercontent.com/84182706/207443296-b9466105-7dfb-46eb-8f71-eee113c3532b.png) + +- Chore: Change Omnichannel aggregations to run on a secondary ([#25346](https://github.com/RocketChat/Rocket.Chat/pull/25346)) + +- Chore: CI improvements ([#28076](https://github.com/RocketChat/Rocket.Chat/pull/28076)) + +- Chore: Composer missing Slash Command preview ([#27652](https://github.com/RocketChat/Rocket.Chat/pull/27652)) + +- Chore: Composer Quote Component ([#27604](https://github.com/RocketChat/Rocket.Chat/pull/27604)) + + ### before + Screen Shot 2022-12-26 at 11 01 17 + + ### after + ![image](https://user-images.githubusercontent.com/27704687/209555642-ca6bdda0-a3f8-4dc1-a34c-d1fb57539b47.png) + +- Chore: Composer Styling ([#27620](https://github.com/RocketChat/Rocket.Chat/pull/27620)) + +- Chore: Composer wrapper around the textarea ([#27658](https://github.com/RocketChat/Rocket.Chat/pull/27658)) + +- Chore: Convert UserTable on Directory to TS ([#27534](https://github.com/RocketChat/Rocket.Chat/pull/27534) by [@nYCSTs](https://github.com/nYCSTs)) + + Rewrote the UserTable component to TS. + +- Chore: Create service template ([#27519](https://github.com/RocketChat/Rocket.Chat/pull/27519)) + +- Chore: Custom emoji empty state ([#27641](https://github.com/RocketChat/Rocket.Chat/pull/27641)) + + It also replace `useEndpointData` in favor of `useQuery` + ### before + ![Screen Shot 2022-12-26 at 15 43 59](https://user-images.githubusercontent.com/27704687/209576037-93744632-a74f-4b0c-926d-b444cf4601e2.png) + + ### after + ![Screen Shot 2022-12-26 at 15 43 08](https://user-images.githubusercontent.com/27704687/209576006-4f2f1928-3532-4f42-88fa-ba661a2b7715.png) + +- Chore: Custom Sounds Empty State ([#27632](https://github.com/RocketChat/Rocket.Chat/pull/27632)) + + It also replace `useEndpointData` in favor of `useQuery` + + ### before + ![Screen Shot 2022-12-23 at 17 32 35](https://user-images.githubusercontent.com/27704687/209403136-791a8196-93f3-4fa6-8519-1d48a1d17430.png) + + ### after + ![Screen Shot 2022-12-23 at 17 31 50](https://user-images.githubusercontent.com/27704687/209403089-8f426d3e-c09d-447a-93a7-0e50ea97c0ca.png) + +- Chore: Deprecate unused omnichannel API ([#27538](https://github.com/RocketChat/Rocket.Chat/pull/27538)) + +- Chore: Do not rely on external service on tests ([#27874](https://github.com/RocketChat/Rocket.Chat/pull/27874)) + +- Chore: e2e changes tests ([#27987](https://github.com/RocketChat/Rocket.Chat/pull/27987)) + +- Chore: e2e omnichannel tests - Close every opened page after the test ([#28152](https://github.com/RocketChat/Rocket.Chat/pull/28152)) + +- Chore: E2E tests small corrections ([#28066](https://github.com/RocketChat/Rocket.Chat/pull/28066)) + +- Chore: EmojiPicker Wrapper Styles ([#28049](https://github.com/RocketChat/Rocket.Chat/pull/28049)) + +- Chore: ExportMessages missing icon ([#27628](https://github.com/RocketChat/Rocket.Chat/pull/27628)) + +- Chore: FileItem hover color ([#27600](https://github.com/RocketChat/Rocket.Chat/pull/27600)) + +- Chore: Fix babel config related to TypeScript `declare` usage ([#28029](https://github.com/RocketChat/Rocket.Chat/pull/28029)) + +- Chore: Fix CI Docker Alpine build missing ([#28138](https://github.com/RocketChat/Rocket.Chat/pull/28138)) + +- Chore: Fix CI docker publish ([#28134](https://github.com/RocketChat/Rocket.Chat/pull/28134)) + +- Chore: Fix e2e EE tests not working reliably ([#28061](https://github.com/RocketChat/Rocket.Chat/pull/28061)) + +- Chore: fix e2e Omnichannel tests ([#28097](https://github.com/RocketChat/Rocket.Chat/pull/28097)) + +- Chore: Fix Email Inbox flaky test ([#28294](https://github.com/RocketChat/Rocket.Chat/pull/28294)) + +- Chore: fix EmailInbox intermittent e2e tests ([#27573](https://github.com/RocketChat/Rocket.Chat/pull/27573)) + +- Chore: Fix fetching Apps-Engine and MongoDB versions for release notes ([#28129](https://github.com/RocketChat/Rocket.Chat/pull/28129)) + +- Chore: Fix homepage grid items style ([#27527](https://github.com/RocketChat/Rocket.Chat/pull/27527)) + + - Change homepage card border-radius from 4px to 8px + +- Chore: Improve `ts-node` startup time with `swc` ([#27686](https://github.com/RocketChat/Rocket.Chat/pull/27686)) + +- Chore: improve global setup e2e ([#28087](https://github.com/RocketChat/Rocket.Chat/pull/28087)) + +- Chore: Improve service's licence check ([#27872](https://github.com/RocketChat/Rocket.Chat/pull/27872)) + +- Chore: improve some e2e selectors ([#27936](https://github.com/RocketChat/Rocket.Chat/pull/27936)) + +- Chore: Improve time of meteor build ([#28128](https://github.com/RocketChat/Rocket.Chat/pull/28128)) + +- Chore: Invites Empty State ([#27631](https://github.com/RocketChat/Rocket.Chat/pull/27631)) + + It also replace `useEndpointData` in favor of `useQuery` + ### before + ![Screen Shot 2022-12-23 at 16 49 45](https://user-images.githubusercontent.com/27704687/209399990-95b15ba3-0ba9-4ae4-92fa-fed4c1d39d31.png) + + ### after + ![Screen Shot 2022-12-23 at 16 48 27](https://user-images.githubusercontent.com/27704687/209399874-1c38f206-c385-49f5-8050-7b4f7b55bd7a.png) + +- Chore: KeyboardShortCut color ([#27599](https://github.com/RocketChat/Rocket.Chat/pull/27599)) + + + + + +- Chore: Livechat convert emoji to ts ([#27425](https://github.com/RocketChat/Rocket.Chat/pull/27425)) + +- Chore: Manually define shared secrets to reusable workflows ([#28315](https://github.com/RocketChat/Rocket.Chat/pull/28315)) + +- Chore: Message search changes ([#28001](https://github.com/RocketChat/Rocket.Chat/pull/28001)) + +- Chore: Migrate cached collections to TypeScript ([#27909](https://github.com/RocketChat/Rocket.Chat/pull/27909)) + +- Chore: More E2E tests for PDF transcript feature of Omnichannel ([#28110](https://github.com/RocketChat/Rocket.Chat/pull/28110)) + +- Chore: Move all variables to first step and reduce code duplication ([#28106](https://github.com/RocketChat/Rocket.Chat/pull/28106)) + +- Chore: move PaletteStyleTag ([#28086](https://github.com/RocketChat/Rocket.Chat/pull/28086)) + +- Chore: Move service definitions to core services package ([#27546](https://github.com/RocketChat/Rocket.Chat/pull/27546)) + +- Chore: Move service shutdown logic to each service ([#27690](https://github.com/RocketChat/Rocket.Chat/pull/27690)) + +- Chore: Notify Marketplace on App Install ([#27925](https://github.com/RocketChat/Rocket.Chat/pull/27925)) + + Notifies Rocket.Chat's Marketplace of an app install action. This correlates with the app request flow. + +- Chore: OAuth authorization pages reconditioned ([#28085](https://github.com/RocketChat/Rocket.Chat/pull/28085)) + +- Chore: Omnichannel Sidebar icons alignment ([#27501](https://github.com/RocketChat/Rocket.Chat/pull/27501)) + +- Chore: Playwright test improvements ([#28100](https://github.com/RocketChat/Rocket.Chat/pull/28100)) + +- Chore: Presence cap tweaks ([#28058](https://github.com/RocketChat/Rocket.Chat/pull/28058)) + +- Chore: Purge styles of the legacy `message` template ([#28126](https://github.com/RocketChat/Rocket.Chat/pull/28126)) + +- Chore: QoL improvements to Omnichannel E2E tests ([#28075](https://github.com/RocketChat/Rocket.Chat/pull/28075)) + +- Chore: Reduce Less usage in theming ([#27689](https://github.com/RocketChat/Rocket.Chat/pull/27689)) + + This PR is a preparation for a coming breaking change on layout colors. + +- Chore: Refactor `AudioMessageRecorder` ([#28019](https://github.com/RocketChat/Rocket.Chat/pull/28019)) + + [DSA-11] + + ![Kapture 2023-02-13 at 17 24 54](https://user-images.githubusercontent.com/27704687/218567103-1090cf5c-61d1-4bd9-8c0a-d582d614ef85.gif) + +- Chore: Refactor `VideoMessageRecorder` ([#27850](https://github.com/RocketChat/Rocket.Chat/pull/27850)) + + Jira Issue: [DSA-2] + ### before + + + ### after + + +- Chore: Refactor CI to improve code reusability and organization ([#28108](https://github.com/RocketChat/Rocket.Chat/pull/28108)) + +- Chore: Refactor Composer Collapsed Formatters and Actions ([#28039](https://github.com/RocketChat/Rocket.Chat/pull/28039)) + + [DSA-19] + + ![Kapture 2023-02-14 at 14 05 19](https://user-images.githubusercontent.com/27704687/218807178-4c280e92-67f2-48ec-afa3-e5b2948120f2.gif) + +- Chore: Refactor Composer Dropdown ([#27931](https://github.com/RocketChat/Rocket.Chat/pull/27931)) + + ![Screen Shot 2023-02-01 at 17 59 31](https://user-images.githubusercontent.com/27704687/216162082-ea258bb8-5629-4898-a410-6162a0fa008e.png) + +- Chore: Refactor Composer Popup ([#28013](https://github.com/RocketChat/Rocket.Chat/pull/28013)) + +- Chore: Refactor CreateChannelModal ([#27469](https://github.com/RocketChat/Rocket.Chat/pull/27469)) + + Jira Issue: [UFR-11] + + - Replace `useForm` + - Improve UI validations on Modal + - Add ToastBar message on creating a channel + - Fixes `topic` field not being added properly + +- Chore: Refactor Directory Tables ([#27646](https://github.com/RocketChat/Rocket.Chat/pull/27646)) + + It also replaces `useEndpointData` in favor of `useQuery` + +- Chore: Refactor e2e selectors to use roles ([#27582](https://github.com/RocketChat/Rocket.Chat/pull/27582)) + +- Chore: Refactor message subcomponents ([#27630](https://github.com/RocketChat/Rocket.Chat/pull/27630)) + +- Chore: Refactor other kinds of message - Phase 1 ([#27712](https://github.com/RocketChat/Rocket.Chat/pull/27712)) + + It pays some technical debts on APIs consumed by message-related components. + +- Chore: Refactor other kinds of message - Phase 2 ([#27927](https://github.com/RocketChat/Rocket.Chat/pull/27927)) + + Migrate "Starred Messages", "Pinned Messages", and "Mentions" from Blaze templates to React components. + +- Chore: Refactor useThemeMode in favor of userPreferences ([#28063](https://github.com/RocketChat/Rocket.Chat/pull/28063)) + +- Chore: Remove `body` template ([#28064](https://github.com/RocketChat/Rocket.Chat/pull/28064)) + +- Chore: Remove `meteor build --debug` option ([#28170](https://github.com/RocketChat/Rocket.Chat/pull/28170)) + +- Chore: Remove duplicated functions in tests ([#28336](https://github.com/RocketChat/Rocket.Chat/pull/28336)) + +- Chore: Remove fail-fast from matrix strategy ([#28153](https://github.com/RocketChat/Rocket.Chat/pull/28153)) + +- Chore: Remove medium prop from ButtonGroup ([#27784](https://github.com/RocketChat/Rocket.Chat/pull/27784)) + +- Chore: Remove method meteor call on message action ([#26213](https://github.com/RocketChat/Rocket.Chat/pull/26213)) + +- Chore: Remove old tooltip usage ([#26882](https://github.com/RocketChat/Rocket.Chat/pull/26882)) + +- Chore: Remove Sidebar from Blaze ([#27571](https://github.com/RocketChat/Rocket.Chat/pull/27571)) + +- Chore: Remove unused Blaze templates after message rewrite ([#28025](https://github.com/RocketChat/Rocket.Chat/pull/28025)) + +- Chore: Remove unused templates and bump fuselage ([#27606](https://github.com/RocketChat/Rocket.Chat/pull/27606)) + +- Chore: Replace borders to `default` ([#27667](https://github.com/RocketChat/Rocket.Chat/pull/27667)) + +- Chore: Replace deprecated color tokens ([#28164](https://github.com/RocketChat/Rocket.Chat/pull/28164)) + +- Chore: Restrict `ChatMessages API` - Phase 2 ([#27457](https://github.com/RocketChat/Rocket.Chat/pull/27457)) + + It split `ChatMessages` service class into a collection of smaller objects, in a composition pattern fashion. Additionally, it loosens its dependency on the DOM tree and assumes almost all methods are asynchronous. + +- Chore: Restrict legacy message events ([#27691](https://github.com/RocketChat/Rocket.Chat/pull/27691)) + + This PR aims to fix conflicts between the legacy messages and the new ones, specially click events on threads. + +- Chore: RoomAutocomplete Debounce Query ([#28083](https://github.com/RocketChat/Rocket.Chat/pull/28083)) + +- Chore: Service cap ([#28022](https://github.com/RocketChat/Rocket.Chat/pull/28022)) + +- Chore: Set missing colors ([#27817](https://github.com/RocketChat/Rocket.Chat/pull/27817)) + +- Chore: Settings regenerator on migration ([#27661](https://github.com/RocketChat/Rocket.Chat/pull/27661)) + +- Chore: Show different labels based on the call originator on direct calls ([#27729](https://github.com/RocketChat/Rocket.Chat/pull/27729)) + + Jira Issue: [VC-26] + +- Chore: Sidebar theme ([#27426](https://github.com/RocketChat/Rocket.Chat/pull/27426)) + +- Chore: SlashCommands Preview ([#28065](https://github.com/RocketChat/Rocket.Chat/pull/28065)) + +- Chore: Sync `develop` with `master` ([#28043](https://github.com/RocketChat/Rocket.Chat/pull/28043) by [@carlosrodrigues94](https://github.com/carlosrodrigues94) & [@ostjen](https://github.com/ostjen)) + +- Chore: test turbo cache action ([#28082](https://github.com/RocketChat/Rocket.Chat/pull/28082)) + +- Chore: Token refactor ([#27655](https://github.com/RocketChat/Rocket.Chat/pull/27655)) + +- Chore: TwoFactorPass Modals icon misalignment ([#27591](https://github.com/RocketChat/Rocket.Chat/pull/27591)) + + ### before + Screen Shot 2022-12-20 at 21 05 24 + + ### after + Screen Shot 2022-12-20 at 21 04 29 + +- Chore: Update color tokens ([#27704](https://github.com/RocketChat/Rocket.Chat/pull/27704)) + + Jira issues: + [DSA-25](https://rocketchat.atlassian.net/browse/DSA-25) + [DSA-26](https://rocketchat.atlassian.net/browse/DSA-26) + [DSA-27](https://rocketchat.atlassian.net/browse/DSA-27) + [DSA-28](https://rocketchat.atlassian.net/browse/DSA-28) + [DSA-30](https://rocketchat.atlassian.net/browse/DSA-30) + + - [x] Fix ScreenshotCarousel tokens + - [x] Replace ScreenshotCarousel Button with IconButton secondary + - [x] Fix UsagePieGraph tokens + - [x] Fix Page.tsx tokens + - [x] Fix VoipFooter tokens + - [x] Fix DeviceIcon token + - [x] Fix SidebarFooterWatermark token + - [x] Fix PaletteDark button hover bg color + - [x] Fix MessageComposerActionsDivider token + - [x] Fix room Announcement colors + - [x] Apply surface-room + - [x] Replace all deprecated Box color tokens usage + - [x] Replace all deprecated Box bg tokens usage + +- Chore: Update ESlint rules of client code ([#27427](https://github.com/RocketChat/Rocket.Chat/pull/27427)) + +- Chore: Update Some Composer Icons ([#27862](https://github.com/RocketChat/Rocket.Chat/pull/27862)) + + Jira Issue [DSA-20] + + ### before + ![Screen Shot 2023-01-26 at 18 09 19](https://user-images.githubusercontent.com/27704687/214950981-794d1f23-b33f-4fcf-9ab1-f042925e5639.png) + + ### after + ![Screen Shot 2023-01-26 at 18 08 28](https://user-images.githubusercontent.com/27704687/214950829-357ea6eb-9fde-4144-8819-5052e21ae604.png) + +- Chore: Update tokens ([#28079](https://github.com/RocketChat/Rocket.Chat/pull/28079)) + +- Chore: Update tsconfig base target to es2020 ([#27552](https://github.com/RocketChat/Rocket.Chat/pull/27552)) + + The base files are not split into two other files, a "client" and a "server" file. Both extends the new base one. Packages should extend either "client" or "server" ones: + + ```mermaid + graph TD; + base[tsconfig.base.json]-->client[tsconfig.base.client.json]; + base-->server[tsconfig.base.server.json]; + server-->s1["@rocket.chat/models"]; + server-->s2["@rocket.chat/ddp-streamer"]; + server-->s3[...]; + client-->c1["@rocket.chat/ui-theming"]; + client-->c2["@rocket.chat/fuselage-ui-kit"]; + client-->c3[...]; + ``` + + Important changes: + + - The client config `target` have been bumped to `es2015` (it was `es5` before) + - The server config `target` have been bumped to `es2020` + - The default value for `jsx` is `react-jsx` + - Raised `"noUnusedLocals": true` to a base config, so had to remove a bunch of imports to `React` that were not being used + +- Chore: Upgrade `mongodb` typings ([#27424](https://github.com/RocketChat/Rocket.Chat/pull/27424)) + + It upgrades the `mongodb` package to overcome the circular reference issue of `IMessage`. + +- Chore: Upgrade EE license for CI ([#27682](https://github.com/RocketChat/Rocket.Chat/pull/27682)) + +- Chore: use useQuery in place of deprecated useEndpointData ([#27673](https://github.com/RocketChat/Rocket.Chat/pull/27673) by [@Dnouv](https://github.com/Dnouv)) + + Chore done: + useEndpointData -> useEndpoint for: + + - `/apps/meteor/client/views/admin/` + - `apps` + - `customEmoji` + - `customSounds` + - `customUserStatus` + - `integrations` + - `invites` + - `oauthApps` + - `permissions` + - `rooms` + - `users` + +- Chore: Wait message to not be Busy ([#28000](https://github.com/RocketChat/Rocket.Chat/pull/28000)) + +- Chore(deps): Bump thehanimo/pr-title-checker from 1.3.4 to 1.3.6 ([#27884](https://github.com/RocketChat/Rocket.Chat/pull/27884) by [@dependabot[bot]](https://github.com/dependabot[bot])) + +- i18n: Language update from LingoHub 🤖 on 2022-12-05Z ([#27450](https://github.com/RocketChat/Rocket.Chat/pull/27450)) + +- i18n: Language update from LingoHub 🤖 on 2022-12-22Z ([#27618](https://github.com/RocketChat/Rocket.Chat/pull/27618)) + +- i18n: Language update from LingoHub 🤖 on 2023-01-09Z ([#27705](https://github.com/RocketChat/Rocket.Chat/pull/27705)) + +- i18n: Language update from LingoHub 🤖 on 2023-01-23Z ([#27814](https://github.com/RocketChat/Rocket.Chat/pull/27814)) + +- i18n: Language update from LingoHub 🤖 on 2023-02-14Z ([#28036](https://github.com/RocketChat/Rocket.Chat/pull/28036)) + +- i18n: Update Hungarian translation ([#27575](https://github.com/RocketChat/Rocket.Chat/pull/27575) by [@urbalazs](https://github.com/urbalazs)) + +- Merge master into develop & Set version to 5.5.0-develop ([#27452](https://github.com/RocketChat/Rocket.Chat/pull/27452)) + +- Regression: Fix mentioning rooms with special chars ([#28206](https://github.com/RocketChat/Rocket.Chat/pull/28206)) + +- Regression: Fix sidebar horizontal scrolling ([#28125](https://github.com/RocketChat/Rocket.Chat/pull/28125)) + +- Regression: "Enable unlimited apps" button on installation modal doesn't do anything ([#28132](https://github.com/RocketChat/Rocket.Chat/pull/28132)) + +- Regression: `Admin UI -> Rooms` Search filter not working ([#27970](https://github.com/RocketChat/Rocket.Chat/pull/27970)) + +- Regression: 0 appearing on sidebar on specific occasions ([#28056](https://github.com/RocketChat/Rocket.Chat/pull/28056)) + + Fixed faulty logic + +- Regression: Add auto translate option back to live chat room ([#28139](https://github.com/RocketChat/Rocket.Chat/pull/28139)) + + Add the `translation` option to the live chat room; + The behavior of this feature in live chat rooms is quite different from direct and group messages. In these rooms, you need to activate and set up the language, while in the live chat room, the `translate` option should always appear for every room and should use the application language to translate. + +- Regression: Add button-icon-disabled-color to the palette ([#27522](https://github.com/RocketChat/Rocket.Chat/pull/27522)) + +- Regression: Add support for 2FA errors to `Meteor.callAsync` ([#27767](https://github.com/RocketChat/Rocket.Chat/pull/27767)) + +- Regression: Add tshow to composer params ([#27602](https://github.com/RocketChat/Rocket.Chat/pull/27602)) + +- Regression: Added anchors elements to the allowed list to be clicked ([#28341](https://github.com/RocketChat/Rocket.Chat/pull/28341)) + +- Regression: Adjusted components using PaginatedMultiSelected to be compatible with new Fuselage version ([#28233](https://github.com/RocketChat/Rocket.Chat/pull/28233)) + +- Regression: Adjusted departments upsell modal message ([#28258](https://github.com/RocketChat/Rocket.Chat/pull/28258)) + + This PR adjusts the logic to display the correct message on the departments upsell modal. This affects users with a trial license, expired expired licence, as well as no licence. + +- Regression: Adjusted departments upsell modal to check for licence and modules ([#28246](https://github.com/RocketChat/Rocket.Chat/pull/28246)) + + This PR fixes a regression on the departments upsell modal, for the rare cases where the workspace has an enterprise licence but has no active modules. This changes improves the check to also consider modules. + +- Regression: App requests notify admin function generating wrong link ([#28111](https://github.com/RocketChat/Rocket.Chat/pull/28111)) + + Fixed a development oversight in which the link of the app request Rocket.Cat message was generated without the marketplace version of the app nor the requests tab param. + Demo gif (before): + ![notify-admin-before](https://user-images.githubusercontent.com/43561537/220368522-084a171c-52ab-48b4-aa43-f73f6cc12ca6.gif) + + Demo gif (after): + ![notify-admin-after](https://user-images.githubusercontent.com/43561537/220368591-93c6e157-922f-4b48-b474-f5c65c2b04b8.gif) + +- Regression: Apps provider not handling apps lists correctly ([#28264](https://github.com/RocketChat/Rocket.Chat/pull/28264)) + + ## Jira tasks: [MKP-272](https://rocketchat.atlassian.net/browse/MKP-272?atlOrigin=eyJpIjoiNDQzMmY4NmYyYTEyNDJjMmJmZmY3ZGUyYmQ3Y2Y2Y2EiLCJwIjoiaiJ9) [MKP-270](https://rocketchat.atlassian.net/browse/MKP-270?atlOrigin=eyJpIjoiOWRhYWM5N2VmY2UwNDAyMjlhY2ZiM2IwYjMwYWQxOWUiLCJwIjoiaiJ9) + Fixed a bug in which the AppsProvider would not handle the marketplace, installed, and private apps lists correctly when running the install, update, and delete listeners. This also solved related bugs of app duplication during installation and loss of reactivity during uninstalls and status changes(private apps only). + Demo gif: ![apps-provider-behavior](https://user-images.githubusercontent.com/43561537/222833328-1d9836c0-738c-41d5-ac17-a5d86452ea83.gif) + +- Regression: Apps-Engine startup process was faulty ([#28322](https://github.com/RocketChat/Rocket.Chat/pull/28322)) + + * App loading routine was forcing apps to be enabled, even if they were previously disabled + * Isolated Apps startup routine for more granular control + +- Regression: Attachment auto size ([#28332](https://github.com/RocketChat/Rocket.Chat/pull/28332)) + + Attachment Image or Image Preview size in small screens are not respecting container boundaries + + **Before:** + ![image](https://user-images.githubusercontent.com/20212776/223826977-507e0b57-aba1-471d-a901-30198a51d82f.png) + + + **NOW:** + ![image](https://user-images.githubusercontent.com/20212776/223826829-7c6006bd-0738-4cd4-acc6-ba8b8c274e3b.png) + +- Regression: Avoid rendering unsupported media on PDFs & update quote styling ([#28048](https://github.com/RocketChat/Rocket.Chat/pull/28048)) + + - Fix faulty logic when deciding which attachment to render based on the mime type of it + + - Replace media query syntax `(width < 767px)` with `(max-width: 767px)` since the first one isn't supported on safari + - Fix a bug when has bold text in multiple rows. + +- Regression: broken message exhibition when edited ([#28180](https://github.com/RocketChat/Rocket.Chat/pull/28180)) + + Sometimes a message will have the fields `editedBy` and `editedAt` present but set to `null`. This PR handle this situation. + +- Regression: Broken message jump onto threads ([#28095](https://github.com/RocketChat/Rocket.Chat/pull/28095)) + +- Regression: Broken room and message composer events ([#27754](https://github.com/RocketChat/Rocket.Chat/pull/27754)) + + It hotfixes two issues: + 1. user card not opening on clicking in user mentions; + 2. slash commands inside threads sending results to the main room. + +- Regression: Change names of requested apps sorting options ([#28312](https://github.com/RocketChat/Rocket.Chat/pull/28312)) + + ## Jira task: [MKP-253](https://rocketchat.atlassian.net/browse/MKP-253) + Changed the name of the requested app-related sorting options to cause less confusion regarding their expected behavior and solved some UX problems with the initial state of the sorting filter when on different marketplace pages. Also fixed some typos. + Demo image: + ![image](https://user-images.githubusercontent.com/43561537/223466309-60f02a71-c21e-4607-a2b4-5de81c3b3cd5.png) + +- Regression: Change text of buttons tooltips on custom content homepage block ([#28094](https://github.com/RocketChat/Rocket.Chat/pull/28094)) + + ### Show to workspace Button: + + * No custom content added: + + “This action will become available after the custom content has been added” + + * W/ custom content: + + "Not it's visible for everyone" + "Not it's visible only for admins" + + --- + + ### Show only this content Button: + + * if CE → “Enterprise only” + * if EE and disabled → "This action will become available after the custom content has been added and made visible to everyone” + * if EE and enabled → “It will hide…" or “It will show…" + +- Regression: Change wording on department removal setting ([#28051](https://github.com/RocketChat/Rocket.Chat/pull/28051)) + +- Regression: Client crashing when updating CachedChatSubscription ([#28062](https://github.com/RocketChat/Rocket.Chat/pull/28062)) + + Currently the typing of 'ISubscription' is a little off from reality. The property `ts` is optional, and this can cause crashes when trying to access `ts`'s properties. + + I decided to avoid changing the type definitions for ISubscription this time, since it will probably impact many other places, and that's not the scope of this task. + +- Regression: Client is not loading new settings from server ([#28248](https://github.com/RocketChat/Rocket.Chat/pull/28248)) + +- Regression: Client-side checks for message deletion ([#27590](https://github.com/RocketChat/Rocket.Chat/pull/27590)) + +- Regression: Composer fix join room action ([#27657](https://github.com/RocketChat/Rocket.Chat/pull/27657)) + +- Regression: Composer Toolbox overlapping borders ([#27714](https://github.com/RocketChat/Rocket.Chat/pull/27714)) + +- Regression: Creating Custom status ([#28292](https://github.com/RocketChat/Rocket.Chat/pull/28292)) + + User is not able to create a custom status from the admin section. Workspace > User Status > New + + The SAVE button is not performing any action + ![image](https://user-images.githubusercontent.com/20212776/223121583-769a571a-365d-4f72-8d0b-f43016d31546.png) + +- Regression: DateRangePicker errors ([#28015](https://github.com/RocketChat/Rocket.Chat/pull/28015)) + + The date range picker for `Yesterday`, `This Week`, `Previous Week`, and `This Month` in the Message Audit page, was not selecting the correct date range and it was causing form validation issues. + + **Error Evidence:** + ![Clipboard - February 10, 2023 6_12 PM](https://user-images.githubusercontent.com/20212776/218519404-f8ab1e02-7b95-452f-8433-374b2208b02a.png) + ![Clipboard - February 10, 2023 6_10 PM](https://user-images.githubusercontent.com/20212776/218519412-4392b3cd-7e21-42f0-aac5-4c30a980b9af.png) + ![Clipboard - February 10, 2023 6_09 PM](https://user-images.githubusercontent.com/20212776/218519417-6726fea6-34bd-41fc-b7fb-e7e3c5ba53cd.png) + ![Clipboard - February 10, 2023 6_08 PM](https://user-images.githubusercontent.com/20212776/218519423-8ec8f0b2-6ad6-4d3c-b678-5383792d4ff3.png) + +- Regression: Decrypt thread main message for room ([#28262](https://github.com/RocketChat/Rocket.Chat/pull/28262)) + +- Regression: Denied Camera permission do not disable VideoMessageAction ([#28210](https://github.com/RocketChat/Rocket.Chat/pull/28210)) + + #### before + ![Kapture 2023-02-28 at 16 12 58](https://user-images.githubusercontent.com/27704687/221955658-2c733275-e193-4029-ba9e-777caf3f03ba.gif) + + #### after + ![Kapture 2023-02-28 at 16 09 20](https://user-images.githubusercontent.com/27704687/221954849-f4379294-0189-4466-a523-ab71e1a8d0af.gif) + +- Regression: Denied Microphone permission disables composer ([#28133](https://github.com/RocketChat/Rocket.Chat/pull/28133)) + + ![Kapture 2023-02-23 at 13 10 38](https://user-images.githubusercontent.com/27704687/220964655-b2a3b69c-9b32-4f82-b585-49ac0118297a.gif) + +- Regression: Disable video message when composer is in use ([#28073](https://github.com/RocketChat/Rocket.Chat/pull/28073)) + +- Regression: Disabled grandfathered apps must have the option to be enabled ([#28266](https://github.com/RocketChat/Rocket.Chat/pull/28266)) + + Grandfathered apps will not follow the new enabling flow and it should always be possible to enable them + +- Regression: Emoji picker styling ([#28046](https://github.com/RocketChat/Rocket.Chat/pull/28046)) + + ### Before + image + + ### After + image + +- Regression: EmojiPicker missing shadow on dark mode ([#28236](https://github.com/RocketChat/Rocket.Chat/pull/28236)) + + #### before + ![Screen Shot 2023-03-01 at 18 23 18](https://user-images.githubusercontent.com/27704687/222267993-3958de34-5f28-4550-ae93-ef81af034b21.png) + + #### after + ![Screen Shot 2023-03-01 at 18 22 14](https://user-images.githubusercontent.com/27704687/222267788-e39d292b-5dc2-4797-b227-1b47008075e7.png) + +- Regression: EnableUnlimitedApps button action ([#28221](https://github.com/RocketChat/Rocket.Chat/pull/28221)) + + "Enable unlimited apps" button on installation modal doesn't do anything. Now it redirects to the `'go-fully-featured-registered'` page. + +- Regression: fix a wrong behavior with the Department table row ([#28157](https://github.com/RocketChat/Rocket.Chat/pull/28157)) + +- Regression: Fix agent departments select value ([#28077](https://github.com/RocketChat/Rocket.Chat/pull/28077)) + +- Regression: fix api tests ([#28067](https://github.com/RocketChat/Rocket.Chat/pull/28067)) + +- Regression: Fix app status filter not working in private apps page ([#28198](https://github.com/RocketChat/Rocket.Chat/pull/28198)) + + ## Jira task: [MKP-266](https://rocketchat.atlassian.net/browse/MKP-266?atlOrigin=eyJpIjoiMzlhNmRhZDNmOGZkNDBmZGEyY2FkNTQ5ZTVlZjUzNzkiLCJwIjoiaiJ9) + Fixed a bug in which the app status filter didn't work because of the new 'enabled*' and 'disabled*' app status. + Demo gif: + ![private-apps-status-filter](https://user-images.githubusercontent.com/43561537/221709473-633f6866-e921-438d-9a20-e6b341823cbf.gif) + +- Regression: fix close flextab on click outside the container ([#27857](https://github.com/RocketChat/Rocket.Chat/pull/27857)) + +- Regression: Fix composer restore ([#27642](https://github.com/RocketChat/Rocket.Chat/pull/27642)) + +- Regression: Fix Custom CSS ([#27993](https://github.com/RocketChat/Rocket.Chat/pull/27993)) + +- Regression: Fix department edit breaking ([#28053](https://github.com/RocketChat/Rocket.Chat/pull/28053)) + +- Regression: Fix emojiPicker reactivity on load-more ([#28331](https://github.com/RocketChat/Rocket.Chat/pull/28331)) + +- Regression: Fix file upload on collapsed composer menu ([#28071](https://github.com/RocketChat/Rocket.Chat/pull/28071)) + +- Regression: Fix go to ThreadList hook ([#27663](https://github.com/RocketChat/Rocket.Chat/pull/27663)) + +- Regression: Fix hasLicense failing due call stack limit reasons ([#28304](https://github.com/RocketChat/Rocket.Chat/pull/28304)) + +- Regression: Fix improper usage of useEndpointData ([#28050](https://github.com/RocketChat/Rocket.Chat/pull/28050)) + +- Regression: Fix intermitent apps engine startup ([#28254](https://github.com/RocketChat/Rocket.Chat/pull/28254)) + + Makes the apps limitation functionality depend on methods from the Apps Engine's service instead of a dynamic import of the apps orchestrator, making the engine's load process deterministic. + +- Regression: Fix missing Formatting items ([#28044](https://github.com/RocketChat/Rocket.Chat/pull/28044)) + +- Regression: Fix not showing global search option ([#28342](https://github.com/RocketChat/Rocket.Chat/pull/28342)) + +- Regression: Fix omnichannel chat forwarding not working ([#28117](https://github.com/RocketChat/Rocket.Chat/pull/28117)) + +- Regression: Fix presence broadcast not re-enabling ([#28017](https://github.com/RocketChat/Rocket.Chat/pull/28017)) + +- Regression: Fix private apps already in marketplace not shown properly on app details page ([#28199](https://github.com/RocketChat/Rocket.Chat/pull/28199)) + + ## Jira task: [MKP-267](https://rocketchat.atlassian.net/browse/MKP-267?atlOrigin=eyJpIjoiMDVmNDJjYjFjZDNiNGU4NTk4NGQ4ODZjMjM3NDYwNDciLCJwIjoiaiJ9) + Fixed a bug in which apps that already existed in the marketplace would not show properly when installed via the private apps page. + Demo gif: + ![private-apps-same-app](https://user-images.githubusercontent.com/43561537/221710893-004adb81-2dd7-4ad4-b0c6-18b644415ac0.gif) + +- Regression: Fix RegisterForm Translations ([#28156](https://github.com/RocketChat/Rocket.Chat/pull/28156)) + +- Regression: Fix remove user from room shows skeleton ([#28247](https://github.com/RocketChat/Rocket.Chat/pull/28247)) + + When the user is removed from a public channel and has it open it will show a grey placeholder screen + + Now, it appears the Join button as usual + +- Regression: Fix slash command with preview ([#28127](https://github.com/RocketChat/Rocket.Chat/pull/28127)) + +- Regression: Fix slash commands ([#28168](https://github.com/RocketChat/Rocket.Chat/pull/28168)) + +- Regression: fix Thread horizontal scrolling ([#28327](https://github.com/RocketChat/Rocket.Chat/pull/28327)) + +- Regression: Fix toggle theme breaking UI ([#28161](https://github.com/RocketChat/Rocket.Chat/pull/28161)) + +- Regression: Fix write stream error on user data export ([#27683](https://github.com/RocketChat/Rocket.Chat/pull/27683)) + +- Regression: Fixed room edit custom field validation ([#28078](https://github.com/RocketChat/Rocket.Chat/pull/28078)) + + This PR fixes custom fields validations not being properly triggered/cleared on the room edit page. + +- Regression: Fixed triggers edit form not being properly updated ([#28235](https://github.com/RocketChat/Rocket.Chat/pull/28235)) + +- Regression: Formatted text rendered by UI Kit ([#28060](https://github.com/RocketChat/Rocket.Chat/pull/28060)) + +- Regression: Gracefully stop DDP Streamer publication and close WS ([#28121](https://github.com/RocketChat/Rocket.Chat/pull/28121)) + +- Regression: Hide price and category filters when inside of private apps page ([#28188](https://github.com/RocketChat/Rocket.Chat/pull/28188)) + + ## Jira task: [MKP-265](https://rocketchat.atlassian.net/browse/MKP-265?atlOrigin=eyJpIjoiMGUyMjI0ZTJjNjg1NDc5ZWE0Y2U4NDVkMzk4MmRmYmEiLCJwIjoiaiJ9) + The price and category filters dont make sense for private apps so when inside of the private apps page these filters will now be hidden. + Demo image: + ![image](https://user-images.githubusercontent.com/43561537/221595718-c812861a-672e-44ac-bb03-6046064e420a.png) + +- Regression: Hide Workspace registration feature for non-admin users ([#28154](https://github.com/RocketChat/Rocket.Chat/pull/28154)) + +- Regression: Image Attachment Description size ([#28149](https://github.com/RocketChat/Rocket.Chat/pull/28149)) + + The Image Attachment is breaking lines to match the size of the image, should follow the same size of the normal message. + + **Previous:** + ![image](https://user-images.githubusercontent.com/20212776/221175529-e574fbdb-9069-48ae-9946-d6ea475ba4bf.png) + + **Current:** + ![image](https://user-images.githubusercontent.com/20212776/221175349-486b4c40-16a2-40ab-9593-089963b6315b.png) + +- Regression: Incorrect installation flow on app detail and upload app pages ([#28173](https://github.com/RocketChat/Rocket.Chat/pull/28173)) + + The install button displayed in the App detail page of an app from the Marketplace that hasn't been installed in the workspace didn't follow the same installation steps performed in the app list on Explore or Enterprise pages. + + This PR isolates the installation handler so the exact same functions are used in both places. + + The same problem was solved in the Upload App page + +- Regression: Incorrect system message upon adding/editing SLA policy for a room. ([#28151](https://github.com/RocketChat/Rocket.Chat/pull/28151)) + +- Regression: Installation of some apps fail ([#28265](https://github.com/RocketChat/Rocket.Chat/pull/28265)) + + Installation was failing for apps that did not include a set o permissions required because the process was short circuiting in those cases. However, they are valid as they signify apps that function with the default permission set + +- Regression: Jump to message not working ([#28163](https://github.com/RocketChat/Rocket.Chat/pull/28163)) + +- Regression: Message > `messageActionDefault`> Copy and Report ([#28040](https://github.com/RocketChat/Rocket.Chat/pull/28040)) + + This regression was probably generated by the Attachments rewrite. + + Issue 1: When selecting the action `Copy` on the message toolbox with Attachment Messages (messages with files/images) + The copied content was empty because was getting from an empty prop. + + **Previous output:** + ![output2](https://user-images.githubusercontent.com/20212776/218820716-e5c6b9cf-8968-4ee7-9e87-f958edcc7fdf.jpg) + + **Current output:** + ![output1](https://user-images.githubusercontent.com/20212776/218820706-c26ff106-1eb9-4e07-bb71-a4f97cc21d97.jpg) + + + Issue 2: When selecting the action `Report` the reported message was showing an unformatted message (with markdown tokens) + + **Previous output:** + ![output4](https://user-images.githubusercontent.com/20212776/218821154-2090a79d-58ee-4717-8646-e1eb2b5ad46e.jpg) + + **Current output:** + ![output3](https://user-images.githubusercontent.com/20212776/218821189-e820b58e-1128-4a34-80d8-0aadeb880830.jpg) + +- Regression: message box issues ([#27495](https://github.com/RocketChat/Rocket.Chat/pull/27495)) + + It fixes some problems introduced/exposed after refactoring the `ChatMessages` API. + +- Regression: message-parse version update ([#28245](https://github.com/RocketChat/Rocket.Chat/pull/28245)) + + Regression to fix URL parsing issues + ![image](https://user-images.githubusercontent.com/20212776/222496497-17ee54be-0c45-403f-97b9-95d7428328d8.png) + +- Regression: Missing contexts on contextual bar ([#27734](https://github.com/RocketChat/Rocket.Chat/pull/27734)) + + It should fixes crashes on starred, pinned, and mentioned messages while those are migrating from Blaze to React. + +- Regression: more message box issues ([#27499](https://github.com/RocketChat/Rocket.Chat/pull/27499)) + + It handles issues regarding editing messages. + +- Regression: New messages not reflected in the chat window for queued chats. ([#28145](https://github.com/RocketChat/Rocket.Chat/pull/28145)) + +- Regression: OAuth Login ([#28303](https://github.com/RocketChat/Rocket.Chat/pull/28303)) + + Login flow with Rocket.Chat as an OAuth provider was broken + +- Regression: OAuthApps are added with empty string `_id` field ([#28257](https://github.com/RocketChat/Rocket.Chat/pull/28257)) + + - Fix OAuthApps added to the database with a empty string `_id` field. + +- Regression: Open Thread ([#27640](https://github.com/RocketChat/Rocket.Chat/pull/27640)) + +- Regression: Re-add app signature migration to fix the faulty previous one ([#28107](https://github.com/RocketChat/Rocket.Chat/pull/28107)) + + Previously merged migration files ended up in a faulty migration + +- Regression: Rectifying thread layout ([#27680](https://github.com/RocketChat/Rocket.Chat/pull/27680)) + + This PR fixes: + - the size and scrolling area of the list of messages; + - the margin and general style of "Also send to channel" checkbox; + - the size of link previews. + +- Regression: Regular users were not able to leave federated rooms ([#28148](https://github.com/RocketChat/Rocket.Chat/pull/28148)) + + When regular users (not owners, nor moderators) tried to leave federated rooms, they were not allowed to do so due to a bad permission check. + + Jira: FED-88 + +- Regression: Remove duplicated broadcast App events ([#28310](https://github.com/RocketChat/Rocket.Chat/pull/28310)) + +- Regression: Remove unnecessary messages from Email transcript ([#28165](https://github.com/RocketChat/Rocket.Chat/pull/28165)) + +- Regression: run clientMessageRecieved hooks on thread main message ([#27962](https://github.com/RocketChat/Rocket.Chat/pull/27962)) + +- Regression: Save button is not enable while trying to save contact manager ([#28183](https://github.com/RocketChat/Rocket.Chat/pull/28183)) + +- Regression: Scroll bars in sidebar ([#28091](https://github.com/RocketChat/Rocket.Chat/pull/28091)) + +- Regression: Scrolling on threads ([#28298](https://github.com/RocketChat/Rocket.Chat/pull/28298)) + +- Regression: SendFileLivechatMessage using deprecated prop affecting PDF transcript ([#28225](https://github.com/RocketChat/Rocket.Chat/pull/28225)) + +- Regression: Show mention instead of the name of the user in app request messages ([#28200](https://github.com/RocketChat/Rocket.Chat/pull/28200)) + + ## Jira task: [MKP-249](https://rocketchat.atlassian.net/browse/MKP-249?atlOrigin=eyJpIjoiYmNmMjBjOGI5OGUwNGVhMTg1NGMyNDZhMGYzMGY4YWMiLCJwIjoiaiJ9) + Stopped using the name of users that requested apps and now the app request messages directly mention the users. + Demo image: + ![image](https://user-images.githubusercontent.com/43561537/221995968-c6e4dc7e-9052-4121-b5d0-610a1fbe7ea1.png) + +- Regression: Show messages instead of the composer when there is no action available on federated rooms ([#28093](https://github.com/RocketChat/Rocket.Chat/pull/28093)) + + Rules: + If the federation module is disabled within the workspace: **do not show the composer and show a message instead**; + + If the federation module is enabled, the user is not part of the room, and the workspace is a CE environment: **do not show the composer and show a message instead.** + + If the federation module is enabled, the is not part of the room, but the workspace is an EE environment: **show the composer with the Join button** + + If everything is enabled, and the user is already part of the room: **show the normal composer** + + Jira: [FED-82] + +- Regression: Sidebar collapsing on extra small views ([#27651](https://github.com/RocketChat/Rocket.Chat/pull/27651)) + + ### before + Screen Shot 2022-12-27 at 10 39 21 + + + ### after + Screen Shot 2022-12-27 at 10 38 10 + +- Regression: Slash commands detected at any line ([#28142](https://github.com/RocketChat/Rocket.Chat/pull/28142)) + +- Regression: Small fixes to installation flow ([#28160](https://github.com/RocketChat/Rocket.Chat/pull/28160)) + + Some UI fixes on app installation flow: + * Some apps were being incorrectly shown as "Enabled" + App status `INITIALIZED` was wrongly considered as meaning an app was "Enabled". That's not the case. + + It was introduced there to mark apps as "installed", but this is not the case anymore. #27330 wanted to solve the situation where an app was initially shown as disabled right after it was installed, and a different solution to this will be provided by changing how Apps-Engine communicates status changes to the UI. + + * Some installed apps in the "Installed" screen incorrectly not being displayed as grandfathered + * Installation modal being shown in EE where it shouldn't + * Installation modal showed wrong label when installing apps from Marketplace + +- Regression: Support generating pdfs from queue ([#28162](https://github.com/RocketChat/Rocket.Chat/pull/28162)) + + This removes a code validation that prevented PDF files from being generated for rooms that were closed directly from the queue. + + After discussing with product, this is a behavior we want and so we're removing the code preventing it and updating the translation keys. + +- Regression: Tooltip for More options dont disappear after click. ([#28201](https://github.com/RocketChat/Rocket.Chat/pull/28201)) + +- Regression: UiKit message surface styles ([#28213](https://github.com/RocketChat/Rocket.Chat/pull/28213)) + +- Regression: Undefined default message context ([#27870](https://github.com/RocketChat/Rocket.Chat/pull/27870)) + + It fixes some contextual bar tabs (e.g. "Mentions"). + +- Regression: Update color tokens for voip footer ([#28197](https://github.com/RocketChat/Rocket.Chat/pull/28197)) + +- Regression: Update Composer Formatters Translation Keys ([#28228](https://github.com/RocketChat/Rocket.Chat/pull/28228)) + +- Regression: upserting data into cached collections ([#27965](https://github.com/RocketChat/Rocket.Chat/pull/27965)) + + This one should get rid of "grey" (temporary) messages. + +- Regression: Video Recorder "record" button alignment ([#28122](https://github.com/RocketChat/Rocket.Chat/pull/28122)) + + ### Before + image + image + + ### After + image + image + +- Regression: View mode preferences without the selected option by default ([#28120](https://github.com/RocketChat/Rocket.Chat/pull/28120)) + + After removing all Meteor Blaze templates from the project, the View mode preferences started presenting the issue: + + No option is selected by default when the view mode preferences are open. + + Possible reason: React does allow you to use name attributes in the input tag, but it may cause some issues with radio buttons. One possible reason is that React uses a synthetic event system that does not rely on native HTML attributes, since we had the wrapper and several blaze templates in the project, this could be effecting this behavior ignoring the name attribute in the inputs. + + + **Previous:** + ![image](https://user-images.githubusercontent.com/20212776/220721444-51e32397-5106-4f16-8af9-7b7e5d7209ea.png) + + + **Current:** + ![image](https://user-images.githubusercontent.com/20212776/220721529-77af023b-951a-44f6-82a8-b2c18a7d0950.png) + +- Regression: Visitor abandonment job not working properly ([#28209](https://github.com/RocketChat/Rocket.Chat/pull/28209)) + +- Regression: Zapier Callout using wrong props ([#28311](https://github.com/RocketChat/Rocket.Chat/pull/28311)) + +- Release 5.4.4 ([#28333](https://github.com/RocketChat/Rocket.Chat/pull/28333)) + +
+ +### 👩‍💻👨‍💻 Contributors 😍 + +- [@Dnouv](https://github.com/Dnouv) +- [@Nabhag8848](https://github.com/Nabhag8848) +- [@carlosrodrigues94](https://github.com/carlosrodrigues94) +- [@dependabot[bot]](https://github.com/dependabot[bot]) +- [@henit-chobisa](https://github.com/henit-chobisa) +- [@jschirrmacher](https://github.com/jschirrmacher) +- [@lingohub[bot]](https://github.com/lingohub[bot]) +- [@nYCSTs](https://github.com/nYCSTs) +- [@ostjen](https://github.com/ostjen) +- [@pouyadarabi](https://github.com/pouyadarabi) +- [@try-catch-stack](https://github.com/try-catch-stack) +- [@urbalazs](https://github.com/urbalazs) +- [@xareyli](https://github.com/xareyli) + +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@AlenDavid](https://github.com/AlenDavid) +- [@AllanPazRibeiro](https://github.com/AllanPazRibeiro) +- [@Educg550](https://github.com/Educg550) +- [@FabioCavaleti](https://github.com/FabioCavaleti) +- [@Harmeet221](https://github.com/Harmeet221) +- [@KevLehman](https://github.com/KevLehman) +- [@LucianoPierdona](https://github.com/LucianoPierdona) +- [@MarcosSpessatto](https://github.com/MarcosSpessatto) +- [@MartinSchoeler](https://github.com/MartinSchoeler) +- [@PedroRorato](https://github.com/PedroRorato) +- [@albuquerquefabio](https://github.com/albuquerquefabio) +- [@aleksandernsilva](https://github.com/aleksandernsilva) +- [@casalsgh](https://github.com/casalsgh) +- [@cauefcr](https://github.com/cauefcr) +- [@csuadev](https://github.com/csuadev) +- [@d-gubert](https://github.com/d-gubert) +- [@debdutdeb](https://github.com/debdutdeb) +- [@dougfabris](https://github.com/dougfabris) +- [@engelgabriel](https://github.com/engelgabriel) +- [@felipe-rod123](https://github.com/felipe-rod123) +- [@filipemarins](https://github.com/filipemarins) +- [@gabriellsh](https://github.com/gabriellsh) +- [@geekgonecrazy](https://github.com/geekgonecrazy) +- [@ggazzo](https://github.com/ggazzo) +- [@graywolf336](https://github.com/graywolf336) +- [@guijun13](https://github.com/guijun13) +- [@hugocostadev](https://github.com/hugocostadev) +- [@juliajforesti](https://github.com/juliajforesti) +- [@matheusbsilva137](https://github.com/matheusbsilva137) +- [@matheuslc](https://github.com/matheuslc) +- [@murtaza98](https://github.com/murtaza98) +- [@nishant23122000](https://github.com/nishant23122000) +- [@pierre-lehnen-rc](https://github.com/pierre-lehnen-rc) +- [@rique223](https://github.com/rique223) +- [@rodrigok](https://github.com/rodrigok) +- [@sampaiodiego](https://github.com/sampaiodiego) +- [@tapiarafael](https://github.com/tapiarafael) +- [@tassoevan](https://github.com/tassoevan) +- [@thassiov](https://github.com/thassiov) +- [@tiagoevanp](https://github.com/tiagoevanp) +- [@totoi690](https://github.com/totoi690) +- [@weslley543](https://github.com/weslley543) +- [@yash-rajpal](https://github.com/yash-rajpal) + +# 5.4.4 +`2023-03-08 · 2 🔍 · 2 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` + +
+🔍 Minor changes + + +- Chore: New temporary settings to limit access to files and outside room members ([#28319](https://github.com/RocketChat/Rocket.Chat/pull/28319)) + +- Release 5.4.4 ([#28333](https://github.com/RocketChat/Rocket.Chat/pull/28333)) + +
+ +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@rodrigok](https://github.com/rodrigok) +- [@sampaiodiego](https://github.com/sampaiodiego) + +# 5.4.3 +`2023-02-14 · 1 🐛 · 2 🔍 · 2 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🐛 Bug fixes + + +- Security Hotfix (https://docs.rocket.chat/guides/security/security-updates) + +
+🔍 Minor changes + + +- Chore: Do not rely on external service on tests ([#27874](https://github.com/RocketChat/Rocket.Chat/pull/27874)) + +- Release 5.4.3 ([#28028](https://github.com/RocketChat/Rocket.Chat/pull/28028)) + +
+ +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@ggazzo](https://github.com/ggazzo) +- [@sampaiodiego](https://github.com/sampaiodiego) + +# 5.4.2 +`2023-01-25 · 1 🚀 · 5 🐛 · 6 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🚀 Improvements + + +- Emoji picker for large amount of custom emojis ([#27745](https://github.com/RocketChat/Rocket.Chat/pull/27745)) + +### 🐛 Bug fixes + + +- `*.files` endpoints returning hidden files ([#27617](https://github.com/RocketChat/Rocket.Chat/pull/27617)) + +- New users aren't mapped to rooms with OAuth groups/channels map ([#27000](https://github.com/RocketChat/Rocket.Chat/pull/27000) by [@carlosrodrigues94](https://github.com/carlosrodrigues94)) + + This change deals with the problem with the new users coming from key cloak, this users were not being mapped to the correct channels on RC. + +- Not all messages in chat conversations are available when forwarding between agents or departments. ([#27816](https://github.com/RocketChat/Rocket.Chat/pull/27816)) + +- OmnichannelRoomIconProvider order breaking VideoConfPopup ([#27740](https://github.com/RocketChat/Rocket.Chat/pull/27740)) + + Jira Issue [VC-39] + +- Showing thumbnails on files list ([#23301](https://github.com/RocketChat/Rocket.Chat/pull/23301) by [@carlosrodrigues94](https://github.com/carlosrodrigues94) & [@ostjen](https://github.com/ostjen)) + +### 👩‍💻👨‍💻 Contributors 😍 + +- [@carlosrodrigues94](https://github.com/carlosrodrigues94) +- [@ostjen](https://github.com/ostjen) + +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@dougfabris](https://github.com/dougfabris) +- [@filipemarins](https://github.com/filipemarins) +- [@matheusbsilva137](https://github.com/matheusbsilva137) +- [@sampaiodiego](https://github.com/sampaiodiego) + +# 5.4.1 +`2022-12-16 · 5 🐛 · 1 🔍 · 7 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🐛 Bug fixes + + +- Custom languages not being applied to i18next ([#27557](https://github.com/RocketChat/Rocket.Chat/pull/27557)) + +- Fix Login with Show default form disabled ([#27475](https://github.com/RocketChat/Rocket.Chat/pull/27475)) + +- Message Actions menu does not close upon choosing an action ([#27328](https://github.com/RocketChat/Rocket.Chat/pull/27328)) + +- Pagination not working on current chats ([#27432](https://github.com/RocketChat/Rocket.Chat/pull/27432)) + +- Registration and Login placeholders not being used ([#27558](https://github.com/RocketChat/Rocket.Chat/pull/27558)) + +
+🔍 Minor changes + + +- Chore: Deprecate unused omnichannel API ([#27538](https://github.com/RocketChat/Rocket.Chat/pull/27538)) + +
+ +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@MartinSchoeler](https://github.com/MartinSchoeler) +- [@aleksandernsilva](https://github.com/aleksandernsilva) +- [@filipemarins](https://github.com/filipemarins) +- [@ggazzo](https://github.com/ggazzo) +- [@hugocostadev](https://github.com/hugocostadev) +- [@murtaza98](https://github.com/murtaza98) +- [@yash-rajpal](https://github.com/yash-rajpal) + +# 5.4.0 +`2022-12-05 · 9 🎉 · 13 🚀 · 61 🐛 · 87 🔍 · 57 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🎉 New features + + +- Add new endpoint 'livechat/agent.status' & deprecate changeLivechatStatus meteor method ([#27047](https://github.com/RocketChat/Rocket.Chat/pull/27047)) + +- Bugsnag client ([#23580](https://github.com/RocketChat/Rocket.Chat/pull/23580)) + +- Custom MessageType for video conference messages ([#27333](https://github.com/RocketChat/Rocket.Chat/pull/27333)) + +- Emphasis Elements (italic, strike and bold) in Message Parser Components ([#27003](https://github.com/RocketChat/Rocket.Chat/pull/27003)) + + Currently the message parser does not accept Emphasis elements mixed with plain text + + `[Normal Link - *Bold*, _Italic_ and ~strike~ Styles](https://rocket.chat/)` return plain text → Should return a Lin with bold/italic/strike + + To fix this behavior it was necessary to edit LinkSpan component in gazzodown package (changes included in this PR) and the grammar/utils files in the `fuselage/message-parser` repository + + Fuselage Pull Request: https://github.com/RocketChat/fuselage/pull/887/ + +- Federation events coverage expansion ([#27119](https://github.com/RocketChat/Rocket.Chat/pull/27119)) + + This PR adds the following features for the Matrix Federation feature: + - Ability to sync Users' real names (since they have at least one room in common with other users); + - User typing event; + +- Incompatible Apps ([#27280](https://github.com/RocketChat/Rocket.Chat/pull/27280)) + +- REST API endpoint `/v1/oauth-apps.create` ([#27054](https://github.com/RocketChat/Rocket.Chat/pull/27054)) + + Created the 'oauth-apps.addOAuthApp' endpoint for the `apps/meteor/client/views/admin/oauthApps/OAuthAddApp.tsx` file, and added Ajv validation. + +- REST API endpoint `/v1/rooms.delete` ([#26866](https://github.com/RocketChat/Rocket.Chat/pull/26866)) + +- Video Conference Message blocks and info action ([#27310](https://github.com/RocketChat/Rocket.Chat/pull/27310)) + +### 🚀 Improvements + + +- Add message name container component to message name header and system message ([#27184](https://github.com/RocketChat/Rocket.Chat/pull/27184)) + + Add `MessageNameContainer` wrapper to display `name` and `username` inline and separate them with a blank space. + + Update font size of system message: + + Before: + ![Screenshot 2022-11-08 at 13 51 58](https://user-images.githubusercontent.com/9275105/200626484-bfcf3eb2-ac36-4b6c-8158-b84bf93023bd.png) + + + After: + Screenshot 2022-11-08 at 10 56 10 + + + Add removed message variation to `ThreadMessageOrigin` component + Before: + ![Screenshot 2022-11-08 at 13 35 45](https://user-images.githubusercontent.com/9275105/200622876-5e5bd7a2-2df1-453a-9e81-96635390648e.png) + + After: + Screenshot 2022-11-08 at 10 51 47 + +- Add searchTerm support for livechat/rid/messages API ([#27214](https://github.com/RocketChat/Rocket.Chat/pull/27214)) + +- Add update option to apps list kebab menu and implement new update badge on apps list ([#27246](https://github.com/RocketChat/Rocket.Chat/pull/27246)) + + Added a new update option to the app menu to follow the removal of the CTA buttons from the apps list. Also implemented the new update badge that will replace the old update button. + Demo gif: + ![update_badge](https://user-images.githubusercontent.com/43561537/202225372-c0369bea-12d4-4ea3-8996-8d4edab00722.gif) + +- Adding a noscript tag for letting users know if they have JS disabled ([#23632](https://github.com/RocketChat/Rocket.Chat/pull/23632) by [@sidmohanty11](https://github.com/sidmohanty11)) + +- Improve searchChats endpoint to have source filter support ([#27262](https://github.com/RocketChat/Rocket.Chat/pull/27262)) + +- Login rewrite in react ([#26782](https://github.com/RocketChat/Rocket.Chat/pull/26782)) + +- Marketplace feedback toasts ([#27239](https://github.com/RocketChat/Rocket.Chat/pull/27239)) + + ## Jira tasks + Save app changes toast: [MKP-160](https://rocketchat.atlassian.net/browse/MKP-160?atlOrigin=eyJpIjoiMjM1YmZjMTVjZGU2NGUwMGIxNTRlYTEwODgwMDk2ZDkiLCJwIjoiaiJ9) + Uninstall app toast: [MKP-168](https://rocketchat.atlassian.net/browse/MKP-168?atlOrigin=eyJpIjoiOThkMjEwOTk5NjhiNDE2OGEwY2MyNWEyNWM5YzNkMTUiLCJwIjoiaiJ9) + Enable/disable app feedback toast: [MKP-169](https://rocketchat.atlassian.net/browse/MKP-169?atlOrigin=eyJpIjoiN2VjODIzOGMwNmJkNGU3N2JhOWEzMDU3Y2IxZjZkNWMiLCJwIjoiaiJ9) + + + Implemented/refactored four toast notifications and refactored another two in marketplace. The first one happens after the user saves the settings of an app, the second one when the user successfully uninstalls an app and the third and fourth ones happen when the user enables and disables an app respectfully. + Demo gif: + ![feedback_toasts](https://user-images.githubusercontent.com/43561537/202277707-a3b38536-e090-4c4f-96b4-8e21bcd10070.gif) + +- Move app list install logic to app menu ([#27056](https://github.com/RocketChat/Rocket.Chat/pull/27056)) + + ## Jira task: [MKP-136](https://rocketchat.atlassian.net/browse/MKP-136?atlOrigin=eyJpIjoiM2M0ODhkZDc0YjQ2NGE5OGE4YTBkZDJhY2M0NGVmZDgiLCJwIjoiaiJ9) + Moved the install/buy/subscribe logic from the CTA buttons that existed in the app list to the app menu. Now the user can install apps by clicking in the kebab menu in the right of the app list entry. Also solved a little undefined bug happening in the app permissions modal. + Demo gif: + ![app_menu](https://user-images.githubusercontent.com/43561537/195204630-e66c7859-028f-4654-8367-96029a855b42.gif) + +- Quotes on E2EE Messages ([#26303](https://github.com/RocketChat/Rocket.Chat/pull/26303)) + + This PR provides basic quoting to E2EE messages, it doesn't support multiple chaining of quotes messages. + + Screenshot 2022-07-19 at 9 42 19 PM + +- Read threads when marking a room as read ([#26754](https://github.com/RocketChat/Rocket.Chat/pull/26754)) + + This PR changes the functionality of `subscription.read` to add read threads when endpoint is called + +- Removed tool tip from sidebar menu ([#24605](https://github.com/RocketChat/Rocket.Chat/pull/24605) by [@Himanshu664](https://github.com/Himanshu664)) + +- Sorting functionality in team channel while leaving a team ([#21790](https://github.com/RocketChat/Rocket.Chat/pull/21790) by [@sumukhah](https://github.com/sumukhah)) + +- VideoConf Miss Config Modal ([#27153](https://github.com/RocketChat/Rocket.Chat/pull/27153)) + + Jira Issue: [VC-9] + + + +### 🐛 Bug fixes + + +- `channels.convertToTeam` endpoint doesn't work when only the `channelName` param is provided ([#26858](https://github.com/RocketChat/Rocket.Chat/pull/26858)) + + - Fix the `channels.convertToTeam` endpoint not working when the `channelName` is sent as parameter. + +- Add condition to createUser button on UsersPage ([#27189](https://github.com/RocketChat/Rocket.Chat/pull/27189)) + + Hide the create user button in admin if the user doesn't have the permission to do so. It was not the case before. + + + https://user-images.githubusercontent.com/45966964/115802514-5ab86300-a3df-11eb-98d8-7aba696bfa7e.mp4 + +- Add condition to invite user if user doesn't have permission ([#27190](https://github.com/RocketChat/Rocket.Chat/pull/27190)) + + If you deactivated the permission to send links, the button was always there and led to an error message. + Before: + + https://user-images.githubusercontent.com/45966964/115801057-23948280-a3dc-11eb-83c2-b3e16f66ddd5.mp4 + + After: + + https://user-images.githubusercontent.com/45966964/115801253-956ccc00-a3dc-11eb-95d0-9baa69410fe1.mp4 + +- Add pause functionality to Custom Sounds ([#24361](https://github.com/RocketChat/Rocket.Chat/pull/24361)) + +- Add sorting channels on teams ([#21675](https://github.com/RocketChat/Rocket.Chat/pull/21675) by [@sumukhah](https://github.com/sumukhah)) + +- Adding error message for wrong dates ([#21677](https://github.com/RocketChat/Rocket.Chat/pull/21677) by [@shrinish123](https://github.com/shrinish123)) + + Before : + ![before](https://user-images.githubusercontent.com/56491104/115405052-85ea5900-a20b-11eb-9c78-5e98de6c454c.png) + + After: + + ![after export](https://user-images.githubusercontent.com/56491104/115405085-8da9fd80-a20b-11eb-8b72-de9ef7c2217b.png) + +- Adjust read only toggle on create channel based on permissions ([#27318](https://github.com/RocketChat/Rocket.Chat/pull/27318)) + +- Adjusted form validation to disallow duplicated emails ([#27037](https://github.com/RocketChat/Rocket.Chat/pull/27037)) + + This pull request revisits the user info form, fixing a bug that allowed the form to be saved with an already existing e-mail. Taking advantage of this opportunity this PR also refactors the file to typescript and adds new libs like `useForm` and `useQuery`. + +- Always parse encrypted messages on client ([#27092](https://github.com/RocketChat/Rocket.Chat/pull/27092)) + +- Archived channels reappearing permanently ([#20476](https://github.com/RocketChat/Rocket.Chat/pull/20476)) + +- AttachmentDescription color token ([#27222](https://github.com/RocketChat/Rocket.Chat/pull/27222)) + +- Avg response time calculation ([#27163](https://github.com/RocketChat/Rocket.Chat/pull/27163)) + +- Change GridFS error message validation ([#26957](https://github.com/RocketChat/Rocket.Chat/pull/26957)) + + Allow uninstalling an app even if source files cannot be found. This validation was already done in the past, but since the error message was changed, the validation was broken. + +- Delete first message when initializing thread returns black screen ([#27117](https://github.com/RocketChat/Rocket.Chat/pull/27117)) + +- Discussion list timestamp and Edit room system messages ([#27180](https://github.com/RocketChat/Rocket.Chat/pull/27180)) + +- Discussions list divider on contextualBar ([#27178](https://github.com/RocketChat/Rocket.Chat/pull/27178)) + +- Display Edit Team instead of Edit Room when in a team ([#27230](https://github.com/RocketChat/Rocket.Chat/pull/27230)) + +- Ensure onetime job runs according to 'startupSetting' everytime ([#27311](https://github.com/RocketChat/Rocket.Chat/pull/27311)) + + - Fixes the condition of not running a _onetime job_ at the app's startup scheduled to run by using the [`startupSetting`](https://github.com/RocketChat/Rocket.Chat.Apps-engine/blob/04f5930244836043040a8c42beff0690a2359a53/src/definition/scheduler/IProcessor.ts#L8) if the job was run previously at another app startup (Agenda does not remove already run jobs from the database, preventing the app from scheduling the job a second time as it thinks the job is already scheduled); + - Declutters the scheduler's collection by removing _onetime jobs_ documents after they are run. + +- Featured apps disappearing, install toast config and save changes button behavior ([#27181](https://github.com/RocketChat/Rocket.Chat/pull/27181)) + + ## Jira tasks + Featured apps disappearing: [MKP-161](https://rocketchat.atlassian.net/browse/MKP-161?atlOrigin=eyJpIjoiYjI4MWMyODJkZjlkNDEwMjhkZWFhNjkxZjBiZTJiOGMiLCJwIjoiaiJ9) + Install toast config: [MKP-162](https://rocketchat.atlassian.net/browse/MKP-162?atlOrigin=eyJpIjoiNjNhNDJjZGE5YWQ5NDJiMWIyZjM4MjMwNmI1MmE5NjUiLCJwIjoiaiJ9) + Save changes button behavior: [MKP-163](https://rocketchat.atlassian.net/browse/MKP-163?atlOrigin=eyJpIjoiZjc3MzUwZTNmYjU3NDJiZjhlOWI0OGIzMGY3ZWQ5ODUiLCJwIjoiaiJ9) + + Fixed three bugs: In the first one featured apps would disappear from the apps list after installation, in the second one the install toast wasn't correctly configured, and in the third one the app details page save button would render even when the current app wasn't installed. + Demo gif: + + ![featured_disappearing](https://user-images.githubusercontent.com/43561537/199850435-ca9e8ba1-7924-414e-96f4-dfb373fdd754.gif) + +- Fix Piwik and add extra setting to allow workarounds ([#27416](https://github.com/RocketChat/Rocket.Chat/pull/27416)) + +- Fixed Allow reacting toggle button in Edit room ([#20324](https://github.com/RocketChat/Rocket.Chat/pull/20324) by [@Darshilp326](https://github.com/Darshilp326)) + + Users can now see changes for toggling allow reacting button after changes. + Users do not need to come back for changing allow reacting button. + + https://user-images.githubusercontent.com/55157259/105572410-f274c980-5d7c-11eb-806a-e23c2abd37de.mp4 + +- Gap between message content and message header when there's no text. ([#27165](https://github.com/RocketChat/Rocket.Chat/pull/27165)) + + Before: + ![image](https://user-images.githubusercontent.com/40830821/199314585-f09920bd-efea-4767-824a-783aca2a229a.png) + ![image](https://user-images.githubusercontent.com/40830821/199320275-cd32a96c-36a2-4c5b-ac3c-0db6aa57fdf7.png) + + After: + ![image](https://user-images.githubusercontent.com/40830821/199314648-b6b48512-b8c0-4c11-81bc-d6b97700bf7a.png) + ![image](https://user-images.githubusercontent.com/40830821/199320172-c6f986b8-29cd-4b2a-95e6-ffe9d51a8eaa.png) + + Additionaly removed a component that was being rendered inside itself, causing spacing issues. + +- Improper grammar when converting channel member to owner ([#27265](https://github.com/RocketChat/Rocket.Chat/pull/27265) by [@JoshMcCullough](https://github.com/JoshMcCullough)) + +- Install private apps modal behavior marketplace ([#26973](https://github.com/RocketChat/Rocket.Chat/pull/26973)) + + Fixed two bugs in the private app install page: + - The first one is a lack of pt-br translation to the agree button of the apps permission modal + - The second one is that the review modal did not show the default permission list when the app being installed did not provide a permissions list. + + **Demo gif**: + ![AppsPermissionModal](https://user-images.githubusercontent.com/43561537/193342594-5516b557-948a-4d9d-ade3-65bb1600e458.gif) + +- Integration history breaking when there's more than 49 records ([#27290](https://github.com/RocketChat/Rocket.Chat/pull/27290)) + + Aditionally, fixed example data for incoming webhooks and converted some files to TS. + +- LDAP "Sync Roles" option doesn't work for custom roles ([#26842](https://github.com/RocketChat/Rocket.Chat/pull/26842)) + + Previously the sync of custom fields on LDAP wasn't working because the check was assuming that the `name` of the role is the same value from `_id`, which is the same for initial roles, but different for custom. + +- LDAP groups to channel mapping attempts to create a new room instead of using an existing one ([#27312](https://github.com/RocketChat/Rocket.Chat/pull/27312)) + + - Check rooms' name and **display name** in order to confirm they don't exist (and then try to create a new room). + +- Livechat: Allow resolving external image and media blocks ([#27387](https://github.com/RocketChat/Rocket.Chat/pull/27387)) + + Allow external urls to be viewed on livechat. + +- MarkdownText component not respecting `Markdown_SupportSchemesForLink` setting ([#27245](https://github.com/RocketChat/Rocket.Chat/pull/27245)) + +- Marketplace app details page back-button behavior ([#27062](https://github.com/RocketChat/Rocket.Chat/pull/27062)) + + Jira task: [MKP-26](https://rocketchat.atlassian.net/browse/MKP-26?atlOrigin=eyJpIjoiM2I4MzVhYmQ2OWRkNDE0ZGI4NWZkMzE3MDQwNmIxMzMiLCJwIjoiaiJ9) + + Fixed the behavior of the marketplace app details page back button. Now it will return the user to the page they accessed the app details from. Also, refactored the overall routing of the marketplace and removed the admin-apps route as everything is now handled by the admin-marketplace route. + + Demo gif: + ![apps-back-button](https://user-images.githubusercontent.com/43561537/195709074-a886472e-5462-474e-8f65-5cfa33d30263.gif) + +- Message Parser version upgrade ([#27284](https://github.com/RocketChat/Rocket.Chat/pull/27284)) + +- Message search breaking URL, usertags and emojis ([#20878](https://github.com/RocketChat/Rocket.Chat/pull/20878) by [@TBG-FR](https://github.com/TBG-FR)) + +- Missing React When Read Only setting on Admin Rooms Edit ([#27183](https://github.com/RocketChat/Rocket.Chat/pull/27183)) + + When the user was editing a room in the admin, he could not set React When Read Only because the option was not there unlike a normal room edit. So i added the option. + +- Modifying userActionIndicator syntax for translations ([#27004](https://github.com/RocketChat/Rocket.Chat/pull/27004) by [@TBG-FR](https://github.com/TBG-FR)) + +- multiple user assigned for a role ([#23741](https://github.com/RocketChat/Rocket.Chat/pull/23741) by [@Aman-Maheshwari](https://github.com/Aman-Maheshwari)) + +- Navigate to home after deleting a channel from edit screen ([#21602](https://github.com/RocketChat/Rocket.Chat/pull/21602) by [@sumukhah](https://github.com/sumukhah)) + +- Removed mobile requirement for showing real name ([#26968](https://github.com/RocketChat/Rocket.Chat/pull/26968) by [@TedsCabin](https://github.com/TedsCabin)) + + Removed the mobile requirement for allowing real names to be used in message headers. + +- Replace regex not compatible with safari ([#27294](https://github.com/RocketChat/Rocket.Chat/pull/27294)) + +- Room Avatar being deleted after upload. ([#27060](https://github.com/RocketChat/Rocket.Chat/pull/27060)) + + Remove avatar before updating it. S3 already overwrites the old image, but since this part of the code is shared among many other File Storage providers, we need to make this deletion before the upload. + +- RoomForeword design ([#27196](https://github.com/RocketChat/Rocket.Chat/pull/27196)) + + Before + ![image](https://user-images.githubusercontent.com/60678893/200065803-aaafe740-62f6-4d11-b9a4-c4f394f00291.png) + + + After + image + +- Scrollable report message ([#26853](https://github.com/RocketChat/Rocket.Chat/pull/26853) by [@yasemincidem](https://github.com/yasemincidem)) + +- Set default value "false" for global search. ([#25568](https://github.com/RocketChat/Rocket.Chat/pull/25568) by [@ivan1kazantsev](https://github.com/ivan1kazantsev)) + + If we disable the "global search", then the "global search" checkbox removes from the UI. It's not what we want. I think, we should set the default to "false", because the default is to search inside the channel/dialog. + +- Show a consistent name on information screen ([#21603](https://github.com/RocketChat/Rocket.Chat/pull/21603) by [@sumukhah](https://github.com/sumukhah)) + +- Show Favorite icon only if user has joined room ([#21976](https://github.com/RocketChat/Rocket.Chat/pull/21976)) + + Before: There was a favorite button even if the user hasn't joined the room + + After: + + ![favorite new](https://user-images.githubusercontent.com/56491104/117336514-e8a14d00-aeb9-11eb-8c06-618bdaefa35f.png) + +- Shrug missing backslash character ([#27233](https://github.com/RocketChat/Rocket.Chat/pull/27233)) + + Previously the escape character `\` was escaping everything. + + To avoid unexpected text formatting errors it was restricted to only escape curtains chars like: * _ ~ ` # . + Doing so the Shrug had to change in the code to display the correct ASCII Art + +- Sidebar context menu in searchList ([#23830](https://github.com/RocketChat/Rocket.Chat/pull/23830) by [@Aman-Maheshwari](https://github.com/Aman-Maheshwari)) + + Removed onClose function from the Box Component inside `searchList.js` as this component wraps the complete list which is rendered and when clicked on the any rendered row inside the component it closes the searchList preventing the context menu to be displayed. + Also added `usePreventDefault` hook. + ## Before + + https://user-images.githubusercontent.com/50165440/144127826-9b6d3e5e-9442-49dc-89c8-b604b910be4c.mp4 + + ## After + + https://user-images.githubusercontent.com/50165440/144127815-d60e1026-a0eb-4e9b-a7f3-fe80dd06a2d8.mp4 + +- Sidebar Room list extended preview not updating on new messages. ([#27259](https://github.com/RocketChat/Rocket.Chat/pull/27259)) + +- Sort RecordList items in REVERSE chronological order, not FORWARD ([#27201](https://github.com/RocketChat/Rocket.Chat/pull/27201) by [@nmagedman](https://github.com/nmagedman)) + + Sort items in the Files sidebar in *reverse* chronological order (newest at top, oldest at bottom), as it did _before_ RC v3.11.0. + +- The parent room icon is now clickable ([#21655](https://github.com/RocketChat/Rocket.Chat/pull/21655) by [@shrinish123](https://github.com/shrinish123)) + + The parent room icon as shown in the video was not clickable but the cursor type on the icon was a pointer. Now even clicking on the icon or anywhere on the parent room tag will redirect you to the parent room. + + Before : + + https://user-images.githubusercontent.com/56491104/115318759-06717100-a19c-11eb-85e6-f3ad4d788721.mp4 + + + After: + + + https://user-images.githubusercontent.com/56491104/115318784-15582380-a19c-11eb-9aca-b40b872774ad.mp4 + +- Thread view expand command in wide screens ([#23136](https://github.com/RocketChat/Rocket.Chat/pull/23136) by [@edward-raven](https://github.com/edward-raven)) + +- ThreadRow hover color ([#27166](https://github.com/RocketChat/Rocket.Chat/pull/27166)) + +- Threads replied message not clickable on new message template ([#27359](https://github.com/RocketChat/Rocket.Chat/pull/27359)) + + Add the link to the parent message on the `ThreadMessagePreview` component; + Add `message ignored` status to the parent message too; + Also, allow clicking the message when is ignored status. + +- UiKit modals taking 5 seconds to close ([#27225](https://github.com/RocketChat/Rocket.Chat/pull/27225)) + +- Unable to set idleTimeLimit for users ([#26951](https://github.com/RocketChat/Rocket.Chat/pull/26951)) + +- Upgrading fuselage package and fix quote message prepend ([#27307](https://github.com/RocketChat/Rocket.Chat/pull/27307)) + + Adding heading styles to message + + + ### [OLD] As it was before this change: + image + + ### [NEW] As it is NOW: + image + + --- + + Fix heading style in quote messages + + Before: + Screen Shot 2022-11-22 at 14 41 55 + + After: + Screen Shot 2022-11-22 at 14 41 47 + +- Uploading Custom Sound files not working, but showing success ([#27177](https://github.com/RocketChat/Rocket.Chat/pull/27177)) + +- Use name if fname is undefined ([#20459](https://github.com/RocketChat/Rocket.Chat/pull/20459) by [@aKn1ghtOut](https://github.com/aKn1ghtOut)) + + In the default general room(and possibly in other cases), the fname property is not set. The site should use the "name" property as a fallback in such cases. + + ### After fix + ![Screenshot from 2021-01-28 03-47-19](https://user-images.githubusercontent.com/38764067/106062371-b0e97300-611c-11eb-97de-1ff4c668a4c8.png) + ![Screenshot from 2021-01-28 03-47-55](https://user-images.githubusercontent.com/38764067/106062374-b21aa000-611c-11eb-83db-93a3d0858d46.png) + +- User approval email doesn't display username and e-mail when user logs in with OAuth ([#27111](https://github.com/RocketChat/Rocket.Chat/pull/27111) by [@carlosrodrigues94](https://github.com/carlosrodrigues94)) + +- User auto complete breaks on enter key press ([#27213](https://github.com/RocketChat/Rocket.Chat/pull/27213)) + +- User email address does not change when provisioned by OAuth ([#27148](https://github.com/RocketChat/Rocket.Chat/pull/27148) by [@carlosrodrigues94](https://github.com/carlosrodrigues94)) + +- UserCard not opening inside Threads ([#27096](https://github.com/RocketChat/Rocket.Chat/pull/27096)) + +
+🔍 Minor changes + + +- Bump version to 5.4.0-develop ([#27439](https://github.com/RocketChat/Rocket.Chat/pull/27439)) + +- Chore: Add deprecation warning to settings ([#27295](https://github.com/RocketChat/Rocket.Chat/pull/27295)) + + ![image](https://user-images.githubusercontent.com/40830821/202707905-dc7e2b02-35ec-4abd-9b91-26b6e66a7124.png) + + List of settings: + - Show edited status + - Allow Message snippeting + - Show formating Tips + - Disable Embeded for Users + - Issue tracker links + - Message attachments > Group Attachment Buttons + - Markdown > All settings inside Group + - Autolinker > All settings inside Group + + Edited Message for old federation. + +- Chore: Add info log to remove all rooms method ([#27106](https://github.com/RocketChat/Rocket.Chat/pull/27106)) + +- Chore: Add tests for omni-jobs & add more context in system messages for jobs ([#27048](https://github.com/RocketChat/Rocket.Chat/pull/27048)) + +- Chore: Added tooltip to options of message-actions ([#24043](https://github.com/RocketChat/Rocket.Chat/pull/24043) by [@aswinidev](https://github.com/aswinidev)) + + https://user-images.githubusercontent.com/76481696/147604643-253d0577-65d6-4bfe-b67e-49a7cc67c03e.mp4 + +- Chore: also send thread to channel translations ([#27242](https://github.com/RocketChat/Rocket.Chat/pull/27242)) + + image + +- Chore: Apps/Marketplace code organization ([#27061](https://github.com/RocketChat/Rocket.Chat/pull/27061)) + +- Chore: Beta Dark Theme switch ([#27324](https://github.com/RocketChat/Rocket.Chat/pull/27324)) + + Add RadioButton on UserDropDown to toggle between light and dark theme. + +- Chore: Bump actions/upload-artifact from 2 to 3 ([#27109](https://github.com/RocketChat/Rocket.Chat/pull/27109) by [@rettinghaus](https://github.com/rettinghaus)) + + Bump actions/upload-artifact from 2 to 3 (no changes in behavior expected) + +- Chore: bumping apps engine version ([#27414](https://github.com/RocketChat/Rocket.Chat/pull/27414)) + +- Chore: change apps-engine version ([#27326](https://github.com/RocketChat/Rocket.Chat/pull/27326)) + +- Chore: Convert chat history react ([#27302](https://github.com/RocketChat/Rocket.Chat/pull/27302)) + +- Chore: Convert client/views/directory/hooks to ts ([#26936](https://github.com/RocketChat/Rocket.Chat/pull/26936)) + +- Chore: Convert client/views/directory/RoomTags to ts ([#26937](https://github.com/RocketChat/Rocket.Chat/pull/26937)) + +- Chore: Convert omni libs to typescript ([#27205](https://github.com/RocketChat/Rocket.Chat/pull/27205)) + +- Chore: Converting game center to typescript ([#26915](https://github.com/RocketChat/Rocket.Chat/pull/26915)) + +- Chore: create AccountProfileForm endpoints ([#26415](https://github.com/RocketChat/Rocket.Chat/pull/26415)) + + Created the '/v1/users.checkUsernameAvailability' and other endpoints for the `apps/meteor/client/views/account/profile/AccountProfileForm.tsx` file, and added Ajv validations. + +- Chore: create MailerRoute endpoints ([#26742](https://github.com/RocketChat/Rocket.Chat/pull/26742)) + + Created 'email-inbox.sendMail' endpoint for the `apps/meteor/client/views/admin/mailer/MailerRoute.tsx` file. + +- Chore: Create new endpoint for test webhooks and deprecate meteor method ([#27160](https://github.com/RocketChat/Rocket.Chat/pull/27160)) + +- Chore: Create unique index for `E2EKey` field ([#27301](https://github.com/RocketChat/Rocket.Chat/pull/27301)) + +- Chore: CreateTeamModal Refactor ([#27027](https://github.com/RocketChat/Rocket.Chat/pull/27027)) + + Jira Issue: [UFR-36] + + - Replace `useForm` + - Improve UI validations on Modal + - Add ToastBar message on creating a team + +- Chore: Cursor pointer to all the action buttons ([#24440](https://github.com/RocketChat/Rocket.Chat/pull/24440) by [@sidmohanty11](https://github.com/sidmohanty11)) + + https://user-images.githubusercontent.com/73601258/152863890-88035cbb-ba14-45c4-92ca-22ab4f566281.mp4 + +- Chore: deprecate refreshClients methods ([#26956](https://github.com/RocketChat/Rocket.Chat/pull/26956)) + + Created the 'assets.refreshClients' endpoint for the `apps/meteor/client/views/admin/settings/groups/AssetsGroupPage.tsx` file. + +- Chore: Deprecation warning on 'typing' stream event. ([#27299](https://github.com/RocketChat/Rocket.Chat/pull/27299)) + +- Chore: docs grammar fix ([#26894](https://github.com/RocketChat/Rocket.Chat/pull/26894) by [@tusharxoxoxo](https://github.com/tusharxoxoxo)) + +- Chore: Enable PR Title Checker for forks ([#27144](https://github.com/RocketChat/Rocket.Chat/pull/27144)) + +- Chore: Fix grammatical typos in release.md ([#21297](https://github.com/RocketChat/Rocket.Chat/pull/21297) by [@sumukhah](https://github.com/sumukhah)) + +- Chore: Fix missing license for forks ([#27258](https://github.com/RocketChat/Rocket.Chat/pull/27258)) + +- Chore: Fix typo in pa-in.js ([#26717](https://github.com/RocketChat/Rocket.Chat/pull/26717) by [@eltociear](https://github.com/eltociear)) + +- Chore: Fixed typo in a comment ([#27316](https://github.com/RocketChat/Rocket.Chat/pull/27316) by [@xareyli](https://github.com/xareyli)) + +- Chore: Improve configurations related to Typescript in Livechat ([#27232](https://github.com/RocketChat/Rocket.Chat/pull/27232)) + +- Chore: Make it easier to run micro services ([#27223](https://github.com/RocketChat/Rocket.Chat/pull/27223)) + + You can now run a microservices environment with `yarn turbo run ms` + +- Chore: Migrate EE LivechatRooms model to typescript ([#27046](https://github.com/RocketChat/Rocket.Chat/pull/27046)) + +- Chore: New Password field is confusing ([#20338](https://github.com/RocketChat/Rocket.Chat/pull/20338) by [@im-adithya](https://github.com/im-adithya)) + +- Chore: README.md ([#21974](https://github.com/RocketChat/Rocket.Chat/pull/21974) by [@satishp962](https://github.com/satishp962)) + +- Chore: Refactor LeaveTeam to Typescript ([#27197](https://github.com/RocketChat/Rocket.Chat/pull/27197)) + + Additionally, it fixes: + - Users would be able to select team channels that they want to leave while leaving the team. + - Users would now automatically leave from team channels he/she selected. + + BEFORE + + + + https://user-images.githubusercontent.com/55157259/116005794-24205980-a626-11eb-888e-59e42ca21f9a.mp4 + + + + + + BEFORE + + https://user-images.githubusercontent.com/55157259/115970150-4babef00-a55e-11eb-97c9-45683ac16cc1.mp4 + + AFTER + + https://user-images.githubusercontent.com/55157259/116005344-21bd0000-a624-11eb-8e58-a956579a08b4.mp4 + + + AFTER + + https://user-images.githubusercontent.com/55157259/115970155-5070a300-a55e-11eb-877f-862dd9a974d7.mp4 + +- Chore: remove auto label action ([#27192](https://github.com/RocketChat/Rocket.Chat/pull/27192)) + +- Chore: Remove blank owner field from rooms ([#21766](https://github.com/RocketChat/Rocket.Chat/pull/21766) by [@Kartik18g](https://github.com/Kartik18g)) + +- Chore: Remove js-preventer Action ([#27195](https://github.com/RocketChat/Rocket.Chat/pull/27195)) + +- Chore: Remove role requirement to use change streams ([#27281](https://github.com/RocketChat/Rocket.Chat/pull/27281)) + + We used to require the `clusterMonitor` role to be able to use Change Streams because we performed a `serverStatus` command, to be able to check if the requirements for change streams are met (like using wired tiger for example). But since our minimum MongoDB supported version is now 4.2, and MMAPv1 [was removed on this version](https://www.mongodb.com/docs/v4.2/core/storage-engines/), there is no need to check that. + + The new approach is just try to use change streams, if it fails for any reason, fallback to oplog. + + If oplog fails as well, we're now halting the process, since it wasn't able to establish a connection for reading real time data, something that is crucial for the application. An additional check was added to make sure `$MONGO_OPLOG_URL` is pointing to the `local` database. + +- Chore: Remove secrets.RC_TURBO_GH_TOKEN dep from build ([#27176](https://github.com/RocketChat/Rocket.Chat/pull/27176)) + +- Chore: Remove SoundRow.js ([#27215](https://github.com/RocketChat/Rocket.Chat/pull/27215)) + +- Chore: Remove turborepo if env is not set ([#27199](https://github.com/RocketChat/Rocket.Chat/pull/27199)) + +- Chore: Remove unused css ([#27289](https://github.com/RocketChat/Rocket.Chat/pull/27289)) + +- Chore: removing useEndpointData from license api ([#26634](https://github.com/RocketChat/Rocket.Chat/pull/26634)) + + The deprecated hook `useEndpointData` was removed and changed to `useMethod` + `useQuery`separated in a hook. + + In `useQuery` options we added an option to keep the cache as `Infinity` until the queries are invalidated or the page refreshes, also the query keys were changed to consolidate the keys and manage the cache in the best way possible to avoid unnecessary API calls. + + In settings changed or user action that impact the License status was added a method to invalidate the cache for license query keys + + E.g: `queryClient.invalidateQueries(['licenses']);` + +- Chore: Replace all saveUserPreferences method calls ([#26187](https://github.com/RocketChat/Rocket.Chat/pull/26187)) + +- Chore: Restrict `ChatMessages` API - Phase 1 ([#27191](https://github.com/RocketChat/Rocket.Chat/pull/27191)) + + It prepares `ChatMessages` to be splitted into smaller components to handle the interaction of a list of messages and the message composer. + +- Chore: Rewrite AutoCompleteDepartment to TypeScript ([#27198](https://github.com/RocketChat/Rocket.Chat/pull/27198)) + + Department field inside of current chats is one of the places who uses AutoCompleteDeparment: + ![image](https://user-images.githubusercontent.com/17487063/200659774-9db7b19d-1e5f-471b-8b7d-540ef3aa59fb.png) + +- Chore: Rewrite the label/description of the Push_request_content_from_server setting ([#27136](https://github.com/RocketChat/Rocket.Chat/pull/27136) by [@nmagedman](https://github.com/nmagedman)) + + Documentation: Clarify the meaning/effect of the setting Push_request_content_from_server ("Fetch full message content from the server on receipt"), which can lead to unexpected "You have a new message" notifications + +- Chore: Show better error logs ([#27156](https://github.com/RocketChat/Rocket.Chat/pull/27156)) + +- Chore: subscriptions.read accepts both "roomId" and "rid" as payload ([#20312](https://github.com/RocketChat/Rocket.Chat/pull/20312) by [@lucassartor](https://github.com/lucassartor)) + + Adding `roomId` as another option of payload in the `subscriptions.read` endpoint besides from `rid`. + +- Chore: Test for import ([#26871](https://github.com/RocketChat/Rocket.Chat/pull/26871)) + +- Chore: Update Apps-Engine to latest ([#27433](https://github.com/RocketChat/Rocket.Chat/pull/27433)) + +- Chore: Update badge tokens ([#27363](https://github.com/RocketChat/Rocket.Chat/pull/27363)) + +- Chore: Update dark theme tokens ([#27386](https://github.com/RocketChat/Rocket.Chat/pull/27386)) + + Update dark theme tokens: + - surface-tint + - button-background-secondary-disabled + - button-background-secondary-danger-disabled + - all status-background + - all status-font + +- Chore: Update tokens ([#27408](https://github.com/RocketChat/Rocket.Chat/pull/27408)) + + Add/update tokens on light and dark palette: + - update stroke-extra-light color + - add status-warning-2 + - add status-service-3 + - add font-pure-white + - add font-pure-black + +- Chore: Updates rocket.cat's logo to match colors of our new logo ([#27314](https://github.com/RocketChat/Rocket.Chat/pull/27314)) + +- Chore: UserAvatar wrapper missing key in RoomForeword ([#27300](https://github.com/RocketChat/Rocket.Chat/pull/27300)) + +- Chore(deps): Bump felixmosh/turborepo-gh-artifacts from 1 to 2 ([#27170](https://github.com/RocketChat/Rocket.Chat/pull/27170) by [@dependabot[bot]](https://github.com/dependabot[bot])) + +- i18n: Language update from LingoHub 🤖 on 2022-10-24Z ([#27127](https://github.com/RocketChat/Rocket.Chat/pull/27127)) + +- i18n: Language update from LingoHub 🤖 on 2022-10-31Z ([#27150](https://github.com/RocketChat/Rocket.Chat/pull/27150)) + +- i18n: Language update from LingoHub 🤖 on 2022-11-07Z ([#27202](https://github.com/RocketChat/Rocket.Chat/pull/27202)) + +- i18n: Language update from LingoHub 🤖 on 2022-11-14Z ([#27255](https://github.com/RocketChat/Rocket.Chat/pull/27255)) + +- i18n: Language update from LingoHub 🤖 on 2022-11-21Z ([#27306](https://github.com/RocketChat/Rocket.Chat/pull/27306)) + +- i18n: Language update from LingoHub 🤖 on 2022-11-28Z ([#27375](https://github.com/RocketChat/Rocket.Chat/pull/27375)) + +- i18n: Language update from LingoHub 🤖 on 2022-11-29Z ([#27410](https://github.com/RocketChat/Rocket.Chat/pull/27410)) + +- Merge master into develop & Set version to 5.4.0-develop ([#27162](https://github.com/RocketChat/Rocket.Chat/pull/27162)) + +- Regression: Admin menu apps option not working ([#27422](https://github.com/RocketChat/Rocket.Chat/pull/27422)) + + Solved a bug caused by the RC production build steps breaking the flow router triggersEnter event that did some rerouting for marketplace. Removed the cited function from the routes.tsx file, and now the rerouting is done directly inside the AppsRoute file. + Demo gif: + ![apps_rerouting_issue](https://user-images.githubusercontent.com/43561537/205097014-644be3fd-913e-48d6-8e2b-c082bd8f80cf.gif) + +- Regression: Bad words Filtering not working on new Message Parser ([#27368](https://github.com/RocketChat/Rocket.Chat/pull/27368) by [@xareyli](https://github.com/xareyli)) + + Was + ![forGH](https://user-images.githubusercontent.com/118266546/204087809-fca6152b-63db-4873-88b8-d86aeb324531.png) + + Now + ![forGH2](https://user-images.githubusercontent.com/118266546/204087822-e3273127-a4f0-4a45-a73e-910eb48c9b6f.png) + +- Regression: Custom fields form not showing in user profile nor admin ([#27244](https://github.com/RocketChat/Rocket.Chat/pull/27244)) + +- Regression: Elevation and components z-index fixes ([#27421](https://github.com/RocketChat/Rocket.Chat/pull/27421)) + +- Regression: fix contact chat history borders ([#27319](https://github.com/RocketChat/Rocket.Chat/pull/27319)) + +- Regression: Fix custom oauth undefined clientConfig ([#27320](https://github.com/RocketChat/Rocket.Chat/pull/27320)) + +- Regression: Fix issues with ContactHistoryItem ([#27406](https://github.com/RocketChat/Rocket.Chat/pull/27406)) + +- Regression: Fix sidebar token highlighted usage ([#27334](https://github.com/RocketChat/Rocket.Chat/pull/27334)) + +- Regression: fix small issues before release ([#27443](https://github.com/RocketChat/Rocket.Chat/pull/27443)) + +- Regression: Login and Registration UI Tweaks ([#27411](https://github.com/RocketChat/Rocket.Chat/pull/27411)) + +- Regression: message-box-editing-color ([#27420](https://github.com/RocketChat/Rocket.Chat/pull/27420)) + +- Regression: Old threads not opening ([#27384](https://github.com/RocketChat/Rocket.Chat/pull/27384)) + +- Regression: Quoting Issue ([#27369](https://github.com/RocketChat/Rocket.Chat/pull/27369) by [@henit-chobisa](https://github.com/henit-chobisa)) + +- Regression: Remove actions from VideoConf Message Block ([#27344](https://github.com/RocketChat/Rocket.Chat/pull/27344)) + +- Regression: Restore fuselage-ui-kit version ([#27331](https://github.com/RocketChat/Rocket.Chat/pull/27331)) + +- Regression: Team name validation on Create Team Modal ([#27345](https://github.com/RocketChat/Rocket.Chat/pull/27345)) + +- Regression: Update VideoConf components colors ([#27365](https://github.com/RocketChat/Rocket.Chat/pull/27365)) + +- Regression: Update VideoConfListItem Color Tokens ([#27402](https://github.com/RocketChat/Rocket.Chat/pull/27402)) + +- Regression: videoconf block showing a zero when no user has joined the call ([#27332](https://github.com/RocketChat/Rocket.Chat/pull/27332)) + +- Regression: VideoConf default info modal not showing meeting URL as a link ([#27382](https://github.com/RocketChat/Rocket.Chat/pull/27382)) + + Before: + ![image](https://user-images.githubusercontent.com/55164754/204304308-87f6e6d3-8411-4974-8628-d81fd9aa07e5.png) + + + After: + ![image](https://user-images.githubusercontent.com/55164754/204303619-6bc7b014-7b11-40a5-a1de-1530e76fff8b.png) + +
+ +### 👩‍💻👨‍💻 Contributors 😍 + +- [@Aman-Maheshwari](https://github.com/Aman-Maheshwari) +- [@Darshilp326](https://github.com/Darshilp326) +- [@Himanshu664](https://github.com/Himanshu664) +- [@JoshMcCullough](https://github.com/JoshMcCullough) +- [@Kartik18g](https://github.com/Kartik18g) +- [@TBG-FR](https://github.com/TBG-FR) +- [@TedsCabin](https://github.com/TedsCabin) +- [@aKn1ghtOut](https://github.com/aKn1ghtOut) +- [@aswinidev](https://github.com/aswinidev) +- [@carlosrodrigues94](https://github.com/carlosrodrigues94) +- [@dependabot[bot]](https://github.com/dependabot[bot]) +- [@edward-raven](https://github.com/edward-raven) +- [@eltociear](https://github.com/eltociear) +- [@henit-chobisa](https://github.com/henit-chobisa) +- [@im-adithya](https://github.com/im-adithya) +- [@ivan1kazantsev](https://github.com/ivan1kazantsev) +- [@lucassartor](https://github.com/lucassartor) +- [@nmagedman](https://github.com/nmagedman) +- [@rettinghaus](https://github.com/rettinghaus) +- [@satishp962](https://github.com/satishp962) +- [@shrinish123](https://github.com/shrinish123) +- [@sidmohanty11](https://github.com/sidmohanty11) +- [@sumukhah](https://github.com/sumukhah) +- [@tusharxoxoxo](https://github.com/tusharxoxoxo) +- [@xareyli](https://github.com/xareyli) +- [@yasemincidem](https://github.com/yasemincidem) + +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@AllanPazRibeiro](https://github.com/AllanPazRibeiro) +- [@KevLehman](https://github.com/KevLehman) +- [@LucianoPierdona](https://github.com/LucianoPierdona) +- [@MarcosSpessatto](https://github.com/MarcosSpessatto) +- [@MartinSchoeler](https://github.com/MartinSchoeler) +- [@aleksandernsilva](https://github.com/aleksandernsilva) +- [@casalsgh](https://github.com/casalsgh) +- [@cauefcr](https://github.com/cauefcr) +- [@d-gubert](https://github.com/d-gubert) +- [@debdutdeb](https://github.com/debdutdeb) +- [@dougfabris](https://github.com/dougfabris) +- [@felipe-rod123](https://github.com/felipe-rod123) +- [@filipemarins](https://github.com/filipemarins) +- [@gabriellsh](https://github.com/gabriellsh) +- [@ggazzo](https://github.com/ggazzo) +- [@guijun13](https://github.com/guijun13) +- [@hugocostadev](https://github.com/hugocostadev) +- [@juliajforesti](https://github.com/juliajforesti) +- [@matheusbsilva137](https://github.com/matheusbsilva137) +- [@matheuslc](https://github.com/matheuslc) +- [@murtaza98](https://github.com/murtaza98) +- [@nishant23122000](https://github.com/nishant23122000) +- [@pierre-lehnen-rc](https://github.com/pierre-lehnen-rc) +- [@rique223](https://github.com/rique223) +- [@sampaiodiego](https://github.com/sampaiodiego) +- [@tapiarafael](https://github.com/tapiarafael) +- [@tassoevan](https://github.com/tassoevan) +- [@thassiov](https://github.com/thassiov) +- [@tiagoevanp](https://github.com/tiagoevanp) +- [@weslley543](https://github.com/weslley543) +- [@yash-rajpal](https://github.com/yash-rajpal) + +# 5.3.6 +`2023-01-24 · 1 🚀 · 1 🐛 · 2 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🚀 Improvements + + +- Emoji picker for large amount of custom emojis ([#27745](https://github.com/RocketChat/Rocket.Chat/pull/27745)) + +### 🐛 Bug fixes + + +- Not all messages in chat conversations are available when forwarding between agents or departments. ([#27816](https://github.com/RocketChat/Rocket.Chat/pull/27816)) + +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@filipemarins](https://github.com/filipemarins) +- [@sampaiodiego](https://github.com/sampaiodiego) + +# 5.3.5 +`2022-12-02 · 1 🐛 · 1 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🐛 Bug fixes + + +- Fix watch db being started on Micro Services env ([#27435](https://github.com/RocketChat/Rocket.Chat/pull/27435)) + +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@ggazzo](https://github.com/ggazzo) + +# 5.3.4 +`2022-11-29 · 1 🐛 · 1 🔍 · 2 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🐛 Bug fixes + + +- Thread messages being included in the room history even though they are not displayed ([#27391](https://github.com/RocketChat/Rocket.Chat/pull/27391)) + +
+🔍 Minor changes + + +- Release 5.3.3 ([#27340](https://github.com/RocketChat/Rocket.Chat/pull/27340)) + +
+ +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@dougfabris](https://github.com/dougfabris) +- [@ggazzo](https://github.com/ggazzo) + +# 5.3.3 +`2022-11-24 · 1 🐛 · 1 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🐛 Bug fixes + + +- Security Hotfix (https://docs.rocket.chat/guides/security/security-updates) + +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@ggazzo](https://github.com/ggazzo) + +# 5.3.2 +`2022-11-18 · 2 🐛 · 2 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🐛 Bug fixes + + +- Replace regex not compatible with safari ([#27294](https://github.com/RocketChat/Rocket.Chat/pull/27294)) + +- Sidebar Room list extended preview not updating on new messages. ([#27259](https://github.com/RocketChat/Rocket.Chat/pull/27259)) + +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@filipemarins](https://github.com/filipemarins) +- [@gabriellsh](https://github.com/gabriellsh) + +# 5.3.1 +`2022-11-14 · 5 🐛 · 1 🔍 · 5 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🐛 Bug fixes + + +- File upload receiving whole file to apply limits ([#27105](https://github.com/RocketChat/Rocket.Chat/pull/27105)) + +- Hide system messages setting not being respected. ([#27151](https://github.com/RocketChat/Rocket.Chat/pull/27151)) + + There was a query missing the parameters in the client. + + Also added a few tests to help reduce the risk of this happening again. + +- Multi instance error message ([#27243](https://github.com/RocketChat/Rocket.Chat/pull/27243)) + +- Next schedule check for Apps ([#27240](https://github.com/RocketChat/Rocket.Chat/pull/27240)) + +- User merge by e-mail on OAuth is case-sensitive ([#27167](https://github.com/RocketChat/Rocket.Chat/pull/27167)) + + - Ignore case when searching for a user by email. + +
+🔍 Minor changes + + +- Chore: Check for Cloud client secret to check if workspace is registered ([#27229](https://github.com/RocketChat/Rocket.Chat/pull/27229)) + +
+ +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@casalsgh](https://github.com/casalsgh) +- [@gabriellsh](https://github.com/gabriellsh) +- [@ggazzo](https://github.com/ggazzo) +- [@matheusbsilva137](https://github.com/matheusbsilva137) +- [@sampaiodiego](https://github.com/sampaiodiego) + +# 5.3.0 +`2022-11-01 · 3 🎉 · 4 🚀 · 13 🐛 · 23 🔍 · 23 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🎉 New features + + +- Add new endpoint 'livechat/room.saveInfo' & deprecate 'livechat:saveInfo' meteor method ([#26789](https://github.com/RocketChat/Rocket.Chat/pull/26789)) + +- Health check for data stream ([#27026](https://github.com/RocketChat/Rocket.Chat/pull/27026)) + +- Matrix federation events coverage expansion (adding support for 3 extra events) ([#26859](https://github.com/RocketChat/Rocket.Chat/pull/26859)) + + FED-17 + FED-25 + FED-27 + FED-28 + FED-30 + The goal of this PR is to add support for more events on Matrix Federation feature. The new supported events are: + + - Mentions + - User avatar sync + - Quotes + +### 🚀 Improvements + + +- Automatically open call info contextual bar when voip room is opened ([#26963](https://github.com/RocketChat/Rocket.Chat/pull/26963)) + + This pull request adds the logic necessary to automatically open the call information contextual bar when entering a voip room. This mirrors the behavior we already have for livechat rooms. + + **Before:** + ![before-voip-480p-speed](https://user-images.githubusercontent.com/6494543/192610275-a81ab19e-2b60-4466-9e04-81b2e938afda.gif) + + **After:** + ![after-voip-480p-speed](https://user-images.githubusercontent.com/6494543/192610356-896ccd48-8c26-4fb9-8fb4-f792ab63e6d5.gif) + +- Better /health response when service not healthy ([#27091](https://github.com/RocketChat/Rocket.Chat/pull/27091)) + + Not healthy services will send a HTTP 500 response when not healthy. + +- Change status/price badge to fuselage tag ([#27044](https://github.com/RocketChat/Rocket.Chat/pull/27044)) + + ## Jira task: [MKP-131](https://rocketchat.atlassian.net/browse/MKP-131?atlOrigin=eyJpIjoiODRjOTk4OGYyZDAwNDIzNmI5N2EyZGRhNTUxOGY2NGEiLCJwIjoiaiJ9) + Changed the custom component that showed prices and statuses to a fuselage Tag component for maintainability reasons since after this PR every general design change to the tag component will be automatically reflected in the marketplace UI. + Demo image (App List): + ![image](https://user-images.githubusercontent.com/43561537/194942430-ba4153f1-2315-4117-85e6-01832cc09d91.png) + + Demo Image (App price): + ![image](https://user-images.githubusercontent.com/43561537/194942498-5ff64a27-7232-47b8-a686-2fda2289e491.png) + +- Respect convert ascii to emoji preference for new message template ([#27038](https://github.com/RocketChat/Rocket.Chat/pull/27038)) + +### 🐛 Bug fixes + + +- Actionable messages are now sent to integrations webhook ([#27052](https://github.com/RocketChat/Rocket.Chat/pull/27052)) + + Actionable messages, with buttons and similar, (saved as blocks internally) were not being sent to external integrations, so CRMs and the like had no visibility on what was the actionable message sent, this PR adds a yaml version of the actions, as well as a proper json object with the same data on the webhook output, so that our clients can have more visibility in their process + +- check if message block has item to show message body ([#27040](https://github.com/RocketChat/Rocket.Chat/pull/27040)) + +- CSS vars usage ([#27107](https://github.com/RocketChat/Rocket.Chat/pull/27107)) + +- Email inbox memory leak on connection failure ([#26850](https://github.com/RocketChat/Rocket.Chat/pull/26850)) + + - Properly removing event listeners on re-connection. + - Attachments handling changed from beforeMessageSent to afterMessageSent, as the id of the message was needed, now rocket.cat will send the "Send Attachment To Email" button. + - Self-disable email inbox when reaching max re-connection attempts + +- Livechat CurrentChats infinity re-rendering ([#27076](https://github.com/RocketChat/Rocket.Chat/pull/27076)) + +- Microphone icon alignment issue (# 27073) ([#27123](https://github.com/RocketChat/Rocket.Chat/pull/27123) by [@mani-rsg](https://github.com/mani-rsg)) + + Aligned microphone icon to its respective position on screen widths <= 500 (mobile screens) + + image + image + +- On hold reactivity for Omnichannel rooms ([#27013](https://github.com/RocketChat/Rocket.Chat/pull/27013)) + + - Fix instabilities from room when changed from on-hold to resume + - Fix gray messages when resume from on-hold + +- Preview message not showing when reply direct message ([#27050](https://github.com/RocketChat/Rocket.Chat/pull/27050)) + +- Remove contact mananger always to support old servers ([#27053](https://github.com/RocketChat/Rocket.Chat/pull/27053)) + +- Remove voip extension when agent is removed or deactivated ([#26960](https://github.com/RocketChat/Rocket.Chat/pull/26960)) + +- starting conferences with mic and cam on their default states do not sync the state with the provider ([#26966](https://github.com/RocketChat/Rocket.Chat/pull/26966)) + + Task: [VC-3] + +- Uncaught error by listening stream-notify-room without subscription ([#27020](https://github.com/RocketChat/Rocket.Chat/pull/27020)) + + fix this: + image + +- Warning about livechat/inquiries.queuedForUser ([#27086](https://github.com/RocketChat/Rocket.Chat/pull/27086)) + +
+🔍 Minor changes + + +- Chore: Apply correct fuselage color tokens ([#27089](https://github.com/RocketChat/Rocket.Chat/pull/27089)) + +- Chore: Bump Apps-Engine version ([#27059](https://github.com/RocketChat/Rocket.Chat/pull/27059)) + +- Chore: bump fuselage packages ([#27157](https://github.com/RocketChat/Rocket.Chat/pull/27157)) + +- Chore: bump fuselage packages ([#27122](https://github.com/RocketChat/Rocket.Chat/pull/27122)) + +- Chore: Email Inbox Sanitization ([#26796](https://github.com/RocketChat/Rocket.Chat/pull/26796)) + + Jira Issue [UFR-3] + + - Rewrite Email Inbox to typescript + - Replace `useForm` + - Fix: return an error if there are no email inboxes in `email-inbox` endpoint + **documentation update**: https://github.com/RocketChat/developer-docs/pull/132 + - Add e2e test cases for creating email inboxes and deleting email inboxes + +- Chore: Implement short description for marketplace apps ([#27030](https://github.com/RocketChat/Rocket.Chat/pull/27030)) + + ## Jira task: [MKP-126](https://rocketchat.atlassian.net/browse/MKP-126) + Implemented the shortDescription field in the marketplace app details header. Now apps have either a shorter description or nothing, in case it doesn't have a shortDescription registered, in their headers description section. + Demo image: + ![image](https://user-images.githubusercontent.com/43561537/194640492-9942f6d9-66ad-4df9-97e8-98c7d51a724c.png) + +- Chore: Refactor AppLogs to TS ([#26938](https://github.com/RocketChat/Rocket.Chat/pull/26938)) + + Rewrote the AppLogs component to TS. Also, improved some error handling logic. + +- Chore: Remove default value from custom home content setting ([#26995](https://github.com/RocketChat/Rocket.Chat/pull/26995)) + + Remove content from `Custom body` setting so that new workspaces don't have initial unstyled HTML in their homepages. + +- Chore: remove excess space from html preview ([#27043](https://github.com/RocketChat/Rocket.Chat/pull/27043)) + +- Chore: Remove Unused CSS ([#27012](https://github.com/RocketChat/Rocket.Chat/pull/27012)) + +- Chore: Switch deprecated fields for projection ([#27025](https://github.com/RocketChat/Rocket.Chat/pull/27025)) + +- Chore: Tests for EE dashboards ([#26974](https://github.com/RocketChat/Rocket.Chat/pull/26974)) + +- Chore: Update Image and link previews ([#27019](https://github.com/RocketChat/Rocket.Chat/pull/27019)) + + - Add message generic cover image preview component to OEmbed Links + - Add new functionalities to URL Image preview, like click to open preview and arrows to move between images in the current chat + - Design changes to keep the original aspect ratio of the image to prevent loss of important image pieces of information + - Add fallback to common issues related to meta tags like `og:image` and others + +- Chore: Use a single notification listener for all videoconf messages ([#26682](https://github.com/RocketChat/Rocket.Chat/pull/26682)) + + Task: [VC-1] + +- Chore: UserCard loader tweaks ([#27068](https://github.com/RocketChat/Rocket.Chat/pull/27068)) + + ### before + ![Kapture 2022-10-14 at 12 47 43](https://user-images.githubusercontent.com/27704687/195888045-6fd900ab-feb1-4dc7-924c-a0fd7634eab6.gif) + + + ### after + ![Kapture 2022-10-14 at 12 45 30](https://user-images.githubusercontent.com/27704687/195887641-652f388b-cf9f-413d-9c07-c0df9a3f7287.gif) + +- i18n: Language update from LingoHub 🤖 on 2022-10-03Z ([#26992](https://github.com/RocketChat/Rocket.Chat/pull/26992)) + +- i18n: Language update from LingoHub 🤖 on 2022-10-10Z ([#27035](https://github.com/RocketChat/Rocket.Chat/pull/27035)) + +- i18n: Language update from LingoHub 🤖 on 2022-10-17Z ([#27082](https://github.com/RocketChat/Rocket.Chat/pull/27082)) + +- Merge master into develop & Set version to 5.3.0-develop ([#27067](https://github.com/RocketChat/Rocket.Chat/pull/27067)) + +- Regression: Quote colors ([#27110](https://github.com/RocketChat/Rocket.Chat/pull/27110)) + + Before + ![image](https://user-images.githubusercontent.com/40830821/196947705-f1b2edf9-7341-4d2a-b8e8-4e3720ab7289.png) + + + After + ![image](https://user-images.githubusercontent.com/40830821/196947512-1267f992-11c7-4ff4-b7a2-9f0b3534f69d.png) + +- Regression: Remove margin-bottom inside UserCard actions ([#27100](https://github.com/RocketChat/Rocket.Chat/pull/27100)) + +- Regression: Toolbox Divider Color ([#27116](https://github.com/RocketChat/Rocket.Chat/pull/27116)) + + ![image](https://user-images.githubusercontent.com/27704687/197018407-d591d6bc-e390-4bcd-9b6a-0bf0a1420bc2.png) + +- Regression: Unify `isLastDocDelayed` logic ([#27120](https://github.com/RocketChat/Rocket.Chat/pull/27120)) + +
+ +### 👩‍💻👨‍💻 Contributors 😍 + +- [@mani-rsg](https://github.com/mani-rsg) + +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@KevLehman](https://github.com/KevLehman) +- [@MarcosSpessatto](https://github.com/MarcosSpessatto) +- [@MartinSchoeler](https://github.com/MartinSchoeler) +- [@aleksandernsilva](https://github.com/aleksandernsilva) +- [@casalsgh](https://github.com/casalsgh) +- [@cauefcr](https://github.com/cauefcr) +- [@d-gubert](https://github.com/d-gubert) +- [@debdutdeb](https://github.com/debdutdeb) +- [@dougfabris](https://github.com/dougfabris) +- [@filipemarins](https://github.com/filipemarins) +- [@gabriellsh](https://github.com/gabriellsh) +- [@ggazzo](https://github.com/ggazzo) +- [@guijun13](https://github.com/guijun13) +- [@hugocostadev](https://github.com/hugocostadev) +- [@juliajforesti](https://github.com/juliajforesti) +- [@murtaza98](https://github.com/murtaza98) +- [@pierre-lehnen-rc](https://github.com/pierre-lehnen-rc) +- [@rique223](https://github.com/rique223) +- [@sampaiodiego](https://github.com/sampaiodiego) +- [@tassoevan](https://github.com/tassoevan) +- [@tiagoevanp](https://github.com/tiagoevanp) +- [@yash-rajpal](https://github.com/yash-rajpal) + +# 5.2.2 +`2023-01-24 · 1 🚀 · 1 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🚀 Improvements + + +- Emoji picker for large amount of custom emojis ([#27745](https://github.com/RocketChat/Rocket.Chat/pull/27745)) + +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@sampaiodiego](https://github.com/sampaiodiego) + +# 5.2.0 +`2022-10-13 · 5 🎉 · 13 🚀 · 19 🐛 · 62 🔍 · 28 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🎉 New features + + +- Add Markup to QuoteAttachment ([#26751](https://github.com/RocketChat/Rocket.Chat/pull/26751)) + +- Get moderators, owners and leaders from room scope via apps-engine ([#26674](https://github.com/RocketChat/Rocket.Chat/pull/26674)) + +- Matrix Federation events coverage expansion (support for 5 more events) ([#26705](https://github.com/RocketChat/Rocket.Chat/pull/26705)) + + The goal of this PR is to add support for more events on Matrix Federation feature. The new supported events are: + + - Edit Messages; + - Delete Messages + - File Upload (including video and audio/voice messages); + - Send emojis on messages; + - Reactions. + +- Move administration links to an exclusive kebab menu ([#26867](https://github.com/RocketChat/Rocket.Chat/pull/26867)) + + Move administration links to an exclusive kebab menu. + + Screen Shot 2022-09-14 at 02 59 03 + +- Sections layout and featured apps for marketplace ([#26514](https://github.com/RocketChat/Rocket.Chat/pull/26514)) + + ### [MKP??+ - Featured Apps](https://app.clickup.com/t/2t1w9x3) + Implemented a new layout for marketplace's apps list page. Now the page has an All apps section and a "featured apps" section in which pre-selected and pre-categorized apps are dynamically shown on the top area of the page to make them stand out. + Demo gif: + ![featured_apps](https://user-images.githubusercontent.com/43561537/184385727-4f44c1d5-d7f7-43bf-a93d-2bc582bd3159.gif) + + ClickUp Task link: https://app.clickup.com/t/2t1w9x3 + +### 🚀 Improvements + + +- Allow delete attachment description on message edit ([#26673](https://github.com/RocketChat/Rocket.Chat/pull/26673)) + +- Better descriptions for VoIP Settings ([#26877](https://github.com/RocketChat/Rocket.Chat/pull/26877)) + +- Changed dial pad appearance to match original design ([#26863](https://github.com/RocketChat/Rocket.Chat/pull/26863)) + + Before: + ![Screen Shot 2022-09-13 at 15 00 34](https://user-images.githubusercontent.com/6494543/189976766-6d085795-a832-4189-898b-4bd631cb4309.png) + + After: + ![Screen Shot 2022-09-13 at 14 59 23](https://user-images.githubusercontent.com/6494543/189976804-c419ac33-6a90-464e-8792-feb0d0ae33e5.png) + +- Include `syncAvatars` on `ldap.syncNow` ([#26824](https://github.com/RocketChat/Rocket.Chat/pull/26824)) + + This PR includes a new call for the method `syncAvatars` when `ldap.syncNow` is called + +- OTR Message ([#24297](https://github.com/RocketChat/Rocket.Chat/pull/24297)) + +- Results of user auto complete ([#26687](https://github.com/RocketChat/Rocket.Chat/pull/26687)) + +- Rounded video attachment ([#26832](https://github.com/RocketChat/Rocket.Chat/pull/26832)) + +- Setting for login email notifications ([#26831](https://github.com/RocketChat/Rocket.Chat/pull/26831)) + +- System messages' consistency ([#26130](https://github.com/RocketChat/Rocket.Chat/pull/26130)) + +- Updating voip tooltips and icons ([#26834](https://github.com/RocketChat/Rocket.Chat/pull/26834)) + + ### This PR includes the following tooltip expression changes: + Call toggle button + * Enabled -> Turn off answer calls + * Disabled -> Turn on answer calls + * Signaling connection disconnected -> Waiting for server connection + + + Chat toggle button + * Available -> Turn off answer chats + * Not available -> Turn on answer chats + + Hold button + * Hold call -> Hold call / Resume call + + Mute button + * Mute -> Turn on microphone / Turn off microphone + + ### Also includes the following icon changes: + + Old: + ![new-1](https://user-images.githubusercontent.com/6494543/189218303-144671cb-6533-46a0-be18-52d62b3701d3.png) + ![new-2](https://user-images.githubusercontent.com/6494543/189218307-8f24797b-bef6-4d8a-9e25-98e96fa59155.png) + ![new-3](https://user-images.githubusercontent.com/6494543/189218309-05a836a3-5c17-4370-9cc6-fd7a6da3d8c2.png) + + + New: + + ![old-1](https://user-images.githubusercontent.com/6494543/189217735-3d9cde83-8e54-421e-b57a-ac9bda748416.png) + ![old-2](https://user-images.githubusercontent.com/6494543/189217738-d4bb2bfb-ddfd-4830-a2e8-a9937e93826a.png) + ![old-3](https://user-images.githubusercontent.com/6494543/189217740-988295bf-9112-4cea-93da-402ea7e82247.png) + +- Use cached EE Cloud license on startup ([#26987](https://github.com/RocketChat/Rocket.Chat/pull/26987)) + +- VideoConference Messages UI ([#26548](https://github.com/RocketChat/Rocket.Chat/pull/26548)) + + + + + + + +- VideoConference Messages UI (#26548)" ([#26961](https://github.com/RocketChat/Rocket.Chat/pull/26961)) + +### 🐛 Bug fixes + + +- **Livechat:** Unread messages badge ([#26843](https://github.com/RocketChat/Rocket.Chat/pull/26843)) + + OC-169 + + Even if the page was reopening, Livechat will inform unread messages + +- Adjusted livechat fallbacks to take null values into account ([#26909](https://github.com/RocketChat/Rocket.Chat/pull/26909)) + +- Admin sidebar navigation ([#26958](https://github.com/RocketChat/Rocket.Chat/pull/26958)) + + ## [MKP-125](https://rocketchat.atlassian.net/browse/MKP-125?atlOrigin=eyJpIjoiMThlMTIwYmFkZWI5NDBlYjhlMWI3YTc1ZDliYTY3NDUiLCJwIjoiaiJ9) + Fix the behavior of the admin sidebar, it didn't activate its options properly on pages that had sub-routes. + Demo gif: + ![sidebar-bug](https://user-images.githubusercontent.com/43561537/192585542-ddd8fd37-e833-4960-ae67-fb408595c7ba.gif) + +- Asset settings description not showing on admin ([#26755](https://github.com/RocketChat/Rocket.Chat/pull/26755)) + +- Check admin setting for whether to display roles or not ([#26601](https://github.com/RocketChat/Rocket.Chat/pull/26601)) + +- Ephemeral messages not respecting katex setting ([#26812](https://github.com/RocketChat/Rocket.Chat/pull/26812)) + +- Expanded thread behind sidebar on small screens ([#26852](https://github.com/RocketChat/Rocket.Chat/pull/26852)) + + Sidebar overlapping expanded threads in window sizes between **1135px and 780px** and but the expanded threads should be limited to sidebar size and should not go through it + + ### **Actual behavior** + ![image](https://user-images.githubusercontent.com/20212776/189692618-b1c0ebdf-36e1-49cb-9179-29b842260a18.png) + + + ### **Expected behavior** + ![image](https://user-images.githubusercontent.com/20212776/189692714-0cce9947-8f72-48af-9a81-04cc521a9833.png) + +- Fix broken legacy message view ([#26819](https://github.com/RocketChat/Rocket.Chat/pull/26819)) + + Fixed `messagesHistory` function, it was filtering messages only with existing threads. + +- Incorrect filter on contact history search ([#26813](https://github.com/RocketChat/Rocket.Chat/pull/26813) by [@neo-clon](https://github.com/neo-clon)) + +- Livechat trigger messages covering all the website ([#26776](https://github.com/RocketChat/Rocket.Chat/pull/26776)) + +- Menu options margin spacing ([#26775](https://github.com/RocketChat/Rocket.Chat/pull/26775)) + + - Change margin spacing from 16-4px to 12-8px + + | before | after | + |--------|-------| + | ![before](https://user-images.githubusercontent.com/48109548/187940409-903eede8-9ade-448d-9211-0e004ccd0ff2.png) | ![after](https://user-images.githubusercontent.com/48109548/187940513-3189ca2a-5f18-4e39-93bb-5843f13fce27.png) | + +- Message sequential after message thread preview ([#26900](https://github.com/RocketChat/Rocket.Chat/pull/26900)) + +- MIME Type fallback for .mov File Extensions ([#26921](https://github.com/RocketChat/Rocket.Chat/pull/26921)) + + Some browsers don't support the MIME type for QuickTime video encoder (.mov), so we had to create a fallback to 'video/mp4'. There are other fallbacks for other browsers, but this is the only one we need for now. + + The fallback func was used in the MediaPreview and VideoAttachments components + +- Old rooms without the associated unit will not be displayed on the current chats ([#26685](https://github.com/RocketChat/Rocket.Chat/pull/26685)) + +- Restore current chats default table order ([#26808](https://github.com/RocketChat/Rocket.Chat/pull/26808)) + +- Sign in with Apple on mobile ([#26827](https://github.com/RocketChat/Rocket.Chat/pull/26827)) + + Our mobile app uses a different method to log in that was removed at #24879 . + + You can also make it available only on mobile: + ![image](https://user-images.githubusercontent.com/8591547/188752062-bef03f01-d995-4422-8a24-984ebed49ce2.png) + + Removes the "Sign in with Apple" text from the log in button. This was something we thought were required by Apple, but it is actually allowed to have just the logo as all others OAuth we have. Source: https://developer.apple.com/design/human-interface-guidelines/technologies/sign-in-with-apple/buttons/#creating-a-custom-sign-in-with-apple-button + +- Typo on new homepage ([#26768](https://github.com/RocketChat/Rocket.Chat/pull/26768)) + +- Unable to send native video recording to Whatsapp ([#26669](https://github.com/RocketChat/Rocket.Chat/pull/26669)) + +- Upload fails when using WebDav as file storage ([#26711](https://github.com/RocketChat/Rocket.Chat/pull/26711)) + +
+🔍 Minor changes + + +- Bump actions/cache from 2 to 3.0.1 ([#25003](https://github.com/RocketChat/Rocket.Chat/pull/25003) by [@dependabot[bot]](https://github.com/dependabot[bot])) + +- Chore: `improve/media-recorder` ([#26426](https://github.com/RocketChat/Rocket.Chat/pull/26426)) + +- Chore: `refactor/room` ([#26675](https://github.com/RocketChat/Rocket.Chat/pull/26675)) + + Replaces `room` Blaze template with React components. + +- Chore: add aria hidden if modal is open ([#26826](https://github.com/RocketChat/Rocket.Chat/pull/26826)) + +- Chore: Add E2E tests to missing omnichannel endpoints ([#26730](https://github.com/RocketChat/Rocket.Chat/pull/26730)) + +- Chore: Add RocketChatDesktop function to open video calls when using Electron ([#26793](https://github.com/RocketChat/Rocket.Chat/pull/26793)) + +- Chore: Add tests to cover issue fixed in #26720 ([#26767](https://github.com/RocketChat/Rocket.Chat/pull/26767)) + +- Chore: break LDAP manager into smaller pieces to improve unit tests ([#26994](https://github.com/RocketChat/Rocket.Chat/pull/26994)) + +- Chore: Bump Apps-Engine version ([#27059](https://github.com/RocketChat/Rocket.Chat/pull/27059)) + +- Chore: Bump fuselage dependencies and implement new tabs variant in marketplace ([#26876](https://github.com/RocketChat/Rocket.Chat/pull/26876)) + + Bumped the necessary dependencies of fuselage and implemented the new tabs component underline variant. + Demo image: + ![image](https://user-images.githubusercontent.com/43561537/190252796-cd4ad872-90e6-413e-92cb-13c0354399da.png) + +- Chore: Bump fuselage to latest ([#27042](https://github.com/RocketChat/Rocket.Chat/pull/27042)) + +- Chore: Bump vm2 to 3.9.11 ([#26940](https://github.com/RocketChat/Rocket.Chat/pull/26940)) + +- Chore: Change BundleChips component appearance ([#26686](https://github.com/RocketChat/Rocket.Chat/pull/26686)) + + # [MKP-44](https://rocketchat.atlassian.net/browse/MKP-44?atlOrigin=eyJpIjoiOTBiNzQ4NzE1ZTJiNDBjMGE0NjQxNmQ2MWNkMTI4YjgiLCJwIjoiaiJ9) + Changed the appearance of the marketplace app bundle chips (E.G.: The blue Enterprise tag in the images bellow). + + Demo image for app details page: + ![image](https://user-images.githubusercontent.com/43561537/190232209-939d29f5-bcdb-4ce4-99d1-1b061d170ab0.png) + + Demo image for list view: + ![image](https://user-images.githubusercontent.com/43561537/190232168-ab898d8a-6a73-4e34-9f47-a5af01bf29fc.png) + +- Chore: Cleanup endpoint handlers ([#26749](https://github.com/RocketChat/Rocket.Chat/pull/26749)) + +- Chore: Configure Prettier for `@rocket.chat/livechat` ([#26846](https://github.com/RocketChat/Rocket.Chat/pull/26846)) + +- Chore: Convert current-chats to useQuery ([#26931](https://github.com/RocketChat/Rocket.Chat/pull/26931)) + +- Chore: Deprecate some omnichannel meteor methods which aren't getting used ([#26839](https://github.com/RocketChat/Rocket.Chat/pull/26839)) + +- Chore: first non-aggressive CSS removal ([#26714](https://github.com/RocketChat/Rocket.Chat/pull/26714)) + +- Chore: Fix API tests retry ([#26860](https://github.com/RocketChat/Rocket.Chat/pull/26860)) + +- Chore: fix regressions for omnichannel due room refactor ([#26912](https://github.com/RocketChat/Rocket.Chat/pull/26912)) + +- Chore: fix wrong `test.step` usage ([#26873](https://github.com/RocketChat/Rocket.Chat/pull/26873)) + +- Chore: Introduce `useQuery` as data source for the `Room` component ([#26855](https://github.com/RocketChat/Rocket.Chat/pull/26855)) + +- Chore: merge all functions using autorun x useSubscription pattern ([#26886](https://github.com/RocketChat/Rocket.Chat/pull/26886)) + +- Chore: Missing Also_send_thread_message_to_channel setting translation ([#26926](https://github.com/RocketChat/Rocket.Chat/pull/26926)) + +- Chore: Move Header to ui-client ([#26757](https://github.com/RocketChat/Rocket.Chat/pull/26757)) + + Screen Shot 2022-08-30 at 23 15 18 + +- Chore: Move micro services to packages ([#26884](https://github.com/RocketChat/Rocket.Chat/pull/26884)) + +- Chore: Move Omnichannel Room Footer to react ([#26864](https://github.com/RocketChat/Rocket.Chat/pull/26864)) + +- Chore: Move presence to package ([#25541](https://github.com/RocketChat/Rocket.Chat/pull/25541)) + +- Chore: Omnichannel endpoints to ts ([#26829](https://github.com/RocketChat/Rocket.Chat/pull/26829)) + +- Chore: Refactor message list context usage ([#26748](https://github.com/RocketChat/Rocket.Chat/pull/26748)) + +- Chore: Refactor omnichannel livechat tests ([#26929](https://github.com/RocketChat/Rocket.Chat/pull/26929)) + +- Chore: Rewrite apps WarningModal component to typescript ([#26845](https://github.com/RocketChat/Rocket.Chat/pull/26845)) + + Translated the admin apps WarningModal component from Javascript to Typescript + +- Chore: Test/improve reliability ([#26724](https://github.com/RocketChat/Rocket.Chat/pull/26724)) + +- Chore: Tests for EE features ([#26939](https://github.com/RocketChat/Rocket.Chat/pull/26939)) + +- Chore: Update fuselage to next version. ([#26841](https://github.com/RocketChat/Rocket.Chat/pull/26841)) + +- Chore: Updating apps engine ([#26924](https://github.com/RocketChat/Rocket.Chat/pull/26924)) + +- Chore: Upgrading livechat's ui-kit package to latest version ([#26709](https://github.com/RocketChat/Rocket.Chat/pull/26709)) + + This PR upgrades Livechat's UiKit package to the version 0.31.16. and adjusts the renderer to be compatible with said version. + +- i18n: Language update from LingoHub 🤖 on 2022-08-29Z ([#26722](https://github.com/RocketChat/Rocket.Chat/pull/26722)) + +- i18n: Language update from LingoHub 🤖 on 2022-09-05Z ([#26805](https://github.com/RocketChat/Rocket.Chat/pull/26805)) + +- i18n: Language update from LingoHub 🤖 on 2022-09-12Z ([#26849](https://github.com/RocketChat/Rocket.Chat/pull/26849)) + +- i18n: Language update from LingoHub 🤖 on 2022-09-19Z ([#26896](https://github.com/RocketChat/Rocket.Chat/pull/26896)) + +- i18n: Language update from LingoHub 🤖 on 2022-09-26Z ([#26948](https://github.com/RocketChat/Rocket.Chat/pull/26948)) + +- Merge master into develop & Set version to 5.2.0-develop ([#26792](https://github.com/RocketChat/Rocket.Chat/pull/26792)) + +- Regression: Cannot edit messages in some environments. ([#27023](https://github.com/RocketChat/Rocket.Chat/pull/27023)) + + An empty `$unset` object was being used and causes exceptions in some mongo versions. + +- Regression: Composer not reactive when omnichannel room closed ([#26983](https://github.com/RocketChat/Rocket.Chat/pull/26983)) + +- Regression: Double Table Cell Causing extra padding on Current Chats ([#27008](https://github.com/RocketChat/Rocket.Chat/pull/27008)) + +- Regression: Event handler blocking mention links ([#26964](https://github.com/RocketChat/Rocket.Chat/pull/26964)) + + Fixes mention links being irresponsive to clicks. + Jira: [TC-55] + + [TC-55]: https://rocketchat.atlassian.net/browse/TC-55?atlOrigin=eyJpIjoiMmQ3ZmE0MWE2NGQwNDIzZThkMzc5NGNhMzU1MjExMGMiLCJwIjoiaiJ9 + +- Regression: Fix open room from current chats ([#26930](https://github.com/RocketChat/Rocket.Chat/pull/26930)) + +- Regression: Fixed takeInquiry method not displaying error messages on the client ([#26976](https://github.com/RocketChat/Rocket.Chat/pull/26976)) + + This pull request brings back the toast message "The maximum number of simultaneous chats per agent has been reached." that should be displayed when an agent tries to take more chats than the maximum allowed. + + ![image](https://user-images.githubusercontent.com/6494543/192891486-8720a5e3-f0c8-4863-b0dc-fa3b922d776b.png) + +- Regression: Handle `undefined` values on `useReactiveQuery`'s query function ([#26988](https://github.com/RocketChat/Rocket.Chat/pull/26988)) + + According to https://tanstack.com/query/v4/docs/reference/useQuery, the query function must **not** return `undefined` values, a quirk that we've been ignoring. + +- Regression: Incorrect on-hold chat resume message ([#26935](https://github.com/RocketChat/Rocket.Chat/pull/26935)) + +- Regression: Omnichannel Contact Center empty on no filter search ([#26975](https://github.com/RocketChat/Rocket.Chat/pull/26975)) + +- Regression: Remove section and replace icon on administration kebab menu ([#26986](https://github.com/RocketChat/Rocket.Chat/pull/26986)) + +- Regression: Remove symbols from number before storing PBX event ([#26969](https://github.com/RocketChat/Rocket.Chat/pull/26969)) + +- Regression: Sidebar Room List not working properly. ([#26950](https://github.com/RocketChat/Rocket.Chat/pull/26950)) + + The CachedCollection Class was assuming that the passed parameter would be modified, instead of using the callback return. + +- Regression: Typo on livechat/queue endpoint client call ([#26962](https://github.com/RocketChat/Rocket.Chat/pull/26962)) + +- Regression: Use raw models instead of meteor ones on visitor inactivity processing ([#27002](https://github.com/RocketChat/Rocket.Chat/pull/27002)) + +- Regression: VideoConf Actions Reactivity in SidebarItem ([#27009](https://github.com/RocketChat/Rocket.Chat/pull/27009)) + + Jira Issue: [VC-10] + +- Regression: wrong permission on livechat/tags endpoints ([#26928](https://github.com/RocketChat/Rocket.Chat/pull/26928)) + +- Release 5.1.1 ([#26822](https://github.com/RocketChat/Rocket.Chat/pull/26822)) + +- Release 5.1.3 ([#26914](https://github.com/RocketChat/Rocket.Chat/pull/26914)) + +- Release 5.1.4 ([#26965](https://github.com/RocketChat/Rocket.Chat/pull/26965)) + +
+ +### 👩‍💻👨‍💻 Contributors 😍 + +- [@dependabot[bot]](https://github.com/dependabot[bot]) +- [@neo-clon](https://github.com/neo-clon) + +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@AllanPazRibeiro](https://github.com/AllanPazRibeiro) +- [@KevLehman](https://github.com/KevLehman) +- [@LucianoPierdona](https://github.com/LucianoPierdona) +- [@MarcosSpessatto](https://github.com/MarcosSpessatto) +- [@MartinSchoeler](https://github.com/MartinSchoeler) +- [@albuquerquefabio](https://github.com/albuquerquefabio) +- [@aleksandernsilva](https://github.com/aleksandernsilva) +- [@d-gubert](https://github.com/d-gubert) +- [@debdutdeb](https://github.com/debdutdeb) +- [@dougfabris](https://github.com/dougfabris) +- [@filipemarins](https://github.com/filipemarins) +- [@gabriellsh](https://github.com/gabriellsh) +- [@ggazzo](https://github.com/ggazzo) +- [@guijun13](https://github.com/guijun13) +- [@hugocostadev](https://github.com/hugocostadev) +- [@jeanfbrito](https://github.com/jeanfbrito) +- [@juliajforesti](https://github.com/juliajforesti) +- [@matheusbsilva137](https://github.com/matheusbsilva137) +- [@murtaza98](https://github.com/murtaza98) +- [@pierre-lehnen-rc](https://github.com/pierre-lehnen-rc) +- [@rique223](https://github.com/rique223) +- [@sampaiodiego](https://github.com/sampaiodiego) +- [@souzaramon](https://github.com/souzaramon) +- [@tassoevan](https://github.com/tassoevan) +- [@tiagoevanp](https://github.com/tiagoevanp) +- [@yash-rajpal](https://github.com/yash-rajpal) + +# 5.1.4 +`2022-09-28 · 1 🔍 · 2 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +
+🔍 Minor changes + + +- Release 5.1.4 ([#26965](https://github.com/RocketChat/Rocket.Chat/pull/26965)) + +
+ +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@aleksandernsilva](https://github.com/aleksandernsilva) +- [@tassoevan](https://github.com/tassoevan) + +# 5.1.3 +`2022-09-24 · 4 🐛 · 2 🔍 · 8 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🐛 Bug fixes + + +- `MongoInvalidArgumentError` on overwriting existing setting ([#26880](https://github.com/RocketChat/Rocket.Chat/pull/26880)) + +- Check if messsage.replies exist on new message template ([#26652](https://github.com/RocketChat/Rocket.Chat/pull/26652)) + +- Error when mentioning a non-member of a public channel ([#26917](https://github.com/RocketChat/Rocket.Chat/pull/26917)) + +- Importer fails when file includes user without an email. ([#26836](https://github.com/RocketChat/Rocket.Chat/pull/26836)) + +
+🔍 Minor changes + + +- Release 5.1.1 ([#26822](https://github.com/RocketChat/Rocket.Chat/pull/26822)) + +- Release 5.1.3 ([#26914](https://github.com/RocketChat/Rocket.Chat/pull/26914)) + +
+ +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@MartinSchoeler](https://github.com/MartinSchoeler) +- [@debdutdeb](https://github.com/debdutdeb) +- [@filipemarins](https://github.com/filipemarins) +- [@hugocostadev](https://github.com/hugocostadev) +- [@pierre-lehnen-rc](https://github.com/pierre-lehnen-rc) +- [@sampaiodiego](https://github.com/sampaiodiego) +- [@tassoevan](https://github.com/tassoevan) +- [@tiagoevanp](https://github.com/tiagoevanp) + +# 5.1.2 +`2022-09-12 · 1 🐛 · 1 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🐛 Bug fixes + + +- Security Hotfix (https://docs.rocket.chat/guides/security/security-updates) + +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@ggazzo](https://github.com/ggazzo) + +# 5.1.1 +`2022-09-08 · 3 🐛 · 3 👩‍💻👨‍💻` + +### Engine versions +- Node: `14.19.3` +- NPM: `6.14.17` +- MongoDB: `4.2, 4.4, 5.0` + +### 🐛 Bug fixes + + +- Fix broken legacy message view ([#26819](https://github.com/RocketChat/Rocket.Chat/pull/26819)) + + Fixed `messagesHistory` function, it was filtering messages only with existing threads. + +- Livechat trigger messages covering all the website ([#26776](https://github.com/RocketChat/Rocket.Chat/pull/26776)) + +- Restore current chats default table order ([#26808](https://github.com/RocketChat/Rocket.Chat/pull/26808)) + +### 👩‍💻👨‍💻 Core Team 🤓 + +- [@MartinSchoeler](https://github.com/MartinSchoeler) +- [@hugocostadev](https://github.com/hugocostadev) +- [@tiagoevanp](https://github.com/tiagoevanp) + # 5.1.0 -`2022-09-02 · 8 🎉 · 7 🚀 · 42 🐛 · 129 🔍 · 38 👩‍💻👨‍💻` +`2022-09-02 · 8 🎉 · 7 🚀 · 42 🐛 · 129 🔍 · 37 👩‍💻👨‍💻` ### Engine versions - Node: `14.19.3` @@ -14,9 +3328,9 @@ image -- Adding oauth crud on the rocket.chat side ([#26220](https://github.com/RocketChat/Rocket.Chat/pull/26220) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Adding oauth crud on the rocket.chat side ([#26220](https://github.com/RocketChat/Rocket.Chat/pull/26220)) -- allow ephemeral messages to receive a specific id ([#26118](https://github.com/RocketChat/Rocket.Chat/pull/26118) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- allow ephemeral messages to receive a specific id ([#26118](https://github.com/RocketChat/Rocket.Chat/pull/26118)) Allow apps to pass a specific ID for ephemeral messages as a way to edit them. @@ -25,7 +3339,7 @@ Users of the endpoints [api/v1/omnichannel/contact.search](https://developer.rocket.chat/reference/api/rest-api/endpoints/omnichannel/livechat-endpoints/livechat-contact/omnichannel-search-contact) and [/api/v1/livechat/visitors.search](https://developer.rocket.chat/reference/api/rest-api/endpoints/omnichannel/livechat-endpoints/visitor/search-for-visitors) are now able to search by custom fields in their objects. Capability of selecting if a custom field can be searched for is added in the Omnichannel pannel as a toggle for `searchable`, the included JSON in the Accounts' Custom Field example has been updated to make it explicit for future configurations that the field has to be enabled as searchable for that to happen. -- Fallback Error component for Engagement Dashboard widgets ([#26441](https://github.com/RocketChat/Rocket.Chat/pull/26441) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Fallback Error component for Engagement Dashboard widgets ([#26441](https://github.com/RocketChat/Rocket.Chat/pull/26441)) As proposed, was added a fallback component to catch errors at Engagement Dashboard widgets individually. It used an Error boundary to catch `react-query` errors, due to this scenario was necessary to install and use the library [react-error-boundary](https://github.com/bvaughn/react-error-boundary) that implements everything and more compared to our ErrorBoundary component, the main reason was to capture Query errors and the implementation with `react-query` library. @@ -52,7 +3366,7 @@ Created the /featured endpoints on the rest.js file. Also created the necessary typings to use together with it. -- Warn admins about running multiple instances of the monolith ([#26667](https://github.com/RocketChat/Rocket.Chat/pull/26667) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Warn admins about running multiple instances of the monolith ([#26667](https://github.com/RocketChat/Rocket.Chat/pull/26667)) ### 🚀 Improvements @@ -81,7 +3395,7 @@ - Add more test cases, since a lot of cases were omitted during the release phase; - Remove unsafe `Object.assign` statements and prefer to use the class `constructor` instead; -- New 'not found page' design ([#26452](https://github.com/RocketChat/Rocket.Chat/pull/26452) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- New 'not found page' design ([#26452](https://github.com/RocketChat/Rocket.Chat/pull/26452)) - Add a new design for the not-found page - Add English translation for "page not found" and "Homepage" @@ -94,28 +3408,28 @@ - Remove device-management banner and modal ([#26729](https://github.com/RocketChat/Rocket.Chat/pull/26729)) -- Spotlight search user results ([#26599](https://github.com/RocketChat/Rocket.Chat/pull/26599) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Spotlight search user results ([#26599](https://github.com/RocketChat/Rocket.Chat/pull/26599)) - use enter key to call using DialPad ([#26454](https://github.com/RocketChat/Rocket.Chat/pull/26454)) ### 🐛 Bug fixes -- - Incoming SMSs no longer clash with ongoing livechat conversations by the same visitor ([#26307](https://github.com/RocketChat/Rocket.Chat/pull/26307) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- - Incoming SMSs no longer clash with ongoing livechat conversations by the same visitor ([#26307](https://github.com/RocketChat/Rocket.Chat/pull/26307)) There was a data race in the defineVisitor function, causing new guests to be created even if a registered guest with that number already existed, also made sure that the open room being searched on is the correct source type, so the clash is not possible anymore. -- Active users count on `@all` and `@here` ([#25957](https://github.com/RocketChat/Rocket.Chat/pull/25957) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Active users count on `@all` and `@here` ([#25957](https://github.com/RocketChat/Rocket.Chat/pull/25957)) this PR updates the old `roomMembersCount` to count active users instead of everyone -- add image format validation ([#25912](https://github.com/RocketChat/Rocket.Chat/pull/25912) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- add image format validation ([#25912](https://github.com/RocketChat/Rocket.Chat/pull/25912)) -- Add Offline License Endpoint ([#26282](https://github.com/RocketChat/Rocket.Chat/pull/26282) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Add Offline License Endpoint ([#26282](https://github.com/RocketChat/Rocket.Chat/pull/26282)) This PR updates the endpoint to add a license -- Agents (with user status offline & omni-status as available) not able to take or forward chat ([#26575](https://github.com/RocketChat/Rocket.Chat/pull/26575) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Agents (with user status offline & omni-status as available) not able to take or forward chat ([#26575](https://github.com/RocketChat/Rocket.Chat/pull/26575)) - Allow normal user to open apps contextual bar ([#26495](https://github.com/RocketChat/Rocket.Chat/pull/26495)) @@ -126,9 +3440,9 @@ - Avatars of other chats disappear when they located near chat with broken avatar ([#26689](https://github.com/RocketChat/Rocket.Chat/pull/26689)) -- Blank screen after requesting transcript ([#26385](https://github.com/RocketChat/Rocket.Chat/pull/26385) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Blank screen after requesting transcript ([#26385](https://github.com/RocketChat/Rocket.Chat/pull/26385)) -- Chats not getting assigned to offline agents even when "Accept with No Online agents" setting is turned on ([#26147](https://github.com/RocketChat/Rocket.Chat/pull/26147) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chats not getting assigned to offline agents even when "Accept with No Online agents" setting is turned on ([#26147](https://github.com/RocketChat/Rocket.Chat/pull/26147)) - Clear push token on save user password ([#26466](https://github.com/RocketChat/Rocket.Chat/pull/26466)) @@ -136,7 +3450,7 @@ The primary change here has been to make the library try and reconnect after some time, up to a certain configured number of times, on a few different error classes. -- Current Chat Custom Field Filter ([#26200](https://github.com/RocketChat/Rocket.Chat/pull/26200) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Current Chat Custom Field Filter ([#26200](https://github.com/RocketChat/Rocket.Chat/pull/26200)) - Decrypt E2EE messages on thread list ([#26133](https://github.com/RocketChat/Rocket.Chat/pull/26133)) @@ -145,7 +3459,7 @@ ### After Screenshot 2022-07-05 at 9 27 42 PM -- Default BH not getting applied in-case any other BH is disabled ([#26471](https://github.com/RocketChat/Rocket.Chat/pull/26471) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Default BH not getting applied in-case any other BH is disabled ([#26471](https://github.com/RocketChat/Rocket.Chat/pull/26471)) - DialPad call button from end to center ([#26459](https://github.com/RocketChat/Rocket.Chat/pull/26459)) @@ -155,7 +3469,7 @@ - incorrect error toast messages ([#26320](https://github.com/RocketChat/Rocket.Chat/pull/26320)) -- Katex is not respecting the 'Katex_Enabled' setting ([#26542](https://github.com/RocketChat/Rocket.Chat/pull/26542) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Katex is not respecting the 'Katex_Enabled' setting ([#26542](https://github.com/RocketChat/Rocket.Chat/pull/26542)) - MDM content alignment ([#26665](https://github.com/RocketChat/Rocket.Chat/pull/26665)) @@ -167,27 +3481,27 @@ after: Screen Shot 2022-08-23 at 11 50 55 -- Missing bio field UI validation ([#26345](https://github.com/RocketChat/Rocket.Chat/pull/26345) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Missing bio field UI validation ([#26345](https://github.com/RocketChat/Rocket.Chat/pull/26345)) - Not allowed error in discussion room with a private parent channel ([#26394](https://github.com/RocketChat/Rocket.Chat/pull/26394)) -- Notification preferences not updated on save ([#26461](https://github.com/RocketChat/Rocket.Chat/pull/26461) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Notification preferences not updated on save ([#26461](https://github.com/RocketChat/Rocket.Chat/pull/26461)) Publish required notification subscription fields on change, so that changes can be seen on save. - Onhold auto chat resume feature not working for email channel ([#26363](https://github.com/RocketChat/Rocket.Chat/pull/26363)) -- Open team after room not found page ([#26264](https://github.com/RocketChat/Rocket.Chat/pull/26264) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Open team after room not found page ([#26264](https://github.com/RocketChat/Rocket.Chat/pull/26264)) After the room not found page, the `FlowRouter` was not clearing `msg` query param, causing the next redirect to private teams break because it's try to find the unknow msg id -- Permission `view-all-teams` is not checked in the `teams.info` endpoint ([#25841](https://github.com/RocketChat/Rocket.Chat/pull/25841) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Permission `view-all-teams` is not checked in the `teams.info` endpoint ([#25841](https://github.com/RocketChat/Rocket.Chat/pull/25841)) Previously any authenticated user was able to access the `teams.info` endpoint, this PR updates this so only users with the `view-all-teams` permission or team members can access it. - Prevent VoIP issues during disconnection when network failed ([#26321](https://github.com/RocketChat/Rocket.Chat/pull/26321)) -- Prune messages not removing thumbnails ([#26443](https://github.com/RocketChat/Rocket.Chat/pull/26443) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Prune messages not removing thumbnails ([#26443](https://github.com/RocketChat/Rocket.Chat/pull/26443)) This PR adds a method on `Uploads` called `findOneByName`, and excludes a thumbnail of an image on `cleanRoomHistory` @@ -197,17 +3511,17 @@ - Reset password errors ([#26597](https://github.com/RocketChat/Rocket.Chat/pull/26597)) -- Save edited tags for omnichannel departments ([#26481](https://github.com/RocketChat/Rocket.Chat/pull/26481) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Save edited tags for omnichannel departments ([#26481](https://github.com/RocketChat/Rocket.Chat/pull/26481)) -- Slack User CSV importer not working ([#26629](https://github.com/RocketChat/Rocket.Chat/pull/26629) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Slack User CSV importer not working ([#26629](https://github.com/RocketChat/Rocket.Chat/pull/26629)) -- Slackbridge Connect Error ([#25793](https://github.com/RocketChat/Rocket.Chat/pull/25793) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Slackbridge Connect Error ([#25793](https://github.com/RocketChat/Rocket.Chat/pull/25793)) This PR fixes an issue that was happening when an invalid token was passed on SlackBridge, basically the app crashes because the error was not being handled -- Slash commands description as undefined ([#26372](https://github.com/RocketChat/Rocket.Chat/pull/26372) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Slash commands description as undefined ([#26372](https://github.com/RocketChat/Rocket.Chat/pull/26372) by [@carlosrodrigues94](https://github.com/carlosrodrigues94)) -- SMS service check ([#26558](https://github.com/RocketChat/Rocket.Chat/pull/26558) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- SMS service check ([#26558](https://github.com/RocketChat/Rocket.Chat/pull/26558)) - Too many REST API requests ([#26330](https://github.com/RocketChat/Rocket.Chat/pull/26330)) @@ -225,15 +3539,15 @@ | User Dropdown | ![image](https://user-images.githubusercontent.com/48109548/183442678-49667402-57fd-4a5c-9077-eaef53aad10c.png) | Screen Shot 2022-08-05 at 15 54 05 | | Create new Dropdown | Screen Shot 2022-08-08 at 11 33 17 | Screen Shot 2022-08-05 at 15 54 26 | -- Unable to remove a user who joined a public team with a mention ([#26218](https://github.com/RocketChat/Rocket.Chat/pull/26218) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Unable to remove a user who joined a public team with a mention ([#26218](https://github.com/RocketChat/Rocket.Chat/pull/26218)) This PR fixes a bug where a user that joins a team by mention don't get added to the team. - Unable to send voice recording to Whatsapp ([#26276](https://github.com/RocketChat/Rocket.Chat/pull/26276)) -- Users can access public discussions inside private channels they are not members of ([#26619](https://github.com/RocketChat/Rocket.Chat/pull/26619) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Users can access public discussions inside private channels they are not members of ([#26619](https://github.com/RocketChat/Rocket.Chat/pull/26619)) -- Users can access public discussions inside private channels they are not members of ([#25981](https://github.com/RocketChat/Rocket.Chat/pull/25981) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Users can access public discussions inside private channels they are not members of ([#25981](https://github.com/RocketChat/Rocket.Chat/pull/25981))
🔍 Minor changes @@ -241,9 +3555,9 @@ - Chore: Accounts/token to TS ([#26434](https://github.com/RocketChat/Rocket.Chat/pull/26434)) -- Chore: Add end-to-end tests to teams listing in the `directory` endpoint ([#26347](https://github.com/RocketChat/Rocket.Chat/pull/26347)) +- Chore: Add end-to-end tests to teams listing in the `directory` endpoint ([#26347](https://github.com/RocketChat/Rocket.Chat/pull/26347) by [@carlosrodrigues94](https://github.com/carlosrodrigues94)) -- Chore: Add license env var to ee tests ([#26650](https://github.com/RocketChat/Rocket.Chat/pull/26650) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Add license env var to ee tests ([#26650](https://github.com/RocketChat/Rocket.Chat/pull/26650)) - Chore: add playwright ee coverage ([#26293](https://github.com/RocketChat/Rocket.Chat/pull/26293)) @@ -265,17 +3579,17 @@ - Chore: Convert `client/views/account/preferences` folder to ts ([#26496](https://github.com/RocketChat/Rocket.Chat/pull/26496)) -- Chore: Convert `LivechatCustomField` model to raw model ([#26446](https://github.com/RocketChat/Rocket.Chat/pull/26446) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Convert `LivechatCustomField` model to raw model ([#26446](https://github.com/RocketChat/Rocket.Chat/pull/26446)) - Chore: Convert AccountPreferencesPage to ts ([#26096](https://github.com/RocketChat/Rocket.Chat/pull/26096)) - Chore: Convert AppSetting to tsx ([#26625](https://github.com/RocketChat/Rocket.Chat/pull/26625)) -- Chore: Convert AppSettingsAssembler to tsx ([#26626](https://github.com/RocketChat/Rocket.Chat/pull/26626) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Convert AppSettingsAssembler to tsx ([#26626](https://github.com/RocketChat/Rocket.Chat/pull/26626)) - Chore: Convert AutoCompleteAgent to tsx ([#26704](https://github.com/RocketChat/Rocket.Chat/pull/26704)) -- Chore: convert autotranslate to ts ([#25953](https://github.com/RocketChat/Rocket.Chat/pull/25953) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: convert autotranslate to ts ([#25953](https://github.com/RocketChat/Rocket.Chat/pull/25953)) Converted the `apps/meteor/app/api/server/v1/autotranslate.js` to ts and created endpoint typings on the `packages/rest-typings/src/v1/autotranslate` folder. @@ -291,9 +3605,9 @@ Created the missing rest endpoint 'roomNameExists' for `apps/meteor/client/sidebar/header/CreateChannel.tsx`, on the packages/rest-typings/src/v1/ folder. -- Chore: Create teams management tests ([#26578](https://github.com/RocketChat/Rocket.Chat/pull/26578) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Create teams management tests ([#26578](https://github.com/RocketChat/Rocket.Chat/pull/26578)) -- Chore: Create tests for Omnichannel admin add a custom fields ([#26609](https://github.com/RocketChat/Rocket.Chat/pull/26609) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Create tests for Omnichannel admin add a custom fields ([#26609](https://github.com/RocketChat/Rocket.Chat/pull/26609)) - Chore: Engagement Dashboard end to end tests ([#26702](https://github.com/RocketChat/Rocket.Chat/pull/26702)) @@ -324,13 +3638,13 @@ #24757 was an old PR and was recently auto-merged, it was not following our latest eslint rules, so now there are some lint issues on the develop. -- Chore: Fix some settings with incompatible default value types ([#26114](https://github.com/RocketChat/Rocket.Chat/pull/26114) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Fix some settings with incompatible default value types ([#26114](https://github.com/RocketChat/Rocket.Chat/pull/26114)) - Chore: fix tests with beforeEach ([#26335](https://github.com/RocketChat/Rocket.Chat/pull/26335)) - Chore: Fix UiKit dependency issue for Livechat ([#26534](https://github.com/RocketChat/Rocket.Chat/pull/26534)) -- Chore: Importer rest types, meteor methods to TS and API unit tests ([#26284](https://github.com/RocketChat/Rocket.Chat/pull/26284) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Importer rest types, meteor methods to TS and API unit tests ([#26284](https://github.com/RocketChat/Rocket.Chat/pull/26284)) - Chore: Improve test for livechat ([#26527](https://github.com/RocketChat/Rocket.Chat/pull/26527)) @@ -342,7 +3656,7 @@ - Use `livechat/room.forward` endpoint to forward omnichannel chats instead of using meteor method "livechat:transfer" -- Chore: Missing permissions translations ([#26546](https://github.com/RocketChat/Rocket.Chat/pull/26546) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Missing permissions translations ([#26546](https://github.com/RocketChat/Rocket.Chat/pull/26546)) - Chore: Missing some English translation keywords ([#20131](https://github.com/RocketChat/Rocket.Chat/pull/20131) by [@Karting06](https://github.com/Karting06)) @@ -352,17 +3666,17 @@ Whenever Mocha runs a test file which imports stuff from outside `apps/meteor`, it uses a hoisted version of React (i.e. located at the root `node_modules`) instead of the one tied to `apps/meteor/node_modules`. This PR adds a monkey patch while we can't migrate to another test runner. -- Chore: ModalFooterControllers adoption ([#26445](https://github.com/RocketChat/Rocket.Chat/pull/26445) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: ModalFooterControllers adoption ([#26445](https://github.com/RocketChat/Rocket.Chat/pull/26445)) -- Chore: More Omnichannel tests ([#26691](https://github.com/RocketChat/Rocket.Chat/pull/26691) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: More Omnichannel tests ([#26691](https://github.com/RocketChat/Rocket.Chat/pull/26691)) - Chore: Move `Card` and related components to `@rocket.chat/ui-client` ([#26653](https://github.com/RocketChat/Rocket.Chat/pull/26653)) -- Chore: Move fuselage-ui-kit to main repo ([#26630](https://github.com/RocketChat/Rocket.Chat/pull/26630) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Move fuselage-ui-kit to main repo ([#26630](https://github.com/RocketChat/Rocket.Chat/pull/26630)) - Chore: Omnichannel endpoints e2e tests ([#26376](https://github.com/RocketChat/Rocket.Chat/pull/26376)) -- Chore: omnichannel-departments tests ([#26607](https://github.com/RocketChat/Rocket.Chat/pull/26607) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: omnichannel-departments tests ([#26607](https://github.com/RocketChat/Rocket.Chat/pull/26607)) - Chore: Options in BaseRaw model could possibly be undefined ([#26395](https://github.com/RocketChat/Rocket.Chat/pull/26395)) @@ -380,9 +3694,9 @@ - Chore: Refactor create-target-channel util ([#26493](https://github.com/RocketChat/Rocket.Chat/pull/26493)) -- Chore: Refactor ReportMessage Modal to React Component ([#26478](https://github.com/RocketChat/Rocket.Chat/pull/26478) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Refactor ReportMessage Modal to React Component ([#26478](https://github.com/RocketChat/Rocket.Chat/pull/26478)) -- Chore: Refactor RoomMembers to Typescript ([#26559](https://github.com/RocketChat/Rocket.Chat/pull/26559) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Refactor RoomMembers to Typescript ([#26559](https://github.com/RocketChat/Rocket.Chat/pull/26559)) - Chore: Refactor WebdavFilePicker Modal to React Component ([#26422](https://github.com/RocketChat/Rocket.Chat/pull/26422)) @@ -402,7 +3716,7 @@ - Chore: Remove Livechat Dashboard Templates ([#26627](https://github.com/RocketChat/Rocket.Chat/pull/26627)) -- Chore: Remove method calls - Stage 1 ([#26149](https://github.com/RocketChat/Rocket.Chat/pull/26149) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Remove method calls - Stage 1 ([#26149](https://github.com/RocketChat/Rocket.Chat/pull/26149)) - Chore: Remove public and node_modules folders from TypeScript server watcher ([#26391](https://github.com/RocketChat/Rocket.Chat/pull/26391)) @@ -410,17 +3724,17 @@ - Chore: Remove translation owners ([#26598](https://github.com/RocketChat/Rocket.Chat/pull/26598)) -- Chore: Remove trash collection from models when not used ([#26628](https://github.com/RocketChat/Rocket.Chat/pull/26628) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Remove trash collection from models when not used ([#26628](https://github.com/RocketChat/Rocket.Chat/pull/26628)) -- Chore: remove useMethod calls ([#26195](https://github.com/RocketChat/Rocket.Chat/pull/26195) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: remove useMethod calls ([#26195](https://github.com/RocketChat/Rocket.Chat/pull/26195)) - Chore: Remove visitor, agent and customTemplate meteor templates ([#26700](https://github.com/RocketChat/Rocket.Chat/pull/26700)) -- Chore: Replace direct multiple icon ([#26342](https://github.com/RocketChat/Rocket.Chat/pull/26342) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Replace direct multiple icon ([#26342](https://github.com/RocketChat/Rocket.Chat/pull/26342)) -- Chore: Replace timeAgo on WebdavFilePickerTable ([#26564](https://github.com/RocketChat/Rocket.Chat/pull/26564) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Replace timeAgo on WebdavFilePickerTable ([#26564](https://github.com/RocketChat/Rocket.Chat/pull/26564)) -- Chore: restrict `.only` ([#26537](https://github.com/RocketChat/Rocket.Chat/pull/26537) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: restrict `.only` ([#26537](https://github.com/RocketChat/Rocket.Chat/pull/26537)) - Chore: Rewrite custom OAuth Modals to react ([#26204](https://github.com/RocketChat/Rocket.Chat/pull/26204)) @@ -434,26 +3748,26 @@ ### after ![Screen Shot 2022-01-31 at 10 58 04](https://user-images.githubusercontent.com/27704687/151806686-7110cec8-a006-4ac1-befd-a2684550ecc5.png) -- Chore: Rewrite VerticalBarOldActions to TS ([#26277](https://github.com/RocketChat/Rocket.Chat/pull/26277) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Rewrite VerticalBarOldActions to TS ([#26277](https://github.com/RocketChat/Rocket.Chat/pull/26277)) -- Chore: Separating user edit form to prevent browser autocomplete ([#26280](https://github.com/RocketChat/Rocket.Chat/pull/26280) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Separating user edit form to prevent browser autocomplete ([#26280](https://github.com/RocketChat/Rocket.Chat/pull/26280)) Separating user edit form to prevent browser password and username auto-complete. The browser will continue showing the suggestion dropdown for the password field, but when you select a suggestion the other text field will not be impacted, as was happening before with 'Nickname' field -- Chore: skipping tests that are based on kebab menu ([#26616](https://github.com/RocketChat/Rocket.Chat/pull/26616) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: skipping tests that are based on kebab menu ([#26616](https://github.com/RocketChat/Rocket.Chat/pull/26616)) - Chore: test for change avatar ([#26543](https://github.com/RocketChat/Rocket.Chat/pull/26543)) - Chore: Tests intermitences ([#26464](https://github.com/RocketChat/Rocket.Chat/pull/26464)) -- Chore: transfer to another agent ([#26545](https://github.com/RocketChat/Rocket.Chat/pull/26545) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: transfer to another agent ([#26545](https://github.com/RocketChat/Rocket.Chat/pull/26545)) - Chore: Update Apps-Engine ([#26765](https://github.com/RocketChat/Rocket.Chat/pull/26765)) - Chore: update codeowners for omnichannel ([#25771](https://github.com/RocketChat/Rocket.Chat/pull/25771)) -- Chore: update fuselage rounded edition ([#26540](https://github.com/RocketChat/Rocket.Chat/pull/26540) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: update fuselage rounded edition ([#26540](https://github.com/RocketChat/Rocket.Chat/pull/26540)) - Chore: Upgrade dependencies ([#26694](https://github.com/RocketChat/Rocket.Chat/pull/26694)) @@ -479,11 +3793,11 @@ - i18n: Language update from LingoHub 🤖 on 2022-08-01Z ([#26429](https://github.com/RocketChat/Rocket.Chat/pull/26429)) -- i18n: Language update from LingoHub 🤖 on 2022-08-08Z ([#26508](https://github.com/RocketChat/Rocket.Chat/pull/26508) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- i18n: Language update from LingoHub 🤖 on 2022-08-08Z ([#26508](https://github.com/RocketChat/Rocket.Chat/pull/26508)) -- i18n: Language update from LingoHub 🤖 on 2022-08-15Z ([#26570](https://github.com/RocketChat/Rocket.Chat/pull/26570) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- i18n: Language update from LingoHub 🤖 on 2022-08-15Z ([#26570](https://github.com/RocketChat/Rocket.Chat/pull/26570)) -- i18n: Language update from LingoHub 🤖 on 2022-08-22Z ([#26645](https://github.com/RocketChat/Rocket.Chat/pull/26645) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- i18n: Language update from LingoHub 🤖 on 2022-08-22Z ([#26645](https://github.com/RocketChat/Rocket.Chat/pull/26645)) - i18n: Makes the text less ambiguous ([#20895](https://github.com/RocketChat/Rocket.Chat/pull/20895) by [@pierreozoux](https://github.com/pierreozoux)) @@ -491,9 +3805,9 @@ - i18n: pt-BR translation typo ([#26732](https://github.com/RocketChat/Rocket.Chat/pull/26732)) -- Regression: "Cache size is not a function" error when booting ([#26683](https://github.com/RocketChat/Rocket.Chat/pull/26683) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Regression: "Cache size is not a function" error when booting ([#26683](https://github.com/RocketChat/Rocket.Chat/pull/26683)) -- Regression: Add alsoSendThreadToChannel to user settings api ([#26663](https://github.com/RocketChat/Rocket.Chat/pull/26663) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Regression: Add alsoSendThreadToChannel to user settings api ([#26663](https://github.com/RocketChat/Rocket.Chat/pull/26663)) - Regression: AutoTranslate is disabled error ([#26701](https://github.com/RocketChat/Rocket.Chat/pull/26701)) @@ -518,17 +3832,17 @@ After: ![image](https://user-images.githubusercontent.com/43561537/181838756-b04fe31c-9e85-4830-8dd4-fddf8ec03458.png) -- Regression: Home cards UI tweaks ([#26610](https://github.com/RocketChat/Rocket.Chat/pull/26610) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Regression: Home cards UI tweaks ([#26610](https://github.com/RocketChat/Rocket.Chat/pull/26610)) - Regression: Instances Modal breaking ([#26779](https://github.com/RocketChat/Rocket.Chat/pull/26779)) Revert back to meteor method for now. -- Regression: invalid statistics format ([#26684](https://github.com/RocketChat/Rocket.Chat/pull/26684) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Regression: invalid statistics format ([#26684](https://github.com/RocketChat/Rocket.Chat/pull/26684)) -- Regression: Modal footer alignment ([#26635](https://github.com/RocketChat/Rocket.Chat/pull/26635) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Regression: Modal footer alignment ([#26635](https://github.com/RocketChat/Rocket.Chat/pull/26635)) -- Regression: Prevent message from being temp forever ([#26668](https://github.com/RocketChat/Rocket.Chat/pull/26668) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Regression: Prevent message from being temp forever ([#26668](https://github.com/RocketChat/Rocket.Chat/pull/26668)) - Regression: Remove log from banners.ts ([#26699](https://github.com/RocketChat/Rocket.Chat/pull/26699)) @@ -540,7 +3854,7 @@ - Regression: Team name validation failing always. ([#26574](https://github.com/RocketChat/Rocket.Chat/pull/26574)) -- Regression: Update custom homepage content behavior ([#26571](https://github.com/RocketChat/Rocket.Chat/pull/26571) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Regression: Update custom homepage content behavior ([#26571](https://github.com/RocketChat/Rocket.Chat/pull/26571)) - Regression: Visitor being overwritten on call end ([#26756](https://github.com/RocketChat/Rocket.Chat/pull/26756)) @@ -563,8 +3877,8 @@ ### 👩‍💻👨‍💻 Contributors 😍 - [@Karting06](https://github.com/Karting06) +- [@carlosrodrigues94](https://github.com/carlosrodrigues94) - [@imyaman](https://github.com/imyaman) -- [@kodiakhq[bot]](https://github.com/kodiakhq[bot]) - [@pierreozoux](https://github.com/pierreozoux) - [@shrinish123](https://github.com/shrinish123) @@ -577,7 +3891,6 @@ - [@MartinSchoeler](https://github.com/MartinSchoeler) - [@albuquerquefabio](https://github.com/albuquerquefabio) - [@aleksandernsilva](https://github.com/aleksandernsilva) -- [@carlosrodrigues94](https://github.com/carlosrodrigues94) - [@casalsgh](https://github.com/casalsgh) - [@cauefcr](https://github.com/cauefcr) - [@d-gubert](https://github.com/d-gubert) @@ -637,7 +3950,7 @@ - [@sampaiodiego](https://github.com/sampaiodiego) # 5.0.4 -`2022-08-19 · 1 🐛 · 3 🔍 · 3 👩‍💻👨‍💻` +`2022-08-19 · 1 🐛 · 3 🔍 · 2 👩‍💻👨‍💻` ### Engine versions - Node: `14.19.3` @@ -647,7 +3960,7 @@ ### 🐛 Bug fixes -- **ENTERPRISE:** User not marked as offline on log out when using micro services ([#26579](https://github.com/RocketChat/Rocket.Chat/pull/26579) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- **ENTERPRISE:** User not marked as offline on log out when using micro services ([#26579](https://github.com/RocketChat/Rocket.Chat/pull/26579))
🔍 Minor changes @@ -661,17 +3974,13 @@
-### 👩‍💻👨‍💻 Contributors 😍 - -- [@kodiakhq[bot]](https://github.com/kodiakhq[bot]) - ### 👩‍💻👨‍💻 Core Team 🤓 - [@murtaza98](https://github.com/murtaza98) - [@sampaiodiego](https://github.com/sampaiodiego) # 5.0.3 -`2022-08-11 · 3 🐛 · 2 🔍 · 8 👩‍💻👨‍💻` +`2022-08-11 · 3 🐛 · 2 🔍 · 7 👩‍💻👨‍💻` ### Engine versions - Node: `14.19.3` @@ -683,7 +3992,7 @@ - Chats holds to load history for some time ([#26425](https://github.com/RocketChat/Rocket.Chat/pull/26425)) -- Endpoints not working when using "Use Real Name" setting ([#26530](https://github.com/RocketChat/Rocket.Chat/pull/26530) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Endpoints not working when using "Use Real Name" setting ([#26530](https://github.com/RocketChat/Rocket.Chat/pull/26530)) The list of endpoints affected is: @@ -694,7 +4003,7 @@ - `/api/v1/im.list` - `/api/v1/im.list.everyone` -- LDAP fails to sync teams when the user DN has escaped characters. ([#26535](https://github.com/RocketChat/Rocket.Chat/pull/26535) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- LDAP fails to sync teams when the user DN has escaped characters. ([#26535](https://github.com/RocketChat/Rocket.Chat/pull/26535))
🔍 Minor changes @@ -706,10 +4015,6 @@
-### 👩‍💻👨‍💻 Contributors 😍 - -- [@kodiakhq[bot]](https://github.com/kodiakhq[bot]) - ### 👩‍💻👨‍💻 Core Team 🤓 - [@KevLehman](https://github.com/KevLehman) @@ -751,7 +4056,7 @@ - [@sampaiodiego](https://github.com/sampaiodiego) # 5.0.1 -`2022-08-02 · 1 🚀 · 1 🐛 · 4 🔍 · 4 👩‍💻👨‍💻` +`2022-08-02 · 1 🚀 · 1 🐛 · 4 🔍 · 3 👩‍💻👨‍💻` ### Engine versions - Node: `14.19.3` @@ -772,9 +4077,9 @@ 🔍 Minor changes -- Chore: Convert UserCardWithData to ts ([#26192](https://github.com/RocketChat/Rocket.Chat/pull/26192) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Convert UserCardWithData to ts ([#26192](https://github.com/RocketChat/Rocket.Chat/pull/26192)) -- Chore: Remove square prop from IconButton ([#26343](https://github.com/RocketChat/Rocket.Chat/pull/26343) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Remove square prop from IconButton ([#26343](https://github.com/RocketChat/Rocket.Chat/pull/26343)) - Regression: Fix app privacy links opening in desktop client instead of browser ([#26368](https://github.com/RocketChat/Rocket.Chat/pull/26368)) @@ -785,10 +4090,6 @@
-### 👩‍💻👨‍💻 Contributors 😍 - -- [@kodiakhq[bot]](https://github.com/kodiakhq[bot]) - ### 👩‍💻👨‍💻 Core Team 🤓 - [@dougfabris](https://github.com/dougfabris) @@ -796,7 +4097,7 @@ - [@sampaiodiego](https://github.com/sampaiodiego) # 5.0.0 -`2022-07-21 · 14 ️️️⚠️ · 33 🎉 · 20 🚀 · 110 🐛 · 389 🔍 · 63 👩‍💻👨‍💻` +`2022-07-21 · 14 ️️️⚠️ · 33 🎉 · 20 🚀 · 110 🐛 · 389 🔍 · 62 👩‍💻👨‍💻` ### Engine versions - Node: `14.19.3` @@ -1036,7 +4337,7 @@ Demo gif: ![privacy-tab](https://user-images.githubusercontent.com/43561537/173878394-333057d4-3c7e-434e-a3ca-d3e08f33c7bc.gif) -- Matrix Federation UX improvements ([#25847](https://github.com/RocketChat/Rocket.Chat/pull/25847)) +- Matrix Federation UX improvements ([#25847](https://github.com/RocketChat/Rocket.Chat/pull/25847) by [@carlosrodrigues94](https://github.com/carlosrodrigues94)) - Message Template React Component ([#23971](https://github.com/RocketChat/Rocket.Chat/pull/23971)) @@ -1106,7 +4407,7 @@ - Add tooltip to sidebar room menu ([#24405](https://github.com/RocketChat/Rocket.Chat/pull/24405) by [@Himanshu664](https://github.com/Himanshu664)) -- add warnings for federation setup ([#25684](https://github.com/RocketChat/Rocket.Chat/pull/25684)) +- add warnings for federation setup ([#25684](https://github.com/RocketChat/Rocket.Chat/pull/25684) by [@carlosrodrigues94](https://github.com/carlosrodrigues94)) - Added MaxNickNameLength and MaxBioLength constants ([#25231](https://github.com/RocketChat/Rocket.Chat/pull/25231) by [@aakash-gitdev](https://github.com/aakash-gitdev)) @@ -2013,7 +5314,7 @@ - Chore: Rewrite action-links to ts ([#25418](https://github.com/RocketChat/Rocket.Chat/pull/25418)) -- Chore: Rewrite AddUsers to TS ([#25830](https://github.com/RocketChat/Rocket.Chat/pull/25830) by [@kodiakhq[bot]](https://github.com/kodiakhq[bot])) +- Chore: Rewrite AddUsers to TS ([#25830](https://github.com/RocketChat/Rocket.Chat/pull/25830)) - Chore: Rewrite Admin UsersTable to Typescript ([#25698](https://github.com/RocketChat/Rocket.Chat/pull/25698)) @@ -2330,7 +5631,7 @@ - Regression: Federated users not showing as federated in Room Members ([#26249](https://github.com/RocketChat/Rocket.Chat/pull/26249)) -- Regression: fix `directory` endpoint not listing teams ([#26310](https://github.com/RocketChat/Rocket.Chat/pull/26310)) +- Regression: fix `directory` endpoint not listing teams ([#26310](https://github.com/RocketChat/Rocket.Chat/pull/26310) by [@carlosrodrigues94](https://github.com/carlosrodrigues94)) - Regression: Fix app icons breaking UI ([#26278](https://github.com/RocketChat/Rocket.Chat/pull/26278)) @@ -2485,7 +5786,7 @@ ### I'm definitely open for better looking alternatives. Please leave a comment if you have a better solution to share. -- Regression: Matrix Federation regressions ([#26283](https://github.com/RocketChat/Rocket.Chat/pull/26283)) +- Regression: Matrix Federation regressions ([#26283](https://github.com/RocketChat/Rocket.Chat/pull/26283) by [@carlosrodrigues94](https://github.com/carlosrodrigues94)) - Regression: Messages in new message template Crashing. ([#25327](https://github.com/RocketChat/Rocket.Chat/pull/25327)) @@ -2672,6 +5973,7 @@ - [@Sh0uld](https://github.com/Sh0uld) - [@aakash-gitdev](https://github.com/aakash-gitdev) - [@amolghode1981](https://github.com/amolghode1981) +- [@carlosrodrigues94](https://github.com/carlosrodrigues94) - [@cuonghuunguyen](https://github.com/cuonghuunguyen) - [@dependabot[bot]](https://github.com/dependabot[bot]) - [@divinespear](https://github.com/divinespear) @@ -2680,7 +5982,6 @@ - [@g-thome](https://github.com/g-thome) - [@joakimaho](https://github.com/joakimaho) - [@kibonusp](https://github.com/kibonusp) -- [@kodiakhq[bot]](https://github.com/kodiakhq[bot]) - [@matthias4217](https://github.com/matthias4217) - [@ostjen](https://github.com/ostjen) - [@paulobernardoaf](https://github.com/paulobernardoaf) @@ -2698,7 +5999,6 @@ - [@alansikora](https://github.com/alansikora) - [@albuquerquefabio](https://github.com/albuquerquefabio) - [@aleksandernsilva](https://github.com/aleksandernsilva) -- [@carlosrodrigues94](https://github.com/carlosrodrigues94) - [@cauefcr](https://github.com/cauefcr) - [@csuadev](https://github.com/csuadev) - [@d-gubert](https://github.com/d-gubert) @@ -3010,7 +6310,7 @@ - Add tooltip to sidebar room menu ([#24405](https://github.com/RocketChat/Rocket.Chat/pull/24405) by [@Himanshu664](https://github.com/Himanshu664)) -- add warnings for federation setup ([#25684](https://github.com/RocketChat/Rocket.Chat/pull/25684)) +- add warnings for federation setup ([#25684](https://github.com/RocketChat/Rocket.Chat/pull/25684) by [@carlosrodrigues94](https://github.com/carlosrodrigues94)) - Added MaxNickNameLength and MaxBioLength constants ([#25231](https://github.com/RocketChat/Rocket.Chat/pull/25231) by [@aakash-gitdev](https://github.com/aakash-gitdev)) @@ -3682,6 +6982,7 @@ - [@Himanshu664](https://github.com/Himanshu664) - [@aakash-gitdev](https://github.com/aakash-gitdev) - [@amolghode1981](https://github.com/amolghode1981) +- [@carlosrodrigues94](https://github.com/carlosrodrigues94) - [@cuonghuunguyen](https://github.com/cuonghuunguyen) - [@dependabot[bot]](https://github.com/dependabot[bot]) - [@divinespear](https://github.com/divinespear) @@ -3704,7 +7005,6 @@ - [@alansikora](https://github.com/alansikora) - [@albuquerquefabio](https://github.com/albuquerquefabio) - [@aleksandernsilva](https://github.com/aleksandernsilva) -- [@carlosrodrigues94](https://github.com/carlosrodrigues94) - [@cauefcr](https://github.com/cauefcr) - [@d-gubert](https://github.com/d-gubert) - [@debdutdeb](https://github.com/debdutdeb) @@ -12808,7 +16108,7 @@ > So basically this chat is going to block the agent's queue until the customer is able to finish his time-consuming download task in which he/she doesn't require any agent's assistance. Due to the `Max Simultaneous Chats per agent` limit, the agent is also not able to use this extra time to help other customer thus affecting his overall productivity. **So how does the On-Hold feature solve this problem?** - With the On-Hold feature, an agent is now able to place a chat on-hold. On-Hold chats **don’t count towards the maximum number of concurrent chats** an agent can have. So in our above example, the agent can simply now place the customer on-hold for 20-30 minutes until the customer downloads the software and within this time, the agent can serve other customers - hence increasing the productivity of an agent. + With the On-Hold feature, an agent is now able to place a chat on-hold. On-Hold chats **don’t count towards the maximum number of concurrent chats** an agent can have. So in our above example, the agent can simply now place the customer on-hold for 20-30 minutes until the customer downloads the software and within this time, the agent can serve other customers - hence increasing the productivity of an agent. ---------------------------------------- ### Working of the new On-Hold feature diff --git a/README.md b/README.md index c750a8d90f472..4c49c90b0a954 100644 --- a/README.md +++ b/README.md @@ -2,31 +2,61 @@ +

+ The ultimate Free Open Source Solution for team communications. +

+ [Rocket.Chat](https://rocket.chat) is an open-source fully customizable communications platform developed in JavaScript for organizations with high standards of data protection. We are a MERN based application enabling real-time conversations between colleagues, with other companies or with your customers, regardless of how they connect with you. The result is an increase in productivity and customer satisfaction rates. Every day, tens of millions of users in over 150 countries and in organizations such as Deutsche Bahn, The US Navy, and Credit Suisse trust [Rocket.Chat](https://rocket.chat) to keep their communications completely private and secure. - * [Review product documentation](https://docs.rocket.chat) - * [Review developer documentation](https://developer.rocket.chat) - +- [Review product documentation](https://docs.rocket.chat) +- [Review developer documentation](https://developer.rocket.chat) + Using our self-managed offerings you can deploy Rocket.Chat on your own server, or you can use SaaS Rocket.Chat. We offer support for both community as well as commercial plans. - - + ## Cloud Hosted Rocket.Chat https://cloud.rocket.chat/trial +## Local development + +### Prerequisites + +You can follow these instructions to setup a dev environment: + +- Install **Node 14.x (LTS)** either [manually](https://nodejs.org/dist/latest-v14.x/) or using a tool like [nvm](https://github.com/creationix/nvm) (recommended) +- Install **Meteor**: https://www.meteor.com/developers/install +- Install **yarn**: https://yarnpkg.com/getting-started/install +- Clone this repo: `git clone https://github.com/RocketChat/Rocket.Chat.git` +- Run `yarn` to install dependencies + +### Starting Rocket.Chat + +``` +yarn dsv +``` + +After initialized, you can access the server at http://localhost:3000 + +### Starting Rocket.Chat in microservices mode + +``` +yarn turbo run ms +``` + +After initialized, you can access the server at http://localhost:4000 ## Installation + Please see the [requirements documentation](https://docs.rocket.chat/installing-and-updating/minimum-requirements-for-using-rocket.chat) for system requirements and more information about supported operating systems. Please refer to [Install Rocket.Chat](https://rocket.chat/install) to install your Rocket.Chat instance. - -## Feature Request +## Feature Request [Rocket.Chat/feature-requests](https://github.com/RocketChat/feature-requests) is used to track Rocket.Chat feature requests and discussions. Click [here](https://github.com/RocketChat/feature-requests/issues/new?template=feature_request.md) to open a new feature request. [Feature Request Forums](https://forums.rocket.chat/c/feature-requests/8) stores the historical archives of old feature requests (up to 2018). @@ -35,7 +65,7 @@ Please refer to [Install Rocket.Chat](https://rocket.chat/install) to install yo Join thousands of members worldwide in our [community server](https://open.rocket.chat). Join [#Support](https://open.rocket.chat/channel/support) for help from our community with general Rocket.Chat questions. Join [#Dev](https://open.rocket.chat/channel/dev) for needing help from the community to develop new features. -Talk with Rocket.Chat's leadership at the [Community Open Call](https://www.youtube.com/playlist?list=PLee3gqXJQrFVaxryc0OKTKc92yqQX9U-5), held monthly. Join us for [the next Community Open Call](https://app.livestorm.co/rocket-chat/community-open-call?type=detailed). +Talk with Rocket.Chat's leadership at the [Community Open Call](https://www.youtube.com/playlist?list=PLee3gqXJQrFVaxryc0OKTKc92yqQX9U-5), held monthly. Join us for [the next Community Open Call](https://app.livestorm.co/rocket-chat/community-open-call?type=detailed). ## Contributions @@ -43,33 +73,32 @@ Rocket.Chat is an open source project and we are very happy to accept community ## Credits -* Emoji provided graciously by [JoyPixels](https://www.joypixels.com). -* Testing with [BrowserStack](https://www.browserstack.com). -* Translations done with [LingoHub](https://lingohub.com). - +- Emoji provided graciously by [JoyPixels](https://www.joypixels.com). +- Testing with [BrowserStack](https://www.browserstack.com). +- Translations done with [LingoHub](https://lingohub.com). ## Mobile Apps In addition to the web interface, you can also download Rocket.Chat clients for: -[![Rocket.Chat on Apple App Store](https://user-images.githubusercontent.com/551004/29770691-a2082ff4-8bc6-11e7-89a6-964cd405ea8e.png)](https://itunes.apple.com/us/app/rocket-chat/id1148741252?mt=8) [![Rocket.Chat on Google Play](https://user-images.githubusercontent.com/551004/29770692-a20975c6-8bc6-11e7-8ab0-1cde275496e0.png)](https://play.google.com/store/apps/details?id=chat.rocket.android) [![](https://user-images.githubusercontent.com/551004/48210349-50649480-e35e-11e8-97d9-74a4331faf3a.png)](https://f-droid.org/en/packages/chat.rocket.android) +[![Rocket.Chat on Apple App Store](https://user-images.githubusercontent.com/551004/29770691-a2082ff4-8bc6-11e7-89a6-964cd405ea8e.png)](https://itunes.apple.com/us/app/rocket-chat/id1148741252?mt=8) [![Rocket.Chat on Google Play](https://user-images.githubusercontent.com/551004/29770692-a20975c6-8bc6-11e7-8ab0-1cde275496e0.png)](https://play.google.com/store/apps/details?id=chat.rocket.android) [![](https://user-images.githubusercontent.com/551004/48210349-50649480-e35e-11e8-97d9-74a4331faf3a.png)](https://f-droid.org/en/packages/chat.rocket.android) ## Learn More -* [API](https://developer.rocket.chat/reference/api) -* [See who's using Rocket.Chat](https://rocket.chat/customer-stories) + +- [API](https://developer.rocket.chat/reference/api) +- [See who's using Rocket.Chat](https://rocket.chat/customer-stories) ## Become a Rocketeer + We're hiring developers, support people, and product managers all the time. Please check our [jobs page](https://rocket.chat/jobs). ## Get the Latest News -* [Twitter](https://twitter.com/RocketChat) -* [Blog](https://rocket.chat/blog) -* [Facebook](https://www.facebook.com/RocketChatApp) -* [LinkedIn](https://www.linkedin.com/company/rocket-chat) -* [Youtube](https://www.youtube.com/channel/UCin9nv7mUjoqrRiwrzS5UVQ) -* [Email Newsletter](https://rocket.chat/newsletter) +- [Twitter](https://twitter.com/RocketChat) +- [Blog](https://rocket.chat/blog) +- [Facebook](https://www.facebook.com/RocketChatApp) +- [LinkedIn](https://www.linkedin.com/company/rocket-chat) +- [Youtube](https://www.youtube.com/channel/UCin9nv7mUjoqrRiwrzS5UVQ) +- [Email Newsletter](https://rocket.chat/newsletter) Any other questions, reach out to us at [our website](https://rocket.chat/contact) or you can email us directly at [contact@rocket.chat](mailto:contact@rocket.chat). We’d be happy to help! - - diff --git a/_templates/package/new/package.json.ejs.t b/_templates/package/new/package.json.ejs.t index 44fe58fea9b44..da6f3d189bd5e 100644 --- a/_templates/package/new/package.json.ejs.t +++ b/_templates/package/new/package.json.ejs.t @@ -11,7 +11,7 @@ to: packages/<%= name %>/package.json "eslint": "^8.12.0", "jest": "^27.5.1", "ts-jest": "^27.1.4", - "typescript": "~4.5.5" + "typescript": "~4.6.4" }, "scripts": { "lint": "eslint --ext .js,.jsx,.ts,.tsx .", diff --git a/_templates/package/new/tsconfig.json.ejs.t b/_templates/package/new/tsconfig.json.ejs.t index 1b5cbc20b8ed1..3e192c674d1b8 100644 --- a/_templates/package/new/tsconfig.json.ejs.t +++ b/_templates/package/new/tsconfig.json.ejs.t @@ -2,7 +2,7 @@ to: packages/<%= name %>/tsconfig.json --- { - "extends": "../../tsconfig.base.json", + "extends": "../../tsconfig.base.client.json", "compilerOptions": { "rootDir": "./src", "outDir": "./dist" diff --git a/_templates/service/new/.eslintrc.json.ejs.t b/_templates/service/new/.eslintrc.json.ejs.t new file mode 100644 index 0000000000000..8700fafc20337 --- /dev/null +++ b/_templates/service/new/.eslintrc.json.ejs.t @@ -0,0 +1,7 @@ +--- +to: ee/apps/<%= name %>/.eslintrc.json +--- +{ + "extends": ["@rocket.chat/eslint-config"], + "ignorePatterns": ["**/dist"] +} diff --git a/_templates/service/new/package.json.ejs.t b/_templates/service/new/package.json.ejs.t new file mode 100644 index 0000000000000..d3040640a6877 --- /dev/null +++ b/_templates/service/new/package.json.ejs.t @@ -0,0 +1,55 @@ +--- +to: ee/apps/<%= name %>/package.json +--- +{ + "name": "@rocket.chat/<%= name.toLowerCase() %>", + "private": true, + "version": "0.1.0", + "description": "Rocket.Chat service", + "scripts": { + "build": "tsc -p tsconfig.json", + "ms": "TRANSPORTER=${TRANSPORTER:-TCP} MONGO_URL=${MONGO_URL:-mongodb://localhost:3001/meteor} ts-node --files src/service.ts", + "test": "echo \"Error: no test specified\" && exit 1", + "lint": "eslint src", + "typecheck": "tsc --noEmit --skipLibCheck -p tsconfig.json" + }, + "keywords": [ + "rocketchat" + ], + "author": "Rocket.Chat", + "dependencies": { + "@rocket.chat/core-services": "workspace:^", + "@rocket.chat/core-typings": "workspace:^", + "@rocket.chat/emitter": "0.31.22", + "@rocket.chat/model-typings": "workspace:^", + "@rocket.chat/models": "workspace:^", + "@rocket.chat/rest-typings": "workspace:^", + "@rocket.chat/string-helpers": "0.31.22", + "@types/node": "^14.18.21", + "ejson": "^2.2.2", + "eventemitter3": "^4.0.7", + "fibers": "^5.0.3", + "mem": "^8.1.1", + "moleculer": "^0.14.21", + "mongodb": "^4.12.1", + "nats": "^2.4.0", + "pino": "^8.4.2", + "polka": "^0.5.2" + }, + "devDependencies": { + "@rocket.chat/eslint-config": "workspace:^", + "@types/eslint": "^8.4.10", + "@types/polka": "^0.5.4", + "eslint": "^8.29.0", + "ts-node": "^10.9.1", + "typescript": "~4.6.4" + }, + "main": "./dist/ee/apps/<%= name %>/src/service.js", + "files": [ + "/dist" + ], + "volta": { + "node": "14.19.3" + } +} + diff --git a/_templates/service/new/service.ejs.t b/_templates/service/new/service.ejs.t new file mode 100644 index 0000000000000..54080d94cf08b --- /dev/null +++ b/_templates/service/new/service.ejs.t @@ -0,0 +1,43 @@ +--- +to: ee/apps/<%= name %>/src/service.ts +--- +import type { Document } from 'mongodb'; +import polka from 'polka'; +import { api } from '@rocket.chat/core-services'; + +import { broker } from '../../../../apps/meteor/ee/server/startup/broker'; +import { Collections, getCollection, getConnection } from '../../../../apps/meteor/ee/server/services/mongo'; +import { registerServiceModels } from '../../../../apps/meteor/ee/server/lib/registerServiceModels'; + +const PORT = process.env.PORT || <%= h.random() %>; + +(async () => { + const db = await getConnection(); + + const trash = await getCollection(Collections.Trash); + + registerServiceModels(db, trash); + + api.setBroker(broker); + + // need to import service after models are registered + const { <%= h.changeCase.pascalCase(name) %> } = await import('./<%= h.changeCase.pascalCase(name) %>'); + + api.registerService(new <%= h.changeCase.pascalCase(name) %>()); + + await api.start(); + + polka() + .get('/health', async function (_req, res) { + try { + await api.nodeList(); + res.end('ok'); + } catch (err) { + console.error('Service not healthy', err); + + res.writeHead(500); + res.end('not healthy'); + } + }) + .listen(PORT); +})(); diff --git a/_templates/service/new/servicesClass.ejs.t b/_templates/service/new/servicesClass.ejs.t new file mode 100644 index 0000000000000..bd55d7032cc25 --- /dev/null +++ b/_templates/service/new/servicesClass.ejs.t @@ -0,0 +1,16 @@ +--- +to: ee/apps/<%= name %>/src/<%= h.changeCase.pascalCase(name) %>.ts +--- +import { ServiceClass } from '@rocket.chat/core-services'; + +export class <%= h.changeCase.pascalCase(name) %> extends ServiceClass { + protected name = '<%= name %>'; + + constructor() { + super(); + + // your stuff + } + + // more stuff +} diff --git a/_templates/service/new/tsconfig.json.ejs.t b/_templates/service/new/tsconfig.json.ejs.t new file mode 100644 index 0000000000000..21751b6672a96 --- /dev/null +++ b/_templates/service/new/tsconfig.json.ejs.t @@ -0,0 +1,12 @@ +--- +to: ee/apps/<%= name %>/tsconfig.json +--- +{ + "extends": "../../../tsconfig.base.server.json", + "compilerOptions": { + "outDir": "./dist" + }, + "files": ["./src/service.ts"], + "include": ["../../../apps/meteor/definition/externals/meteor"], + "exclude": ["./dist"] +} diff --git a/apps/meteor/app.json b/app.json similarity index 86% rename from apps/meteor/app.json rename to app.json index 1513ba1382a80..54ff885b504bc 100644 --- a/apps/meteor/app.json +++ b/app.json @@ -2,11 +2,12 @@ "name": "Rocket.Chat", "description": "Have your own open-source Slack-like online chat platform.", "repository": "https://github.com/RocketChat/Rocket.Chat", - "logo": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat/master/public/images/logo/1024x1024.png", + "logo": "https://raw.githubusercontent.com/RocketChat/Rocket.Chat.Artwork/master/Logos/2020/png/logo-horizontal-red.png", "keywords": ["meteor", "social", "community", "chat"], "website": "https://rocket.chat", "env": { "BUILDPACK_URL": "https://github.com/RocketChat/meteor-buildpack-horse.git", + "METEOR_APP_DIR": "apps/meteor/", "HEROKU_APP_NAME": { "description": "Please re-enter your App Name from the top.", "required": true diff --git a/apps/meteor/.docker-mongo/Dockerfile b/apps/meteor/.docker-mongo/Dockerfile index f8556d971d8bc..998fda0463632 100644 --- a/apps/meteor/.docker-mongo/Dockerfile +++ b/apps/meteor/.docker-mongo/Dockerfile @@ -1,4 +1,4 @@ -FROM node:14.19.3-bullseye-slim +FROM node:14.21.2-bullseye-slim LABEL maintainer="buildmaster@rocket.chat" diff --git a/apps/meteor/.docker/Dockerfile b/apps/meteor/.docker/Dockerfile index ce06aeb052eba..aeb5f4648aaac 100644 --- a/apps/meteor/.docker/Dockerfile +++ b/apps/meteor/.docker/Dockerfile @@ -1,4 +1,4 @@ -FROM node:14.19.3-bullseye-slim +FROM node:14.21.2-bullseye-slim LABEL maintainer="buildmaster@rocket.chat" diff --git a/apps/meteor/.docker/Dockerfile.alpine b/apps/meteor/.docker/Dockerfile.alpine index 99aa4c2eb0164..cc896cf9051f4 100644 --- a/apps/meteor/.docker/Dockerfile.alpine +++ b/apps/meteor/.docker/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM node:14.19.3-alpine3.15 +FROM node:14.21.2-alpine3.16 RUN apk add --no-cache ttf-dejavu diff --git a/apps/meteor/.docker/Dockerfile.rhel b/apps/meteor/.docker/Dockerfile.rhel index 60144f4ec05c8..acc51c42be8af 100644 --- a/apps/meteor/.docker/Dockerfile.rhel +++ b/apps/meteor/.docker/Dockerfile.rhel @@ -1,6 +1,6 @@ FROM registry.access.redhat.com/ubi8/nodejs-12 -ENV RC_VERSION 5.1.0 +ENV RC_VERSION 6.0.0 MAINTAINER buildmaster@rocket.chat diff --git a/apps/meteor/.eslintcache b/apps/meteor/.eslintcache new file mode 100644 index 0000000000000..7ace0936baa73 --- /dev/null +++ b/apps/meteor/.eslintcache @@ -0,0 +1 @@ +[{"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.mocharc.api.js":"1","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.mocharc.client.js":"2","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.mocharc.definition.js":"3","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.mocharc.js":"4","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.scripts/check-i18n.js":"5","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.scripts/fix-i18n.js":"6","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.scripts/make-migration.ts":"7","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.scripts/run-ha.ts":"8","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.scripts/translationDiff.js":"9","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.scripts/version.js":"10","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/babel.config.js":"11","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/decorators.tsx":"12","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/logo.svg.d.ts":"13","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/main.js":"14","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/manager.ts":"15","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/mocks/empty.ts":"16","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/mocks/meteor.js":"17","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/preview.ts":"18","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/TOTPCrowd.js":"19","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/TOTPGoogle.js":"20","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/TOTPLDAP.js":"21","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/TOTPOAuth.js":"22","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/TOTPPassword.js":"23","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/TOTPSaml.js":"24","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/index.ts":"25","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/overrideMeteorCall.ts":"26","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/MethodInvocationOverride.js":"27","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/code/EmailCheck.ts":"28","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/code/ICodeCheck.ts":"29","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/code/PasswordCheckFallback.ts":"30","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/code/TOTPCheck.ts":"31","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/code/index.ts":"32","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/functions/resetTOTP.ts":"33","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/index.ts":"34","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/lib/totp.ts":"35","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/loginHandler.ts":"36","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/methods/checkCodesRemaining.ts":"37","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/methods/disable.ts":"38","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/methods/enable.ts":"39","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/methods/regenerateCodes.ts":"40","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/methods/validateTempToken.ts":"41","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/startup/settings.ts":"42","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/twoFactorRequired.ts":"43","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/action-links/client/index.ts":"44","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/action-links/client/lib/actionLinks.ts":"45","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/analytics/client/index.ts":"46","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/analytics/client/loadScript.ts":"47","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/analytics/client/trackEvents.js":"48","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/analytics/server/index.ts":"49","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/analytics/server/settings.ts":"50","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/api.d.ts":"51","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/api.helpers.ts":"52","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/api.js":"53","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/default/info.ts":"54","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/addUserToFileObj.ts":"55","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/composeRoomWithLastMessage.ts":"56","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/deprecationWarning.ts":"57","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/getLoggedInUser.ts":"58","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/getPaginationItems.ts":"59","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/getUserFromParams.ts":"60","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/getUserInfo.ts":"61","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/isUserFromParams.ts":"62","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/isWidget.ts":"63","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/parseJsonQuery.ts":"64","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/requestParams.ts":"65","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/index.ts":"66","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/cleanQuery.ts":"67","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/emailInbox.ts":"68","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/emoji-custom.ts":"69","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/getServerInfo.ts":"70","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/getUploadFormData.ts":"71","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/integrations.ts":"72","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/isValidQuery.ts":"73","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/messages.ts":"74","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/rooms.ts":"75","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/users.ts":"76","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/webdav.ts":"77","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/middlewares/authentication.ts":"78","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/settings.ts":"79","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/assets.ts":"80","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/autotranslate.ts":"81","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/banners.ts":"82","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/channels.js":"83","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/channels.ts":"84","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/chat.js":"85","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/cloud.ts":"86","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/commands.ts":"87","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/connection.d.ts":"88","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/custom-sounds.ts":"89","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/custom-user-status.ts":"90","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/dns.ts":"91","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/e2e.ts":"92","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/email-inbox.ts":"93","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/emoji-custom.ts":"94","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/groups.js":"95","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/im.ts":"96","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/import.ts":"97","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/instances.ts":"98","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/integrations.ts":"99","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/invites.ts":"100","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/ldap.ts":"101","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/mailer.ts":"102","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/misc.ts":"103","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/oauthapps.ts":"104","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/permissions.ts":"105","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/presence.ts":"106","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/push.ts":"107","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/roles.ts":"108","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/rooms.js":"109","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/rooms.ts":"110","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/settings.ts":"111","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/stats.ts":"112","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/subscriptions.ts":"113","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/teams.ts":"114","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/users.ts":"115","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/videoConference.ts":"116","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/events.ts":"117","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/extensions.ts":"118","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/index.ts":"119","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/logger.ts":"120","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/omnichannel.ts":"121","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/queues.ts":"122","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/rooms.ts":"123","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/server-connection.ts":"124","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/webdav.ts":"125","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/client/index.ts":"126","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/lib/config.ts":"127","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/lib/handleIdentityToken.ts":"128","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/server/AppleCustomOAuth.ts":"129","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/server/appleOauthRegisterService.ts":"130","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/server/index.ts":"131","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/server/loginHandler.ts":"132","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/activation.ts":"133","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/api.ts":"134","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/bridges.js":"135","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/cloud.ts":"136","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/commands.ts":"137","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/details.ts":"138","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/environmental.ts":"139","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/http.ts":"140","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/index.ts":"141","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/internal.ts":"142","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/internalFederation.ts":"143","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/listeners.js":"144","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/livechat.ts":"145","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/messages.ts":"146","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/oauthApps.ts":"147","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/persistence.ts":"148","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/rooms.ts":"149","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/scheduler.ts":"150","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/settings.ts":"151","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/uiInteraction.ts":"152","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/uploads.ts":"153","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/users.ts":"154","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/videoConferences.ts":"155","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/departments.js":"156","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/index.ts":"157","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/messages.js":"158","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/rooms.js":"159","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/settings.js":"160","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/uploads.js":"161","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/users.js":"162","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/videoConferences.ts":"163","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/visitors.js":"164","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/assets/server/assets.ts":"165","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/assets/server/index.ts":"166","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/ILoginAttempt.ts":"167","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/hooks/login.ts":"168","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/index.ts":"169","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/lib/logLoginAttempts.ts":"170","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/lib/restrictLoginAttempts.ts":"171","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/startup/index.js":"172","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/startup/settings.ts":"173","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/client/hasPermission.ts":"174","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/client/hasRole.ts":"175","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/client/index.ts":"176","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/client/lib/ChatPermissions.js":"177","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/client/lib/streamer.ts":"178","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/client/startup.js":"179","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/index.js":"180","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/lib/AuthorizationUtils.ts":"181","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/lib/index.ts":"182","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/canAccessRoom.ts":"183","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/canDeleteMessage.ts":"184","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/canSendMessage.ts":"185","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/getRoles.ts":"186","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/getUsersInRole.ts":"187","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/hasPermission.ts":"188","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/hasRole.ts":"189","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/upsertPermissions.ts":"190","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/index.js":"191","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/methods/addPermissionToRole.ts":"192","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/methods/addUserToRole.ts":"193","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/methods/deleteRole.ts":"194","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/methods/removeRoleFromPermission.ts":"195","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/methods/removeUserFromRole.ts":"196","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/streamer/permissions/index.ts":"197","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/client/index.ts":"198","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/client/lib/actionButton.ts":"199","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/client/lib/autotranslate.ts":"200","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/client/lib/tabBar.ts":"201","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/autotranslate.ts":"202","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/deeplTranslate.ts":"203","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/googleTranslate.ts":"204","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/index.ts":"205","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/logger.ts":"206","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/methods/getProviderUiMetadata.ts":"207","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/methods/getSupportedLanguages.ts":"208","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/methods/saveSettings.ts":"209","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/methods/translateMessage.ts":"210","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/msTranslate.ts":"211","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/permissions.ts":"212","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/settings.ts":"213","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/bot-helpers/server/index.js":"214","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/bot-helpers/server/settings.ts":"215","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cas/client/cas_client.js":"216","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cas/client/index.ts":"217","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cas/server/cas_rocketchat.js":"218","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cas/server/cas_server.js":"219","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cas/server/index.ts":"220","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/client/index.ts":"221","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/client/lib/ChannelSettings.js":"222","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/client/tabBar.ts":"223","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/index.js":"224","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveReactWhenReadOnly.js":"225","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomAnnouncement.js":"226","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomCustomFields.js":"227","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomDescription.js":"228","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomEncrypted.ts":"229","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomName.js":"230","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomReadOnly.js":"231","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomSystemMessages.js":"232","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomTopic.js":"233","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomType.js":"234","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveStreamingOptions.js":"235","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/index.ts":"236","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.js":"237","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/buildRegistrationData.ts":"238","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/checkUserHasCloudLogin.js":"239","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/connectWorkspace.ts":"240","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/disconnectWorkspace.ts":"241","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/finishOAuthAuthorization.js":"242","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getConfirmationPoll.ts":"243","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getOAuthAuthorizationUrl.ts":"244","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getRedirectUri.js":"245","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getUserCloudAccessToken.ts":"246","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts":"247","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getWorkspaceAccessTokenWithScope.js":"248","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getWorkspaceKey.js":"249","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts":"250","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/reconnectWorkspace.ts":"251","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/registerPreIntentWorkspaceWizard.ts":"252","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/removeWorkspaceRegistrationInfo.ts":"253","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/retrieveRegistrationStatus.ts":"254","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/saveRegistrationData.js":"255","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts":"256","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/startRegisterWorkspaceSetupWizard.ts":"257","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/syncWorkspace.ts":"258","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/userLoggedOut.js":"259","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/userLogout.js":"260","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/index.js":"261","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/license.js":"262","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/methods.js":"263","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/oauthScopes.js":"264","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/colors/client/client.js":"265","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/colors/client/index.ts":"266","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/colors/server/index.ts":"267","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/colors/server/settings.ts":"268","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cors/client/index.js":"269","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cors/server/cors.js":"270","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cors/server/index.js":"271","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/crowd/client/index.ts":"272","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/crowd/client/loginHelper.js":"273","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/crowd/server/crowd.js":"274","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/crowd/server/index.ts":"275","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/crowd/server/settings.ts":"276","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-oauth/client/custom_oauth_client.js":"277","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-oauth/client/swapSessionStorage.js":"278","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-oauth/index.js":"279","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-oauth/server/custom_oauth_server.d.ts":"280","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-oauth/server/custom_oauth_server.js":"281","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-oauth/server/transform_helpers.js":"282","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/client/index.ts":"283","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/client/lib/CustomSounds.js":"284","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/client/notifications/deleteCustomSound.js":"285","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/client/notifications/updateCustomSound.js":"286","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/index.ts":"287","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/methods/deleteCustomSound.js":"288","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/methods/insertOrUpdateSound.js":"289","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/methods/listCustomSounds.js":"290","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/methods/uploadCustomSound.js":"291","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/startup/custom-sounds.js":"292","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/startup/settings.ts":"293","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/client/createDiscussionMessageAction.ts":"294","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/client/index.ts":"295","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/client/lib/messageTypes/discussionMessage.js":"296","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/client/tabBar.ts":"297","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/server/config.ts":"298","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/server/hooks/joinDiscussionOnMessage.js":"299","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.js":"300","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/server/index.ts":"301","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/server/methods/createDiscussion.ts":"302","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/server/permissions.ts":"303","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/dolphin/client/index.ts":"304","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/dolphin/lib/common.js":"305","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/dolphin/server/index.ts":"306","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/dolphin/server/startup.ts":"307","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/drupal/client/index.ts":"308","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/drupal/lib/common.js":"309","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/drupal/server/index.ts":"310","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/drupal/server/startup.ts":"311","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/E2ERoomState.ts":"312","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/events.js":"313","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/helper.js":"314","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/index.ts":"315","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/logger.ts":"316","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/rocketchat.e2e.room.js":"317","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/rocketchat.e2e.ts":"318","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/tabbar.ts":"319","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/wordList.ts":"320","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/beforeCreateRoom.js":"321","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/functions/handleSuggestedGroupKey.ts":"322","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/index.js":"323","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/fetchMyKeys.js":"324","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/getUsersOfRoomWithoutKey.js":"325","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/requestSubscriptionKeys.js":"326","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/resetOwnE2EKey.js":"327","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/setRoomKeyID.js":"328","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/setUserPublicAndPrivateKeys.js":"329","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/updateGroupKey.ts":"330","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/settings.ts":"331","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/client/emojiParser.js":"332","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/client/emojiPicker.js":"333","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/client/function-isSet.js":"334","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/client/index.ts":"335","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/client/lib/EmojiPicker.js":"336","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/index.js":"337","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/lib/rocketchat.js":"338","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/server/index.ts":"339","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/client/index.ts":"340","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/client/lib/emojiCustom.js":"341","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/client/lib/function-isSet.js":"342","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/client/notifications/deleteEmojiCustom.js":"343","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/client/notifications/updateEmojiCustom.js":"344","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/index.ts":"345","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/methods/deleteEmojiCustom.js":"346","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/methods/insertOrUpdateEmoji.js":"347","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/methods/listEmojiCustom.js":"348","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/methods/uploadEmojiCustom.js":"349","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/startup/emoji-custom.js":"350","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/startup/settings.ts":"351","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-emojione/client/index.ts":"352","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-emojione/lib/emojiPicker.js":"353","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-emojione/lib/emojioneRender.js":"354","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-emojione/lib/rocketchat.js":"355","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-emojione/server/callbacks.js":"356","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-emojione/server/index.ts":"357","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/error-handler/index.ts":"358","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/error-handler/server/index.ts":"359","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/error-handler/server/lib/RocketChat.ErrorHandler.js":"360","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/error-handler/server/startup/settings.ts":"361","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/constants.ts":"362","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/endpoints/dispatch.js":"363","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/endpoints/index.ts":"364","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/endpoints/requestFromLatest.js":"365","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/endpoints/uploads.js":"366","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/endpoints/users.js":"367","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/functions/addUser.js":"368","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/functions/dashboard.js":"369","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/functions/errors.js":"370","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/functions/helpers.ts":"371","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/functions/resolveDNS.ts":"372","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/functions/searchUsers.js":"373","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/handler/index.js":"374","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterAddedToRoom.js":"375","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterCreateDirectRoom.js":"376","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterCreateRoom.js":"377","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterDeleteMessage.js":"378","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterLeaveRoom.js":"379","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterMuteUser.js":"380","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterRemoveFromRoom.js":"381","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterSaveMessage.js":"382","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterSetReaction.js":"383","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterUnmuteUser.js":"384","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterUnsetReaction.js":"385","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/beforeDeleteRoom.js":"386","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/index.ts":"387","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/callbacks.js":"388","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/crypt.js":"389","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/dns.js":"390","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/getFederationDiscoveryMethod.js":"391","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/getFederationDomain.js":"392","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/http.js":"393","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/isFederationEnabled.js":"394","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/logger.js":"395","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/methods/dashboard.js":"396","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/methods/index.ts":"397","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/methods/loadContextEvents.js":"398","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/methods/testSetup.js":"399","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/normalizers/index.ts":"400","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/normalizers/message.js":"401","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/normalizers/room.js":"402","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/normalizers/subscription.js":"403","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/normalizers/user.js":"404","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/startup/generateKeys.js":"405","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/startup/index.ts":"406","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/startup/registerCallbacks.js":"407","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/startup/settings.ts":"408","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/Federation.ts":"409","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/AbstractFederationService.ts":"410","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/MessageServiceListener.ts":"411","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/RoomRedactionHandlers.ts":"412","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/RoomServiceListener.ts":"413","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/UserServiceListener.ts":"414","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/input/MessageReceiverDto.ts":"415","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/input/RoomReceiverDto.ts":"416","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/input/UserReceiverDto.ts":"417","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/sender/MessageSenders.ts":"418","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/sender/MessageServiceSender.ts":"419","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/sender/RoomInternalHooksValidator.ts":"420","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/sender/RoomServiceSender.ts":"421","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/sender/UserServiceSender.ts":"422","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/sender/input/RoomSenderDto.ts":"423","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/domain/FederatedRoom.ts":"424","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/domain/FederatedUser.ts":"425","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/domain/IFederationBridge.ts":"426","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/index.ts":"427","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/Factory.ts":"428","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/Bridge.ts":"429","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/MessageReceiver.ts":"430","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/MessageTextParser.ts":"431","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/RoomReceiver.ts":"432","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/UserReceiver.ts":"433","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/AbstractMatrixEvent.ts":"434","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixEventType.ts":"435","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixPowerLevels.ts":"436","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomJoinRules.ts":"437","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomType.ts":"438","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomVisibility.ts":"439","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/MessageReacted.ts":"440","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomCreated.ts":"441","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomEventRedacted.ts":"442","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomJoinRulesChanged.ts":"443","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomMembershipChanged.ts":"444","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomMessageSent.ts":"445","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomNameChanged.ts":"446","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomPowerLevelsChanged.ts":"447","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomTopicChanged.ts":"448","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/UserTypingStatusChanged.ts":"449","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/BaseEvent.ts":"450","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/Message.ts":"451","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/Room.ts":"452","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/User.ts":"453","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/index.ts":"454","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/queue/InMemoryQueue.ts":"455","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/File.ts":"456","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Message.ts":"457","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/MessageConverter.ts":"458","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Notification.ts":"459","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Room.ts":"460","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Settings.ts":"461","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/User.ts":"462","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/logger.ts":"463","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/MessageTextParser.ts":"464","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.ts":"465","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/definitions/InternalFederatedRoomRoles.ts":"466","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/hooks/index.ts":"467","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/slash-commands/action.ts":"468","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/slash-commands/index.ts":"469","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/statistics.ts":"470","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file/index.ts":"471","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file/server/file.server.js":"472","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file/server/index.ts":"473","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/client/index.js":"474","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/client/lib/fileUploadHandler.js":"475","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/index.js":"476","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/lib/FileUploadBase.js":"477","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/config/AmazonS3.js":"478","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/config/FileSystem.js":"479","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/config/GoogleStorage.js":"480","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/config/GridFS.js":"481","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/config/Webdav.js":"482","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/config/_configUploadStorage.js":"483","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/index.js":"484","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/lib/FileUpload.js":"485","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/lib/proxy.js":"486","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/lib/ranges.js":"487","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/lib/requests.js":"488","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/lib/streamToBuffer.ts":"489","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/methods/getS3FileUrl.js":"490","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/methods/sendFileMessage.ts":"491","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/startup/settings.ts":"492","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/ufs/AmazonS3/server.js":"493","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/ufs/GoogleStorage/server.js":"494","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/ufs/Webdav/server.js":"495","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/github-enterprise/client/index.ts":"496","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/github-enterprise/lib/common.js":"497","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/github-enterprise/server/index.ts":"498","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/github-enterprise/server/startup.ts":"499","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/gitlab/client/index.ts":"500","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/gitlab/lib/common.js":"501","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/gitlab/server/index.ts":"502","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/gitlab/server/startup.ts":"503","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/google-oauth/server/index.js":"504","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/highlight-words/client/client.ts":"505","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/highlight-words/client/helper.js":"506","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/highlight-words/client/index.ts":"507","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/highlight-words/index.ts":"508","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/iframe-login/client/iframe_client.js":"509","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/iframe-login/client/index.js":"510","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/iframe-login/server/iframe_rocketchat.ts":"511","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/iframe-login/server/iframe_server.js":"512","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/iframe-login/server/index.js":"513","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/client/index.js":"514","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/lib/ImporterInfo.js":"515","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/lib/ImporterProgressStep.js":"516","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/lib/Importers.js":"517","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImportDataConverter.ts":"518","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImporterBase.js":"519","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImporterProgress.js":"520","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImporterSelection.js":"521","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImporterSelectionChannel.js":"522","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImporterSelectionUser.js":"523","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImporterWebsocket.js":"524","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/VirtualDataConverter.ts":"525","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/definitions/IConversionCallbacks.ts":"526","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/index.js":"527","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/downloadPublicImportFile.ts":"528","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/getImportFileData.ts":"529","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/getImportProgress.ts":"530","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/getLatestImportOperations.ts":"531","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/index.ts":"532","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/startImport.ts":"533","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/uploadImportFile.ts":"534","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/models/RawImports.js":"535","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/startup/setImportsToInvalid.js":"536","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/startup/store.js":"537","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-csv/client/adder.js":"538","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-csv/client/index.js":"539","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-csv/lib/info.js":"540","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-csv/server/importer.js":"541","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-csv/server/index.js":"542","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-hipchat-enterprise/client/adder.js":"543","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-hipchat-enterprise/client/index.js":"544","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-hipchat-enterprise/lib/info.js":"545","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-hipchat-enterprise/server/importer.js":"546","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-hipchat-enterprise/server/index.js":"547","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-pending-avatars/server/importer.js":"548","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-pending-avatars/server/index.js":"549","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-pending-avatars/server/info.js":"550","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-pending-files/server/importer.js":"551","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-pending-files/server/index.js":"552","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-pending-files/server/info.js":"553","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack/client/adder.js":"554","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack/client/index.js":"555","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack/lib/info.js":"556","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack/server/importer.js":"557","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack/server/index.js":"558","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack-users/client/adder.js":"559","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack-users/client/index.js":"560","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack-users/lib/info.js":"561","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack-users/server/importer.js":"562","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack-users/server/index.js":"563","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/client/streamer.js":"564","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/lib/outgoingEvents.ts":"565","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/api/api.js":"566","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/index.js":"567","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/lib/mountQueriesBasedOnPermission.js":"568","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/lib/triggerHandler.js":"569","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/lib/validateOutgoingIntegration.ts":"570","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/logger.js":"571","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/clearIntegrationHistory.ts":"572","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/incoming/addIncomingIntegration.ts":"573","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/incoming/deleteIncomingIntegration.ts":"574","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.js":"575","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/outgoing/addOutgoingIntegration.ts":"576","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/outgoing/deleteOutgoingIntegration.ts":"577","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/outgoing/replayOutgoingIntegration.ts":"578","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/outgoing/updateOutgoingIntegration.js":"579","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/triggers.js":"580","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/invites/server/functions/findOrCreateInvite.js":"581","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/invites/server/functions/listInvites.js":"582","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/invites/server/functions/removeInvite.js":"583","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/invites/server/functions/sendInvitationEmail.ts":"584","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/invites/server/functions/useInviteToken.js":"585","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/invites/server/functions/validateInviteToken.js":"586","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/index.js":"587","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/index.js":"588","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/index.js":"589","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/index.js":"590","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onCreateRoom.js":"591","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onCreateUser.js":"592","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onJoinRoom.js":"593","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onLeaveRoom.js":"594","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onLogin.js":"595","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onLogout.js":"596","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onSaveMessage.js":"597","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/disconnected.js":"598","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/index.js":"599","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/joinedChannel.js":"600","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/leftChannel.js":"601","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/nickChanged.js":"602","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/sentMessage.js":"603","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/userRegistered.js":"604","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-settings.ts":"605","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc.js":"606","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/methods/resetIrcConnection.ts":"607","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/servers/RFC2813/codes.js":"608","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/servers/RFC2813/index.js":"609","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/servers/RFC2813/localCommandHandlers.js":"610","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/servers/RFC2813/parseMessage.js":"611","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/servers/RFC2813/peerCommandHandlers.js":"612","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/servers/index.js":"613","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/katex/client/index.ts":"614","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/katex/server/index.ts":"615","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/katex/server/settings.ts":"616","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/OAuthProxy.js":"617","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/index.js":"618","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/lib/LoginPresence.js":"619","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/lib/RocketChatAnnouncement.js":"620","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/lib/index.js":"621","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/methods/sendMessage.js":"622","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/startup/settingsOnLoadSiteUrl.ts":"623","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/views/customFieldsForm.js":"624","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/index.js":"625","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/lib/MessageTypes.ts":"626","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/addOAuthService.ts":"627","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/addUserToDefaultChannels.ts":"628","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/addUserToRoom.ts":"629","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/archiveRoom.ts":"630","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/attachMessage.ts":"631","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/checkEmailAvailability.ts":"632","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/checkUsernameAvailability.ts":"633","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/cleanRoomHistory.ts":"634","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/closeOmnichannelConversations.ts":"635","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/createDirectRoom.ts":"636","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/createRoom.ts":"637","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/deleteMessage.ts":"638","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/deleteRoom.ts":"639","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/deleteUser.ts":"640","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getAvatarSuggestionForUser.ts":"641","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getFullUserData.ts":"642","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getRoomByNameOrIdWithOptionToJoin.ts":"643","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getRoomsWithSingleOwner.ts":"644","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getStatusText.ts":"645","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getUserCreatedByApp.ts":"646","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getUserSingleOwnedRooms.ts":"647","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getUsernameSuggestion.ts":"648","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/index.ts":"649","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/insertMessage.js":"650","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/isTheLastMessage.ts":"651","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/loadMessageHistory.ts":"652","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/notifications/desktop.js":"653","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/notifications/email.js":"654","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/notifications/index.js":"655","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/notifications/mobile.js":"656","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/parseUrlsInMessage.js":"657","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/processWebhookMessage.js":"658","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/relinquishRoomOwnerships.ts":"659","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/removeUserFromRoom.ts":"660","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/saveCustomFields.ts":"661","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/saveCustomFieldsWithoutValidation.js":"662","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/saveUser.js":"663","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/saveUserIdentity.ts":"664","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/sendMessage.js":"665","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setEmail.ts":"666","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setRealName.ts":"667","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setRoomAvatar.ts":"668","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setStatusText.ts":"669","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setUserActiveStatus.ts":"670","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setUserAvatar.ts":"671","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setUsername.ts":"672","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/unarchiveRoom.ts":"673","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/updateGroupDMsName.ts":"674","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/updateMessage.ts":"675","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/validateCustomFields.js":"676","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/validateName.ts":"677","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/index.js":"678","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/PasswordPolicyClass.js":"679","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/RateLimiter.js":"680","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/bugsnag.ts":"681","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/debug.js":"682","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/defaultBlockedDomainsList.js":"683","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/deprecationWarningLogger.ts":"684","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/getHiddenSystemMessages.ts":"685","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/index.js":"686","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/interceptDirectReplyEmails.js":"687","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/loginErrorMessageOverride.js":"688","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/meteorFixes.js":"689","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/msgStream.js":"690","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.js":"691","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/passwordPolicy.js":"692","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/processDirectEmail.ts":"693","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js":"694","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/validateEmailDomain.js":"695","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/addOAuthService.ts":"696","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/addUserToRoom.ts":"697","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/addUsersToRoom.js":"698","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/archiveRoom.ts":"699","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/blockUser.ts":"700","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/checkRegistrationSecretURL.ts":"701","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/checkUsernameAvailability.ts":"702","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/cleanRoomHistory.js":"703","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/createChannel.ts":"704","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/createPrivateGroup.js":"705","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/createToken.ts":"706","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/deleteMessage.ts":"707","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/deleteUserOwnAccount.ts":"708","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/executeSlashCommandPreview.ts":"709","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/filterATAllTag.js":"710","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/filterATHereTag.js":"711","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/filterBadWords.ts":"712","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getChannelHistory.ts":"713","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getMessages.ts":"714","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getRoomJoinCode.ts":"715","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getRoomRoles.ts":"716","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getSingleMessage.ts":"717","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getSlashCommandPreviews.ts":"718","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getUserRoles.js":"719","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getUsernameSuggestion.js":"720","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/insertOrUpdateUser.js":"721","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/joinDefaultChannels.ts":"722","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/joinRoom.ts":"723","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/leaveRoom.ts":"724","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/refreshOAuthService.ts":"725","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/removeOAuthService.ts":"726","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/restartServer.ts":"727","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/saveCustomFields.ts":"728","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/saveSetting.js":"729","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/saveSettings.js":"730","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/sendMessage.js":"731","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/sendSMTPTestEmail.js":"732","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/setAdminStatus.ts":"733","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/setEmail.ts":"734","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/setRealName.ts":"735","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/setUsername.ts":"736","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/unarchiveRoom.ts":"737","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/unblockUser.ts":"738","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/updateMessage.js":"739","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/oauth/facebook.js":"740","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/oauth/google.js":"741","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/oauth/oauth.js":"742","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/oauth/proxy.js":"743","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/oauth/twitter.js":"744","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/email.ts":"745","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/index.ts":"746","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/oAuthServicesUpdate.js":"747","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/rateLimiter.js":"748","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/robots.js":"749","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/settings.ts":"750","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/settingsOnLoadCdnPrefix.js":"751","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/settingsOnLoadDirectReply.ts":"752","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/settingsOnLoadSMTP.ts":"753","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/settingsOnLoadSiteUrl.ts":"754","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/collections/LivechatCustomField.js":"755","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/collections/LivechatInquiry.js":"756","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/collections/LivechatTrigger.js":"757","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/externalFrame/crypto.ts":"758","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/externalFrame/externalFrameContainer.js":"759","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/externalFrame/generateNewKey.ts":"760","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/externalFrame/index.js":"761","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/externalFrame/tabBar.ts":"762","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/index.js":"763","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/lib/chartHandler.ts":"764","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/lib/stream/inquiry.js":"765","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/lib/stream/queueManager.js":"766","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/startup/notifyUnreadRooms.js":"767","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/tabBar.ts":"768","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/ui.js":"769","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/views/app/business-hours/BusinessHours.ts":"770","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/views/app/business-hours/IBusinessHourBehavior.ts":"771","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/views/app/business-hours/Single.ts":"772","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/voip.ts":"773","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/agent.ts":"774","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/appearance.ts":"775","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/businessHours.ts":"776","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/dashboards.ts":"777","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/departments.ts":"778","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/inquiries.ts":"779","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/integrations.ts":"780","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/queue.ts":"781","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/rooms.ts":"782","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/sms.js":"783","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/triggers.ts":"784","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/upload.ts":"785","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/users.ts":"786","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/visitors.ts":"787","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/lib/Assets.ts":"788","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/lib/inquiries.ts":"789","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/lib/messageTypes.ts":"790","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/lib/stream/constants.ts":"791","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/agents.ts":"792","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/appearance.ts":"793","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/businessHours.ts":"794","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/customFields.ts":"795","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/departments.ts":"796","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/inquiries.ts":"797","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/integrations.ts":"798","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/livechat.ts":"799","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/queue.ts":"800","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/rooms.ts":"801","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/transfer.ts":"802","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/triggers.ts":"803","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/users.ts":"804","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/visitors.ts":"805","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/rest.ts":"806","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/agent.ts":"807","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/config.ts":"808","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/contact.ts":"809","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/customField.ts":"810","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/message.ts":"811","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/offlineMessage.ts":"812","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/pageVisited.ts":"813","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/room.ts":"814","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/transcript.ts":"815","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/transfer.ts":"816","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/videoCall.ts":"817","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/visitor.ts":"818","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/webhooks.ts":"819","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api.ts":"820","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/business-hour/AbstractBusinessHour.ts":"821","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/business-hour/BusinessHourManager.ts":"822","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/business-hour/Default.ts":"823","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/business-hour/Helper.ts":"824","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/business-hour/Single.ts":"825","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/business-hour/index.ts":"826","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/config.ts":"827","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/externalFrame/generateNewKey.ts":"828","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/externalFrame/index.js":"829","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/externalFrame/settings.ts":"830","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/afterUserActions.ts":"831","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/beforeDelegateAgent.js":"832","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/leadCapture.js":"833","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/markRoomNotResponded.js":"834","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/markRoomResponded.js":"835","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/offlineMessage.js":"836","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/offlineMessageToChannel.js":"837","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.js":"838","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/saveAnalyticsData.js":"839","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/saveContactLastChat.js":"840","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/saveLastMessageToInquiry.ts":"841","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/saveLastVisitorMessageTs.js":"842","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/sendEmailTranscriptOnClose.ts":"843","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/sendToCRM.js":"844","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/index.js":"845","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/Analytics.js":"846","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/Contacts.ts":"847","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/Departments.ts":"848","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/Helper.js":"849","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/Livechat.js":"850","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/LivechatTyped.d.ts":"851","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/LivechatTyped.ts":"852","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/QueueManager.js":"853","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/RoutingManager.js":"854","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/analytics/agents.js":"855","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/analytics/dashboards.js":"856","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/analytics/departments.js":"857","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/callbackLogger.ts":"858","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/routing/AutoSelection.js":"859","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/routing/External.js":"860","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/routing/ManualSelection.js":"861","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/settings.ts":"862","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/stream/agentStatus.ts":"863","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/livechat.js":"864","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/addAgent.js":"865","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/addManager.js":"866","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/changeLivechatStatus.js":"867","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/closeRoom.ts":"868","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/discardTranscript.ts":"869","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getAgentData.js":"870","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getAgentOverviewData.js":"871","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getAnalyticsChartData.js":"872","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getAnalyticsOverviewData.js":"873","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getCustomFields.js":"874","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getDepartmentForwardRestrictions.js":"875","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getFirstRoomMessage.js":"876","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getNextAgent.js":"877","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getRoutingConfig.js":"878","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getTagsList.js":"879","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/loadHistory.js":"880","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/loginByToken.js":"881","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/pageVisited.js":"882","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/registerGuest.js":"883","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeAgent.js":"884","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeAllClosedRooms.ts":"885","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeCustomField.js":"886","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeDepartment.js":"887","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeManager.js":"888","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeRoom.ts":"889","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeTrigger.js":"890","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/requestTranscript.ts":"891","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/returnAsInquiry.js":"892","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveAgentInfo.js":"893","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveAppearance.ts":"894","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveBusinessHour.ts":"895","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveCustomField.js":"896","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveDepartment.js":"897","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveDepartmentAgents.js":"898","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveInfo.js":"899","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveIntegration.ts":"900","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveSurveyFeedback.js":"901","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveTrigger.js":"902","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/searchAgent.js":"903","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/sendFileLivechatMessage.js":"904","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/sendMessageLivechat.js":"905","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/sendOfflineMessage.js":"906","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/sendTranscript.js":"907","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/setCustomField.js":"908","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/setDepartmentForVisitor.js":"909","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/setUpConnection.js":"910","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/takeInquiry.js":"911","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/transfer.js":"912","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/webhookTest.js":"913","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/roomAccessValidator.compatibility.js":"914","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/roomAccessValidator.internalService.ts":"915","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/sendMessageBySMS.js":"916","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/startup.js":"917","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/statistics/LivechatAgentActivityMonitor.ts":"918","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/logger/client/index.js":"919","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/logger/client/logger.js":"920","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/logger/index.js":"921","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/logger/server/index.js":"922","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mail-messages/server/functions/sendMail.ts":"923","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mail-messages/server/functions/unsubscribe.ts":"924","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mail-messages/server/index.ts":"925","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mail-messages/server/lib/Mailer.ts":"926","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mail-messages/server/methods/sendMail.ts":"927","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mail-messages/server/methods/unsubscribe.ts":"928","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mailer/index.ts":"929","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mailer/server/api.ts":"930","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mailer/server/replaceVariables.ts":"931","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mapview/server/index.js":"932","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mapview/server/settings.ts":"933","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/client/getGlobalWindow.ts":"934","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/client/index.js":"935","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/getGlobalWindow.ts":"936","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/hljs.js":"937","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/markdown.js":"938","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/parser/filtered/filtered.js":"939","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/parser/original/code.js":"940","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/parser/original/markdown.js":"941","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/parser/original/original.js":"942","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/parser/original/token.ts":"943","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/server/getGlobalWindow.ts":"944","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/server/index.js":"945","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/client/client.js":"946","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/client/index.ts":"947","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/lib/MentionsParser.js":"948","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/server/Mentions.js":"949","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/server/index.js":"950","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/server/methods/getUserMentionsByChannel.js":"951","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/server/server.js":"952","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-attachments/client/index.js":"953","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-attachments/client/renderField.js":"954","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-attachments/index.js":"955","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-mark-as-unread/client/actionButton.ts":"956","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-mark-as-unread/client/index.js":"957","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-mark-as-unread/server/index.js":"958","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-mark-as-unread/server/logger.js":"959","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-mark-as-unread/server/unreadMessages.js":"960","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-pin/server/index.js":"961","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-pin/server/pinMessage.js":"962","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-pin/server/settings.ts":"963","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-pin/server/startup/indexes.js":"964","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-star/server/index.js":"965","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-star/server/settings.ts":"966","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-star/server/starMessage.js":"967","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-star/server/startup/indexes.js":"968","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/client/index.js":"969","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/client/saml_client.js":"970","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/IAttributeMapping.ts":"971","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/IAuthorizeRequestVariables.ts":"972","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ILogoutRequestVariables.ts":"973","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ILogoutResponse.ts":"974","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ILogoutResponseVariables.ts":"975","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/IMetadataVariables.ts":"976","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ISAMLAction.ts":"977","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ISAMLAssertion.ts":"978","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ISAMLGlobalSettings.ts":"979","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ISAMLRequest.ts":"980","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ISAMLUser.ts":"981","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/IServiceProviderOptions.ts":"982","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/callbacks.ts":"983","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/index.js":"984","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/SAML.ts":"985","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/ServiceProvider.ts":"986","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/Utils.ts":"987","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/constants.ts":"988","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/generators/AuthorizeRequest.ts":"989","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/generators/LogoutRequest.ts":"990","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/generators/LogoutResponse.ts":"991","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/generators/ServiceProviderMetadata.ts":"992","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/parsers/LogoutRequest.ts":"993","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/parsers/LogoutResponse.ts":"994","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/parsers/Response.ts":"995","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/settings.ts":"996","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/listener.ts":"997","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/loginHandler.ts":"998","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/methods/addSamlService.ts":"999","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/methods/samlLogout.ts":"1000","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/startup.ts":"1001","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-autocomplete/client/autocomplete-client.js":"1002","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-autocomplete/client/collection.js":"1003","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-autocomplete/client/index.js":"1004","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-autocomplete/client/templates.js":"1005","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/metrics/index.js":"1006","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/metrics/server/index.js":"1007","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/metrics/server/lib/collectMetrics.ts":"1008","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/metrics/server/lib/metrics.js":"1009","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/metrics/server/lib/statsTracker.js":"1010","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/index.ts":"1011","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/Avatars.ts":"1012","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/Base.ts":"1013","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/CachedChannelList.ts":"1014","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/CachedChatRoom.ts":"1015","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/CachedChatSubscription.ts":"1016","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/CachedUserList.ts":"1017","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/ChatMessage.ts":"1018","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/ChatPermissions.ts":"1019","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/ChatRoom.ts":"1020","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/ChatSubscription.ts":"1021","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/CustomSounds.ts":"1022","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/EmojiCustom.ts":"1023","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/Roles.ts":"1024","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/RoomRoles.ts":"1025","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/Uploads.ts":"1026","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/UserAndRoom.ts":"1027","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/UserDataFiles.ts":"1028","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/UserRoles.ts":"1029","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/Users.ts":"1030","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/WebdavAccounts.ts":"1031","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/index.ts":"1032","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/index.ts":"1033","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/lib/setUpdatedAt.ts":"1034","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/FederationEvents.js":"1035","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/FederationRoomEvents.js":"1036","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/ImportData.ts":"1037","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/Imports.js":"1038","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/LivechatBusinessHours.ts":"1039","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/LivechatDepartment.js":"1040","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/LivechatDepartmentAgents.js":"1041","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/LivechatInquiry.ts":"1042","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/LivechatRooms.js":"1043","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/Messages.js":"1044","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/Rooms.js":"1045","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/Subscriptions.js":"1046","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/Users.js":"1047","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/_Base.js":"1048","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/_BaseDb.js":"1049","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/apps-logs-model.js":"1050","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/apps-model.js":"1051","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/apps-persistence-model.js":"1052","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/nextcloud/client/index.js":"1053","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/nextcloud/lib/common.js":"1054","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/nextcloud/server/addWebdavServer.js":"1055","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/nextcloud/server/index.js":"1056","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/nextcloud/server/startup.ts":"1057","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notification-queue/server/NotificationQueue.ts":"1058","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/client/index.js":"1059","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/client/lib/Notifications.js":"1060","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/client/lib/Presence.ts":"1061","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/index.js":"1062","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/server/index.js":"1063","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/server/lib/Notifications.ts":"1064","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/server/lib/Presence.ts":"1065","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/admin/functions/addOAuthApp.ts":"1066","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/admin/functions/parseUriList.ts":"1067","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/admin/methods/addOAuthApp.ts":"1068","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/admin/methods/deleteOAuthApp.ts":"1069","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/admin/methods/updateOAuthApp.ts":"1070","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/index.ts":"1071","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/oauth/default-services.ts":"1072","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/oauth/oauth2-server.ts":"1073","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oembed/server/index.ts":"1074","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oembed/server/jumpToMessage.ts":"1075","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oembed/server/providers.ts":"1076","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oembed/server/server.ts":"1077","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/client/OTR.ts":"1078","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/client/OTRRoom.ts":"1079","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/client/index.ts":"1080","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/client/messageTypes.ts":"1081","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/client/tabBar.ts":"1082","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/lib/IOTR.ts":"1083","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/lib/OtrRoomState.ts":"1084","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/lib/constants.ts":"1085","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/lib/functions.ts":"1086","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/server/index.ts":"1087","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/server/methods/deleteOldOTRMessages.ts":"1088","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/server/methods/sendSystemMessages.ts":"1089","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/server/methods/updateOTRAck.ts":"1090","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/server/settings.ts":"1091","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push/server/apn.js":"1092","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push/server/gcm.js":"1093","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push/server/index.js":"1094","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push/server/logger.js":"1095","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push/server/methods.js":"1096","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push/server/push.js":"1097","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push-notifications/client/index.js":"1098","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push-notifications/client/tabBar.ts":"1099","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push-notifications/server/index.js":"1100","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push-notifications/server/lib/PushNotification.ts":"1101","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push-notifications/server/methods/saveNotificationSettings.js":"1102","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/reactions/client/index.ts":"1103","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/reactions/client/init.js":"1104","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/reactions/client/methods/setReaction.js":"1105","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/reactions/server/index.ts":"1106","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/reactions/server/setReaction.js":"1107","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/retention-policy/index.ts":"1108","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/retention-policy/server/cronPruneMessages.ts":"1109","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/retention-policy/server/index.ts":"1110","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/retention-policy/server/startup/settings.ts":"1111","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/events/events.js":"1112","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/index.js":"1113","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/logger/logger.js":"1114","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/model/provider.js":"1115","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/provider/defaultProvider.js":"1116","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/search.internalService.ts":"1117","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/service/providerService.js":"1118","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/service/validationService.js":"1119","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/client/index.ts":"1120","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/client/lib/settings.ts":"1121","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/index.js":"1122","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/lib/settings.ts":"1123","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/CachedSettings.ts":"1124","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/Middleware.ts":"1125","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/SettingsRegistry.ts":"1126","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/applyMiddlewares.ts":"1127","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/cached.ts":"1128","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/convertValue.ts":"1129","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/getSettingDefaults.ts":"1130","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/overrideGenerator.ts":"1131","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/overrideSetting.ts":"1132","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/overwriteSetting.ts":"1133","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/settings.mocks.ts":"1134","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/validateSetting.ts":"1135","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/index.ts":"1136","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/raw.ts":"1137","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/startup.ts":"1138","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/client/index.js":"1139","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/client/slackbridge_import.client.js":"1140","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/RocketAdapter.js":"1141","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/SlackAPI.js":"1142","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/SlackAdapter.js":"1143","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/index.js":"1144","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/logger.js":"1145","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/removeChannelLinks.js":"1146","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/settings.ts":"1147","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/slackbridge.js":"1148","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/slackbridge_import.server.js":"1149","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/client/index.ts":"1150","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/lib/gimme.ts":"1151","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/lib/lenny.ts":"1152","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/lib/shrug.ts":"1153","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/lib/tableflip.ts":"1154","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/lib/unflip.ts":"1155","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/server/index.ts":"1156","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-archiveroom/client/client.ts":"1157","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-archiveroom/client/index.ts":"1158","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-archiveroom/server/index.ts":"1159","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-archiveroom/server/server.ts":"1160","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-create/client/client.ts":"1161","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-create/client/index.ts":"1162","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-create/server/index.ts":"1163","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-create/server/server.ts":"1164","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-help/server/index.ts":"1165","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-help/server/server.ts":"1166","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-hide/client/hide.ts":"1167","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-hide/client/index.ts":"1168","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-hide/server/hide.ts":"1169","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-hide/server/index.ts":"1170","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-invite/client/client.ts":"1171","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-invite/client/index.ts":"1172","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-invite/server/index.ts":"1173","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-invite/server/server.ts":"1174","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-inviteall/client/client.ts":"1175","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-inviteall/client/index.ts":"1176","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-inviteall/server/index.ts":"1177","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-inviteall/server/server.ts":"1178","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-join/client/client.ts":"1179","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-join/client/index.ts":"1180","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-join/server/index.ts":"1181","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-join/server/server.ts":"1182","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-kick/client/client.ts":"1183","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-kick/client/index.ts":"1184","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-kick/server/index.ts":"1185","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-kick/server/server.ts":"1186","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-leave/server/index.ts":"1187","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-leave/server/leave.ts":"1188","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-me/server/index.ts":"1189","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-me/server/me.ts":"1190","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-msg/server/index.ts":"1191","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-msg/server/server.ts":"1192","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-mute/server/index.ts":"1193","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-mute/server/mute.ts":"1194","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-mute/server/unmute.ts":"1195","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-open/client/client.ts":"1196","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-open/client/index.ts":"1197","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-open/index.ts":"1198","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-status/client/index.ts":"1199","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-status/client/status.ts":"1200","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-status/server/index.ts":"1201","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-status/server/status.ts":"1202","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-topic/client/index.ts":"1203","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-topic/client/topic.ts":"1204","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-topic/server/index.ts":"1205","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-topic/server/topic.ts":"1206","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-unarchiveroom/client/client.ts":"1207","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-unarchiveroom/client/index.ts":"1208","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-unarchiveroom/server/index.ts":"1209","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-unarchiveroom/server/server.ts":"1210","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/index.js":"1211","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/server/functions/generateEml.js":"1212","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/server/functions/sendEmail.js":"1213","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/server/index.js":"1214","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/server/lib/rocketchat.js":"1215","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/server/settings.js":"1216","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/server/startup.js":"1217","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/index.js":"1218","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/server/SMS.js":"1219","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/server/index.js":"1220","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/server/services/mobex.js":"1221","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/server/services/twilio.js":"1222","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/server/services/voxtelesys.js":"1223","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/server/settings.ts":"1224","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/spotify/lib/spotify.ts":"1225","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/spotify/server/index.ts":"1226","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/index.js":"1227","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/functions/getLastStatistics.js":"1228","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/functions/getStatistics.ts":"1229","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/functions/otrStats.ts":"1230","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/functions/slashCommandsStats.ts":"1231","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/functions/updateStatsCounter.ts":"1232","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/index.js":"1233","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/SAUMonitor.ts":"1234","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/UAParserCustom.js":"1235","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/getAppsStatistics.js":"1236","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/getImporterStatistics.ts":"1237","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/getServicesStatistics.ts":"1238","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/statistics.ts":"1239","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/telemetryEvents.ts":"1240","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/methods/getStatistics.js":"1241","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/startup/monitor.js":"1242","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/theme/client/index.ts":"1243","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/theme/server/index.ts":"1244","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/theme/server/server.ts":"1245","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/theme/server/variables.ts":"1246","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/client/flextab/threadlist.tsx":"1247","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/client/index.ts":"1248","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/client/lib/normalizeThreadTitle.ts":"1249","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/client/messageAction/follow.ts":"1250","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/client/messageAction/replyInThread.ts":"1251","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/client/messageAction/unfollow.ts":"1252","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/functions.js":"1253","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/hooks/aftersavemessage.js":"1254","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/hooks/index.js":"1255","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/index.js":"1256","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/methods/followMessage.js":"1257","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/methods/getThreadMessages.js":"1258","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/methods/getThreadsList.js":"1259","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/methods/index.js":"1260","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/methods/unfollowMessage.js":"1261","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/settings.ts":"1262","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/token-login/server/index.js":"1263","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/token-login/server/login_token_server.js":"1264","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/tokenpass/client/index.js":"1265","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/tokenpass/lib/common.js":"1266","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/tokenpass/server/index.js":"1267","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/tokenpass/server/startup.js":"1268","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/index.ts":"1269","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/ChatMessages.ts":"1270","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/UserAction.ts":"1271","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/accounts.js":"1272","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/codeMirror/codeMirror.js":"1273","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/codeMirror/codeMirrorComponent.js":"1274","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/codeMirror/index.js":"1275","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/collections.js":"1276","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/iframeCommands.js":"1277","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/notification.js":"1278","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/parentTemplate.js":"1279","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/recorderjs/AudioEncoder.ts":"1280","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/recorderjs/AudioRecorder.ts":"1281","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/recorderjs/videoRecorder.js":"1282","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/rocket.js":"1283","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/userCard.tsx":"1284","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/userPopoverStatus.js":"1285","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/views/app/lib/CommonRoomTemplateInstance.ts":"1286","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/views/app/lib/scrolling.ts":"1287","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/views/app/photoswipeContent.ts":"1288","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/views/app/roomSearch.ts":"1289","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-cached-collection/client/index.ts":"1290","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-cached-collection/client/models/CachedCollection.ts":"1291","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-cached-collection/client/models/CachedCollectionManager.ts":"1292","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-clean-history/client/index.js":"1293","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-clean-history/client/lib/tabBar.ts":"1294","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-clean-history/index.js":"1295","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-login/index.ts":"1296","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-login/username/username.ts":"1297","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/client/index.ts":"1298","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/client/loading/index.ts":"1299","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/public/generateHTML.js":"1300","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/public/generateSprite.js":"1301","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/server/index.js":"1302","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/server/inject.ts":"1303","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/server/scripts.ts":"1304","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/ActionButtonSyncer.ts":"1305","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/ActionManager.js":"1306","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/actionButtons/dropdownAction.ts":"1307","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/actionButtons/lib/applyButtonFilters.ts":"1308","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/actionButtons/messageAction.ts":"1309","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/actionButtons/messageBox.ts":"1310","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/actionButtons/tabbar.ts":"1311","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/findParentMessage.ts":"1312","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/index.ts":"1313","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/messageBox/createComposerAPI.ts":"1314","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/messageBox/messageBox.ts":"1315","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/messageBox/messageBoxFormatting.ts":"1316","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/messageThread.ts":"1317","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/ComposerBoxPopup.tsx":"1318","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/components/composerBoxPopup/ComposerBoxPopupCannedResponse.tsx":"1319","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/components/composerBoxPopup/ComposerBoxPopupEmoji.tsx":"1320","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/components/composerBoxPopup/ComposerBoxPopupRoom.tsx":"1321","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/components/composerBoxPopup/ComposerBoxPopupSlashCommand.tsx":"1322","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/components/composerBoxPopup/ComposerBoxPopupUser.tsx":"1323","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/components/composerBoxPopupPreview/ComposerBoxPopupPreview.tsx":"1324","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/hooks/useComposerBoxPopup.ts":"1325","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/hooks/useComposerBoxPopupQueries.ts":"1326","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/messagePopupConfig.js":"1327","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/messagePopupSlashCommandPreview.js":"1328","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/index.ts":"1329","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/index.ts":"1330","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/AccountBox.ts":"1331","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/IframeLogin.js":"1332","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/MessageAction.ts":"1333","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/RoomHistoryManager.ts":"1334","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/RoomManager.ts":"1335","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/mainReady.ts":"1336","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageActionDefault.ts":"1337","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageBox.ts":"1338","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageContext.ts":"1339","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/openRoom.tsx":"1340","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/readMessages.ts":"1341","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/index.js":"1342","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/lib/Message.js":"1343","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/lib/MessageTypes.ts":"1344","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/server/index.js":"1345","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-vrecord/server/index.js":"1346","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-vrecord/server/settings.ts":"1347","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/client/index.js":"1348","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/client/lib/customUserStatus.js":"1349","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/client/lib/userStatus.ts":"1350","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/client/notifications/deleteCustomUserStatus.js":"1351","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/client/notifications/updateCustomUserStatus.js":"1352","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/index.js":"1353","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/server/index.js":"1354","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/server/methods/deleteCustomUserStatus.js":"1355","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/server/methods/getUserStatusText.js":"1356","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/server/methods/insertOrUpdateUserStatus.js":"1357","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/server/methods/listCustomUserStatus.js":"1358","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/server/methods/setUserStatus.js":"1359","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/client/index.ts":"1360","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/client/lib/RestApiClient.ts":"1361","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/index.js":"1362","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/fileUploadRestrictions.js":"1363","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getAvatarColor.ts":"1364","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getAvatarURL.ts":"1365","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getDefaultSubscriptionPref.js":"1366","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getRoomAvatarURL.js":"1367","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getURL.js":"1368","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getUserAvatarURL.js":"1369","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getUserNotificationPreference.js":"1370","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getUserPreference.js":"1371","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/mimeTypes.ts":"1372","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/placeholders.js":"1373","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/slashCommand.ts":"1374","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/tapi18n.js":"1375","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/templateVarHandler.js":"1376","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/functions/getDefaultUserFields.ts":"1377","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/functions/getMongoInfo.js":"1378","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/functions/isDocker.js":"1379","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/functions/normalizeMessageFileUpload.js":"1380","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/functions/safeGetMeteorUser.ts":"1381","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/index.js":"1382","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/lib/JWTHelper.js":"1383","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/lib/cron/Cronjobs.ts":"1384","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/lib/getTimezone.ts":"1385","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/lib/getValidRoomName.js":"1386","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/lib/normalizeMessagesForUser.ts":"1387","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/client/index.js":"1388","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/addSettings.ts":"1389","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/functions/checkVersionUpdate.ts":"1390","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/functions/getNewUpdates.ts":"1391","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/index.ts":"1392","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/logger.ts":"1393","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/methods/banner_dismiss.js":"1394","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/sampleUpdateData.js":"1395","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/videobridge/client/index.ts":"1396","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/videobridge/client/tabBar.tsx":"1397","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/voip/server/startup.ts":"1398","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/client/actionButton.ts":"1399","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/client/index.js":"1400","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/client/startup/sync.js":"1401","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/index.js":"1402","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/lib/getWebdavCredentials.ts":"1403","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/lib/uploadFileToWebdav.ts":"1404","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/lib/webdavClientAdapter.ts":"1405","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/methods/addWebdavAccount.ts":"1406","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/methods/getFileFromWebdav.ts":"1407","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/methods/getWebdavFileList.ts":"1408","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/methods/getWebdavFilePreview.ts":"1409","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/methods/removeWebdavAccount.ts":"1410","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/methods/uploadFileToWebdav.ts":"1411","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/startup/settings.ts":"1412","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/client/WebRTCClass.js":"1413","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/client/actionLink.tsx":"1414","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/client/adapter.js":"1415","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/client/index.js":"1416","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/client/screenShare.js":"1417","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/client/tabBar.tsx":"1418","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/index.js":"1419","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/server/index.js":"1420","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/server/settings.ts":"1421","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/wordpress/client/index.js":"1422","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/wordpress/lib/common.js":"1423","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/wordpress/server/index.js":"1424","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/wordpress/server/startup.ts":"1425","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/UIKit/hooks/useUIKitHandleAction.tsx":"1426","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/UIKit/hooks/useUIKitHandleClose.tsx":"1427","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/UIKit/hooks/useUIKitStateManager.tsx":"1428","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AdministrationList.spec.tsx":"1429","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AdministrationList.tsx":"1430","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AdministrationModelList.spec.tsx":"1431","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AdministrationModelList.tsx":"1432","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AppsModelList.spec.tsx":"1433","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AppsModelList.tsx":"1434","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AuditModelList.spec.tsx":"1435","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AuditModelList.tsx":"1436","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AutoCompleteAgent.tsx":"1437","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AutoCompleteAgentWithoutExtension.tsx":"1438","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AutoCompleteDepartment.tsx":"1439","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AutoCompleteDepartmentMultiple.tsx":"1440","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Backdrop.tsx":"1441","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerBadge.stories.tsx":"1442","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerBadge.tsx":"1443","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerIcon.stories.tsx":"1444","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerIcon.tsx":"1445","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerMenu.tsx":"1446","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerMenuButton.stories.tsx":"1447","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerMenuButton.tsx":"1448","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/Line.tsx":"1449","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/Wrapper.tsx":"1450","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/index.ts":"1451","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/ConfirmOwnerChangeModal.tsx":"1452","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx":"1453","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/CreateDiscussion/DefaultParentRoomField.tsx":"1454","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/CreateDiscussion/index.ts":"1455","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/CustomFieldsForm.js":"1456","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/CustomFieldsFormV2.tsx":"1457","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Emoji.tsx":"1458","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/FilterByText.tsx":"1459","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GazzodownText.tsx":"1460","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericModal.stories.tsx":"1461","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericModal.tsx":"1462","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/GenericTable.stories.tsx":"1463","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/GenericTable.tsx":"1464","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/HeaderCell.tsx":"1465","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/NoResults.tsx":"1466","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/SortIcon.tsx":"1467","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTable.tsx":"1468","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableBody.tsx":"1469","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableCell.tsx":"1470","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableHeader.tsx":"1471","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableHeaderCell.tsx":"1472","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableLoadingRow.tsx":"1473","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableLoadingTable.tsx":"1474","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableRow.tsx":"1475","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/hooks/useCurrent.ts":"1476","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/hooks/useItemsPerPage.ts":"1477","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/hooks/useItemsPerPageLabel.ts":"1478","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/hooks/usePagination.ts":"1479","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/hooks/useShowingResultsLabel.ts":"1480","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/hooks/useSort.ts":"1481","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/index.ts":"1482","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanel.stories.tsx":"1483","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanel.tsx":"1484","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelAction.tsx":"1485","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelActionGroup.tsx":"1486","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelAvatar.tsx":"1487","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelField.tsx":"1488","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelLabel.tsx":"1489","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelSection.tsx":"1490","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelText.tsx":"1491","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelTitle.tsx":"1492","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/RetentionPolicyCallout.tsx":"1493","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/index.ts":"1494","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/LocalTime.tsx":"1495","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/MarkdownText.stories.tsx":"1496","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/MarkdownText.tsx":"1497","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/OmnichannelSortingDisclaimer.tsx":"1498","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/Skeleton.tsx":"1499","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/Tags.tsx":"1500","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/hooks/useAgentsList.ts":"1501","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/hooks/useAvailableAgentsList.ts":"1502","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts":"1503","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/CloseChatModal.tsx":"1504","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/CloseChatModalData.tsx":"1505","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/EnterpriseDepartmentsModal.tsx":"1506","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx":"1507","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/ModalSeparator/ModalSeparator.tsx":"1508","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/ModalSeparator/index.ts":"1509","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/ReturnChatQueueModal.tsx":"1510","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/TranscriptModal.tsx":"1511","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/Page.stories.tsx":"1512","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/Page.tsx":"1513","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/PageBlockWithBorder.tsx":"1514","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/PageContent.tsx":"1515","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/PageContext.ts":"1516","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/PageHeader.tsx":"1517","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/PageScrollableContent.tsx":"1518","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/PageScrollableContentWithShadow.tsx":"1519","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/index.ts":"1520","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/PageSkeleton.tsx":"1521","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/PlanTag.tsx":"1522","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RawText.tsx":"1523","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomAutoComplete/Avatar.tsx":"1524","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx":"1525","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomAutoComplete/hooks/useRoomsList.ts":"1526","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomAutoComplete/index.ts":"1527","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/OmnichannelAppSourceRoomIcon.tsx":"1528","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/OmnichannelCoreSourceRoomIcon.tsx":"1529","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/OmnichannelRoomIcon.tsx":"1530","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/context/OmnichannelRoomIconContext.tsx":"1531","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/index.tsx":"1532","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/lib/OmnichannelRoomIcon.ts":"1533","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/provider/OmnichannelRoomIconProvider.tsx":"1534","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/RoomIcon.tsx":"1535","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/index.tsx":"1536","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/ScrollableContentWrapper.tsx":"1537","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/Content.tsx":"1538","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/Header.tsx":"1539","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/ListItem.tsx":"1540","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/Sidebar.tsx":"1541","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/SidebarGenericItem.tsx":"1542","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/SidebarItemsAssembler.tsx":"1543","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/SidebarNavigationItem.tsx":"1544","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/index.ts":"1545","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Skeleton.tsx":"1546","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/SortList/GroupingList.tsx":"1547","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/SortList/SortList.tsx":"1548","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/SortList/SortModeList.tsx":"1549","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/SortList/ViewModeList.tsx":"1550","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/SortList/index.ts":"1551","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Subtitle.tsx":"1552","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TextCopy.tsx":"1553","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TooltipPortal.tsx":"1554","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx":"1555","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TwoFactorModal/TwoFactorModal.tsx":"1556","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TwoFactorModal/TwoFactorPasswordModal.tsx":"1557","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TwoFactorModal/TwoFactorTotpModal.tsx":"1558","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TwoFactorModal/index.ts":"1559","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UTCClock.tsx":"1560","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UpsellModal.stories.tsx":"1561","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UpsellModal.tsx":"1562","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UrlChangeModal.tsx":"1563","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoComplete/UserAutoComplete.stories.tsx":"1564","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoComplete/UserAutoComplete.tsx":"1565","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoComplete/index.ts":"1566","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx":"1567","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated.tsx":"1568","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultipleOption.tsx":"1569","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultipleOptions.tsx":"1570","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoCompleteMultiple/index.ts":"1571","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCard.stories.tsx":"1572","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCard.tsx":"1573","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCardAction.tsx":"1574","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCardContainer.tsx":"1575","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCardInfo.tsx":"1576","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCardRole.tsx":"1577","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCardRoles.tsx":"1578","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCardUsername.tsx":"1579","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/index.ts":"1580","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserInfo/UserInfo.stories.tsx":"1581","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserInfo/UserInfo.tsx":"1582","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserInfo/UserInfoAction.tsx":"1583","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserInfo/UserInfoAvatar.tsx":"1584","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserInfo/UserInfoUsername.tsx":"1585","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserInfo/index.ts":"1586","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserStatus/ReactiveUserStatus.tsx":"1587","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserStatus/index.ts":"1588","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserStatusMenu.tsx":"1589","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBar.tsx":"1590","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarAction.tsx":"1591","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarActions.tsx":"1592","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarBack.tsx":"1593","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarButton.tsx":"1594","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarClose.tsx":"1595","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarContent.tsx":"1596","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarFooter.tsx":"1597","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarHeader.tsx":"1598","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarIcon.tsx":"1599","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarInnerContent.tsx":"1600","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarScrollableContent.tsx":"1601","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarSkeleton.tsx":"1602","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarText.tsx":"1603","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/index.ts":"1604","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/WarningModal.tsx":"1605","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/AppAvatar.tsx":"1606","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/BaseAvatar.tsx":"1607","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/RoomAvatar.tsx":"1608","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/RoomAvatarEditor.tsx":"1609","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/UserAvatar.tsx":"1610","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/UserAvatarEditor/UserAvatarEditor.tsx":"1611","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/UserAvatarEditor/UserAvatarSuggestions.js":"1612","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/UserAvatarEditor/index.ts":"1613","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/connectionStatus/ConnectionStatusBar.stories.tsx":"1614","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/connectionStatus/ConnectionStatusBar.tsx":"1615","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/Counter.stories.tsx":"1616","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/Counter.tsx":"1617","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/CounterSet.stories.tsx":"1618","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/CounterSet.tsx":"1619","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/Growth.stories.tsx":"1620","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/Growth.tsx":"1621","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/NegativeGrowthSymbol.stories.tsx":"1622","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/NegativeGrowthSymbol.tsx":"1623","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/PositiveGrowthSymbol.stories.tsx":"1624","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/PositiveGrowthSymbol.tsx":"1625","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/IgnoredContent.tsx":"1626","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/MessageCollapsible.tsx":"1627","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/MessageContentBody.tsx":"1628","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/MessageHeader.tsx":"1629","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/ReadReceiptIndicator.tsx":"1630","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/StatusIndicators.tsx":"1631","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/ToolboxHolder.tsx":"1632","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/Action.tsx":"1633","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/Attachments.tsx":"1634","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/BroadcastMetrics.tsx":"1635","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/DiscussionMetrics.tsx":"1636","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/Location.tsx":"1637","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/MessageActions.tsx":"1638","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/Reactions.tsx":"1639","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/ThreadMetrics.tsx":"1640","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/UiKitSurface.tsx":"1641","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/UrlPreviews.tsx":"1642","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/actions/MessageAction.stories.tsx":"1643","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/actions/MessageAction.tsx":"1644","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/AttachmentsItem.tsx":"1645","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/DefaultAttachment.tsx":"1646","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/FileAttachment.tsx":"1647","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/QuoteAttachment.tsx":"1648","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/default/ActionAttachmentButton.tsx":"1649","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/default/ActionAttachtment.tsx":"1650","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/default/Field.tsx":"1651","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/default/FieldsAttachment.tsx":"1652","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/default/ShortField.tsx":"1653","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/default/hooks/usePerformActionMutation.ts":"1654","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/file/AudioAttachment.tsx":"1655","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx":"1656","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/file/ImageAttachment.tsx":"1657","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/file/VideoAttachment.tsx":"1658","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/file/hooks/useLoadImage.tsx":"1659","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/Attachment.tsx":"1660","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentAuthor.tsx":"1661","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentAuthorAvatar.tsx":"1662","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentAuthorName.tsx":"1663","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentBlock.tsx":"1664","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentContent.tsx":"1665","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentDescription.tsx":"1666","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentDetails.tsx":"1667","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentDownload.tsx":"1668","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentImage.tsx":"1669","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentInner.tsx":"1670","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentRow.tsx":"1671","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentSize.tsx":"1672","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentText.tsx":"1673","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentThumb.tsx":"1674","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentTitle.tsx":"1675","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentTitleLink.tsx":"1676","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/image/ImageBox.tsx":"1677","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/image/Load.tsx":"1678","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/image/Retry.tsx":"1679","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/collapsible/CollapsibleContent.tsx":"1680","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/location/MapView.tsx":"1681","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/location/MapViewFallback.tsx":"1682","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/location/MapViewImage.tsx":"1683","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/location/hooks/useAsyncImage.ts":"1684","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/reactions/Reaction.tsx":"1685","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/reactions/useToggleReactionMutation.ts":"1686","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/uikit/ParsedText.tsx":"1687","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedCollapsible.tsx":"1688","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedHtmlPreview.tsx":"1689","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedImagePreview.tsx":"1690","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedLinkPreview.tsx":"1691","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedPreviewContent.tsx":"1692","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedPreviewMetadata.ts":"1693","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedResolver.tsx":"1694","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/UrlAudioPreview.tsx":"1695","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/UrlImagePreview.tsx":"1696","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/UrlPreview.tsx":"1697","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/UrlPreviewMetadata.tsx":"1698","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/UrlPreviewResolver.tsx":"1699","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/UrlVideoPreview.tsx":"1700","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/buildImageURL.ts":"1701","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/header/MessageRoles.stories.tsx":"1702","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/header/MessageRoles.tsx":"1703","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/header/hooks/useMessageRoles.ts":"1704","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/helpers/followSyle.ts":"1705","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/hooks/useCollapse.tsx":"1706","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/hooks/useNormalizedMessage.ts":"1707","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/hooks/useOembedLayout.ts":"1708","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/hooks/useSubscriptionFromMessageQuery.ts":"1709","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/list/MessageListContext.tsx":"1710","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/list/MessageListSkeleton.tsx":"1711","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/notification/AllMentionNotification.tsx":"1712","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/notification/MeMentionNotification.tsx":"1713","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/notification/MessageNotification.tsx":"1714","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/notification/UnreadMessagesNotification.tsx":"1715","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/toolbox/DesktopToolboxDropdown.tsx":"1716","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/toolbox/MessageActionMenu.tsx":"1717","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/toolbox/MobileToolboxDropdown.tsx":"1718","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/toolbox/Toolbox.tsx":"1719","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/toolbox/ToolboxDropdown.tsx":"1720","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/RoomMessage.tsx":"1721","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/SystemMessage.tsx":"1722","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/ThreadMessage.tsx":"1723","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/ThreadMessagePreview.spec.tsx":"1724","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/ThreadMessagePreview.tsx":"1725","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/room/RoomMessageContent.spec.tsx":"1726","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx":"1727","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/thread/ThreadMessageContent.tsx":"1728","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/threadPreview/ThreadMessagePreviewBody.tsx":"1729","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/modal/ModalBackdrop.tsx":"1730","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/modal/ModalPortal.tsx":"1731","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/root/ErrorBoundary.tsx":"1732","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/voip/room/VoipRoomForeword.tsx":"1733","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/withDoNotAskAgain.tsx":"1734","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/contexts/ActionManagerContext.ts":"1735","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/contexts/CallContext.ts":"1736","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/contexts/OmnichannelContext.ts":"1737","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/contexts/UserPresenceContext.ts":"1738","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/contexts/VideoConfContext.ts":"1739","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/definitions/MinimongoCollection.ts":"1740","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/definitions/Subscribable.ts":"1741","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/definitions/SubscriptionWithRoom.ts":"1742","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/definitions/css.d.ts":"1743","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/definitions/html.d.ts":"1744","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/definitions/info.d.ts":"1745","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/lists/useRecordList.ts":"1746","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/lists/useScrollableMessageList.ts":"1747","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/lists/useScrollableRecordList.ts":"1748","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/lists/useStreamUpdatesForMessageList.ts":"1749","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useOmnichannel.ts":"1750","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useOmnichannelAgentAvailable.ts":"1751","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useOmnichannelEnabled.ts":"1752","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useOmnichannelEnterpriseEnabled.ts":"1753","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useOmnichannelRouteConfig.ts":"1754","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useOmnichannelShowQueueLink.ts":"1755","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useQueuedInquiries.ts":"1756","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useAsyncState.ts":"1757","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useClipboardWithToast.ts":"1758","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useComponentDidUpdate.ts":"1759","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useDecryptedMessage.ts":"1760","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useDialModal.tsx":"1761","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useDontAskAgain.ts":"1762","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useEmbeddedLayout.ts":"1763","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useEndpointAction.ts":"1764","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useEndpointData.ts":"1765","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useEndpointUpload.ts":"1766","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFileInput.ts":"1767","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useForm.ts":"1768","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormatDate.ts":"1769","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormatDateAndTime.ts":"1770","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormatDuration.ts":"1771","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormatMemorySize.ts":"1772","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormatRelativeTime.ts":"1773","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormatTime.ts":"1774","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormattedRelativeTime.ts":"1775","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useHighlightedCode.ts":"1776","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useIsEnterprise.ts":"1777","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useLicense.ts":"1778","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useLocalePercentage.ts":"1779","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/usePresence.ts":"1780","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/usePreventPropagation.ts":"1781","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useReactiveQuery.ts":"1782","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useReactiveValue.ts":"1783","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useReactiveVar.ts":"1784","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useRegistrationStatus.ts":"1785","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useResizeInlineBreakpoint.ts":"1786","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useRoomIcon.tsx":"1787","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useRoomInfoEndpoint.ts":"1788","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useTimeAgo.ts":"1789","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useTimeFromNow.ts":"1790","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useTimezoneNameList.ts":"1791","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useTimezoneTime.ts":"1792","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useUTCClock.ts":"1793","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useUpdateAvatar.ts":"1794","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useUserCustomFields.ts":"1795","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useUserData.ts":"1796","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useUserDisplayName.ts":"1797","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/importPackages.ts":"1798","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/2fa/overrideLoginMethod.ts":"1799","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/2fa/process2faReturn.ts":"1800","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/2fa/utils.ts":"1801","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/RoomManager.ts":"1802","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/VideoConfManager.ts":"1803","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/appLayout.ts":"1804","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/asyncState/AsyncState.ts":"1805","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/asyncState/AsyncStatePhase.ts":"1806","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/asyncState/functions.ts":"1807","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/asyncState/index.ts":"1808","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/banners.ts":"1809","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/baseURI.ts":"1810","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/ChatAPI.ts":"1811","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/Upload.ts":"1812","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/data.ts":"1813","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/processMessageEditing.ts":"1814","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/processSetReaction.ts":"1815","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/processSlashCommand.ts":"1816","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/processTooLongMessage.ts":"1817","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/replyBroadcast.ts":"1818","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/requestMessageDeletion.ts":"1819","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/sendMessage.ts":"1820","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/uploadFiles.ts":"1821","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/uploads.ts":"1822","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/clickableItem.js":"1823","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/constants.ts":"1824","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/createReactiveSubscriptionFactory.ts":"1825","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/createRouteGroup.tsx":"1826","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/createSidebarItems.ts":"1827","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/createSubscription.ts":"1828","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/download.ts":"1829","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/errorHandling.ts":"1830","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/federation/Federation.ts":"1831","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/getLocalePercentage.ts":"1832","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/getUserDisplayName.ts":"1833","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/getWebdavServerName.ts":"1834","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/imperativeModal.ts":"1835","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/lists/CannedResponseList.ts":"1836","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/lists/DiscussionsList.ts":"1837","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/lists/FilesList.ts":"1838","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/lists/MessageList.ts":"1839","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/lists/RecordList.ts":"1840","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/lists/ThreadsList.ts":"1841","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/meteorCallWrapper.ts":"1842","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/bson.ts":"1843","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/comparisons.ts":"1844","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/index.ts":"1845","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/lookups.ts":"1846","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/query.ts":"1847","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/sort.ts":"1848","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/types.ts":"1849","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/normalizeThreadMessage.tsx":"1850","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/onClientBeforeSendMessage.ts":"1851","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/onClientMessageReceived.ts":"1852","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/parseMessageTextToAstMarkdown.ts":"1853","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/portals/blazePortals.ts":"1854","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/portals/createTemplateForComponent.ts":"1855","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/portals/portalsSubscription.ts":"1856","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/presence.ts":"1857","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/queryClient.ts":"1858","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomCoordinator.ts":"1859","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomExit.ts":"1860","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/conversation.ts":"1861","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/direct.ts":"1862","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/favorite.ts":"1863","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/index.ts":"1864","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/livechat.ts":"1865","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/private.ts":"1866","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/public.ts":"1867","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/unread.ts":"1868","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/voip.ts":"1869","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/settings/PrivateSettingsCachedCollection.ts":"1870","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/settings/PublicSettingsCachedCollection.ts":"1871","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/toast.ts":"1872","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/userData.ts":"1873","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/applyCustomTranslations.ts":"1874","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/call.ts":"1875","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/callWithErrorHandling.ts":"1876","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/createAnchor.ts":"1877","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/createToken.ts":"1878","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/deleteAnchor.ts":"1879","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/detectEmoji.ts":"1880","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/domEvents.ts":"1881","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/filterLanguage.ts":"1882","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/fireGlobalEvent.ts":"1883","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/formatBytes.ts":"1884","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/formatDate.ts":"1885","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/formatDateAndTime.ts":"1886","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/formatTime.ts":"1887","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/getAvatarAsPng.ts":"1888","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/getConfig.ts":"1889","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/getDateRange.ts":"1890","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/getUidDirectMessage.ts":"1891","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/getUserEmailVerified.ts":"1892","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/goToRoomById.ts":"1893","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/isIE11.ts":"1894","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/isIOsDevice.ts":"1895","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/isLayoutEmbedded.ts":"1896","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/isRTL.ts":"1897","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/isRTLScriptLanguage.ts":"1898","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/isValidImageFormat.ts":"1899","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/keyCodes.ts":"1900","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/legacyJumpToMessage.ts":"1901","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/mapMessageFromApi.ts":"1902","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/messageArgs.ts":"1903","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/prependReplies.ts":"1904","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/queueMicrotask.ts":"1905","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/renderEmoji.ts":"1906","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/renderMessageEmoji.ts":"1907","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/setMessageJumpQueryStringParameter.ts":"1908","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/timeAgo.ts":"1909","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/userAgentMIMETypeFallback.ts":"1910","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/waitForElement.ts":"1911","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/waitUntilFind.ts":"1912","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/voip/Helper.ts":"1913","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/voip/LocalStream.ts":"1914","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/voip/QueueAggregator.ts":"1915","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/voip/RemoteStream.ts":"1916","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/voip/Stream.ts":"1917","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/voip/VoIPUser.ts":"1918","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/main.ts":"1919","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/hideRoom.ts":"1920","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/index.ts":"1921","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/openRoom.ts":"1922","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/pinMessage.ts":"1923","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/setUserActiveStatus.ts":"1924","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/starMessage.ts":"1925","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/toggleFavorite.ts":"1926","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/unpinMessage.ts":"1927","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/updateMessage.ts":"1928","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/polyfills/childNodeRemove.ts":"1929","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/polyfills/cssVars.ts":"1930","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/polyfills/customEventPolyfill.ts":"1931","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/polyfills/hoverTouchClick.ts":"1932","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/polyfills/index.ts":"1933","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/polyfills/objectFromEntries.ts":"1934","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/portals/VideoConfPopupPortal.ts":"1935","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/ActionManagerProvider.tsx":"1936","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/AttachmentProvider.tsx":"1937","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/AuthorizationProvider.tsx":"1938","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/AvatarUrlProvider.tsx":"1939","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/CallProvider/CallProvider.tsx":"1940","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/CallProvider/definitions/IceServer.ts":"1941","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/CallProvider/hooks/useWebRtcServers.ts":"1942","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/CallProvider/index.ts":"1943","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/CallProvider/lib/parseStringToIceServers.ts":"1944","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/ConnectionStatusProvider.tsx":"1945","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/CustomSoundProvider.tsx":"1946","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/DeviceProvider/DeviceProvider.tsx":"1947","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/DeviceProvider/lib/isSetSinkIdAvailable.tsx":"1948","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/LayoutProvider.tsx":"1949","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/MeteorProvider.tsx":"1950","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/ModalProvider.tsx":"1951","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/OmnichannelProvider.tsx":"1952","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/RouterProvider.tsx":"1953","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/ServerProvider.tsx":"1954","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/SessionProvider.tsx":"1955","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/SettingsProvider.tsx":"1956","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/ToastMessagesProvider.tsx":"1957","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/TooltipProvider.tsx":"1958","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/TranslationProvider.tsx":"1959","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/UserPresenceProvider.tsx":"1960","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/UserProvider.tsx":"1961","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/VideoConfProvider.tsx":"1962","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Item/Condensed.stories.tsx":"1963","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Item/Condensed.tsx":"1964","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Item/Extended.stories.tsx":"1965","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Item/Extended.tsx":"1966","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Item/Medium.stories.tsx":"1967","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Item/Medium.tsx":"1968","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomList/RoomList.tsx":"1969","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomList/RoomListRow.tsx":"1970","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomList/ScrollerWithCustomProps.tsx":"1971","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomList/SideBarItemTemplateWithData.tsx":"1972","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomList/index.ts":"1973","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomList/normalizeSidebarMessage.ts":"1974","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomMenu.tsx":"1975","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Sidebar.stories.tsx":"1976","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Sidebar.tsx":"1977","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/SidebarPortal.tsx":"1978","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/SidebarFooter.tsx":"1979","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/SidebarFooterDefault.tsx":"1980","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/index.ts":"1981","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/voip/VoipFooter.stories.tsx":"1982","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/voip/VoipFooter.tsx":"1983","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/voip/hooks/useOmnichannelContactLabel.ts":"1984","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/voip/index.tsx":"1985","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/CreateChannel/CreateChannelModal.tsx":"1986","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/CreateChannel/index.ts":"1987","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/CreateDirectMessage.tsx":"1988","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx":"1989","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/CreateTeam/index.ts":"1990","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/EditStatusModal.tsx":"1991","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/UserAvatarButton.tsx":"1992","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/UserDropdown.tsx":"1993","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/Administration.tsx":"1994","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/CreateRoom.tsx":"1995","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/CreateRoomList.tsx":"1996","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/Directory.tsx":"1997","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/Home.tsx":"1998","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/Login.tsx":"1999","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/Search.tsx":"2000","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/Sort.tsx":"2001","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/hooks/useCreateRoomModal.tsx":"2002","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/hooks/useDropdownVisibility.ts":"2003","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/index.tsx":"2004","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/hooks/useAvatarTemplate.tsx":"2005","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/hooks/usePreventDefault.ts":"2006","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/hooks/useQueryOptions.ts":"2007","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/hooks/useRoomList.ts":"2008","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/hooks/useShortcutOpenMenu.ts":"2009","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/hooks/useTemplateByViewMode.tsx":"2010","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/index.ts":"2011","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/search/Row.tsx":"2012","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/search/ScrollerWithCustomProps.tsx":"2013","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/search/SearchList.tsx":"2014","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/search/UserItem.tsx":"2015","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/OmnichannelSection.tsx":"2016","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/StatusDisabledSection.tsx":"2017","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/OmnichannelCallDialPad.tsx":"2018","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/OmnichannelCallToggle.tsx":"2019","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/OmnichannelCallToggleError.tsx":"2020","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/OmnichannelCallToggleLoading.tsx":"2021","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/OmnichannelCallToggleReady.tsx":"2022","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/OmnichannelLivechatToggle.tsx":"2023","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/index.ts":"2024","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/UserDeleted.ts":"2025","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/absoluteUrl.ts":"2026","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/index.ts":"2027","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/jumpToMessage.ts":"2028","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/jumpToPinMessage.ts":"2029","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/jumpToSearchMessage.ts":"2030","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/jumpToStarMessage.ts":"2031","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/permalinkPinned.ts":"2032","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/permalinkStar.ts":"2033","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/pinMessage.ts":"2034","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/readReceipt.ts":"2035","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/starMessage.ts":"2036","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/unpinMessage.ts":"2037","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/unstarMessage.ts":"2038","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/afterLogoutCleanUp/customScriptOnLogout.ts":"2039","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/afterLogoutCleanUp/index.ts":"2040","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/afterLogoutCleanUp/purgeAllDrafts.ts":"2041","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/afterLogoutCleanUp/roomManager.ts":"2042","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/appRoot.tsx":"2043","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/banners.ts":"2044","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/callbacks.ts":"2045","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/contextualBar/exportMessagesTab.ts":"2046","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/contextualBar/index.ts":"2047","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/contextualBar/mentionsTab.ts":"2048","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/contextualBar/pinnedMessagesTab.ts":"2049","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/contextualBar/starredMessagesTab.ts":"2050","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/customOAuth.ts":"2051","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/customTranslations.ts":"2052","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/e2e.ts":"2053","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/emailVerification.ts":"2054","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/enterRoom/index.ts":"2055","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/enterRoom/readMessages.ts":"2056","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/forceLogout.ts":"2057","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/i18n.ts":"2058","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/incomingMessages.ts":"2059","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/index.ts":"2060","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/ldap.ts":"2061","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/loadMissedMessages.ts":"2062","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/loginViaQuery.ts":"2063","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/messageObserve.ts":"2064","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/messageTypes.ts":"2065","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/notifications/index.ts":"2066","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/notifications/konchatNotifications.ts":"2067","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/notifications/updateAvatar.ts":"2068","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/notifications/usersNameChanged.ts":"2069","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/oauth.ts":"2070","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/openedRoom.ts":"2071","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/otr.ts":"2072","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/readMessage.ts":"2073","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/reloadRoomAfterLogin.ts":"2074","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/autotranslate.ts":"2075","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/emoji.ts":"2076","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/hexcolor.ts":"2077","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/highlightWords.ts":"2078","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/index.ts":"2079","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/katex.ts":"2080","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/mentionsMessage.ts":"2081","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderNotification/index.ts":"2082","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderNotification/markdown.ts":"2083","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/roomObserve.ts":"2084","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/rootUrlChange.ts":"2085","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/routes.tsx":"2086","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/setupWizard.ts":"2087","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/slashCommands/federation.ts":"2088","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/slashCommands/index.ts":"2089","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/slashCommands/list.ts":"2090","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/startup.ts":"2091","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/streamMessage/autotranslate.ts":"2092","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/streamMessage/index.ts":"2093","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/unread.ts":"2094","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/userRoles.ts":"2095","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/userStatusManuallySet.ts":"2096","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/usersObserve.ts":"2097","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/stories/contexts/ModalContextMock.tsx":"2098","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/stories/contexts/QueryClientProviderMock.tsx":"2099","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/stories/contexts/RouterContextMock.tsx":"2100","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/stories/contexts/ServerContextMock.tsx":"2101","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/stories/contexts/TranslationContextMock.tsx":"2102","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/stories/hooks/useAutoSequence.ts":"2103","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/avatarUrlFromUsername.ts":"2104","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/emojiUrlFromName.ts":"2105","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/hasPermission.ts":"2106","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/index.ts":"2107","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/log.ts":"2108","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/nrrargs.ts":"2109","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/preference.ts":"2110","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/renderEmoji.ts":"2111","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/setting.ts":"2112","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/userHasAllPermission.ts":"2113","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templates.ts":"2114","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/AccountRouter.tsx":"2115","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/AccountSidebar.tsx":"2116","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/index.ts":"2117","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/integrations/AccountIntegrationsPage.tsx":"2118","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/integrations/AccountIntegrationsRoute.tsx":"2119","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/omnichannel/OmnichannelPreferencesPage.tsx":"2120","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/omnichannel/PreferencesConversationTranscript.tsx":"2121","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/AccountPreferencesPage.tsx":"2122","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/MyDataModal.tsx":"2123","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesGlobalSection.tsx":"2124","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesHighlightsSection.tsx":"2125","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesLocalizationSection.tsx":"2126","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesMessagesSection.tsx":"2127","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesMyDataSection.tsx":"2128","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesNotificationsSection.tsx":"2129","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesSoundSection.tsx":"2130","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesUserPresenceSection.tsx":"2131","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/profile/AccountProfileForm.tsx":"2132","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/profile/AccountProfilePage.tsx":"2133","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/profile/AccountProfileRoute.tsx":"2134","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx":"2135","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/routes.tsx":"2136","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/security/AccountSecurityPage.tsx":"2137","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/security/AccountSecurityRoute.tsx":"2138","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/security/BackupCodesModal.tsx":"2139","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/security/EndToEnd.tsx":"2140","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/security/TwoFactorEmail.tsx":"2141","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/security/TwoFactorTOTP.tsx":"2142","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/sidebarItems.ts":"2143","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/tokens/AccountTokensPage.tsx":"2144","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/tokens/AccountTokensRoute.tsx":"2145","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/tokens/AccountTokensTable/AccountTokensRow.tsx":"2146","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/tokens/AccountTokensTable/AccountTokensTable.tsx":"2147","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/tokens/AccountTokensTable/AddToken.tsx":"2148","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/tokens/AccountTokensTable/index.ts":"2149","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/AdministrationLayout.tsx":"2150","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/AdministrationRouter.tsx":"2151","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/EditableSettingsContext.ts":"2152","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/CloudPage.tsx":"2153","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/CloudRoute.js":"2154","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/ConnectToCloudSection.js":"2155","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/CopyStep.tsx":"2156","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/ManualWorkspaceRegistrationModal.js":"2157","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/PasteStep.tsx":"2158","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/RegisterWorkspace.tsx":"2159","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/TroubleshootingSection.js":"2160","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/WhatIsItSection.js":"2161","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/WorkspaceLoginSection.js":"2162","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/WorkspaceRegistrationSection.js":"2163","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/components/RegisterWorkspaceCards.tsx":"2164","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/components/RegisterWorkspaceMenu.tsx":"2165","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/constants.js":"2166","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/hooks/useFeatureBullets.tsx":"2167","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/ConnectWorkspaceModal.tsx":"2168","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/DisconnectWorkspaceModal.tsx":"2169","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisterWorkspaceModal.tsx":"2170","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupModal.tsx":"2171","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupStepOneModal.tsx":"2172","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupStepTwoModal.tsx":"2173","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisterWorkspaceSetupModal/index.tsx":"2174","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisterWorkspaceTokenModal.tsx":"2175","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisteredWorkspaceModal.tsx":"2176","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx":"2177","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx":"2178","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customEmoji/CustomEmojiRoute.tsx":"2179","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx":"2180","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customEmoji/EditCustomEmojiWithData.tsx":"2181","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx":"2182","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customSounds/CustomSoundRow.tsx":"2183","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customSounds/CustomSoundsRoute.tsx":"2184","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customSounds/EditCustomSound.tsx":"2185","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customSounds/EditSound.tsx":"2186","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customSounds/lib.ts":"2187","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserActiveConnections.tsx":"2188","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusDisabledModal.tsx":"2189","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx":"2190","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusFormWithData.tsx":"2191","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusRoute.tsx":"2192","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusService.tsx":"2193","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusRow.tsx":"2194","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx":"2195","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/index.ts":"2196","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/hooks/useActiveConnections.ts":"2197","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/hooks/useStatusDisabledModal.tsx":"2198","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/emailInbox/EmailInboxForm.tsx":"2199","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/emailInbox/EmailInboxFormWithData.tsx":"2200","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/emailInbox/EmailInboxPage.tsx":"2201","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/emailInbox/EmailInboxRoute.tsx":"2202","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/emailInbox/EmailInboxTable.tsx":"2203","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/emailInbox/SendTestButton.tsx":"2204","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/FederationDashboardPage.stories.tsx":"2205","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/FederationDashboardPage.tsx":"2206","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/FederationDashboardRoute.tsx":"2207","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/OverviewSection.stories.tsx":"2208","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/OverviewSection.tsx":"2209","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/ServersSection.stories.tsx":"2210","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/ServersSection.tsx":"2211","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportHistoryPage.stories.tsx":"2212","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportHistoryPage.tsx":"2213","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportOperationSummary.js":"2214","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportOperationSummary.stories.tsx":"2215","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportOperationSummarySkeleton.js":"2216","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportProgressPage.tsx":"2217","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportRoute.js":"2218","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportTypes.ts":"2219","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/NewImportPage.js":"2220","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/NewImportPage.stories.tsx":"2221","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/PrepareChannels.tsx":"2222","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/PrepareImportPage.js":"2223","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/PrepareUsers.tsx":"2224","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/useErrorHandler.js":"2225","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/index.ts":"2226","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/DeploymentCard.stories.tsx":"2227","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/DeploymentCard.tsx":"2228","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/DescriptionList.js":"2229","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/DescriptionList.stories.tsx":"2230","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/DescriptionListEntry.js":"2231","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/Feature.js":"2232","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/Feature.stories.tsx":"2233","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/FederationCard.tsx":"2234","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/CardHeader.tsx":"2235","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/DNSRecordItem.tsx":"2236","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/DNSRecords.tsx":"2237","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/DNSText.tsx":"2238","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/FederationModal.tsx":"2239","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/InviteUsers.tsx":"2240","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/Types.ts":"2241","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/index.ts":"2242","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/Section.tsx":"2243","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/SectionStatusIcon.tsx":"2244","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/index.ts":"2245","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/index.ts":"2246","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/InformationPage.stories.tsx":"2247","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/InformationPage.tsx":"2248","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/InformationRoute.tsx":"2249","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/InstancesModal.js":"2250","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/InstancesModal.stories.tsx":"2251","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/LicenseCard.stories.tsx":"2252","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/LicenseCard.tsx":"2253","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/OfflineLicenseModal.stories.tsx":"2254","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/OfflineLicenseModal.tsx":"2255","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/UsageCard.stories.tsx":"2256","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/UsageCard.tsx":"2257","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/UsagePieGraph.stories.tsx":"2258","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/UsagePieGraph.tsx":"2259","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/FilterByTypeAndText.js":"2260","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/IncomingWebhookForm.js":"2261","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/IntegrationRow.js":"2262","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/IntegrationsPage.tsx":"2263","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/IntegrationsRoute.js":"2264","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/IntegrationsTable.js":"2265","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/OutgoiongWebhookForm.js":"2266","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/EditIncomingWebhook.js":"2267","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/EditIncomingWebhookWithData.js":"2268","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/EditIntegrationsPage.js":"2269","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/EditOutgoingWebhook.js":"2270","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/EditOutgoingWebhookWithData.js":"2271","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/HistoryContent.tsx":"2272","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/HistoryItem.js":"2273","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/OutgoingWebhookHistoryPage.tsx":"2274","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/helpers/triggerWords.ts":"2275","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/new/NewBot.js":"2276","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/new/NewIncomingWebhook.js":"2277","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/new/NewIntegrationsPage.js":"2278","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/new/NewOutgoingWebhook.js":"2279","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/new/NewZapier.js":"2280","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/useExampleIncomingData.tsx":"2281","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/invites/InviteRow.tsx":"2282","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/invites/InvitesPage.tsx":"2283","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/invites/InvitesRoute.tsx":"2284","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/mailer/Mailer.stories.tsx":"2285","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/mailer/Mailer.tsx":"2286","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/mailer/MailerRoute.tsx":"2287","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx":"2288","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/oauthApps/EditOauthAppWithData.tsx":"2289","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/oauthApps/OAuthAddApp.tsx":"2290","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/oauthApps/OAuthAppsPage.tsx":"2291","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/oauthApps/OAuthAppsRoute.tsx":"2292","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/oauthApps/OAuthAppsTable.tsx":"2293","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/CustomRoleUpsellModal.tsx":"2294","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/EditRolePage.tsx":"2295","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/EditRolePageWithData.tsx":"2296","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsContextBar.tsx":"2297","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsRouter.tsx":"2298","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionRow.tsx":"2299","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx":"2300","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTableFilter.tsx":"2301","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx":"2302","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsTable/RoleHeader.tsx":"2303","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsTable/index.ts":"2304","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/RoleForm.tsx":"2305","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRolePage.tsx":"2306","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRolePageWithData.tsx":"2307","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTable.tsx":"2308","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTableRow.tsx":"2309","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTableWithData.tsx":"2310","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/index.ts":"2311","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/index.ts":"2312","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/hooks/useChangeRole.ts":"2313","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/hooks/usePermissionsAndRoles.ts":"2314","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/hooks/useRole.ts":"2315","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/EditRoom.tsx":"2316","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/EditRoomContextBar.tsx":"2317","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/EditRoomWithData.tsx":"2318","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/FilterByTypeAndText.tsx":"2319","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/RoomsPage.tsx":"2320","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/RoomsRoute.tsx":"2321","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/RoomsTable.tsx":"2322","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/routes.tsx":"2323","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/EditableSettingsProvider.tsx":"2324","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/GroupPage.stories.tsx":"2325","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/GroupPage.tsx":"2326","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/GroupPageSkeleton.tsx":"2327","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/GroupSelector.stories.tsx":"2328","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/GroupSelector.tsx":"2329","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/MemoizedSetting.tsx":"2330","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/ResetSettingButton.stories.tsx":"2331","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/ResetSettingButton.tsx":"2332","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/Section.stories.tsx":"2333","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/Section.tsx":"2334","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/SectionSkeleton.tsx":"2335","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/Setting.stories.tsx":"2336","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/Setting.tsx":"2337","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/SettingSkeleton.tsx":"2338","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/SettingsGroupCard.tsx":"2339","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/SettingsPage.tsx":"2340","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/SettingsRoute.tsx":"2341","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/AssetsGroupPage.tsx":"2342","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/CreateOAuthModal.tsx":"2343","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/GenericGroupPage.tsx":"2344","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/LDAPGroupPage.tsx":"2345","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/OAuthGroupPage.tsx":"2346","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/TabbedGroupPage.tsx":"2347","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/VoipGroupPage.tsx":"2348","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/voip/AssignAgentButton.tsx":"2349","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/voip/AssignAgentModal.tsx":"2350","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/voip/RemoveAgentButton.tsx":"2351","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/voip/VoipExtensionsPage.tsx":"2352","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/hooks/useSettingsGroups.ts":"2353","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/ActionSettingInput.stories.tsx":"2354","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/ActionSettingInput.tsx":"2355","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/AssetSettingInput.stories.tsx":"2356","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/AssetSettingInput.tsx":"2357","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/BooleanSettingInput.stories.tsx":"2358","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/BooleanSettingInput.tsx":"2359","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/CodeMirror.tsx":"2360","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/CodeSettingInput.stories.tsx":"2361","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/CodeSettingInput.tsx":"2362","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/ColorSettingInput.stories.tsx":"2363","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/ColorSettingInput.tsx":"2364","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/FontSettingInput.stories.tsx":"2365","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/FontSettingInput.tsx":"2366","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/GenericSettingInput.stories.tsx":"2367","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/GenericSettingInput.tsx":"2368","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/IntSettingInput.stories.tsx":"2369","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/IntSettingInput.tsx":"2370","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/LanguageSettingInput.stories.tsx":"2371","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/LanguageSettingInput.tsx":"2372","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/LookupSettingInput.tsx":"2373","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/MultiSelectSettingInput.stories.tsx":"2374","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/MultiSelectSettingInput.tsx":"2375","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/PasswordSettingInput.stories.tsx":"2376","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/PasswordSettingInput.tsx":"2377","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/RelativeUrlSettingInput.stories.tsx":"2378","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/RelativeUrlSettingInput.tsx":"2379","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/RoomPickSettingInput.tsx":"2380","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/SelectSettingInput.stories.tsx":"2381","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/SelectSettingInput.tsx":"2382","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/SelectTimezoneSettingInput.tsx":"2383","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/StringSettingInput.stories.tsx":"2384","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/StringSettingInput.tsx":"2385","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/sidebar/AdminSidebar.tsx":"2386","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/sidebar/AdminSidebarPages.tsx":"2387","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/sidebar/UpgradeTab.tsx":"2388","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/sidebarItems.ts":"2389","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/upgrade/UpgradePage/UpgradePage.tsx":"2390","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/upgrade/UpgradePage/index.ts":"2391","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/upgrade/UpgradePageError/UpgradePageError.tsx":"2392","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/upgrade/UpgradePageError/index.ts":"2393","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/AddUser.js":"2394","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/AdminUserInfoActions.tsx":"2395","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/AdminUserInfoWithData.tsx":"2396","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/EditUser.js":"2397","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/EditUserWithData.tsx":"2398","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/InviteUsers.tsx":"2399","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/UserForm.js":"2400","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/UsersPage.tsx":"2401","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/UsersRoute.tsx":"2402","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/UsersTable/UsersTable.tsx":"2403","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/UsersTable/UsersTableRow.tsx":"2404","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/UsersTable/index.ts":"2405","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useChangeAdminStatusAction.ts":"2406","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useChangeUserStatusAction.ts":"2407","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useConfirmOwnerChanges.tsx":"2408","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useDeleteUserAction.tsx":"2409","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useResetE2EEKeyAction.tsx":"2410","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useResetTOTPAction.tsx":"2411","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useSendInvitationEmailMutation.ts":"2412","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/viewLogs/ServerLogs.tsx":"2413","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/viewLogs/ViewLogsPage.stories.tsx":"2414","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/viewLogs/ViewLogsPage.tsx":"2415","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/viewLogs/ViewLogsRoute.tsx":"2416","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/viewLogs/ansispan.ts":"2417","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/banners/BannerRegion.tsx":"2418","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/banners/LegacyBanner.tsx":"2419","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/banners/UiKitBanner.tsx":"2420","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/blocks/ConnectedModalBlock.js":"2421","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/blocks/ModalBlock.js":"2422","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/blocks/getButtonStyle.ts":"2423","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/blocks/textParsers.js":"2424","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/composer/AudioMessageRecorder/AudioMessageRecorder.tsx":"2425","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/composer/AudioMessageRecorder/index.ts":"2426","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/composer/EmojiPickerWrapper.tsx":"2427","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/composer/VideoMessageRecorder/VideoMessageRecorder.tsx":"2428","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/composer/VideoMessageRecorder/index.ts":"2429","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/DirectoryPage.tsx":"2430","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/RoomTags.tsx":"2431","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/hooks/useDirectoryQuery.ts":"2432","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/index.ts":"2433","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/channels/ChannelsTab.tsx":"2434","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTable.tsx":"2435","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTableRow.tsx":"2436","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/index.ts":"2437","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/teams/TeamsTab.tsx":"2438","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTable.tsx":"2439","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTableRow.tsx":"2440","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/teams/TeamsTable/index.ts":"2441","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/users/UsersTab.tsx":"2442","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx":"2443","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTableRow.tsx":"2444","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/users/UsersTable/index.ts":"2445","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/e2e/EnterE2EPasswordModal.tsx":"2446","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/e2e/SaveE2EPasswordModal.tsx":"2447","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/CustomHomePage.tsx":"2448","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/CustomHomePageContent.tsx":"2449","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/DefaultHomePage.tsx":"2450","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/HomePage.tsx":"2451","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/HomePageHeader.tsx":"2452","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/HomepageGridItem.tsx":"2453","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/AddUsersCard.tsx":"2454","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/CreateChannelsCard.tsx":"2455","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/CustomContentCard.tsx":"2456","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/DesktopAppsCard.tsx":"2457","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/DocumentationCard.tsx":"2458","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/JoinRoomsCard.tsx":"2459","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/MobileAppsCard.tsx":"2460","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useActionSpread.ts":"2461","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts":"2462","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useImperativeModal.ts":"2463","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useMembersList.ts":"2464","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useMonitorsList.ts":"2465","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useThemeShortcut.ts":"2466","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useUpgradeTabParams.ts":"2467","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/invite/InvitePage.tsx":"2468","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/invite/SecretURLPage.tsx":"2469","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/mailer/MailerUnsubscriptionPage.tsx":"2470","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AccordionLoading.tsx":"2471","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/AppDetailsPage.tsx":"2472","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/AppDetailsPageHeader.tsx":"2473","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/AppDetailsPageLoading.tsx":"2474","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/AppDetailsPageTabs.tsx":"2475","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/index.ts":"2476","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/AppDetails.tsx":"2477","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/AppDetailsAPIs.tsx":"2478","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/index.ts":"2479","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogs.tsx":"2480","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogsItem.tsx":"2481","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogsItemEntry.tsx":"2482","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/index.ts":"2483","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/AppReleases.tsx":"2484","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/AppReleasesItem.tsx":"2485","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/index.ts":"2486","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppRequests/AppRequestItem.tsx":"2487","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppRequests/AppRequests.tsx":"2488","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppRequests/AppRequestsLoading.tsx":"2489","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppSecurity/AppSecurity.tsx":"2490","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppSecurity/AppSecurityLabel.tsx":"2491","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppSettings/AppSetting.tsx":"2492","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppSettings/AppSettings.tsx":"2493","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppSettings/AppSettingsAssembler.tsx":"2494","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppSettings/index.ts":"2495","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.tsx":"2496","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatusPriceDisplay.tsx":"2497","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/index.ts":"2498","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppInstallPage.js":"2499","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppMenu.js":"2500","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppPermissionsReviewModal.tsx":"2501","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppUpdateModal.tsx":"2502","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsContext.tsx":"2503","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsList/AppRow.tsx":"2504","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsList/AppsList.tsx":"2505","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsList/index.ts":"2506","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/AppsFilters.tsx":"2507","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/AppsPage.tsx":"2508","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/AppsPageConnectionError.tsx":"2509","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/AppsPageContent.tsx":"2510","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/AppsPageContentBody.tsx":"2511","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/AppsPageContentSkeleton.tsx":"2512","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/FeaturedAppsSections.tsx":"2513","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/NoAppRequestsEmptyState.tsx":"2514","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/NoInstalledAppMatchesEmptyState.tsx":"2515","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/NoInstalledAppsEmptyState.tsx":"2516","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/NoMarketplaceOrInstalledAppMatchesEmptyState.tsx":"2517","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/PrivateEmptyState.stories.tsx":"2518","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/PrivateEmptyState.tsx":"2519","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/index.ts":"2520","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsProvider.tsx":"2521","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsRoute.tsx":"2522","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/BundleChips.tsx":"2523","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/CloudLoginModal.tsx":"2524","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/IframeModal.js":"2525","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/MarketplaceRouter.tsx":"2526","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/MarketplaceSidebar.tsx":"2527","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/UnlimitedAppsUpsellModal.tsx":"2528","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/AppInstallModal/AppInstallModal.stories.tsx":"2529","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/AppInstallModal/AppInstallModal.tsx":"2530","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/AppPermissionsList.tsx":"2531","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/BannerEnterpriseTrialEnded.tsx":"2532","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/CategoryFilter/CategoryDropDown.stories.tsx":"2533","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/CategoryFilter/CategoryDropDown.tsx":"2534","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/CategoryFilter/CategoryDropDownAnchor.tsx":"2535","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/CategoryFilter/CategoryDropDownList.tsx":"2536","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/CategoryFilter/TagList.tsx":"2537","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/DropDownListWrapper.tsx":"2538","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/EnabledAppsCount.tsx":"2539","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/MarketplaceHeader.tsx":"2540","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/RadioButtonList.tsx":"2541","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/RadioDropDown/RadioDownAnchor.tsx":"2542","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/RadioDropDown/RadioDropDown.stories.tsx":"2543","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/RadioDropDown/RadioDropDown.tsx":"2544","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/ScreenshotCarousel.tsx":"2545","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/ScreenshotCarouselAnchor.tsx":"2546","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/UninstallGrandfatheredAppModal/UninstallGrandfatheredAppModal.stories.tsx":"2547","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/UninstallGrandfatheredAppModal/UninstallGrandfatheredAppModal.tsx":"2548","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/definitions/AppInfo.ts":"2549","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/definitions/CategoryDropdownDefinitions.ts":"2550","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/definitions/RadioDropDownDefinitions.ts":"2551","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/filterAppsByCategories.ts":"2552","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/filterAppsByDisabled.ts":"2553","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/filterAppsByEnabled.ts":"2554","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/filterAppsByFree.ts":"2555","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/filterAppsByPaid.ts":"2556","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/filterAppsByText.ts":"2557","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/installApp.ts":"2558","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/isValidReference.tsx":"2559","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/marketplaceActions.ts":"2560","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/normalizeFeaturedApps.ts":"2561","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/onMouseEventPreventSideEffects.ts":"2562","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/sortAppsByAlphabeticalOrInverseOrder.ts":"2563","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/sortAppsByClosestOrFarthestModificationDate.ts":"2564","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/updateApp.ts":"2565","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers.ts":"2566","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useAppInfo.ts":"2567","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useAppInstallationHandler.tsx":"2568","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useAppRequestStats.ts":"2569","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useAppRequests.ts":"2570","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useAppsCountQuery.ts":"2571","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useCategories.ts":"2572","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useCategoryFlatList.ts":"2573","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useCategoryToggle.ts":"2574","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useFeaturedApps.ts":"2575","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useFilteredApps.ts":"2576","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useLogs.ts":"2577","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useOpenAppPermissionsReviewModal.tsx":"2578","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useOpenIncompatibleModal.tsx":"2579","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useRadioToggle.ts":"2580","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/index.ts":"2581","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/lib/getManifestFromZippedApp.ts":"2582","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/routes.tsx":"2583","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/sidebarItems.tsx":"2584","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/types.ts":"2585","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/meet/CallPage.tsx":"2586","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/meet/MeetPage.tsx":"2587","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/meet/OngoingCallDuration.tsx":"2588","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/modal/ModalRegion.tsx":"2589","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/notAuthorized/NotAuthorizedPage.stories.tsx":"2590","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/notAuthorized/NotAuthorizedPage.tsx":"2591","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/notFound/NotFoundPage.stories.tsx":"2592","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/notFound/NotFoundPage.tsx":"2593","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/OAuthAuthorizationPage.tsx":"2594","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/OAuthErrorPage.tsx":"2595","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/components/AuthorizationFormPage.tsx":"2596","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/components/CurrentUserDisplay.tsx":"2597","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/components/ErrorPage.tsx":"2598","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/components/Layout.tsx":"2599","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/hooks/useOAuthAppQuery.ts":"2600","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/OmnichannelRouter.tsx":"2601","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/additionalForms.tsx":"2602","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AddAgent.tsx":"2603","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentEdit.tsx":"2604","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentEditWithData.tsx":"2605","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentInfo.tsx":"2606","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentInfoAction.tsx":"2607","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentInfoActions.tsx":"2608","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentsPage.tsx":"2609","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentsPageRow.tsx":"2610","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentsTab.tsx":"2611","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/RemoveAgentButton.tsx":"2612","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/hooks/useQuery.ts":"2613","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/AgentOverview.js":"2614","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/AnalyticsPage.js":"2615","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/AnalyticsPage.stories.tsx":"2616","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/DateRangePicker.js":"2617","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/DateRangePicker.stories.tsx":"2618","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/InterchangeableChart.js":"2619","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/Overview.js":"2620","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/appearance/AppearanceForm.stories.tsx":"2621","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/appearance/AppearanceForm.tsx":"2622","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/appearance/AppearancePage.tsx":"2623","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/appearance/AppearancePageContainer.tsx":"2624","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursForm.js":"2625","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursForm.stories.tsx":"2626","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursFormContainer.js":"2627","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursPage.js":"2628","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursRouter.js":"2629","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/EditBusinessHoursPage.js":"2630","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/NewBusinessHoursPage.js":"2631","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/TimeRangeFieldsAssembler.js":"2632","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/TimeRangeInput.js":"2633","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/mapBusinessHoursForm.js":"2634","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/components/AgentInfoDetails.tsx":"2635","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/components/CustomField.tsx":"2636","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/components/Field.tsx":"2637","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/components/Info.tsx":"2638","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/components/Label.tsx":"2639","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/ContactHistory.tsx":"2640","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/ContactHistoryItem.tsx":"2641","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/ContactHistoryVerticalBar.tsx":"2642","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessage.tsx":"2643","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessagesVerticalBar.tsx":"2644","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/MessageList/useHistoryMessageList.ts":"2645","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/useHistoryList.ts":"2646","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx":"2647","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/CustomFieldsVerticalBar.tsx":"2648","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/FilterByText.tsx":"2649","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/Label.tsx":"2650","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/RemoveAllClosed.tsx":"2651","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/RemoveChatButton.tsx":"2652","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/hooks/useAllCustomFields.tsx":"2653","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/hooks/useCurrentChats.ts":"2654","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/hooks/useRemoveCurrentChatMutation.ts":"2655","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/CustomFieldsForm.js":"2656","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/CustomFieldsForm.stories.tsx":"2657","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/CustomFieldsPage.js":"2658","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/CustomFieldsRoute.js":"2659","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/EditCustomFieldsPage.js":"2660","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/EditCustomFieldsPageContainer.js":"2661","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/NewCustomFieldsPage.js":"2662","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/RemoveCustomFieldButton.js":"2663","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/AddAgent.js":"2664","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/AgentRow.js":"2665","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/ArchivedDepartmentsPageWithData.tsx":"2666","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/ArchivedItemMenu.tsx":"2667","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/Count.js":"2668","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/DepartmentItemMenu.tsx":"2669","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/DepartmentsAgentsTable.js":"2670","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/DepartmentsPageWithData.tsx":"2671","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/DepartmentsRoute.tsx":"2672","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/DepartmentsTable.tsx":"2673","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/EditDepartment.js":"2674","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/EditDepartmentWithAllowedForwardData.js":"2675","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/EditDepartmentWithData.js":"2676","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/NewDepartment.tsx":"2677","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/Order.js":"2678","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/PermanentDepartmentRemovalModal.tsx":"2679","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/RemoveAgentButton.js":"2680","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/CallsContextualBarDirectory.tsx":"2681","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/ChatsContextualBar.tsx":"2682","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/ContactContextualBar.tsx":"2683","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/ContextualBar.tsx":"2684","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/OmnichannelDirectoryPage.tsx":"2685","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/Call.tsx":"2686","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/CallTab.tsx":"2687","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx":"2688","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/CallTableRow.tsx":"2689","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/contextualBar/CallsContextualBarRoom.tsx":"2690","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/contextualBar/InfoField.tsx":"2691","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/contextualBar/VoipInfo.tsx":"2692","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/contextualBar/VoipInfoCallButton.tsx":"2693","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/Chat.tsx":"2694","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/ChatTab.tsx":"2695","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/ChatTable.tsx":"2696","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatInfo.js":"2697","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatInfoDirectory.js":"2698","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatsContextualBar.tsx":"2699","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/DepartmentField.tsx":"2700","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit/RoomEdit.tsx":"2701","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit/RoomEditWithData.tsx":"2702","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit/index.ts":"2703","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/VisitorClientInfo.js":"2704","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/AgentField.tsx":"2705","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/CallDialpadButton.tsx":"2706","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/ContactField.tsx":"2707","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/FormSkeleton.tsx":"2708","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/PriorityField.tsx":"2709","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/SlaField.tsx":"2710","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/SourceField.tsx":"2711","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/index.ts":"2712","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/contacts/ContactTab.js":"2713","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.tsx":"2714","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactEditWithData.js":"2715","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactInfo.tsx":"2716","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactNewEdit.tsx":"2717","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactsContextualBar.tsx":"2718","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/useCustomFieldsMetadata.tsx":"2719","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/useDepartmentInfo.ts":"2720","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/useOmnichannelRoomInfo.tsx":"2721","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/usePriorityInfo.tsx":"2722","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/useSlaInfo.tsx":"2723","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/useSlaPolicies.tsx":"2724","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/useVisitorInfo.tsx":"2725","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/utils/formatCustomFieldsMetadata.tsx":"2726","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/installation/Installation.stories.tsx":"2727","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/installation/Installation.tsx":"2728","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/installation/Wrapper.tsx":"2729","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/managers/AddManager.tsx":"2730","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/managers/ManagersRoute.tsx":"2731","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/managers/RemoveManagerButton.tsx":"2732","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/queueList/QueueListFilter.tsx":"2733","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/queueList/QueueListPage.tsx":"2734","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/queueList/hooks/useQuery.ts":"2735","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/queueList/index.tsx":"2736","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/RealTimeMonitoringPage.js":"2737","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/AgentStatusChart.js":"2738","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/Chart.js":"2739","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatDurationChart.js":"2740","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js":"2741","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerAgentChart.js":"2742","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerDepartmentChart.js":"2743","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ResponseTimesChart.js":"2744","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/getMomentChartLabelsAndData.js":"2745","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/getMomentCurrentLabel.js":"2746","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/useUpdateChartData.js":"2747","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/counter/CounterContainer.js":"2748","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/counter/CounterContainer.stories.tsx":"2749","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/counter/CounterItem.js":"2750","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/counter/CounterRow.js":"2751","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/AgentsOverview.js":"2752","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ChatsOverview.js":"2753","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ConversationOverview.js":"2754","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ProductivityOverview.js":"2755","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/routes.ts":"2756","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/sidebar/OmnichannelSidebar.tsx":"2757","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/sidebarItems.ts":"2758","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/EditTriggerPage.js":"2759","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/EditTriggerPageContainer.js":"2760","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/NewTriggerPage.js":"2761","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/TriggersForm.stories.tsx":"2762","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/TriggersForm.tsx":"2763","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/TriggersPage.js":"2764","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/TriggersRow.js":"2765","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/TriggersTable.js":"2766","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/TriggersTableContainer.js":"2767","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/webhooks/WebhooksPage.js":"2768","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/webhooks/WebhooksPageContainer.js":"2769","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Announcement/Announcement.stories.tsx":"2770","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Announcement/Announcement.tsx":"2771","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Announcement/AnnouncementComponent.tsx":"2772","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Announcement/index.tsx":"2773","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/DirectRoomHeader.tsx":"2774","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/FederatedRoomOriginServer.tsx":"2775","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Header.tsx":"2776","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/HeaderIconWithRoom.tsx":"2777","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/BackButton.tsx":"2778","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx":"2779","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/QuickActions.tsx":"2780","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/ToolBoxActionOptions.tsx":"2781","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/usePutChatOnHoldMutation.ts":"2782","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx":"2783","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts":"2784","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/index.ts":"2785","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/VoipRoomHeader.tsx":"2786","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/ParentRoom.tsx":"2787","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/ParentRoomWithData.tsx":"2788","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/ParentRoomWithEndpointData.tsx":"2789","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/ParentTeam.tsx":"2790","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/RoomHeader.tsx":"2791","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/RoomTitle.tsx":"2792","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/ToolBox/ToolBox.tsx":"2793","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/ToolBox/index.ts":"2794","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/icons/Encrypted.js":"2795","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/icons/Favorite.js":"2796","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/icons/Translate.tsx":"2797","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/index.ts":"2798","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MemberListRouter.js":"2799","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/MessageList.tsx":"2800","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/MessageListErrorBoundary.tsx":"2801","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/contexts/MessageHighlightContext.tsx":"2802","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/contexts/SelectedMessagesContext.tsx":"2803","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useAutoTranslate.spec.ts":"2804","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useAutoTranslate.ts":"2805","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useJumpToMessage.ts":"2806","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useKatex.ts":"2807","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.ts":"2808","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useMessageBody.tsx":"2809","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useMessages.ts":"2810","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useParentMessage.ts":"2811","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/index.ts":"2812","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/autoTranslate.ts":"2813","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/isMessageFirstUnread.ts":"2814","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/isMessageNewDay.ts":"2815","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/isMessageSequential.ts":"2816","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/isOwnUserMessage.ts":"2817","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/isParsedMessage.ts":"2818","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/isValidLink.ts":"2819","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/providers/MessageHighlightProvider.tsx":"2820","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsx":"2821","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/providers/messageHighlightSubscription.ts":"2822","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Room/ComposerSkeleton.tsx":"2823","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Room/Room.tsx":"2824","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/RoomNotFound.tsx":"2825","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/RoomSkeleton.tsx":"2826","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/ShareLocation/ShareLocationModal.tsx":"2827","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/ShareLocation/getGeolocationPermission.ts":"2828","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/ShareLocation/getGeolocationPosition.ts":"2829","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx":"2830","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/UserCard/index.ts":"2831","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/BlazeTemplate.tsx":"2832","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/VerticalBarOldActions.tsx":"2833","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/DropTargetOverlay.tsx":"2834","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/ErroredUploadProgressIndicator.tsx":"2835","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/JumpToRecentMessagesBar.tsx":"2836","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/LeaderBar.tsx":"2837","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/LoadingMessagesIndicator.tsx":"2838","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/NewMessagesButton.tsx":"2839","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/RetentionPolicyWarning.tsx":"2840","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/RoomBody.tsx":"2841","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/RoomForeword.tsx":"2842","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/UnreadMessagesIndicator.tsx":"2843","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/UploadProgressIndicator.tsx":"2844","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerAnonymous.tsx":"2845","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerBlocked.tsx":"2846","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerContainer.tsx":"2847","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerFederation/ComposerFederation.tsx":"2848","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerFederation/ComposerFederationDisabled.tsx":"2849","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerFederation/ComposerFederationJoinRoomDisabled.tsx":"2850","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerFederation/index.ts":"2851","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerJoinWithPassword.tsx":"2852","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerMessage.tsx":"2853","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/ComposerOmnichannel.tsx":"2854","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/ComposerOmnichannelInquiry.tsx":"2855","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/ComposerOmnichannelJoin.tsx":"2856","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/ComposerOmnichannelOnHold.tsx":"2857","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/hooks/useResumeChatOnHoldMutation.ts":"2858","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/index.tsx":"2859","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerReadOnly.tsx":"2860","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerUserActionIndicator/ComposerUserActionIndicator.tsx":"2861","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerUserActionIndicator/index.ts":"2862","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerUsersAction/ComposerUsersAction.tsx":"2863","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerVoIP.tsx":"2864","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/MessageComposer.spec.ts":"2865","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/RoomComposer/hooks/useAutoGrow.ts":"2866","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/hooks/useMessageComposerCanJoin.ts":"2867","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/hooks/useMessageComposerIsAnonymous.ts":"2868","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/hooks/useMessageComposerIsBlocked.ts":"2869","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/hooks/useMessageComposerIsReadOnly.ts":"2870","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/hooks/useMessageComposerMergedRefs.ts":"2871","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBox.tsx":"2872","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/ActionsToolbarDropdown.tsx":"2873","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/MessageBoxActionsToolbar.tsx":"2874","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/actions/AudioMessageAction.tsx":"2875","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/actions/CreateDiscussionAction.tsx":"2876","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/actions/FileUploadAction.tsx":"2877","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/actions/ShareLocationAction.tsx":"2878","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/actions/VideoMessageAction.tsx":"2879","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/actions/WebdavAction.tsx":"2880","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/index.ts":"2881","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxFormattingToolbar/FormattingToolbarDropdown.tsx":"2882","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxFormattingToolbar/MessageBoxFormattingToolbar.tsx":"2883","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxFormattingToolbar/index.ts":"2884","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxReplies.tsx":"2885","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/hooks/useMediaActionTitle.ts":"2886","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/hooks/useMediaPermissions.ts":"2887","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/hooks/useMessageBoxAutoFocus.ts":"2888","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/useDropTarget.ts":"2889","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/useFileUploadDropTarget.ts":"2890","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/useRetentionPolicy.ts":"2891","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/useRoomMessageContext.ts":"2892","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/useRoomRolesManagement.ts":"2893","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/useUnreadMessages.ts":"2894","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/contextualBar/MessageListTab.tsx":"2895","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contexts/ChatContext.ts":"2896","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contexts/ComposerPopupContext.ts":"2897","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contexts/RoomAPIContext.ts":"2898","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contexts/RoomContext.ts":"2899","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contexts/ToolboxContext.ts":"2900","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Apps/Apps.tsx":"2901","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Apps/AppsWithData.tsx":"2902","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Apps/index.ts":"2903","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslate.stories.tsx":"2904","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslate.tsx":"2905","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslateWithData.tsx":"2906","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/AutoTranslate/index.ts":"2907","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/DiscussionList.js":"2908","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/Row.js":"2909","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/components/DiscussionMessage.js":"2910","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/components/Message.stories.tsx":"2911","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/index.ts":"2912","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/mapProps.js":"2913","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/useDiscussionsList.ts":"2914","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/withData.js":"2915","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.stories.tsx":"2916","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx":"2917","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/ExportMessages/FileExport.tsx":"2918","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/ExportMessages/MailExportForm.tsx":"2919","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/ExportMessages/index.ts":"2920","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/ChannelToTeamModal/ChannelToTeamModal.js":"2921","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/ChannelToTeamModal/StepOne.js":"2922","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/ChannelToTeamModal/StepTwo.js":"2923","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannel.js":"2924","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannelWithData.js":"2925","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/index.ts":"2926","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.js":"2927","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.stories.tsx":"2928","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfoWithData.js":"2929","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/index.ts":"2930","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/index.js":"2931","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcutSection.tsx":"2932","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcuts.stories.tsx":"2933","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcuts.tsx":"2934","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcutsWithData.tsx":"2935","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/index.ts":"2936","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MentionsTab.tsx":"2937","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx":"2938","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearch.tsx":"2939","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchForm.tsx":"2940","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useMessageSearchProviderQuery.ts":"2941","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useMessageSearchQuery.ts":"2942","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MessageSearchTab/index.ts":"2943","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/NotificationPreferences.stories.tsx":"2944","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/NotificationPreferences.tsx":"2945","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/NotificationPreferencesWithData.tsx":"2946","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/components/NotificationByDevice.tsx":"2947","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/components/NotificationToogle.tsx":"2948","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/components/Preferences.tsx":"2949","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/index.ts":"2950","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/OTR/OTR.stories.tsx":"2951","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/OTR/OTR.tsx":"2952","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/OTR/OTRWithData.tsx":"2953","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/OTR/components/OTREstablished.tsx":"2954","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/OTR/components/OTRStates.tsx":"2955","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/OTR/index.ts":"2956","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/PinnedMessagesTab.tsx":"2957","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessages.stories.tsx":"2958","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessages.tsx":"2959","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesDateTimeRow.tsx":"2960","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.tsx":"2961","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/PruneMessages/index.ts":"2962","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/RoomFiles.js":"2963","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/RoomFiles.stories.tsx":"2964","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/RoomFilesWithData.js":"2965","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/Row.js":"2966","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/components/FileItem.js":"2967","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/components/FileItem.stories.tsx":"2968","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/components/FileItemIcon.js":"2969","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/components/FileItemIcon.stories.tsx":"2970","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/components/MenuItem.js":"2971","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useFilesList.ts":"2972","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useMessageDeletionIsAllowed.js":"2973","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/index.ts":"2974","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/lib/getDifference.js":"2975","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsers.stories.tsx":"2976","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsers.tsx":"2977","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsersWithData.tsx":"2978","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/index.ts":"2979","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/EditInviteLink.tsx":"2980","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/InviteLink.tsx":"2981","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/InviteUsers.stories.tsx":"2982","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/InviteUsers.tsx":"2983","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/InviteUsersWithData.tsx":"2984","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/index.ts":"2985","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembers.stories.tsx":"2986","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembers.tsx":"2987","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersActions.tsx":"2988","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersItem.tsx":"2989","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersRow.tsx":"2990","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersWithData.tsx":"2991","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/index.ts":"2992","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx":"2993","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx":"2994","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/ThreadList.tsx":"2995","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/Threads.tsx":"2996","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx":"2997","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadListItem.tsx":"2998","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadListMessage.tsx":"2999","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsx":"3000","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadSkeleton.tsx":"3001","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadTitle.tsx":"3002","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useGetMessageByID.ts":"3003","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageJump.ts":"3004","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageListScrolling.ts":"3005","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessages.ts":"3006","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMainMessageQuery.ts":"3007","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadsList.ts":"3008","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useToggleFollowingThreadMutation.ts":"3009","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/index.ts":"3010","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/UserInfo/UserInfoActions.tsx":"3011","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/UserInfo/UserInfoWithData.tsx":"3012","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/UserInfo/index.ts":"3013","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfBlockModal.tsx":"3014","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfConfigModal.tsx":"3015","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfList.tsx":"3016","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfListItem.tsx":"3017","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfListWithData.tsx":"3018","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfRecordList.ts":"3019","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/index.ts":"3020","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/useVideoConfList.ts":"3021","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopup/IncomingPopup.tsx":"3022","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopup/OutgoingPopup.tsx":"3023","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopup/StartCallPopup.tsx":"3024","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopup/TimedVideoConfPopup.tsx":"3025","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopup/VideoConfPopupRoomInfo.tsx":"3026","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopup/index.ts":"3027","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopups.tsx":"3028","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/index.ts":"3029","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/useVideoConfWarning.tsx":"3030","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useAppsContextualBar.ts":"3031","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useGoToRoom.ts":"3032","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useGoToThread.ts":"3033","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useGoToThreadList.ts":"3034","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useIsVisible.ts":"3035","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useScrollMessageList.ts":"3036","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserHasRoomRole.ts":"3037","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useBlockUserAction.ts":"3038","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useCallAction.tsx":"3039","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useChangeLeaderAction.ts":"3040","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useChangeModeratorAction.tsx":"3041","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useChangeOwnerAction.tsx":"3042","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useDirectMessageAction.ts":"3043","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useIgnoreUserAction.ts":"3044","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useMuteUserAction.tsx":"3045","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useRemoveUserAction.tsx":"3046","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/index.ts":"3047","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/useUserInfoActions.ts":"3048","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/index.ts":"3049","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/layout/RoomLayout.tsx":"3050","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/QuickActions/QuickActionsContext.tsx":"3051","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/QuickActions/defaultActions.ts":"3052","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/QuickActions/index.tsx":"3053","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/Toolbox/IframeButtons.tsx":"3054","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/Toolbox/defaultActions.ts":"3055","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/Toolbox/generator.tsx":"3056","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/Toolbox/index.tsx":"3057","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/getRoomDirectives.ts":"3058","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/FilePreview.tsx":"3059","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.stories.tsx":"3060","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.tsx":"3061","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/GenericPreview.tsx":"3062","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/ImagePreview.tsx":"3063","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/MediaPreview.tsx":"3064","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/PreviewSkeleton.tsx":"3065","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/index.ts":"3066","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReactionListModal/ReactionListModal.tsx":"3067","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReactionListModal/ReactionUserTag.tsx":"3068","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReactionListModal/Reactions.tsx":"3069","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReactionListModal/index.ts":"3070","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptRow.tsx":"3071","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx":"3072","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReadReceiptsModal/index.ts":"3073","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReportMessageModal/ReportMessageModal.tsx":"3074","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReportMessageModal/index.ts":"3075","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/ChatProvider.tsx":"3076","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx":"3077","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/RoomProvider.tsx":"3078","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/SelectedMessagesProvider.tsx":"3079","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/ToolboxProvider.tsx":"3080","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/VirtualAction.tsx":"3081","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/hooks/useChatMessagesInstance.ts":"3082","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/hooks/useDepsMatch.ts":"3083","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/hooks/useInstance.ts":"3084","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/hooks/useToolboxActions.ts":"3085","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/hooks/useUserCard.ts":"3086","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/AddWebdavAccountModal.tsx":"3087","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/SaveToWebdavModal.tsx":"3088","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/FilePickerBreadcrumbs.tsx":"3089","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerGrid/WebdavFilePickerGrid.tsx":"3090","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerGrid/WebdavFilePickerGridItem.tsx":"3091","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerGrid/index.ts":"3092","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerModal.tsx":"3093","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerTable.tsx":"3094","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/index.ts":"3095","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/lib/getNodeFileSize.ts":"3096","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/lib/getNodeIconType.ts":"3097","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/lib/sortWebdavNodes.ts":"3098","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/AppLayout.tsx":"3099","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/AppRoot.tsx":"3100","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/BlazeTemplate.tsx":"3101","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/AuthenticationCheck.tsx":"3102","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/LayoutWithSidebar.tsx":"3103","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/LoginPage.tsx":"3104","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/MainLayout.tsx":"3105","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/PasswordChangeCheck.tsx":"3106","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/Preload.tsx":"3107","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/TwoFactorAuthSetupCheck.tsx":"3108","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/UsernameCheck.tsx":"3109","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/index.ts":"3110","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/useCustomScript.ts":"3111","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/useIframeLogin.ts":"3112","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/useViewportScrolling.ts":"3113","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/PageLoading.tsx":"3114","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/PortalWrapper.ts":"3115","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/PortalsWrapper.tsx":"3116","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/hooks/useClearUnreadAllMessagesMutation.ts":"3117","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/hooks/useEscapeKeyStroke.ts":"3118","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/hooks/useGoogleTagManager.ts":"3119","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/hooks/useMessageLinkClicks.ts":"3120","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/SetupWizardPage.tsx":"3121","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/SetupWizardRoute.tsx":"3122","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/contexts/SetupWizardContext.tsx":"3123","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/hooks/useBodyPosition.ts":"3124","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/hooks/useParameters.ts":"3125","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/hooks/useRouteLock.ts":"3126","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/hooks/useStepRouting.ts":"3127","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/providers/SetupWizardProvider.tsx":"3128","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/steps/AdminInfoStep.tsx":"3129","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/steps/CloudAccountConfirmation.tsx":"3130","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/steps/OrganizationInfoStep.tsx":"3131","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/steps/RegisterServerStep.tsx":"3132","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ChannelDesertionTable/ChannelDesertionTable.tsx":"3133","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ChannelDesertionTable/ChannelDesertionTableRow.tsx":"3134","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ChannelDesertionTable/index.ts":"3135","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ConvertToChannelModal/BaseConvertToChannelModal.tsx":"3136","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx":"3137","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ConvertToChannelModal/ModalSteps/FirstStep.tsx":"3138","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ConvertToChannelModal/ModalSteps/SecondStep.tsx":"3139","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ConvertToChannelModal/index.ts":"3140","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/RoomLinkList.js":"3141","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/TeamAutocomplete/Avatar.js":"3142","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/TeamAutocomplete/TeamAutocomplete.js":"3143","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/TeamAutocomplete/index.ts":"3144","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx":"3145","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/RoomsInput.tsx":"3146","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/index.ts":"3147","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/BaseTeamsChannels.js":"3148","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/ConfirmationModal/ConfirmationModal.tsx":"3149","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/ConfirmationModal/index.ts":"3150","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/RoomActions.js":"3151","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/Row.js":"3152","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItem.js":"3153","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.js":"3154","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/hooks/useTeamsChannelList.ts":"3155","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/index.ts":"3156","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/tabBar.ts":"3157","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/ChannelDeletionTable.js":"3158","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/ChannelRow.js":"3159","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/DeleteTeamModal.js":"3160","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/DeleteTeamModal.stories.tsx":"3161","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/DeleteTeamModalWithRooms.tsx":"3162","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/StepOne.js":"3163","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/StepTwo.js":"3164","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/index.ts":"3165","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamModal/LeaveTeamModal.stories.tsx":"3166","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamModal/LeaveTeamModal.tsx":"3167","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamModal/LeaveTeamModalChannels.tsx":"3168","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamModal/LeaveTeamModalConfirmation.tsx":"3169","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx":"3170","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/index.ts":"3171","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.stories.tsx":"3172","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.tsx":"3173","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/TeamsInfoWithData.js":"3174","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/index.js":"3175","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/tabBar.ts":"3176","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/BaseRemoveUsersModal.js":"3177","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersFirstStep.js":"3178","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js":"3179","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersSecondStep.js":"3180","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/index.ts":"3181","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/index.ts":"3182","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/IRoomTypeConfig.ts":"3183","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/IRoutingManagerConfig.ts":"3184","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/express.d.ts":"3185","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/global.d.ts":"3186","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/ldap-escape.d.ts":"3187","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/less/browser.d.ts":"3188","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/less-plugin-autoprefixer.d.ts":"3189","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/accounts-base.d.ts":"3190","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/babel-compiler.d.ts":"3191","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/check.d.ts":"3192","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/ddp-common.d.ts":"3193","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/ddp-rate-limiter.d.ts":"3194","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/ejson.d.ts":"3195","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/facts-base.d.ts":"3196","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/htmljs.d.ts":"3197","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/jparker:gravatar.d.ts":"3198","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/kadira-flow-router.d.ts":"3199","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/konecty-user-presence.d.ts":"3200","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/littledata-synced-cron.d.ts":"3201","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/logging.d.ts":"3202","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/meteor.d.ts":"3203","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/meteorhacks-inject-initial.d.ts":"3204","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/mongo.d.ts":"3205","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/mystor-device-detection.d.ts":"3206","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/oauth.d.ts":"3207","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/oauth2server.d.ts":"3208","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/ostrio-cookies.d.ts":"3209","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/random.d.ts":"3210","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/rocketchat-streamer.d.ts":"3211","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/rocketchat-tap-i18n.d.ts":"3212","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/routepolicy.d.ts":"3213","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/session.d.ts":"3214","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/sha.d.ts":"3215","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/templating.d.ts":"3216","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/tracker.d.ts":"3217","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/url.d.ts":"3218","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/webapp-hashing.d.ts":"3219","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/mongodb.d.ts":"3220","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/rocket.chat/fuselage-tokens/colors.d.ts":"3221","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/service-configuration.d.ts":"3222","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/xml-encryption.d.ts":"3223","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/yaqrcode.d.ts":"3224","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/methods/federation.ts":"3225","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/methods/index.ts":"3226","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/methods/omnichannel.ts":"3227","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/api-enterprise/server/canned-responses.ts":"3228","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/api-enterprise/server/index.ts":"3229","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/api-enterprise/server/lib/canned-responses.js":"3230","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/authorization/client/index.ts":"3231","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/authorization/lib/addRoleRestrictions.js":"3232","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/authorization/lib/guestPermissions.js":"3233","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/authorization/server/index.ts":"3234","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/authorization/server/resetEnterprisePermissions.ts":"3235","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/authorization/server/validateUserRoles.js":"3236","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/client/collections/CannedResponse.ts":"3237","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/client/index.js":"3238","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/client/startup/responses.js":"3239","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/client/streamer.js":"3240","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/client/tabBar.ts":"3241","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/hooks/onMessageSentParsePlaceholder.ts":"3242","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/hooks/onRemoveAgentDepartment.ts":"3243","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/hooks/onSaveAgentDepartment.ts":"3244","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/index.js":"3245","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/methods/removeCannedResponse.js":"3246","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/methods/saveCannedResponse.js":"3247","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/permissions.ts":"3248","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/settings.ts":"3249","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/ecdh/Session.ts":"3250","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/ecdh/client/ClientSession.ts":"3251","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/ecdh/server/ServerSession.ts":"3252","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/RoomService.ts":"3253","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/input/RoomInputDto.ts":"3254","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/sender/AbstractFederationService.ts":"3255","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/sender/input/RoomSenderDto.ts":"3256","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/sender/room/DMRoomInternalHooksServiceSender.ts":"3257","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/sender/room/RoomInternalHooksServiceSender.ts":"3258","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/sender/room/RoomServiceSender.ts":"3259","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/domain/FederatedRoom.ts":"3260","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/domain/FederatedUser.ts":"3261","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/domain/IFederationBridge.ts":"3262","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/index.ts":"3263","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/Factory.ts":"3264","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/matrix/Bridge.ts":"3265","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/rocket-chat/adapters/Room.ts":"3266","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/rocket-chat/adapters/User.ts":"3267","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.ts":"3268","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/rocket-chat/hooks/index.ts":"3269","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/rocket-chat/slash-commands/action.ts":"3270","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/rocket-chat/slash-commands/index.ts":"3271","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/client/index.ts":"3272","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/definition/ILicense.ts":"3273","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/definition/ILicenseTag.ts":"3274","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/bundles.ts":"3275","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/decrypt.ts":"3276","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/getSeatsRequestLink.ts":"3277","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/getStatistics.ts":"3278","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/getTagColor.ts":"3279","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/index.ts":"3280","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/lib/isUnderAppLimits.ts":"3281","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/license.internalService.ts":"3282","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/license.ts":"3283","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/maxSeatsBanners.ts":"3284","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/methods.ts":"3285","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/settings.js":"3286","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/startup.js":"3287","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat/imports/server/rest/departments.js":"3288","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat/imports/server/rest/inquiries.js":"3289","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat/imports/server/rest/rooms.js":"3290","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat/imports/server/rest/sms.js":"3291","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat/imports/server/rest/upload.js":"3292","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat/index.js":"3293","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/SingleBusinessHour.ts":"3294","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/components/modals/PlaceChatOnHoldModal.tsx":"3295","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/index.js":"3296","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/messageTypes.ts":"3297","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/startup.ts":"3298","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/views/business-hours/Multiple.ts":"3299","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/views/livechatSideNavItems.js":"3300","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/lib/QuickActions/defaultActions.ts":"3301","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/lib/messageTypes.ts":"3302","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/agents.ts":"3303","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/business-hours.ts":"3304","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/departments.ts":"3305","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/index.ts":"3306","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/inquiries.ts":"3307","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/definition.ts":"3308","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/inquiries.ts":"3309","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/monitors.ts":"3310","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/priorities.ts":"3311","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/sla.ts":"3312","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/tags.ts":"3313","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/units.ts":"3314","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/monitors.ts":"3315","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/priorities.ts":"3316","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/rooms.ts":"3317","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/sla.ts":"3318","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/tags.ts":"3319","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/transcript.ts":"3320","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/units.ts":"3321","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/business-hour/Custom.ts":"3322","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/business-hour/Helper.ts":"3323","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/business-hour/Multiple.ts":"3324","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/business-hour/index.ts":"3325","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/business-hour/lib/business-hour.ts":"3326","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/addDepartmentAncestors.js":"3327","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterForwardChatToAgent.ts":"3328","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterForwardChatToDepartment.js":"3329","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterInquiryQueued.ts":"3330","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterOnHold.ts":"3331","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterOnHoldChatResumed.ts":"3332","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterRemoveDepartment.ts":"3333","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterReturnRoomAsInquiry.ts":"3334","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterTakeInquiry.js":"3335","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/applyDepartmentRestrictions.ts":"3336","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/applySimultaneousChatsRestrictions.ts":"3337","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/autoCloseQueued.ts":"3338","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeForwardRoomToDepartment.js":"3339","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeJoinRoom.ts":"3340","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeListTags.js":"3341","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeNewInquiry.ts":"3342","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeNewRoom.js":"3343","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.js":"3344","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/checkAgentBeforeTakeInquiry.ts":"3345","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/handleNextAgentPreferredEvents.js":"3346","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/index.ts":"3347","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onAgentAssignmentFailed.ts":"3348","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onBusinessHourStart.ts":"3349","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onCheckRoomParamsApi.js":"3350","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onCloseLivechat.js":"3351","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onLoadConfigApi.js":"3352","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onLoadForwardDepartmentRestrictions.js":"3353","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onSaveVisitorInfo.ts":"3354","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onTransferFailure.ts":"3355","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/resumeOnHold.js":"3356","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/scheduleAutoTransfer.ts":"3357","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/sendPdfTranscriptOnClose.ts":"3358","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/setPredictedVisitorAbandonmentTime.js":"3359","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/index.ts":"3360","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/AutoCloseOnHoldScheduler.ts":"3361","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/AutoTransferChatScheduler.ts":"3362","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/Department.js":"3363","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/Helper.js":"3364","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/LivechatEnterprise.js":"3365","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/QueueInactivityMonitor.ts":"3366","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/SlaHelper.ts":"3367","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/VisitorInactivityMonitor.ts":"3368","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/debounceByParams.ts":"3369","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/logger.ts":"3370","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/query.helper.js":"3371","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/routing/LoadBalancing.js":"3372","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/routing/LoadRotation.ts":"3373","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/runEndpointsAsUser.js":"3374","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/units.ts":"3375","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/addMonitor.js":"3376","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/getUnitsFromUserRoles.ts":"3377","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/removeBusinessHour.ts":"3378","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/removeMonitor.js":"3379","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/removeTag.js":"3380","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/removeUnit.js":"3381","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts":"3382","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/saveTag.js":"3383","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/saveUnit.js":"3384","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/permissions.ts":"3385","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/priorities.ts":"3386","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/settings.ts":"3387","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/startup.ts":"3388","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/message-read-receipt/server/hooks/afterReadMessages.ts":"3389","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/message-read-receipt/server/hooks/afterSaveMessage.ts":"3390","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/message-read-receipt/server/hooks/index.ts":"3391","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/message-read-receipt/server/index.ts":"3392","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/index.js":"3393","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/index.js":"3394","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/CannedResponse.js":"3395","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/LivechatDepartment.js":"3396","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/LivechatPriority.js":"3397","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/LivechatTag.js":"3398","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/LivechatUnit.js":"3399","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/LivechatUnitMonitors.js":"3400","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/Messages.js":"3401","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/Users.ts":"3402","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/raw/LivechatDepartmentAgents.ts":"3403","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/settings/server/index.js":"3404","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/settings/server/settings.internalService.ts":"3405","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/settings/server/settings.ts":"3406","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/teams-mention/server/EEMentionQueries.js":"3407","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/teams-mention/server/EESpotlight.js":"3408","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/teams-mention/server/index.ts":"3409","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/voip-enterprise/server/index.ts":"3410","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/voip-enterprise/server/lib/calculateOnHoldTimeForRoom.ts":"3411","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/voip-enterprise/server/services/voipService.ts":"3412","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/@types/IOrchestrator.ts":"3413","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/RealAppsEngineUIHost.js":"3414","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/communication/index.js":"3415","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/communication/websockets.js":"3416","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/gameCenter/GameCenter.tsx":"3417","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/gameCenter/GameCenterContainer.tsx":"3418","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx":"3419","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/gameCenter/GameCenterList.tsx":"3420","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/gameCenter/hooks/useExternalComponentsQuery.ts":"3421","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/gameCenter/tabBar.tsx":"3422","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/i18n.js":"3423","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/index.js":"3424","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/orchestrator.ts":"3425","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/components/deviceManagement/LoggedOutBanner.tsx":"3426","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/deviceManagement/components/DeviceIcon.tsx":"3427","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/deviceManagement/components/DeviceManagementTable/DeviceManagementTable.tsx":"3428","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/deviceManagement/components/DeviceManagementTable/index.ts":"3429","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/ecdh.ts":"3430","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useAgentsList.ts":"3431","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useDeviceLogout.tsx":"3432","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useDevicesMenuOption.tsx":"3433","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useHasLicenseModule.ts":"3434","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useOutboundDialer.ts":"3435","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useTagsList.ts":"3436","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useVoipClient.ts":"3437","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useVoipFooterMenu.tsx":"3438","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/index.ts":"3439","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/lib/fetchFeatures.ts":"3440","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/lib/onToggledFeature.ts":"3441","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/lib/voip/EEVoipClient.ts":"3442","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/lib/voip/parseOutboundPhoneNumber.ts":"3443","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/BusinessHoursRow.js":"3444","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/BusinessHoursTable.js":"3445","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/BusinessHoursTable.stories.tsx":"3446","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/BusinessHoursTableContainer.js":"3447","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/ContactManagerInfo.js":"3448","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/RemoveBusinessHourButton.js":"3449","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/BusinessHoursMultiple.js":"3450","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/BusinessHoursMultiple.stories.tsx":"3451","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/BusinessHoursMultipleContainer.js":"3452","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/BusinessHoursTimeZone.js":"3453","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/BusinessHoursTimeZone.stories.tsx":"3454","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/ContactManager.js":"3455","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/CustomFieldsAdditionalForm.js":"3456","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/CustomFieldsAdditionalFormContainer.js":"3457","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/DepartmentBusinessHours.js":"3458","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/DepartmentForwarding.tsx":"3459","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/EeNumberInput.js":"3460","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/EeTextAreaInput.js":"3461","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/EeTextInput.js":"3462","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/MaxChatsPerAgent.tsx":"3463","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/MaxChatsPerAgentContainer.js":"3464","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/MaxChatsPerAgentDisplay.js":"3465","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/PrioritiesSelect.tsx":"3466","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/SlaPoliciesSelect.tsx":"3467","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/register.ts":"3468","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEdit.tsx":"3469","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEditWithData.tsx":"3470","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEditWithDepartmentData.tsx":"3471","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseFilter.tsx":"3472","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseNew.tsx":"3473","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponsesPage.tsx":"3474","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponsesRoute.tsx":"3475","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/IOmnichannelCannedResponse.ts":"3476","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/RemoveCannedResponseButton.tsx":"3477","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/components/cannedResponseForm.tsx":"3478","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/MarkdownTextEditor/InsertPlaceholderDropdown.tsx":"3479","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/MarkdownTextEditor/MarkdownTextEditor.stories.tsx":"3480","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/MarkdownTextEditor/index.tsx":"3481","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/TextEditor/IconButton.tsx":"3482","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/TextEditor/TextButton.tsx":"3483","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/TextEditor/TextEditor.stories.tsx":"3484","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/TextEditor/Textarea.tsx":"3485","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/TextEditor/Toolbox.tsx":"3486","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/TextEditor/index.tsx":"3487","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/CreateCannedResponseModal.stories.tsx":"3488","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/CreateCannedResponseModal.tsx":"3489","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/PreviewText.tsx":"3490","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/SharingOptions.tsx":"3491","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/index.tsx":"3492","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/index.ts":"3493","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/CannedResponse.stories.tsx":"3494","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/CannedResponse.tsx":"3495","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/CannedResponseList.stories.tsx":"3496","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/CannedResponseList.tsx":"3497","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/Item.stories.tsx":"3498","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/Item.tsx":"3499","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/WrapCannedResponse.tsx":"3500","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/index.tsx":"3501","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/hooks/useCannedResponseFilterOptions.ts":"3502","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/hooks/useCannedResponseList.ts":"3503","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/hooks/useOmnichannelPriorities.ts":"3504","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/hooks/useOmnichannelPrioritiesMenu.tsx":"3505","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/hooks/useScopeDict.ts":"3506","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/index.js":"3507","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/monitors/MonitorsPage.js":"3508","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/monitors/MonitorsPageContainer.js":"3509","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/monitors/MonitorsRow.js":"3510","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/monitors/MonitorsTable.js":"3511","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PrioritiesPage.tsx":"3512","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PrioritiesResetModal.tsx":"3513","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PrioritiesRoute.tsx":"3514","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PrioritiesTable.tsx":"3515","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PriorityEditForm.tsx":"3516","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PriorityEditFormWithData.tsx":"3517","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PriorityIcon.tsx":"3518","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PriorityVerticalBar.tsx":"3519","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/routes.ts":"3520","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/slaPolicies/RemoveSlaButton.tsx":"3521","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/slaPolicies/SlaEdit.tsx":"3522","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/slaPolicies/SlaEditWithData.tsx":"3523","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/slaPolicies/SlaNew.tsx":"3524","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/slaPolicies/SlasPage.tsx":"3525","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/slaPolicies/SlasRoute.tsx":"3526","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/AutoCompleteTags.js":"3527","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/AutoCompleteTagsMultiple.js":"3528","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/CurrentChatTags.tsx":"3529","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/RemoveTagButton.js":"3530","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/TagEdit.js":"3531","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/TagEditWithData.js":"3532","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/TagEditWithDepartmentData.tsx":"3533","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/TagsPage.js":"3534","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/TagsRoute.js":"3535","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/units/RemoveUnitButton.js":"3536","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/units/UnitEdit.js":"3537","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/units/UnitEditWithData.tsx":"3538","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/units/UnitsPage.js":"3539","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/units/UnitsRoute.js":"3540","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/sidebar/footer/SidebarFooterWatermark.tsx":"3541","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/audit.tsx":"3542","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/deviceManagement.ts":"3543","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/engagementDashboard.ts":"3544","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/index.ts":"3545","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/readReceipt.ts":"3546","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/slashCommands/federation.ts":"3547","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/slashCommands/index.ts":"3548","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/account/deviceManagement/DeviceManagementAccountPage.tsx":"3549","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/account/deviceManagement/DeviceManagementAccountTable/DeviceManagementAccountRow.tsx":"3550","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/account/deviceManagement/DeviceManagementAccountTable/DeviceManagementAccountTable.tsx":"3551","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/account/deviceManagement/DeviceManagementAccountTable/index.ts":"3552","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementAdminPage.tsx":"3553","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementAdminRoute.tsx":"3554","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementAdminTable/DeviceManagementAdminRow.tsx":"3555","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementAdminTable/DeviceManagementAdminTable.tsx":"3556","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementAdminTable/index.ts":"3557","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementInfo/DeviceManagementInfo.tsx":"3558","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementInfo/DeviceManagementInfoWithData.tsx":"3559","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementInfo/index.ts":"3560","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardCard.tsx":"3561","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardCardErrorBoundary.tsx":"3562","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardCardFilter.tsx":"3563","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.stories.tsx":"3564","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx":"3565","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardRoute.tsx":"3566","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/channels/ChannelsOverview.tsx":"3567","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/channels/ChannelsTab.stories.tsx":"3568","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/channels/ChannelsTab.tsx":"3569","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/channels/useChannelsList.ts":"3570","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/DownloadDataButton.tsx":"3571","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/LegendSymbol.stories.tsx":"3572","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/LegendSymbol.tsx":"3573","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/PeriodSelector.tsx":"3574","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/colors.ts":"3575","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/periods.ts":"3576","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/usePeriodLabel.ts":"3577","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/usePeriodSelectorState.ts":"3578","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/MessagesPerChannelSection.tsx":"3579","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/MessagesSentSection.tsx":"3580","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/MessagesTab.stories.tsx":"3581","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/MessagesTab.tsx":"3582","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/useMessageOrigins.ts":"3583","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/useMessagesSent.ts":"3584","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/useTopFivePopularChannels.ts":"3585","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/ActiveUsersSection.tsx":"3586","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/BusiestChatTimesSection.tsx":"3587","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/ContentForDays.tsx":"3588","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/ContentForHours.tsx":"3589","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/NewUsersSection.tsx":"3590","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersByTimeOfTheDaySection.tsx":"3591","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersTab.stories.tsx":"3592","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersTab.tsx":"3593","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/useActiveUsers.ts":"3594","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/useHourlyChatActivity.ts":"3595","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/useNewUsers.ts":"3596","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/useUsersByTimeOfTheDay.ts":"3597","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/useWeeklyChatActivity.ts":"3598","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/info/SeatsCard.tsx":"3599","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/CloseToSeatsCapModal.tsx":"3600","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/ReachedSeatsCapModal.tsx":"3601","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/SeatsCapUsage/SeatsCapUsage.stories.tsx":"3602","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/SeatsCapUsage/SeatsCapUsage.tsx":"3603","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/SeatsCapUsage/index.ts":"3604","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/SeatsCapUsage/useUsageLabel.ts":"3605","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/UserPageHeaderContentWithSeatsCap.tsx":"3606","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/useRequestSeatsLink.ts":"3607","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/useSeatsCap.ts":"3608","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/AuditLogPage.tsx":"3609","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/AuditPage.tsx":"3610","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/AuditFiltersDisplay.tsx":"3611","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/AuditForm.tsx":"3612","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/AuditLogEntry.tsx":"3613","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/AuditLogTable.tsx":"3614","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/AuditMessageList.tsx":"3615","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/AuditResult.tsx":"3616","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/forms/DateRangePicker.tsx":"3617","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/forms/RoomAutoComplete.tsx":"3618","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/forms/UsernamesAutoComplete.tsx":"3619","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/forms/VisitorAutoComplete.tsx":"3620","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/tabs/DirectTab.tsx":"3621","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/tabs/OmnichannelTab.tsx":"3622","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/tabs/RoomsTab.tsx":"3623","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/tabs/UsersTab.tsx":"3624","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/hooks/useAuditForm.ts":"3625","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/hooks/useAuditMutation.ts":"3626","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/hooks/useAuditTab.ts":"3627","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/hooks/useSendTelemetryMutation.ts":"3628","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/utils/dateRange.ts":"3629","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/components/modals/WrapUpCallModal.tsx":"3630","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/DialInput.tsx":"3631","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/DialPadModal.stories.tsx":"3632","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/DialPadModal.tsx":"3633","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/Pad.tsx":"3634","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/PadButton.tsx":"3635","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/hooks/useDialPad.tsx":"3636","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/hooks/useEnterKey.tsx":"3637","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/hooks/useLongPress.tsx":"3638","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modals/DeviceSettingsModal.tsx":"3639","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/IAuditLog.ts":"3640","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/index.ts":"3641","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/methods/audit.ts":"3642","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/methods/index.ts":"3643","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/methods/license.ts":"3644","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/index.ts":"3645","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/chat.ts":"3646","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/engagementDashboard.ts":"3647","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/omnichannel/businessHours.ts":"3648","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/omnichannel/businessUnits.ts":"3649","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/omnichannel/cannedResponses.ts":"3650","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/omnichannel/index.ts":"3651","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/roles.ts":"3652","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/sessions/SessionsPaginateProps.ts":"3653","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/sessions/SessionsProps.ts":"3654","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/sessions/index.ts":"3655","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/sessions/sessions.ts":"3656","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/lib/misc/DeferredValue.ts":"3657","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/lib/misc/Utilities.js":"3658","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/lib/misc/determineFileType.js":"3659","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/lib/misc/formatAppInstanceForRest.ts":"3660","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/lib/misc/transformMappedData.js":"3661","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/NetworkBroker.ts":"3662","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/api.ts":"3663","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/chat.ts":"3664","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/engagementDashboard/channels.ts":"3665","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/engagementDashboard/index.ts":"3666","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/engagementDashboard/messages.ts":"3667","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/engagementDashboard/users.ts":"3668","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/federation/index.ts":"3669","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/federation/rooms.ts":"3670","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/index.ts":"3671","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/ldap.ts":"3672","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/licenses.ts":"3673","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/roles.ts":"3674","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/sessions.ts":"3675","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/appRequestsCron.ts":"3676","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/endpoints/actionButtonsHandler.ts":"3677","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/endpoints/appsCountHandler.ts":"3678","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/events.ts":"3679","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/index.ts":"3680","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/rest.js":"3681","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/uikit.ts":"3682","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/websockets.ts":"3683","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/cron.js":"3684","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/index.ts":"3685","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/marketplace/appInstall.ts":"3686","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/marketplace/appRequestNotifyUsers.ts":"3687","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/orchestrator.js":"3688","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/startup.ts":"3689","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/storage/AppFileSystemSourceStorage.ts":"3690","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/storage/AppGridFSSourceStorage.ts":"3691","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/storage/AppRealStorage.ts":"3692","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/storage/ConfigurableAppSourceStorage.ts":"3693","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/storage/index.js":"3694","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/storage/logs-storage.js":"3695","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/configuration/index.ts":"3696","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/configuration/ldap.ts":"3697","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/configuration/oauth.ts":"3698","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/configuration/saml.ts":"3699","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/configuration/videoConference.ts":"3700","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/index.ts":"3701","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/EnterpriseCheck.ts":"3702","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/audit/AuditLog.ts":"3703","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/audit/methods.ts":"3704","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/audit/startup.ts":"3705","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/constants.ts":"3706","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/deviceManagement/session.ts":"3707","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/deviceManagement/startup.ts":"3708","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/channels.ts":"3709","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/date.ts":"3710","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/messages.ts":"3711","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/startup.ts":"3712","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/users.ts":"3713","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/Manager.ts":"3714","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/copyCustomFieldsLDAP.spec.ts":"3715","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/copyCustomFieldsLDAP.ts":"3716","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/getNestedProp.spec.ts":"3717","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/getNestedProp.ts":"3718","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/replacesNestedValues.spec.ts":"3719","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/replacesNestedValues.ts":"3720","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/message-read-receipt/ReadReceipt.js":"3721","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/oauth/Manager.ts":"3722","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/registerServiceModels.ts":"3723","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/roles/insertRole.ts":"3724","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/roles/updateRole.ts":"3725","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/syncUserRoles.ts":"3726","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/local-services/instance/service.ts":"3727","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/local-services/ldap/service.ts":"3728","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/local-services/message-reads/service.ts":"3729","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/methods/getReadReceipts.js":"3730","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/CannedResponse.ts":"3731","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatDepartment.ts":"3732","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatInquiry.ts":"3733","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatPriority.ts":"3734","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatRooms.ts":"3735","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatTag.ts":"3736","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatUnit.ts":"3737","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatUnitMonitors.ts":"3738","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/OmnichannelServiceLevelAgreements.ts":"3739","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/ReadReceipts.ts":"3740","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/CannedResponse.ts":"3741","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatDepartment.ts":"3742","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatInquiry.ts":"3743","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatPriority.ts":"3744","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatRooms.ts":"3745","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatTag.ts":"3746","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatUnit.ts":"3747","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatUnitMonitors.ts":"3748","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/ReadReceipts.ts":"3749","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/ServiceLevelAgreements.ts":"3750","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/startup.ts":"3751","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/requestSeatsRoute.ts":"3752","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/sdk/index.ts":"3753","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/sdk/types/IInstanceService.ts":"3754","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/sdk/types/ILDAPEEService.ts":"3755","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/sdk/types/IMessageReadsService.ts":"3756","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/sdk/types/index.ts":"3757","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/services/ecdh-proxy/ECDHProxy.ts":"3758","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/services/ecdh-proxy/lib/server.ts":"3759","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/services/ecdh-proxy/service.ts":"3760","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/services/mongo.ts":"3761","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/settings/deviceManagement.ts":"3762","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/settings/index.ts":"3763","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/settings/ldap.ts":"3764","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/settings/saml.ts":"3765","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/settings/video-conference.ts":"3766","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/audit.ts":"3767","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/broker.ts":"3768","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/deviceManagement.ts":"3769","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/engagementDashboard.ts":"3770","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/index.ts":"3771","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/presence.ts":"3772","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/seatsCap.ts":"3773","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/services.ts":"3774","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/upsell.ts":"3775","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/application/DMRoomInternalHooksServiceSender.spec.ts":"3776","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/application/RoomInternalHooksServiceSender.spec.ts":"3777","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/application/RoomService.spec.ts":"3778","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/application/input/RoomInputDto.spec.ts":"3779","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.spec.ts":"3780","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/infrastructure/rocket-chat/hooks/hooks.spec.ts":"3781","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/infrastructure/rocket-chat/slash-commands/actions.spec.ts":"3782","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/imports/personal-access-tokens/server/api/methods/generateToken.js":"3783","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/imports/personal-access-tokens/server/api/methods/index.js":"3784","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/imports/personal-access-tokens/server/api/methods/regenerateToken.js":"3785","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/imports/personal-access-tokens/server/api/methods/removeToken.js":"3786","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/imports/personal-access-tokens/server/index.js":"3787","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/imports/startup/server/index.ts":"3788","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/ClientLogger.ts":"3789","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/callbacks.ts":"3790","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/createQuoteAttachment.ts":"3791","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/emailValidator.ts":"3792","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/getImageExtensionFromMime.ts":"3793","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/getMessageUrlRegex.ts":"3794","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/getUserEmailAddress.ts":"3795","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/isTruthy.ts":"3796","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/oauthRedirectUri.ts":"3797","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/random.ts":"3798","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/roles/getMostImportantRole.ts":"3799","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/roles/isValidRoleScope.ts":"3800","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/adminFields.ts":"3801","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/coordinator.ts":"3802","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/conversation.ts":"3803","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/direct.ts":"3804","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/discussion.ts":"3805","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/favorite.ts":"3806","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/livechat.ts":"3807","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/private.ts":"3808","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/public.ts":"3809","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/unread.ts":"3810","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/voip.ts":"3811","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/transforms.ts":"3812","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/typedJSONParse.ts":"3813","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/upgradeTab.ts":"3814","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/addMinutesToADate.ts":"3815","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/arrayUtils.ts":"3816","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/comparisons.ts":"3817","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/getFileExtension.ts":"3818","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/highOrderFunctions.ts":"3819","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/isJSON.ts":"3820","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/isRelativeURL.ts":"3821","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/isURL.ts":"3822","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/omit.ts":"3823","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/parseCSV.ts":"3824","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/parseParameters.ts":"3825","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/promisify.ts":"3826","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/safeHtmlDots.ts":"3827","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/secondsToHHMMSS.ts":"3828","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/stringUtils.ts":"3829","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/videoConference/constants.ts":"3830","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/accounts-linkedin/linkedin.js":"3831","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/accounts-linkedin/notice.js":"3832","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/accounts-linkedin/package.js":"3833","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/linkedin-oauth/linkedin-client.js":"3834","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/linkedin-oauth/linkedin-server.js":"3835","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/linkedin-oauth/package.js":"3836","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/package.js":"3837","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-config.js":"3838","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-filter.js":"3839","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-methods.js":"3840","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-mime.js":"3841","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-server.js":"3842","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-store-permissions.js":"3843","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-store.js":"3844","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-tokens.js":"3845","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-uploader.js":"3846","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs.js":"3847","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-ddp/client/index.js":"3848","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-ddp/package.js":"3849","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-i18n/package.js":"3850","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-livechat/package.js":"3851","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-livechat/plugin/build-livechat.js":"3852","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-mongo-config/package.js":"3853","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-mongo-config/server/index.js":"3854","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-postcss/build.js":"3855","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-postcss/package.js":"3856","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-version/package.js":"3857","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-version/plugin/compile-version.js":"3858","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/playwright-federation.config.ts":"3859","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/playwright.config.ts":"3860","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/configuration/accounts_meld.js":"3861","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/configuration/ldap.ts":"3862","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/cron/federation.ts":"3863","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/cron/nps.js":"3864","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/cron/oembed.js":"3865","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/cron/statistics.js":"3866","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/cron/userDataDownloads.ts":"3867","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/cron/videoConferences.ts":"3868","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/DatabaseWatcher.ts":"3869","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/convertChangeStreamPayload.ts":"3870","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/convertOplogPayload.ts":"3871","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/readSecondaryPreferred.ts":"3872","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/trash.ts":"3873","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/utils.ts":"3874","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/watchCollections.ts":"3875","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/email/IMAPInterceptor.ts":"3876","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/features/EmailInbox/EmailInbox.ts":"3877","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/features/EmailInbox/EmailInbox_Incoming.ts":"3878","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/features/EmailInbox/EmailInbox_Outgoing.ts":"3879","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/features/EmailInbox/index.ts":"3880","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/features/EmailInbox/logger.ts":"3881","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/hooks/index.ts":"3882","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/hooks/messages/markdownParser.ts":"3883","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/hooks/sauMonitorHooks.ts":"3884","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/importPackages.ts":"3885","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/compareUserPassword.ts":"3886","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/compareUserPasswordHistory.ts":"3887","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/copyFileUpload.ts":"3888","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts":"3889","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/getPath.ts":"3890","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/getRoomData.ts":"3891","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/index.ts":"3892","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/makeZipFile.ts":"3893","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/processDataDownloads.ts":"3894","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/sendEmail.ts":"3895","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/sendFile.ts":"3896","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/sendViaEmail.ts":"3897","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/uploadZipFile.ts":"3898","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/fileUtils.ts":"3899","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/findUsersOfRoom.ts":"3900","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/getClientAddress.ts":"3901","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/getMomentLocale.ts":"3902","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/http/call.ts":"3903","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/http/fetch.ts":"3904","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/isPresenceMonitorEnabled.ts":"3905","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/isRunningMs.ts":"3906","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/isUserIdFederated.ts":"3907","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/ldap/Connection.ts":"3908","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/ldap/DataConverter.ts":"3909","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/ldap/Logger.ts":"3910","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/ldap/Manager.ts":"3911","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/ldap/getLDAPConditionalSetting.ts":"3912","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/Logger.ts":"3913","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/getPino.ts":"3914","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/logLevel.ts":"3915","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/logPayloads.ts":"3916","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/logQueue.ts":"3917","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/showBox.ts":"3918","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/startup.ts":"3919","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/system.ts":"3920","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/messages/getMessageForUser.ts":"3921","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/migrations.ts":"3922","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/pushConfig.ts":"3923","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/readMessages.ts":"3924","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/resetUserE2EKey.ts":"3925","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/roles/addUserRoles.ts":"3926","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/roles/createOrUpdateProtectedRole.ts":"3927","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/roles/getRoomRoles.ts":"3928","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/roles/removeUserFromRoles.ts":"3929","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/roles/validateRoleList.ts":"3930","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomCoordinator.ts":"3931","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/conversation.ts":"3932","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/direct.ts":"3933","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/favorite.ts":"3934","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/index.ts":"3935","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/livechat.ts":"3936","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/private.ts":"3937","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/public.ts":"3938","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/unread.ts":"3939","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/voip.ts":"3940","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/sendDirectMessageToUsers.ts":"3941","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/sendMessagesToAdmins.ts":"3942","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/settingsRegenerator.ts":"3943","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/spotlight.js":"3944","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/statistics/getSettingsStatistics.ts":"3945","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/videoConfProviders.ts":"3946","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/videoConfTypes.ts":"3947","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/main.ts":"3948","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/OEmbedCacheCleanup.js":"3949","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/addAllUserToRoom.js":"3950","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/addRoomLeader.js":"3951","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/addRoomModerator.js":"3952","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/addRoomOwner.js":"3953","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/afterVerifyEmail.ts":"3954","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/browseChannels.js":"3955","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/canAccessRoom.js":"3956","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/channelsList.js":"3957","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/createDirectMessage.js":"3958","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/deleteFileMessage.js":"3959","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/deleteUser.js":"3960","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/eraseRoom.ts":"3961","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getAvatarSuggestion.ts":"3962","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getPasswordPolicy.js":"3963","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getRoomById.js":"3964","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getRoomIdByNameOrId.js":"3965","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getRoomNameById.js":"3966","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getSetupWizardParameters.ts":"3967","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getTotalChannels.js":"3968","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getUsersOfRoom.js":"3969","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/hideRoom.js":"3970","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/ignoreUser.js":"3971","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/loadHistory.js":"3972","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/loadLocale.js":"3973","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/loadMissedMessages.js":"3974","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/loadNextMessages.js":"3975","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/loadSurroundingMessages.js":"3976","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/logoutCleanUp.js":"3977","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/messageSearch.js":"3978","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/muteUserInRoom.js":"3979","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/openRoom.js":"3980","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/readMessages.js":"3981","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/readThreads.js":"3982","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/registerUser.js":"3983","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/removeRoomLeader.js":"3984","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/removeRoomModerator.js":"3985","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/removeRoomOwner.ts":"3986","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/removeUserFromRoom.ts":"3987","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/reportMessage.js":"3988","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/requestDataDownload.ts":"3989","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/resetAvatar.js":"3990","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/roomNameExists.ts":"3991","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/saveUserPreferences.js":"3992","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/saveUserProfile.js":"3993","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/sendConfirmationEmail.ts":"3994","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/sendForgotPasswordEmail.js":"3995","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/setAvatarFromService.js":"3996","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/setUserActiveStatus.js":"3997","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/setUserPassword.js":"3998","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/toogleFavorite.js":"3999","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/unmuteUserInRoom.js":"4000","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/userPresence.ts":"4001","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/userSetUtcOffset.js":"4002","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Analytics.ts":"4003","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Avatars.ts":"4004","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Banners.ts":"4005","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/BannersDismiss.ts":"4006","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/CredentialTokens.ts":"4007","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/CustomSounds.ts":"4008","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/CustomUserStatus.ts":"4009","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/EmailInbox.ts":"4010","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/EmailMessageHistory.ts":"4011","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/EmojiCustom.ts":"4012","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/ExportOperations.ts":"4013","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/FederationKeys.ts":"4014","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/FederationServers.ts":"4015","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/ImportData.ts":"4016","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/InstanceStatus.ts":"4017","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/IntegrationHistory.ts":"4018","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Integrations.ts":"4019","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Invites.ts":"4020","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatAgentActivity.ts":"4021","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatBusinessHours.ts":"4022","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatCustomField.ts":"4023","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatDepartment.ts":"4024","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatDepartmentAgents.ts":"4025","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatInquiry.ts":"4026","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatRooms.ts":"4027","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatTrigger.ts":"4028","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatVisitors.ts":"4029","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LoginServiceConfiguration.ts":"4030","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/MatrixBridgedRoom.ts":"4031","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/MatrixBridgedUser.ts":"4032","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/MessageReads.ts":"4033","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Messages.ts":"4034","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/NotificationQueue.ts":"4035","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Nps.ts":"4036","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/NpsVote.ts":"4037","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/OAuthApps.ts":"4038","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/OEmbedCache.ts":"4039","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/PbxEvents.ts":"4040","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Permissions.ts":"4041","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/PushToken.ts":"4042","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Reports.ts":"4043","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Roles.ts":"4044","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Rooms.ts":"4045","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/ServerEvents.ts":"4046","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Sessions.ts":"4047","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Settings.ts":"4048","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/SmarshHistory.ts":"4049","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Statistics.ts":"4050","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Subscriptions.ts":"4051","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Team.ts":"4052","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/TeamMember.ts":"4053","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Uploads.ts":"4054","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/UserDataFiles.ts":"4055","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Users.ts":"4056","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/UsersSessions.ts":"4057","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/VideoConference.ts":"4058","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/VoipRoom.ts":"4059","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/WebdavAccounts.ts":"4060","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Analytics.ts":"4061","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Avatars.ts":"4062","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Banners.ts":"4063","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/BannersDismiss.ts":"4064","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/BaseRaw.ts":"4065","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/CredentialTokens.ts":"4066","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/CustomSounds.ts":"4067","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/CustomUserStatus.ts":"4068","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/EmailInbox.ts":"4069","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/EmailMessageHistory.ts":"4070","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/EmojiCustom.ts":"4071","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/ExportOperations.ts":"4072","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/FederationKeys.ts":"4073","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/FederationServers.ts":"4074","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/ImportData.ts":"4075","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/InstanceStatus.ts":"4076","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/IntegrationHistory.ts":"4077","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Integrations.ts":"4078","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Invites.ts":"4079","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatAgentActivity.ts":"4080","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatBusinessHours.ts":"4081","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatCustomField.ts":"4082","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatDepartment.ts":"4083","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatDepartmentAgents.ts":"4084","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatInquiry.ts":"4085","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatRooms.js":"4086","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatTrigger.ts":"4087","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatVisitors.ts":"4088","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LoginServiceConfiguration.ts":"4089","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/MatrixBridgedRoom.ts":"4090","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/MatrixBridgedUser.ts":"4091","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/MessageReads.ts":"4092","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Messages.ts":"4093","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/NotificationQueue.ts":"4094","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Nps.ts":"4095","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/NpsVote.ts":"4096","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/OAuthApps.ts":"4097","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/OEmbedCache.ts":"4098","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/PbxEvents.ts":"4099","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Permissions.ts":"4100","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/PushToken.ts":"4101","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Reports.ts":"4102","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Roles.ts":"4103","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Rooms.js":"4104","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/ServerEvents.ts":"4105","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Sessions.ts":"4106","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Settings.ts":"4107","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/SmarshHistory.ts":"4108","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Statistics.ts":"4109","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Subscriptions.ts":"4110","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Team.ts":"4111","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/TeamMember.ts":"4112","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Uploads.ts":"4113","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/UserDataFiles.ts":"4114","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Users.js":"4115","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/UsersSessions.ts":"4116","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/VideoConference.ts":"4117","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/VoipRoom.ts":"4118","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/WebdavAccounts.ts":"4119","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/startup.ts":"4120","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/core-apps/banner.module.ts":"4121","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/core-apps/nps/createModal.ts":"4122","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/core-apps/nps.module.ts":"4123","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/core-apps/videoconf.module.ts":"4124","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/listeners/listeners.module.ts":"4125","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/notifications/notifications.module.ts":"4126","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/streamer/streamer.module.ts":"4127","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/watchers/publishFields.ts":"4128","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/watchers/watchers.module.ts":"4129","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/overrides/http.ts":"4130","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/publications/messages.js":"4131","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/publications/room/index.js":"4132","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/publications/settings/index.ts":"4133","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/publications/spotlight.js":"4134","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/publications/subscription/index.js":"4135","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/index.js":"4136","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/middlewares/auth.js":"4137","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/middlewares/browserVersion.js":"4138","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/middlewares/index.js":"4139","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/room.js":"4140","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/user.js":"4141","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/utils.js":"4142","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/health.ts":"4143","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/i18n.ts":"4144","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/timesync.ts":"4145","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/userDataDownload.ts":"4146","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/analytics/service.ts":"4147","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/apps-engine/service.ts":"4148","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/authorization/canAccessRoom.ts":"4149","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/authorization/canAccessRoomLivechat.ts":"4150","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/authorization/canAccessRoomVoip.ts":"4151","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/authorization/service.ts":"4152","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/banner/service.ts":"4153","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/device-management/events.ts":"4154","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/device-management/service.ts":"4155","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/federation/service.ts":"4156","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/image/service.ts":"4157","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/ldap/service.ts":"4158","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/messages/service.ts":"4159","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/meteor/service.ts":"4160","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/nps/getAndCreateNpsSurvey.ts":"4161","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/nps/notification.ts":"4162","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/nps/sendNpsResults.ts":"4163","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/nps/service.ts":"4164","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/omnichannel/service.ts":"4165","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/omnichannel-voip/internalTypes.ts":"4166","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/omnichannel-voip/service.ts":"4167","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/push/service.ts":"4168","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/room/service.ts":"4169","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/sauMonitor/events.ts":"4170","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/sauMonitor/service.ts":"4171","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/settings/service.ts":"4172","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/startup.ts":"4173","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/team/service.ts":"4174","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/translation/service.ts":"4175","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/uikit-core-app/service.ts":"4176","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/upload/service.ts":"4177","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/user/lib/getNewUserRoles.ts":"4178","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/video-conference/service.ts":"4179","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/Command.ts":"4180","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/CommandHandler.ts":"4181","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/Commands.ts":"4182","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ICallbackContext.ts":"4183","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/IConnection.ts":"4184","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ami/ACDQueue.ts":"4185","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ami/AMIConnection.ts":"4186","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ami/CallbackContext.ts":"4187","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ami/CommandFactory.ts":"4188","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ami/ContinuousMonitor.ts":"4189","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ami/PJSIPEndpoint.ts":"4190","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/websocket/WebsocketConnection.ts":"4191","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/lib/Helper.ts":"4192","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/service.ts":"4193","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/settings/index.ts":"4194","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/settings/ldap.ts":"4195","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/settings/userDataDownload.ts":"4196","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/settings/video-conference.ts":"4197","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/appcache.js":"4198","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/callbacks.ts":"4199","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/coreApps.ts":"4200","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/cron.js":"4201","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/index.ts":"4202","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/initialData.js":"4203","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/localServices.ts":"4204","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/index.ts":"4205","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/minimumVersion.ts":"4206","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v266.ts":"4207","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v267.ts":"4208","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v268.ts":"4209","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v269.ts":"4210","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v270.ts":"4211","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v271.ts":"4212","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v272.ts":"4213","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v273.ts":"4214","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v274.ts":"4215","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v275.ts":"4216","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v276.ts":"4217","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v277.ts":"4218","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v278.ts":"4219","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v279.ts":"4220","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v280.ts":"4221","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v281.ts":"4222","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v282.ts":"4223","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v283.ts":"4224","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v284.ts":"4225","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v285.ts":"4226","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v286.ts":"4227","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v287.ts":"4228","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v288.ts":"4229","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v289.ts":"4230","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v290.ts":"4231","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v291.ts":"4232","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v292.ts":"4233","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/xrun.js":"4234","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/presenceTroubleshoot.ts":"4235","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/serverRunning.js":"4236","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/watchDb.ts":"4237","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/stream/stdout.ts":"4238","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/administration-menu.spec.ts":"4239","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/administration.spec.ts":"4240","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/anonymous-user.spec.ts":"4241","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/apps.spec.ts":"4242","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/channel-management.spec.ts":"4243","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/config/constants.ts":"4244","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/config/global-setup.ts":"4245","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/config/global.d.ts":"4246","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/create-channel.spec.ts":"4247","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/create-direct.spec.ts":"4248","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/create-discussion.spec.ts":"4249","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/e2e-encryption.spec.ts":"4250","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/email-inboxes.spec.ts":"4251","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/emojis.spec.ts":"4252","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/engagement-dashboard.spec.ts":"4253","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/config/constants.ts":"4254","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/config/global-setup.ts":"4255","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/account-profile.ts":"4256","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/admin.ts":"4257","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/channel.ts":"4258","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/account-sidenav.ts":"4259","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/admin-flextab-users.ts":"4260","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/admin-flextab.ts":"4261","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-content.ts":"4262","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-flextab-channels.ts":"4263","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-flextab-dm-member.ts":"4264","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-flextab-members.ts":"4265","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-flextab-notificationPreferences.ts":"4266","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-flextab-room.ts":"4267","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-flextab.ts":"4268","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-sidenav.ts":"4269","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/admin/rooms.spec.ts":"4270","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/admin/users.spec.ts":"4271","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/ce-version/ce.spec.ts":"4272","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/channel/dm.spec.ts":"4273","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/channel/private.spec.ts":"4274","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/channel/public.spec.ts":"4275","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts":"4276","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts":"4277","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts":"4278","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/user-account/user.spec.ts":"4279","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/utils/auth.ts":"4280","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/utils/channel.ts":"4281","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/utils/format.ts":"4282","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/utils/register-user.ts":"4283","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/utils/test.ts":"4284","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/file-upload.spec.ts":"4285","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/fixtures/collections/users.ts":"4286","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/fixtures/createAuxContext.ts":"4287","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/fixtures/inject-initial-data.ts":"4288","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/fixtures/insert-apps.ts":"4289","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/fixtures/userStates.ts":"4290","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/forgot-password.spec.ts":"4291","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/homepage.spec.ts":"4292","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/imports.spec.ts":"4293","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/login.spec.ts":"4294","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/message-actions.spec.ts":"4295","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/message-mentions.spec.ts":"4296","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/messaging.spec.ts":"4297","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-agents.spec.ts":"4298","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-auto-onhold-chat-closing.spec.ts":"4299","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-auto-transfer-unanswered-chat.spec.ts":"4300","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-canned-responses-sidebar.spec.ts":"4301","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-changing-room-priority-and-sla.spec.ts":"4302","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-chat-history.spec.ts":"4303","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-close-chat.spec.ts":"4304","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-contact-center.spec.ts":"4305","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-contact-info.spec.ts":"4306","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-currentChats.spec.ts":"4307","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-custom-fields.spec.ts":"4308","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-departaments-ce.spec.ts":"4309","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-departaments.spec.ts":"4310","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-livechat.spec.ts":"4311","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-manager.spec.ts":"4312","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-priorities.spec.ts":"4313","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-send-transcript.spec.ts":"4314","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-sla-policies.spec.ts":"4315","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-takeChat.spec.ts":"4316","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-transfer-to-another-agents.spec.ts":"4317","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-triggers.spec.ts":"4318","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/account-profile.ts":"4319","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/admin-email-inboxes.ts":"4320","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/admin.ts":"4321","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/auth.ts":"4322","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/account-sidenav.ts":"4323","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-users.ts":"4324","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/admin-flextab.ts":"4325","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts":"4326","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-channels.ts":"4327","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-members.ts":"4328","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-notificationPreferences.ts":"4329","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-room.ts":"4330","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts":"4331","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-omnichannel-content.ts":"4332","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts":"4333","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/index.ts":"4334","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/omnichannel-close-chat-modal.ts":"4335","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/omnichannel-sidenav.ts":"4336","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/home-channel.ts":"4337","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/home-discussion.ts":"4338","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/home-omnichannel.ts":"4339","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/home-team.ts":"4340","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/index.ts":"4341","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-agents.ts":"4342","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-contacts-list.ts":"4343","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-current-chats.ts":"4344","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-custom-fields.ts":"4345","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-departments.ts":"4346","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-info.ts":"4347","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts":"4348","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-manage-contact.ts":"4349","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-manager.ts":"4350","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-priorities.ts":"4351","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-section.ts":"4352","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-sla-policies.ts":"4353","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-triggers.ts":"4354","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/utils.ts":"4355","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/permissions.spec.ts":"4356","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/register.spec.ts":"4357","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/settings-account-profile.spec.ts":"4358","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/settings-assets.spec.ts":"4359","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/system-messages.spec.ts":"4360","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/team-management.spec.ts":"4361","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/thread-actions.spec.ts":"4362","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/user-invitations.spec.ts":"4363","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/utils/create-target-channel.ts":"4364","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/utils/index.ts":"4365","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/utils/omnichannel/priority.ts":"4366","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/utils/omnichannel/sla.ts":"4367","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/utils/setSettingValueById.ts":"4368","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/utils/test.ts":"4369","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/video-conference-ring.spec.ts":"4370","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/video-conference.spec.ts":"4371","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/00-autotranslate.js":"4372","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/00-miscellaneous.js":"4373","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/01-users.js":"4374","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/02-channels.js":"4375","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/03-groups.js":"4376","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/04-direct-message.js":"4377","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/05-chat.js":"4378","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/06-outgoing-integrations.js":"4379","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/07-incoming-integrations.js":"4380","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/08-settings.js":"4381","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/09-rooms.js":"4382","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/10-subscriptions.js":"4383","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/11-permissions.js":"4384","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/12-emoji-custom.js":"4385","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/14-assets.js":"4386","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/16-commands.js":"4387","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/17-custom-sounds.js":"4388","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/17-custom-user-status.js":"4389","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/17-webdav.js":"4390","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/18-oauthapps.js":"4391","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/19-statistics.js":"4392","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/20-licenses.js":"4393","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/21-banners.js":"4394","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/22-push-token.js":"4395","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/23-invites.js":"4396","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/24-methods.js":"4397","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/25-teams.js":"4398","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/26-LDAP.ts":"4399","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/27-presence.ts":"4400","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/27-roles.ts":"4401","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/import.spec.ts":"4402","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts":"4403","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/01-agents.ts":"4404","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/02-appearance.ts":"4405","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/03-custom-fields.ts":"4406","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/04-dashboards.ts":"4407","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts":"4408","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/06-integrations.ts":"4409","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts":"4410","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/08-triggers.ts":"4411","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts":"4412","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/10-departments.ts":"4413","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/11-email-inbox.ts":"4414","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts":"4415","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/12-mailer.ts":"4416","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/12-priorites.ts":"4417","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/13-tags.ts":"4418","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/14-units.ts":"4419","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/15-canned-responses.ts":"4420","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/16-video-call.ts":"4421","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/17-dashboards-ee.ts":"4422","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/18-rooms-ee.ts":"4423","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts":"4424","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/methods/changeLivechatStatus.ts":"4425","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/00-installation.js":"4426","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/01-send-messages.js":"4427","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/02-send-messages-as-user.js":"4428","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/03-slash-command-test-simple.js":"4429","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/04-slash-command-test-with-arguments.js":"4430","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/05-video-conferences.ts":"4431","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/apps-uninstall.js":"4432","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/teardown.js":"4433","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/client/FakeChatProvider.tsx":"4434","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/client/FakeRoomProvider.tsx":"4435","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/client/ModalContextMock.tsx":"4436","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/client/RouterContextMock.tsx":"4437","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/client/blobUrls.ts":"4438","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/client/jsdom.ts":"4439","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/data.ts":"4440","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/server/mongodb.ts":"4441","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/setup/chaiPlugins.ts":"4442","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/setup/cleanupTestingLibrary.ts":"4443","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/setup/hoistedReact.ts":"4444","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/setup/registerWebApiMocks.ts":"4445","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/api/server/v1/lib/checkPermissions.spec.ts":"4446","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/api/server/v1/lib/checkPermissionsForInvocation.spec.ts":"4447","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/api/server/v1/lib/isValidQuery.spec.ts":"4448","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/messages.tests.js":"4449","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/mocks/models/BaseModel.mock.js":"4450","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/mocks/models/Messages.mock.js":"4451","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/mocks/models/Rooms.mock.js":"4452","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/mocks/models/Users.mock.js":"4453","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/mocks/models/index.js":"4454","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/mocks/orchestrator.mock.js":"4455","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/custom-oauth/server/transform_helpers.tests.js":"4456","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/Federation.spec.ts":"4457","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/MessageServiceListener.spec.ts":"4458","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/RoomServiceListener.spec.ts":"4459","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/UserServiceListener.spec.ts":"4460","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/sender/MessageSenders.spec.ts":"4461","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/sender/MessageServiceSender.spec.ts":"4462","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/sender/RoomInternalHooksValidator.spec.ts":"4463","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/sender/RoomServiceSender.spec.ts":"4464","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/sender/UserServiceSender.spec.ts":"4465","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/domain/FederatedRoom.spec.ts":"4466","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/domain/FederatedUser.spec.ts":"4467","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/Bridge.spec.ts":"4468","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/converters/MatrixTextParser.spec.ts":"4469","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/converters/RoomReceiver.spec.ts":"4470","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/converters/UserReceiver.spec.ts":"4471","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/handlers/BaseEvent.spec.ts":"4472","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/handlers/MatrixEventsHandler.spec.ts":"4473","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/handlers/Room.spec.ts":"4474","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/queue/InMemoryQueue.spec.ts":"4475","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/rocket-chat/converters/RocketTextParser.spec.ts":"4476","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/rocket-chat/converters/RoomSender.spec.ts":"4477","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/rocket-chat/hooks/hooks.spec.ts":"4478","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/rocket-chat/slash-commands/actions.spec.ts":"4479","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/rocket-chat/statistics.spec.ts":"4480","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/highlight-words/helper.tests.js":"4481","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/lib/server.tests.js":"4482","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/mailer/api.spec.ts":"4483","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/markdown/client.mocks.js":"4484","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/markdown/client.tests.js":"4485","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/mentions/client.tests.js":"4486","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/mentions/server.tests.js":"4487","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/meteor-accounts-saml/data.ts":"4488","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/meteor-accounts-saml/server.tests.ts":"4489","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/models/server/raw/Sessions.tests.js":"4490","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/settings/server/functions/getSettingDefaults.tests.ts":"4491","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/settings/server/functions/overrideGenerator.tests.ts":"4492","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/settings/server/functions/settings.tests.ts":"4493","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/settings/server/functions/validateSettings.tests.ts":"4494","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/statistics/server/lib/UAParserCustom.tests.js":"4495","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/ui-utils/client.tests.ts":"4496","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/ui-utils/server.tests.js":"4497","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/utils/lib/getURL.tests.js":"4498","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/components/Omnichannel/modals/TranscriptModal.spec.tsx":"4499","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/lib/download.spec.ts":"4500","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/lib/federation/Federation.spec.ts":"4501","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/lib/minimongo/bson.spec.ts":"4502","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/lib/minimongo/comparisons.spec.ts":"4503","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/lib/minimongo/lookups.spec.ts":"4504","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/lib/utils/isRTLScriptLanguage.spec.ts":"4505","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/providers/CallProvider/lib/parseStringToIceServers.spec.ts":"4506","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/siderbar/header/actions/Administration.spec.tsx":"4507","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByCategories.test.ts":"4508","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByFree.test.ts":"4509","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByPaid.test.ts":"4510","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByText.test.ts":"4511","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/admin/apps/helpers/sortAppsByAlphabeticalOrInverseOrder.test.ts":"4512","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/admin/apps/helpers/sortAppsByClosestOrFarthestModificationDate.test.ts":"4513","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/notFound/NotFoundPage.spec.tsx":"4514","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/Message.spec.tsx":"4515","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/hooks/useKatex.spec.ts":"4516","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/autoTranslate.spec.ts":"4517","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/buildImageURL.spec.ts":"4518","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/isMessageFirstUnread.spec.ts":"4519","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/isMessageNewDay.spec.ts":"4520","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/isMessageSequential.spec.ts":"4521","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/isOwnUserMessage.spec.ts":"4522","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/isParsedMessage.spec.ts":"4523","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/isValidLink.spec.ts":"4524","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessage.spec.ts":"4525","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessageAttachments.spec.ts":"4526","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessageQuoteAttachment.spec.ts":"4527","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/federation/FederationAddServerProps.spec.ts":"4528","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/federation/FederationJoinExternalPublicRoomProps.spec.ts":"4529","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/federation/FederationPublicRoomsProps.spec.ts":"4530","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/federation/FederationRemoveServerProps.spec.ts":"4531","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsAddMembersProps.spec.ts":"4532","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsConvertToChannelProps.spec.ts":"4533","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsDeleteProps.spec.ts":"4534","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsLeaveProps.spec.ts":"4535","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsRemoveMemberProps.spec.ts":"4536","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsRemoveRoomProps.spec.ts":"4537","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsUpdateMemberProps.spec.ts":"4538","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsUpdateProps.spec.ts":"4539","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/video-conference/VideoConfCancelProps.spec.ts":"4540","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/video-conference/VideoConfInfoProps.spec.ts":"4541","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/video-conference/VideoConfJoinProps.spec.ts":"4542","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/video-conference/VideoConfListProps.spec.ts":"4543","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/video-conference/VideoConfStartProps.spec.ts":"4544","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/mimeTypes.tests.ts":"4545","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/roles/getMostImportantRole.tests.ts":"4546","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/upgradeTab.spec.ts":"4547","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/arrayUtils.tests.ts":"4548","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/isRelativeURL.spec.ts":"4549","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/isURL.spec.ts":"4550","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/parseCSV.tests.ts":"4551","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/parseParameters.tests.ts":"4552","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/secondsToHHMMSS.spec.ts":"4553","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/stringUtils.tests.ts":"4554","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/server/lib/fileUtils.tests.ts":"4555","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/server/sdk/errors.tests.ts":"4556"},{"size":368,"mtime":1678221097010,"results":"4557","hashOfConfig":"4558"},{"size":858,"mtime":1678221097011,"results":"4559","hashOfConfig":"4558"},{"size":576,"mtime":1675188401362,"results":"4560","hashOfConfig":"4558"},{"size":786,"mtime":1675188401362,"results":"4561","hashOfConfig":"4558"},{"size":2647,"mtime":1675188401362,"results":"4562","hashOfConfig":"4558"},{"size":785,"mtime":1675188401362,"results":"4563","hashOfConfig":"4558"},{"size":1679,"mtime":1675188401362,"results":"4564","hashOfConfig":"4558"},{"size":1937,"mtime":1675188401363,"results":"4565","hashOfConfig":"4558"},{"size":1233,"mtime":1675188401363,"results":"4566","hashOfConfig":"4558"},{"size":273,"mtime":1675188401363,"results":"4567","hashOfConfig":"4558"},{"size":467,"mtime":1678221097011,"results":"4568","hashOfConfig":"4569"},{"size":1958,"mtime":1678221097011,"results":"4570","hashOfConfig":"4569"},{"size":43,"mtime":1675188401363,"results":"4571","hashOfConfig":"4569"},{"size":1705,"mtime":1675188401363,"results":"4572","hashOfConfig":"4569"},{"size":444,"mtime":1675188401363,"results":"4573","hashOfConfig":"4569"},{"size":19,"mtime":1675188401363,"results":"4574","hashOfConfig":"4569"},{"size":1458,"mtime":1675188401363,"results":"4575","hashOfConfig":"4569"},{"size":492,"mtime":1675188401363,"results":"4576","hashOfConfig":"4569"},{"size":891,"mtime":1675188401367,"results":"4577","hashOfConfig":"4558"},{"size":1709,"mtime":1678221097011,"results":"4578","hashOfConfig":"4558"},{"size":1405,"mtime":1675188401367,"results":"4579","hashOfConfig":"4558"},{"size":4912,"mtime":1675188401367,"results":"4580","hashOfConfig":"4558"},{"size":1468,"mtime":1675188401367,"results":"4581","hashOfConfig":"4558"},{"size":861,"mtime":1675188401367,"results":"4582","hashOfConfig":"4558"},{"size":165,"mtime":1675188401367,"results":"4583","hashOfConfig":"4558"},{"size":2201,"mtime":1678221097011,"results":"4584","hashOfConfig":"4558"},{"size":423,"mtime":1675188401367,"results":"4585","hashOfConfig":"4558"},{"size":3923,"mtime":1675188401367,"results":"4586","hashOfConfig":"4558"},{"size":434,"mtime":1675188401367,"results":"4587","hashOfConfig":"4558"},{"size":1120,"mtime":1675188401367,"results":"4588","hashOfConfig":"4558"},{"size":944,"mtime":1675188401367,"results":"4589","hashOfConfig":"4558"},{"size":6129,"mtime":1678221097011,"results":"4590","hashOfConfig":"4558"},{"size":2138,"mtime":1678221097011,"results":"4591","hashOfConfig":"4558"},{"size":260,"mtime":1675188401368,"results":"4592","hashOfConfig":"4558"},{"size":1713,"mtime":1675188401368,"results":"4593","hashOfConfig":"4558"},{"size":2669,"mtime":1676418804556,"results":"4594","hashOfConfig":"4558"},{"size":532,"mtime":1675188401368,"results":"4595","hashOfConfig":"4558"},{"size":665,"mtime":1675188401368,"results":"4596","hashOfConfig":"4558"},{"size":894,"mtime":1676418804556,"results":"4597","hashOfConfig":"4558"},{"size":901,"mtime":1675188401368,"results":"4598","hashOfConfig":"4558"},{"size":891,"mtime":1675188401368,"results":"4599","hashOfConfig":"4558"},{"size":1609,"mtime":1675188401368,"results":"4600","hashOfConfig":"4558"},{"size":1295,"mtime":1675188401368,"results":"4601","hashOfConfig":"4558"},{"size":74,"mtime":1675188401368,"results":"4602","hashOfConfig":"4558"},{"size":1216,"mtime":1678221097012,"results":"4603","hashOfConfig":"4558"},{"size":47,"mtime":1678221097012,"results":"4604","hashOfConfig":"4558"},{"size":3753,"mtime":1675694258640,"results":"4605","hashOfConfig":"4558"},{"size":5817,"mtime":1675188401369,"results":"4606","hashOfConfig":"4558"},{"size":21,"mtime":1678221097012,"results":"4607","hashOfConfig":"4558"},{"size":2315,"mtime":1675188401369,"results":"4608","hashOfConfig":"4558"},{"size":7871,"mtime":1675188401369,"results":"4609","hashOfConfig":"4558"},{"size":3407,"mtime":1675188401369,"results":"4610","hashOfConfig":"4558"},{"size":23269,"mtime":1678221097012,"results":"4611","hashOfConfig":"4558"},{"size":495,"mtime":1675188401369,"results":"4612","hashOfConfig":"4558"},{"size":605,"mtime":1675188401370,"results":"4613","hashOfConfig":"4558"},{"size":461,"mtime":1675188401370,"results":"4614","hashOfConfig":"4558"},{"size":927,"mtime":1678282296172,"results":"4615","hashOfConfig":"4558"},{"size":484,"mtime":1675188401370,"results":"4616","hashOfConfig":"4558"},{"size":1345,"mtime":1675188401370,"results":"4617","hashOfConfig":"4558"},{"size":1837,"mtime":1675188401370,"results":"4618","hashOfConfig":"4558"},{"size":1394,"mtime":1675188401370,"results":"4619","hashOfConfig":"4558"},{"size":401,"mtime":1675188401370,"results":"4620","hashOfConfig":"4558"},{"size":451,"mtime":1675188401370,"results":"4621","hashOfConfig":"4558"},{"size":4919,"mtime":1675188401370,"results":"4622","hashOfConfig":"4558"},{"size":213,"mtime":1675188401370,"results":"4623","hashOfConfig":"4558"},{"size":1472,"mtime":1678221097012,"results":"4624","hashOfConfig":"4558"},{"size":723,"mtime":1675188401370,"results":"4625","hashOfConfig":"4558"},{"size":2240,"mtime":1675188401371,"results":"4626","hashOfConfig":"4558"},{"size":753,"mtime":1675188401371,"results":"4627","hashOfConfig":"4558"},{"size":566,"mtime":1675188401371,"results":"4628","hashOfConfig":"4558"},{"size":2949,"mtime":1678221097012,"results":"4629","hashOfConfig":"4558"},{"size":1142,"mtime":1675188401371,"results":"4630","hashOfConfig":"4558"},{"size":1808,"mtime":1675188401371,"results":"4631","hashOfConfig":"4558"},{"size":2922,"mtime":1678221097012,"results":"4632","hashOfConfig":"4558"},{"size":4765,"mtime":1678282296172,"results":"4633","hashOfConfig":"4558"},{"size":3499,"mtime":1675188401371,"results":"4634","hashOfConfig":"4558"},{"size":363,"mtime":1675188401371,"results":"4635","hashOfConfig":"4558"},{"size":947,"mtime":1675188401371,"results":"4636","hashOfConfig":"4558"},{"size":1412,"mtime":1678321762660,"results":"4637","hashOfConfig":"4558"},{"size":1634,"mtime":1675188401371,"results":"4638","hashOfConfig":"4558"},{"size":2692,"mtime":1675188401371,"results":"4639","hashOfConfig":"4558"},{"size":6955,"mtime":1678221097013,"results":"4640","hashOfConfig":"4558"},{"size":24054,"mtime":1678221097013,"results":"4641","hashOfConfig":"4558"},{"size":11150,"mtime":1678221097013,"results":"4642","hashOfConfig":"4558"},{"size":21209,"mtime":1678221097013,"results":"4643","hashOfConfig":"4558"},{"size":3015,"mtime":1678221097013,"results":"4644","hashOfConfig":"4558"},{"size":8813,"mtime":1675188401372,"results":"4645","hashOfConfig":"4558"},{"size":326,"mtime":1675188401372,"results":"4646","hashOfConfig":"4558"},{"size":605,"mtime":1675188401372,"results":"4647","hashOfConfig":"4558"},{"size":2666,"mtime":1675188401372,"results":"4648","hashOfConfig":"4558"},{"size":3398,"mtime":1675188401372,"results":"4649","hashOfConfig":"4558"},{"size":5357,"mtime":1678221097014,"results":"4650","hashOfConfig":"4558"},{"size":3735,"mtime":1675188401373,"results":"4651","hashOfConfig":"4558"},{"size":4245,"mtime":1678221097014,"results":"4652","hashOfConfig":"4558"},{"size":28668,"mtime":1678221097014,"results":"4653","hashOfConfig":"4558"},{"size":13937,"mtime":1675694258642,"results":"4654","hashOfConfig":"4558"},{"size":4008,"mtime":1675188401373,"results":"4655","hashOfConfig":"4558"},{"size":1203,"mtime":1678221097015,"results":"4656","hashOfConfig":"4558"},{"size":6991,"mtime":1675188401373,"results":"4657","hashOfConfig":"4558"},{"size":2513,"mtime":1678221097015,"results":"4658","hashOfConfig":"4558"},{"size":1508,"mtime":1678221097015,"results":"4659","hashOfConfig":"4558"},{"size":921,"mtime":1675694258642,"results":"4660","hashOfConfig":"4558"},{"size":17833,"mtime":1675694251283,"results":"4661","hashOfConfig":"4558"},{"size":1695,"mtime":1678282296172,"results":"4662","hashOfConfig":"4558"},{"size":2342,"mtime":1675188401374,"results":"4663","hashOfConfig":"4558"},{"size":567,"mtime":1678221097015,"results":"4664","hashOfConfig":"4558"},{"size":2943,"mtime":1675188401374,"results":"4665","hashOfConfig":"4558"},{"size":7177,"mtime":1678221097015,"results":"4666","hashOfConfig":"4558"},{"size":13506,"mtime":1678221097015,"results":"4667","hashOfConfig":"4558"},{"size":1121,"mtime":1675188401374,"results":"4668","hashOfConfig":"4558"},{"size":6072,"mtime":1675188401374,"results":"4669","hashOfConfig":"4558"},{"size":1151,"mtime":1675188401374,"results":"4670","hashOfConfig":"4558"},{"size":2305,"mtime":1675694258642,"results":"4671","hashOfConfig":"4558"},{"size":14676,"mtime":1678221097016,"results":"4672","hashOfConfig":"4558"},{"size":29806,"mtime":1678321762660,"results":"4673","hashOfConfig":"4558"},{"size":4997,"mtime":1678221097016,"results":"4674","hashOfConfig":"4558"},{"size":987,"mtime":1678221097016,"results":"4675","hashOfConfig":"4558"},{"size":3329,"mtime":1678221097016,"results":"4676","hashOfConfig":"4558"},{"size":109,"mtime":1675188401375,"results":"4677","hashOfConfig":"4558"},{"size":95,"mtime":1675188401375,"results":"4678","hashOfConfig":"4558"},{"size":7506,"mtime":1678221097016,"results":"4679","hashOfConfig":"4558"},{"size":1464,"mtime":1678221097017,"results":"4680","hashOfConfig":"4558"},{"size":8268,"mtime":1678221097017,"results":"4681","hashOfConfig":"4558"},{"size":1762,"mtime":1678221097017,"results":"4682","hashOfConfig":"4558"},{"size":1079,"mtime":1675188401375,"results":"4683","hashOfConfig":"4558"},{"size":152,"mtime":1675188401375,"results":"4684","hashOfConfig":"4558"},{"size":284,"mtime":1675188401376,"results":"4685","hashOfConfig":"4558"},{"size":1255,"mtime":1675188401376,"results":"4686","hashOfConfig":"4558"},{"size":998,"mtime":1678221097017,"results":"4687","hashOfConfig":"4558"},{"size":2262,"mtime":1675188401376,"results":"4688","hashOfConfig":"4558"},{"size":63,"mtime":1675188401376,"results":"4689","hashOfConfig":"4558"},{"size":1274,"mtime":1675188401376,"results":"4690","hashOfConfig":"4558"},{"size":1387,"mtime":1678221097017,"results":"4691","hashOfConfig":"4558"},{"size":4144,"mtime":1678221097017,"results":"4692","hashOfConfig":"4558"},{"size":3540,"mtime":1678221097018,"results":"4693","hashOfConfig":"4558"},{"size":916,"mtime":1678221097018,"results":"4694","hashOfConfig":"4558"},{"size":8518,"mtime":1678221097018,"results":"4695","hashOfConfig":"4558"},{"size":721,"mtime":1678221097018,"results":"4696","hashOfConfig":"4558"},{"size":1886,"mtime":1678221097018,"results":"4697","hashOfConfig":"4558"},{"size":3472,"mtime":1678221097018,"results":"4698","hashOfConfig":"4558"},{"size":973,"mtime":1678221097018,"results":"4699","hashOfConfig":"4558"},{"size":1192,"mtime":1678221097018,"results":"4700","hashOfConfig":"4558"},{"size":442,"mtime":1678221097018,"results":"4701","hashOfConfig":"4558"},{"size":8042,"mtime":1678221097019,"results":"4702","hashOfConfig":"4558"},{"size":10088,"mtime":1678221097019,"results":"4703","hashOfConfig":"4558"},{"size":3513,"mtime":1678221097019,"results":"4704","hashOfConfig":"4558"},{"size":2721,"mtime":1678221097019,"results":"4705","hashOfConfig":"4558"},{"size":4134,"mtime":1678221097019,"results":"4706","hashOfConfig":"4558"},{"size":6971,"mtime":1678326191464,"results":"4707","hashOfConfig":"4558"},{"size":6538,"mtime":1678221097020,"results":"4708","hashOfConfig":"4558"},{"size":2637,"mtime":1678221097020,"results":"4709","hashOfConfig":"4558"},{"size":958,"mtime":1678221097020,"results":"4710","hashOfConfig":"4558"},{"size":2674,"mtime":1678221097020,"results":"4711","hashOfConfig":"4558"},{"size":4244,"mtime":1678221097020,"results":"4712","hashOfConfig":"4558"},{"size":2730,"mtime":1678221097020,"results":"4713","hashOfConfig":"4558"},{"size":2049,"mtime":1678221097020,"results":"4714","hashOfConfig":"4558"},{"size":617,"mtime":1678221097021,"results":"4715","hashOfConfig":"4558"},{"size":6812,"mtime":1678221097021,"results":"4716","hashOfConfig":"4558"},{"size":5330,"mtime":1678221097021,"results":"4717","hashOfConfig":"4558"},{"size":1181,"mtime":1675188401381,"results":"4718","hashOfConfig":"4558"},{"size":2167,"mtime":1678221097021,"results":"4719","hashOfConfig":"4558"},{"size":2738,"mtime":1675188401381,"results":"4720","hashOfConfig":"4558"},{"size":730,"mtime":1678221097021,"results":"4721","hashOfConfig":"4558"},{"size":1456,"mtime":1678221097021,"results":"4722","hashOfConfig":"4558"},{"size":14099,"mtime":1678221097021,"results":"4723","hashOfConfig":"4558"},{"size":45,"mtime":1675188401382,"results":"4724","hashOfConfig":"4558"},{"size":434,"mtime":1675188401383,"results":"4725","hashOfConfig":"4558"},{"size":734,"mtime":1675188401383,"results":"4726","hashOfConfig":"4558"},{"size":52,"mtime":1675188401383,"results":"4727","hashOfConfig":"4558"},{"size":1126,"mtime":1675188401383,"results":"4728","hashOfConfig":"4558"},{"size":5503,"mtime":1675188401383,"results":"4729","hashOfConfig":"4558"},{"size":13104,"mtime":1678221097022,"results":"4730","hashOfConfig":"4558"},{"size":2628,"mtime":1675188401383,"results":"4731","hashOfConfig":"4558"},{"size":3022,"mtime":1678221097022,"results":"4732","hashOfConfig":"4558"},{"size":707,"mtime":1675188401383,"results":"4733","hashOfConfig":"4558"},{"size":380,"mtime":1678221097022,"results":"4734","hashOfConfig":"4558"},{"size":130,"mtime":1675188401384,"results":"4735","hashOfConfig":"4558"},{"size":100,"mtime":1675188401384,"results":"4736","hashOfConfig":"4558"},{"size":1131,"mtime":1678221097022,"results":"4737","hashOfConfig":"4558"},{"size":179,"mtime":1675188401384,"results":"4738","hashOfConfig":"4558"},{"size":1218,"mtime":1675188401384,"results":"4739","hashOfConfig":"4558"},{"size":339,"mtime":1678221097022,"results":"4740","hashOfConfig":"4558"},{"size":624,"mtime":1678221097022,"results":"4741","hashOfConfig":"4558"},{"size":1868,"mtime":1678221097023,"results":"4742","hashOfConfig":"4558"},{"size":2603,"mtime":1678221097023,"results":"4743","hashOfConfig":"4558"},{"size":180,"mtime":1675188401384,"results":"4744","hashOfConfig":"4558"},{"size":2005,"mtime":1675188401384,"results":"4745","hashOfConfig":"4558"},{"size":1214,"mtime":1678221097023,"results":"4746","hashOfConfig":"4558"},{"size":1111,"mtime":1675188401384,"results":"4747","hashOfConfig":"4558"},{"size":15911,"mtime":1678221097023,"results":"4748","hashOfConfig":"4558"},{"size":1089,"mtime":1678221097023,"results":"4749","hashOfConfig":"4558"},{"size":1443,"mtime":1675188401385,"results":"4750","hashOfConfig":"4558"},{"size":2666,"mtime":1678221097024,"results":"4751","hashOfConfig":"4558"},{"size":1636,"mtime":1675188401385,"results":"4752","hashOfConfig":"4558"},{"size":1217,"mtime":1675188401385,"results":"4753","hashOfConfig":"4558"},{"size":2757,"mtime":1678221097024,"results":"4754","hashOfConfig":"4558"},{"size":664,"mtime":1675188401385,"results":"4755","hashOfConfig":"4558"},{"size":183,"mtime":1675188401386,"results":"4756","hashOfConfig":"4558"},{"size":4215,"mtime":1678221097024,"results":"4757","hashOfConfig":"4558"},{"size":6420,"mtime":1678221097024,"results":"4758","hashOfConfig":"4558"},{"size":770,"mtime":1675188401386,"results":"4759","hashOfConfig":"4558"},{"size":11149,"mtime":1678221097024,"results":"4760","hashOfConfig":"4558"},{"size":8145,"mtime":1675188401386,"results":"4761","hashOfConfig":"4558"},{"size":6244,"mtime":1678221097024,"results":"4762","hashOfConfig":"4558"},{"size":619,"mtime":1675188401387,"results":"4763","hashOfConfig":"4558"},{"size":145,"mtime":1675188401387,"results":"4764","hashOfConfig":"4558"},{"size":555,"mtime":1675188401387,"results":"4765","hashOfConfig":"4558"},{"size":1082,"mtime":1675188401387,"results":"4766","hashOfConfig":"4558"},{"size":1605,"mtime":1675188401387,"results":"4767","hashOfConfig":"4558"},{"size":444,"mtime":1675188401387,"results":"4768","hashOfConfig":"4558"},{"size":6097,"mtime":1675188401387,"results":"4769","hashOfConfig":"4558"},{"size":243,"mtime":1675188401387,"results":"4770","hashOfConfig":"4558"},{"size":1904,"mtime":1675188401387,"results":"4771","hashOfConfig":"4558"},{"size":4510,"mtime":1675188401387,"results":"4772","hashOfConfig":"4558"},{"size":421,"mtime":1675188401387,"results":"4773","hashOfConfig":"4558"},{"size":2623,"mtime":1675188401388,"results":"4774","hashOfConfig":"4558"},{"size":23,"mtime":1678221097025,"results":"4775","hashOfConfig":"4558"},{"size":2974,"mtime":1675188401388,"results":"4776","hashOfConfig":"4558"},{"size":8387,"mtime":1678221097025,"results":"4777","hashOfConfig":"4558"},{"size":50,"mtime":1678221097025,"results":"4778","hashOfConfig":"4558"},{"size":77,"mtime":1678221097025,"results":"4779","hashOfConfig":"4558"},{"size":1244,"mtime":1678221097025,"results":"4780","hashOfConfig":"4558"},{"size":439,"mtime":1675188401388,"results":"4781","hashOfConfig":"4558"},{"size":187,"mtime":1678221097025,"results":"4782","hashOfConfig":"4558"},{"size":656,"mtime":1675188401389,"results":"4783","hashOfConfig":"4558"},{"size":823,"mtime":1675188401389,"results":"4784","hashOfConfig":"4558"},{"size":779,"mtime":1675188401389,"results":"4785","hashOfConfig":"4558"},{"size":566,"mtime":1675188401389,"results":"4786","hashOfConfig":"4558"},{"size":795,"mtime":1675188401389,"results":"4787","hashOfConfig":"4558"},{"size":2079,"mtime":1678221097025,"results":"4788","hashOfConfig":"4558"},{"size":609,"mtime":1675188401389,"results":"4789","hashOfConfig":"4558"},{"size":765,"mtime":1675188401389,"results":"4790","hashOfConfig":"4558"},{"size":700,"mtime":1675188401389,"results":"4791","hashOfConfig":"4558"},{"size":1836,"mtime":1675188401389,"results":"4792","hashOfConfig":"4558"},{"size":625,"mtime":1675188401389,"results":"4793","hashOfConfig":"4558"},{"size":227,"mtime":1678221097026,"results":"4794","hashOfConfig":"4558"},{"size":10740,"mtime":1678221097026,"results":"4795","hashOfConfig":"4558"},{"size":2511,"mtime":1678221097026,"results":"4796","hashOfConfig":"4558"},{"size":523,"mtime":1675188401391,"results":"4797","hashOfConfig":"4558"},{"size":1512,"mtime":1675188401391,"results":"4798","hashOfConfig":"4558"},{"size":426,"mtime":1678221097026,"results":"4799","hashOfConfig":"4558"},{"size":1776,"mtime":1675188401392,"results":"4800","hashOfConfig":"4558"},{"size":877,"mtime":1675188401392,"results":"4801","hashOfConfig":"4558"},{"size":716,"mtime":1675188401392,"results":"4802","hashOfConfig":"4558"},{"size":190,"mtime":1675188401392,"results":"4803","hashOfConfig":"4558"},{"size":2879,"mtime":1678221097026,"results":"4804","hashOfConfig":"4558"},{"size":1252,"mtime":1675188401392,"results":"4805","hashOfConfig":"4558"},{"size":2002,"mtime":1678221097027,"results":"4806","hashOfConfig":"4558"},{"size":436,"mtime":1675188401392,"results":"4807","hashOfConfig":"4558"},{"size":1779,"mtime":1675188401392,"results":"4808","hashOfConfig":"4558"},{"size":460,"mtime":1678221097027,"results":"4809","hashOfConfig":"4558"},{"size":1087,"mtime":1678221097027,"results":"4810","hashOfConfig":"4558"},{"size":799,"mtime":1678221097027,"results":"4811","hashOfConfig":"4558"},{"size":795,"mtime":1675188401392,"results":"4812","hashOfConfig":"4558"},{"size":1092,"mtime":1675188401392,"results":"4813","hashOfConfig":"4558"},{"size":1343,"mtime":1675188401393,"results":"4814","hashOfConfig":"4558"},{"size":1057,"mtime":1675188401393,"results":"4815","hashOfConfig":"4558"},{"size":2636,"mtime":1678221097027,"results":"4816","hashOfConfig":"4558"},{"size":317,"mtime":1675188401393,"results":"4817","hashOfConfig":"4558"},{"size":1481,"mtime":1675188401393,"results":"4818","hashOfConfig":"4558"},{"size":2180,"mtime":1675188401393,"results":"4819","hashOfConfig":"4558"},{"size":34,"mtime":1675188401393,"results":"4820","hashOfConfig":"4558"},{"size":5684,"mtime":1678221097027,"results":"4821","hashOfConfig":"4558"},{"size":363,"mtime":1675188401393,"results":"4822","hashOfConfig":"4558"},{"size":502,"mtime":1675188401393,"results":"4823","hashOfConfig":"4558"},{"size":65,"mtime":1678221097027,"results":"4824","hashOfConfig":"4558"},{"size":21,"mtime":1678221097027,"results":"4825","hashOfConfig":"4558"},{"size":225,"mtime":1675188401394,"results":"4826","hashOfConfig":"4558"},{"size":284,"mtime":1675188401394,"results":"4827","hashOfConfig":"4558"},{"size":3624,"mtime":1675694258647,"results":"4828","hashOfConfig":"4558"},{"size":250,"mtime":1675188401394,"results":"4829","hashOfConfig":"4558"},{"size":24,"mtime":1678221097028,"results":"4830","hashOfConfig":"4558"},{"size":544,"mtime":1675188401394,"results":"4831","hashOfConfig":"4558"},{"size":10539,"mtime":1675188401394,"results":"4832","hashOfConfig":"4558"},{"size":73,"mtime":1678221097028,"results":"4833","hashOfConfig":"4558"},{"size":1883,"mtime":1675188401394,"results":"4834","hashOfConfig":"4558"},{"size":3485,"mtime":1675188401395,"results":"4835","hashOfConfig":"4558"},{"size":1332,"mtime":1675188401395,"results":"4836","hashOfConfig":"4558"},{"size":215,"mtime":1675188401395,"results":"4837","hashOfConfig":"4558"},{"size":156,"mtime":1675188401395,"results":"4838","hashOfConfig":"4558"},{"size":11867,"mtime":1675694258647,"results":"4839","hashOfConfig":"4558"},{"size":4317,"mtime":1675188401395,"results":"4840","hashOfConfig":"4558"},{"size":140,"mtime":1678221097028,"results":"4841","hashOfConfig":"4558"},{"size":3674,"mtime":1678221097028,"results":"4842","hashOfConfig":"4558"},{"size":383,"mtime":1678221097028,"results":"4843","hashOfConfig":"4558"},{"size":383,"mtime":1678221097028,"results":"4844","hashOfConfig":"4558"},{"size":216,"mtime":1678221097028,"results":"4845","hashOfConfig":"4558"},{"size":880,"mtime":1678221097029,"results":"4846","hashOfConfig":"4558"},{"size":2488,"mtime":1678221097029,"results":"4847","hashOfConfig":"4558"},{"size":188,"mtime":1675188401396,"results":"4848","hashOfConfig":"4558"},{"size":916,"mtime":1678221097029,"results":"4849","hashOfConfig":"4558"},{"size":2299,"mtime":1675188401396,"results":"4850","hashOfConfig":"4558"},{"size":577,"mtime":1675188401396,"results":"4851","hashOfConfig":"4558"},{"size":1806,"mtime":1675188401396,"results":"4852","hashOfConfig":"4558"},{"size":131,"mtime":1678221097029,"results":"4853","hashOfConfig":"4558"},{"size":407,"mtime":1675188401397,"results":"4854","hashOfConfig":"4558"},{"size":932,"mtime":1675188401397,"results":"4855","hashOfConfig":"4558"},{"size":1007,"mtime":1675188401397,"results":"4856","hashOfConfig":"4558"},{"size":691,"mtime":1675188401397,"results":"4857","hashOfConfig":"4558"},{"size":1588,"mtime":1675188401397,"results":"4858","hashOfConfig":"4558"},{"size":139,"mtime":1678221097029,"results":"4859","hashOfConfig":"4558"},{"size":6413,"mtime":1678221097029,"results":"4860","hashOfConfig":"4558"},{"size":439,"mtime":1675188401397,"results":"4861","hashOfConfig":"4558"},{"size":53,"mtime":1678221097030,"results":"4862","hashOfConfig":"4558"},{"size":2008,"mtime":1675188401398,"results":"4863","hashOfConfig":"4558"},{"size":44,"mtime":1678221097030,"results":"4864","hashOfConfig":"4558"},{"size":1658,"mtime":1675188401398,"results":"4865","hashOfConfig":"4558"},{"size":53,"mtime":1678221097030,"results":"4866","hashOfConfig":"4558"},{"size":1210,"mtime":1675188401398,"results":"4867","hashOfConfig":"4558"},{"size":44,"mtime":1678221097030,"results":"4868","hashOfConfig":"4558"},{"size":747,"mtime":1675188401398,"results":"4869","hashOfConfig":"4558"},{"size":315,"mtime":1675188401398,"results":"4870","hashOfConfig":"4558"},{"size":140,"mtime":1675188401398,"results":"4871","hashOfConfig":"4558"},{"size":4005,"mtime":1675188401399,"results":"4872","hashOfConfig":"4558"},{"size":34,"mtime":1678221097030,"results":"4873","hashOfConfig":"4558"},{"size":544,"mtime":1675188401399,"results":"4874","hashOfConfig":"4558"},{"size":11681,"mtime":1678221097030,"results":"4875","hashOfConfig":"4558"},{"size":13738,"mtime":1678221097030,"results":"4876","hashOfConfig":"4558"},{"size":1561,"mtime":1678221097031,"results":"4877","hashOfConfig":"4558"},{"size":17579,"mtime":1675188401399,"results":"4878","hashOfConfig":"4558"},{"size":410,"mtime":1675188401399,"results":"4879","hashOfConfig":"4558"},{"size":872,"mtime":1678221097031,"results":"4880","hashOfConfig":"4558"},{"size":589,"mtime":1678221097031,"results":"4881","hashOfConfig":"4558"},{"size":331,"mtime":1675188401400,"results":"4882","hashOfConfig":"4558"},{"size":1077,"mtime":1675188401400,"results":"4883","hashOfConfig":"4558"},{"size":932,"mtime":1678221097031,"results":"4884","hashOfConfig":"4558"},{"size":529,"mtime":1675188401400,"results":"4885","hashOfConfig":"4558"},{"size":984,"mtime":1675188401400,"results":"4886","hashOfConfig":"4558"},{"size":446,"mtime":1675188401400,"results":"4887","hashOfConfig":"4558"},{"size":831,"mtime":1678221097031,"results":"4888","hashOfConfig":"4558"},{"size":585,"mtime":1675188401400,"results":"4889","hashOfConfig":"4558"},{"size":1918,"mtime":1675188401404,"results":"4890","hashOfConfig":"4558"},{"size":10232,"mtime":1678321762660,"results":"4891","hashOfConfig":"4558"},{"size":374,"mtime":1675188401404,"results":"4892","hashOfConfig":"4558"},{"size":152,"mtime":1678221097033,"results":"4893","hashOfConfig":"4558"},{"size":4961,"mtime":1678221097033,"results":"4894","hashOfConfig":"4558"},{"size":187,"mtime":1678221097033,"results":"4895","hashOfConfig":"4558"},{"size":927,"mtime":1675188401404,"results":"4896","hashOfConfig":"4558"},{"size":43,"mtime":1678221097033,"results":"4897","hashOfConfig":"4558"},{"size":116,"mtime":1678221097031,"results":"4898","hashOfConfig":"4558"},{"size":7275,"mtime":1675694258649,"results":"4899","hashOfConfig":"4558"},{"size":374,"mtime":1675188401400,"results":"4900","hashOfConfig":"4558"},{"size":266,"mtime":1675188401400,"results":"4901","hashOfConfig":"4558"},{"size":266,"mtime":1675188401400,"results":"4902","hashOfConfig":"4558"},{"size":214,"mtime":1678221097031,"results":"4903","hashOfConfig":"4558"},{"size":852,"mtime":1678221097032,"results":"4904","hashOfConfig":"4558"},{"size":5245,"mtime":1678221097032,"results":"4905","hashOfConfig":"4558"},{"size":754,"mtime":1676418804557,"results":"4906","hashOfConfig":"4558"},{"size":2145,"mtime":1678221097032,"results":"4907","hashOfConfig":"4558"},{"size":3508,"mtime":1675694258650,"results":"4908","hashOfConfig":"4558"},{"size":573,"mtime":1675188401401,"results":"4909","hashOfConfig":"4558"},{"size":61,"mtime":1678221097032,"results":"4910","hashOfConfig":"4558"},{"size":32308,"mtime":1675188401403,"results":"4911","hashOfConfig":"4558"},{"size":211,"mtime":1675188401403,"results":"4912","hashOfConfig":"4558"},{"size":9201,"mtime":1675188401403,"results":"4913","hashOfConfig":"4558"},{"size":331,"mtime":1675188401403,"results":"4914","hashOfConfig":"4558"},{"size":50,"mtime":1678221097032,"results":"4915","hashOfConfig":"4558"},{"size":32,"mtime":1678221097033,"results":"4916","hashOfConfig":"4558"},{"size":113,"mtime":1678221097033,"results":"4917","hashOfConfig":"4558"},{"size":1886,"mtime":1675188401404,"results":"4918","hashOfConfig":"4558"},{"size":178,"mtime":1675188401404,"results":"4919","hashOfConfig":"4558"},{"size":216,"mtime":1678221097039,"results":"4920","hashOfConfig":"4558"},{"size":14780,"mtime":1678221097039,"results":"4921","hashOfConfig":"4558"},{"size":89,"mtime":1678221097039,"results":"4922","hashOfConfig":"4558"},{"size":2046,"mtime":1675188401410,"results":"4923","hashOfConfig":"4558"},{"size":703,"mtime":1675188401410,"results":"4924","hashOfConfig":"4558"},{"size":1473,"mtime":1675188401411,"results":"4925","hashOfConfig":"4558"},{"size":900,"mtime":1675188401411,"results":"4926","hashOfConfig":"4558"},{"size":1181,"mtime":1678221097039,"results":"4927","hashOfConfig":"4558"},{"size":654,"mtime":1675188401411,"results":"4928","hashOfConfig":"4558"},{"size":2693,"mtime":1675188401411,"results":"4929","hashOfConfig":"4558"},{"size":567,"mtime":1675188401411,"results":"4930","hashOfConfig":"4558"},{"size":511,"mtime":1675188401411,"results":"4931","hashOfConfig":"4558"},{"size":2408,"mtime":1675188401411,"results":"4932","hashOfConfig":"4558"},{"size":2816,"mtime":1675188401411,"results":"4933","hashOfConfig":"4558"},{"size":2136,"mtime":1675188401411,"results":"4934","hashOfConfig":"4558"},{"size":3123,"mtime":1675188401411,"results":"4935","hashOfConfig":"4558"},{"size":1007,"mtime":1675188401412,"results":"4936","hashOfConfig":"4558"},{"size":1680,"mtime":1675188401412,"results":"4937","hashOfConfig":"4558"},{"size":1051,"mtime":1675188401412,"results":"4938","hashOfConfig":"4558"},{"size":1848,"mtime":1675188401412,"results":"4939","hashOfConfig":"4558"},{"size":1253,"mtime":1675188401412,"results":"4940","hashOfConfig":"4558"},{"size":1078,"mtime":1675188401412,"results":"4941","hashOfConfig":"4558"},{"size":1067,"mtime":1675188401412,"results":"4942","hashOfConfig":"4558"},{"size":1090,"mtime":1675188401412,"results":"4943","hashOfConfig":"4558"},{"size":1150,"mtime":1675188401412,"results":"4944","hashOfConfig":"4558"},{"size":62,"mtime":1678221097039,"results":"4945","hashOfConfig":"4558"},{"size":730,"mtime":1675188401412,"results":"4946","hashOfConfig":"4558"},{"size":1673,"mtime":1675188401412,"results":"4947","hashOfConfig":"4558"},{"size":4635,"mtime":1675188401412,"results":"4948","hashOfConfig":"4558"},{"size":149,"mtime":1675188401412,"results":"4949","hashOfConfig":"4558"},{"size":147,"mtime":1675188401412,"results":"4950","hashOfConfig":"4558"},{"size":1513,"mtime":1675188401413,"results":"4951","hashOfConfig":"4558"},{"size":131,"mtime":1675188401413,"results":"4952","hashOfConfig":"4558"},{"size":402,"mtime":1675188401413,"results":"4953","hashOfConfig":"4558"},{"size":259,"mtime":1675188401413,"results":"4954","hashOfConfig":"4558"},{"size":74,"mtime":1678221097039,"results":"4955","hashOfConfig":"4558"},{"size":691,"mtime":1675188401413,"results":"4956","hashOfConfig":"4558"},{"size":512,"mtime":1675188401413,"results":"4957","hashOfConfig":"4558"},{"size":214,"mtime":1678221097039,"results":"4958","hashOfConfig":"4558"},{"size":2862,"mtime":1675188401413,"results":"4959","hashOfConfig":"4558"},{"size":2857,"mtime":1675188401413,"results":"4960","hashOfConfig":"4558"},{"size":1414,"mtime":1675188401413,"results":"4961","hashOfConfig":"4558"},{"size":1925,"mtime":1675188401413,"results":"4962","hashOfConfig":"4558"},{"size":194,"mtime":1675188401413,"results":"4963","hashOfConfig":"4558"},{"size":76,"mtime":1678221097039,"results":"4964","hashOfConfig":"4558"},{"size":1485,"mtime":1675188401413,"results":"4965","hashOfConfig":"4558"},{"size":3052,"mtime":1675694258653,"results":"4966","hashOfConfig":"4558"},{"size":2447,"mtime":1678221097033,"results":"4967","hashOfConfig":"4558"},{"size":4675,"mtime":1675694258650,"results":"4968","hashOfConfig":"4558"},{"size":2450,"mtime":1678221097034,"results":"4969","hashOfConfig":"4558"},{"size":2305,"mtime":1678221097034,"results":"4970","hashOfConfig":"4558"},{"size":21587,"mtime":1678221097034,"results":"4971","hashOfConfig":"4558"},{"size":3130,"mtime":1678221097034,"results":"4972","hashOfConfig":"4558"},{"size":870,"mtime":1678221097034,"results":"4973","hashOfConfig":"4558"},{"size":10975,"mtime":1678221097034,"results":"4974","hashOfConfig":"4558"},{"size":716,"mtime":1678221097034,"results":"4975","hashOfConfig":"4558"},{"size":4411,"mtime":1675188401406,"results":"4976","hashOfConfig":"4558"},{"size":3873,"mtime":1675188401406,"results":"4977","hashOfConfig":"4558"},{"size":4106,"mtime":1675188401406,"results":"4978","hashOfConfig":"4558"},{"size":17743,"mtime":1678221097035,"results":"4979","hashOfConfig":"4558"},{"size":2997,"mtime":1675694258651,"results":"4980","hashOfConfig":"4558"},{"size":2562,"mtime":1678221097035,"results":"4981","hashOfConfig":"4558"},{"size":6091,"mtime":1678221097035,"results":"4982","hashOfConfig":"4558"},{"size":3328,"mtime":1675694258651,"results":"4983","hashOfConfig":"4558"},{"size":4039,"mtime":1678221097035,"results":"4984","hashOfConfig":"4558"},{"size":5262,"mtime":1678221097035,"results":"4985","hashOfConfig":"4558"},{"size":10962,"mtime":1678221097035,"results":"4986","hashOfConfig":"4558"},{"size":16964,"mtime":1678221097035,"results":"4987","hashOfConfig":"4558"},{"size":1123,"mtime":1678221097036,"results":"4988","hashOfConfig":"4558"},{"size":3976,"mtime":1678221097036,"results":"4989","hashOfConfig":"4558"},{"size":17524,"mtime":1678221097036,"results":"4990","hashOfConfig":"4558"},{"size":727,"mtime":1678221097036,"results":"4991","hashOfConfig":"4558"},{"size":616,"mtime":1678221097036,"results":"4992","hashOfConfig":"4558"},{"size":440,"mtime":1678221097036,"results":"4993","hashOfConfig":"4558"},{"size":78,"mtime":1678221097036,"results":"4994","hashOfConfig":"4558"},{"size":92,"mtime":1678221097037,"results":"4995","hashOfConfig":"4558"},{"size":83,"mtime":1675188401407,"results":"4996","hashOfConfig":"4558"},{"size":79,"mtime":1678221097037,"results":"4997","hashOfConfig":"4558"},{"size":512,"mtime":1675188401408,"results":"4998","hashOfConfig":"4558"},{"size":575,"mtime":1678221097037,"results":"4999","hashOfConfig":"4558"},{"size":420,"mtime":1675188401408,"results":"5000","hashOfConfig":"4558"},{"size":554,"mtime":1675188401408,"results":"5001","hashOfConfig":"4558"},{"size":678,"mtime":1675188401408,"results":"5002","hashOfConfig":"4558"},{"size":1405,"mtime":1675188401408,"results":"5003","hashOfConfig":"4558"},{"size":448,"mtime":1675188401408,"results":"5004","hashOfConfig":"4558"},{"size":1032,"mtime":1678221097037,"results":"5005","hashOfConfig":"4558"},{"size":453,"mtime":1675188401408,"results":"5006","hashOfConfig":"4558"},{"size":495,"mtime":1675694258652,"results":"5007","hashOfConfig":"4558"},{"size":340,"mtime":1675188401408,"results":"5008","hashOfConfig":"4558"},{"size":818,"mtime":1678221097037,"results":"5009","hashOfConfig":"4558"},{"size":6736,"mtime":1678221097037,"results":"5010","hashOfConfig":"4558"},{"size":835,"mtime":1678221097037,"results":"5011","hashOfConfig":"4558"},{"size":633,"mtime":1675188401409,"results":"5012","hashOfConfig":"4558"},{"size":525,"mtime":1675188401409,"results":"5013","hashOfConfig":"4558"},{"size":2618,"mtime":1675188401409,"results":"5014","hashOfConfig":"4558"},{"size":8024,"mtime":1678221097038,"results":"5015","hashOfConfig":"4558"},{"size":284,"mtime":1675188401409,"results":"5016","hashOfConfig":"4558"},{"size":1724,"mtime":1678221097038,"results":"5017","hashOfConfig":"4558"},{"size":10295,"mtime":1678221097038,"results":"5018","hashOfConfig":"4558"},{"size":9919,"mtime":1675694258652,"results":"5019","hashOfConfig":"4558"},{"size":4857,"mtime":1675694258652,"results":"5020","hashOfConfig":"4558"},{"size":267,"mtime":1675188401409,"results":"5021","hashOfConfig":"4558"},{"size":4819,"mtime":1678221097038,"results":"5022","hashOfConfig":"4558"},{"size":1800,"mtime":1678221097038,"results":"5023","hashOfConfig":"4558"},{"size":89,"mtime":1678221097038,"results":"5024","hashOfConfig":"4558"},{"size":7926,"mtime":1678221097039,"results":"5025","hashOfConfig":"4558"},{"size":1352,"mtime":1675188401410,"results":"5026","hashOfConfig":"4558"},{"size":1048,"mtime":1675188401410,"results":"5027","hashOfConfig":"4558"},{"size":282,"mtime":1675188401410,"results":"5028","hashOfConfig":"4558"},{"size":32,"mtime":1678221097040,"results":"5029","hashOfConfig":"4558"},{"size":5207,"mtime":1675188401416,"results":"5030","hashOfConfig":"4558"},{"size":76,"mtime":1678221097041,"results":"5031","hashOfConfig":"4558"},{"size":92,"mtime":1675188401414,"results":"5032","hashOfConfig":"4558"},{"size":958,"mtime":1675188401414,"results":"5033","hashOfConfig":"4558"},{"size":187,"mtime":1675188401414,"results":"5034","hashOfConfig":"4558"},{"size":2146,"mtime":1675188401414,"results":"5035","hashOfConfig":"4558"},{"size":3040,"mtime":1675188401414,"results":"5036","hashOfConfig":"4558"},{"size":3529,"mtime":1675188401414,"results":"5037","hashOfConfig":"4558"},{"size":2724,"mtime":1678221097040,"results":"5038","hashOfConfig":"4558"},{"size":4799,"mtime":1675188401414,"results":"5039","hashOfConfig":"4558"},{"size":1856,"mtime":1675188401414,"results":"5040","hashOfConfig":"4558"},{"size":787,"mtime":1675188401414,"results":"5041","hashOfConfig":"4558"},{"size":288,"mtime":1675188401414,"results":"5042","hashOfConfig":"4558"},{"size":19755,"mtime":1678321762661,"results":"5043","hashOfConfig":"4558"},{"size":2543,"mtime":1678221097040,"results":"5044","hashOfConfig":"4558"},{"size":1228,"mtime":1675188401415,"results":"5045","hashOfConfig":"4558"},{"size":681,"mtime":1678321762661,"results":"5046","hashOfConfig":"4558"},{"size":428,"mtime":1675188401415,"results":"5047","hashOfConfig":"4558"},{"size":889,"mtime":1675188401415,"results":"5048","hashOfConfig":"4558"},{"size":4662,"mtime":1678221097040,"results":"5049","hashOfConfig":"4558"},{"size":6845,"mtime":1678321762661,"results":"5050","hashOfConfig":"4558"},{"size":3479,"mtime":1675188401415,"results":"5051","hashOfConfig":"4558"},{"size":2912,"mtime":1675188401415,"results":"5052","hashOfConfig":"4558"},{"size":3371,"mtime":1675188401415,"results":"5053","hashOfConfig":"4558"},{"size":71,"mtime":1678221097041,"results":"5054","hashOfConfig":"4558"},{"size":1191,"mtime":1675188401416,"results":"5055","hashOfConfig":"4558"},{"size":44,"mtime":1678221097041,"results":"5056","hashOfConfig":"4558"},{"size":884,"mtime":1675188401416,"results":"5057","hashOfConfig":"4558"},{"size":60,"mtime":1678221097041,"results":"5058","hashOfConfig":"4558"},{"size":1729,"mtime":1675188401416,"results":"5059","hashOfConfig":"4558"},{"size":44,"mtime":1678221097041,"results":"5060","hashOfConfig":"4558"},{"size":955,"mtime":1675188401417,"results":"5061","hashOfConfig":"4558"},{"size":3221,"mtime":1675188401417,"results":"5062","hashOfConfig":"4558"},{"size":739,"mtime":1675188401417,"results":"5063","hashOfConfig":"4558"},{"size":1426,"mtime":1675188401417,"results":"5064","hashOfConfig":"4558"},{"size":64,"mtime":1675188401417,"results":"5065","hashOfConfig":"4558"},{"size":32,"mtime":1678221097041,"results":"5066","hashOfConfig":"4558"},{"size":956,"mtime":1678221097041,"results":"5067","hashOfConfig":"4558"},{"size":26,"mtime":1675188401417,"results":"5068","hashOfConfig":"4558"},{"size":555,"mtime":1675188401417,"results":"5069","hashOfConfig":"4558"},{"size":596,"mtime":1675188401417,"results":"5070","hashOfConfig":"4558"},{"size":56,"mtime":1675188401417,"results":"5071","hashOfConfig":"4558"},{"size":158,"mtime":1675188401420,"results":"5072","hashOfConfig":"4558"},{"size":588,"mtime":1675188401420,"results":"5073","hashOfConfig":"4558"},{"size":1641,"mtime":1675188401420,"results":"5074","hashOfConfig":"4558"},{"size":1129,"mtime":1675188401420,"results":"5075","hashOfConfig":"4558"},{"size":24852,"mtime":1678221097041,"results":"5076","hashOfConfig":"4558"},{"size":13885,"mtime":1675188401421,"results":"5077","hashOfConfig":"4558"},{"size":408,"mtime":1675188401421,"results":"5078","hashOfConfig":"4558"},{"size":503,"mtime":1675188401421,"results":"5079","hashOfConfig":"4558"},{"size":857,"mtime":1675188401421,"results":"5080","hashOfConfig":"4558"},{"size":827,"mtime":1675188401421,"results":"5081","hashOfConfig":"4558"},{"size":431,"mtime":1675188401421,"results":"5082","hashOfConfig":"4558"},{"size":3436,"mtime":1675188401421,"results":"5083","hashOfConfig":"4558"},{"size":504,"mtime":1675188401421,"results":"5084","hashOfConfig":"4558"},{"size":796,"mtime":1675188401421,"results":"5085","hashOfConfig":"4558"},{"size":3171,"mtime":1675188401421,"results":"5086","hashOfConfig":"4558"},{"size":2494,"mtime":1675694258654,"results":"5087","hashOfConfig":"4558"},{"size":1255,"mtime":1675188401421,"results":"5088","hashOfConfig":"4558"},{"size":740,"mtime":1675188401421,"results":"5089","hashOfConfig":"4558"},{"size":230,"mtime":1675188401421,"results":"5090","hashOfConfig":"4558"},{"size":1905,"mtime":1675188401422,"results":"5091","hashOfConfig":"4558"},{"size":2079,"mtime":1675188401422,"results":"5092","hashOfConfig":"4558"},{"size":181,"mtime":1675188401422,"results":"5093","hashOfConfig":"4558"},{"size":1219,"mtime":1675188401422,"results":"5094","hashOfConfig":"4558"},{"size":600,"mtime":1675188401422,"results":"5095","hashOfConfig":"4558"},{"size":137,"mtime":1675188401418,"results":"5096","hashOfConfig":"4558"},{"size":18,"mtime":1675188401418,"results":"5097","hashOfConfig":"4558"},{"size":308,"mtime":1675188401418,"results":"5098","hashOfConfig":"4558"},{"size":6750,"mtime":1675188401418,"results":"5099","hashOfConfig":"4558"},{"size":192,"mtime":1675188401418,"results":"5100","hashOfConfig":"4558"},{"size":165,"mtime":1675188401418,"results":"5101","hashOfConfig":"4558"},{"size":18,"mtime":1675188401418,"results":"5102","hashOfConfig":"4558"},{"size":379,"mtime":1675188401418,"results":"5103","hashOfConfig":"4558"},{"size":9333,"mtime":1675188401418,"results":"5104","hashOfConfig":"4558"},{"size":248,"mtime":1675188401418,"results":"5105","hashOfConfig":"4558"},{"size":1933,"mtime":1675188401419,"results":"5106","hashOfConfig":"4558"},{"size":227,"mtime":1675188401419,"results":"5107","hashOfConfig":"4558"},{"size":200,"mtime":1675188401419,"results":"5108","hashOfConfig":"4558"},{"size":5430,"mtime":1675188401419,"results":"5109","hashOfConfig":"4558"},{"size":219,"mtime":1675188401419,"results":"5110","hashOfConfig":"4558"},{"size":194,"mtime":1675188401419,"results":"5111","hashOfConfig":"4558"},{"size":141,"mtime":1675188401420,"results":"5112","hashOfConfig":"4558"},{"size":18,"mtime":1675188401420,"results":"5113","hashOfConfig":"4558"},{"size":187,"mtime":1675188401420,"results":"5114","hashOfConfig":"4558"},{"size":17044,"mtime":1675188401420,"results":"5115","hashOfConfig":"4558"},{"size":200,"mtime":1675188401420,"results":"5116","hashOfConfig":"4558"},{"size":151,"mtime":1675188401419,"results":"5117","hashOfConfig":"4558"},{"size":18,"mtime":1675188401419,"results":"5118","hashOfConfig":"4558"},{"size":343,"mtime":1675188401419,"results":"5119","hashOfConfig":"4558"},{"size":1836,"mtime":1675188401419,"results":"5120","hashOfConfig":"4558"},{"size":220,"mtime":1675188401419,"results":"5121","hashOfConfig":"4558"},{"size":126,"mtime":1675188401422,"results":"5122","hashOfConfig":"4558"},{"size":1487,"mtime":1675188401422,"results":"5123","hashOfConfig":"4558"},{"size":13186,"mtime":1678221097042,"results":"5124","hashOfConfig":"4558"},{"size":705,"mtime":1675188401422,"results":"5125","hashOfConfig":"4558"},{"size":2205,"mtime":1675188401422,"results":"5126","hashOfConfig":"4558"},{"size":25990,"mtime":1678221097042,"results":"5127","hashOfConfig":"4558"},{"size":6877,"mtime":1675188401423,"results":"5128","hashOfConfig":"4558"},{"size":216,"mtime":1675188401423,"results":"5129","hashOfConfig":"4558"},{"size":1249,"mtime":1675188401423,"results":"5130","hashOfConfig":"4558"},{"size":4335,"mtime":1678221097042,"results":"5131","hashOfConfig":"4558"},{"size":945,"mtime":1675188401423,"results":"5132","hashOfConfig":"4558"},{"size":4294,"mtime":1678221097042,"results":"5133","hashOfConfig":"4558"},{"size":1685,"mtime":1675188401423,"results":"5134","hashOfConfig":"4558"},{"size":1135,"mtime":1675188401423,"results":"5135","hashOfConfig":"4558"},{"size":1309,"mtime":1675188401423,"results":"5136","hashOfConfig":"4558"},{"size":2727,"mtime":1675188401423,"results":"5137","hashOfConfig":"4558"},{"size":1236,"mtime":1675188401423,"results":"5138","hashOfConfig":"4558"},{"size":3188,"mtime":1678221097042,"results":"5139","hashOfConfig":"4558"},{"size":451,"mtime":1675188401424,"results":"5140","hashOfConfig":"4558"},{"size":822,"mtime":1675188401424,"results":"5141","hashOfConfig":"4558"},{"size":1697,"mtime":1678221097042,"results":"5142","hashOfConfig":"4558"},{"size":1757,"mtime":1678221097042,"results":"5143","hashOfConfig":"4558"},{"size":1240,"mtime":1675188401424,"results":"5144","hashOfConfig":"4558"},{"size":32,"mtime":1675188401424,"results":"5145","hashOfConfig":"4558"},{"size":80,"mtime":1675188401424,"results":"5146","hashOfConfig":"4558"},{"size":5675,"mtime":1678221097043,"results":"5147","hashOfConfig":"4558"},{"size":378,"mtime":1675188401424,"results":"5148","hashOfConfig":"4558"},{"size":346,"mtime":1675188401424,"results":"5149","hashOfConfig":"4558"},{"size":988,"mtime":1675188401424,"results":"5150","hashOfConfig":"4558"},{"size":109,"mtime":1675188401425,"results":"5151","hashOfConfig":"4558"},{"size":108,"mtime":1675188401425,"results":"5152","hashOfConfig":"4558"},{"size":1045,"mtime":1675188401425,"results":"5153","hashOfConfig":"4558"},{"size":187,"mtime":1675188401425,"results":"5154","hashOfConfig":"4558"},{"size":1089,"mtime":1675188401425,"results":"5155","hashOfConfig":"4558"},{"size":303,"mtime":1675188401425,"results":"5156","hashOfConfig":"4558"},{"size":354,"mtime":1675188401425,"results":"5157","hashOfConfig":"4558"},{"size":681,"mtime":1675188401425,"results":"5158","hashOfConfig":"4558"},{"size":565,"mtime":1675188401425,"results":"5159","hashOfConfig":"4558"},{"size":494,"mtime":1675188401425,"results":"5160","hashOfConfig":"4558"},{"size":1026,"mtime":1675188401425,"results":"5161","hashOfConfig":"4558"},{"size":1114,"mtime":1675188401425,"results":"5162","hashOfConfig":"4558"},{"size":1504,"mtime":1675188401425,"results":"5163","hashOfConfig":"4558"},{"size":651,"mtime":1675188401425,"results":"5164","hashOfConfig":"4558"},{"size":1531,"mtime":1675188401425,"results":"5165","hashOfConfig":"4558"},{"size":7462,"mtime":1675188401426,"results":"5166","hashOfConfig":"4558"},{"size":4054,"mtime":1675188401426,"results":"5167","hashOfConfig":"4558"},{"size":1811,"mtime":1675188401426,"results":"5168","hashOfConfig":"4558"},{"size":1595,"mtime":1675188401426,"results":"5169","hashOfConfig":"4558"},{"size":2190,"mtime":1675188401426,"results":"5170","hashOfConfig":"4558"},{"size":54,"mtime":1675188401426,"results":"5171","hashOfConfig":"4558"},{"size":6344,"mtime":1675188401426,"results":"5172","hashOfConfig":"4558"},{"size":21,"mtime":1675188401427,"results":"5173","hashOfConfig":"4558"},{"size":840,"mtime":1675188401427,"results":"5174","hashOfConfig":"4558"},{"size":816,"mtime":1678221097043,"results":"5175","hashOfConfig":"4558"},{"size":226,"mtime":1675188401427,"results":"5176","hashOfConfig":"4558"},{"size":1145,"mtime":1675188401427,"results":"5177","hashOfConfig":"4558"},{"size":1320,"mtime":1675188401427,"results":"5178","hashOfConfig":"4558"},{"size":116,"mtime":1675188401427,"results":"5179","hashOfConfig":"4558"},{"size":1513,"mtime":1678221097043,"results":"5180","hashOfConfig":"4558"},{"size":359,"mtime":1675188401428,"results":"5181","hashOfConfig":"4558"},{"size":1780,"mtime":1675188401428,"results":"5182","hashOfConfig":"4558"},{"size":187,"mtime":1675188401428,"results":"5183","hashOfConfig":"4558"},{"size":8241,"mtime":1675694258654,"results":"5184","hashOfConfig":"4558"},{"size":8639,"mtime":1675188401428,"results":"5185","hashOfConfig":"4558"},{"size":937,"mtime":1675188401428,"results":"5186","hashOfConfig":"4558"},{"size":3762,"mtime":1678221097043,"results":"5187","hashOfConfig":"4558"},{"size":435,"mtime":1675188401428,"results":"5188","hashOfConfig":"4558"},{"size":724,"mtime":1675188401428,"results":"5189","hashOfConfig":"4558"},{"size":299,"mtime":1678221097043,"results":"5190","hashOfConfig":"4558"},{"size":1555,"mtime":1678221097043,"results":"5191","hashOfConfig":"4558"},{"size":2427,"mtime":1678221097044,"results":"5192","hashOfConfig":"4558"},{"size":857,"mtime":1678221097044,"results":"5193","hashOfConfig":"4558"},{"size":5304,"mtime":1678221097044,"results":"5194","hashOfConfig":"4558"},{"size":5229,"mtime":1678221097044,"results":"5195","hashOfConfig":"4558"},{"size":2557,"mtime":1678221097044,"results":"5196","hashOfConfig":"4558"},{"size":510,"mtime":1675188401429,"results":"5197","hashOfConfig":"4558"},{"size":3625,"mtime":1678221097044,"results":"5198","hashOfConfig":"4558"},{"size":4509,"mtime":1675694258655,"results":"5199","hashOfConfig":"4558"},{"size":2553,"mtime":1675188401429,"results":"5200","hashOfConfig":"4558"},{"size":2818,"mtime":1675188401429,"results":"5201","hashOfConfig":"4558"},{"size":3048,"mtime":1675188401429,"results":"5202","hashOfConfig":"4558"},{"size":321,"mtime":1675188401429,"results":"5203","hashOfConfig":"4558"},{"size":466,"mtime":1678221097044,"results":"5204","hashOfConfig":"4558"},{"size":1234,"mtime":1675188401429,"results":"5205","hashOfConfig":"4558"},{"size":2083,"mtime":1675188401429,"results":"5206","hashOfConfig":"4558"},{"size":2084,"mtime":1678221097044,"results":"5207","hashOfConfig":"4558"},{"size":851,"mtime":1675188401430,"results":"5208","hashOfConfig":"4558"},{"size":366,"mtime":1675188401430,"results":"5209","hashOfConfig":"4558"},{"size":1878,"mtime":1678221097045,"results":"5210","hashOfConfig":"4558"},{"size":2240,"mtime":1678221097045,"results":"5211","hashOfConfig":"4558"},{"size":7013,"mtime":1678221097045,"results":"5212","hashOfConfig":"4558"},{"size":2227,"mtime":1675188401430,"results":"5213","hashOfConfig":"4558"},{"size":3001,"mtime":1675188401430,"results":"5214","hashOfConfig":"4558"},{"size":591,"mtime":1675188401430,"results":"5215","hashOfConfig":"4558"},{"size":3446,"mtime":1678221097045,"results":"5216","hashOfConfig":"4558"},{"size":1335,"mtime":1675188401430,"results":"5217","hashOfConfig":"4558"},{"size":1986,"mtime":1678221097045,"results":"5218","hashOfConfig":"4558"},{"size":435,"mtime":1678221097045,"results":"5219","hashOfConfig":"4558"},{"size":1388,"mtime":1678221097046,"results":"5220","hashOfConfig":"4558"},{"size":12923,"mtime":1678221097046,"results":"5221","hashOfConfig":"4558"},{"size":3329,"mtime":1675188401431,"results":"5222","hashOfConfig":"4558"},{"size":7037,"mtime":1678221097046,"results":"5223","hashOfConfig":"4558"},{"size":2368,"mtime":1678221097046,"results":"5224","hashOfConfig":"4558"},{"size":1438,"mtime":1678221097046,"results":"5225","hashOfConfig":"4558"},{"size":1484,"mtime":1678221097046,"results":"5226","hashOfConfig":"4558"},{"size":1444,"mtime":1678221097047,"results":"5227","hashOfConfig":"4558"},{"size":4959,"mtime":1678221097047,"results":"5228","hashOfConfig":"4558"},{"size":3640,"mtime":1678221097047,"results":"5229","hashOfConfig":"4558"},{"size":3339,"mtime":1678221097047,"results":"5230","hashOfConfig":"4558"},{"size":311,"mtime":1675188401431,"results":"5231","hashOfConfig":"4558"},{"size":2243,"mtime":1675188401431,"results":"5232","hashOfConfig":"4558"},{"size":2486,"mtime":1678221097047,"results":"5233","hashOfConfig":"4558"},{"size":1746,"mtime":1678221097048,"results":"5234","hashOfConfig":"4558"},{"size":366,"mtime":1675188401432,"results":"5235","hashOfConfig":"4558"},{"size":1873,"mtime":1678221097048,"results":"5236","hashOfConfig":"4558"},{"size":5688,"mtime":1675188401432,"results":"5237","hashOfConfig":"4558"},{"size":1421,"mtime":1675188401432,"results":"5238","hashOfConfig":"4558"},{"size":921,"mtime":1675188401432,"results":"5239","hashOfConfig":"4558"},{"size":3363,"mtime":1678221097048,"results":"5240","hashOfConfig":"4558"},{"size":16902,"mtime":1675188401432,"results":"5241","hashOfConfig":"4558"},{"size":413,"mtime":1675694258656,"results":"5242","hashOfConfig":"4558"},{"size":766,"mtime":1675188401432,"results":"5243","hashOfConfig":"4558"},{"size":749,"mtime":1675188401432,"results":"5244","hashOfConfig":"4558"},{"size":3673,"mtime":1675188401432,"results":"5245","hashOfConfig":"4558"},{"size":485,"mtime":1675188401432,"results":"5246","hashOfConfig":"4558"},{"size":4095,"mtime":1675188401433,"results":"5247","hashOfConfig":"4558"},{"size":136,"mtime":1675188401433,"results":"5248","hashOfConfig":"4558"},{"size":6548,"mtime":1678221097048,"results":"5249","hashOfConfig":"4558"},{"size":1306,"mtime":1675188401433,"results":"5250","hashOfConfig":"4558"},{"size":3255,"mtime":1675188401433,"results":"5251","hashOfConfig":"4558"},{"size":10656,"mtime":1675188401433,"results":"5252","hashOfConfig":"4558"},{"size":1959,"mtime":1675188401433,"results":"5253","hashOfConfig":"4558"},{"size":696,"mtime":1675188401433,"results":"5254","hashOfConfig":"4558"},{"size":181,"mtime":1675188401433,"results":"5255","hashOfConfig":"4558"},{"size":3127,"mtime":1678221097048,"results":"5256","hashOfConfig":"4558"},{"size":1191,"mtime":1678221097048,"results":"5257","hashOfConfig":"4558"},{"size":1183,"mtime":1678221097049,"results":"5258","hashOfConfig":"4558"},{"size":289,"mtime":1675188401433,"results":"5259","hashOfConfig":"4558"},{"size":1023,"mtime":1675694258656,"results":"5260","hashOfConfig":"4558"},{"size":1225,"mtime":1675188401434,"results":"5261","hashOfConfig":"4558"},{"size":810,"mtime":1675188401434,"results":"5262","hashOfConfig":"4558"},{"size":795,"mtime":1675188401434,"results":"5263","hashOfConfig":"4558"},{"size":662,"mtime":1675188401434,"results":"5264","hashOfConfig":"4558"},{"size":1045,"mtime":1675694258656,"results":"5265","hashOfConfig":"4558"},{"size":1763,"mtime":1678221097049,"results":"5266","hashOfConfig":"4558"},{"size":1425,"mtime":1678221097049,"results":"5267","hashOfConfig":"4558"},{"size":1769,"mtime":1678221097049,"results":"5268","hashOfConfig":"4558"},{"size":1783,"mtime":1678221097049,"results":"5269","hashOfConfig":"4558"},{"size":1715,"mtime":1675188401434,"results":"5270","hashOfConfig":"4558"},{"size":3100,"mtime":1678221097049,"results":"5271","hashOfConfig":"4558"},{"size":777,"mtime":1675188401434,"results":"5272","hashOfConfig":"4558"},{"size":635,"mtime":1675188401434,"results":"5273","hashOfConfig":"4558"},{"size":944,"mtime":1675188401434,"results":"5274","hashOfConfig":"4558"},{"size":671,"mtime":1675188401434,"results":"5275","hashOfConfig":"4558"},{"size":1186,"mtime":1678221097049,"results":"5276","hashOfConfig":"4558"},{"size":324,"mtime":1678221097050,"results":"5277","hashOfConfig":"4558"},{"size":368,"mtime":1675188401435,"results":"5278","hashOfConfig":"4558"},{"size":495,"mtime":1675188401435,"results":"5279","hashOfConfig":"4558"},{"size":529,"mtime":1675188401435,"results":"5280","hashOfConfig":"4558"},{"size":1364,"mtime":1678221097050,"results":"5281","hashOfConfig":"4558"},{"size":2001,"mtime":1678221097050,"results":"5282","hashOfConfig":"4558"},{"size":864,"mtime":1675188401435,"results":"5283","hashOfConfig":"4558"},{"size":2786,"mtime":1675188401435,"results":"5284","hashOfConfig":"4558"},{"size":722,"mtime":1675188401435,"results":"5285","hashOfConfig":"4558"},{"size":474,"mtime":1675188401435,"results":"5286","hashOfConfig":"4558"},{"size":1469,"mtime":1675188401435,"results":"5287","hashOfConfig":"4558"},{"size":1901,"mtime":1675188401435,"results":"5288","hashOfConfig":"4558"},{"size":3402,"mtime":1678221097050,"results":"5289","hashOfConfig":"4558"},{"size":1177,"mtime":1678221097050,"results":"5290","hashOfConfig":"4558"},{"size":1073,"mtime":1678221097050,"results":"5291","hashOfConfig":"4558"},{"size":980,"mtime":1675188401436,"results":"5292","hashOfConfig":"4558"},{"size":817,"mtime":1675188401436,"results":"5293","hashOfConfig":"4558"},{"size":2175,"mtime":1675188401436,"results":"5294","hashOfConfig":"4558"},{"size":804,"mtime":1675188401436,"results":"5295","hashOfConfig":"4558"},{"size":749,"mtime":1675188401436,"results":"5296","hashOfConfig":"4558"},{"size":3356,"mtime":1678221097050,"results":"5297","hashOfConfig":"4558"},{"size":1497,"mtime":1675188401436,"results":"5298","hashOfConfig":"4558"},{"size":1793,"mtime":1675188401436,"results":"5299","hashOfConfig":"4558"},{"size":1780,"mtime":1675188401436,"results":"5300","hashOfConfig":"4558"},{"size":452,"mtime":1675188401436,"results":"5301","hashOfConfig":"4558"},{"size":1454,"mtime":1675188401436,"results":"5302","hashOfConfig":"4558"},{"size":13657,"mtime":1678221097051,"results":"5303","hashOfConfig":"4558"},{"size":219,"mtime":1675188401436,"results":"5304","hashOfConfig":"4558"},{"size":8144,"mtime":1675188401436,"results":"5305","hashOfConfig":"4558"},{"size":7471,"mtime":1675188401437,"results":"5306","hashOfConfig":"4558"},{"size":374,"mtime":1675188401437,"results":"5307","hashOfConfig":"4558"},{"size":73792,"mtime":1678221097051,"results":"5308","hashOfConfig":"4558"},{"size":1397,"mtime":1678221097051,"results":"5309","hashOfConfig":"4558"},{"size":1191,"mtime":1675188401437,"results":"5310","hashOfConfig":"4558"},{"size":1062,"mtime":1675188401437,"results":"5311","hashOfConfig":"4558"},{"size":919,"mtime":1675188401437,"results":"5312","hashOfConfig":"4558"},{"size":132,"mtime":1675188401437,"results":"5313","hashOfConfig":"4558"},{"size":98,"mtime":1675188401437,"results":"5314","hashOfConfig":"4558"},{"size":123,"mtime":1675188401437,"results":"5315","hashOfConfig":"4558"},{"size":1671,"mtime":1675188401438,"results":"5316","hashOfConfig":"4558"},{"size":1361,"mtime":1675188401438,"results":"5317","hashOfConfig":"4558"},{"size":269,"mtime":1675188401438,"results":"5318","hashOfConfig":"4558"},{"size":81,"mtime":1675188401438,"results":"5319","hashOfConfig":"4558"},{"size":548,"mtime":1675188401438,"results":"5320","hashOfConfig":"4558"},{"size":182,"mtime":1675188401438,"results":"5321","hashOfConfig":"4558"},{"size":5347,"mtime":1675188401438,"results":"5322","hashOfConfig":"4558"},{"size":224,"mtime":1675188401438,"results":"5323","hashOfConfig":"4558"},{"size":3901,"mtime":1678221097051,"results":"5324","hashOfConfig":"4558"},{"size":929,"mtime":1675188401438,"results":"5325","hashOfConfig":"4558"},{"size":909,"mtime":1675694258658,"results":"5326","hashOfConfig":"4558"},{"size":646,"mtime":1675694258658,"results":"5327","hashOfConfig":"4558"},{"size":1058,"mtime":1675188401439,"results":"5328","hashOfConfig":"4558"},{"size":269,"mtime":1675188401439,"results":"5329","hashOfConfig":"4558"},{"size":367,"mtime":1675188401439,"results":"5330","hashOfConfig":"4558"},{"size":1602,"mtime":1675188401439,"results":"5331","hashOfConfig":"4558"},{"size":680,"mtime":1675188401439,"results":"5332","hashOfConfig":"4558"},{"size":362,"mtime":1675188401439,"results":"5333","hashOfConfig":"4558"},{"size":561,"mtime":1675188401439,"results":"5334","hashOfConfig":"4558"},{"size":7778,"mtime":1675188401439,"results":"5335","hashOfConfig":"4558"},{"size":8673,"mtime":1678221097052,"results":"5336","hashOfConfig":"4558"},{"size":3907,"mtime":1675694258658,"results":"5337","hashOfConfig":"4558"},{"size":342,"mtime":1675188401439,"results":"5338","hashOfConfig":"4558"},{"size":770,"mtime":1675188401439,"results":"5339","hashOfConfig":"4558"},{"size":2971,"mtime":1675694258658,"results":"5340","hashOfConfig":"4558"},{"size":5947,"mtime":1678221097052,"results":"5341","hashOfConfig":"4558"},{"size":919,"mtime":1675188401440,"results":"5342","hashOfConfig":"4558"},{"size":2200,"mtime":1675188401440,"results":"5343","hashOfConfig":"4558"},{"size":3471,"mtime":1675188401440,"results":"5344","hashOfConfig":"4558"},{"size":5048,"mtime":1675694258658,"results":"5345","hashOfConfig":"4558"},{"size":241,"mtime":1675188401440,"results":"5346","hashOfConfig":"4558"},{"size":774,"mtime":1678221097052,"results":"5347","hashOfConfig":"4558"},{"size":4336,"mtime":1675694258658,"results":"5348","hashOfConfig":"4558"},{"size":89,"mtime":1675188401440,"results":"5349","hashOfConfig":"4558"},{"size":579,"mtime":1675694258658,"results":"5350","hashOfConfig":"4558"},{"size":1010,"mtime":1675694258658,"results":"5351","hashOfConfig":"4558"},{"size":370,"mtime":1675188401440,"results":"5352","hashOfConfig":"4558"},{"size":1218,"mtime":1675694258658,"results":"5353","hashOfConfig":"4558"},{"size":5574,"mtime":1678221097052,"results":"5354","hashOfConfig":"4558"},{"size":2871,"mtime":1678221097052,"results":"5355","hashOfConfig":"4558"},{"size":615,"mtime":1675694258659,"results":"5356","hashOfConfig":"4558"},{"size":7204,"mtime":1678221097052,"results":"5357","hashOfConfig":"4558"},{"size":966,"mtime":1675694258659,"results":"5358","hashOfConfig":"4558"},{"size":1998,"mtime":1675694258659,"results":"5359","hashOfConfig":"4558"},{"size":1109,"mtime":1678221097053,"results":"5360","hashOfConfig":"4558"},{"size":879,"mtime":1675694258659,"results":"5361","hashOfConfig":"4558"},{"size":1827,"mtime":1675188401441,"results":"5362","hashOfConfig":"4558"},{"size":4859,"mtime":1675694258659,"results":"5363","hashOfConfig":"4558"},{"size":315,"mtime":1675694258659,"results":"5364","hashOfConfig":"4558"},{"size":3104,"mtime":1675188401441,"results":"5365","hashOfConfig":"4558"},{"size":1193,"mtime":1678221097053,"results":"5366","hashOfConfig":"4558"},{"size":2280,"mtime":1675188401441,"results":"5367","hashOfConfig":"4558"},{"size":2314,"mtime":1675188401442,"results":"5368","hashOfConfig":"4558"},{"size":7117,"mtime":1675188401442,"results":"5369","hashOfConfig":"4558"},{"size":702,"mtime":1675188401442,"results":"5370","hashOfConfig":"4558"},{"size":624,"mtime":1675188401442,"results":"5371","hashOfConfig":"4558"},{"size":13271,"mtime":1678221097053,"results":"5372","hashOfConfig":"4558"},{"size":646,"mtime":1678221097053,"results":"5373","hashOfConfig":"4558"},{"size":746,"mtime":1675188401442,"results":"5374","hashOfConfig":"4558"},{"size":2704,"mtime":1675188401442,"results":"5375","hashOfConfig":"4558"},{"size":4936,"mtime":1675188401442,"results":"5376","hashOfConfig":"4558"},{"size":2067,"mtime":1675694258659,"results":"5377","hashOfConfig":"4558"},{"size":589,"mtime":1678221097052,"results":"5378","hashOfConfig":"4558"},{"size":4622,"mtime":1678221097053,"results":"5379","hashOfConfig":"4558"},{"size":5634,"mtime":1675188401442,"results":"5380","hashOfConfig":"4558"},{"size":1171,"mtime":1675188401442,"results":"5381","hashOfConfig":"4558"},{"size":2574,"mtime":1678221097053,"results":"5382","hashOfConfig":"4558"},{"size":1681,"mtime":1675188401443,"results":"5383","hashOfConfig":"4558"},{"size":957,"mtime":1675188401443,"results":"5384","hashOfConfig":"4558"},{"size":18197,"mtime":1678221097053,"results":"5385","hashOfConfig":"4558"},{"size":275,"mtime":1675188401443,"results":"5386","hashOfConfig":"4558"},{"size":48,"mtime":1675188401443,"results":"5387","hashOfConfig":"4558"},{"size":931,"mtime":1675188401443,"results":"5388","hashOfConfig":"4558"},{"size":970,"mtime":1675188401443,"results":"5389","hashOfConfig":"4558"},{"size":614,"mtime":1675188401443,"results":"5390","hashOfConfig":"4558"},{"size":1500,"mtime":1675188401443,"results":"5391","hashOfConfig":"4558"},{"size":692,"mtime":1675188401443,"results":"5392","hashOfConfig":"4558"},{"size":847,"mtime":1675188401443,"results":"5393","hashOfConfig":"4558"},{"size":572,"mtime":1675188401443,"results":"5394","hashOfConfig":"4558"},{"size":2001,"mtime":1675188401443,"results":"5395","hashOfConfig":"4558"},{"size":3625,"mtime":1678221097054,"results":"5396","hashOfConfig":"4558"},{"size":3207,"mtime":1675188401444,"results":"5397","hashOfConfig":"4558"},{"size":381,"mtime":1675188401444,"results":"5398","hashOfConfig":"4558"},{"size":851,"mtime":1678221097054,"results":"5399","hashOfConfig":"4558"},{"size":512,"mtime":1675188401444,"results":"5400","hashOfConfig":"4558"},{"size":2025,"mtime":1678221097054,"results":"5401","hashOfConfig":"4558"},{"size":6418,"mtime":1678221097054,"results":"5402","hashOfConfig":"4558"},{"size":2750,"mtime":1678221097054,"results":"5403","hashOfConfig":"4558"},{"size":22086,"mtime":1675188401444,"results":"5404","hashOfConfig":"4558"},{"size":3457,"mtime":1678221097054,"results":"5405","hashOfConfig":"4558"},{"size":2074,"mtime":1678221097054,"results":"5406","hashOfConfig":"4558"},{"size":17500,"mtime":1678221097055,"results":"5407","hashOfConfig":"4558"},{"size":38103,"mtime":1678221097055,"results":"5408","hashOfConfig":"4558"},{"size":715,"mtime":1678221097055,"results":"5409","hashOfConfig":"4558"},{"size":9549,"mtime":1678221097055,"results":"5410","hashOfConfig":"4558"},{"size":3845,"mtime":1678221097055,"results":"5411","hashOfConfig":"4558"},{"size":7613,"mtime":1678221097055,"results":"5412","hashOfConfig":"4558"},{"size":1928,"mtime":1675188401445,"results":"5413","hashOfConfig":"4558"},{"size":10473,"mtime":1675188401445,"results":"5414","hashOfConfig":"4558"},{"size":5509,"mtime":1675188401445,"results":"5415","hashOfConfig":"4558"},{"size":132,"mtime":1675188401445,"results":"5416","hashOfConfig":"4558"},{"size":1029,"mtime":1675188401445,"results":"5417","hashOfConfig":"4558"},{"size":1722,"mtime":1675188401445,"results":"5418","hashOfConfig":"4558"},{"size":676,"mtime":1675188401445,"results":"5419","hashOfConfig":"4558"},{"size":371,"mtime":1678221097055,"results":"5420","hashOfConfig":"4558"},{"size":1822,"mtime":1678221097056,"results":"5421","hashOfConfig":"4558"},{"size":1336,"mtime":1675188401446,"results":"5422","hashOfConfig":"4558"},{"size":624,"mtime":1675188401446,"results":"5423","hashOfConfig":"4558"},{"size":634,"mtime":1675188401446,"results":"5424","hashOfConfig":"4558"},{"size":1910,"mtime":1675188401446,"results":"5425","hashOfConfig":"4558"},{"size":3355,"mtime":1678221097056,"results":"5426","hashOfConfig":"4558"},{"size":1037,"mtime":1678221097056,"results":"5427","hashOfConfig":"4558"},{"size":680,"mtime":1675188401446,"results":"5428","hashOfConfig":"4558"},{"size":795,"mtime":1675188401446,"results":"5429","hashOfConfig":"4558"},{"size":790,"mtime":1675188401447,"results":"5430","hashOfConfig":"4558"},{"size":975,"mtime":1675188401447,"results":"5431","hashOfConfig":"4558"},{"size":416,"mtime":1675188401447,"results":"5432","hashOfConfig":"4558"},{"size":725,"mtime":1675188401447,"results":"5433","hashOfConfig":"4558"},{"size":906,"mtime":1675188401447,"results":"5434","hashOfConfig":"4558"},{"size":905,"mtime":1675188401447,"results":"5435","hashOfConfig":"4558"},{"size":193,"mtime":1675188401447,"results":"5436","hashOfConfig":"4558"},{"size":542,"mtime":1675188401447,"results":"5437","hashOfConfig":"4558"},{"size":1061,"mtime":1675188401447,"results":"5438","hashOfConfig":"4558"},{"size":532,"mtime":1675188401447,"results":"5439","hashOfConfig":"4558"},{"size":412,"mtime":1675188401447,"results":"5440","hashOfConfig":"4558"},{"size":1599,"mtime":1675188401447,"results":"5441","hashOfConfig":"4558"},{"size":644,"mtime":1675188401447,"results":"5442","hashOfConfig":"4558"},{"size":1118,"mtime":1678221097056,"results":"5443","hashOfConfig":"4558"},{"size":797,"mtime":1675188401447,"results":"5444","hashOfConfig":"4558"},{"size":740,"mtime":1678221097056,"results":"5445","hashOfConfig":"4558"},{"size":655,"mtime":1675188401448,"results":"5446","hashOfConfig":"4558"},{"size":1043,"mtime":1678221097056,"results":"5447","hashOfConfig":"4558"},{"size":560,"mtime":1675188401448,"results":"5448","hashOfConfig":"4558"},{"size":856,"mtime":1678221097056,"results":"5449","hashOfConfig":"4558"},{"size":842,"mtime":1675188401448,"results":"5450","hashOfConfig":"4558"},{"size":787,"mtime":1675188401448,"results":"5451","hashOfConfig":"4558"},{"size":1464,"mtime":1675188401448,"results":"5452","hashOfConfig":"4558"},{"size":440,"mtime":1675188401448,"results":"5453","hashOfConfig":"4558"},{"size":1723,"mtime":1675188401448,"results":"5454","hashOfConfig":"4558"},{"size":606,"mtime":1678221097056,"results":"5455","hashOfConfig":"4558"},{"size":727,"mtime":1675188401448,"results":"5456","hashOfConfig":"4558"},{"size":2263,"mtime":1678221097056,"results":"5457","hashOfConfig":"4558"},{"size":2277,"mtime":1678221097056,"results":"5458","hashOfConfig":"4558"},{"size":1384,"mtime":1675188401449,"results":"5459","hashOfConfig":"4558"},{"size":801,"mtime":1675188401449,"results":"5460","hashOfConfig":"4558"},{"size":1036,"mtime":1678221097057,"results":"5461","hashOfConfig":"4558"},{"size":2157,"mtime":1678221097057,"results":"5462","hashOfConfig":"4558"},{"size":1267,"mtime":1675188401449,"results":"5463","hashOfConfig":"4558"},{"size":720,"mtime":1675188401449,"results":"5464","hashOfConfig":"4558"},{"size":960,"mtime":1678221097057,"results":"5465","hashOfConfig":"4558"},{"size":805,"mtime":1675188401449,"results":"5466","hashOfConfig":"4558"},{"size":1266,"mtime":1675188401449,"results":"5467","hashOfConfig":"4558"},{"size":438,"mtime":1675188401449,"results":"5468","hashOfConfig":"4558"},{"size":1377,"mtime":1675188401449,"results":"5469","hashOfConfig":"4558"},{"size":2233,"mtime":1675188401449,"results":"5470","hashOfConfig":"4558"},{"size":1988,"mtime":1675694258660,"results":"5471","hashOfConfig":"4558"},{"size":2515,"mtime":1678221097057,"results":"5472","hashOfConfig":"4558"},{"size":700,"mtime":1678221097057,"results":"5473","hashOfConfig":"4558"},{"size":2680,"mtime":1675188401450,"results":"5474","hashOfConfig":"4558"},{"size":2571,"mtime":1675188401450,"results":"5475","hashOfConfig":"4558"},{"size":5005,"mtime":1675188401450,"results":"5476","hashOfConfig":"4558"},{"size":19,"mtime":1675188401451,"results":"5477","hashOfConfig":"4558"},{"size":2445,"mtime":1678221097057,"results":"5478","hashOfConfig":"4558"},{"size":187,"mtime":1675188401451,"results":"5479","hashOfConfig":"4558"},{"size":202,"mtime":1675188401452,"results":"5480","hashOfConfig":"4558"},{"size":2415,"mtime":1675188401452,"results":"5481","hashOfConfig":"4558"},{"size":450,"mtime":1675188401452,"results":"5482","hashOfConfig":"4558"},{"size":120,"mtime":1675188401452,"results":"5483","hashOfConfig":"4558"},{"size":159,"mtime":1675188401452,"results":"5484","hashOfConfig":"4558"},{"size":848,"mtime":1675694258661,"results":"5485","hashOfConfig":"4558"},{"size":585,"mtime":1675694258661,"results":"5486","hashOfConfig":"4558"},{"size":30,"mtime":1675188401452,"results":"5487","hashOfConfig":"4558"},{"size":6165,"mtime":1678221097057,"results":"5488","hashOfConfig":"4558"},{"size":167,"mtime":1675188401452,"results":"5489","hashOfConfig":"4558"},{"size":21,"mtime":1675188401452,"results":"5490","hashOfConfig":"4558"},{"size":593,"mtime":1675188401453,"results":"5491","hashOfConfig":"4558"},{"size":86,"mtime":1675188401453,"results":"5492","hashOfConfig":"4558"},{"size":145,"mtime":1675188401453,"results":"5493","hashOfConfig":"4558"},{"size":171,"mtime":1675188401453,"results":"5494","hashOfConfig":"4558"},{"size":19995,"mtime":1675188401453,"results":"5495","hashOfConfig":"4558"},{"size":2495,"mtime":1678221097058,"results":"5496","hashOfConfig":"4558"},{"size":1527,"mtime":1675188401453,"results":"5497","hashOfConfig":"4558"},{"size":2569,"mtime":1675188401453,"results":"5498","hashOfConfig":"4558"},{"size":6099,"mtime":1675188401453,"results":"5499","hashOfConfig":"4558"},{"size":525,"mtime":1675188401453,"results":"5500","hashOfConfig":"4558"},{"size":1396,"mtime":1675188401454,"results":"5501","hashOfConfig":"4558"},{"size":166,"mtime":1675188401454,"results":"5502","hashOfConfig":"4558"},{"size":718,"mtime":1678221097058,"results":"5503","hashOfConfig":"4558"},{"size":566,"mtime":1675188401454,"results":"5504","hashOfConfig":"4558"},{"size":58,"mtime":1678221097058,"results":"5505","hashOfConfig":"4558"},{"size":3946,"mtime":1675188401455,"results":"5506","hashOfConfig":"4558"},{"size":2291,"mtime":1675188401455,"results":"5507","hashOfConfig":"4558"},{"size":64,"mtime":1675188401455,"results":"5508","hashOfConfig":"4558"},{"size":799,"mtime":1675188401455,"results":"5509","hashOfConfig":"4558"},{"size":2236,"mtime":1678221097058,"results":"5510","hashOfConfig":"4558"},{"size":55,"mtime":1675188401455,"results":"5511","hashOfConfig":"4558"},{"size":493,"mtime":1675188401455,"results":"5512","hashOfConfig":"4558"},{"size":32,"mtime":1675188401455,"results":"5513","hashOfConfig":"4558"},{"size":1374,"mtime":1675188401455,"results":"5514","hashOfConfig":"4558"},{"size":25,"mtime":1675188401455,"results":"5515","hashOfConfig":"4558"},{"size":27,"mtime":1675188401455,"results":"5516","hashOfConfig":"4558"},{"size":113,"mtime":1675188401455,"results":"5517","hashOfConfig":"4558"},{"size":1782,"mtime":1675188401455,"results":"5518","hashOfConfig":"4558"},{"size":72,"mtime":1675188401456,"results":"5519","hashOfConfig":"4558"},{"size":6472,"mtime":1678221097058,"results":"5520","hashOfConfig":"4558"},{"size":168,"mtime":1675188401456,"results":"5521","hashOfConfig":"4558"},{"size":265,"mtime":1675188401456,"results":"5522","hashOfConfig":"4558"},{"size":73,"mtime":1675188401458,"results":"5523","hashOfConfig":"4558"},{"size":169,"mtime":1675188401458,"results":"5524","hashOfConfig":"4558"},{"size":1590,"mtime":1678221097058,"results":"5525","hashOfConfig":"4558"},{"size":264,"mtime":1675188401458,"results":"5526","hashOfConfig":"4558"},{"size":24,"mtime":1675188401459,"results":"5527","hashOfConfig":"4558"},{"size":2709,"mtime":1675188401459,"results":"5528","hashOfConfig":"4558"},{"size":316,"mtime":1675188401459,"results":"5529","hashOfConfig":"4558"},{"size":256,"mtime":1675188401459,"results":"5530","hashOfConfig":"4558"},{"size":222,"mtime":1675188401459,"results":"5531","hashOfConfig":"4558"},{"size":94,"mtime":1675188401459,"results":"5532","hashOfConfig":"4558"},{"size":248,"mtime":1675188401459,"results":"5533","hashOfConfig":"4558"},{"size":181,"mtime":1675188401459,"results":"5534","hashOfConfig":"4558"},{"size":102,"mtime":1675188401459,"results":"5535","hashOfConfig":"4558"},{"size":82,"mtime":1675188401459,"results":"5536","hashOfConfig":"4558"},{"size":305,"mtime":1675188401459,"results":"5537","hashOfConfig":"4558"},{"size":65,"mtime":1675188401459,"results":"5538","hashOfConfig":"4558"},{"size":390,"mtime":1675188401460,"results":"5539","hashOfConfig":"4558"},{"size":686,"mtime":1675188401460,"results":"5540","hashOfConfig":"4558"},{"size":402,"mtime":1675188401460,"results":"5541","hashOfConfig":"4558"},{"size":132,"mtime":1675188401460,"results":"5542","hashOfConfig":"4558"},{"size":15407,"mtime":1675188401460,"results":"5543","hashOfConfig":"4558"},{"size":6569,"mtime":1675188401460,"results":"5544","hashOfConfig":"4558"},{"size":13316,"mtime":1675188401460,"results":"5545","hashOfConfig":"4558"},{"size":3789,"mtime":1675188401460,"results":"5546","hashOfConfig":"4558"},{"size":2928,"mtime":1675188401460,"results":"5547","hashOfConfig":"4558"},{"size":1729,"mtime":1675188401460,"results":"5548","hashOfConfig":"4558"},{"size":1663,"mtime":1675188401460,"results":"5549","hashOfConfig":"4558"},{"size":2110,"mtime":1675188401460,"results":"5550","hashOfConfig":"4558"},{"size":1718,"mtime":1675188401461,"results":"5551","hashOfConfig":"4558"},{"size":1664,"mtime":1675188401461,"results":"5552","hashOfConfig":"4558"},{"size":14063,"mtime":1675188401461,"results":"5553","hashOfConfig":"4558"},{"size":11295,"mtime":1675188401461,"results":"5554","hashOfConfig":"4558"},{"size":2474,"mtime":1675188401461,"results":"5555","hashOfConfig":"4558"},{"size":1685,"mtime":1675188401461,"results":"5556","hashOfConfig":"4558"},{"size":165,"mtime":1675188401461,"results":"5557","hashOfConfig":"4558"},{"size":2082,"mtime":1675188401461,"results":"5558","hashOfConfig":"4558"},{"size":467,"mtime":1675188401461,"results":"5559","hashOfConfig":"4558"},{"size":13168,"mtime":1678221097059,"results":"5560","hashOfConfig":"4558"},{"size":82,"mtime":1675188401461,"results":"5561","hashOfConfig":"4558"},{"size":151,"mtime":1675188401462,"results":"5562","hashOfConfig":"4558"},{"size":2041,"mtime":1678221097059,"results":"5563","hashOfConfig":"4558"},{"size":32,"mtime":1675188401462,"results":"5564","hashOfConfig":"4558"},{"size":155,"mtime":1675188401462,"results":"5565","hashOfConfig":"4558"},{"size":5988,"mtime":1675188401462,"results":"5566","hashOfConfig":"4558"},{"size":6336,"mtime":1675188401462,"results":"5567","hashOfConfig":"4558"},{"size":920,"mtime":1675188401462,"results":"5568","hashOfConfig":"4558"},{"size":1912,"mtime":1678221097059,"results":"5569","hashOfConfig":"4558"},{"size":162,"mtime":1678221097059,"results":"5570","hashOfConfig":"4558"},{"size":1317,"mtime":1678221097059,"results":"5571","hashOfConfig":"4558"},{"size":163,"mtime":1678221097059,"results":"5572","hashOfConfig":"4558"},{"size":3632,"mtime":1678221097059,"results":"5573","hashOfConfig":"4558"},{"size":4626,"mtime":1678221097059,"results":"5574","hashOfConfig":"4558"},{"size":97,"mtime":1678221097059,"results":"5575","hashOfConfig":"4558"},{"size":959,"mtime":1678221097060,"results":"5576","hashOfConfig":"4558"},{"size":326,"mtime":1678221097060,"results":"5577","hashOfConfig":"4558"},{"size":582,"mtime":1678221097060,"results":"5578","hashOfConfig":"4558"},{"size":1582,"mtime":1678221097060,"results":"5579","hashOfConfig":"4558"},{"size":256,"mtime":1678221097060,"results":"5580","hashOfConfig":"4558"},{"size":536,"mtime":1678221097060,"results":"5581","hashOfConfig":"4558"},{"size":1389,"mtime":1678221097060,"results":"5582","hashOfConfig":"4558"},{"size":227,"mtime":1678221097060,"results":"5583","hashOfConfig":"4558"},{"size":230,"mtime":1678221097060,"results":"5584","hashOfConfig":"4558"},{"size":94,"mtime":1678221097060,"results":"5585","hashOfConfig":"4558"},{"size":260,"mtime":1678221097060,"results":"5586","hashOfConfig":"4558"},{"size":241,"mtime":1678221097060,"results":"5587","hashOfConfig":"4558"},{"size":899,"mtime":1678221097060,"results":"5588","hashOfConfig":"4558"},{"size":189,"mtime":1678221097061,"results":"5589","hashOfConfig":"4558"},{"size":181,"mtime":1675188401464,"results":"5590","hashOfConfig":"4558"},{"size":1013,"mtime":1678221097061,"results":"5591","hashOfConfig":"4558"},{"size":243,"mtime":1675188401464,"results":"5592","hashOfConfig":"4558"},{"size":4480,"mtime":1675188401464,"results":"5593","hashOfConfig":"4558"},{"size":2903,"mtime":1675188401464,"results":"5594","hashOfConfig":"4558"},{"size":1718,"mtime":1675188401464,"results":"5595","hashOfConfig":"4558"},{"size":891,"mtime":1675188401464,"results":"5596","hashOfConfig":"4558"},{"size":1727,"mtime":1675188401464,"results":"5597","hashOfConfig":"4558"},{"size":3366,"mtime":1678221097061,"results":"5598","hashOfConfig":"4558"},{"size":4891,"mtime":1678221097061,"results":"5599","hashOfConfig":"4558"},{"size":4629,"mtime":1678221097061,"results":"5600","hashOfConfig":"4558"},{"size":17218,"mtime":1678221097061,"results":"5601","hashOfConfig":"4558"},{"size":27730,"mtime":1678221097062,"results":"5602","hashOfConfig":"4558"},{"size":22040,"mtime":1678221097062,"results":"5603","hashOfConfig":"4558"},{"size":22974,"mtime":1678221097062,"results":"5604","hashOfConfig":"4558"},{"size":29342,"mtime":1678221097062,"results":"5605","hashOfConfig":"4558"},{"size":4389,"mtime":1678221097062,"results":"5606","hashOfConfig":"4558"},{"size":5454,"mtime":1675188401465,"results":"5607","hashOfConfig":"4558"},{"size":467,"mtime":1675188401465,"results":"5608","hashOfConfig":"4558"},{"size":143,"mtime":1678221097063,"results":"5609","hashOfConfig":"4558"},{"size":280,"mtime":1675188401465,"results":"5610","hashOfConfig":"4558"},{"size":24,"mtime":1675188401466,"results":"5611","hashOfConfig":"4558"},{"size":1207,"mtime":1675188401466,"results":"5612","hashOfConfig":"4558"},{"size":1107,"mtime":1675188401466,"results":"5613","hashOfConfig":"4558"},{"size":72,"mtime":1675188401466,"results":"5614","hashOfConfig":"4558"},{"size":1284,"mtime":1675188401466,"results":"5615","hashOfConfig":"4558"},{"size":3830,"mtime":1675188401466,"results":"5616","hashOfConfig":"4558"},{"size":76,"mtime":1675188401466,"results":"5617","hashOfConfig":"4558"},{"size":3004,"mtime":1675188401466,"results":"5618","hashOfConfig":"4558"},{"size":623,"mtime":1678221097063,"results":"5619","hashOfConfig":"4558"},{"size":187,"mtime":1675188401466,"results":"5620","hashOfConfig":"4558"},{"size":76,"mtime":1675188401466,"results":"5621","hashOfConfig":"4558"},{"size":1187,"mtime":1678327032369,"results":"5622","hashOfConfig":"4558"},{"size":2866,"mtime":1675188401467,"results":"5623","hashOfConfig":"4558"},{"size":2226,"mtime":1678282296172,"results":"5624","hashOfConfig":"4558"},{"size":426,"mtime":1678221097063,"results":"5625","hashOfConfig":"4558"},{"size":783,"mtime":1678221097064,"results":"5626","hashOfConfig":"4558"},{"size":1051,"mtime":1678221097064,"results":"5627","hashOfConfig":"4558"},{"size":2460,"mtime":1678221097064,"results":"5628","hashOfConfig":"4558"},{"size":227,"mtime":1678221097064,"results":"5629","hashOfConfig":"4558"},{"size":503,"mtime":1675188401468,"results":"5630","hashOfConfig":"4558"},{"size":2854,"mtime":1675188401468,"results":"5631","hashOfConfig":"4558"},{"size":103,"mtime":1675188401469,"results":"5632","hashOfConfig":"4558"},{"size":2833,"mtime":1678221097064,"results":"5633","hashOfConfig":"4558"},{"size":4838,"mtime":1678221097064,"results":"5634","hashOfConfig":"4558"},{"size":11708,"mtime":1675188401469,"results":"5635","hashOfConfig":"4558"},{"size":1101,"mtime":1675188401469,"results":"5636","hashOfConfig":"4558"},{"size":10832,"mtime":1675188401469,"results":"5637","hashOfConfig":"4558"},{"size":80,"mtime":1675188401469,"results":"5638","hashOfConfig":"4558"},{"size":650,"mtime":1675188401470,"results":"5639","hashOfConfig":"4558"},{"size":1119,"mtime":1678221097064,"results":"5640","hashOfConfig":"4558"},{"size":1298,"mtime":1675188401470,"results":"5641","hashOfConfig":"4558"},{"size":209,"mtime":1675188401470,"results":"5642","hashOfConfig":"4558"},{"size":210,"mtime":1675188401470,"results":"5643","hashOfConfig":"4558"},{"size":2026,"mtime":1675188401470,"results":"5644","hashOfConfig":"4558"},{"size":134,"mtime":1675188401470,"results":"5645","hashOfConfig":"4558"},{"size":718,"mtime":1675188401470,"results":"5646","hashOfConfig":"4558"},{"size":352,"mtime":1675188401470,"results":"5647","hashOfConfig":"4558"},{"size":419,"mtime":1675188401470,"results":"5648","hashOfConfig":"4558"},{"size":270,"mtime":1675188401470,"results":"5649","hashOfConfig":"4558"},{"size":4156,"mtime":1675188401471,"results":"5650","hashOfConfig":"4558"},{"size":3615,"mtime":1675188401471,"results":"5651","hashOfConfig":"4558"},{"size":73,"mtime":1675188401471,"results":"5652","hashOfConfig":"4558"},{"size":103,"mtime":1675188401471,"results":"5653","hashOfConfig":"4558"},{"size":3252,"mtime":1675188401471,"results":"5654","hashOfConfig":"4558"},{"size":10263,"mtime":1675188401471,"results":"5655","hashOfConfig":"4558"},{"size":19,"mtime":1675188401470,"results":"5656","hashOfConfig":"4558"},{"size":658,"mtime":1675188401470,"results":"5657","hashOfConfig":"4558"},{"size":130,"mtime":1675188401470,"results":"5658","hashOfConfig":"4558"},{"size":3975,"mtime":1675188401471,"results":"5659","hashOfConfig":"4558"},{"size":3984,"mtime":1675188401471,"results":"5660","hashOfConfig":"4558"},{"size":49,"mtime":1678221097064,"results":"5661","hashOfConfig":"4558"},{"size":1176,"mtime":1678221097065,"results":"5662","hashOfConfig":"4558"},{"size":1989,"mtime":1678221097065,"results":"5663","hashOfConfig":"4558"},{"size":24,"mtime":1678221097065,"results":"5664","hashOfConfig":"4558"},{"size":4613,"mtime":1678221097065,"results":"5665","hashOfConfig":"4558"},{"size":32,"mtime":1675188401472,"results":"5666","hashOfConfig":"4558"},{"size":3658,"mtime":1678221097065,"results":"5667","hashOfConfig":"4558"},{"size":59,"mtime":1675188401472,"results":"5668","hashOfConfig":"4558"},{"size":3589,"mtime":1675188401472,"results":"5669","hashOfConfig":"4558"},{"size":1356,"mtime":1675188401473,"results":"5670","hashOfConfig":"4558"},{"size":313,"mtime":1675188401473,"results":"5671","hashOfConfig":"4558"},{"size":122,"mtime":1675188401473,"results":"5672","hashOfConfig":"4558"},{"size":3570,"mtime":1675188401473,"results":"5673","hashOfConfig":"4558"},{"size":1248,"mtime":1675188401474,"results":"5674","hashOfConfig":"4558"},{"size":1199,"mtime":1678221097066,"results":"5675","hashOfConfig":"4558"},{"size":5700,"mtime":1675188401474,"results":"5676","hashOfConfig":"4558"},{"size":1967,"mtime":1675188401474,"results":"5677","hashOfConfig":"4558"},{"size":65,"mtime":1675188401474,"results":"5678","hashOfConfig":"4558"},{"size":1591,"mtime":1678221097066,"results":"5679","hashOfConfig":"4558"},{"size":187,"mtime":1675188401474,"results":"5680","hashOfConfig":"4558"},{"size":3522,"mtime":1675188401474,"results":"5681","hashOfConfig":"4558"},{"size":11847,"mtime":1675188401475,"results":"5682","hashOfConfig":"4558"},{"size":548,"mtime":1675188401475,"results":"5683","hashOfConfig":"4558"},{"size":9076,"mtime":1678221097066,"results":"5684","hashOfConfig":"4558"},{"size":2211,"mtime":1675188401475,"results":"5685","hashOfConfig":"4558"},{"size":98,"mtime":1675188401475,"results":"5686","hashOfConfig":"4558"},{"size":366,"mtime":1675188401475,"results":"5687","hashOfConfig":"4558"},{"size":1423,"mtime":1675188401475,"results":"5688","hashOfConfig":"4558"},{"size":579,"mtime":1675188401475,"results":"5689","hashOfConfig":"4558"},{"size":143,"mtime":1675188401475,"results":"5690","hashOfConfig":"4558"},{"size":167,"mtime":1675188401475,"results":"5691","hashOfConfig":"4558"},{"size":2191,"mtime":1675188401475,"results":"5692","hashOfConfig":"4558"},{"size":1493,"mtime":1675188401475,"results":"5693","hashOfConfig":"4558"},{"size":746,"mtime":1675188401475,"results":"5694","hashOfConfig":"4558"},{"size":747,"mtime":1675188401475,"results":"5695","hashOfConfig":"4558"},{"size":479,"mtime":1675188401476,"results":"5696","hashOfConfig":"4558"},{"size":38,"mtime":1675188401476,"results":"5697","hashOfConfig":"4558"},{"size":371,"mtime":1675188401476,"results":"5698","hashOfConfig":"4558"},{"size":16719,"mtime":1675188401476,"results":"5699","hashOfConfig":"4558"},{"size":4316,"mtime":1675188401476,"results":"5700","hashOfConfig":"4558"},{"size":38746,"mtime":1675188401476,"results":"5701","hashOfConfig":"4558"},{"size":114,"mtime":1675188401476,"results":"5702","hashOfConfig":"4558"},{"size":304,"mtime":1675188401476,"results":"5703","hashOfConfig":"4558"},{"size":847,"mtime":1675188401477,"results":"5704","hashOfConfig":"4558"},{"size":2173,"mtime":1675188401477,"results":"5705","hashOfConfig":"4558"},{"size":3018,"mtime":1675188401477,"results":"5706","hashOfConfig":"4558"},{"size":2059,"mtime":1675188401477,"results":"5707","hashOfConfig":"4558"},{"size":120,"mtime":1675188401477,"results":"5708","hashOfConfig":"4558"},{"size":658,"mtime":1675188401477,"results":"5709","hashOfConfig":"4558"},{"size":673,"mtime":1675188401477,"results":"5710","hashOfConfig":"4558"},{"size":515,"mtime":1675188401477,"results":"5711","hashOfConfig":"4558"},{"size":536,"mtime":1675188401477,"results":"5712","hashOfConfig":"4558"},{"size":535,"mtime":1675188401477,"results":"5713","hashOfConfig":"4558"},{"size":120,"mtime":1675188401477,"results":"5714","hashOfConfig":"4558"},{"size":227,"mtime":1675188401478,"results":"5715","hashOfConfig":"4558"},{"size":19,"mtime":1675188401478,"results":"5716","hashOfConfig":"4558"},{"size":19,"mtime":1675188401478,"results":"5717","hashOfConfig":"4558"},{"size":1743,"mtime":1678221097066,"results":"5718","hashOfConfig":"4558"},{"size":249,"mtime":1675188401478,"results":"5719","hashOfConfig":"4558"},{"size":19,"mtime":1675188401478,"results":"5720","hashOfConfig":"4558"},{"size":19,"mtime":1675188401478,"results":"5721","hashOfConfig":"4558"},{"size":1600,"mtime":1678221097067,"results":"5722","hashOfConfig":"4558"},{"size":19,"mtime":1675188401478,"results":"5723","hashOfConfig":"4558"},{"size":1735,"mtime":1678221097067,"results":"5724","hashOfConfig":"4558"},{"size":168,"mtime":1675188401479,"results":"5725","hashOfConfig":"4558"},{"size":17,"mtime":1675188401479,"results":"5726","hashOfConfig":"4558"},{"size":1967,"mtime":1678221097067,"results":"5727","hashOfConfig":"4558"},{"size":17,"mtime":1675188401479,"results":"5728","hashOfConfig":"4558"},{"size":258,"mtime":1675188401479,"results":"5729","hashOfConfig":"4558"},{"size":19,"mtime":1675188401479,"results":"5730","hashOfConfig":"4558"},{"size":19,"mtime":1675188401479,"results":"5731","hashOfConfig":"4558"},{"size":2424,"mtime":1678221097067,"results":"5732","hashOfConfig":"4558"},{"size":481,"mtime":1675188401479,"results":"5733","hashOfConfig":"4558"},{"size":19,"mtime":1675188401479,"results":"5734","hashOfConfig":"4558"},{"size":19,"mtime":1675188401479,"results":"5735","hashOfConfig":"4558"},{"size":3273,"mtime":1678221097068,"results":"5736","hashOfConfig":"4558"},{"size":551,"mtime":1675188401480,"results":"5737","hashOfConfig":"4558"},{"size":19,"mtime":1675188401480,"results":"5738","hashOfConfig":"4558"},{"size":19,"mtime":1675188401480,"results":"5739","hashOfConfig":"4558"},{"size":1364,"mtime":1678221097068,"results":"5740","hashOfConfig":"4558"},{"size":376,"mtime":1675188401480,"results":"5741","hashOfConfig":"4558"},{"size":19,"mtime":1675188401480,"results":"5742","hashOfConfig":"4558"},{"size":19,"mtime":1675188401480,"results":"5743","hashOfConfig":"4558"},{"size":1204,"mtime":1678221097068,"results":"5744","hashOfConfig":"4558"},{"size":18,"mtime":1675188401480,"results":"5745","hashOfConfig":"4558"},{"size":1266,"mtime":1678221097069,"results":"5746","hashOfConfig":"4558"},{"size":15,"mtime":1675188401480,"results":"5747","hashOfConfig":"4558"},{"size":514,"mtime":1678221097069,"results":"5748","hashOfConfig":"4558"},{"size":19,"mtime":1675188401481,"results":"5749","hashOfConfig":"4558"},{"size":1789,"mtime":1678221097069,"results":"5750","hashOfConfig":"4558"},{"size":36,"mtime":1675188401481,"results":"5751","hashOfConfig":"4558"},{"size":1119,"mtime":1678221097069,"results":"5752","hashOfConfig":"4558"},{"size":1149,"mtime":1678221097069,"results":"5753","hashOfConfig":"4558"},{"size":1571,"mtime":1678221097070,"results":"5754","hashOfConfig":"4558"},{"size":19,"mtime":1675188401481,"results":"5755","hashOfConfig":"4558"},{"size":32,"mtime":1675188401481,"results":"5756","hashOfConfig":"4558"},{"size":19,"mtime":1675188401481,"results":"5757","hashOfConfig":"4558"},{"size":913,"mtime":1678221097070,"results":"5758","hashOfConfig":"4558"},{"size":19,"mtime":1675188401481,"results":"5759","hashOfConfig":"4558"},{"size":1163,"mtime":1678221097070,"results":"5760","hashOfConfig":"4558"},{"size":18,"mtime":1675188401482,"results":"5761","hashOfConfig":"4558"},{"size":898,"mtime":1675188401482,"results":"5762","hashOfConfig":"4558"},{"size":18,"mtime":1675188401482,"results":"5763","hashOfConfig":"4558"},{"size":650,"mtime":1675188401482,"results":"5764","hashOfConfig":"4558"},{"size":233,"mtime":1675188401482,"results":"5765","hashOfConfig":"4558"},{"size":19,"mtime":1675188401482,"results":"5766","hashOfConfig":"4558"},{"size":19,"mtime":1675188401482,"results":"5767","hashOfConfig":"4558"},{"size":1981,"mtime":1678221097070,"results":"5768","hashOfConfig":"4558"},{"size":32,"mtime":1675188401482,"results":"5769","hashOfConfig":"4558"},{"size":4216,"mtime":1675188401482,"results":"5770","hashOfConfig":"4558"},{"size":959,"mtime":1675188401482,"results":"5771","hashOfConfig":"4558"},{"size":107,"mtime":1675188401482,"results":"5772","hashOfConfig":"4558"},{"size":26,"mtime":1675188401483,"results":"5773","hashOfConfig":"4558"},{"size":1355,"mtime":1675188401483,"results":"5774","hashOfConfig":"4558"},{"size":724,"mtime":1675188401483,"results":"5775","hashOfConfig":"4558"},{"size":32,"mtime":1675188401483,"results":"5776","hashOfConfig":"4558"},{"size":1016,"mtime":1675188401483,"results":"5777","hashOfConfig":"4558"},{"size":138,"mtime":1675188401483,"results":"5778","hashOfConfig":"4558"},{"size":3762,"mtime":1675188401483,"results":"5779","hashOfConfig":"4558"},{"size":3803,"mtime":1678221097070,"results":"5780","hashOfConfig":"4558"},{"size":3366,"mtime":1678221097071,"results":"5781","hashOfConfig":"4558"},{"size":3855,"mtime":1675188401483,"results":"5782","hashOfConfig":"4558"},{"size":1357,"mtime":1675188401483,"results":"5783","hashOfConfig":"4558"},{"size":358,"mtime":1675188401484,"results":"5784","hashOfConfig":"4558"},{"size":32,"mtime":1675188401484,"results":"5785","hashOfConfig":"4558"},{"size":442,"mtime":1675188401484,"results":"5786","hashOfConfig":"4558"},{"size":1165,"mtime":1675188401484,"results":"5787","hashOfConfig":"4558"},{"size":379,"mtime":1675188401484,"results":"5788","hashOfConfig":"4558"},{"size":405,"mtime":1675188401484,"results":"5789","hashOfConfig":"4558"},{"size":331,"mtime":1675188401484,"results":"5790","hashOfConfig":"4558"},{"size":418,"mtime":1675188401484,"results":"5791","hashOfConfig":"4558"},{"size":9041,"mtime":1675188401484,"results":"5792","hashOfConfig":"4558"},{"size":3045,"mtime":1675188401484,"results":"5793","hashOfConfig":"4558"},{"size":612,"mtime":1678221097071,"results":"5794","hashOfConfig":"4558"},{"size":429,"mtime":1675188401484,"results":"5795","hashOfConfig":"4558"},{"size":5105,"mtime":1675188401484,"results":"5796","hashOfConfig":"4558"},{"size":18856,"mtime":1678221097071,"results":"5797","hashOfConfig":"4558"},{"size":814,"mtime":1678221097071,"results":"5798","hashOfConfig":"4558"},{"size":386,"mtime":1675188401485,"results":"5799","hashOfConfig":"4558"},{"size":521,"mtime":1675188401485,"results":"5800","hashOfConfig":"4558"},{"size":132,"mtime":1678221097073,"results":"5801","hashOfConfig":"4558"},{"size":41,"mtime":1678221097073,"results":"5802","hashOfConfig":"4558"},{"size":1248,"mtime":1678221097073,"results":"5803","hashOfConfig":"4558"},{"size":219,"mtime":1678221097073,"results":"5804","hashOfConfig":"4558"},{"size":2044,"mtime":1675188401488,"results":"5805","hashOfConfig":"4558"},{"size":163,"mtime":1678221097073,"results":"5806","hashOfConfig":"4558"},{"size":1639,"mtime":1675188401488,"results":"5807","hashOfConfig":"4558"},{"size":1655,"mtime":1675188401488,"results":"5808","hashOfConfig":"4558"},{"size":1168,"mtime":1675188401489,"results":"5809","hashOfConfig":"4558"},{"size":1449,"mtime":1675188401489,"results":"5810","hashOfConfig":"4558"},{"size":2268,"mtime":1675694258669,"results":"5811","hashOfConfig":"4558"},{"size":2102,"mtime":1675188401489,"results":"5812","hashOfConfig":"4558"},{"size":29,"mtime":1675188401489,"results":"5813","hashOfConfig":"4558"},{"size":59,"mtime":1675188401489,"results":"5814","hashOfConfig":"4558"},{"size":1414,"mtime":1678221097074,"results":"5815","hashOfConfig":"4558"},{"size":1450,"mtime":1678221097074,"results":"5816","hashOfConfig":"4558"},{"size":893,"mtime":1675188401489,"results":"5817","hashOfConfig":"4558"},{"size":111,"mtime":1675188401489,"results":"5818","hashOfConfig":"4558"},{"size":1453,"mtime":1678221097074,"results":"5819","hashOfConfig":"4558"},{"size":234,"mtime":1675188401489,"results":"5820","hashOfConfig":"4558"},{"size":31,"mtime":1675188401490,"results":"5821","hashOfConfig":"4558"},{"size":505,"mtime":1675188401490,"results":"5822","hashOfConfig":"4558"},{"size":24,"mtime":1675188401490,"results":"5823","hashOfConfig":"4558"},{"size":1020,"mtime":1675188401490,"results":"5824","hashOfConfig":"4558"},{"size":44,"mtime":1675188401490,"results":"5825","hashOfConfig":"4558"},{"size":776,"mtime":1675188401490,"results":"5826","hashOfConfig":"4558"},{"size":650,"mtime":1678221097081,"results":"5827","hashOfConfig":"4558"},{"size":6721,"mtime":1678221097081,"results":"5828","hashOfConfig":"4558"},{"size":4873,"mtime":1678221097081,"results":"5829","hashOfConfig":"4558"},{"size":540,"mtime":1676418804561,"results":"5830","hashOfConfig":"4558"},{"size":6262,"mtime":1675188401507,"results":"5831","hashOfConfig":"4558"},{"size":1669,"mtime":1675188401507,"results":"5832","hashOfConfig":"4558"},{"size":32,"mtime":1675188401507,"results":"5833","hashOfConfig":"4558"},{"size":423,"mtime":1675188401507,"results":"5834","hashOfConfig":"4558"},{"size":3162,"mtime":1678221097081,"results":"5835","hashOfConfig":"4558"},{"size":6668,"mtime":1678221097081,"results":"5836","hashOfConfig":"4558"},{"size":495,"mtime":1675188401508,"results":"5837","hashOfConfig":"4558"},{"size":1680,"mtime":1675188401508,"results":"5838","hashOfConfig":"4558"},{"size":1814,"mtime":1675188401508,"results":"5839","hashOfConfig":"4558"},{"size":2712,"mtime":1675188401508,"results":"5840","hashOfConfig":"4558"},{"size":1355,"mtime":1675188401508,"results":"5841","hashOfConfig":"4558"},{"size":1927,"mtime":1678221097081,"results":"5842","hashOfConfig":"4558"},{"size":1700,"mtime":1675188401508,"results":"5843","hashOfConfig":"4558"},{"size":394,"mtime":1678221097082,"results":"5844","hashOfConfig":"4558"},{"size":175,"mtime":1675188401508,"results":"5845","hashOfConfig":"4558"},{"size":4072,"mtime":1675188401509,"results":"5846","hashOfConfig":"4558"},{"size":411,"mtime":1678221097082,"results":"5847","hashOfConfig":"4558"},{"size":138,"mtime":1678221097074,"results":"5848","hashOfConfig":"4558"},{"size":9911,"mtime":1678282296173,"results":"5849","hashOfConfig":"4558"},{"size":2114,"mtime":1678221097074,"results":"5850","hashOfConfig":"4558"},{"size":23,"mtime":1675188401491,"results":"5851","hashOfConfig":"4558"},{"size":929,"mtime":1675188401491,"results":"5852","hashOfConfig":"4558"},{"size":32,"mtime":1675188401491,"results":"5853","hashOfConfig":"4558"},{"size":33,"mtime":1675694258670,"results":"5854","hashOfConfig":"4558"},{"size":5246,"mtime":1678221097075,"results":"5855","hashOfConfig":"4558"},{"size":20,"mtime":1678221097075,"results":"5856","hashOfConfig":"4558"},{"size":49,"mtime":1678221097075,"results":"5857","hashOfConfig":"4558"},{"size":1550,"mtime":1675188401492,"results":"5858","hashOfConfig":"4558"},{"size":1926,"mtime":1675188401492,"results":"5859","hashOfConfig":"4558"},{"size":5016,"mtime":1678221097075,"results":"5860","hashOfConfig":"4558"},{"size":3128,"mtime":1675188401501,"results":"5861","hashOfConfig":"4558"},{"size":1702,"mtime":1675694258670,"results":"5862","hashOfConfig":"4558"},{"size":1760,"mtime":1675188401501,"results":"5863","hashOfConfig":"4558"},{"size":5924,"mtime":1678221097075,"results":"5864","hashOfConfig":"4558"},{"size":704,"mtime":1675188401501,"results":"5865","hashOfConfig":"4558"},{"size":2605,"mtime":1675188401501,"results":"5866","hashOfConfig":"4558"},{"size":1359,"mtime":1678221097075,"results":"5867","hashOfConfig":"4558"},{"size":1383,"mtime":1678221097075,"results":"5868","hashOfConfig":"4558"},{"size":1488,"mtime":1678221097076,"results":"5869","hashOfConfig":"4558"},{"size":1126,"mtime":1678221097076,"results":"5870","hashOfConfig":"4558"},{"size":50,"mtime":1678221097076,"results":"5871","hashOfConfig":"4558"},{"size":9209,"mtime":1678221097076,"results":"5872","hashOfConfig":"4558"},{"size":210,"mtime":1678221097076,"results":"5873","hashOfConfig":"4558"},{"size":3199,"mtime":1678221097076,"results":"5874","hashOfConfig":"4558"},{"size":1096,"mtime":1678221097076,"results":"5875","hashOfConfig":"4558"},{"size":2316,"mtime":1678221097077,"results":"5876","hashOfConfig":"4558"},{"size":483,"mtime":1678221097077,"results":"5877","hashOfConfig":"4558"},{"size":465,"mtime":1678221097077,"results":"5878","hashOfConfig":"4558"},{"size":639,"mtime":1678221097077,"results":"5879","hashOfConfig":"4558"},{"size":503,"mtime":1678221097077,"results":"5880","hashOfConfig":"4558"},{"size":1456,"mtime":1678221097077,"results":"5881","hashOfConfig":"4558"},{"size":4541,"mtime":1678221097077,"results":"5882","hashOfConfig":"4558"},{"size":7076,"mtime":1678221097078,"results":"5883","hashOfConfig":"4558"},{"size":1464,"mtime":1678221097078,"results":"5884","hashOfConfig":"4558"},{"size":1099,"mtime":1678221097078,"results":"5885","hashOfConfig":"4558"},{"size":9029,"mtime":1678221097078,"results":"5886","hashOfConfig":"4558"},{"size":32,"mtime":1678221097078,"results":"5887","hashOfConfig":"4558"},{"size":619,"mtime":1678221097078,"results":"5888","hashOfConfig":"4558"},{"size":2241,"mtime":1678221097079,"results":"5889","hashOfConfig":"4558"},{"size":2584,"mtime":1675188401504,"results":"5890","hashOfConfig":"4558"},{"size":6392,"mtime":1678221097079,"results":"5891","hashOfConfig":"4558"},{"size":8210,"mtime":1678221097079,"results":"5892","hashOfConfig":"4558"},{"size":7827,"mtime":1678221097079,"results":"5893","hashOfConfig":"4558"},{"size":101,"mtime":1675188401505,"results":"5894","hashOfConfig":"4558"},{"size":8834,"mtime":1678221097080,"results":"5895","hashOfConfig":"4558"},{"size":2130,"mtime":1678221097080,"results":"5896","hashOfConfig":"4558"},{"size":4086,"mtime":1678221097080,"results":"5897","hashOfConfig":"4558"},{"size":3402,"mtime":1678221097080,"results":"5898","hashOfConfig":"4558"},{"size":4268,"mtime":1678221097080,"results":"5899","hashOfConfig":"4558"},{"size":187,"mtime":1675188401506,"results":"5900","hashOfConfig":"4558"},{"size":1120,"mtime":1678221097080,"results":"5901","hashOfConfig":"4558"},{"size":1213,"mtime":1678221097081,"results":"5902","hashOfConfig":"4558"},{"size":94,"mtime":1678221097081,"results":"5903","hashOfConfig":"4558"},{"size":21,"mtime":1675188401506,"results":"5904","hashOfConfig":"4558"},{"size":266,"mtime":1675188401506,"results":"5905","hashOfConfig":"4558"},{"size":252,"mtime":1675188401509,"results":"5906","hashOfConfig":"4558"},{"size":1598,"mtime":1675188401509,"results":"5907","hashOfConfig":"4558"},{"size":900,"mtime":1675188401509,"results":"5908","hashOfConfig":"4558"},{"size":291,"mtime":1675188401509,"results":"5909","hashOfConfig":"4558"},{"size":291,"mtime":1675188401509,"results":"5910","hashOfConfig":"4558"},{"size":187,"mtime":1675188401509,"results":"5911","hashOfConfig":"4558"},{"size":201,"mtime":1675188401509,"results":"5912","hashOfConfig":"4558"},{"size":754,"mtime":1678221097082,"results":"5913","hashOfConfig":"4558"},{"size":342,"mtime":1675188401509,"results":"5914","hashOfConfig":"4558"},{"size":2717,"mtime":1678221097082,"results":"5915","hashOfConfig":"4558"},{"size":379,"mtime":1675188401510,"results":"5916","hashOfConfig":"4558"},{"size":1130,"mtime":1675188401510,"results":"5917","hashOfConfig":"4558"},{"size":791,"mtime":1675188401510,"results":"5918","hashOfConfig":"4558"},{"size":1374,"mtime":1678221097082,"results":"5919","hashOfConfig":"4558"},{"size":171,"mtime":1675188401510,"results":"5920","hashOfConfig":"4558"},{"size":1465,"mtime":1675188401510,"results":"5921","hashOfConfig":"4558"},{"size":177,"mtime":1675188401510,"results":"5922","hashOfConfig":"4558"},{"size":403,"mtime":1675188401510,"results":"5923","hashOfConfig":"4558"},{"size":1069,"mtime":1675188401510,"results":"5924","hashOfConfig":"4558"},{"size":428,"mtime":1675188401510,"results":"5925","hashOfConfig":"4558"},{"size":2065,"mtime":1678221097082,"results":"5926","hashOfConfig":"4558"},{"size":442,"mtime":1675188401510,"results":"5927","hashOfConfig":"4558"},{"size":915,"mtime":1675188401510,"results":"5928","hashOfConfig":"4558"},{"size":858,"mtime":1675188401510,"results":"5929","hashOfConfig":"4558"},{"size":478,"mtime":1675188401511,"results":"5930","hashOfConfig":"4558"},{"size":1015,"mtime":1678221097082,"results":"5931","hashOfConfig":"4558"},{"size":3420,"mtime":1675188401511,"results":"5932","hashOfConfig":"4558"},{"size":285,"mtime":1675188401511,"results":"5933","hashOfConfig":"4558"},{"size":1005,"mtime":1675188401511,"results":"5934","hashOfConfig":"4558"},{"size":770,"mtime":1675188401511,"results":"5935","hashOfConfig":"4558"},{"size":1900,"mtime":1675188401511,"results":"5936","hashOfConfig":"4558"},{"size":495,"mtime":1675188401511,"results":"5937","hashOfConfig":"4558"},{"size":757,"mtime":1675188401511,"results":"5938","hashOfConfig":"4558"},{"size":933,"mtime":1675188401511,"results":"5939","hashOfConfig":"4558"},{"size":971,"mtime":1675188401511,"results":"5940","hashOfConfig":"4558"},{"size":578,"mtime":1675188401511,"results":"5941","hashOfConfig":"4558"},{"size":781,"mtime":1675188401511,"results":"5942","hashOfConfig":"4558"},{"size":977,"mtime":1678221097083,"results":"5943","hashOfConfig":"4558"},{"size":2661,"mtime":1675188401512,"results":"5944","hashOfConfig":"4558"},{"size":2207,"mtime":1675188401512,"results":"5945","hashOfConfig":"4558"},{"size":995,"mtime":1675188401512,"results":"5946","hashOfConfig":"4558"},{"size":451,"mtime":1675188401512,"results":"5947","hashOfConfig":"4558"},{"size":2753,"mtime":1675188401512,"results":"5948","hashOfConfig":"4558"},{"size":1979,"mtime":1675188401512,"results":"5949","hashOfConfig":"4558"},{"size":1034,"mtime":1678221097083,"results":"5950","hashOfConfig":"4558"},{"size":90,"mtime":1675188401512,"results":"5951","hashOfConfig":"4558"},{"size":313,"mtime":1675188401512,"results":"5952","hashOfConfig":"4558"},{"size":363,"mtime":1675188401512,"results":"5953","hashOfConfig":"4558"},{"size":19,"mtime":1675188401512,"results":"5954","hashOfConfig":"4558"},{"size":3787,"mtime":1678221097083,"results":"5955","hashOfConfig":"4558"},{"size":873,"mtime":1678221097083,"results":"5956","hashOfConfig":"4558"},{"size":1265,"mtime":1675188401513,"results":"5957","hashOfConfig":"4558"},{"size":321,"mtime":1678221097083,"results":"5958","hashOfConfig":"4558"},{"size":694,"mtime":1675188401513,"results":"5959","hashOfConfig":"4558"},{"size":262,"mtime":1675188401513,"results":"5960","hashOfConfig":"4558"},{"size":292,"mtime":1675188401513,"results":"5961","hashOfConfig":"4558"},{"size":923,"mtime":1675188401513,"results":"5962","hashOfConfig":"4558"},{"size":2752,"mtime":1675188401513,"results":"5963","hashOfConfig":"4558"},{"size":3171,"mtime":1678221097084,"results":"5964","hashOfConfig":"4558"},{"size":1320,"mtime":1675188401514,"results":"5965","hashOfConfig":"4558"},{"size":1275,"mtime":1675188401514,"results":"5966","hashOfConfig":"4558"},{"size":1392,"mtime":1675188401514,"results":"5967","hashOfConfig":"4558"},{"size":866,"mtime":1678221097084,"results":"5968","hashOfConfig":"4558"},{"size":1503,"mtime":1678221097084,"results":"5969","hashOfConfig":"4558"},{"size":217,"mtime":1675188401514,"results":"5970","hashOfConfig":"4558"},{"size":25519,"mtime":1678221097084,"results":"5971","hashOfConfig":"4558"},{"size":1357,"mtime":1678221097084,"results":"5972","hashOfConfig":"4558"},{"size":704,"mtime":1675188401514,"results":"5973","hashOfConfig":"4558"},{"size":94,"mtime":1675188401514,"results":"5974","hashOfConfig":"4558"},{"size":1426,"mtime":1675188401514,"results":"5975","hashOfConfig":"4558"},{"size":1179,"mtime":1675188401514,"results":"5976","hashOfConfig":"4558"},{"size":158,"mtime":1675188401514,"results":"5977","hashOfConfig":"4558"},{"size":21,"mtime":1675188401515,"results":"5978","hashOfConfig":"4558"},{"size":1048,"mtime":1675188401515,"results":"5979","hashOfConfig":"4558"},{"size":63,"mtime":1675188401515,"results":"5980","hashOfConfig":"4558"},{"size":2980,"mtime":1675188401515,"results":"5981","hashOfConfig":"4558"},{"size":44,"mtime":1675188401515,"results":"5982","hashOfConfig":"4558"},{"size":2135,"mtime":1675188401515,"results":"5983","hashOfConfig":"4558"},{"size":1309,"mtime":1678221097085,"results":"5984","hashOfConfig":"5985"},{"size":1610,"mtime":1678221097085,"results":"5986","hashOfConfig":"5985"},{"size":1044,"mtime":1678221097085,"results":"5987","hashOfConfig":"5985"},{"size":2931,"mtime":1678221097085,"results":"5988","hashOfConfig":"5985"},{"size":2669,"mtime":1678221097085,"results":"5989","hashOfConfig":"5985"},{"size":5141,"mtime":1678221097085,"results":"5990","hashOfConfig":"5985"},{"size":3578,"mtime":1678221097085,"results":"5991","hashOfConfig":"5985"},{"size":4328,"mtime":1678221097086,"results":"5992","hashOfConfig":"5985"},{"size":2507,"mtime":1678221097086,"results":"5993","hashOfConfig":"5985"},{"size":2054,"mtime":1678221097086,"results":"5994","hashOfConfig":"5985"},{"size":1057,"mtime":1678221097086,"results":"5995","hashOfConfig":"5985"},{"size":1929,"mtime":1678221097086,"results":"5996","hashOfConfig":"5985"},{"size":2178,"mtime":1678221097086,"results":"5997","hashOfConfig":"5985"},{"size":2126,"mtime":1678282296173,"results":"5998","hashOfConfig":"5985"},{"size":2105,"mtime":1678221097086,"results":"5999","hashOfConfig":"5985"},{"size":307,"mtime":1678221097087,"results":"6000","hashOfConfig":"5985"},{"size":701,"mtime":1678221097087,"results":"6001","hashOfConfig":"5985"},{"size":435,"mtime":1678221097087,"results":"6002","hashOfConfig":"5985"},{"size":808,"mtime":1678221097087,"results":"6003","hashOfConfig":"5985"},{"size":647,"mtime":1678221097087,"results":"6004","hashOfConfig":"5985"},{"size":737,"mtime":1678221097087,"results":"6005","hashOfConfig":"5985"},{"size":1161,"mtime":1678221097087,"results":"6006","hashOfConfig":"5985"},{"size":907,"mtime":1678221097087,"results":"6007","hashOfConfig":"5985"},{"size":1089,"mtime":1678221097088,"results":"6008","hashOfConfig":"5985"},{"size":473,"mtime":1678221097088,"results":"6009","hashOfConfig":"5985"},{"size":40,"mtime":1675188401517,"results":"6010","hashOfConfig":"5985"},{"size":2303,"mtime":1678221097088,"results":"6011","hashOfConfig":"5985"},{"size":4978,"mtime":1678221097088,"results":"6012","hashOfConfig":"5985"},{"size":1142,"mtime":1678221097088,"results":"6013","hashOfConfig":"5985"},{"size":46,"mtime":1675188401517,"results":"6014","hashOfConfig":"5985"},{"size":4543,"mtime":1675694258678,"results":"6015","hashOfConfig":"5985"},{"size":2084,"mtime":1678221097088,"results":"6016","hashOfConfig":"5985"},{"size":446,"mtime":1678221097088,"results":"6017","hashOfConfig":"5985"},{"size":2160,"mtime":1678221097089,"results":"6018","hashOfConfig":"5985"},{"size":3549,"mtime":1678221097089,"results":"6019","hashOfConfig":"5985"},{"size":1526,"mtime":1678221097089,"results":"6020","hashOfConfig":"5985"},{"size":2787,"mtime":1678221097089,"results":"6021","hashOfConfig":"5985"},{"size":1443,"mtime":1678221097089,"results":"6022","hashOfConfig":"5985"},{"size":3831,"mtime":1678221097089,"results":"6023","hashOfConfig":"5985"},{"size":837,"mtime":1678221097089,"results":"6024","hashOfConfig":"5985"},{"size":1143,"mtime":1678221097090,"results":"6025","hashOfConfig":"5985"},{"size":757,"mtime":1678221097090,"results":"6026","hashOfConfig":"5985"},{"size":775,"mtime":1678221097090,"results":"6027","hashOfConfig":"5985"},{"size":182,"mtime":1678221097090,"results":"6028","hashOfConfig":"5985"},{"size":233,"mtime":1678221097090,"results":"6029","hashOfConfig":"5985"},{"size":321,"mtime":1678221097090,"results":"6030","hashOfConfig":"5985"},{"size":895,"mtime":1678221097090,"results":"6031","hashOfConfig":"5985"},{"size":671,"mtime":1678221097090,"results":"6032","hashOfConfig":"5985"},{"size":358,"mtime":1678221097091,"results":"6033","hashOfConfig":"5985"},{"size":230,"mtime":1678221097091,"results":"6034","hashOfConfig":"5985"},{"size":253,"mtime":1675188401519,"results":"6035","hashOfConfig":"5985"},{"size":401,"mtime":1675188401519,"results":"6036","hashOfConfig":"5985"},{"size":243,"mtime":1675188401519,"results":"6037","hashOfConfig":"5985"},{"size":1090,"mtime":1675188401519,"results":"6038","hashOfConfig":"5985"},{"size":668,"mtime":1678221097091,"results":"6039","hashOfConfig":"5985"},{"size":745,"mtime":1675188401519,"results":"6040","hashOfConfig":"5985"},{"size":475,"mtime":1675188401519,"results":"6041","hashOfConfig":"5985"},{"size":2477,"mtime":1678221097091,"results":"6042","hashOfConfig":"5985"},{"size":232,"mtime":1678221097091,"results":"6043","hashOfConfig":"5985"},{"size":451,"mtime":1678221097091,"results":"6044","hashOfConfig":"5985"},{"size":423,"mtime":1678221097091,"results":"6045","hashOfConfig":"5985"},{"size":263,"mtime":1678221097091,"results":"6046","hashOfConfig":"5985"},{"size":215,"mtime":1678221097092,"results":"6047","hashOfConfig":"5985"},{"size":280,"mtime":1678221097092,"results":"6048","hashOfConfig":"5985"},{"size":253,"mtime":1678221097092,"results":"6049","hashOfConfig":"5985"},{"size":399,"mtime":1678221097092,"results":"6050","hashOfConfig":"5985"},{"size":684,"mtime":1678221097092,"results":"6051","hashOfConfig":"5985"},{"size":1154,"mtime":1678221097092,"results":"6052","hashOfConfig":"5985"},{"size":688,"mtime":1675188401520,"results":"6053","hashOfConfig":"5985"},{"size":461,"mtime":1678221097092,"results":"6054","hashOfConfig":"5985"},{"size":1667,"mtime":1678221097092,"results":"6055","hashOfConfig":"5985"},{"size":4280,"mtime":1678221097092,"results":"6056","hashOfConfig":"5985"},{"size":995,"mtime":1678221097093,"results":"6057","hashOfConfig":"5985"},{"size":256,"mtime":1678221097093,"results":"6058","hashOfConfig":"5985"},{"size":3271,"mtime":1678221097093,"results":"6059","hashOfConfig":"5985"},{"size":2244,"mtime":1675188401520,"results":"6060","hashOfConfig":"5985"},{"size":1814,"mtime":1675188401520,"results":"6061","hashOfConfig":"5985"},{"size":2902,"mtime":1678221097093,"results":"6062","hashOfConfig":"5985"},{"size":8185,"mtime":1678221097093,"results":"6063","hashOfConfig":"5985"},{"size":1504,"mtime":1678221097093,"results":"6064","hashOfConfig":"5985"},{"size":3068,"mtime":1678282296173,"results":"6065","hashOfConfig":"5985"},{"size":4897,"mtime":1678221097093,"results":"6066","hashOfConfig":"5985"},{"size":312,"mtime":1678221097094,"results":"6067","hashOfConfig":"5985"},{"size":44,"mtime":1675188401521,"results":"6068","hashOfConfig":"5985"},{"size":982,"mtime":1678221097094,"results":"6069","hashOfConfig":"5985"},{"size":3870,"mtime":1678221097094,"results":"6070","hashOfConfig":"5985"},{"size":2014,"mtime":1678221097094,"results":"6071","hashOfConfig":"5985"},{"size":800,"mtime":1678221097094,"results":"6072","hashOfConfig":"5985"},{"size":628,"mtime":1678221097094,"results":"6073","hashOfConfig":"5985"},{"size":403,"mtime":1678221097094,"results":"6074","hashOfConfig":"5985"},{"size":280,"mtime":1678221097095,"results":"6075","hashOfConfig":"5985"},{"size":1526,"mtime":1678221097095,"results":"6076","hashOfConfig":"5985"},{"size":1144,"mtime":1678221097095,"results":"6077","hashOfConfig":"5985"},{"size":701,"mtime":1678221097095,"results":"6078","hashOfConfig":"5985"},{"size":441,"mtime":1675188401522,"results":"6079","hashOfConfig":"5985"},{"size":699,"mtime":1678221097095,"results":"6080","hashOfConfig":"5985"},{"size":875,"mtime":1678221097095,"results":"6081","hashOfConfig":"5985"},{"size":242,"mtime":1678221097095,"results":"6082","hashOfConfig":"5985"},{"size":433,"mtime":1678221097096,"results":"6083","hashOfConfig":"5985"},{"size":2140,"mtime":1678221097096,"results":"6084","hashOfConfig":"5985"},{"size":1662,"mtime":1675188401522,"results":"6085","hashOfConfig":"5985"},{"size":46,"mtime":1675188401522,"results":"6086","hashOfConfig":"5985"},{"size":1568,"mtime":1678221097096,"results":"6087","hashOfConfig":"5985"},{"size":800,"mtime":1678221097096,"results":"6088","hashOfConfig":"5985"},{"size":856,"mtime":1678221097096,"results":"6089","hashOfConfig":"5985"},{"size":1038,"mtime":1678221097096,"results":"6090","hashOfConfig":"5985"},{"size":39,"mtime":1675188401523,"results":"6091","hashOfConfig":"5985"},{"size":1252,"mtime":1675188401523,"results":"6092","hashOfConfig":"5985"},{"size":2704,"mtime":1678221097096,"results":"6093","hashOfConfig":"5985"},{"size":1155,"mtime":1678221097096,"results":"6094","hashOfConfig":"5985"},{"size":28,"mtime":1675188401523,"results":"6095","hashOfConfig":"5985"},{"size":1785,"mtime":1678221097096,"results":"6096","hashOfConfig":"5985"},{"size":512,"mtime":1678221097097,"results":"6097","hashOfConfig":"5985"},{"size":911,"mtime":1678221097097,"results":"6098","hashOfConfig":"5985"},{"size":751,"mtime":1678221097097,"results":"6099","hashOfConfig":"5985"},{"size":324,"mtime":1678221097097,"results":"6100","hashOfConfig":"5985"},{"size":867,"mtime":1678221097097,"results":"6101","hashOfConfig":"5985"},{"size":1234,"mtime":1678221097097,"results":"6102","hashOfConfig":"5985"},{"size":1616,"mtime":1678221097097,"results":"6103","hashOfConfig":"5985"},{"size":441,"mtime":1675188401524,"results":"6104","hashOfConfig":"5985"},{"size":416,"mtime":1678221097097,"results":"6105","hashOfConfig":"5985"},{"size":1896,"mtime":1678221097098,"results":"6106","hashOfConfig":"5985"},{"size":447,"mtime":1678221097098,"results":"6107","hashOfConfig":"5985"},{"size":1656,"mtime":1678221097098,"results":"6108","hashOfConfig":"5985"},{"size":2141,"mtime":1678221097098,"results":"6109","hashOfConfig":"5985"},{"size":38,"mtime":1675188401524,"results":"6110","hashOfConfig":"5985"},{"size":341,"mtime":1678221097098,"results":"6111","hashOfConfig":"5985"},{"size":1492,"mtime":1678221097098,"results":"6112","hashOfConfig":"5985"},{"size":539,"mtime":1678221097098,"results":"6113","hashOfConfig":"5985"},{"size":2126,"mtime":1678221097098,"results":"6114","hashOfConfig":"5985"},{"size":1397,"mtime":1678221097098,"results":"6115","hashOfConfig":"5985"},{"size":1521,"mtime":1678221097099,"results":"6116","hashOfConfig":"5985"},{"size":1474,"mtime":1678221097099,"results":"6117","hashOfConfig":"5985"},{"size":44,"mtime":1675188401525,"results":"6118","hashOfConfig":"5985"},{"size":343,"mtime":1678221097099,"results":"6119","hashOfConfig":"5985"},{"size":1795,"mtime":1678221097099,"results":"6120","hashOfConfig":"5985"},{"size":1847,"mtime":1678221097099,"results":"6121","hashOfConfig":"5985"},{"size":974,"mtime":1678221097099,"results":"6122","hashOfConfig":"5985"},{"size":453,"mtime":1678221097099,"results":"6123","hashOfConfig":"5985"},{"size":2160,"mtime":1678221097099,"results":"6124","hashOfConfig":"5985"},{"size":46,"mtime":1675188401525,"results":"6125","hashOfConfig":"5985"},{"size":2336,"mtime":1678221097100,"results":"6126","hashOfConfig":"5985"},{"size":4113,"mtime":1678221097100,"results":"6127","hashOfConfig":"5985"},{"size":986,"mtime":1678221097100,"results":"6128","hashOfConfig":"5985"},{"size":1161,"mtime":1678221097100,"results":"6129","hashOfConfig":"5985"},{"size":54,"mtime":1675188401525,"results":"6130","hashOfConfig":"5985"},{"size":2932,"mtime":1678221097100,"results":"6131","hashOfConfig":"5985"},{"size":3834,"mtime":1678221097100,"results":"6132","hashOfConfig":"5985"},{"size":395,"mtime":1678221097101,"results":"6133","hashOfConfig":"5985"},{"size":413,"mtime":1678221097101,"results":"6134","hashOfConfig":"5985"},{"size":326,"mtime":1678221097101,"results":"6135","hashOfConfig":"5985"},{"size":312,"mtime":1678221097101,"results":"6136","hashOfConfig":"5985"},{"size":407,"mtime":1678221097101,"results":"6137","hashOfConfig":"5985"},{"size":714,"mtime":1678221097101,"results":"6138","hashOfConfig":"5985"},{"size":429,"mtime":1675188401526,"results":"6139","hashOfConfig":"5985"},{"size":3273,"mtime":1678221097101,"results":"6140","hashOfConfig":"5985"},{"size":5199,"mtime":1678221097102,"results":"6141","hashOfConfig":"5985"},{"size":483,"mtime":1678221097102,"results":"6142","hashOfConfig":"5985"},{"size":348,"mtime":1678221097102,"results":"6143","hashOfConfig":"5985"},{"size":584,"mtime":1678221097102,"results":"6144","hashOfConfig":"5985"},{"size":391,"mtime":1675188401526,"results":"6145","hashOfConfig":"5985"},{"size":606,"mtime":1678221097102,"results":"6146","hashOfConfig":"5985"},{"size":236,"mtime":1675188401526,"results":"6147","hashOfConfig":"5985"},{"size":2924,"mtime":1678221097102,"results":"6148","hashOfConfig":"5985"},{"size":846,"mtime":1678221097102,"results":"6149","hashOfConfig":"5985"},{"size":578,"mtime":1678221097103,"results":"6150","hashOfConfig":"5985"},{"size":308,"mtime":1678221097103,"results":"6151","hashOfConfig":"5985"},{"size":512,"mtime":1678221097103,"results":"6152","hashOfConfig":"5985"},{"size":334,"mtime":1678221097103,"results":"6153","hashOfConfig":"5985"},{"size":545,"mtime":1678221097103,"results":"6154","hashOfConfig":"5985"},{"size":388,"mtime":1678221097103,"results":"6155","hashOfConfig":"5985"},{"size":407,"mtime":1678221097104,"results":"6156","hashOfConfig":"5985"},{"size":847,"mtime":1678221097104,"results":"6157","hashOfConfig":"5985"},{"size":300,"mtime":1678221097104,"results":"6158","hashOfConfig":"5985"},{"size":396,"mtime":1678221097104,"results":"6159","hashOfConfig":"5985"},{"size":562,"mtime":1678221097104,"results":"6160","hashOfConfig":"5985"},{"size":690,"mtime":1678221097104,"results":"6161","hashOfConfig":"5985"},{"size":329,"mtime":1678221097104,"results":"6162","hashOfConfig":"5985"},{"size":1199,"mtime":1675188401527,"results":"6163","hashOfConfig":"5985"},{"size":1089,"mtime":1678221097105,"results":"6164","hashOfConfig":"5985"},{"size":594,"mtime":1678221097105,"results":"6165","hashOfConfig":"5985"},{"size":551,"mtime":1678221097105,"results":"6166","hashOfConfig":"5985"},{"size":748,"mtime":1678221097105,"results":"6167","hashOfConfig":"5985"},{"size":2809,"mtime":1678221097105,"results":"6168","hashOfConfig":"5985"},{"size":680,"mtime":1678221097105,"results":"6169","hashOfConfig":"5985"},{"size":4154,"mtime":1678221097106,"results":"6170","hashOfConfig":"5985"},{"size":770,"mtime":1675188401528,"results":"6171","hashOfConfig":"5985"},{"size":46,"mtime":1675188401528,"results":"6172","hashOfConfig":"5985"},{"size":1999,"mtime":1678221097106,"results":"6173","hashOfConfig":"5985"},{"size":2439,"mtime":1678221097106,"results":"6174","hashOfConfig":"5985"},{"size":992,"mtime":1678221097106,"results":"6175","hashOfConfig":"5985"},{"size":842,"mtime":1678221097106,"results":"6176","hashOfConfig":"5985"},{"size":632,"mtime":1678221097106,"results":"6177","hashOfConfig":"5985"},{"size":585,"mtime":1678221097106,"results":"6178","hashOfConfig":"5985"},{"size":1182,"mtime":1678221097106,"results":"6179","hashOfConfig":"5985"},{"size":702,"mtime":1678221097106,"results":"6180","hashOfConfig":"5985"},{"size":895,"mtime":1678221097107,"results":"6181","hashOfConfig":"5985"},{"size":1175,"mtime":1678221097107,"results":"6182","hashOfConfig":"5985"},{"size":895,"mtime":1678221097107,"results":"6183","hashOfConfig":"5985"},{"size":1174,"mtime":1678221097107,"results":"6184","hashOfConfig":"5985"},{"size":865,"mtime":1678221097107,"results":"6185","hashOfConfig":"5985"},{"size":1032,"mtime":1678221097107,"results":"6186","hashOfConfig":"5985"},{"size":1801,"mtime":1678221097107,"results":"6187","hashOfConfig":"5985"},{"size":3191,"mtime":1678221097107,"results":"6188","hashOfConfig":"5985"},{"size":464,"mtime":1678221097107,"results":"6189","hashOfConfig":"5985"},{"size":2233,"mtime":1678221097107,"results":"6190","hashOfConfig":"5985"},{"size":1395,"mtime":1678221097107,"results":"6191","hashOfConfig":"5985"},{"size":329,"mtime":1678221097107,"results":"6192","hashOfConfig":"5985"},{"size":565,"mtime":1678221097108,"results":"6193","hashOfConfig":"5985"},{"size":933,"mtime":1678221097108,"results":"6194","hashOfConfig":"5985"},{"size":1195,"mtime":1678221097108,"results":"6195","hashOfConfig":"5985"},{"size":511,"mtime":1678221097108,"results":"6196","hashOfConfig":"5985"},{"size":1341,"mtime":1678221097108,"results":"6197","hashOfConfig":"5985"},{"size":1277,"mtime":1678221097108,"results":"6198","hashOfConfig":"5985"},{"size":3139,"mtime":1678221097108,"results":"6199","hashOfConfig":"5985"},{"size":3510,"mtime":1678221097108,"results":"6200","hashOfConfig":"5985"},{"size":4226,"mtime":1678221097108,"results":"6201","hashOfConfig":"5985"},{"size":606,"mtime":1678221097108,"results":"6202","hashOfConfig":"5985"},{"size":1190,"mtime":1678221097108,"results":"6203","hashOfConfig":"5985"},{"size":878,"mtime":1678221097108,"results":"6204","hashOfConfig":"5985"},{"size":4049,"mtime":1678221097108,"results":"6205","hashOfConfig":"5985"},{"size":959,"mtime":1678221097109,"results":"6206","hashOfConfig":"5985"},{"size":2508,"mtime":1678221097109,"results":"6207","hashOfConfig":"5985"},{"size":1265,"mtime":1678221097109,"results":"6208","hashOfConfig":"5985"},{"size":1115,"mtime":1678221097109,"results":"6209","hashOfConfig":"5985"},{"size":547,"mtime":1678221097109,"results":"6210","hashOfConfig":"5985"},{"size":587,"mtime":1678221097109,"results":"6211","hashOfConfig":"5985"},{"size":260,"mtime":1678221097109,"results":"6212","hashOfConfig":"5985"},{"size":1276,"mtime":1678221097109,"results":"6213","hashOfConfig":"5985"},{"size":982,"mtime":1678221097109,"results":"6214","hashOfConfig":"5985"},{"size":1839,"mtime":1678221097110,"results":"6215","hashOfConfig":"5985"},{"size":1361,"mtime":1678221097110,"results":"6216","hashOfConfig":"5985"},{"size":1282,"mtime":1678221097110,"results":"6217","hashOfConfig":"5985"},{"size":330,"mtime":1678221097110,"results":"6218","hashOfConfig":"5985"},{"size":629,"mtime":1678221097110,"results":"6219","hashOfConfig":"5985"},{"size":312,"mtime":1678221097110,"results":"6220","hashOfConfig":"5985"},{"size":280,"mtime":1678221097110,"results":"6221","hashOfConfig":"5985"},{"size":293,"mtime":1678221097110,"results":"6222","hashOfConfig":"5985"},{"size":582,"mtime":1678221097110,"results":"6223","hashOfConfig":"5985"},{"size":297,"mtime":1678221097110,"results":"6224","hashOfConfig":"5985"},{"size":376,"mtime":1678221097111,"results":"6225","hashOfConfig":"5985"},{"size":341,"mtime":1678221097111,"results":"6226","hashOfConfig":"5985"},{"size":655,"mtime":1678221097111,"results":"6227","hashOfConfig":"5985"},{"size":2690,"mtime":1678326191467,"results":"6228","hashOfConfig":"5985"},{"size":249,"mtime":1678221097111,"results":"6229","hashOfConfig":"5985"},{"size":317,"mtime":1678221097111,"results":"6230","hashOfConfig":"5985"},{"size":607,"mtime":1678221097111,"results":"6231","hashOfConfig":"5985"},{"size":290,"mtime":1678221097111,"results":"6232","hashOfConfig":"5985"},{"size":297,"mtime":1678221097111,"results":"6233","hashOfConfig":"5985"},{"size":304,"mtime":1678221097111,"results":"6234","hashOfConfig":"5985"},{"size":434,"mtime":1678221097111,"results":"6235","hashOfConfig":"5985"},{"size":483,"mtime":1678326191468,"results":"6236","hashOfConfig":"5985"},{"size":845,"mtime":1678221097112,"results":"6237","hashOfConfig":"5985"},{"size":855,"mtime":1678221097112,"results":"6238","hashOfConfig":"5985"},{"size":590,"mtime":1678221097112,"results":"6239","hashOfConfig":"5985"},{"size":986,"mtime":1678221097112,"results":"6240","hashOfConfig":"5985"},{"size":646,"mtime":1678221097112,"results":"6241","hashOfConfig":"5985"},{"size":494,"mtime":1678221097112,"results":"6242","hashOfConfig":"5985"},{"size":557,"mtime":1678221097112,"results":"6243","hashOfConfig":"5985"},{"size":2137,"mtime":1678221097113,"results":"6244","hashOfConfig":"5985"},{"size":840,"mtime":1678221097113,"results":"6245","hashOfConfig":"5985"},{"size":809,"mtime":1678221097113,"results":"6246","hashOfConfig":"5985"},{"size":833,"mtime":1678221097113,"results":"6247","hashOfConfig":"5985"},{"size":495,"mtime":1678221097113,"results":"6248","hashOfConfig":"5985"},{"size":548,"mtime":1678221097113,"results":"6249","hashOfConfig":"5985"},{"size":679,"mtime":1678221097113,"results":"6250","hashOfConfig":"5985"},{"size":1617,"mtime":1678221097113,"results":"6251","hashOfConfig":"5985"},{"size":524,"mtime":1678221097114,"results":"6252","hashOfConfig":"5985"},{"size":697,"mtime":1678221097114,"results":"6253","hashOfConfig":"5985"},{"size":410,"mtime":1678221097114,"results":"6254","hashOfConfig":"5985"},{"size":606,"mtime":1678326191468,"results":"6255","hashOfConfig":"5985"},{"size":843,"mtime":1678221097114,"results":"6256","hashOfConfig":"5985"},{"size":111,"mtime":1678221097114,"results":"6257","hashOfConfig":"5985"},{"size":671,"mtime":1678221097114,"results":"6258","hashOfConfig":"5985"},{"size":444,"mtime":1678221097114,"results":"6259","hashOfConfig":"5985"},{"size":406,"mtime":1678221097114,"results":"6260","hashOfConfig":"5985"},{"size":753,"mtime":1678221097114,"results":"6261","hashOfConfig":"5985"},{"size":648,"mtime":1678221097114,"results":"6262","hashOfConfig":"5985"},{"size":1018,"mtime":1678221097114,"results":"6263","hashOfConfig":"5985"},{"size":249,"mtime":1675188401535,"results":"6264","hashOfConfig":"5985"},{"size":640,"mtime":1678221097115,"results":"6265","hashOfConfig":"5985"},{"size":1526,"mtime":1678221097115,"results":"6266","hashOfConfig":"5985"},{"size":727,"mtime":1678221097115,"results":"6267","hashOfConfig":"5985"},{"size":424,"mtime":1678221097115,"results":"6268","hashOfConfig":"5985"},{"size":3798,"mtime":1678221097115,"results":"6269","hashOfConfig":"5985"},{"size":1020,"mtime":1678221097115,"results":"6270","hashOfConfig":"5985"},{"size":317,"mtime":1678221097115,"results":"6271","hashOfConfig":"5985"},{"size":240,"mtime":1678221097115,"results":"6272","hashOfConfig":"5985"},{"size":639,"mtime":1678221097115,"results":"6273","hashOfConfig":"5985"},{"size":311,"mtime":1678221097116,"results":"6274","hashOfConfig":"5985"},{"size":1857,"mtime":1678221097116,"results":"6275","hashOfConfig":"5985"},{"size":2335,"mtime":1678221097116,"results":"6276","hashOfConfig":"5985"},{"size":847,"mtime":1678221097116,"results":"6277","hashOfConfig":"5985"},{"size":3479,"mtime":1678221097116,"results":"6278","hashOfConfig":"5985"},{"size":902,"mtime":1678221097116,"results":"6279","hashOfConfig":"5985"},{"size":3487,"mtime":1678221097116,"results":"6280","hashOfConfig":"5985"},{"size":4429,"mtime":1678221097116,"results":"6281","hashOfConfig":"5985"},{"size":2539,"mtime":1678221097117,"results":"6282","hashOfConfig":"5985"},{"size":3203,"mtime":1678221097117,"results":"6283","hashOfConfig":"5985"},{"size":4247,"mtime":1678221097117,"results":"6284","hashOfConfig":"5985"},{"size":2967,"mtime":1678221097117,"results":"6285","hashOfConfig":"5985"},{"size":4594,"mtime":1678221097117,"results":"6286","hashOfConfig":"5985"},{"size":3565,"mtime":1678221097117,"results":"6287","hashOfConfig":"5985"},{"size":937,"mtime":1678221097117,"results":"6288","hashOfConfig":"5985"},{"size":2169,"mtime":1678221097118,"results":"6289","hashOfConfig":"5985"},{"size":651,"mtime":1678221097118,"results":"6290","hashOfConfig":"5985"},{"size":606,"mtime":1678221097118,"results":"6291","hashOfConfig":"5985"},{"size":1218,"mtime":1678221097118,"results":"6292","hashOfConfig":"5985"},{"size":1930,"mtime":1678221097118,"results":"6293","hashOfConfig":"5985"},{"size":411,"mtime":1678221097119,"results":"6294","hashOfConfig":"5985"},{"size":8106,"mtime":1678221097119,"results":"6295","hashOfConfig":"5985"},{"size":801,"mtime":1678221097119,"results":"6296","hashOfConfig":"5985"},{"size":369,"mtime":1678221097119,"results":"6297","hashOfConfig":"5985"},{"size":3554,"mtime":1678221097119,"results":"6298","hashOfConfig":"5985"},{"size":366,"mtime":1678221097119,"results":"6299","hashOfConfig":"5985"},{"size":92,"mtime":1678221097119,"results":"6300","hashOfConfig":"5985"},{"size":783,"mtime":1678221097120,"results":"6301","hashOfConfig":"5985"},{"size":48,"mtime":1675188401538,"results":"6302","hashOfConfig":"5985"},{"size":49,"mtime":1675188401538,"results":"6303","hashOfConfig":"5985"},{"size":453,"mtime":1675188401538,"results":"6304","hashOfConfig":"5985"},{"size":1597,"mtime":1678221097120,"results":"6305","hashOfConfig":"5985"},{"size":1099,"mtime":1678221097120,"results":"6306","hashOfConfig":"5985"},{"size":961,"mtime":1678221097120,"results":"6307","hashOfConfig":"5985"},{"size":2203,"mtime":1678221097120,"results":"6308","hashOfConfig":"5985"},{"size":285,"mtime":1678221097120,"results":"6309","hashOfConfig":"5985"},{"size":144,"mtime":1675188401539,"results":"6310","hashOfConfig":"5985"},{"size":130,"mtime":1675188401539,"results":"6311","hashOfConfig":"5985"},{"size":218,"mtime":1678221097120,"results":"6312","hashOfConfig":"5985"},{"size":241,"mtime":1675188401539,"results":"6313","hashOfConfig":"5985"},{"size":153,"mtime":1675188401539,"results":"6314","hashOfConfig":"5985"},{"size":192,"mtime":1675188401539,"results":"6315","hashOfConfig":"5985"},{"size":1587,"mtime":1675188401539,"results":"6316","hashOfConfig":"5985"},{"size":644,"mtime":1678221097121,"results":"6317","hashOfConfig":"5985"},{"size":363,"mtime":1675188401539,"results":"6318","hashOfConfig":"5985"},{"size":861,"mtime":1678221097121,"results":"6319","hashOfConfig":"5985"},{"size":1263,"mtime":1675188401539,"results":"6320","hashOfConfig":"5985"},{"size":432,"mtime":1675188401539,"results":"6321","hashOfConfig":"5985"},{"size":167,"mtime":1675188401539,"results":"6322","hashOfConfig":"5985"},{"size":1445,"mtime":1678221097121,"results":"6323","hashOfConfig":"5985"},{"size":1987,"mtime":1678221097121,"results":"6324","hashOfConfig":"5985"},{"size":1065,"mtime":1678221097121,"results":"6325","hashOfConfig":"5985"},{"size":1518,"mtime":1675188401539,"results":"6326","hashOfConfig":"5985"},{"size":4731,"mtime":1678221097121,"results":"6327","hashOfConfig":"5985"},{"size":334,"mtime":1675188401540,"results":"6328","hashOfConfig":"5985"},{"size":886,"mtime":1678221097121,"results":"6329","hashOfConfig":"5985"},{"size":785,"mtime":1675188401540,"results":"6330","hashOfConfig":"5985"},{"size":664,"mtime":1678221097121,"results":"6331","hashOfConfig":"5985"},{"size":476,"mtime":1675188401540,"results":"6332","hashOfConfig":"5985"},{"size":693,"mtime":1675188401540,"results":"6333","hashOfConfig":"5985"},{"size":455,"mtime":1675188401540,"results":"6334","hashOfConfig":"5985"},{"size":241,"mtime":1675188401540,"results":"6335","hashOfConfig":"5985"},{"size":586,"mtime":1678221097122,"results":"6336","hashOfConfig":"5985"},{"size":547,"mtime":1678221097122,"results":"6337","hashOfConfig":"5985"},{"size":342,"mtime":1675188401540,"results":"6338","hashOfConfig":"5985"},{"size":769,"mtime":1678221097122,"results":"6339","hashOfConfig":"5985"},{"size":350,"mtime":1678221097122,"results":"6340","hashOfConfig":"5985"},{"size":1561,"mtime":1678221097122,"results":"6341","hashOfConfig":"5985"},{"size":463,"mtime":1675188401540,"results":"6342","hashOfConfig":"5985"},{"size":300,"mtime":1678221097122,"results":"6343","hashOfConfig":"5985"},{"size":600,"mtime":1678221097123,"results":"6344","hashOfConfig":"5985"},{"size":559,"mtime":1675188401541,"results":"6345","hashOfConfig":"5985"},{"size":1330,"mtime":1678221097123,"results":"6346","hashOfConfig":"5985"},{"size":865,"mtime":1678221097123,"results":"6347","hashOfConfig":"5985"},{"size":901,"mtime":1675188401541,"results":"6348","hashOfConfig":"5985"},{"size":221,"mtime":1675188401541,"results":"6349","hashOfConfig":"5985"},{"size":161,"mtime":1675188401541,"results":"6350","hashOfConfig":"5985"},{"size":628,"mtime":1675188401541,"results":"6351","hashOfConfig":"5985"},{"size":204,"mtime":1675188401541,"results":"6352","hashOfConfig":"5985"},{"size":2443,"mtime":1678221097123,"results":"6353","hashOfConfig":"5985"},{"size":1047,"mtime":1675188401541,"results":"6354","hashOfConfig":"5985"},{"size":733,"mtime":1678221097123,"results":"6355","hashOfConfig":"5985"},{"size":407,"mtime":1675188401541,"results":"6356","hashOfConfig":"5985"},{"size":2622,"mtime":1678221097123,"results":"6357","hashOfConfig":"5985"},{"size":1298,"mtime":1675188401542,"results":"6358","hashOfConfig":"5985"},{"size":3446,"mtime":1678221097124,"results":"6359","hashOfConfig":"5985"},{"size":1239,"mtime":1675188401542,"results":"6360","hashOfConfig":"5985"},{"size":4454,"mtime":1678221097124,"results":"6361","hashOfConfig":"5985"},{"size":22786,"mtime":1678221097124,"results":"6362","hashOfConfig":"5985"},{"size":657,"mtime":1678221097124,"results":"6363","hashOfConfig":"5985"},{"size":503,"mtime":1678221097124,"results":"6364","hashOfConfig":"5985"},{"size":126,"mtime":1675188401542,"results":"6365","hashOfConfig":"5985"},{"size":2428,"mtime":1678221097124,"results":"6366","hashOfConfig":"5985"},{"size":139,"mtime":1675188401542,"results":"6367","hashOfConfig":"5985"},{"size":1985,"mtime":1678221097125,"results":"6368","hashOfConfig":"5985"},{"size":484,"mtime":1675188401542,"results":"6369","hashOfConfig":"5985"},{"size":5475,"mtime":1678221097125,"results":"6370","hashOfConfig":"5985"},{"size":127,"mtime":1678221097125,"results":"6371","hashOfConfig":"5985"},{"size":9712,"mtime":1678221097125,"results":"6372","hashOfConfig":"5985"},{"size":787,"mtime":1678221097125,"results":"6373","hashOfConfig":"5985"},{"size":694,"mtime":1678221097125,"results":"6374","hashOfConfig":"5985"},{"size":2606,"mtime":1678221097125,"results":"6375","hashOfConfig":"5985"},{"size":1906,"mtime":1678221097125,"results":"6376","hashOfConfig":"5985"},{"size":497,"mtime":1678221097125,"results":"6377","hashOfConfig":"5985"},{"size":1935,"mtime":1678221097125,"results":"6378","hashOfConfig":"5985"},{"size":2520,"mtime":1678221097125,"results":"6379","hashOfConfig":"5985"},{"size":1531,"mtime":1678221097126,"results":"6380","hashOfConfig":"5985"},{"size":3424,"mtime":1678221097126,"results":"6381","hashOfConfig":"5985"},{"size":639,"mtime":1678221097126,"results":"6382","hashOfConfig":"5985"},{"size":132,"mtime":1675188401543,"results":"6383","hashOfConfig":"5985"},{"size":1158,"mtime":1675188401543,"results":"6384","hashOfConfig":"5985"},{"size":3493,"mtime":1678282296173,"results":"6385","hashOfConfig":"5985"},{"size":1584,"mtime":1678221097126,"results":"6386","hashOfConfig":"5985"},{"size":298,"mtime":1675188401544,"results":"6387","hashOfConfig":"5985"},{"size":1599,"mtime":1675188401544,"results":"6388","hashOfConfig":"5985"},{"size":1526,"mtime":1675188401544,"results":"6389","hashOfConfig":"5985"},{"size":2966,"mtime":1678221097126,"results":"6390","hashOfConfig":"5985"},{"size":312,"mtime":1675188401544,"results":"6391","hashOfConfig":"5985"},{"size":231,"mtime":1675188401544,"results":"6392","hashOfConfig":"5985"},{"size":263,"mtime":1678221097126,"results":"6393","hashOfConfig":"5985"},{"size":1772,"mtime":1678221097126,"results":"6394","hashOfConfig":"5985"},{"size":611,"mtime":1675188401544,"results":"6395","hashOfConfig":"5985"},{"size":1410,"mtime":1675188401544,"results":"6396","hashOfConfig":"5985"},{"size":879,"mtime":1675188401544,"results":"6397","hashOfConfig":"5985"},{"size":349,"mtime":1675188401544,"results":"6398","hashOfConfig":"5985"},{"size":3594,"mtime":1678221097126,"results":"6399","hashOfConfig":"5985"},{"size":2165,"mtime":1675188401545,"results":"6400","hashOfConfig":"5985"},{"size":2006,"mtime":1675188401545,"results":"6401","hashOfConfig":"5985"},{"size":3507,"mtime":1675188401545,"results":"6402","hashOfConfig":"5985"},{"size":1619,"mtime":1675188401545,"results":"6403","hashOfConfig":"5985"},{"size":261,"mtime":1675188401545,"results":"6404","hashOfConfig":"5985"},{"size":1230,"mtime":1675188401545,"results":"6405","hashOfConfig":"5985"},{"size":8604,"mtime":1678221097127,"results":"6406","hashOfConfig":"5985"},{"size":1885,"mtime":1678221097127,"results":"6407","hashOfConfig":"5985"},{"size":1590,"mtime":1675188401545,"results":"6408","hashOfConfig":"5985"},{"size":851,"mtime":1678221097127,"results":"6409","hashOfConfig":"5985"},{"size":248,"mtime":1675188401545,"results":"6410","hashOfConfig":"5985"},{"size":205,"mtime":1675188401545,"results":"6411","hashOfConfig":"5985"},{"size":5806,"mtime":1678221097127,"results":"6412","hashOfConfig":"5985"},{"size":2543,"mtime":1678221097127,"results":"6413","hashOfConfig":"5985"},{"size":2417,"mtime":1678221097127,"results":"6414","hashOfConfig":"5985"},{"size":1483,"mtime":1675188401546,"results":"6415","hashOfConfig":"5985"},{"size":4525,"mtime":1678221097127,"results":"6416","hashOfConfig":"5985"},{"size":216,"mtime":1675188401546,"results":"6417","hashOfConfig":"5985"},{"size":5872,"mtime":1678221097127,"results":"6418","hashOfConfig":"5985"},{"size":1092,"mtime":1675188401546,"results":"6419","hashOfConfig":"5985"},{"size":529,"mtime":1675188401546,"results":"6420","hashOfConfig":"5985"},{"size":4593,"mtime":1678221097127,"results":"6421","hashOfConfig":"5985"},{"size":548,"mtime":1675188401546,"results":"6422","hashOfConfig":"5985"},{"size":161,"mtime":1675188401546,"results":"6423","hashOfConfig":"5985"},{"size":2487,"mtime":1675188401546,"results":"6424","hashOfConfig":"5985"},{"size":3131,"mtime":1678221097128,"results":"6425","hashOfConfig":"5985"},{"size":3233,"mtime":1678221097128,"results":"6426","hashOfConfig":"5985"},{"size":452,"mtime":1675188401547,"results":"6427","hashOfConfig":"5985"},{"size":1126,"mtime":1678221097128,"results":"6428","hashOfConfig":"5985"},{"size":775,"mtime":1678221097128,"results":"6429","hashOfConfig":"5985"},{"size":458,"mtime":1678221097128,"results":"6430","hashOfConfig":"5985"},{"size":654,"mtime":1675188401547,"results":"6431","hashOfConfig":"5985"},{"size":4039,"mtime":1678221097128,"results":"6432","hashOfConfig":"5985"},{"size":682,"mtime":1675188401547,"results":"6433","hashOfConfig":"5985"},{"size":488,"mtime":1678221097128,"results":"6434","hashOfConfig":"5985"},{"size":500,"mtime":1678221097128,"results":"6435","hashOfConfig":"5985"},{"size":537,"mtime":1675188401547,"results":"6436","hashOfConfig":"5985"},{"size":132,"mtime":1675188401547,"results":"6437","hashOfConfig":"5985"},{"size":285,"mtime":1675188401547,"results":"6438","hashOfConfig":"5985"},{"size":549,"mtime":1678221097128,"results":"6439","hashOfConfig":"5985"},{"size":991,"mtime":1675188401547,"results":"6440","hashOfConfig":"5985"},{"size":313,"mtime":1675188401547,"results":"6441","hashOfConfig":"5985"},{"size":582,"mtime":1675188401547,"results":"6442","hashOfConfig":"5985"},{"size":354,"mtime":1675188401547,"results":"6443","hashOfConfig":"5985"},{"size":419,"mtime":1678221097129,"results":"6444","hashOfConfig":"5985"},{"size":800,"mtime":1678221097129,"results":"6445","hashOfConfig":"5985"},{"size":824,"mtime":1678221097129,"results":"6446","hashOfConfig":"5985"},{"size":815,"mtime":1675188401548,"results":"6447","hashOfConfig":"5985"},{"size":253,"mtime":1675188401548,"results":"6448","hashOfConfig":"5985"},{"size":381,"mtime":1675188401548,"results":"6449","hashOfConfig":"5985"},{"size":486,"mtime":1678221097129,"results":"6450","hashOfConfig":"5985"},{"size":247,"mtime":1675188401548,"results":"6451","hashOfConfig":"5985"},{"size":919,"mtime":1675188401548,"results":"6452","hashOfConfig":"5985"},{"size":404,"mtime":1675188401548,"results":"6453","hashOfConfig":"5985"},{"size":75,"mtime":1675188401548,"results":"6454","hashOfConfig":"5985"},{"size":155,"mtime":1675188401548,"results":"6455","hashOfConfig":"5985"},{"size":365,"mtime":1675188401548,"results":"6456","hashOfConfig":"5985"},{"size":280,"mtime":1675188401548,"results":"6457","hashOfConfig":"5985"},{"size":251,"mtime":1675188401548,"results":"6458","hashOfConfig":"5985"},{"size":479,"mtime":1675188401548,"results":"6459","hashOfConfig":"5985"},{"size":1277,"mtime":1678221097129,"results":"6460","hashOfConfig":"5985"},{"size":550,"mtime":1678221097129,"results":"6461","hashOfConfig":"5985"},{"size":508,"mtime":1678221097129,"results":"6462","hashOfConfig":"5985"},{"size":461,"mtime":1678221097130,"results":"6463","hashOfConfig":"5985"},{"size":187,"mtime":1675188401549,"results":"6464","hashOfConfig":"5985"},{"size":1772,"mtime":1678221097130,"results":"6465","hashOfConfig":"5985"},{"size":268,"mtime":1675188401549,"results":"6466","hashOfConfig":"5985"},{"size":247,"mtime":1678221097130,"results":"6467","hashOfConfig":"5985"},{"size":1015,"mtime":1678221097130,"results":"6468","hashOfConfig":"5985"},{"size":537,"mtime":1675188401549,"results":"6469","hashOfConfig":"5985"},{"size":782,"mtime":1678221097130,"results":"6470","hashOfConfig":"5985"},{"size":289,"mtime":1675188401549,"results":"6471","hashOfConfig":"5985"},{"size":978,"mtime":1678221097130,"results":"6472","hashOfConfig":"5985"},{"size":3678,"mtime":1678221097130,"results":"6473","hashOfConfig":"5985"},{"size":4305,"mtime":1678221097131,"results":"6474","hashOfConfig":"5985"},{"size":2050,"mtime":1675188401549,"results":"6475","hashOfConfig":"5985"},{"size":1836,"mtime":1675188401549,"results":"6476","hashOfConfig":"5985"},{"size":35486,"mtime":1678221097131,"results":"6477","hashOfConfig":"5985"},{"size":423,"mtime":1678221097131,"results":"6478","hashOfConfig":"5985"},{"size":341,"mtime":1675188401550,"results":"6479","hashOfConfig":"5985"},{"size":199,"mtime":1678221097131,"results":"6480","hashOfConfig":"5985"},{"size":321,"mtime":1675188401550,"results":"6481","hashOfConfig":"5985"},{"size":1181,"mtime":1678221097131,"results":"6482","hashOfConfig":"5985"},{"size":173,"mtime":1675188401550,"results":"6483","hashOfConfig":"5985"},{"size":1525,"mtime":1678221097131,"results":"6484","hashOfConfig":"5985"},{"size":321,"mtime":1675188401550,"results":"6485","hashOfConfig":"5985"},{"size":1192,"mtime":1678221097131,"results":"6486","hashOfConfig":"5985"},{"size":2691,"mtime":1678221097132,"results":"6487","hashOfConfig":"5985"},{"size":369,"mtime":1675188401550,"results":"6488","hashOfConfig":"5985"},{"size":2910,"mtime":1678221097132,"results":"6489","hashOfConfig":"5985"},{"size":561,"mtime":1675188401550,"results":"6490","hashOfConfig":"5985"},{"size":397,"mtime":1675188401550,"results":"6491","hashOfConfig":"5985"},{"size":203,"mtime":1675188401550,"results":"6492","hashOfConfig":"5985"},{"size":240,"mtime":1675188401550,"results":"6493","hashOfConfig":"5985"},{"size":641,"mtime":1678221097132,"results":"6494","hashOfConfig":"5985"},{"size":534,"mtime":1678221097132,"results":"6495","hashOfConfig":"5985"},{"size":1334,"mtime":1678326191468,"results":"6496","hashOfConfig":"5985"},{"size":1804,"mtime":1678221097132,"results":"6497","hashOfConfig":"5985"},{"size":1330,"mtime":1678221097132,"results":"6498","hashOfConfig":"5985"},{"size":21050,"mtime":1678221097133,"results":"6499","hashOfConfig":"5985"},{"size":86,"mtime":1675188401551,"results":"6500","hashOfConfig":"5985"},{"size":484,"mtime":1678221097133,"results":"6501","hashOfConfig":"5985"},{"size":32,"mtime":1675188401551,"results":"6502","hashOfConfig":"5985"},{"size":666,"mtime":1678221097133,"results":"6503","hashOfConfig":"5985"},{"size":650,"mtime":1678221097133,"results":"6504","hashOfConfig":"5985"},{"size":366,"mtime":1678221097133,"results":"6505","hashOfConfig":"5985"},{"size":3268,"mtime":1678221097134,"results":"6506","hashOfConfig":"5985"},{"size":224,"mtime":1678221097134,"results":"6507","hashOfConfig":"5985"},{"size":1801,"mtime":1678221097134,"results":"6508","hashOfConfig":"5985"},{"size":2673,"mtime":1678326191469,"results":"6509","hashOfConfig":"5985"},{"size":755,"mtime":1678221097134,"results":"6510","hashOfConfig":"5985"},{"size":6266,"mtime":1678221097134,"results":"6511","hashOfConfig":"5985"},{"size":3537,"mtime":1678221097134,"results":"6512","hashOfConfig":"5985"},{"size":2709,"mtime":1678221097135,"results":"6513","hashOfConfig":"5985"},{"size":599,"mtime":1678221097135,"results":"6514","hashOfConfig":"5985"},{"size":3749,"mtime":1678221097135,"results":"6515","hashOfConfig":"5985"},{"size":1361,"mtime":1678221097135,"results":"6516","hashOfConfig":"5985"},{"size":4085,"mtime":1678221097135,"results":"6517","hashOfConfig":"5985"},{"size":6030,"mtime":1678221097136,"results":"6518","hashOfConfig":"5985"},{"size":1114,"mtime":1678221097136,"results":"6519","hashOfConfig":"5985"},{"size":5701,"mtime":1678221097136,"results":"6520","hashOfConfig":"5985"},{"size":4004,"mtime":1678221097136,"results":"6521","hashOfConfig":"5985"},{"size":1632,"mtime":1678221097136,"results":"6522","hashOfConfig":"5985"},{"size":1972,"mtime":1678221097136,"results":"6523","hashOfConfig":"5985"},{"size":2185,"mtime":1678221097137,"results":"6524","hashOfConfig":"5985"},{"size":2679,"mtime":1678221097137,"results":"6525","hashOfConfig":"5985"},{"size":1611,"mtime":1678221097137,"results":"6526","hashOfConfig":"5985"},{"size":1868,"mtime":1678221097137,"results":"6527","hashOfConfig":"5985"},{"size":3531,"mtime":1678221097137,"results":"6528","hashOfConfig":"5985"},{"size":2371,"mtime":1678221097137,"results":"6529","hashOfConfig":"5985"},{"size":833,"mtime":1678221097138,"results":"6530","hashOfConfig":"5985"},{"size":7090,"mtime":1678221097138,"results":"6531","hashOfConfig":"5985"},{"size":38,"mtime":1675188401554,"results":"6532","hashOfConfig":"5985"},{"size":842,"mtime":1678221097138,"results":"6533","hashOfConfig":"5985"},{"size":6366,"mtime":1678221097138,"results":"6534","hashOfConfig":"5985"},{"size":2927,"mtime":1678221097138,"results":"6535","hashOfConfig":"5985"},{"size":3155,"mtime":1678221097139,"results":"6536","hashOfConfig":"5985"},{"size":462,"mtime":1678221097139,"results":"6537","hashOfConfig":"5985"},{"size":496,"mtime":1678221097139,"results":"6538","hashOfConfig":"5985"},{"size":1114,"mtime":1678221097139,"results":"6539","hashOfConfig":"5985"},{"size":43,"mtime":1675188401554,"results":"6540","hashOfConfig":"5985"},{"size":3083,"mtime":1678221097139,"results":"6541","hashOfConfig":"5985"},{"size":5366,"mtime":1678221097139,"results":"6542","hashOfConfig":"5985"},{"size":692,"mtime":1678221097140,"results":"6543","hashOfConfig":"5985"},{"size":2752,"mtime":1678221097140,"results":"6544","hashOfConfig":"5985"},{"size":10676,"mtime":1678221097140,"results":"6545","hashOfConfig":"5985"},{"size":48,"mtime":1678221097140,"results":"6546","hashOfConfig":"5985"},{"size":1924,"mtime":1678221097140,"results":"6547","hashOfConfig":"5985"},{"size":8250,"mtime":1678221097140,"results":"6548","hashOfConfig":"5985"},{"size":45,"mtime":1675188401555,"results":"6549","hashOfConfig":"5985"},{"size":3280,"mtime":1678221097141,"results":"6550","hashOfConfig":"5985"},{"size":2135,"mtime":1678221097141,"results":"6551","hashOfConfig":"5985"},{"size":6330,"mtime":1678221097141,"results":"6552","hashOfConfig":"5985"},{"size":1308,"mtime":1678221097141,"results":"6553","hashOfConfig":"5985"},{"size":1164,"mtime":1678221097141,"results":"6554","hashOfConfig":"5985"},{"size":2649,"mtime":1678221097141,"results":"6555","hashOfConfig":"5985"},{"size":646,"mtime":1678221097142,"results":"6556","hashOfConfig":"5985"},{"size":724,"mtime":1678221097142,"results":"6557","hashOfConfig":"5985"},{"size":563,"mtime":1678221097142,"results":"6558","hashOfConfig":"5985"},{"size":1192,"mtime":1678221097142,"results":"6559","hashOfConfig":"5985"},{"size":829,"mtime":1678221097142,"results":"6560","hashOfConfig":"5985"},{"size":512,"mtime":1678221097142,"results":"6561","hashOfConfig":"5985"},{"size":1060,"mtime":1678221097142,"results":"6562","hashOfConfig":"5985"},{"size":1297,"mtime":1678221097143,"results":"6563","hashOfConfig":"5985"},{"size":1310,"mtime":1678221097143,"results":"6564","hashOfConfig":"5985"},{"size":901,"mtime":1678221097143,"results":"6565","hashOfConfig":"5985"},{"size":689,"mtime":1678221097143,"results":"6566","hashOfConfig":"5985"},{"size":3906,"mtime":1675694258722,"results":"6567","hashOfConfig":"5985"},{"size":595,"mtime":1678221097143,"results":"6568","hashOfConfig":"5985"},{"size":607,"mtime":1678221097143,"results":"6569","hashOfConfig":"5985"},{"size":37,"mtime":1678221097143,"results":"6570","hashOfConfig":"5985"},{"size":983,"mtime":1678221097143,"results":"6571","hashOfConfig":"5985"},{"size":629,"mtime":1678221097144,"results":"6572","hashOfConfig":"5985"},{"size":10427,"mtime":1678221097144,"results":"6573","hashOfConfig":"5985"},{"size":1250,"mtime":1678221097144,"results":"6574","hashOfConfig":"5985"},{"size":2247,"mtime":1678221097144,"results":"6575","hashOfConfig":"5985"},{"size":639,"mtime":1678221097144,"results":"6576","hashOfConfig":"5985"},{"size":838,"mtime":1678221097144,"results":"6577","hashOfConfig":"5985"},{"size":739,"mtime":1678221097144,"results":"6578","hashOfConfig":"5985"},{"size":388,"mtime":1678221097145,"results":"6579","hashOfConfig":"5985"},{"size":415,"mtime":1678221097145,"results":"6580","hashOfConfig":"5985"},{"size":1674,"mtime":1678221097145,"results":"6581","hashOfConfig":"5985"},{"size":1275,"mtime":1678221097145,"results":"6582","hashOfConfig":"5985"},{"size":220,"mtime":1678221097145,"results":"6583","hashOfConfig":"5985"},{"size":383,"mtime":1675188401558,"results":"6584","hashOfConfig":"5985"},{"size":137,"mtime":1675188401558,"results":"6585","hashOfConfig":"5985"},{"size":293,"mtime":1678221097145,"results":"6586","hashOfConfig":"5985"},{"size":608,"mtime":1678221097145,"results":"6587","hashOfConfig":"5985"},{"size":690,"mtime":1678221097145,"results":"6588","hashOfConfig":"5985"},{"size":595,"mtime":1678221097145,"results":"6589","hashOfConfig":"5985"},{"size":912,"mtime":1678221097145,"results":"6590","hashOfConfig":"5985"},{"size":869,"mtime":1678221097146,"results":"6591","hashOfConfig":"5985"},{"size":1026,"mtime":1678221097146,"results":"6592","hashOfConfig":"5985"},{"size":1391,"mtime":1678221097146,"results":"6593","hashOfConfig":"5985"},{"size":1027,"mtime":1678221097146,"results":"6594","hashOfConfig":"5985"},{"size":1335,"mtime":1678221097146,"results":"6595","hashOfConfig":"5985"},{"size":1213,"mtime":1678221097146,"results":"6596","hashOfConfig":"5985"},{"size":1137,"mtime":1678221097146,"results":"6597","hashOfConfig":"5985"},{"size":327,"mtime":1675188401558,"results":"6598","hashOfConfig":"5985"},{"size":84,"mtime":1678221097146,"results":"6599","hashOfConfig":"5985"},{"size":432,"mtime":1678221097146,"results":"6600","hashOfConfig":"5985"},{"size":317,"mtime":1675188401558,"results":"6601","hashOfConfig":"5985"},{"size":751,"mtime":1675694258725,"results":"6602","hashOfConfig":"5985"},{"size":1753,"mtime":1675188401558,"results":"6603","hashOfConfig":"5985"},{"size":693,"mtime":1675188401558,"results":"6604","hashOfConfig":"5985"},{"size":742,"mtime":1678221097146,"results":"6605","hashOfConfig":"5985"},{"size":115,"mtime":1678221097146,"results":"6606","hashOfConfig":"5985"},{"size":295,"mtime":1678221097146,"results":"6607","hashOfConfig":"5985"},{"size":859,"mtime":1678221097146,"results":"6608","hashOfConfig":"5985"},{"size":358,"mtime":1678221097146,"results":"6609","hashOfConfig":"5985"},{"size":619,"mtime":1675188401558,"results":"6610","hashOfConfig":"5985"},{"size":450,"mtime":1675188401558,"results":"6611","hashOfConfig":"5985"},{"size":4098,"mtime":1678221097147,"results":"6612","hashOfConfig":"5985"},{"size":741,"mtime":1675188401559,"results":"6613","hashOfConfig":"5985"},{"size":25,"mtime":1678221097147,"results":"6614","hashOfConfig":"5985"},{"size":316,"mtime":1678221097147,"results":"6615","hashOfConfig":"5985"},{"size":443,"mtime":1675188401559,"results":"6616","hashOfConfig":"5985"},{"size":2754,"mtime":1678221097147,"results":"6617","hashOfConfig":"5985"},{"size":1153,"mtime":1678221097147,"results":"6618","hashOfConfig":"5985"},{"size":1007,"mtime":1678221097147,"results":"6619","hashOfConfig":"5985"},{"size":382,"mtime":1675188401559,"results":"6620","hashOfConfig":"5985"},{"size":1374,"mtime":1678221097147,"results":"6621","hashOfConfig":"5985"},{"size":499,"mtime":1675188401559,"results":"6622","hashOfConfig":"5985"},{"size":729,"mtime":1675188401559,"results":"6623","hashOfConfig":"5985"},{"size":1526,"mtime":1678221097147,"results":"6624","hashOfConfig":"5985"},{"size":87,"mtime":1675188401559,"results":"6625","hashOfConfig":"5985"},{"size":3198,"mtime":1678221097148,"results":"6626","hashOfConfig":"5985"},{"size":473,"mtime":1675188401560,"results":"6627","hashOfConfig":"5985"},{"size":905,"mtime":1675188401560,"results":"6628","hashOfConfig":"5985"},{"size":889,"mtime":1675188401560,"results":"6629","hashOfConfig":"5985"},{"size":306,"mtime":1675188401560,"results":"6630","hashOfConfig":"5985"},{"size":2591,"mtime":1678221097148,"results":"6631","hashOfConfig":"5985"},{"size":629,"mtime":1675188401560,"results":"6632","hashOfConfig":"5985"},{"size":852,"mtime":1675188401560,"results":"6633","hashOfConfig":"5985"},{"size":820,"mtime":1675188401560,"results":"6634","hashOfConfig":"5985"},{"size":681,"mtime":1675188401560,"results":"6635","hashOfConfig":"5985"},{"size":709,"mtime":1675188401560,"results":"6636","hashOfConfig":"5985"},{"size":988,"mtime":1675188401560,"results":"6637","hashOfConfig":"5985"},{"size":138,"mtime":1678221097148,"results":"6638","hashOfConfig":"5985"},{"size":821,"mtime":1675188401561,"results":"6639","hashOfConfig":"5985"},{"size":851,"mtime":1675188401561,"results":"6640","hashOfConfig":"5985"},{"size":21,"mtime":1675188401561,"results":"6641","hashOfConfig":"5985"},{"size":448,"mtime":1678221097148,"results":"6642","hashOfConfig":"5985"},{"size":402,"mtime":1675188401561,"results":"6643","hashOfConfig":"5985"},{"size":1563,"mtime":1675188401561,"results":"6644","hashOfConfig":"5985"},{"size":6181,"mtime":1678221097148,"results":"6645","hashOfConfig":"5985"},{"size":660,"mtime":1675188401561,"results":"6646","hashOfConfig":"5985"},{"size":429,"mtime":1675188401561,"results":"6647","hashOfConfig":"5985"},{"size":40,"mtime":1675188401561,"results":"6648","hashOfConfig":"5985"},{"size":541,"mtime":1675188401561,"results":"6649","hashOfConfig":"5985"},{"size":2806,"mtime":1678221097148,"results":"6650","hashOfConfig":"5985"},{"size":851,"mtime":1675188401561,"results":"6651","hashOfConfig":"5985"},{"size":26,"mtime":1675188401562,"results":"6652","hashOfConfig":"5985"},{"size":2320,"mtime":1675188401562,"results":"6653","hashOfConfig":"5985"},{"size":1616,"mtime":1675188401562,"results":"6654","hashOfConfig":"5985"},{"size":445,"mtime":1678221097148,"results":"6655","hashOfConfig":"5985"},{"size":922,"mtime":1675188401562,"results":"6656","hashOfConfig":"5985"},{"size":870,"mtime":1678221097149,"results":"6657","hashOfConfig":"5985"},{"size":494,"mtime":1678221097149,"results":"6658","hashOfConfig":"5985"},{"size":816,"mtime":1678221097149,"results":"6659","hashOfConfig":"5985"},{"size":6112,"mtime":1678221097149,"results":"6660","hashOfConfig":"5985"},{"size":1643,"mtime":1678221097149,"results":"6661","hashOfConfig":"5985"},{"size":375,"mtime":1675188401562,"results":"6662","hashOfConfig":"5985"},{"size":189,"mtime":1675188401562,"results":"6663","hashOfConfig":"5985"},{"size":199,"mtime":1675188401563,"results":"6664","hashOfConfig":"5985"},{"size":189,"mtime":1675188401563,"results":"6665","hashOfConfig":"5985"},{"size":225,"mtime":1675188401563,"results":"6666","hashOfConfig":"5985"},{"size":131,"mtime":1675188401563,"results":"6667","hashOfConfig":"5985"},{"size":142,"mtime":1675188401563,"results":"6668","hashOfConfig":"5985"},{"size":247,"mtime":1675188401563,"results":"6669","hashOfConfig":"5985"},{"size":157,"mtime":1675188401563,"results":"6670","hashOfConfig":"5985"},{"size":176,"mtime":1675188401563,"results":"6671","hashOfConfig":"5985"},{"size":411,"mtime":1675188401563,"results":"6672","hashOfConfig":"5985"},{"size":320,"mtime":1678221097149,"results":"6673","hashOfConfig":"5985"},{"size":909,"mtime":1678221097149,"results":"6674","hashOfConfig":"5985"},{"size":1225,"mtime":1678221097150,"results":"6675","hashOfConfig":"5985"},{"size":133,"mtime":1675188401563,"results":"6676","hashOfConfig":"5985"},{"size":2426,"mtime":1678221097150,"results":"6677","hashOfConfig":"5985"},{"size":525,"mtime":1678221097150,"results":"6678","hashOfConfig":"5985"},{"size":2104,"mtime":1678221097150,"results":"6679","hashOfConfig":"5985"},{"size":2680,"mtime":1678221097150,"results":"6680","hashOfConfig":"5985"},{"size":5134,"mtime":1678221097150,"results":"6681","hashOfConfig":"5985"},{"size":934,"mtime":1678221097150,"results":"6682","hashOfConfig":"5985"},{"size":2207,"mtime":1678221097151,"results":"6683","hashOfConfig":"5985"},{"size":1229,"mtime":1678221097151,"results":"6684","hashOfConfig":"5985"},{"size":1590,"mtime":1678221097151,"results":"6685","hashOfConfig":"5985"},{"size":8501,"mtime":1678221097151,"results":"6686","hashOfConfig":"5985"},{"size":3031,"mtime":1678221097151,"results":"6687","hashOfConfig":"5985"},{"size":7757,"mtime":1678221097151,"results":"6688","hashOfConfig":"5985"},{"size":4368,"mtime":1678221097152,"results":"6689","hashOfConfig":"5985"},{"size":1804,"mtime":1678221097152,"results":"6690","hashOfConfig":"5985"},{"size":12000,"mtime":1678221097152,"results":"6691","hashOfConfig":"5985"},{"size":8804,"mtime":1678221097152,"results":"6692","hashOfConfig":"5985"},{"size":507,"mtime":1678221097152,"results":"6693","hashOfConfig":"5985"},{"size":1776,"mtime":1678221097152,"results":"6694","hashOfConfig":"5985"},{"size":1009,"mtime":1678221097152,"results":"6695","hashOfConfig":"5985"},{"size":1786,"mtime":1678221097153,"results":"6696","hashOfConfig":"5985"},{"size":635,"mtime":1678221097153,"results":"6697","hashOfConfig":"5985"},{"size":1204,"mtime":1678221097153,"results":"6698","hashOfConfig":"5985"},{"size":4366,"mtime":1678221097153,"results":"6699","hashOfConfig":"5985"},{"size":1626,"mtime":1678221097153,"results":"6700","hashOfConfig":"5985"},{"size":5708,"mtime":1678221097153,"results":"6701","hashOfConfig":"5985"},{"size":1378,"mtime":1678221097153,"results":"6702","hashOfConfig":"5985"},{"size":499,"mtime":1678221097154,"results":"6703","hashOfConfig":"5985"},{"size":508,"mtime":1678221097154,"results":"6704","hashOfConfig":"5985"},{"size":1759,"mtime":1678221097154,"results":"6705","hashOfConfig":"5985"},{"size":6261,"mtime":1678221097154,"results":"6706","hashOfConfig":"5985"},{"size":2471,"mtime":1678221097154,"results":"6707","hashOfConfig":"5985"},{"size":48,"mtime":1675188401566,"results":"6708","hashOfConfig":"5985"},{"size":363,"mtime":1678221097154,"results":"6709","hashOfConfig":"5985"},{"size":1351,"mtime":1678221097154,"results":"6710","hashOfConfig":"5985"},{"size":3377,"mtime":1678221097154,"results":"6711","hashOfConfig":"5985"},{"size":5049,"mtime":1678221097155,"results":"6712","hashOfConfig":"5985"},{"size":412,"mtime":1678221097155,"results":"6713","hashOfConfig":"5985"},{"size":2171,"mtime":1675694258738,"results":"6714","hashOfConfig":"5985"},{"size":2234,"mtime":1678221097155,"results":"6715","hashOfConfig":"5985"},{"size":981,"mtime":1675188401573,"results":"6716","hashOfConfig":"5985"},{"size":2489,"mtime":1678221097155,"results":"6717","hashOfConfig":"5985"},{"size":2895,"mtime":1678221097155,"results":"6718","hashOfConfig":"5985"},{"size":1767,"mtime":1675188401573,"results":"6719","hashOfConfig":"5985"},{"size":879,"mtime":1675188401573,"results":"6720","hashOfConfig":"5985"},{"size":3007,"mtime":1675188401573,"results":"6721","hashOfConfig":"5985"},{"size":2170,"mtime":1675188401573,"results":"6722","hashOfConfig":"5985"},{"size":607,"mtime":1678221097155,"results":"6723","hashOfConfig":"5985"},{"size":1601,"mtime":1678221097155,"results":"6724","hashOfConfig":"5985"},{"size":177,"mtime":1675188401573,"results":"6725","hashOfConfig":"5985"},{"size":1366,"mtime":1678221097156,"results":"6726","hashOfConfig":"5985"},{"size":1893,"mtime":1678221097156,"results":"6727","hashOfConfig":"5985"},{"size":2267,"mtime":1678221097156,"results":"6728","hashOfConfig":"5985"},{"size":2598,"mtime":1678221097156,"results":"6729","hashOfConfig":"5985"},{"size":1953,"mtime":1678221097156,"results":"6730","hashOfConfig":"5985"},{"size":3522,"mtime":1678221097156,"results":"6731","hashOfConfig":"5985"},{"size":3337,"mtime":1678221097156,"results":"6732","hashOfConfig":"5985"},{"size":57,"mtime":1678221097156,"results":"6733","hashOfConfig":"5985"},{"size":3136,"mtime":1678221097156,"results":"6734","hashOfConfig":"5985"},{"size":2552,"mtime":1678221097157,"results":"6735","hashOfConfig":"5985"},{"size":4063,"mtime":1678221097157,"results":"6736","hashOfConfig":"5985"},{"size":4174,"mtime":1678221097157,"results":"6737","hashOfConfig":"5985"},{"size":2192,"mtime":1678221097157,"results":"6738","hashOfConfig":"5985"},{"size":5868,"mtime":1678221097157,"results":"6739","hashOfConfig":"5985"},{"size":1804,"mtime":1678221097157,"results":"6740","hashOfConfig":"5985"},{"size":3955,"mtime":1678221097157,"results":"6741","hashOfConfig":"5985"},{"size":1564,"mtime":1678221097158,"results":"6742","hashOfConfig":"5985"},{"size":6119,"mtime":1678221097158,"results":"6743","hashOfConfig":"5985"},{"size":1841,"mtime":1678221097158,"results":"6744","hashOfConfig":"5985"},{"size":5141,"mtime":1678221097158,"results":"6745","hashOfConfig":"5985"},{"size":1578,"mtime":1675188401574,"results":"6746","hashOfConfig":"5985"},{"size":1121,"mtime":1678221097158,"results":"6747","hashOfConfig":"5985"},{"size":1012,"mtime":1678221097158,"results":"6748","hashOfConfig":"5985"},{"size":4313,"mtime":1678282296173,"results":"6749","hashOfConfig":"5985"},{"size":2085,"mtime":1678221097158,"results":"6750","hashOfConfig":"5985"},{"size":3066,"mtime":1678221097158,"results":"6751","hashOfConfig":"5985"},{"size":3838,"mtime":1678221097159,"results":"6752","hashOfConfig":"5985"},{"size":1083,"mtime":1678221097159,"results":"6753","hashOfConfig":"5985"},{"size":3646,"mtime":1678221097159,"results":"6754","hashOfConfig":"5985"},{"size":51,"mtime":1675188401575,"results":"6755","hashOfConfig":"5985"},{"size":584,"mtime":1678221097159,"results":"6756","hashOfConfig":"5985"},{"size":785,"mtime":1678221097159,"results":"6757","hashOfConfig":"5985"},{"size":12220,"mtime":1678221097159,"results":"6758","hashOfConfig":"5985"},{"size":1067,"mtime":1678221097159,"results":"6759","hashOfConfig":"5985"},{"size":1337,"mtime":1678221097160,"results":"6760","hashOfConfig":"5985"},{"size":486,"mtime":1678221097160,"results":"6761","hashOfConfig":"5985"},{"size":4083,"mtime":1678221097160,"results":"6762","hashOfConfig":"5985"},{"size":1203,"mtime":1678221097160,"results":"6763","hashOfConfig":"5985"},{"size":1541,"mtime":1678221097160,"results":"6764","hashOfConfig":"5985"},{"size":687,"mtime":1678221097160,"results":"6765","hashOfConfig":"5985"},{"size":472,"mtime":1678221097160,"results":"6766","hashOfConfig":"5985"},{"size":1181,"mtime":1678221097160,"results":"6767","hashOfConfig":"5985"},{"size":1542,"mtime":1678221097161,"results":"6768","hashOfConfig":"5985"},{"size":1476,"mtime":1678221097161,"results":"6769","hashOfConfig":"5985"},{"size":842,"mtime":1678221097161,"results":"6770","hashOfConfig":"5985"},{"size":513,"mtime":1678221097161,"results":"6771","hashOfConfig":"5985"},{"size":6293,"mtime":1678221097161,"results":"6772","hashOfConfig":"5985"},{"size":2533,"mtime":1678221097161,"results":"6773","hashOfConfig":"5985"},{"size":846,"mtime":1678221097161,"results":"6774","hashOfConfig":"5985"},{"size":704,"mtime":1675188401576,"results":"6775","hashOfConfig":"5985"},{"size":5345,"mtime":1678221097161,"results":"6776","hashOfConfig":"5985"},{"size":812,"mtime":1675188401576,"results":"6777","hashOfConfig":"5985"},{"size":544,"mtime":1678221097161,"results":"6778","hashOfConfig":"5985"},{"size":8402,"mtime":1678221097162,"results":"6779","hashOfConfig":"5985"},{"size":481,"mtime":1678221097162,"results":"6780","hashOfConfig":"5985"},{"size":3169,"mtime":1678221097162,"results":"6781","hashOfConfig":"5985"},{"size":7156,"mtime":1678221097162,"results":"6782","hashOfConfig":"5985"},{"size":3045,"mtime":1678221097162,"results":"6783","hashOfConfig":"5985"},{"size":936,"mtime":1675188401577,"results":"6784","hashOfConfig":"5985"},{"size":159,"mtime":1675188401577,"results":"6785","hashOfConfig":"5985"},{"size":6392,"mtime":1678221097162,"results":"6786","hashOfConfig":"5985"},{"size":3027,"mtime":1678221097163,"results":"6787","hashOfConfig":"5985"},{"size":547,"mtime":1675188401577,"results":"6788","hashOfConfig":"5985"},{"size":747,"mtime":1678221097163,"results":"6789","hashOfConfig":"5985"},{"size":512,"mtime":1675188401577,"results":"6790","hashOfConfig":"5985"},{"size":323,"mtime":1675188401577,"results":"6791","hashOfConfig":"5985"},{"size":580,"mtime":1678221097163,"results":"6792","hashOfConfig":"5985"},{"size":3174,"mtime":1678221097163,"results":"6793","hashOfConfig":"5985"},{"size":290,"mtime":1678221097163,"results":"6794","hashOfConfig":"5985"},{"size":631,"mtime":1678221097163,"results":"6795","hashOfConfig":"5985"},{"size":5454,"mtime":1678221097163,"results":"6796","hashOfConfig":"5985"},{"size":235,"mtime":1678221097164,"results":"6797","hashOfConfig":"5985"},{"size":6930,"mtime":1678221097164,"results":"6798","hashOfConfig":"5985"},{"size":1437,"mtime":1678221097164,"results":"6799","hashOfConfig":"5985"},{"size":700,"mtime":1678221097164,"results":"6800","hashOfConfig":"5985"},{"size":35,"mtime":1675188401578,"results":"6801","hashOfConfig":"5985"},{"size":718,"mtime":1678221097164,"results":"6802","hashOfConfig":"5985"},{"size":2501,"mtime":1678221097164,"results":"6803","hashOfConfig":"5985"},{"size":102,"mtime":1675188401578,"results":"6804","hashOfConfig":"5985"},{"size":44,"mtime":1675188401578,"results":"6805","hashOfConfig":"5985"},{"size":7237,"mtime":1678221097164,"results":"6806","hashOfConfig":"5985"},{"size":3438,"mtime":1678221097165,"results":"6807","hashOfConfig":"5985"},{"size":3220,"mtime":1678221097165,"results":"6808","hashOfConfig":"5985"},{"size":2891,"mtime":1678221097165,"results":"6809","hashOfConfig":"5985"},{"size":1014,"mtime":1678221097165,"results":"6810","hashOfConfig":"5985"},{"size":2027,"mtime":1678221097165,"results":"6811","hashOfConfig":"5985"},{"size":2856,"mtime":1678221097165,"results":"6812","hashOfConfig":"5985"},{"size":1682,"mtime":1678221097166,"results":"6813","hashOfConfig":"5985"},{"size":3714,"mtime":1678221097166,"results":"6814","hashOfConfig":"5985"},{"size":5867,"mtime":1678221097166,"results":"6815","hashOfConfig":"5985"},{"size":5586,"mtime":1678221097166,"results":"6816","hashOfConfig":"5985"},{"size":1474,"mtime":1678221097166,"results":"6817","hashOfConfig":"5985"},{"size":2269,"mtime":1678221097166,"results":"6818","hashOfConfig":"5985"},{"size":813,"mtime":1675188401579,"results":"6819","hashOfConfig":"5985"},{"size":8051,"mtime":1675694258745,"results":"6820","hashOfConfig":"5985"},{"size":1016,"mtime":1675188401580,"results":"6821","hashOfConfig":"5985"},{"size":2239,"mtime":1678221097167,"results":"6822","hashOfConfig":"5985"},{"size":1127,"mtime":1675188401580,"results":"6823","hashOfConfig":"5985"},{"size":4146,"mtime":1678221097167,"results":"6824","hashOfConfig":"5985"},{"size":12573,"mtime":1675694258745,"results":"6825","hashOfConfig":"5985"},{"size":3298,"mtime":1678221097167,"results":"6826","hashOfConfig":"5985"},{"size":1412,"mtime":1678221097167,"results":"6827","hashOfConfig":"5985"},{"size":1540,"mtime":1675188401580,"results":"6828","hashOfConfig":"5985"},{"size":3951,"mtime":1678221097167,"results":"6829","hashOfConfig":"5985"},{"size":1412,"mtime":1678221097167,"results":"6830","hashOfConfig":"5985"},{"size":1116,"mtime":1678221097167,"results":"6831","hashOfConfig":"5985"},{"size":6332,"mtime":1675188401581,"results":"6832","hashOfConfig":"5985"},{"size":4582,"mtime":1678221097168,"results":"6833","hashOfConfig":"5985"},{"size":309,"mtime":1675188401581,"results":"6834","hashOfConfig":"5985"},{"size":322,"mtime":1675188401581,"results":"6835","hashOfConfig":"5985"},{"size":1743,"mtime":1678221097168,"results":"6836","hashOfConfig":"5985"},{"size":1417,"mtime":1675188401581,"results":"6837","hashOfConfig":"5985"},{"size":2043,"mtime":1678221097168,"results":"6838","hashOfConfig":"5985"},{"size":1649,"mtime":1678282296173,"results":"6839","hashOfConfig":"5985"},{"size":978,"mtime":1675694258746,"results":"6840","hashOfConfig":"5985"},{"size":2538,"mtime":1678221097168,"results":"6841","hashOfConfig":"5985"},{"size":3838,"mtime":1678221097168,"results":"6842","hashOfConfig":"5985"},{"size":478,"mtime":1678221097168,"results":"6843","hashOfConfig":"5985"},{"size":398,"mtime":1678221097169,"results":"6844","hashOfConfig":"5985"},{"size":3721,"mtime":1678221097169,"results":"6845","hashOfConfig":"5985"},{"size":1764,"mtime":1678221097169,"results":"6846","hashOfConfig":"5985"},{"size":5467,"mtime":1678221097169,"results":"6847","hashOfConfig":"5985"},{"size":1780,"mtime":1678282296173,"results":"6848","hashOfConfig":"5985"},{"size":2883,"mtime":1678221097169,"results":"6849","hashOfConfig":"5985"},{"size":1343,"mtime":1678221097169,"results":"6850","hashOfConfig":"5985"},{"size":482,"mtime":1678221097169,"results":"6851","hashOfConfig":"5985"},{"size":1935,"mtime":1678221097170,"results":"6852","hashOfConfig":"5985"},{"size":1060,"mtime":1678221097170,"results":"6853","hashOfConfig":"5985"},{"size":3574,"mtime":1678221097170,"results":"6854","hashOfConfig":"5985"},{"size":1004,"mtime":1678221097170,"results":"6855","hashOfConfig":"5985"},{"size":1530,"mtime":1678221097170,"results":"6856","hashOfConfig":"5985"},{"size":1030,"mtime":1678221097170,"results":"6857","hashOfConfig":"5985"},{"size":2299,"mtime":1678221097170,"results":"6858","hashOfConfig":"5985"},{"size":4461,"mtime":1678221097171,"results":"6859","hashOfConfig":"5985"},{"size":938,"mtime":1678221097171,"results":"6860","hashOfConfig":"5985"},{"size":1630,"mtime":1678221097171,"results":"6861","hashOfConfig":"5985"},{"size":1041,"mtime":1678221097171,"results":"6862","hashOfConfig":"5985"},{"size":46,"mtime":1675188401583,"results":"6863","hashOfConfig":"5985"},{"size":2323,"mtime":1678221097171,"results":"6864","hashOfConfig":"5985"},{"size":3943,"mtime":1678221097171,"results":"6865","hashOfConfig":"5985"},{"size":474,"mtime":1678221097172,"results":"6866","hashOfConfig":"5985"},{"size":3143,"mtime":1678221097172,"results":"6867","hashOfConfig":"5985"},{"size":1758,"mtime":1678221097172,"results":"6868","hashOfConfig":"5985"},{"size":2238,"mtime":1678221097172,"results":"6869","hashOfConfig":"5985"},{"size":54,"mtime":1675188401583,"results":"6870","hashOfConfig":"5985"},{"size":53,"mtime":1675188401583,"results":"6871","hashOfConfig":"5985"},{"size":934,"mtime":1675188401584,"results":"6872","hashOfConfig":"5985"},{"size":1669,"mtime":1678221097172,"results":"6873","hashOfConfig":"5985"},{"size":358,"mtime":1678221097172,"results":"6874","hashOfConfig":"5985"},{"size":11911,"mtime":1678221097173,"results":"6875","hashOfConfig":"5985"},{"size":598,"mtime":1678221097173,"results":"6876","hashOfConfig":"5985"},{"size":1263,"mtime":1678221097173,"results":"6877","hashOfConfig":"5985"},{"size":3390,"mtime":1678221097173,"results":"6878","hashOfConfig":"5985"},{"size":1228,"mtime":1678221097173,"results":"6879","hashOfConfig":"5985"},{"size":483,"mtime":1678221097173,"results":"6880","hashOfConfig":"5985"},{"size":7203,"mtime":1678282296173,"results":"6881","hashOfConfig":"5985"},{"size":3172,"mtime":1678221097174,"results":"6882","hashOfConfig":"5985"},{"size":5817,"mtime":1678221097174,"results":"6883","hashOfConfig":"5985"},{"size":753,"mtime":1678221097174,"results":"6884","hashOfConfig":"5985"},{"size":5222,"mtime":1678221097174,"results":"6885","hashOfConfig":"5985"},{"size":995,"mtime":1678221097175,"results":"6886","hashOfConfig":"5985"},{"size":497,"mtime":1678221097175,"results":"6887","hashOfConfig":"5985"},{"size":1102,"mtime":1678221097175,"results":"6888","hashOfConfig":"5985"},{"size":3594,"mtime":1678221097175,"results":"6889","hashOfConfig":"5985"},{"size":490,"mtime":1678221097175,"results":"6890","hashOfConfig":"5985"},{"size":541,"mtime":1678221097175,"results":"6891","hashOfConfig":"5985"},{"size":615,"mtime":1678221097175,"results":"6892","hashOfConfig":"5985"},{"size":2956,"mtime":1678221097176,"results":"6893","hashOfConfig":"5985"},{"size":545,"mtime":1678221097176,"results":"6894","hashOfConfig":"5985"},{"size":1869,"mtime":1678221097176,"results":"6895","hashOfConfig":"5985"},{"size":4926,"mtime":1678221097176,"results":"6896","hashOfConfig":"5985"},{"size":408,"mtime":1678221097176,"results":"6897","hashOfConfig":"5985"},{"size":1484,"mtime":1678221097176,"results":"6898","hashOfConfig":"5985"},{"size":2012,"mtime":1678221097176,"results":"6899","hashOfConfig":"5985"},{"size":799,"mtime":1678221097177,"results":"6900","hashOfConfig":"5985"},{"size":762,"mtime":1678221097177,"results":"6901","hashOfConfig":"5985"},{"size":1362,"mtime":1678221097177,"results":"6902","hashOfConfig":"5985"},{"size":755,"mtime":1678221097177,"results":"6903","hashOfConfig":"5985"},{"size":4260,"mtime":1678221097177,"results":"6904","hashOfConfig":"5985"},{"size":4158,"mtime":1678221097177,"results":"6905","hashOfConfig":"5985"},{"size":1739,"mtime":1678221097178,"results":"6906","hashOfConfig":"5985"},{"size":2224,"mtime":1678221097178,"results":"6907","hashOfConfig":"5985"},{"size":902,"mtime":1678221097178,"results":"6908","hashOfConfig":"5985"},{"size":2818,"mtime":1678221097178,"results":"6909","hashOfConfig":"5985"},{"size":1673,"mtime":1678221097178,"results":"6910","hashOfConfig":"5985"},{"size":3970,"mtime":1678221097178,"results":"6911","hashOfConfig":"5985"},{"size":1493,"mtime":1678221097178,"results":"6912","hashOfConfig":"5985"},{"size":1246,"mtime":1678221097179,"results":"6913","hashOfConfig":"5985"},{"size":1343,"mtime":1678221097179,"results":"6914","hashOfConfig":"5985"},{"size":1037,"mtime":1678221097179,"results":"6915","hashOfConfig":"5985"},{"size":2864,"mtime":1678221097179,"results":"6916","hashOfConfig":"5985"},{"size":1044,"mtime":1678221097179,"results":"6917","hashOfConfig":"5985"},{"size":1193,"mtime":1678221097179,"results":"6918","hashOfConfig":"5985"},{"size":3157,"mtime":1678221097179,"results":"6919","hashOfConfig":"5985"},{"size":1570,"mtime":1678221097180,"results":"6920","hashOfConfig":"5985"},{"size":2031,"mtime":1678221097180,"results":"6921","hashOfConfig":"5985"},{"size":1642,"mtime":1678221097180,"results":"6922","hashOfConfig":"5985"},{"size":2865,"mtime":1678221097180,"results":"6923","hashOfConfig":"5985"},{"size":1147,"mtime":1678221097180,"results":"6924","hashOfConfig":"5985"},{"size":1412,"mtime":1678221097180,"results":"6925","hashOfConfig":"5985"},{"size":1167,"mtime":1678221097180,"results":"6926","hashOfConfig":"5985"},{"size":1424,"mtime":1678221097180,"results":"6927","hashOfConfig":"5985"},{"size":1139,"mtime":1678221097181,"results":"6928","hashOfConfig":"5985"},{"size":1443,"mtime":1678221097181,"results":"6929","hashOfConfig":"5985"},{"size":1196,"mtime":1678221097181,"results":"6930","hashOfConfig":"5985"},{"size":1540,"mtime":1678221097181,"results":"6931","hashOfConfig":"5985"},{"size":1852,"mtime":1678221097181,"results":"6932","hashOfConfig":"5985"},{"size":1602,"mtime":1678221097181,"results":"6933","hashOfConfig":"5985"},{"size":1914,"mtime":1678221097181,"results":"6934","hashOfConfig":"5985"},{"size":1172,"mtime":1678221097181,"results":"6935","hashOfConfig":"5985"},{"size":1497,"mtime":1678221097182,"results":"6936","hashOfConfig":"5985"},{"size":1195,"mtime":1678221097182,"results":"6937","hashOfConfig":"5985"},{"size":1541,"mtime":1678221097182,"results":"6938","hashOfConfig":"5985"},{"size":3049,"mtime":1678221097182,"results":"6939","hashOfConfig":"5985"},{"size":1935,"mtime":1678221097182,"results":"6940","hashOfConfig":"5985"},{"size":1644,"mtime":1678221097182,"results":"6941","hashOfConfig":"5985"},{"size":1478,"mtime":1678221097183,"results":"6942","hashOfConfig":"5985"},{"size":1341,"mtime":1678221097183,"results":"6943","hashOfConfig":"5985"},{"size":1946,"mtime":1678221097183,"results":"6944","hashOfConfig":"5985"},{"size":1134,"mtime":1678221097183,"results":"6945","hashOfConfig":"5985"},{"size":1083,"mtime":1678221097183,"results":"6946","hashOfConfig":"5985"},{"size":1284,"mtime":1678221097183,"results":"6947","hashOfConfig":"5985"},{"size":3216,"mtime":1678221097183,"results":"6948","hashOfConfig":"5985"},{"size":3155,"mtime":1678221097184,"results":"6949","hashOfConfig":"5985"},{"size":41,"mtime":1675188401590,"results":"6950","hashOfConfig":"5985"},{"size":966,"mtime":1678221097184,"results":"6951","hashOfConfig":"5985"},{"size":46,"mtime":1675188401590,"results":"6952","hashOfConfig":"5985"},{"size":4038,"mtime":1678221097184,"results":"6953","hashOfConfig":"5985"},{"size":4212,"mtime":1678221097184,"results":"6954","hashOfConfig":"5985"},{"size":3421,"mtime":1678221097184,"results":"6955","hashOfConfig":"5985"},{"size":4856,"mtime":1678221097184,"results":"6956","hashOfConfig":"5985"},{"size":1920,"mtime":1678221097185,"results":"6957","hashOfConfig":"5985"},{"size":2243,"mtime":1678221097185,"results":"6958","hashOfConfig":"5985"},{"size":8361,"mtime":1678221097185,"results":"6959","hashOfConfig":"5985"},{"size":3183,"mtime":1678221097185,"results":"6960","hashOfConfig":"5985"},{"size":483,"mtime":1678221097185,"results":"6961","hashOfConfig":"5985"},{"size":5023,"mtime":1678221097185,"results":"6962","hashOfConfig":"5985"},{"size":2467,"mtime":1678221097186,"results":"6963","hashOfConfig":"5985"},{"size":40,"mtime":1675188401591,"results":"6964","hashOfConfig":"5985"},{"size":1194,"mtime":1678221097186,"results":"6965","hashOfConfig":"5985"},{"size":1674,"mtime":1678221097186,"results":"6966","hashOfConfig":"5985"},{"size":1274,"mtime":1678221097186,"results":"6967","hashOfConfig":"5985"},{"size":2222,"mtime":1678221097186,"results":"6968","hashOfConfig":"5985"},{"size":1610,"mtime":1678221097186,"results":"6969","hashOfConfig":"5985"},{"size":1574,"mtime":1678221097187,"results":"6970","hashOfConfig":"5985"},{"size":905,"mtime":1678221097187,"results":"6971","hashOfConfig":"5985"},{"size":5462,"mtime":1678221097187,"results":"6972","hashOfConfig":"5985"},{"size":716,"mtime":1678221097187,"results":"6973","hashOfConfig":"5985"},{"size":452,"mtime":1678221097187,"results":"6974","hashOfConfig":"5985"},{"size":455,"mtime":1678221097187,"results":"6975","hashOfConfig":"5985"},{"size":904,"mtime":1675188401592,"results":"6976","hashOfConfig":"5985"},{"size":565,"mtime":1678221097187,"results":"6977","hashOfConfig":"5985"},{"size":1415,"mtime":1678221097188,"results":"6978","hashOfConfig":"5985"},{"size":2026,"mtime":1678221097188,"results":"6979","hashOfConfig":"5985"},{"size":4552,"mtime":1675188401592,"results":"6980","hashOfConfig":"5985"},{"size":4917,"mtime":1678221097188,"results":"6981","hashOfConfig":"5985"},{"size":265,"mtime":1678221097188,"results":"6982","hashOfConfig":"5985"},{"size":368,"mtime":1678221097188,"results":"6983","hashOfConfig":"5985"},{"size":4270,"mtime":1678221097188,"results":"6984","hashOfConfig":"5985"},{"size":50,"mtime":1675188401592,"results":"6985","hashOfConfig":"5985"},{"size":3502,"mtime":1678221097188,"results":"6986","hashOfConfig":"5985"},{"size":4540,"mtime":1678221097189,"results":"6987","hashOfConfig":"5985"},{"size":50,"mtime":1678221097189,"results":"6988","hashOfConfig":"5985"},{"size":2050,"mtime":1678221097189,"results":"6989","hashOfConfig":"5985"},{"size":637,"mtime":1678221097189,"results":"6990","hashOfConfig":"5985"},{"size":663,"mtime":1678221097189,"results":"6991","hashOfConfig":"5985"},{"size":43,"mtime":1678221097189,"results":"6992","hashOfConfig":"5985"},{"size":472,"mtime":1678221097189,"results":"6993","hashOfConfig":"5985"},{"size":4841,"mtime":1678221097190,"results":"6994","hashOfConfig":"5985"},{"size":2207,"mtime":1678221097190,"results":"6995","hashOfConfig":"5985"},{"size":43,"mtime":1678221097190,"results":"6996","hashOfConfig":"5985"},{"size":468,"mtime":1678221097190,"results":"6997","hashOfConfig":"5985"},{"size":4356,"mtime":1678221097190,"results":"6998","hashOfConfig":"5985"},{"size":1889,"mtime":1678221097190,"results":"6999","hashOfConfig":"5985"},{"size":40,"mtime":1678221097190,"results":"7000","hashOfConfig":"5985"},{"size":579,"mtime":1678221097190,"results":"7001","hashOfConfig":"5985"},{"size":5032,"mtime":1678221097190,"results":"7002","hashOfConfig":"5985"},{"size":2031,"mtime":1678221097190,"results":"7003","hashOfConfig":"5985"},{"size":40,"mtime":1678221097191,"results":"7004","hashOfConfig":"5985"},{"size":1730,"mtime":1678221097191,"results":"7005","hashOfConfig":"5985"},{"size":847,"mtime":1678221097191,"results":"7006","hashOfConfig":"5985"},{"size":638,"mtime":1678221097191,"results":"7007","hashOfConfig":"5985"},{"size":456,"mtime":1678221097191,"results":"7008","hashOfConfig":"5985"},{"size":2599,"mtime":1678221097191,"results":"7009","hashOfConfig":"5985"},{"size":432,"mtime":1678221097191,"results":"7010","hashOfConfig":"5985"},{"size":888,"mtime":1678221097191,"results":"7011","hashOfConfig":"5985"},{"size":548,"mtime":1678221097192,"results":"7012","hashOfConfig":"5985"},{"size":857,"mtime":1678221097192,"results":"7013","hashOfConfig":"5985"},{"size":967,"mtime":1678221097192,"results":"7014","hashOfConfig":"5985"},{"size":4325,"mtime":1678221097192,"results":"7015","hashOfConfig":"5985"},{"size":1175,"mtime":1678221097192,"results":"7016","hashOfConfig":"5985"},{"size":823,"mtime":1678221097192,"results":"7017","hashOfConfig":"5985"},{"size":829,"mtime":1678221097192,"results":"7018","hashOfConfig":"5985"},{"size":986,"mtime":1678221097192,"results":"7019","hashOfConfig":"5985"},{"size":904,"mtime":1678221097193,"results":"7020","hashOfConfig":"5985"},{"size":1903,"mtime":1678221097193,"results":"7021","hashOfConfig":"5985"},{"size":625,"mtime":1678221097193,"results":"7022","hashOfConfig":"5985"},{"size":2075,"mtime":1675188401595,"results":"7023","hashOfConfig":"5985"},{"size":1650,"mtime":1678221097193,"results":"7024","hashOfConfig":"5985"},{"size":333,"mtime":1675694258765,"results":"7025","hashOfConfig":"5985"},{"size":1519,"mtime":1678282296174,"results":"7026","hashOfConfig":"5985"},{"size":2456,"mtime":1678221097193,"results":"7027","hashOfConfig":"5985"},{"size":555,"mtime":1678221097193,"results":"7028","hashOfConfig":"5985"},{"size":1932,"mtime":1678221097194,"results":"7029","hashOfConfig":"5985"},{"size":449,"mtime":1678221097194,"results":"7030","hashOfConfig":"5985"},{"size":4588,"mtime":1678221097194,"results":"7031","hashOfConfig":"5985"},{"size":2805,"mtime":1678221097194,"results":"7032","hashOfConfig":"5985"},{"size":570,"mtime":1678221097194,"results":"7033","hashOfConfig":"5985"},{"size":2180,"mtime":1678221097194,"results":"7034","hashOfConfig":"5985"},{"size":44,"mtime":1678221097194,"results":"7035","hashOfConfig":"5985"},{"size":3264,"mtime":1678221097195,"results":"7036","hashOfConfig":"5985"},{"size":1324,"mtime":1678221097195,"results":"7037","hashOfConfig":"5985"},{"size":40,"mtime":1678221097195,"results":"7038","hashOfConfig":"5985"},{"size":1162,"mtime":1678221097195,"results":"7039","hashOfConfig":"5985"},{"size":880,"mtime":1678221097195,"results":"7040","hashOfConfig":"5985"},{"size":837,"mtime":1678221097195,"results":"7041","hashOfConfig":"5985"},{"size":37,"mtime":1678221097195,"results":"7042","hashOfConfig":"5985"},{"size":1342,"mtime":1678221097195,"results":"7043","hashOfConfig":"5985"},{"size":1240,"mtime":1678221097195,"results":"7044","hashOfConfig":"5985"},{"size":41,"mtime":1678221097195,"results":"7045","hashOfConfig":"5985"},{"size":1536,"mtime":1678221097196,"results":"7046","hashOfConfig":"5985"},{"size":3261,"mtime":1678221097196,"results":"7047","hashOfConfig":"5985"},{"size":860,"mtime":1678221097196,"results":"7048","hashOfConfig":"5985"},{"size":1772,"mtime":1678221097196,"results":"7049","hashOfConfig":"5985"},{"size":308,"mtime":1678221097196,"results":"7050","hashOfConfig":"5985"},{"size":2506,"mtime":1678221097196,"results":"7051","hashOfConfig":"5985"},{"size":1997,"mtime":1678221097196,"results":"7052","hashOfConfig":"5985"},{"size":894,"mtime":1678221097196,"results":"7053","hashOfConfig":"5985"},{"size":41,"mtime":1678221097196,"results":"7054","hashOfConfig":"5985"},{"size":5180,"mtime":1678282296174,"results":"7055","hashOfConfig":"5985"},{"size":1089,"mtime":1678221097197,"results":"7056","hashOfConfig":"5985"},{"size":39,"mtime":1678221097197,"results":"7057","hashOfConfig":"5985"},{"size":6327,"mtime":1678221097197,"results":"7058","hashOfConfig":"5985"},{"size":10589,"mtime":1678282296174,"results":"7059","hashOfConfig":"5985"},{"size":1226,"mtime":1678221097197,"results":"7060","hashOfConfig":"5985"},{"size":1229,"mtime":1678221097197,"results":"7061","hashOfConfig":"5985"},{"size":978,"mtime":1678221097197,"results":"7062","hashOfConfig":"5985"},{"size":3398,"mtime":1678221097197,"results":"7063","hashOfConfig":"5985"},{"size":538,"mtime":1678221097197,"results":"7064","hashOfConfig":"5985"},{"size":38,"mtime":1678221097197,"results":"7065","hashOfConfig":"5985"},{"size":3031,"mtime":1678221097198,"results":"7066","hashOfConfig":"5985"},{"size":871,"mtime":1678221097198,"results":"7067","hashOfConfig":"5985"},{"size":856,"mtime":1678221097198,"results":"7068","hashOfConfig":"5985"},{"size":7951,"mtime":1678282296174,"results":"7069","hashOfConfig":"5985"},{"size":2032,"mtime":1678221097198,"results":"7070","hashOfConfig":"5985"},{"size":708,"mtime":1678221097198,"results":"7071","hashOfConfig":"5985"},{"size":941,"mtime":1678221097198,"results":"7072","hashOfConfig":"5985"},{"size":445,"mtime":1678221097198,"results":"7073","hashOfConfig":"5985"},{"size":1266,"mtime":1678221097198,"results":"7074","hashOfConfig":"5985"},{"size":806,"mtime":1678221097198,"results":"7075","hashOfConfig":"5985"},{"size":1544,"mtime":1678221097198,"results":"7076","hashOfConfig":"5985"},{"size":529,"mtime":1678221097199,"results":"7077","hashOfConfig":"5985"},{"size":518,"mtime":1678221097199,"results":"7078","hashOfConfig":"5985"},{"size":38,"mtime":1678221097199,"results":"7079","hashOfConfig":"5985"},{"size":13261,"mtime":1678282296174,"results":"7080","hashOfConfig":"5985"},{"size":1638,"mtime":1678221097199,"results":"7081","hashOfConfig":"5985"},{"size":724,"mtime":1678221097199,"results":"7082","hashOfConfig":"5985"},{"size":833,"mtime":1678221097199,"results":"7083","hashOfConfig":"5985"},{"size":858,"mtime":1678221097199,"results":"7084","hashOfConfig":"5985"},{"size":1163,"mtime":1678221097199,"results":"7085","hashOfConfig":"5985"},{"size":1331,"mtime":1678221097199,"results":"7086","hashOfConfig":"5985"},{"size":1381,"mtime":1678221097199,"results":"7087","hashOfConfig":"5985"},{"size":585,"mtime":1678221097199,"results":"7088","hashOfConfig":"5985"},{"size":2439,"mtime":1678221097200,"results":"7089","hashOfConfig":"5985"},{"size":1746,"mtime":1678221097200,"results":"7090","hashOfConfig":"5985"},{"size":1263,"mtime":1678221097200,"results":"7091","hashOfConfig":"5985"},{"size":3020,"mtime":1678221097200,"results":"7092","hashOfConfig":"5985"},{"size":1769,"mtime":1678221097200,"results":"7093","hashOfConfig":"5985"},{"size":1711,"mtime":1678221097200,"results":"7094","hashOfConfig":"5985"},{"size":1024,"mtime":1678221097200,"results":"7095","hashOfConfig":"5985"},{"size":671,"mtime":1678221097200,"results":"7096","hashOfConfig":"5985"},{"size":891,"mtime":1678221097200,"results":"7097","hashOfConfig":"5985"},{"size":1162,"mtime":1678221097200,"results":"7098","hashOfConfig":"5985"},{"size":2140,"mtime":1678221097201,"results":"7099","hashOfConfig":"5985"},{"size":817,"mtime":1678221097201,"results":"7100","hashOfConfig":"5985"},{"size":661,"mtime":1678221097201,"results":"7101","hashOfConfig":"5985"},{"size":1163,"mtime":1678221097201,"results":"7102","hashOfConfig":"5985"},{"size":1426,"mtime":1678221097201,"results":"7103","hashOfConfig":"5985"},{"size":2280,"mtime":1678221097201,"results":"7104","hashOfConfig":"5985"},{"size":3261,"mtime":1678221097201,"results":"7105","hashOfConfig":"5985"},{"size":681,"mtime":1678221097201,"results":"7106","hashOfConfig":"5985"},{"size":1267,"mtime":1678221097201,"results":"7107","hashOfConfig":"5985"},{"size":398,"mtime":1678221097201,"results":"7108","hashOfConfig":"5985"},{"size":546,"mtime":1678221097202,"results":"7109","hashOfConfig":"5985"},{"size":478,"mtime":1678221097202,"results":"7110","hashOfConfig":"5985"},{"size":220,"mtime":1678221097202,"results":"7111","hashOfConfig":"5985"},{"size":336,"mtime":1678221097202,"results":"7112","hashOfConfig":"5985"},{"size":320,"mtime":1678221097202,"results":"7113","hashOfConfig":"5985"},{"size":156,"mtime":1678221097202,"results":"7114","hashOfConfig":"5985"},{"size":173,"mtime":1678221097202,"results":"7115","hashOfConfig":"5985"},{"size":126,"mtime":1678221097202,"results":"7116","hashOfConfig":"5985"},{"size":592,"mtime":1678282296174,"results":"7117","hashOfConfig":"5985"},{"size":310,"mtime":1678221097202,"results":"7118","hashOfConfig":"5985"},{"size":189,"mtime":1678221097202,"results":"7119","hashOfConfig":"5985"},{"size":385,"mtime":1678221097203,"results":"7120","hashOfConfig":"5985"},{"size":150,"mtime":1678221097203,"results":"7121","hashOfConfig":"5985"},{"size":169,"mtime":1678221097203,"results":"7122","hashOfConfig":"5985"},{"size":256,"mtime":1678221097203,"results":"7123","hashOfConfig":"5985"},{"size":592,"mtime":1678282296174,"results":"7124","hashOfConfig":"5985"},{"size":9620,"mtime":1678221097202,"results":"7125","hashOfConfig":"5985"},{"size":2978,"mtime":1678221097203,"results":"7126","hashOfConfig":"5985"},{"size":3896,"mtime":1678221097203,"results":"7127","hashOfConfig":"5985"},{"size":471,"mtime":1678221097203,"results":"7128","hashOfConfig":"5985"},{"size":578,"mtime":1678221097203,"results":"7129","hashOfConfig":"5985"},{"size":1793,"mtime":1678221097203,"results":"7130","hashOfConfig":"5985"},{"size":2013,"mtime":1678221097203,"results":"7131","hashOfConfig":"5985"},{"size":373,"mtime":1678221097203,"results":"7132","hashOfConfig":"5985"},{"size":1274,"mtime":1678221097204,"results":"7133","hashOfConfig":"5985"},{"size":524,"mtime":1678221097204,"results":"7134","hashOfConfig":"5985"},{"size":4852,"mtime":1678282296174,"results":"7135","hashOfConfig":"5985"},{"size":479,"mtime":1678221097204,"results":"7136","hashOfConfig":"5985"},{"size":989,"mtime":1678221097204,"results":"7137","hashOfConfig":"5985"},{"size":858,"mtime":1678221097204,"results":"7138","hashOfConfig":"5985"},{"size":539,"mtime":1678221097204,"results":"7139","hashOfConfig":"5985"},{"size":152,"mtime":1678221097204,"results":"7140","hashOfConfig":"5985"},{"size":1448,"mtime":1678221097204,"results":"7141","hashOfConfig":"5985"},{"size":376,"mtime":1678221097204,"results":"7142","hashOfConfig":"5985"},{"size":1783,"mtime":1678221097204,"results":"7143","hashOfConfig":"5985"},{"size":76,"mtime":1678221097204,"results":"7144","hashOfConfig":"5985"},{"size":9985,"mtime":1678221097205,"results":"7145","hashOfConfig":"5985"},{"size":4697,"mtime":1678221097205,"results":"7146","hashOfConfig":"5985"},{"size":590,"mtime":1678221097205,"results":"7147","hashOfConfig":"5985"},{"size":794,"mtime":1678221097205,"results":"7148","hashOfConfig":"5985"},{"size":470,"mtime":1678221097205,"results":"7149","hashOfConfig":"5985"},{"size":525,"mtime":1678221097205,"results":"7150","hashOfConfig":"5985"},{"size":200,"mtime":1675188401597,"results":"7151","hashOfConfig":"5985"},{"size":902,"mtime":1678221097205,"results":"7152","hashOfConfig":"5985"},{"size":1096,"mtime":1678221097205,"results":"7153","hashOfConfig":"5985"},{"size":620,"mtime":1678221097205,"results":"7154","hashOfConfig":"5985"},{"size":2865,"mtime":1678282296175,"results":"7155","hashOfConfig":"5985"},{"size":1869,"mtime":1678221097206,"results":"7156","hashOfConfig":"5985"},{"size":645,"mtime":1678221097206,"results":"7157","hashOfConfig":"5985"},{"size":794,"mtime":1678221097206,"results":"7158","hashOfConfig":"5985"},{"size":934,"mtime":1678221097206,"results":"7159","hashOfConfig":"5985"},{"size":953,"mtime":1678221097206,"results":"7160","hashOfConfig":"5985"},{"size":1488,"mtime":1678221097206,"results":"7161","hashOfConfig":"5985"},{"size":1310,"mtime":1678221097206,"results":"7162","hashOfConfig":"5985"},{"size":6661,"mtime":1678221097206,"results":"7163","hashOfConfig":"5985"},{"size":1798,"mtime":1678221097206,"results":"7164","hashOfConfig":"5985"},{"size":2327,"mtime":1678221097207,"results":"7165","hashOfConfig":"5985"},{"size":594,"mtime":1678221097207,"results":"7166","hashOfConfig":"5985"},{"size":1922,"mtime":1678221097207,"results":"7167","hashOfConfig":"5985"},{"size":4526,"mtime":1678221097207,"results":"7168","hashOfConfig":"5985"},{"size":2144,"mtime":1678221097207,"results":"7169","hashOfConfig":"5985"},{"size":1146,"mtime":1678221097207,"results":"7170","hashOfConfig":"5985"},{"size":1738,"mtime":1678221097207,"results":"7171","hashOfConfig":"5985"},{"size":801,"mtime":1678221097207,"results":"7172","hashOfConfig":"5985"},{"size":1366,"mtime":1675188401598,"results":"7173","hashOfConfig":"5985"},{"size":3476,"mtime":1678282296175,"results":"7174","hashOfConfig":"5985"},{"size":480,"mtime":1678221097208,"results":"7175","hashOfConfig":"5985"},{"size":3342,"mtime":1675188401598,"results":"7176","hashOfConfig":"5985"},{"size":547,"mtime":1678221097208,"results":"7177","hashOfConfig":"5985"},{"size":2272,"mtime":1675188401598,"results":"7178","hashOfConfig":"5985"},{"size":1909,"mtime":1675188401598,"results":"7179","hashOfConfig":"5985"},{"size":414,"mtime":1678221097208,"results":"7180","hashOfConfig":"5985"},{"size":10635,"mtime":1678221097208,"results":"7181","hashOfConfig":"5985"},{"size":3041,"mtime":1678221097208,"results":"7182","hashOfConfig":"5985"},{"size":1275,"mtime":1678221097208,"results":"7183","hashOfConfig":"5985"},{"size":1076,"mtime":1675188401598,"results":"7184","hashOfConfig":"5985"},{"size":1005,"mtime":1678221097208,"results":"7185","hashOfConfig":"5985"},{"size":2616,"mtime":1675188401599,"results":"7186","hashOfConfig":"5985"},{"size":937,"mtime":1675188401599,"results":"7187","hashOfConfig":"5985"},{"size":1346,"mtime":1675188401599,"results":"7188","hashOfConfig":"5985"},{"size":3947,"mtime":1678221097209,"results":"7189","hashOfConfig":"5985"},{"size":2784,"mtime":1675188401599,"results":"7190","hashOfConfig":"5985"},{"size":1040,"mtime":1675188401599,"results":"7191","hashOfConfig":"5985"},{"size":1103,"mtime":1675188401599,"results":"7192","hashOfConfig":"5985"},{"size":479,"mtime":1675188401599,"results":"7193","hashOfConfig":"5985"},{"size":896,"mtime":1678221097209,"results":"7194","hashOfConfig":"5985"},{"size":1039,"mtime":1678221097209,"results":"7195","hashOfConfig":"5985"},{"size":197,"mtime":1678221097209,"results":"7196","hashOfConfig":"5985"},{"size":428,"mtime":1678221097209,"results":"7197","hashOfConfig":"5985"},{"size":263,"mtime":1678221097209,"results":"7198","hashOfConfig":"5985"},{"size":645,"mtime":1678221097209,"results":"7199","hashOfConfig":"5985"},{"size":2550,"mtime":1678221097209,"results":"7200","hashOfConfig":"5985"},{"size":3503,"mtime":1678221097209,"results":"7201","hashOfConfig":"5985"},{"size":3882,"mtime":1678221097210,"results":"7202","hashOfConfig":"5985"},{"size":4038,"mtime":1678221097210,"results":"7203","hashOfConfig":"5985"},{"size":1442,"mtime":1678221097210,"results":"7204","hashOfConfig":"5985"},{"size":2215,"mtime":1678221097210,"results":"7205","hashOfConfig":"5985"},{"size":10459,"mtime":1678221097210,"results":"7206","hashOfConfig":"5985"},{"size":2394,"mtime":1678221097210,"results":"7207","hashOfConfig":"5985"},{"size":6669,"mtime":1678282296175,"results":"7208","hashOfConfig":"5985"},{"size":254,"mtime":1678221097211,"results":"7209","hashOfConfig":"5985"},{"size":1717,"mtime":1678221097211,"results":"7210","hashOfConfig":"5985"},{"size":1738,"mtime":1678221097211,"results":"7211","hashOfConfig":"5985"},{"size":502,"mtime":1678221097211,"results":"7212","hashOfConfig":"5985"},{"size":763,"mtime":1678221097211,"results":"7213","hashOfConfig":"5985"},{"size":725,"mtime":1678221097211,"results":"7214","hashOfConfig":"5985"},{"size":2069,"mtime":1675188401601,"results":"7215","hashOfConfig":"5985"},{"size":978,"mtime":1678221097211,"results":"7216","hashOfConfig":"5985"},{"size":1339,"mtime":1675188401601,"results":"7217","hashOfConfig":"5985"},{"size":4171,"mtime":1675188401601,"results":"7218","hashOfConfig":"5985"},{"size":2860,"mtime":1675188401601,"results":"7219","hashOfConfig":"5985"},{"size":1191,"mtime":1678221097211,"results":"7220","hashOfConfig":"5985"},{"size":2726,"mtime":1675188401601,"results":"7221","hashOfConfig":"5985"},{"size":1417,"mtime":1675188401601,"results":"7222","hashOfConfig":"5985"},{"size":1480,"mtime":1678221097212,"results":"7223","hashOfConfig":"5985"},{"size":1648,"mtime":1675188401601,"results":"7224","hashOfConfig":"5985"},{"size":1813,"mtime":1678221097212,"results":"7225","hashOfConfig":"5985"},{"size":2258,"mtime":1678221097212,"results":"7226","hashOfConfig":"5985"},{"size":905,"mtime":1675188401601,"results":"7227","hashOfConfig":"5985"},{"size":2557,"mtime":1678221097212,"results":"7228","hashOfConfig":"5985"},{"size":1673,"mtime":1675188401602,"results":"7229","hashOfConfig":"5985"},{"size":1929,"mtime":1678221097212,"results":"7230","hashOfConfig":"5985"},{"size":2045,"mtime":1678221097212,"results":"7231","hashOfConfig":"5985"},{"size":3470,"mtime":1678221097212,"results":"7232","hashOfConfig":"5985"},{"size":16305,"mtime":1678282296175,"results":"7233","hashOfConfig":"5985"},{"size":1101,"mtime":1678282296175,"results":"7234","hashOfConfig":"5985"},{"size":1355,"mtime":1678221097212,"results":"7235","hashOfConfig":"5985"},{"size":1430,"mtime":1678221097212,"results":"7236","hashOfConfig":"5985"},{"size":905,"mtime":1675188401602,"results":"7237","hashOfConfig":"5985"},{"size":1645,"mtime":1678221097212,"results":"7238","hashOfConfig":"5985"},{"size":1138,"mtime":1675188401602,"results":"7239","hashOfConfig":"5985"},{"size":1804,"mtime":1678221097213,"results":"7240","hashOfConfig":"5985"},{"size":2329,"mtime":1678221097213,"results":"7241","hashOfConfig":"5985"},{"size":1829,"mtime":1678221097213,"results":"7242","hashOfConfig":"5985"},{"size":819,"mtime":1678221097213,"results":"7243","hashOfConfig":"5985"},{"size":2195,"mtime":1678221097213,"results":"7244","hashOfConfig":"5985"},{"size":743,"mtime":1678221097213,"results":"7245","hashOfConfig":"5985"},{"size":585,"mtime":1678221097213,"results":"7246","hashOfConfig":"5985"},{"size":4068,"mtime":1678221097213,"results":"7247","hashOfConfig":"5985"},{"size":2045,"mtime":1678221097213,"results":"7248","hashOfConfig":"5985"},{"size":407,"mtime":1678221097214,"results":"7249","hashOfConfig":"5985"},{"size":407,"mtime":1678221097214,"results":"7250","hashOfConfig":"5985"},{"size":4406,"mtime":1678221097214,"results":"7251","hashOfConfig":"5985"},{"size":1232,"mtime":1678221097214,"results":"7252","hashOfConfig":"5985"},{"size":743,"mtime":1678221097214,"results":"7253","hashOfConfig":"5985"},{"size":434,"mtime":1678221097214,"results":"7254","hashOfConfig":"5985"},{"size":5231,"mtime":1678221097214,"results":"7255","hashOfConfig":"5985"},{"size":5937,"mtime":1678221097214,"results":"7256","hashOfConfig":"5985"},{"size":5782,"mtime":1678221097215,"results":"7257","hashOfConfig":"5985"},{"size":1432,"mtime":1678221097215,"results":"7258","hashOfConfig":"5985"},{"size":883,"mtime":1678221097215,"results":"7259","hashOfConfig":"5985"},{"size":5408,"mtime":1678221097215,"results":"7260","hashOfConfig":"5985"},{"size":1306,"mtime":1678221097215,"results":"7261","hashOfConfig":"5985"},{"size":116,"mtime":1678221097215,"results":"7262","hashOfConfig":"5985"},{"size":1723,"mtime":1678221097215,"results":"7263","hashOfConfig":"5985"},{"size":1505,"mtime":1678221097215,"results":"7264","hashOfConfig":"5985"},{"size":1186,"mtime":1678221097215,"results":"7265","hashOfConfig":"5985"},{"size":1775,"mtime":1678221097215,"results":"7266","hashOfConfig":"5985"},{"size":352,"mtime":1678221097215,"results":"7267","hashOfConfig":"5985"},{"size":894,"mtime":1678221097215,"results":"7268","hashOfConfig":"5985"},{"size":830,"mtime":1678221097216,"results":"7269","hashOfConfig":"5985"},{"size":1900,"mtime":1678221097216,"results":"7270","hashOfConfig":"5985"},{"size":322,"mtime":1678221097216,"results":"7271","hashOfConfig":"5985"},{"size":404,"mtime":1675188401605,"results":"7272","hashOfConfig":"5985"},{"size":5851,"mtime":1678221097216,"results":"7273","hashOfConfig":"5985"},{"size":907,"mtime":1678221097216,"results":"7274","hashOfConfig":"5985"},{"size":5792,"mtime":1678221097216,"results":"7275","hashOfConfig":"5985"},{"size":6779,"mtime":1678221097216,"results":"7276","hashOfConfig":"5985"},{"size":1688,"mtime":1678221097216,"results":"7277","hashOfConfig":"5985"},{"size":683,"mtime":1678221097217,"results":"7278","hashOfConfig":"5985"},{"size":541,"mtime":1678221097217,"results":"7279","hashOfConfig":"5985"},{"size":1095,"mtime":1678221097217,"results":"7280","hashOfConfig":"5985"},{"size":817,"mtime":1678221097217,"results":"7281","hashOfConfig":"5985"},{"size":509,"mtime":1678221097217,"results":"7282","hashOfConfig":"5985"},{"size":639,"mtime":1678221097217,"results":"7283","hashOfConfig":"5985"},{"size":482,"mtime":1678221097217,"results":"7284","hashOfConfig":"5985"},{"size":702,"mtime":1678221097217,"results":"7285","hashOfConfig":"5985"},{"size":384,"mtime":1678221097217,"results":"7286","hashOfConfig":"5985"},{"size":1510,"mtime":1678221097218,"results":"7287","hashOfConfig":"5985"},{"size":374,"mtime":1678221097218,"results":"7288","hashOfConfig":"5985"},{"size":1352,"mtime":1678221097218,"results":"7289","hashOfConfig":"5985"},{"size":4698,"mtime":1678221097218,"results":"7290","hashOfConfig":"5985"},{"size":1689,"mtime":1678221097218,"results":"7291","hashOfConfig":"5985"},{"size":2498,"mtime":1678282296175,"results":"7292","hashOfConfig":"5985"},{"size":1443,"mtime":1678221097218,"results":"7293","hashOfConfig":"5985"},{"size":1295,"mtime":1675188401606,"results":"7294","hashOfConfig":"5985"},{"size":3475,"mtime":1678221097218,"results":"7295","hashOfConfig":"5985"},{"size":4899,"mtime":1678282296176,"results":"7296","hashOfConfig":"5985"},{"size":1767,"mtime":1678221097219,"results":"7297","hashOfConfig":"5985"},{"size":325,"mtime":1675188401607,"results":"7298","hashOfConfig":"5985"},{"size":2185,"mtime":1678221097219,"results":"7299","hashOfConfig":"5985"},{"size":1707,"mtime":1678221097219,"results":"7300","hashOfConfig":"5985"},{"size":1687,"mtime":1678221097219,"results":"7301","hashOfConfig":"5985"},{"size":1670,"mtime":1678221097219,"results":"7302","hashOfConfig":"5985"},{"size":2505,"mtime":1678221097219,"results":"7303","hashOfConfig":"5985"},{"size":450,"mtime":1675188401607,"results":"7304","hashOfConfig":"5985"},{"size":229,"mtime":1675188401607,"results":"7305","hashOfConfig":"5985"},{"size":419,"mtime":1675188401607,"results":"7306","hashOfConfig":"5985"},{"size":905,"mtime":1675188401608,"results":"7307","hashOfConfig":"5985"},{"size":667,"mtime":1678221097219,"results":"7308","hashOfConfig":"5985"},{"size":443,"mtime":1675188401608,"results":"7309","hashOfConfig":"5985"},{"size":718,"mtime":1675188401608,"results":"7310","hashOfConfig":"5985"},{"size":691,"mtime":1678221097219,"results":"7311","hashOfConfig":"5985"},{"size":637,"mtime":1678221097219,"results":"7312","hashOfConfig":"5985"},{"size":713,"mtime":1678221097220,"results":"7313","hashOfConfig":"5985"},{"size":684,"mtime":1678221097220,"results":"7314","hashOfConfig":"5985"},{"size":2612,"mtime":1678221097220,"results":"7315","hashOfConfig":"5985"},{"size":1331,"mtime":1678221097220,"results":"7316","hashOfConfig":"5985"},{"size":2175,"mtime":1678221097220,"results":"7317","hashOfConfig":"5985"},{"size":2330,"mtime":1675188401609,"results":"7318","hashOfConfig":"5985"},{"size":868,"mtime":1678221097220,"results":"7319","hashOfConfig":"5985"},{"size":1994,"mtime":1675188401609,"results":"7320","hashOfConfig":"5985"},{"size":1145,"mtime":1678221097220,"results":"7321","hashOfConfig":"5985"},{"size":5827,"mtime":1678221097220,"results":"7322","hashOfConfig":"5985"},{"size":1939,"mtime":1678221097220,"results":"7323","hashOfConfig":"5985"},{"size":1928,"mtime":1675188401609,"results":"7324","hashOfConfig":"5985"},{"size":1098,"mtime":1675188401609,"results":"7325","hashOfConfig":"5985"},{"size":1058,"mtime":1678221097221,"results":"7326","hashOfConfig":"5985"},{"size":5041,"mtime":1675694258779,"results":"7327","hashOfConfig":"5985"},{"size":1408,"mtime":1675188401610,"results":"7328","hashOfConfig":"5985"},{"size":540,"mtime":1678221097221,"results":"7329","hashOfConfig":"5985"},{"size":1546,"mtime":1678221097221,"results":"7330","hashOfConfig":"5985"},{"size":1181,"mtime":1678221097221,"results":"7331","hashOfConfig":"5985"},{"size":42,"mtime":1675188401610,"results":"7332","hashOfConfig":"5985"},{"size":892,"mtime":1678221097221,"results":"7333","hashOfConfig":"5985"},{"size":752,"mtime":1678221097221,"results":"7334","hashOfConfig":"5985"},{"size":1408,"mtime":1678221097221,"results":"7335","hashOfConfig":"5985"},{"size":740,"mtime":1678221097221,"results":"7336","hashOfConfig":"5985"},{"size":785,"mtime":1678221097221,"results":"7337","hashOfConfig":"5985"},{"size":1817,"mtime":1678221097222,"results":"7338","hashOfConfig":"5985"},{"size":1320,"mtime":1678221097222,"results":"7339","hashOfConfig":"5985"},{"size":1624,"mtime":1678221097222,"results":"7340","hashOfConfig":"5985"},{"size":960,"mtime":1678221097222,"results":"7341","hashOfConfig":"5985"},{"size":11694,"mtime":1678221097222,"results":"7342","hashOfConfig":"5985"},{"size":928,"mtime":1678221097222,"results":"7343","hashOfConfig":"5985"},{"size":42,"mtime":1678221097222,"results":"7344","hashOfConfig":"5985"},{"size":1702,"mtime":1678221097223,"results":"7345","hashOfConfig":"5985"},{"size":779,"mtime":1678221097223,"results":"7346","hashOfConfig":"5985"},{"size":736,"mtime":1678221097223,"results":"7347","hashOfConfig":"5985"},{"size":718,"mtime":1678221097223,"results":"7348","hashOfConfig":"5985"},{"size":1948,"mtime":1678221097223,"results":"7349","hashOfConfig":"5985"},{"size":2236,"mtime":1678221097223,"results":"7350","hashOfConfig":"5985"},{"size":465,"mtime":1678221097223,"results":"7351","hashOfConfig":"5985"},{"size":4353,"mtime":1678221097223,"results":"7352","hashOfConfig":"5985"},{"size":37,"mtime":1678221097223,"results":"7353","hashOfConfig":"5985"},{"size":965,"mtime":1675188401612,"results":"7354","hashOfConfig":"5985"},{"size":1137,"mtime":1678221097224,"results":"7355","hashOfConfig":"5985"},{"size":715,"mtime":1678221097224,"results":"7356","hashOfConfig":"5985"},{"size":36,"mtime":1675188401612,"results":"7357","hashOfConfig":"5985"},{"size":1167,"mtime":1675188401612,"results":"7358","hashOfConfig":"5985"},{"size":3558,"mtime":1678221097224,"results":"7359","hashOfConfig":"5985"},{"size":1080,"mtime":1678221097224,"results":"7360","hashOfConfig":"5985"},{"size":451,"mtime":1678221097224,"results":"7361","hashOfConfig":"5985"},{"size":1877,"mtime":1675188401612,"results":"7362","hashOfConfig":"5985"},{"size":5429,"mtime":1678221097224,"results":"7363","hashOfConfig":"5985"},{"size":2046,"mtime":1678221097224,"results":"7364","hashOfConfig":"5985"},{"size":1646,"mtime":1678221097224,"results":"7365","hashOfConfig":"5985"},{"size":547,"mtime":1678221097224,"results":"7366","hashOfConfig":"5985"},{"size":957,"mtime":1678221097225,"results":"7367","hashOfConfig":"5985"},{"size":1241,"mtime":1678221097225,"results":"7368","hashOfConfig":"5985"},{"size":1055,"mtime":1678221097225,"results":"7369","hashOfConfig":"5985"},{"size":424,"mtime":1678221097225,"results":"7370","hashOfConfig":"5985"},{"size":31,"mtime":1675188401613,"results":"7371","hashOfConfig":"5985"},{"size":590,"mtime":1678221097225,"results":"7372","hashOfConfig":"5985"},{"size":404,"mtime":1675188401613,"results":"7373","hashOfConfig":"5985"},{"size":244,"mtime":1678221097225,"results":"7374","hashOfConfig":"5985"},{"size":928,"mtime":1678221097225,"results":"7375","hashOfConfig":"5985"},{"size":208,"mtime":1675188401613,"results":"7376","hashOfConfig":"5985"},{"size":168,"mtime":1678221097225,"results":"7377","hashOfConfig":"5985"},{"size":137,"mtime":1675188401613,"results":"7378","hashOfConfig":"5985"},{"size":858,"mtime":1678221097225,"results":"7379","hashOfConfig":"5985"},{"size":5779,"mtime":1678326191472,"results":"7380","hashOfConfig":"5985"},{"size":1180,"mtime":1678221097226,"results":"7381","hashOfConfig":"5985"},{"size":284,"mtime":1678221097226,"results":"7382","hashOfConfig":"5985"},{"size":2636,"mtime":1678221097226,"results":"7383","hashOfConfig":"5985"},{"size":1338,"mtime":1678221097226,"results":"7384","hashOfConfig":"5985"},{"size":995,"mtime":1678221097226,"results":"7385","hashOfConfig":"5985"},{"size":2992,"mtime":1678221097226,"results":"7386","hashOfConfig":"5985"},{"size":266,"mtime":1675188401614,"results":"7387","hashOfConfig":"5985"},{"size":261,"mtime":1675188401614,"results":"7388","hashOfConfig":"5985"},{"size":3520,"mtime":1678221097226,"results":"7389","hashOfConfig":"5985"},{"size":46,"mtime":1675188401614,"results":"7390","hashOfConfig":"5985"},{"size":2491,"mtime":1678221097226,"results":"7391","hashOfConfig":"5985"},{"size":1403,"mtime":1678221097227,"results":"7392","hashOfConfig":"5985"},{"size":2800,"mtime":1678221097227,"results":"7393","hashOfConfig":"5985"},{"size":931,"mtime":1678221097227,"results":"7394","hashOfConfig":"5985"},{"size":732,"mtime":1678221097227,"results":"7395","hashOfConfig":"5985"},{"size":2318,"mtime":1678221097227,"results":"7396","hashOfConfig":"5985"},{"size":327,"mtime":1678221097227,"results":"7397","hashOfConfig":"5985"},{"size":739,"mtime":1678221097227,"results":"7398","hashOfConfig":"5985"},{"size":1298,"mtime":1678221097227,"results":"7399","hashOfConfig":"5985"},{"size":19801,"mtime":1678221097227,"results":"7400","hashOfConfig":"5985"},{"size":2105,"mtime":1678221097228,"results":"7401","hashOfConfig":"5985"},{"size":1229,"mtime":1678221097228,"results":"7402","hashOfConfig":"5985"},{"size":1219,"mtime":1678221097228,"results":"7403","hashOfConfig":"5985"},{"size":1442,"mtime":1678221097228,"results":"7404","hashOfConfig":"5985"},{"size":383,"mtime":1678221097228,"results":"7405","hashOfConfig":"5985"},{"size":2373,"mtime":1678221097228,"results":"7406","hashOfConfig":"5985"},{"size":1327,"mtime":1678221097228,"results":"7407","hashOfConfig":"5985"},{"size":439,"mtime":1678221097228,"results":"7408","hashOfConfig":"5985"},{"size":456,"mtime":1678221097228,"results":"7409","hashOfConfig":"5985"},{"size":48,"mtime":1678221097228,"results":"7410","hashOfConfig":"5985"},{"size":1765,"mtime":1678221097229,"results":"7411","hashOfConfig":"5985"},{"size":2759,"mtime":1678221097229,"results":"7412","hashOfConfig":"5985"},{"size":1931,"mtime":1678221097229,"results":"7413","hashOfConfig":"5985"},{"size":1565,"mtime":1678221097229,"results":"7414","hashOfConfig":"5985"},{"size":1127,"mtime":1678221097229,"results":"7415","hashOfConfig":"5985"},{"size":1042,"mtime":1678221097229,"results":"7416","hashOfConfig":"5985"},{"size":966,"mtime":1678221097229,"results":"7417","hashOfConfig":"5985"},{"size":49,"mtime":1678221097229,"results":"7418","hashOfConfig":"5985"},{"size":1256,"mtime":1678221097229,"results":"7419","hashOfConfig":"5985"},{"size":1587,"mtime":1678221097230,"results":"7420","hashOfConfig":"5985"},{"size":57,"mtime":1678221097230,"results":"7421","hashOfConfig":"5985"},{"size":79,"mtime":1675188401616,"results":"7422","hashOfConfig":"5985"},{"size":462,"mtime":1678221097230,"results":"7423","hashOfConfig":"5985"},{"size":346,"mtime":1675188401617,"results":"7424","hashOfConfig":"5985"},{"size":2122,"mtime":1678221097230,"results":"7425","hashOfConfig":"5985"},{"size":460,"mtime":1678221097230,"results":"7426","hashOfConfig":"5985"},{"size":457,"mtime":1675188401617,"results":"7427","hashOfConfig":"5985"},{"size":627,"mtime":1678221097230,"results":"7428","hashOfConfig":"5985"},{"size":805,"mtime":1678221097230,"results":"7429","hashOfConfig":"5985"},{"size":881,"mtime":1678221097230,"results":"7430","hashOfConfig":"5985"},{"size":13942,"mtime":1678221097230,"results":"7431","hashOfConfig":"5985"},{"size":2596,"mtime":1678221097231,"results":"7432","hashOfConfig":"5985"},{"size":1489,"mtime":1678221097231,"results":"7433","hashOfConfig":"5985"},{"size":2821,"mtime":1678221097231,"results":"7434","hashOfConfig":"5985"},{"size":1320,"mtime":1678221097231,"results":"7435","hashOfConfig":"5985"},{"size":2313,"mtime":1678221097231,"results":"7436","hashOfConfig":"5985"},{"size":1461,"mtime":1678221097231,"results":"7437","hashOfConfig":"5985"},{"size":3087,"mtime":1678221097231,"results":"7438","hashOfConfig":"5985"},{"size":2158,"mtime":1678221097231,"results":"7439","hashOfConfig":"5985"},{"size":54,"mtime":1678221097231,"results":"7440","hashOfConfig":"5985"},{"size":1750,"mtime":1678221097231,"results":"7441","hashOfConfig":"5985"},{"size":2140,"mtime":1678221097231,"results":"7442","hashOfConfig":"5985"},{"size":57,"mtime":1678221097232,"results":"7443","hashOfConfig":"5985"},{"size":1680,"mtime":1678221097232,"results":"7444","hashOfConfig":"5985"},{"size":937,"mtime":1678221097232,"results":"7445","hashOfConfig":"5985"},{"size":1436,"mtime":1678221097232,"results":"7446","hashOfConfig":"5985"},{"size":776,"mtime":1678221097232,"results":"7447","hashOfConfig":"5985"},{"size":1119,"mtime":1678221097232,"results":"7448","hashOfConfig":"5985"},{"size":2115,"mtime":1678221097232,"results":"7449","hashOfConfig":"5985"},{"size":2921,"mtime":1678221097232,"results":"7450","hashOfConfig":"5985"},{"size":2925,"mtime":1678221097232,"results":"7451","hashOfConfig":"5985"},{"size":2554,"mtime":1678221097232,"results":"7452","hashOfConfig":"5985"},{"size":1104,"mtime":1678221097233,"results":"7453","hashOfConfig":"5985"},{"size":4933,"mtime":1678221097233,"results":"7454","hashOfConfig":"5985"},{"size":302,"mtime":1678221097233,"results":"7455","hashOfConfig":"5985"},{"size":1431,"mtime":1678221097233,"results":"7456","hashOfConfig":"5985"},{"size":161,"mtime":1675188401618,"results":"7457","hashOfConfig":"5985"},{"size":2598,"mtime":1678221097233,"results":"7458","hashOfConfig":"5985"},{"size":1512,"mtime":1678221097233,"results":"7459","hashOfConfig":"5985"},{"size":1698,"mtime":1678221097233,"results":"7460","hashOfConfig":"5985"},{"size":6631,"mtime":1678321762662,"results":"7461","hashOfConfig":"5985"},{"size":42,"mtime":1675188401618,"results":"7462","hashOfConfig":"5985"},{"size":714,"mtime":1678221097233,"results":"7463","hashOfConfig":"5985"},{"size":1712,"mtime":1678221097233,"results":"7464","hashOfConfig":"5985"},{"size":2128,"mtime":1678221097234,"results":"7465","hashOfConfig":"5985"},{"size":51,"mtime":1675188401619,"results":"7466","hashOfConfig":"5985"},{"size":2859,"mtime":1678221097234,"results":"7467","hashOfConfig":"5985"},{"size":1164,"mtime":1678221097234,"results":"7468","hashOfConfig":"5985"},{"size":1606,"mtime":1678221097234,"results":"7469","hashOfConfig":"5985"},{"size":1220,"mtime":1678221097234,"results":"7470","hashOfConfig":"5985"},{"size":44,"mtime":1675188401619,"results":"7471","hashOfConfig":"5985"},{"size":358,"mtime":1675188401619,"results":"7472","hashOfConfig":"5985"},{"size":1696,"mtime":1678221097234,"results":"7473","hashOfConfig":"5985"},{"size":1975,"mtime":1675188401619,"results":"7474","hashOfConfig":"5985"},{"size":603,"mtime":1678221097234,"results":"7475","hashOfConfig":"5985"},{"size":1651,"mtime":1678221097234,"results":"7476","hashOfConfig":"5985"},{"size":2429,"mtime":1678221097234,"results":"7477","hashOfConfig":"5985"},{"size":5581,"mtime":1678221097235,"results":"7478","hashOfConfig":"5985"},{"size":44,"mtime":1675188401620,"results":"7479","hashOfConfig":"5985"},{"size":563,"mtime":1675188401620,"results":"7480","hashOfConfig":"5985"},{"size":1113,"mtime":1675188401620,"results":"7481","hashOfConfig":"5985"},{"size":592,"mtime":1675188401620,"results":"7482","hashOfConfig":"5985"},{"size":16514,"mtime":1678221097235,"results":"7483","hashOfConfig":"5985"},{"size":471,"mtime":1675188401620,"results":"7484","hashOfConfig":"5985"},{"size":49,"mtime":1675188401620,"results":"7485","hashOfConfig":"5985"},{"size":5414,"mtime":1678221097235,"results":"7486","hashOfConfig":"5985"},{"size":1445,"mtime":1678221097235,"results":"7487","hashOfConfig":"5985"},{"size":7025,"mtime":1678221097235,"results":"7488","hashOfConfig":"5985"},{"size":46,"mtime":1675188401621,"results":"7489","hashOfConfig":"5985"},{"size":642,"mtime":1675188401621,"results":"7490","hashOfConfig":"5985"},{"size":555,"mtime":1678221097235,"results":"7491","hashOfConfig":"5985"},{"size":671,"mtime":1678221097235,"results":"7492","hashOfConfig":"5985"},{"size":1792,"mtime":1678221097236,"results":"7493","hashOfConfig":"5985"},{"size":541,"mtime":1678221097236,"results":"7494","hashOfConfig":"5985"},{"size":55,"mtime":1675188401621,"results":"7495","hashOfConfig":"5985"},{"size":1364,"mtime":1678221097236,"results":"7496","hashOfConfig":"5985"},{"size":1932,"mtime":1678221097236,"results":"7497","hashOfConfig":"5985"},{"size":4152,"mtime":1678221097236,"results":"7498","hashOfConfig":"5985"},{"size":2547,"mtime":1678221097236,"results":"7499","hashOfConfig":"5985"},{"size":451,"mtime":1678221097236,"results":"7500","hashOfConfig":"5985"},{"size":1049,"mtime":1678221097236,"results":"7501","hashOfConfig":"5985"},{"size":46,"mtime":1678221097236,"results":"7502","hashOfConfig":"5985"},{"size":2022,"mtime":1678221097237,"results":"7503","hashOfConfig":"5985"},{"size":3875,"mtime":1678221097237,"results":"7504","hashOfConfig":"5985"},{"size":3351,"mtime":1678221097237,"results":"7505","hashOfConfig":"5985"},{"size":744,"mtime":1678221097237,"results":"7506","hashOfConfig":"5985"},{"size":945,"mtime":1678221097237,"results":"7507","hashOfConfig":"5985"},{"size":612,"mtime":1678221097237,"results":"7508","hashOfConfig":"5985"},{"size":61,"mtime":1675188401622,"results":"7509","hashOfConfig":"5985"},{"size":1332,"mtime":1678221097237,"results":"7510","hashOfConfig":"5985"},{"size":2683,"mtime":1678221097237,"results":"7511","hashOfConfig":"5985"},{"size":1730,"mtime":1678221097238,"results":"7512","hashOfConfig":"5985"},{"size":641,"mtime":1678221097238,"results":"7513","hashOfConfig":"5985"},{"size":880,"mtime":1678221097238,"results":"7514","hashOfConfig":"5985"},{"size":41,"mtime":1675188401622,"results":"7515","hashOfConfig":"5985"},{"size":1362,"mtime":1678221097238,"results":"7516","hashOfConfig":"5985"},{"size":764,"mtime":1678221097238,"results":"7517","hashOfConfig":"5985"},{"size":4192,"mtime":1678221097238,"results":"7518","hashOfConfig":"5985"},{"size":883,"mtime":1678221097238,"results":"7519","hashOfConfig":"5985"},{"size":6004,"mtime":1678221097238,"results":"7520","hashOfConfig":"5985"},{"size":51,"mtime":1675188401622,"results":"7521","hashOfConfig":"5985"},{"size":2674,"mtime":1675188401623,"results":"7522","hashOfConfig":"5985"},{"size":1545,"mtime":1678221097239,"results":"7523","hashOfConfig":"5985"},{"size":2425,"mtime":1675188401623,"results":"7524","hashOfConfig":"5985"},{"size":337,"mtime":1675188401623,"results":"7525","hashOfConfig":"5985"},{"size":1643,"mtime":1678221097239,"results":"7526","hashOfConfig":"5985"},{"size":732,"mtime":1678221097239,"results":"7527","hashOfConfig":"5985"},{"size":7290,"mtime":1675188401623,"results":"7528","hashOfConfig":"5985"},{"size":985,"mtime":1678221097239,"results":"7529","hashOfConfig":"5985"},{"size":1049,"mtime":1678221097239,"results":"7530","hashOfConfig":"5985"},{"size":2734,"mtime":1678221097239,"results":"7531","hashOfConfig":"5985"},{"size":1640,"mtime":1678221097239,"results":"7532","hashOfConfig":"5985"},{"size":47,"mtime":1675188401623,"results":"7533","hashOfConfig":"5985"},{"size":288,"mtime":1675188401624,"results":"7534","hashOfConfig":"5985"},{"size":650,"mtime":1678221097239,"results":"7535","hashOfConfig":"5985"},{"size":1944,"mtime":1678221097240,"results":"7536","hashOfConfig":"5985"},{"size":2088,"mtime":1678221097240,"results":"7537","hashOfConfig":"5985"},{"size":46,"mtime":1675188401624,"results":"7538","hashOfConfig":"5985"},{"size":2089,"mtime":1678221097240,"results":"7539","hashOfConfig":"5985"},{"size":1148,"mtime":1678221097240,"results":"7540","hashOfConfig":"5985"},{"size":790,"mtime":1678221097240,"results":"7541","hashOfConfig":"5985"},{"size":1635,"mtime":1678221097240,"results":"7542","hashOfConfig":"5985"},{"size":3189,"mtime":1678221097240,"results":"7543","hashOfConfig":"5985"},{"size":49,"mtime":1675188401624,"results":"7544","hashOfConfig":"5985"},{"size":1347,"mtime":1678221097240,"results":"7545","hashOfConfig":"5985"},{"size":4831,"mtime":1678221097240,"results":"7546","hashOfConfig":"5985"},{"size":980,"mtime":1678221097241,"results":"7547","hashOfConfig":"5985"},{"size":1989,"mtime":1678221097241,"results":"7548","hashOfConfig":"5985"},{"size":864,"mtime":1678221097241,"results":"7549","hashOfConfig":"5985"},{"size":4171,"mtime":1678221097241,"results":"7550","hashOfConfig":"5985"},{"size":49,"mtime":1675188401625,"results":"7551","hashOfConfig":"5985"},{"size":1375,"mtime":1678221097241,"results":"7552","hashOfConfig":"5985"},{"size":4708,"mtime":1678221097241,"results":"7553","hashOfConfig":"5985"},{"size":6048,"mtime":1678221097241,"results":"7554","hashOfConfig":"5985"},{"size":399,"mtime":1678221097241,"results":"7555","hashOfConfig":"5985"},{"size":4249,"mtime":1678221097241,"results":"7556","hashOfConfig":"5985"},{"size":2996,"mtime":1678221097241,"results":"7557","hashOfConfig":"5985"},{"size":3433,"mtime":1678221097242,"results":"7558","hashOfConfig":"5985"},{"size":4778,"mtime":1678321762662,"results":"7559","hashOfConfig":"5985"},{"size":405,"mtime":1678221097242,"results":"7560","hashOfConfig":"5985"},{"size":599,"mtime":1678221097242,"results":"7561","hashOfConfig":"5985"},{"size":1047,"mtime":1678282296176,"results":"7562","hashOfConfig":"5985"},{"size":1866,"mtime":1678221097242,"results":"7563","hashOfConfig":"5985"},{"size":1092,"mtime":1678282296176,"results":"7564","hashOfConfig":"5985"},{"size":1389,"mtime":1678221097242,"results":"7565","hashOfConfig":"5985"},{"size":3737,"mtime":1678221097242,"results":"7566","hashOfConfig":"5985"},{"size":1687,"mtime":1678221097242,"results":"7567","hashOfConfig":"5985"},{"size":1267,"mtime":1678221097242,"results":"7568","hashOfConfig":"5985"},{"size":37,"mtime":1678221097242,"results":"7569","hashOfConfig":"5985"},{"size":1724,"mtime":1678221097243,"results":"7570","hashOfConfig":"5985"},{"size":2981,"mtime":1678221097243,"results":"7571","hashOfConfig":"5985"},{"size":46,"mtime":1675188401626,"results":"7572","hashOfConfig":"5985"},{"size":1131,"mtime":1678221097243,"results":"7573","hashOfConfig":"5985"},{"size":2796,"mtime":1678221097243,"results":"7574","hashOfConfig":"5985"},{"size":2803,"mtime":1678221097243,"results":"7575","hashOfConfig":"5985"},{"size":3476,"mtime":1678221097243,"results":"7576","hashOfConfig":"5985"},{"size":1075,"mtime":1678221097243,"results":"7577","hashOfConfig":"5985"},{"size":359,"mtime":1675188401627,"results":"7578","hashOfConfig":"5985"},{"size":51,"mtime":1675188401627,"results":"7579","hashOfConfig":"5985"},{"size":1584,"mtime":1675188401627,"results":"7580","hashOfConfig":"5985"},{"size":3252,"mtime":1678221097243,"results":"7581","hashOfConfig":"5985"},{"size":2228,"mtime":1678221097244,"results":"7582","hashOfConfig":"5985"},{"size":2779,"mtime":1678221097244,"results":"7583","hashOfConfig":"5985"},{"size":2044,"mtime":1678221097244,"results":"7584","hashOfConfig":"5985"},{"size":1565,"mtime":1678221097244,"results":"7585","hashOfConfig":"5985"},{"size":49,"mtime":1675188401629,"results":"7586","hashOfConfig":"5985"},{"size":1836,"mtime":1678221097244,"results":"7587","hashOfConfig":"5985"},{"size":45,"mtime":1675188401629,"results":"7588","hashOfConfig":"5985"},{"size":891,"mtime":1675694258798,"results":"7589","hashOfConfig":"5985"},{"size":1215,"mtime":1678221097244,"results":"7590","hashOfConfig":"5985"},{"size":1132,"mtime":1678221097244,"results":"7591","hashOfConfig":"5985"},{"size":804,"mtime":1678221097244,"results":"7592","hashOfConfig":"5985"},{"size":688,"mtime":1678221097244,"results":"7593","hashOfConfig":"5985"},{"size":695,"mtime":1678221097245,"results":"7594","hashOfConfig":"5985"},{"size":669,"mtime":1678221097245,"results":"7595","hashOfConfig":"5985"},{"size":457,"mtime":1678221097245,"results":"7596","hashOfConfig":"5985"},{"size":1773,"mtime":1678221097245,"results":"7597","hashOfConfig":"5985"},{"size":1807,"mtime":1678221097245,"results":"7598","hashOfConfig":"5985"},{"size":2266,"mtime":1678221097245,"results":"7599","hashOfConfig":"5985"},{"size":4803,"mtime":1678221097245,"results":"7600","hashOfConfig":"5985"},{"size":4247,"mtime":1678221097245,"results":"7601","hashOfConfig":"5985"},{"size":1765,"mtime":1678221097246,"results":"7602","hashOfConfig":"5985"},{"size":1892,"mtime":1678221097246,"results":"7603","hashOfConfig":"5985"},{"size":3424,"mtime":1678221097246,"results":"7604","hashOfConfig":"5985"},{"size":3769,"mtime":1678221097246,"results":"7605","hashOfConfig":"5985"},{"size":59,"mtime":1675188401630,"results":"7606","hashOfConfig":"5985"},{"size":2458,"mtime":1678221097246,"results":"7607","hashOfConfig":"5985"},{"size":286,"mtime":1675188401630,"results":"7608","hashOfConfig":"5985"},{"size":956,"mtime":1678221097246,"results":"7609","hashOfConfig":"5985"},{"size":704,"mtime":1678221097246,"results":"7610","hashOfConfig":"5985"},{"size":1012,"mtime":1678221097246,"results":"7611","hashOfConfig":"5985"},{"size":1908,"mtime":1678221097247,"results":"7612","hashOfConfig":"5985"},{"size":224,"mtime":1675188401631,"results":"7613","hashOfConfig":"5985"},{"size":2040,"mtime":1678221097247,"results":"7614","hashOfConfig":"5985"},{"size":992,"mtime":1678221097247,"results":"7615","hashOfConfig":"5985"},{"size":1927,"mtime":1678221097247,"results":"7616","hashOfConfig":"5985"},{"size":1754,"mtime":1678221097247,"results":"7617","hashOfConfig":"5985"},{"size":1247,"mtime":1678221097247,"results":"7618","hashOfConfig":"5985"},{"size":687,"mtime":1678221097247,"results":"7619","hashOfConfig":"5985"},{"size":3400,"mtime":1678221097247,"results":"7620","hashOfConfig":"5985"},{"size":467,"mtime":1678221097247,"results":"7621","hashOfConfig":"5985"},{"size":926,"mtime":1678221097248,"results":"7622","hashOfConfig":"5985"},{"size":2208,"mtime":1678221097248,"results":"7623","hashOfConfig":"5985"},{"size":245,"mtime":1678221097248,"results":"7624","hashOfConfig":"5985"},{"size":45,"mtime":1675188401632,"results":"7625","hashOfConfig":"5985"},{"size":1039,"mtime":1678221097248,"results":"7626","hashOfConfig":"5985"},{"size":594,"mtime":1678221097248,"results":"7627","hashOfConfig":"5985"},{"size":1247,"mtime":1678221097248,"results":"7628","hashOfConfig":"5985"},{"size":47,"mtime":1675188401632,"results":"7629","hashOfConfig":"5985"},{"size":1201,"mtime":1678221097248,"results":"7630","hashOfConfig":"5985"},{"size":1741,"mtime":1678221097248,"results":"7631","hashOfConfig":"5985"},{"size":47,"mtime":1675188401632,"results":"7632","hashOfConfig":"5985"},{"size":2304,"mtime":1678221097248,"results":"7633","hashOfConfig":"5985"},{"size":48,"mtime":1675188401632,"results":"7634","hashOfConfig":"5985"},{"size":614,"mtime":1678221097249,"results":"7635","hashOfConfig":"5985"},{"size":11453,"mtime":1678221097249,"results":"7636","hashOfConfig":"5985"},{"size":3724,"mtime":1678282296176,"results":"7637","hashOfConfig":"5985"},{"size":1620,"mtime":1678221097249,"results":"7638","hashOfConfig":"5985"},{"size":3045,"mtime":1678221097249,"results":"7639","hashOfConfig":"5985"},{"size":1364,"mtime":1678221097249,"results":"7640","hashOfConfig":"5985"},{"size":637,"mtime":1678221097249,"results":"7641","hashOfConfig":"5985"},{"size":379,"mtime":1678221097249,"results":"7642","hashOfConfig":"5985"},{"size":483,"mtime":1678221097249,"results":"7643","hashOfConfig":"5985"},{"size":848,"mtime":1678221097249,"results":"7644","hashOfConfig":"5985"},{"size":850,"mtime":1678221097249,"results":"7645","hashOfConfig":"5985"},{"size":3238,"mtime":1678221097250,"results":"7646","hashOfConfig":"5985"},{"size":3939,"mtime":1678221097250,"results":"7647","hashOfConfig":"5985"},{"size":1176,"mtime":1678221097250,"results":"7648","hashOfConfig":"5985"},{"size":1876,"mtime":1678221097250,"results":"7649","hashOfConfig":"5985"},{"size":398,"mtime":1678221097250,"results":"7650","hashOfConfig":"5985"},{"size":50,"mtime":1675188401633,"results":"7651","hashOfConfig":"5985"},{"size":7841,"mtime":1678221097250,"results":"7652","hashOfConfig":"5985"},{"size":3466,"mtime":1678221097250,"results":"7653","hashOfConfig":"5985"},{"size":51,"mtime":1675188401633,"results":"7654","hashOfConfig":"5985"},{"size":400,"mtime":1675188401634,"results":"7655","hashOfConfig":"5985"},{"size":1039,"mtime":1675188401634,"results":"7656","hashOfConfig":"5985"},{"size":805,"mtime":1678221097250,"results":"7657","hashOfConfig":"5985"},{"size":1125,"mtime":1678221097251,"results":"7658","hashOfConfig":"5985"},{"size":1069,"mtime":1678221097251,"results":"7659","hashOfConfig":"5985"},{"size":1038,"mtime":1678221097251,"results":"7660","hashOfConfig":"5985"},{"size":693,"mtime":1678221097251,"results":"7661","hashOfConfig":"5985"},{"size":2064,"mtime":1678221097251,"results":"7662","hashOfConfig":"5985"},{"size":726,"mtime":1678221097251,"results":"7663","hashOfConfig":"5985"},{"size":589,"mtime":1678221097251,"results":"7664","hashOfConfig":"5985"},{"size":701,"mtime":1678221097251,"results":"7665","hashOfConfig":"5985"},{"size":1174,"mtime":1678221097252,"results":"7666","hashOfConfig":"5985"},{"size":1433,"mtime":1678221097252,"results":"7667","hashOfConfig":"5985"},{"size":1172,"mtime":1678221097252,"results":"7668","hashOfConfig":"5985"},{"size":40,"mtime":1675188401635,"results":"7669","hashOfConfig":"5985"},{"size":389,"mtime":1675188401635,"results":"7670","hashOfConfig":"5985"},{"size":413,"mtime":1675188401635,"results":"7671","hashOfConfig":"5985"},{"size":366,"mtime":1675188401635,"results":"7672","hashOfConfig":"5985"},{"size":408,"mtime":1678221097252,"results":"7673","hashOfConfig":"5985"},{"size":656,"mtime":1678221097252,"results":"7674","hashOfConfig":"5985"},{"size":546,"mtime":1678221097252,"results":"7675","hashOfConfig":"5985"},{"size":916,"mtime":1678221097252,"results":"7676","hashOfConfig":"5985"},{"size":1715,"mtime":1678221097252,"results":"7677","hashOfConfig":"5985"},{"size":766,"mtime":1678221097252,"results":"7678","hashOfConfig":"5985"},{"size":1050,"mtime":1678221097252,"results":"7679","hashOfConfig":"5985"},{"size":785,"mtime":1678221097253,"results":"7680","hashOfConfig":"5985"},{"size":1040,"mtime":1678221097253,"results":"7681","hashOfConfig":"5985"},{"size":2511,"mtime":1678221097253,"results":"7682","hashOfConfig":"5985"},{"size":360,"mtime":1675188401635,"results":"7683","hashOfConfig":"5985"},{"size":778,"mtime":1678221097253,"results":"7684","hashOfConfig":"5985"},{"size":1105,"mtime":1675188401635,"results":"7685","hashOfConfig":"5985"},{"size":930,"mtime":1678221097253,"results":"7686","hashOfConfig":"5985"},{"size":6762,"mtime":1678221097253,"results":"7687","hashOfConfig":"5985"},{"size":1247,"mtime":1678221097253,"results":"7688","hashOfConfig":"5985"},{"size":2058,"mtime":1678221097253,"results":"7689","hashOfConfig":"5985"},{"size":2361,"mtime":1678221097254,"results":"7690","hashOfConfig":"5985"},{"size":1955,"mtime":1678221097254,"results":"7691","hashOfConfig":"5985"},{"size":2974,"mtime":1678221097254,"results":"7692","hashOfConfig":"5985"},{"size":1448,"mtime":1678221097254,"results":"7693","hashOfConfig":"5985"},{"size":51,"mtime":1675694258806,"results":"7694","hashOfConfig":"5985"},{"size":2252,"mtime":1678221097254,"results":"7695","hashOfConfig":"5985"},{"size":1386,"mtime":1678221097254,"results":"7696","hashOfConfig":"5985"},{"size":1706,"mtime":1678221097254,"results":"7697","hashOfConfig":"5985"},{"size":1175,"mtime":1678221097255,"results":"7698","hashOfConfig":"5985"},{"size":51,"mtime":1675188401637,"results":"7699","hashOfConfig":"5985"},{"size":453,"mtime":1675188401637,"results":"7700","hashOfConfig":"5985"},{"size":322,"mtime":1675188401637,"results":"7701","hashOfConfig":"5985"},{"size":1053,"mtime":1678221097255,"results":"7702","hashOfConfig":"5985"},{"size":46,"mtime":1675188401637,"results":"7703","hashOfConfig":"5985"},{"size":2897,"mtime":1678221097255,"results":"7704","hashOfConfig":"5985"},{"size":3159,"mtime":1678221097255,"results":"7705","hashOfConfig":"5985"},{"size":46,"mtime":1675188401637,"results":"7706","hashOfConfig":"5985"},{"size":2832,"mtime":1675188401637,"results":"7707","hashOfConfig":"5985"},{"size":1087,"mtime":1678221097255,"results":"7708","hashOfConfig":"5985"},{"size":47,"mtime":1675188401638,"results":"7709","hashOfConfig":"5985"},{"size":4090,"mtime":1678221097255,"results":"7710","hashOfConfig":"5985"},{"size":319,"mtime":1675188401638,"results":"7711","hashOfConfig":"5985"},{"size":2162,"mtime":1675188401638,"results":"7712","hashOfConfig":"5985"},{"size":2829,"mtime":1678221097255,"results":"7713","hashOfConfig":"5985"},{"size":2243,"mtime":1676321802401,"results":"7714","hashOfConfig":"5985"},{"size":43,"mtime":1675188401638,"results":"7715","hashOfConfig":"5985"},{"size":366,"mtime":1678221097255,"results":"7716","hashOfConfig":"5985"},{"size":2464,"mtime":1675188401638,"results":"7717","hashOfConfig":"5985"},{"size":794,"mtime":1675188401638,"results":"7718","hashOfConfig":"5985"},{"size":2045,"mtime":1675188401638,"results":"7719","hashOfConfig":"5985"},{"size":1750,"mtime":1678221097256,"results":"7720","hashOfConfig":"5985"},{"size":1276,"mtime":1678221097256,"results":"7721","hashOfConfig":"5985"},{"size":1229,"mtime":1678221097256,"results":"7722","hashOfConfig":"5985"},{"size":1014,"mtime":1675188401639,"results":"7723","hashOfConfig":"5985"},{"size":54,"mtime":1675188401639,"results":"7724","hashOfConfig":"5985"},{"size":1490,"mtime":1678221097256,"results":"7725","hashOfConfig":"5985"},{"size":2412,"mtime":1678221097256,"results":"7726","hashOfConfig":"5985"},{"size":1521,"mtime":1678221097256,"results":"7727","hashOfConfig":"5985"},{"size":1080,"mtime":1678221097256,"results":"7728","hashOfConfig":"5985"},{"size":1298,"mtime":1678221097256,"results":"7729","hashOfConfig":"5985"},{"size":47,"mtime":1675694258808,"results":"7730","hashOfConfig":"5985"},{"size":1439,"mtime":1678221097257,"results":"7731","hashOfConfig":"5985"},{"size":5753,"mtime":1678221097257,"results":"7732","hashOfConfig":"5985"},{"size":5758,"mtime":1678221097257,"results":"7733","hashOfConfig":"5985"},{"size":1524,"mtime":1678221097257,"results":"7734","hashOfConfig":"5985"},{"size":366,"mtime":1678221097257,"results":"7735","hashOfConfig":"5985"},{"size":2163,"mtime":1675188401640,"results":"7736","hashOfConfig":"5985"},{"size":1341,"mtime":1675188401640,"results":"7737","hashOfConfig":"5985"},{"size":1323,"mtime":1678221097257,"results":"7738","hashOfConfig":"5985"},{"size":828,"mtime":1678221097257,"results":"7739","hashOfConfig":"5985"},{"size":46,"mtime":1675188401640,"results":"7740","hashOfConfig":"5985"},{"size":80,"mtime":1675188401640,"results":"7741","hashOfConfig":"5985"},{"size":3999,"mtime":1678221097257,"results":"7742","hashOfConfig":"4558"},{"size":219,"mtime":1675188401640,"results":"7743","hashOfConfig":"4558"},{"size":171,"mtime":1675188401640,"results":"7744","hashOfConfig":"4558"},{"size":928,"mtime":1678221097258,"results":"7745","hashOfConfig":"4558"},{"size":199,"mtime":1675188401640,"results":"7746","hashOfConfig":"4558"},{"size":139,"mtime":1678221097258,"results":"7747","hashOfConfig":"4558"},{"size":158,"mtime":1678221097258,"results":"7748","hashOfConfig":"4558"},{"size":1323,"mtime":1678221097258,"results":"7749","hashOfConfig":"4558"},{"size":230,"mtime":1675188401641,"results":"7750","hashOfConfig":"4558"},{"size":159,"mtime":1675188401641,"results":"7751","hashOfConfig":"4558"},{"size":159,"mtime":1675188401641,"results":"7752","hashOfConfig":"4558"},{"size":306,"mtime":1675188401641,"results":"7753","hashOfConfig":"4558"},{"size":310,"mtime":1675188401641,"results":"7754","hashOfConfig":"4558"},{"size":162,"mtime":1675188401641,"results":"7755","hashOfConfig":"4558"},{"size":203,"mtime":1675188401641,"results":"7756","hashOfConfig":"4558"},{"size":150,"mtime":1675694258809,"results":"7757","hashOfConfig":"4558"},{"size":3480,"mtime":1678221097258,"results":"7758","hashOfConfig":"4558"},{"size":454,"mtime":1675188401641,"results":"7759","hashOfConfig":"4558"},{"size":366,"mtime":1675188401641,"results":"7760","hashOfConfig":"4558"},{"size":407,"mtime":1675188401641,"results":"7761","hashOfConfig":"4558"},{"size":2145,"mtime":1678221097258,"results":"7762","hashOfConfig":"4558"},{"size":132,"mtime":1675188401641,"results":"7763","hashOfConfig":"4558"},{"size":975,"mtime":1675188401641,"results":"7764","hashOfConfig":"4558"},{"size":188,"mtime":1675188401642,"results":"7765","hashOfConfig":"4558"},{"size":744,"mtime":1675188401642,"results":"7766","hashOfConfig":"4558"},{"size":711,"mtime":1675188401642,"results":"7767","hashOfConfig":"4558"},{"size":423,"mtime":1678221097258,"results":"7768","hashOfConfig":"4558"},{"size":128,"mtime":1675188401642,"results":"7769","hashOfConfig":"4558"},{"size":2186,"mtime":1675188401642,"results":"7770","hashOfConfig":"4558"},{"size":851,"mtime":1675188401642,"results":"7771","hashOfConfig":"4558"},{"size":128,"mtime":1675188401642,"results":"7772","hashOfConfig":"4558"},{"size":131,"mtime":1675188401642,"results":"7773","hashOfConfig":"4558"},{"size":73,"mtime":1675188401642,"results":"7774","hashOfConfig":"4558"},{"size":1980,"mtime":1678221097258,"results":"7775","hashOfConfig":"4558"},{"size":105,"mtime":1675188401642,"results":"7776","hashOfConfig":"4558"},{"size":232,"mtime":1675188401642,"results":"7777","hashOfConfig":"4558"},{"size":357,"mtime":1675188401642,"results":"7778","hashOfConfig":"4558"},{"size":175,"mtime":1675188401642,"results":"7779","hashOfConfig":"4558"},{"size":121,"mtime":1675188401642,"results":"7780","hashOfConfig":"4558"},{"size":422,"mtime":1675188401642,"results":"7781","hashOfConfig":"4558"},{"size":937,"mtime":1675188401643,"results":"7782","hashOfConfig":"4558"},{"size":455,"mtime":1675188401643,"results":"7783","hashOfConfig":"4558"},{"size":394,"mtime":1675188401643,"results":"7784","hashOfConfig":"4558"},{"size":47,"mtime":1675188401643,"results":"7785","hashOfConfig":"4558"},{"size":1821,"mtime":1678221097258,"results":"7786","hashOfConfig":"4558"},{"size":2419,"mtime":1675188401643,"results":"7787","hashOfConfig":"4558"},{"size":136,"mtime":1675188401643,"results":"7788","hashOfConfig":"4558"},{"size":4624,"mtime":1675188401643,"results":"7789","hashOfConfig":"4558"},{"size":284,"mtime":1675188401644,"results":"7790","hashOfConfig":"4558"},{"size":274,"mtime":1675188401644,"results":"7791","hashOfConfig":"4558"},{"size":104,"mtime":1675188401644,"results":"7792","hashOfConfig":"4558"},{"size":37,"mtime":1675188401644,"results":"7793","hashOfConfig":"4558"},{"size":325,"mtime":1675188401644,"results":"7794","hashOfConfig":"4558"},{"size":813,"mtime":1675188401644,"results":"7795","hashOfConfig":"4558"},{"size":150,"mtime":1678221097258,"results":"7796","hashOfConfig":"4558"},{"size":122,"mtime":1678221097258,"results":"7797","hashOfConfig":"4558"},{"size":1300,"mtime":1675188401645,"results":"7798","hashOfConfig":"4558"},{"size":121,"mtime":1675188401645,"results":"7799","hashOfConfig":"4558"},{"size":756,"mtime":1675188401645,"results":"7800","hashOfConfig":"4558"},{"size":2238,"mtime":1675188401645,"results":"7801","hashOfConfig":"4558"},{"size":717,"mtime":1675188401645,"results":"7802","hashOfConfig":"4558"},{"size":672,"mtime":1675188401646,"results":"7803","hashOfConfig":"4558"},{"size":416,"mtime":1675188401646,"results":"7804","hashOfConfig":"4558"},{"size":940,"mtime":1675188401646,"results":"7805","hashOfConfig":"4558"},{"size":3403,"mtime":1675188401646,"results":"7806","hashOfConfig":"4558"},{"size":779,"mtime":1675188401646,"results":"7807","hashOfConfig":"4558"},{"size":459,"mtime":1675188401646,"results":"7808","hashOfConfig":"4558"},{"size":2113,"mtime":1675188401646,"results":"7809","hashOfConfig":"4558"},{"size":747,"mtime":1675188401646,"results":"7810","hashOfConfig":"4558"},{"size":916,"mtime":1675188401646,"results":"7811","hashOfConfig":"4558"},{"size":8339,"mtime":1678221097259,"results":"7812","hashOfConfig":"4558"},{"size":2250,"mtime":1678221097259,"results":"7813","hashOfConfig":"4558"},{"size":2307,"mtime":1678221097259,"results":"7814","hashOfConfig":"4558"},{"size":4247,"mtime":1678221097259,"results":"7815","hashOfConfig":"4558"},{"size":6237,"mtime":1678221097259,"results":"7816","hashOfConfig":"4558"},{"size":10471,"mtime":1678221097259,"results":"7817","hashOfConfig":"4558"},{"size":2018,"mtime":1678221097260,"results":"7818","hashOfConfig":"4558"},{"size":258,"mtime":1675188401647,"results":"7819","hashOfConfig":"4558"},{"size":149,"mtime":1675188401647,"results":"7820","hashOfConfig":"4558"},{"size":1697,"mtime":1678221097260,"results":"7821","hashOfConfig":"4558"},{"size":3511,"mtime":1678221097260,"results":"7822","hashOfConfig":"4558"},{"size":6892,"mtime":1678221097260,"results":"7823","hashOfConfig":"4558"},{"size":6785,"mtime":1678221097260,"results":"7824","hashOfConfig":"4558"},{"size":439,"mtime":1675188401647,"results":"7825","hashOfConfig":"4558"},{"size":1480,"mtime":1678221097260,"results":"7826","hashOfConfig":"4558"},{"size":8283,"mtime":1678221097260,"results":"7827","hashOfConfig":"4558"},{"size":5185,"mtime":1678221097260,"results":"7828","hashOfConfig":"4558"},{"size":1379,"mtime":1675188401648,"results":"7829","hashOfConfig":"4558"},{"size":976,"mtime":1675188401648,"results":"7830","hashOfConfig":"4558"},{"size":442,"mtime":1678282296177,"results":"7831","hashOfConfig":"4558"},{"size":433,"mtime":1678221097261,"results":"7832","hashOfConfig":"4558"},{"size":64,"mtime":1678221097261,"results":"7833","hashOfConfig":"4558"},{"size":1574,"mtime":1678221097261,"results":"7834","hashOfConfig":"4558"},{"size":1350,"mtime":1675188401648,"results":"7835","hashOfConfig":"4558"},{"size":1017,"mtime":1675188401648,"results":"7836","hashOfConfig":"4558"},{"size":3224,"mtime":1678221097261,"results":"7837","hashOfConfig":"4558"},{"size":216,"mtime":1675188401648,"results":"7838","hashOfConfig":"4558"},{"size":208,"mtime":1675188401648,"results":"7839","hashOfConfig":"4558"},{"size":921,"mtime":1678282296177,"results":"7840","hashOfConfig":"4558"},{"size":1257,"mtime":1678221097261,"results":"7841","hashOfConfig":"4558"},{"size":11130,"mtime":1678282296177,"results":"7842","hashOfConfig":"4558"},{"size":2972,"mtime":1678221097262,"results":"7843","hashOfConfig":"4558"},{"size":435,"mtime":1675188401649,"results":"7844","hashOfConfig":"4558"},{"size":1346,"mtime":1675188401649,"results":"7845","hashOfConfig":"4558"},{"size":339,"mtime":1675188401649,"results":"7846","hashOfConfig":"4558"},{"size":369,"mtime":1675188401656,"results":"7847","hashOfConfig":"4558"},{"size":310,"mtime":1675188401656,"results":"7848","hashOfConfig":"4558"},{"size":301,"mtime":1675188401656,"results":"7849","hashOfConfig":"4558"},{"size":317,"mtime":1675188401656,"results":"7850","hashOfConfig":"4558"},{"size":308,"mtime":1675188401656,"results":"7851","hashOfConfig":"4558"},{"size":214,"mtime":1675188401656,"results":"7852","hashOfConfig":"4558"},{"size":246,"mtime":1675188401649,"results":"7853","hashOfConfig":"4558"},{"size":1049,"mtime":1675188401649,"results":"7854","hashOfConfig":"4558"},{"size":354,"mtime":1675188401649,"results":"7855","hashOfConfig":"4558"},{"size":562,"mtime":1675188401649,"results":"7856","hashOfConfig":"4558"},{"size":946,"mtime":1675188401649,"results":"7857","hashOfConfig":"4558"},{"size":687,"mtime":1675188401649,"results":"7858","hashOfConfig":"4558"},{"size":1214,"mtime":1678221097262,"results":"7859","hashOfConfig":"4558"},{"size":267,"mtime":1675188401650,"results":"7860","hashOfConfig":"4558"},{"size":1192,"mtime":1678221097262,"results":"7861","hashOfConfig":"4558"},{"size":3192,"mtime":1675188401650,"results":"7862","hashOfConfig":"4558"},{"size":571,"mtime":1675188401650,"results":"7863","hashOfConfig":"4558"},{"size":8956,"mtime":1675188401650,"results":"7864","hashOfConfig":"4558"},{"size":228,"mtime":1678221097262,"results":"7865","hashOfConfig":"4558"},{"size":562,"mtime":1678221097262,"results":"7866","hashOfConfig":"4558"},{"size":184,"mtime":1675188401650,"results":"7867","hashOfConfig":"4558"},{"size":913,"mtime":1678221097262,"results":"7868","hashOfConfig":"4558"},{"size":1559,"mtime":1675188401650,"results":"7869","hashOfConfig":"4558"},{"size":3364,"mtime":1678221097262,"results":"7870","hashOfConfig":"4558"},{"size":1863,"mtime":1678221097262,"results":"7871","hashOfConfig":"4558"},{"size":1273,"mtime":1675188401650,"results":"7872","hashOfConfig":"4558"},{"size":1367,"mtime":1675188401651,"results":"7873","hashOfConfig":"4558"},{"size":950,"mtime":1675188401651,"results":"7874","hashOfConfig":"4558"},{"size":2144,"mtime":1678221097262,"results":"7875","hashOfConfig":"4558"},{"size":2948,"mtime":1678221097262,"results":"7876","hashOfConfig":"4558"},{"size":2333,"mtime":1678221097262,"results":"7877","hashOfConfig":"4558"},{"size":1016,"mtime":1675188401651,"results":"7878","hashOfConfig":"4558"},{"size":1320,"mtime":1678221097263,"results":"7879","hashOfConfig":"4558"},{"size":3065,"mtime":1675188401651,"results":"7880","hashOfConfig":"4558"},{"size":4346,"mtime":1675188401651,"results":"7881","hashOfConfig":"4558"},{"size":2897,"mtime":1675188401651,"results":"7882","hashOfConfig":"4558"},{"size":11709,"mtime":1675188401651,"results":"7883","hashOfConfig":"4558"},{"size":19,"mtime":1675188401651,"results":"7884","hashOfConfig":"4558"},{"size":1175,"mtime":1675188401651,"results":"7885","hashOfConfig":"4558"},{"size":687,"mtime":1675188401651,"results":"7886","hashOfConfig":"4558"},{"size":447,"mtime":1675188401651,"results":"7887","hashOfConfig":"4558"},{"size":1305,"mtime":1675188401652,"results":"7888","hashOfConfig":"4558"},{"size":1295,"mtime":1675188401652,"results":"7889","hashOfConfig":"4558"},{"size":1444,"mtime":1675694258811,"results":"7890","hashOfConfig":"4558"},{"size":681,"mtime":1675188401652,"results":"7891","hashOfConfig":"4558"},{"size":1193,"mtime":1678221097263,"results":"7892","hashOfConfig":"4558"},{"size":1005,"mtime":1675188401652,"results":"7893","hashOfConfig":"4558"},{"size":874,"mtime":1675188401652,"results":"7894","hashOfConfig":"4558"},{"size":948,"mtime":1675188401652,"results":"7895","hashOfConfig":"4558"},{"size":1833,"mtime":1675188401652,"results":"7896","hashOfConfig":"4558"},{"size":746,"mtime":1675188401652,"results":"7897","hashOfConfig":"4558"},{"size":1471,"mtime":1675188401652,"results":"7898","hashOfConfig":"4558"},{"size":1232,"mtime":1675188401652,"results":"7899","hashOfConfig":"4558"},{"size":307,"mtime":1675188401652,"results":"7900","hashOfConfig":"4558"},{"size":1997,"mtime":1678221097263,"results":"7901","hashOfConfig":"4558"},{"size":739,"mtime":1678221097263,"results":"7902","hashOfConfig":"4558"},{"size":3051,"mtime":1678221097263,"results":"7903","hashOfConfig":"4558"},{"size":2486,"mtime":1675188401653,"results":"7904","hashOfConfig":"4558"},{"size":3523,"mtime":1675188401653,"results":"7905","hashOfConfig":"4558"},{"size":905,"mtime":1678221097263,"results":"7906","hashOfConfig":"4558"},{"size":2208,"mtime":1678221097263,"results":"7907","hashOfConfig":"4558"},{"size":706,"mtime":1675188401653,"results":"7908","hashOfConfig":"4558"},{"size":320,"mtime":1678221097263,"results":"7909","hashOfConfig":"4558"},{"size":685,"mtime":1678221097263,"results":"7910","hashOfConfig":"4558"},{"size":630,"mtime":1675188401653,"results":"7911","hashOfConfig":"4558"},{"size":1049,"mtime":1675188401653,"results":"7912","hashOfConfig":"4558"},{"size":2770,"mtime":1678221097263,"results":"7913","hashOfConfig":"4558"},{"size":2002,"mtime":1675188401653,"results":"7914","hashOfConfig":"4558"},{"size":1294,"mtime":1675188401653,"results":"7915","hashOfConfig":"4558"},{"size":3412,"mtime":1678221097263,"results":"7916","hashOfConfig":"4558"},{"size":1134,"mtime":1678221097264,"results":"7917","hashOfConfig":"4558"},{"size":1285,"mtime":1675188401654,"results":"7918","hashOfConfig":"4558"},{"size":1723,"mtime":1678221097264,"results":"7919","hashOfConfig":"4558"},{"size":2318,"mtime":1678221097264,"results":"7920","hashOfConfig":"4558"},{"size":3153,"mtime":1675694258812,"results":"7921","hashOfConfig":"4558"},{"size":1189,"mtime":1675188401654,"results":"7922","hashOfConfig":"4558"},{"size":8802,"mtime":1678221097264,"results":"7923","hashOfConfig":"4558"},{"size":12048,"mtime":1678282296177,"results":"7924","hashOfConfig":"4558"},{"size":3810,"mtime":1678221097264,"results":"7925","hashOfConfig":"4558"},{"size":1727,"mtime":1678221097264,"results":"7926","hashOfConfig":"4558"},{"size":4278,"mtime":1678221097264,"results":"7927","hashOfConfig":"4558"},{"size":968,"mtime":1675188401654,"results":"7928","hashOfConfig":"4558"},{"size":390,"mtime":1675188401654,"results":"7929","hashOfConfig":"4558"},{"size":782,"mtime":1675188401655,"results":"7930","hashOfConfig":"4558"},{"size":840,"mtime":1675188401655,"results":"7931","hashOfConfig":"4558"},{"size":1186,"mtime":1675188401655,"results":"7932","hashOfConfig":"4558"},{"size":702,"mtime":1675188401655,"results":"7933","hashOfConfig":"4558"},{"size":604,"mtime":1675188401655,"results":"7934","hashOfConfig":"4558"},{"size":474,"mtime":1675188401655,"results":"7935","hashOfConfig":"4558"},{"size":799,"mtime":1675188401655,"results":"7936","hashOfConfig":"4558"},{"size":601,"mtime":1675188401655,"results":"7937","hashOfConfig":"4558"},{"size":491,"mtime":1675188401655,"results":"7938","hashOfConfig":"4558"},{"size":455,"mtime":1675188401655,"results":"7939","hashOfConfig":"4558"},{"size":459,"mtime":1675188401655,"results":"7940","hashOfConfig":"4558"},{"size":2439,"mtime":1675188401655,"results":"7941","hashOfConfig":"4558"},{"size":502,"mtime":1675188401655,"results":"7942","hashOfConfig":"4558"},{"size":537,"mtime":1675188401656,"results":"7943","hashOfConfig":"4558"},{"size":1471,"mtime":1678221097264,"results":"7944","hashOfConfig":"4558"},{"size":904,"mtime":1678221097265,"results":"7945","hashOfConfig":"4558"},{"size":7520,"mtime":1678221097265,"results":"7946","hashOfConfig":"4558"},{"size":1733,"mtime":1675188401656,"results":"7947","hashOfConfig":"4558"},{"size":805,"mtime":1678221097265,"results":"7948","hashOfConfig":"4558"},{"size":933,"mtime":1678221097265,"results":"7949","hashOfConfig":"4558"},{"size":59,"mtime":1678221097265,"results":"7950","hashOfConfig":"4558"},{"size":129,"mtime":1678221097265,"results":"7951","hashOfConfig":"4558"},{"size":114,"mtime":1675188401656,"results":"7952","hashOfConfig":"4558"},{"size":463,"mtime":1678221097265,"results":"7953","hashOfConfig":"4558"},{"size":1392,"mtime":1675188401657,"results":"7954","hashOfConfig":"4558"},{"size":1722,"mtime":1678282296177,"results":"7955","hashOfConfig":"4558"},{"size":748,"mtime":1678221097265,"results":"7956","hashOfConfig":"4558"},{"size":829,"mtime":1675188401657,"results":"7957","hashOfConfig":"4558"},{"size":4379,"mtime":1675188401657,"results":"7958","hashOfConfig":"4558"},{"size":861,"mtime":1675188401657,"results":"7959","hashOfConfig":"4558"},{"size":1236,"mtime":1678221097266,"results":"7960","hashOfConfig":"4558"},{"size":2548,"mtime":1678221097266,"results":"7961","hashOfConfig":"4558"},{"size":994,"mtime":1675188401657,"results":"7962","hashOfConfig":"4558"},{"size":58,"mtime":1675188401657,"results":"7963","hashOfConfig":"4558"},{"size":518,"mtime":1678221097267,"results":"7964","hashOfConfig":"4558"},{"size":1531,"mtime":1675188401657,"results":"7965","hashOfConfig":"4558"},{"size":433,"mtime":1678221097267,"results":"7966","hashOfConfig":"4558"},{"size":734,"mtime":1678221097267,"results":"7967","hashOfConfig":"4558"},{"size":1481,"mtime":1678221097267,"results":"7968","hashOfConfig":"4558"},{"size":33,"mtime":1675188401658,"results":"7969","hashOfConfig":"4558"},{"size":1064,"mtime":1675188401658,"results":"7970","hashOfConfig":"4558"},{"size":1612,"mtime":1678221097268,"results":"7971","hashOfConfig":"4558"},{"size":3099,"mtime":1678221097268,"results":"7972","hashOfConfig":"7973"},{"size":1428,"mtime":1678221097268,"results":"7974","hashOfConfig":"7973"},{"size":64,"mtime":1678221097268,"results":"7975","hashOfConfig":"7973"},{"size":2154,"mtime":1678282296177,"results":"7976","hashOfConfig":"7973"},{"size":1537,"mtime":1678221097268,"results":"7977","hashOfConfig":"7973"},{"size":952,"mtime":1678221097268,"results":"7978","hashOfConfig":"7973"},{"size":2024,"mtime":1678221097269,"results":"7979","hashOfConfig":"7973"},{"size":2590,"mtime":1678221097269,"results":"7980","hashOfConfig":"7973"},{"size":407,"mtime":1678221097269,"results":"7981","hashOfConfig":"7973"},{"size":672,"mtime":1678221097270,"results":"7982","hashOfConfig":"7973"},{"size":1200,"mtime":1678221097270,"results":"7983","hashOfConfig":"7973"},{"size":70,"mtime":1678221097270,"results":"7984","hashOfConfig":"7973"},{"size":8052,"mtime":1678282296177,"results":"7985","hashOfConfig":"7973"},{"size":458,"mtime":1678221097271,"results":"7986","hashOfConfig":"7973"},{"size":664,"mtime":1678221097271,"results":"7987","hashOfConfig":"7973"},{"size":3076,"mtime":1678221097271,"results":"7988","hashOfConfig":"7973"},{"size":51,"mtime":1675188401660,"results":"7989","hashOfConfig":"7973"},{"size":2257,"mtime":1675188401660,"results":"7990","hashOfConfig":"7973"},{"size":1643,"mtime":1675188401660,"results":"7991","hashOfConfig":"7973"},{"size":1914,"mtime":1678221097271,"results":"7992","hashOfConfig":"7973"},{"size":901,"mtime":1678221097271,"results":"7993","hashOfConfig":"7973"},{"size":494,"mtime":1678282296178,"results":"7994","hashOfConfig":"7973"},{"size":421,"mtime":1675188401660,"results":"7995","hashOfConfig":"7973"},{"size":1620,"mtime":1675188401660,"results":"7996","hashOfConfig":"7973"},{"size":4149,"mtime":1678221097271,"results":"7997","hashOfConfig":"7973"},{"size":560,"mtime":1678221097272,"results":"7998","hashOfConfig":"7973"},{"size":199,"mtime":1678221097272,"results":"7999","hashOfConfig":"7973"},{"size":336,"mtime":1675188401660,"results":"8000","hashOfConfig":"7973"},{"size":855,"mtime":1675188401660,"results":"8001","hashOfConfig":"7973"},{"size":2534,"mtime":1678221097272,"results":"8002","hashOfConfig":"7973"},{"size":139,"mtime":1675188401661,"results":"8003","hashOfConfig":"7973"},{"size":1529,"mtime":1675188401661,"results":"8004","hashOfConfig":"7973"},{"size":1397,"mtime":1675188401661,"results":"8005","hashOfConfig":"7973"},{"size":1544,"mtime":1678221097273,"results":"8006","hashOfConfig":"7973"},{"size":1101,"mtime":1678221097273,"results":"8007","hashOfConfig":"7973"},{"size":1175,"mtime":1678221097273,"results":"8008","hashOfConfig":"7973"},{"size":1467,"mtime":1675188401661,"results":"8009","hashOfConfig":"7973"},{"size":1228,"mtime":1675188401661,"results":"8010","hashOfConfig":"7973"},{"size":819,"mtime":1678221097273,"results":"8011","hashOfConfig":"7973"},{"size":859,"mtime":1675188401661,"results":"8012","hashOfConfig":"7973"},{"size":1105,"mtime":1675188401661,"results":"8013","hashOfConfig":"7973"},{"size":644,"mtime":1678221097273,"results":"8014","hashOfConfig":"7973"},{"size":551,"mtime":1675188401661,"results":"8015","hashOfConfig":"7973"},{"size":2209,"mtime":1675188401662,"results":"8016","hashOfConfig":"7973"},{"size":1386,"mtime":1675188401662,"results":"8017","hashOfConfig":"7973"},{"size":735,"mtime":1678221097273,"results":"8018","hashOfConfig":"7973"},{"size":2328,"mtime":1678221097273,"results":"8019","hashOfConfig":"7973"},{"size":488,"mtime":1675188401662,"results":"8020","hashOfConfig":"7973"},{"size":496,"mtime":1675188401662,"results":"8021","hashOfConfig":"7973"},{"size":480,"mtime":1675188401662,"results":"8022","hashOfConfig":"7973"},{"size":762,"mtime":1678221097273,"results":"8023","hashOfConfig":"7973"},{"size":539,"mtime":1675188401662,"results":"8024","hashOfConfig":"7973"},{"size":526,"mtime":1675188401662,"results":"8025","hashOfConfig":"7973"},{"size":2224,"mtime":1678221097274,"results":"8026","hashOfConfig":"7973"},{"size":850,"mtime":1678221097274,"results":"8027","hashOfConfig":"7973"},{"size":4219,"mtime":1678221097274,"results":"8028","hashOfConfig":"7973"},{"size":5448,"mtime":1678282296178,"results":"8029","hashOfConfig":"7973"},{"size":1399,"mtime":1678221097274,"results":"8030","hashOfConfig":"7973"},{"size":1496,"mtime":1678221097274,"results":"8031","hashOfConfig":"7973"},{"size":1911,"mtime":1678221097274,"results":"8032","hashOfConfig":"7973"},{"size":351,"mtime":1678221097274,"results":"8033","hashOfConfig":"7973"},{"size":2073,"mtime":1678221097274,"results":"8034","hashOfConfig":"7973"},{"size":7456,"mtime":1678221097275,"results":"8035","hashOfConfig":"7973"},{"size":342,"mtime":1675188401663,"results":"8036","hashOfConfig":"7973"},{"size":1919,"mtime":1678221097275,"results":"8037","hashOfConfig":"7973"},{"size":2949,"mtime":1678221097275,"results":"8038","hashOfConfig":"7973"},{"size":2377,"mtime":1678221097275,"results":"8039","hashOfConfig":"7973"},{"size":438,"mtime":1678221097275,"results":"8040","hashOfConfig":"7973"},{"size":4193,"mtime":1678221097275,"results":"8041","hashOfConfig":"7973"},{"size":652,"mtime":1678221097275,"results":"8042","hashOfConfig":"7973"},{"size":705,"mtime":1678221097275,"results":"8043","hashOfConfig":"7973"},{"size":1296,"mtime":1678221097276,"results":"8044","hashOfConfig":"7973"},{"size":502,"mtime":1678221097276,"results":"8045","hashOfConfig":"7973"},{"size":414,"mtime":1678221097276,"results":"8046","hashOfConfig":"7973"},{"size":504,"mtime":1678221097276,"results":"8047","hashOfConfig":"7973"},{"size":1136,"mtime":1678221097276,"results":"8048","hashOfConfig":"7973"},{"size":1998,"mtime":1678221097276,"results":"8049","hashOfConfig":"7973"},{"size":617,"mtime":1678221097276,"results":"8050","hashOfConfig":"7973"},{"size":1000,"mtime":1678221097276,"results":"8051","hashOfConfig":"7973"},{"size":3925,"mtime":1678282296178,"results":"8052","hashOfConfig":"7973"},{"size":50,"mtime":1675188401664,"results":"8053","hashOfConfig":"7973"},{"size":1261,"mtime":1678221097277,"results":"8054","hashOfConfig":"7973"},{"size":2858,"mtime":1678221097277,"results":"8055","hashOfConfig":"7973"},{"size":2422,"mtime":1678221097277,"results":"8056","hashOfConfig":"7973"},{"size":3868,"mtime":1678221097277,"results":"8057","hashOfConfig":"7973"},{"size":857,"mtime":1678221097277,"results":"8058","hashOfConfig":"7973"},{"size":2233,"mtime":1678221097277,"results":"8059","hashOfConfig":"7973"},{"size":1367,"mtime":1678221097277,"results":"8060","hashOfConfig":"7973"},{"size":2651,"mtime":1678221097277,"results":"8061","hashOfConfig":"7973"},{"size":848,"mtime":1675188401665,"results":"8062","hashOfConfig":"7973"},{"size":2460,"mtime":1675188401665,"results":"8063","hashOfConfig":"7973"},{"size":170,"mtime":1678221097277,"results":"8064","hashOfConfig":"7973"},{"size":2422,"mtime":1678221097277,"results":"8065","hashOfConfig":"7973"},{"size":451,"mtime":1675188401665,"results":"8066","hashOfConfig":"7973"},{"size":56,"mtime":1675188401665,"results":"8067","hashOfConfig":"7973"},{"size":2854,"mtime":1678221097278,"results":"8068","hashOfConfig":"7973"},{"size":586,"mtime":1675188401665,"results":"8069","hashOfConfig":"7973"},{"size":1546,"mtime":1675188401666,"results":"8070","hashOfConfig":"7973"},{"size":1409,"mtime":1675188401666,"results":"8071","hashOfConfig":"7973"},{"size":3409,"mtime":1678221097278,"results":"8072","hashOfConfig":"7973"},{"size":703,"mtime":1678221097278,"results":"8073","hashOfConfig":"7973"},{"size":682,"mtime":1678221097278,"results":"8074","hashOfConfig":"7973"},{"size":1391,"mtime":1678221097278,"results":"8075","hashOfConfig":"7973"},{"size":3287,"mtime":1678221097278,"results":"8076","hashOfConfig":"7973"},{"size":1056,"mtime":1678221097278,"results":"8077","hashOfConfig":"7973"},{"size":2224,"mtime":1678221097278,"results":"8078","hashOfConfig":"7973"},{"size":974,"mtime":1678221097278,"results":"8079","hashOfConfig":"7973"},{"size":758,"mtime":1678221097279,"results":"8080","hashOfConfig":"7973"},{"size":1582,"mtime":1678221097279,"results":"8081","hashOfConfig":"7973"},{"size":3844,"mtime":1678221097279,"results":"8082","hashOfConfig":"7973"},{"size":947,"mtime":1678221097279,"results":"8083","hashOfConfig":"7973"},{"size":242,"mtime":1678221097279,"results":"8084","hashOfConfig":"7973"},{"size":2264,"mtime":1678221097279,"results":"8085","hashOfConfig":"7973"},{"size":4882,"mtime":1678221097279,"results":"8086","hashOfConfig":"7973"},{"size":1427,"mtime":1675188401666,"results":"8087","hashOfConfig":"7973"},{"size":1591,"mtime":1675188401666,"results":"8088","hashOfConfig":"7973"},{"size":329,"mtime":1678221097279,"results":"8089","hashOfConfig":"7973"},{"size":1460,"mtime":1675188401666,"results":"8090","hashOfConfig":"7973"},{"size":3380,"mtime":1678221097279,"results":"8091","hashOfConfig":"7973"},{"size":1130,"mtime":1678221097280,"results":"8092","hashOfConfig":"7973"},{"size":1430,"mtime":1678221097280,"results":"8093","hashOfConfig":"7973"},{"size":1337,"mtime":1675188401667,"results":"8094","hashOfConfig":"7973"},{"size":3701,"mtime":1678221097280,"results":"8095","hashOfConfig":"7973"},{"size":1468,"mtime":1675188401667,"results":"8096","hashOfConfig":"7973"},{"size":7328,"mtime":1675188401667,"results":"8097","hashOfConfig":"7973"},{"size":1569,"mtime":1678221097280,"results":"8098","hashOfConfig":"7973"},{"size":1344,"mtime":1675188401667,"results":"8099","hashOfConfig":"7973"},{"size":3943,"mtime":1678221097280,"results":"8100","hashOfConfig":"7973"},{"size":812,"mtime":1678221097280,"results":"8101","hashOfConfig":"7973"},{"size":2215,"mtime":1678221097280,"results":"8102","hashOfConfig":"7973"},{"size":1487,"mtime":1675188401667,"results":"8103","hashOfConfig":"7973"},{"size":1010,"mtime":1675188401667,"results":"8104","hashOfConfig":"7973"},{"size":147,"mtime":1678221097280,"results":"8105","hashOfConfig":"7973"},{"size":1057,"mtime":1678221097281,"results":"8106","hashOfConfig":"7973"},{"size":432,"mtime":1675188401668,"results":"8107","hashOfConfig":"7973"},{"size":23,"mtime":1675188401668,"results":"8108","hashOfConfig":"7973"},{"size":554,"mtime":1678221097281,"results":"8109","hashOfConfig":"7973"},{"size":1600,"mtime":1678221097281,"results":"8110","hashOfConfig":"7973"},{"size":2922,"mtime":1678221097281,"results":"8111","hashOfConfig":"7973"},{"size":58,"mtime":1675188401668,"results":"8112","hashOfConfig":"7973"},{"size":947,"mtime":1678221097281,"results":"8113","hashOfConfig":"7973"},{"size":579,"mtime":1678221097281,"results":"8114","hashOfConfig":"7973"},{"size":2623,"mtime":1678221097281,"results":"8115","hashOfConfig":"7973"},{"size":4226,"mtime":1678221097281,"results":"8116","hashOfConfig":"7973"},{"size":56,"mtime":1675188401668,"results":"8117","hashOfConfig":"7973"},{"size":3306,"mtime":1678221097281,"results":"8118","hashOfConfig":"7973"},{"size":2039,"mtime":1678221097282,"results":"8119","hashOfConfig":"7973"},{"size":58,"mtime":1675188401669,"results":"8120","hashOfConfig":"7973"},{"size":776,"mtime":1678221097282,"results":"8121","hashOfConfig":"7973"},{"size":1653,"mtime":1678221097282,"results":"8122","hashOfConfig":"7973"},{"size":546,"mtime":1678221097282,"results":"8123","hashOfConfig":"7973"},{"size":543,"mtime":1678221097282,"results":"8124","hashOfConfig":"7973"},{"size":2291,"mtime":1678221097282,"results":"8125","hashOfConfig":"7973"},{"size":1559,"mtime":1678221097282,"results":"8126","hashOfConfig":"7973"},{"size":4352,"mtime":1678221097282,"results":"8127","hashOfConfig":"7973"},{"size":442,"mtime":1678221097282,"results":"8128","hashOfConfig":"7973"},{"size":341,"mtime":1678221097283,"results":"8129","hashOfConfig":"7973"},{"size":1059,"mtime":1678221097283,"results":"8130","hashOfConfig":"7973"},{"size":1591,"mtime":1678221097283,"results":"8131","hashOfConfig":"7973"},{"size":871,"mtime":1678221097283,"results":"8132","hashOfConfig":"7973"},{"size":578,"mtime":1678221097283,"results":"8133","hashOfConfig":"7973"},{"size":858,"mtime":1678221097283,"results":"8134","hashOfConfig":"7973"},{"size":306,"mtime":1675188401670,"results":"8135","hashOfConfig":"7973"},{"size":1547,"mtime":1678221097283,"results":"8136","hashOfConfig":"7973"},{"size":341,"mtime":1678221097284,"results":"8137","hashOfConfig":"7973"},{"size":482,"mtime":1678221097284,"results":"8138","hashOfConfig":"7973"},{"size":8196,"mtime":1678221097284,"results":"8139","hashOfConfig":"7973"},{"size":5041,"mtime":1678221097284,"results":"8140","hashOfConfig":"7973"},{"size":437,"mtime":1678221097284,"results":"8141","hashOfConfig":"7973"},{"size":707,"mtime":1678221097284,"results":"8142","hashOfConfig":"7973"},{"size":959,"mtime":1678221097284,"results":"8143","hashOfConfig":"7973"},{"size":962,"mtime":1678221097285,"results":"8144","hashOfConfig":"7973"},{"size":1036,"mtime":1678221097285,"results":"8145","hashOfConfig":"7973"},{"size":8310,"mtime":1678221097285,"results":"8146","hashOfConfig":"7973"},{"size":1690,"mtime":1678221097285,"results":"8147","hashOfConfig":"7973"},{"size":3819,"mtime":1678221097285,"results":"8148","hashOfConfig":"7973"},{"size":4096,"mtime":1678221097285,"results":"8149","hashOfConfig":"7973"},{"size":6272,"mtime":1678221097285,"results":"8150","hashOfConfig":"7973"},{"size":5691,"mtime":1678221097286,"results":"8151","hashOfConfig":"7973"},{"size":491,"mtime":1678221097286,"results":"8152","hashOfConfig":"7973"},{"size":1634,"mtime":1678221097286,"results":"8153","hashOfConfig":"7973"},{"size":976,"mtime":1675188401671,"results":"8154","hashOfConfig":"7973"},{"size":985,"mtime":1675188401671,"results":"8155","hashOfConfig":"7973"},{"size":958,"mtime":1678221097286,"results":"8156","hashOfConfig":"7973"},{"size":1052,"mtime":1678221097286,"results":"8157","hashOfConfig":"7973"},{"size":986,"mtime":1675188401671,"results":"8158","hashOfConfig":"7973"},{"size":1907,"mtime":1678221097286,"results":"8159","hashOfConfig":"7973"},{"size":1294,"mtime":1678221097286,"results":"8160","hashOfConfig":"7973"},{"size":1388,"mtime":1678221097286,"results":"8161","hashOfConfig":"7973"},{"size":487,"mtime":1678221097286,"results":"8162","hashOfConfig":"7973"},{"size":1134,"mtime":1678221097287,"results":"8163","hashOfConfig":"7973"},{"size":43,"mtime":1675188401672,"results":"8164","hashOfConfig":"7973"},{"size":307,"mtime":1675188401672,"results":"8165","hashOfConfig":"7973"},{"size":3141,"mtime":1678221097287,"results":"8166","hashOfConfig":"7973"},{"size":144,"mtime":1675188401672,"results":"8167","hashOfConfig":"7973"},{"size":457,"mtime":1675188401672,"results":"8168","hashOfConfig":"7973"},{"size":1776,"mtime":1678221097287,"results":"8169","hashOfConfig":"7973"},{"size":2141,"mtime":1678221097287,"results":"8170","hashOfConfig":"7973"},{"size":1009,"mtime":1678221097287,"results":"8171","hashOfConfig":"7973"},{"size":2878,"mtime":1678221097287,"results":"8172","hashOfConfig":"7973"},{"size":2089,"mtime":1678221097287,"results":"8173","hashOfConfig":"7973"},{"size":1063,"mtime":1678221097287,"results":"8174","hashOfConfig":"7973"},{"size":1409,"mtime":1678221097287,"results":"8175","hashOfConfig":"7973"},{"size":775,"mtime":1678221097287,"results":"8176","hashOfConfig":"7973"},{"size":5179,"mtime":1678221097287,"results":"8177","hashOfConfig":"7973"},{"size":2152,"mtime":1678221097288,"results":"8178","hashOfConfig":"7973"},{"size":1169,"mtime":1678221097288,"results":"8179","hashOfConfig":"7973"},{"size":1877,"mtime":1678221097288,"results":"8180","hashOfConfig":"7973"},{"size":1890,"mtime":1678221097288,"results":"8181","hashOfConfig":"7973"},{"size":2311,"mtime":1678221097288,"results":"8182","hashOfConfig":"7973"},{"size":1297,"mtime":1678221097288,"results":"8183","hashOfConfig":"7973"},{"size":1404,"mtime":1678221097288,"results":"8184","hashOfConfig":"7973"},{"size":718,"mtime":1678221097288,"results":"8185","hashOfConfig":"7973"},{"size":961,"mtime":1678221097288,"results":"8186","hashOfConfig":"7973"},{"size":997,"mtime":1678221097288,"results":"8187","hashOfConfig":"7973"},{"size":329,"mtime":1678221097288,"results":"8188","hashOfConfig":"7973"},{"size":232,"mtime":1678221097288,"results":"8189","hashOfConfig":"7973"},{"size":2115,"mtime":1678221097289,"results":"8190","hashOfConfig":"7973"},{"size":997,"mtime":1678221097289,"results":"8191","hashOfConfig":"7973"},{"size":430,"mtime":1678221097289,"results":"8192","hashOfConfig":"7973"},{"size":2023,"mtime":1678221097289,"results":"8193","hashOfConfig":"7973"},{"size":872,"mtime":1678221097289,"results":"8194","hashOfConfig":"7973"},{"size":1398,"mtime":1678221097289,"results":"8195","hashOfConfig":"7973"},{"size":2816,"mtime":1678221097289,"results":"8196","hashOfConfig":"7973"},{"size":452,"mtime":1675188401673,"results":"8197","hashOfConfig":"7973"},{"size":1928,"mtime":1678221097289,"results":"8198","hashOfConfig":"7973"},{"size":4415,"mtime":1678221097289,"results":"8199","hashOfConfig":"7973"},{"size":1109,"mtime":1678221097290,"results":"8200","hashOfConfig":"8201"},{"size":37,"mtime":1678221097290,"results":"8202","hashOfConfig":"8201"},{"size":918,"mtime":1678221097290,"results":"8203","hashOfConfig":"8201"},{"size":38,"mtime":1678221097290,"results":"8204","hashOfConfig":"8201"},{"size":344,"mtime":1678221097290,"results":"8205","hashOfConfig":"8201"},{"size":206,"mtime":1678221097290,"results":"8206","hashOfConfig":"8201"},{"size":784,"mtime":1678221097290,"results":"8207","hashOfConfig":"8201"},{"size":2706,"mtime":1678221097290,"results":"8208","hashOfConfig":"8201"},{"size":463,"mtime":1678221097290,"results":"8209","hashOfConfig":"8201"},{"size":1025,"mtime":1678221097290,"results":"8210","hashOfConfig":"8201"},{"size":1044,"mtime":1678221097290,"results":"8211","hashOfConfig":"8201"},{"size":80,"mtime":1675188401674,"results":"8212","hashOfConfig":"8201"},{"size":1619,"mtime":1678221097291,"results":"8213","hashOfConfig":"8201"},{"size":516,"mtime":1675188401674,"results":"8214","hashOfConfig":"8201"},{"size":318,"mtime":1675188401674,"results":"8215","hashOfConfig":"8201"},{"size":96,"mtime":1678221097291,"results":"8216","hashOfConfig":"8201"},{"size":1126,"mtime":1678221097291,"results":"8217","hashOfConfig":"8201"},{"size":661,"mtime":1678221097291,"results":"8218","hashOfConfig":"4558"},{"size":1493,"mtime":1678221097291,"results":"8219","hashOfConfig":"4558"},{"size":381,"mtime":1678221097291,"results":"8220","hashOfConfig":"4558"},{"size":1160,"mtime":1678221097291,"results":"8221","hashOfConfig":"4558"},{"size":2834,"mtime":1678221097291,"results":"8222","hashOfConfig":"4558"},{"size":4915,"mtime":1678221097291,"results":"8223","hashOfConfig":"4558"},{"size":1206,"mtime":1675188401674,"results":"8224","hashOfConfig":"4558"},{"size":667,"mtime":1678221097291,"results":"8225","hashOfConfig":"4558"},{"size":980,"mtime":1675188401674,"results":"8226","hashOfConfig":"4558"},{"size":60,"mtime":1675188401674,"results":"8227","hashOfConfig":"4558"},{"size":1866,"mtime":1675188401675,"results":"8228","hashOfConfig":"4558"},{"size":2831,"mtime":1675188401675,"results":"8229","hashOfConfig":"4558"},{"size":18,"mtime":1678221097292,"results":"8230","hashOfConfig":"4558"},{"size":2466,"mtime":1678221097292,"results":"8231","hashOfConfig":"4558"},{"size":110,"mtime":1678221097292,"results":"8232","hashOfConfig":"4558"},{"size":797,"mtime":1675188401675,"results":"8233","hashOfConfig":"4558"},{"size":1889,"mtime":1678221097292,"results":"8234","hashOfConfig":"4558"},{"size":2752,"mtime":1678221097292,"results":"8235","hashOfConfig":"4558"},{"size":4957,"mtime":1675188401675,"results":"8236","hashOfConfig":"4558"},{"size":2432,"mtime":1678221097292,"results":"8237","hashOfConfig":"4558"},{"size":493,"mtime":1678221097292,"results":"8238","hashOfConfig":"4558"},{"size":1127,"mtime":1678221097292,"results":"8239","hashOfConfig":"4558"},{"size":386,"mtime":1678282296178,"results":"8240","hashOfConfig":"4558"},{"size":266,"mtime":1678221097292,"results":"8241","hashOfConfig":"4558"},{"size":35666,"mtime":1678221097292,"results":"8242","hashOfConfig":"4558"},{"size":7825,"mtime":1678221097293,"results":"8243","hashOfConfig":"4558"},{"size":6904,"mtime":1678282296178,"results":"8244","hashOfConfig":"4558"},{"size":3142,"mtime":1678221097293,"results":"8245","hashOfConfig":"4558"},{"size":96,"mtime":1678221097293,"results":"8246","hashOfConfig":"4558"},{"size":1190,"mtime":1678221097293,"results":"8247","hashOfConfig":"4558"},{"size":3107,"mtime":1678221097293,"results":"8248","hashOfConfig":"4558"},{"size":8160,"mtime":1678321762662,"results":"8249","hashOfConfig":"4558"},{"size":171,"mtime":1678321762662,"results":"8250","hashOfConfig":"4558"},{"size":1725,"mtime":1678221097293,"results":"8251","hashOfConfig":"4558"},{"size":2984,"mtime":1678221097293,"results":"8252","hashOfConfig":"4558"},{"size":2008,"mtime":1678221097293,"results":"8253","hashOfConfig":"4558"},{"size":1511,"mtime":1678221097293,"results":"8254","hashOfConfig":"4558"},{"size":325,"mtime":1678221097294,"results":"8255","hashOfConfig":"4558"},{"size":1225,"mtime":1678221097294,"results":"8256","hashOfConfig":"4558"},{"size":80,"mtime":1675188401675,"results":"8257","hashOfConfig":"4558"},{"size":3404,"mtime":1675188401675,"results":"8258","hashOfConfig":"4558"},{"size":3176,"mtime":1678221097294,"results":"8259","hashOfConfig":"4558"},{"size":3196,"mtime":1678221097294,"results":"8260","hashOfConfig":"4558"},{"size":1692,"mtime":1678221097294,"results":"8261","hashOfConfig":"4558"},{"size":675,"mtime":1678221097294,"results":"8262","hashOfConfig":"4558"},{"size":1835,"mtime":1678221097294,"results":"8263","hashOfConfig":"4558"},{"size":161,"mtime":1678221097294,"results":"8264","hashOfConfig":"4558"},{"size":4986,"mtime":1678221097294,"results":"8265","hashOfConfig":"4558"},{"size":643,"mtime":1678221097294,"results":"8266","hashOfConfig":"4558"},{"size":64,"mtime":1678221097295,"results":"8267","hashOfConfig":"4558"},{"size":3883,"mtime":1678221097295,"results":"8268","hashOfConfig":"4558"},{"size":1493,"mtime":1675188401676,"results":"8269","hashOfConfig":"4558"},{"size":1574,"mtime":1675188401676,"results":"8270","hashOfConfig":"4558"},{"size":1563,"mtime":1675188401676,"results":"8271","hashOfConfig":"4558"},{"size":4698,"mtime":1675188401676,"results":"8272","hashOfConfig":"4558"},{"size":1312,"mtime":1675188401676,"results":"8273","hashOfConfig":"4558"},{"size":4436,"mtime":1675188401676,"results":"8274","hashOfConfig":"4558"},{"size":19342,"mtime":1678221097295,"results":"8275","hashOfConfig":"4558"},{"size":4950,"mtime":1675188401676,"results":"8276","hashOfConfig":"4558"},{"size":1793,"mtime":1675188401676,"results":"8277","hashOfConfig":"4558"},{"size":454,"mtime":1675188401676,"results":"8278","hashOfConfig":"4558"},{"size":213,"mtime":1675188401676,"results":"8279","hashOfConfig":"4558"},{"size":1262,"mtime":1675188401676,"results":"8280","hashOfConfig":"4558"},{"size":794,"mtime":1675188401677,"results":"8281","hashOfConfig":"4558"},{"size":3834,"mtime":1678221097295,"results":"8282","hashOfConfig":"4558"},{"size":2518,"mtime":1678221097295,"results":"8283","hashOfConfig":"4558"},{"size":3833,"mtime":1678221097295,"results":"8284","hashOfConfig":"4558"},{"size":1255,"mtime":1678221097295,"results":"8285","hashOfConfig":"4558"},{"size":1799,"mtime":1678221097295,"results":"8286","hashOfConfig":"4558"},{"size":2648,"mtime":1678221097296,"results":"8287","hashOfConfig":"4558"},{"size":4113,"mtime":1678221097296,"results":"8288","hashOfConfig":"4558"},{"size":542,"mtime":1678221097296,"results":"8289","hashOfConfig":"4558"},{"size":2126,"mtime":1678221097296,"results":"8290","hashOfConfig":"4558"},{"size":1261,"mtime":1678221097296,"results":"8291","hashOfConfig":"4558"},{"size":232,"mtime":1675188401677,"results":"8292","hashOfConfig":"4558"},{"size":246,"mtime":1678221097296,"results":"8293","hashOfConfig":"4558"},{"size":240,"mtime":1678221097296,"results":"8294","hashOfConfig":"4558"},{"size":240,"mtime":1675188401677,"results":"8295","hashOfConfig":"4558"},{"size":232,"mtime":1676322465696,"results":"8296","hashOfConfig":"4558"},{"size":220,"mtime":1675188401677,"results":"8297","hashOfConfig":"4558"},{"size":224,"mtime":1675188401677,"results":"8298","hashOfConfig":"4558"},{"size":256,"mtime":1675188401677,"results":"8299","hashOfConfig":"4558"},{"size":269,"mtime":1678221097296,"results":"8300","hashOfConfig":"4558"},{"size":224,"mtime":1678221097296,"results":"8301","hashOfConfig":"4558"},{"size":474,"mtime":1675188401677,"results":"8302","hashOfConfig":"4558"},{"size":660,"mtime":1678221097296,"results":"8303","hashOfConfig":"4558"},{"size":2600,"mtime":1678221097296,"results":"8304","hashOfConfig":"4558"},{"size":1776,"mtime":1678221097297,"results":"8305","hashOfConfig":"4558"},{"size":10142,"mtime":1678221097297,"results":"8306","hashOfConfig":"4558"},{"size":380,"mtime":1675188401678,"results":"8307","hashOfConfig":"4558"},{"size":734,"mtime":1675188401678,"results":"8308","hashOfConfig":"4558"},{"size":425,"mtime":1675188401678,"results":"8309","hashOfConfig":"4558"},{"size":769,"mtime":1678221097297,"results":"8310","hashOfConfig":"4558"},{"size":1719,"mtime":1678221097297,"results":"8311","hashOfConfig":"4558"},{"size":579,"mtime":1678221097297,"results":"8312","hashOfConfig":"4558"},{"size":581,"mtime":1678221097297,"results":"8313","hashOfConfig":"4558"},{"size":495,"mtime":1678221097297,"results":"8314","hashOfConfig":"4558"},{"size":124,"mtime":1678221097297,"results":"8315","hashOfConfig":"4558"},{"size":121,"mtime":1675188401678,"results":"8316","hashOfConfig":"4558"},{"size":104,"mtime":1678221097297,"results":"8317","hashOfConfig":"4558"},{"size":74,"mtime":1678221097297,"results":"8318","hashOfConfig":"4558"},{"size":164,"mtime":1678221097298,"results":"8319","hashOfConfig":"4558"},{"size":6712,"mtime":1675188401680,"results":"8320","hashOfConfig":"4558"},{"size":163,"mtime":1678221097298,"results":"8321","hashOfConfig":"4558"},{"size":1394,"mtime":1675188401680,"results":"8322","hashOfConfig":"4558"},{"size":646,"mtime":1675188401680,"results":"8323","hashOfConfig":"4558"},{"size":63,"mtime":1675188401680,"results":"8324","hashOfConfig":"4558"},{"size":6562,"mtime":1675188401680,"results":"8325","hashOfConfig":"4558"},{"size":4775,"mtime":1675188401680,"results":"8326","hashOfConfig":"4558"},{"size":780,"mtime":1675188401680,"results":"8327","hashOfConfig":"4558"},{"size":286,"mtime":1678221097298,"results":"8328","hashOfConfig":"4558"},{"size":4191,"mtime":1678221097298,"results":"8329","hashOfConfig":"4558"},{"size":491,"mtime":1675188401681,"results":"8330","hashOfConfig":"4558"},{"size":615,"mtime":1675188401681,"results":"8331","hashOfConfig":"4558"},{"size":512,"mtime":1678321762662,"results":"8332","hashOfConfig":"4558"},{"size":1191,"mtime":1678221097298,"results":"8333","hashOfConfig":"4558"},{"size":3457,"mtime":1675188401681,"results":"8334","hashOfConfig":"4558"},{"size":907,"mtime":1678221097299,"results":"8335","hashOfConfig":"4558"},{"size":468,"mtime":1675188401681,"results":"8336","hashOfConfig":"4558"},{"size":14534,"mtime":1678221097299,"results":"8337","hashOfConfig":"4558"},{"size":38162,"mtime":1678221097299,"results":"8338","hashOfConfig":"4558"},{"size":19470,"mtime":1678221097300,"results":"8339","hashOfConfig":"4558"},{"size":1725,"mtime":1678221097300,"results":"8340","hashOfConfig":"4558"},{"size":8723,"mtime":1678221097300,"results":"8341","hashOfConfig":"4558"},{"size":17168,"mtime":1678221097300,"results":"8342","hashOfConfig":"4558"},{"size":3233,"mtime":1678221097301,"results":"8343","hashOfConfig":"4558"},{"size":1459,"mtime":1675188401683,"results":"8344","hashOfConfig":"4558"},{"size":78,"mtime":1675188401683,"results":"8345","hashOfConfig":"4558"},{"size":1202,"mtime":1675188401684,"results":"8346","hashOfConfig":"4558"},{"size":1148,"mtime":1675188401684,"results":"8347","hashOfConfig":"4558"},{"size":24,"mtime":1675188401684,"results":"8348","hashOfConfig":"4558"},{"size":46,"mtime":1678221097301,"results":"8349","hashOfConfig":"4558"},{"size":1289,"mtime":1675188401684,"results":"8350","hashOfConfig":"4558"},{"size":15149,"mtime":1678221097301,"results":"8351","hashOfConfig":"4558"},{"size":628,"mtime":1675188401684,"results":"8352","hashOfConfig":"4558"},{"size":462,"mtime":1675188401684,"results":"8353","hashOfConfig":"4558"},{"size":377,"mtime":1675188401684,"results":"8354","hashOfConfig":"4558"},{"size":193,"mtime":1675188401684,"results":"8355","hashOfConfig":"4558"},{"size":242,"mtime":1675188401684,"results":"8356","hashOfConfig":"4558"},{"size":93,"mtime":1675188401684,"results":"8357","hashOfConfig":"4558"},{"size":1277,"mtime":1675188401684,"results":"8358","hashOfConfig":"4558"},{"size":517,"mtime":1675188401684,"results":"8359","hashOfConfig":"4558"},{"size":1197,"mtime":1675188401685,"results":"8360","hashOfConfig":"4558"},{"size":169,"mtime":1675188401685,"results":"8361","hashOfConfig":"4558"},{"size":472,"mtime":1678221097301,"results":"8362","hashOfConfig":"4558"},{"size":5444,"mtime":1675188401685,"results":"8363","hashOfConfig":"4558"},{"size":301,"mtime":1675188401685,"results":"8364","hashOfConfig":"4558"},{"size":566,"mtime":1675188401685,"results":"8365","hashOfConfig":"4558"},{"size":291,"mtime":1675188401685,"results":"8366","hashOfConfig":"4558"},{"size":326,"mtime":1675188401685,"results":"8367","hashOfConfig":"4558"},{"size":626,"mtime":1675188401685,"results":"8368","hashOfConfig":"4558"},{"size":478,"mtime":1675188401685,"results":"8369","hashOfConfig":"4558"},{"size":470,"mtime":1675188401685,"results":"8370","hashOfConfig":"4558"},{"size":288,"mtime":1675188401685,"results":"8371","hashOfConfig":"4558"},{"size":646,"mtime":1675188401685,"results":"8372","hashOfConfig":"4558"},{"size":1067,"mtime":1675188401685,"results":"8373","hashOfConfig":"4558"},{"size":167,"mtime":1675188401685,"results":"8374","hashOfConfig":"4558"},{"size":1221,"mtime":1678282296178,"results":"8375","hashOfConfig":"4558"},{"size":168,"mtime":1675188401686,"results":"8376","hashOfConfig":"4558"},{"size":134,"mtime":1675188401686,"results":"8377","hashOfConfig":"4558"},{"size":758,"mtime":1675188401686,"results":"8378","hashOfConfig":"4558"},{"size":275,"mtime":1678221097301,"results":"8379","hashOfConfig":"4558"},{"size":2025,"mtime":1675188401686,"results":"8380","hashOfConfig":"4558"},{"size":122,"mtime":1675188401686,"results":"8381","hashOfConfig":"4558"},{"size":101,"mtime":1675188401686,"results":"8382","hashOfConfig":"4558"},{"size":125,"mtime":1675188401686,"results":"8383","hashOfConfig":"4558"},{"size":210,"mtime":1675188401686,"results":"8384","hashOfConfig":"4558"},{"size":212,"mtime":1675188401686,"results":"8385","hashOfConfig":"4558"},{"size":1906,"mtime":1675188401686,"results":"8386","hashOfConfig":"4558"},{"size":682,"mtime":1678221097301,"results":"8387","hashOfConfig":"4558"},{"size":220,"mtime":1676418804568,"results":"8388","hashOfConfig":"4558"},{"size":478,"mtime":1675188401686,"results":"8389","hashOfConfig":"4558"},{"size":3863,"mtime":1678221097301,"results":"8390","hashOfConfig":"4558"},{"size":178,"mtime":1675188401686,"results":"8391","hashOfConfig":"4558"},{"size":841,"mtime":1675188401687,"results":"8392","hashOfConfig":"8393"},{"size":384,"mtime":1675188401687,"results":"8394","hashOfConfig":"8393"},{"size":820,"mtime":1675188401687,"results":"8395","hashOfConfig":"8393"},{"size":2204,"mtime":1675188401687,"results":"8396","hashOfConfig":"8393"},{"size":3918,"mtime":1675188401687,"results":"8397","hashOfConfig":"8393"},{"size":599,"mtime":1675188401687,"results":"8398","hashOfConfig":"8393"},{"size":1792,"mtime":1675188401688,"results":"8399","hashOfConfig":"8393"},{"size":3684,"mtime":1675188401688,"results":"8400","hashOfConfig":"8393"},{"size":5684,"mtime":1675188401688,"results":"8401","hashOfConfig":"8393"},{"size":9240,"mtime":1675188401688,"results":"8402","hashOfConfig":"8393"},{"size":4185,"mtime":1675188401688,"results":"8403","hashOfConfig":"8393"},{"size":11672,"mtime":1675188401688,"results":"8404","hashOfConfig":"8393"},{"size":2930,"mtime":1675188401688,"results":"8405","hashOfConfig":"8393"},{"size":16986,"mtime":1675188401688,"results":"8406","hashOfConfig":"8393"},{"size":1310,"mtime":1675188401688,"results":"8407","hashOfConfig":"8393"},{"size":13408,"mtime":1675188401688,"results":"8408","hashOfConfig":"8393"},{"size":6109,"mtime":1675188401689,"results":"8409","hashOfConfig":"8393"},{"size":327,"mtime":1675188401689,"results":"8410","hashOfConfig":"8393"},{"size":224,"mtime":1675188401689,"results":"8411","hashOfConfig":"8393"},{"size":1024,"mtime":1675188401745,"results":"8412","hashOfConfig":"8413"},{"size":381,"mtime":1675188401745,"results":"8414","hashOfConfig":"8393"},{"size":737,"mtime":1675188401745,"results":"8415","hashOfConfig":"8393"},{"size":235,"mtime":1675188401746,"results":"8416","hashOfConfig":"8393"},{"size":1877,"mtime":1678221097425,"results":"8417","hashOfConfig":"8393"},{"size":4071,"mtime":1678221097425,"results":"8418","hashOfConfig":"8393"},{"size":306,"mtime":1675188401746,"results":"8419","hashOfConfig":"8393"},{"size":312,"mtime":1675188401746,"results":"8420","hashOfConfig":"8393"},{"size":1851,"mtime":1675188401746,"results":"8421","hashOfConfig":"8393"},{"size":659,"mtime":1678221097425,"results":"8422","hashOfConfig":"4558"},{"size":1102,"mtime":1678221097425,"results":"8423","hashOfConfig":"4558"},{"size":1697,"mtime":1675188401794,"results":"8424","hashOfConfig":"4558"},{"size":1395,"mtime":1678221097459,"results":"8425","hashOfConfig":"4558"},{"size":2901,"mtime":1675188401794,"results":"8426","hashOfConfig":"4558"},{"size":503,"mtime":1678221097459,"results":"8427","hashOfConfig":"4558"},{"size":250,"mtime":1675188401794,"results":"8428","hashOfConfig":"4558"},{"size":1394,"mtime":1675188401794,"results":"8429","hashOfConfig":"4558"},{"size":1155,"mtime":1678221097459,"results":"8430","hashOfConfig":"4558"},{"size":1040,"mtime":1678221097459,"results":"8431","hashOfConfig":"4558"},{"size":5804,"mtime":1677854429203,"results":"8432","hashOfConfig":"4558"},{"size":1381,"mtime":1675188401795,"results":"8433","hashOfConfig":"4558"},{"size":1242,"mtime":1675188401795,"results":"8434","hashOfConfig":"4558"},{"size":811,"mtime":1678221097459,"results":"8435","hashOfConfig":"4558"},{"size":568,"mtime":1675188401795,"results":"8436","hashOfConfig":"4558"},{"size":124,"mtime":1675188401795,"results":"8437","hashOfConfig":"4558"},{"size":889,"mtime":1678221097459,"results":"8438","hashOfConfig":"4558"},{"size":5928,"mtime":1675188401795,"results":"8439","hashOfConfig":"4558"},{"size":2836,"mtime":1678221097460,"results":"8440","hashOfConfig":"4558"},{"size":7431,"mtime":1675188401795,"results":"8441","hashOfConfig":"4558"},{"size":7239,"mtime":1675188401795,"results":"8442","hashOfConfig":"4558"},{"size":64,"mtime":1675188401795,"results":"8443","hashOfConfig":"4558"},{"size":99,"mtime":1675188401796,"results":"8444","hashOfConfig":"4558"},{"size":64,"mtime":1675188401796,"results":"8445","hashOfConfig":"4558"},{"size":1360,"mtime":1678221097460,"results":"8446","hashOfConfig":"4558"},{"size":1824,"mtime":1678221097460,"results":"8447","hashOfConfig":"4558"},{"size":3530,"mtime":1678221097460,"results":"8448","hashOfConfig":"4558"},{"size":826,"mtime":1675188401796,"results":"8449","hashOfConfig":"4558"},{"size":1474,"mtime":1675188401796,"results":"8450","hashOfConfig":"4558"},{"size":522,"mtime":1678221097460,"results":"8451","hashOfConfig":"4558"},{"size":9101,"mtime":1678221097461,"results":"8452","hashOfConfig":"4558"},{"size":86,"mtime":1678221097461,"results":"8453","hashOfConfig":"4558"},{"size":802,"mtime":1678221097461,"results":"8454","hashOfConfig":"4558"},{"size":186,"mtime":1678221097461,"results":"8455","hashOfConfig":"4558"},{"size":477,"mtime":1678221097461,"results":"8456","hashOfConfig":"4558"},{"size":8200,"mtime":1678221097461,"results":"8457","hashOfConfig":"4558"},{"size":706,"mtime":1678221097461,"results":"8458","hashOfConfig":"4558"},{"size":2332,"mtime":1678221097461,"results":"8459","hashOfConfig":"4558"},{"size":2021,"mtime":1678221097461,"results":"8460","hashOfConfig":"4558"},{"size":1205,"mtime":1678221097461,"results":"8461","hashOfConfig":"4558"},{"size":270,"mtime":1675188401797,"results":"8462","hashOfConfig":"4558"},{"size":1137,"mtime":1675188401797,"results":"8463","hashOfConfig":"4558"},{"size":339,"mtime":1675188401797,"results":"8464","hashOfConfig":"4558"},{"size":460,"mtime":1675188401797,"results":"8465","hashOfConfig":"4558"},{"size":5716,"mtime":1675188401797,"results":"8466","hashOfConfig":"4558"},{"size":1289,"mtime":1675188401797,"results":"8467","hashOfConfig":"4558"},{"size":316,"mtime":1675188401797,"results":"8468","hashOfConfig":"4558"},{"size":190,"mtime":1675188401797,"results":"8469","hashOfConfig":"4558"},{"size":335,"mtime":1678221097461,"results":"8470","hashOfConfig":"4558"},{"size":21116,"mtime":1675188401797,"results":"8471","hashOfConfig":"4558"},{"size":1372,"mtime":1675188401797,"results":"8472","hashOfConfig":"4558"},{"size":348,"mtime":1675188401798,"results":"8473","hashOfConfig":"4558"},{"size":14813,"mtime":1675188401798,"results":"8474","hashOfConfig":"4558"},{"size":440,"mtime":1675188401798,"results":"8475","hashOfConfig":"4558"},{"size":2761,"mtime":1675694258896,"results":"8476","hashOfConfig":"4558"},{"size":1170,"mtime":1675694258896,"results":"8477","hashOfConfig":"4558"},{"size":168,"mtime":1675188401798,"results":"8478","hashOfConfig":"4558"},{"size":978,"mtime":1675188401798,"results":"8479","hashOfConfig":"4558"},{"size":1319,"mtime":1675188401798,"results":"8480","hashOfConfig":"4558"},{"size":1221,"mtime":1678221097461,"results":"8481","hashOfConfig":"4558"},{"size":436,"mtime":1675188401798,"results":"8482","hashOfConfig":"4558"},{"size":86,"mtime":1675188401798,"results":"8483","hashOfConfig":"4558"},{"size":559,"mtime":1675188401798,"results":"8484","hashOfConfig":"4558"},{"size":7408,"mtime":1675188401798,"results":"8485","hashOfConfig":"4558"},{"size":3212,"mtime":1675188401799,"results":"8486","hashOfConfig":"4558"},{"size":909,"mtime":1675694258897,"results":"8487","hashOfConfig":"4558"},{"size":2114,"mtime":1678221097462,"results":"8488","hashOfConfig":"4558"},{"size":891,"mtime":1678221097462,"results":"8489","hashOfConfig":"4558"},{"size":1006,"mtime":1675188401799,"results":"8490","hashOfConfig":"4558"},{"size":970,"mtime":1675188401799,"results":"8491","hashOfConfig":"4558"},{"size":915,"mtime":1678221097462,"results":"8492","hashOfConfig":"4558"},{"size":432,"mtime":1675188401799,"results":"8493","hashOfConfig":"4558"},{"size":3860,"mtime":1678221097462,"results":"8494","hashOfConfig":"4558"},{"size":269,"mtime":1675188401799,"results":"8495","hashOfConfig":"4558"},{"size":3196,"mtime":1678221097462,"results":"8496","hashOfConfig":"4558"},{"size":249,"mtime":1675188401800,"results":"8497","hashOfConfig":"4558"},{"size":161,"mtime":1675188401800,"results":"8498","hashOfConfig":"4558"},{"size":1625,"mtime":1675188401800,"results":"8499","hashOfConfig":"4558"},{"size":1762,"mtime":1678221097462,"results":"8500","hashOfConfig":"4558"},{"size":2178,"mtime":1678221097462,"results":"8501","hashOfConfig":"4558"},{"size":239,"mtime":1675188401800,"results":"8502","hashOfConfig":"4558"},{"size":843,"mtime":1675188401800,"results":"8503","hashOfConfig":"4558"},{"size":1073,"mtime":1678221097462,"results":"8504","hashOfConfig":"4558"},{"size":1670,"mtime":1675188401800,"results":"8505","hashOfConfig":"4558"},{"size":1129,"mtime":1678221097462,"results":"8506","hashOfConfig":"4558"},{"size":7188,"mtime":1678221097463,"results":"8507","hashOfConfig":"4558"},{"size":4422,"mtime":1678221097463,"results":"8508","hashOfConfig":"4558"},{"size":1704,"mtime":1675188401800,"results":"8509","hashOfConfig":"4558"},{"size":1281,"mtime":1675188401800,"results":"8510","hashOfConfig":"4558"},{"size":2811,"mtime":1678221097463,"results":"8511","hashOfConfig":"4558"},{"size":736,"mtime":1675188401801,"results":"8512","hashOfConfig":"4558"},{"size":1752,"mtime":1675188401801,"results":"8513","hashOfConfig":"4558"},{"size":2035,"mtime":1678221097463,"results":"8514","hashOfConfig":"4558"},{"size":2359,"mtime":1678221097463,"results":"8515","hashOfConfig":"4558"},{"size":2297,"mtime":1678221097463,"results":"8516","hashOfConfig":"4558"},{"size":1083,"mtime":1675188401801,"results":"8517","hashOfConfig":"4558"},{"size":7566,"mtime":1678221097463,"results":"8518","hashOfConfig":"4558"},{"size":1493,"mtime":1675188401801,"results":"8519","hashOfConfig":"4558"},{"size":2754,"mtime":1678221097463,"results":"8520","hashOfConfig":"4558"},{"size":3393,"mtime":1675188401801,"results":"8521","hashOfConfig":"4558"},{"size":445,"mtime":1675188401801,"results":"8522","hashOfConfig":"4558"},{"size":1679,"mtime":1678221097464,"results":"8523","hashOfConfig":"4558"},{"size":2130,"mtime":1678221097464,"results":"8524","hashOfConfig":"4558"},{"size":744,"mtime":1675694258898,"results":"8525","hashOfConfig":"4558"},{"size":759,"mtime":1675188401802,"results":"8526","hashOfConfig":"4558"},{"size":923,"mtime":1675188401802,"results":"8527","hashOfConfig":"4558"},{"size":790,"mtime":1675188401802,"results":"8528","hashOfConfig":"4558"},{"size":955,"mtime":1675188401802,"results":"8529","hashOfConfig":"4558"},{"size":495,"mtime":1675188401802,"results":"8530","hashOfConfig":"4558"},{"size":344,"mtime":1675188401802,"results":"8531","hashOfConfig":"4558"},{"size":1550,"mtime":1675188401802,"results":"8532","hashOfConfig":"4558"},{"size":398,"mtime":1675188401802,"results":"8533","hashOfConfig":"4558"},{"size":1007,"mtime":1675188401802,"results":"8534","hashOfConfig":"4558"},{"size":1268,"mtime":1675188401802,"results":"8535","hashOfConfig":"4558"},{"size":358,"mtime":1675188401802,"results":"8536","hashOfConfig":"4558"},{"size":649,"mtime":1678221097464,"results":"8537","hashOfConfig":"4558"},{"size":1085,"mtime":1678221097464,"results":"8538","hashOfConfig":"4558"},{"size":1493,"mtime":1678221097464,"results":"8539","hashOfConfig":"4558"},{"size":460,"mtime":1678221097464,"results":"8540","hashOfConfig":"4558"},{"size":6777,"mtime":1678282250825,"results":"8541","hashOfConfig":"4558"},{"size":2054,"mtime":1678221097464,"results":"8542","hashOfConfig":"4558"},{"size":398,"mtime":1675188401803,"results":"8543","hashOfConfig":"4558"},{"size":878,"mtime":1675694258898,"results":"8544","hashOfConfig":"4558"},{"size":1108,"mtime":1678221097464,"results":"8545","hashOfConfig":"4558"},{"size":4048,"mtime":1678221097465,"results":"8546","hashOfConfig":"4558"},{"size":2058,"mtime":1678221097465,"results":"8547","hashOfConfig":"4558"},{"size":2361,"mtime":1678221097465,"results":"8548","hashOfConfig":"4558"},{"size":2571,"mtime":1678221097465,"results":"8549","hashOfConfig":"4558"},{"size":2834,"mtime":1678221097465,"results":"8550","hashOfConfig":"4558"},{"size":1557,"mtime":1678221097465,"results":"8551","hashOfConfig":"4558"},{"size":2813,"mtime":1678221097465,"results":"8552","hashOfConfig":"4558"},{"size":1590,"mtime":1678221097465,"results":"8553","hashOfConfig":"4558"},{"size":665,"mtime":1675188401804,"results":"8554","hashOfConfig":"4558"},{"size":4184,"mtime":1678221097465,"results":"8555","hashOfConfig":"4558"},{"size":4537,"mtime":1678221097466,"results":"8556","hashOfConfig":"4558"},{"size":870,"mtime":1675694258899,"results":"8557","hashOfConfig":"4558"},{"size":795,"mtime":1675188401804,"results":"8558","hashOfConfig":"4558"},{"size":1615,"mtime":1675188401804,"results":"8559","hashOfConfig":"4558"},{"size":768,"mtime":1675188401804,"results":"8560","hashOfConfig":"4558"},{"size":1108,"mtime":1675188401804,"results":"8561","hashOfConfig":"4558"},{"size":720,"mtime":1675188401804,"results":"8562","hashOfConfig":"4558"},{"size":1984,"mtime":1678221097466,"results":"8563","hashOfConfig":"4558"},{"size":806,"mtime":1678221097466,"results":"8564","hashOfConfig":"4558"},{"size":497,"mtime":1675188401804,"results":"8565","hashOfConfig":"4558"},{"size":199,"mtime":1675188401805,"results":"8566","hashOfConfig":"4558"},{"size":191,"mtime":1675188401805,"results":"8567","hashOfConfig":"4558"},{"size":191,"mtime":1675188401805,"results":"8568","hashOfConfig":"4558"},{"size":219,"mtime":1675188401805,"results":"8569","hashOfConfig":"4558"},{"size":227,"mtime":1675188401805,"results":"8570","hashOfConfig":"4558"},{"size":211,"mtime":1675188401805,"results":"8571","hashOfConfig":"4558"},{"size":227,"mtime":1675188401805,"results":"8572","hashOfConfig":"4558"},{"size":203,"mtime":1675188401805,"results":"8573","hashOfConfig":"4558"},{"size":239,"mtime":1675188401805,"results":"8574","hashOfConfig":"4558"},{"size":277,"mtime":1675188401805,"results":"8575","hashOfConfig":"4558"},{"size":227,"mtime":1675188401805,"results":"8576","hashOfConfig":"4558"},{"size":219,"mtime":1675188401805,"results":"8577","hashOfConfig":"4558"},{"size":231,"mtime":1675188401805,"results":"8578","hashOfConfig":"4558"},{"size":203,"mtime":1675188401805,"results":"8579","hashOfConfig":"4558"},{"size":219,"mtime":1675188401805,"results":"8580","hashOfConfig":"4558"},{"size":235,"mtime":1675188401805,"results":"8581","hashOfConfig":"4558"},{"size":211,"mtime":1675188401806,"results":"8582","hashOfConfig":"4558"},{"size":191,"mtime":1675188401806,"results":"8583","hashOfConfig":"4558"},{"size":247,"mtime":1675188401806,"results":"8584","hashOfConfig":"4558"},{"size":247,"mtime":1675188401806,"results":"8585","hashOfConfig":"4558"},{"size":239,"mtime":1675188401806,"results":"8586","hashOfConfig":"4558"},{"size":305,"mtime":1675188401806,"results":"8587","hashOfConfig":"4558"},{"size":329,"mtime":1675188401806,"results":"8588","hashOfConfig":"4558"},{"size":293,"mtime":1675188401806,"results":"8589","hashOfConfig":"4558"},{"size":285,"mtime":1676322465696,"results":"8590","hashOfConfig":"4558"},{"size":223,"mtime":1675188401806,"results":"8591","hashOfConfig":"4558"},{"size":227,"mtime":1675188401806,"results":"8592","hashOfConfig":"4558"},{"size":263,"mtime":1675188401806,"results":"8593","hashOfConfig":"4558"},{"size":231,"mtime":1675188401806,"results":"8594","hashOfConfig":"4558"},{"size":231,"mtime":1675188401806,"results":"8595","hashOfConfig":"4558"},{"size":211,"mtime":1678221097466,"results":"8596","hashOfConfig":"4558"},{"size":265,"mtime":1675188401806,"results":"8597","hashOfConfig":"4558"},{"size":231,"mtime":1675188401806,"results":"8598","hashOfConfig":"4558"},{"size":175,"mtime":1675188401807,"results":"8599","hashOfConfig":"4558"},{"size":191,"mtime":1675188401807,"results":"8600","hashOfConfig":"4558"},{"size":199,"mtime":1675188401807,"results":"8601","hashOfConfig":"4558"},{"size":207,"mtime":1675188401807,"results":"8602","hashOfConfig":"4558"},{"size":199,"mtime":1675188401807,"results":"8603","hashOfConfig":"4558"},{"size":277,"mtime":1675188401807,"results":"8604","hashOfConfig":"4558"},{"size":199,"mtime":1675188401807,"results":"8605","hashOfConfig":"4558"},{"size":191,"mtime":1675188401807,"results":"8606","hashOfConfig":"4558"},{"size":253,"mtime":1675188401807,"results":"8607","hashOfConfig":"4558"},{"size":253,"mtime":1675188401807,"results":"8608","hashOfConfig":"4558"},{"size":211,"mtime":1675188401807,"results":"8609","hashOfConfig":"4558"},{"size":195,"mtime":1675188401807,"results":"8610","hashOfConfig":"4558"},{"size":265,"mtime":1675188401807,"results":"8611","hashOfConfig":"4558"},{"size":215,"mtime":1675188401807,"results":"8612","hashOfConfig":"4558"},{"size":203,"mtime":1675188401807,"results":"8613","hashOfConfig":"4558"},{"size":285,"mtime":1675188401807,"results":"8614","hashOfConfig":"4558"},{"size":179,"mtime":1675188401808,"results":"8615","hashOfConfig":"4558"},{"size":203,"mtime":1675188401808,"results":"8616","hashOfConfig":"4558"},{"size":191,"mtime":1675188401808,"results":"8617","hashOfConfig":"4558"},{"size":215,"mtime":1675188401808,"results":"8618","hashOfConfig":"4558"},{"size":183,"mtime":1675188401808,"results":"8619","hashOfConfig":"4558"},{"size":215,"mtime":1675188401808,"results":"8620","hashOfConfig":"4558"},{"size":223,"mtime":1675188401808,"results":"8621","hashOfConfig":"4558"},{"size":265,"mtime":1675188401808,"results":"8622","hashOfConfig":"4558"},{"size":219,"mtime":1675188401808,"results":"8623","hashOfConfig":"4558"},{"size":4892,"mtime":1678221097466,"results":"8624","hashOfConfig":"4558"},{"size":1996,"mtime":1675188401808,"results":"8625","hashOfConfig":"4558"},{"size":1868,"mtime":1675188401808,"results":"8626","hashOfConfig":"4558"},{"size":1366,"mtime":1675188401808,"results":"8627","hashOfConfig":"4558"},{"size":11928,"mtime":1678221097466,"results":"8628","hashOfConfig":"4558"},{"size":1115,"mtime":1675188401809,"results":"8629","hashOfConfig":"4558"},{"size":1307,"mtime":1675188401809,"results":"8630","hashOfConfig":"4558"},{"size":1856,"mtime":1675188401809,"results":"8631","hashOfConfig":"4558"},{"size":566,"mtime":1675188401809,"results":"8632","hashOfConfig":"4558"},{"size":869,"mtime":1675188401809,"results":"8633","hashOfConfig":"4558"},{"size":1886,"mtime":1675188401809,"results":"8634","hashOfConfig":"4558"},{"size":1938,"mtime":1675188401809,"results":"8635","hashOfConfig":"4558"},{"size":1857,"mtime":1675188401809,"results":"8636","hashOfConfig":"4558"},{"size":1176,"mtime":1675188401809,"results":"8637","hashOfConfig":"4558"},{"size":940,"mtime":1675188401809,"results":"8638","hashOfConfig":"4558"},{"size":638,"mtime":1675188401809,"results":"8639","hashOfConfig":"4558"},{"size":993,"mtime":1675188401809,"results":"8640","hashOfConfig":"4558"},{"size":1435,"mtime":1675188401809,"results":"8641","hashOfConfig":"4558"},{"size":1147,"mtime":1675188401810,"results":"8642","hashOfConfig":"4558"},{"size":5412,"mtime":1678221097466,"results":"8643","hashOfConfig":"4558"},{"size":4401,"mtime":1675188401810,"results":"8644","hashOfConfig":"4558"},{"size":1868,"mtime":1675188401810,"results":"8645","hashOfConfig":"4558"},{"size":4405,"mtime":1678221097466,"results":"8646","hashOfConfig":"4558"},{"size":3874,"mtime":1678221097467,"results":"8647","hashOfConfig":"4558"},{"size":5594,"mtime":1678221097467,"results":"8648","hashOfConfig":"4558"},{"size":32179,"mtime":1678221097467,"results":"8649","hashOfConfig":"4558"},{"size":934,"mtime":1678221097467,"results":"8650","hashOfConfig":"4558"},{"size":9614,"mtime":1678221097467,"results":"8651","hashOfConfig":"4558"},{"size":662,"mtime":1675188401810,"results":"8652","hashOfConfig":"4558"},{"size":1395,"mtime":1675188401811,"results":"8653","hashOfConfig":"4558"},{"size":1872,"mtime":1675694258900,"results":"8654","hashOfConfig":"4558"},{"size":1598,"mtime":1678221097467,"results":"8655","hashOfConfig":"4558"},{"size":13432,"mtime":1678221097467,"results":"8656","hashOfConfig":"4558"},{"size":2051,"mtime":1675188401811,"results":"8657","hashOfConfig":"4558"},{"size":2083,"mtime":1675188401811,"results":"8658","hashOfConfig":"4558"},{"size":2627,"mtime":1675188401811,"results":"8659","hashOfConfig":"4558"},{"size":759,"mtime":1678282296180,"results":"8660","hashOfConfig":"4558"},{"size":951,"mtime":1675188401811,"results":"8661","hashOfConfig":"4558"},{"size":1378,"mtime":1675188401811,"results":"8662","hashOfConfig":"4558"},{"size":1628,"mtime":1675188401811,"results":"8663","hashOfConfig":"4558"},{"size":859,"mtime":1675188401811,"results":"8664","hashOfConfig":"4558"},{"size":752,"mtime":1675188401811,"results":"8665","hashOfConfig":"4558"},{"size":8119,"mtime":1678221097468,"results":"8666","hashOfConfig":"4558"},{"size":13640,"mtime":1678282296181,"results":"8667","hashOfConfig":"4558"},{"size":1901,"mtime":1675188401812,"results":"8668","hashOfConfig":"4558"},{"size":31954,"mtime":1678221097468,"results":"8669","hashOfConfig":"4558"},{"size":4518,"mtime":1675188401812,"results":"8670","hashOfConfig":"4558"},{"size":469,"mtime":1675188401812,"results":"8671","hashOfConfig":"4558"},{"size":629,"mtime":1675188401812,"results":"8672","hashOfConfig":"4558"},{"size":12000,"mtime":1678221097468,"results":"8673","hashOfConfig":"4558"},{"size":6082,"mtime":1675188401812,"results":"8674","hashOfConfig":"4558"},{"size":5429,"mtime":1675188401812,"results":"8675","hashOfConfig":"4558"},{"size":2808,"mtime":1675694258900,"results":"8676","hashOfConfig":"4558"},{"size":1039,"mtime":1675188401812,"results":"8677","hashOfConfig":"4558"},{"size":23871,"mtime":1678221097468,"results":"8678","hashOfConfig":"4558"},{"size":2877,"mtime":1675188401813,"results":"8679","hashOfConfig":"4558"},{"size":6253,"mtime":1678221097468,"results":"8680","hashOfConfig":"4558"},{"size":4539,"mtime":1678221097469,"results":"8681","hashOfConfig":"4558"},{"size":1380,"mtime":1675188401813,"results":"8682","hashOfConfig":"4558"},{"size":1470,"mtime":1678221097469,"results":"8683","hashOfConfig":"4558"},{"size":474,"mtime":1678221097469,"results":"8684","hashOfConfig":"4558"},{"size":1998,"mtime":1675188401813,"results":"8685","hashOfConfig":"4558"},{"size":1222,"mtime":1678221097469,"results":"8686","hashOfConfig":"4558"},{"size":1067,"mtime":1678221097469,"results":"8687","hashOfConfig":"4558"},{"size":13495,"mtime":1678282296181,"results":"8688","hashOfConfig":"4558"},{"size":15982,"mtime":1678221097469,"results":"8689","hashOfConfig":"4558"},{"size":8573,"mtime":1678221097469,"results":"8690","hashOfConfig":"4558"},{"size":1842,"mtime":1678221097470,"results":"8691","hashOfConfig":"4558"},{"size":11383,"mtime":1678221097470,"results":"8692","hashOfConfig":"4558"},{"size":222,"mtime":1675188401814,"results":"8693","hashOfConfig":"4558"},{"size":1234,"mtime":1675188401814,"results":"8694","hashOfConfig":"4558"},{"size":1970,"mtime":1675188401814,"results":"8695","hashOfConfig":"4558"},{"size":2692,"mtime":1675188401814,"results":"8696","hashOfConfig":"4558"},{"size":916,"mtime":1678221097470,"results":"8697","hashOfConfig":"4558"},{"size":793,"mtime":1675188401815,"results":"8698","hashOfConfig":"4558"},{"size":250,"mtime":1675188401815,"results":"8699","hashOfConfig":"4558"},{"size":326,"mtime":1675188401815,"results":"8700","hashOfConfig":"4558"},{"size":4368,"mtime":1675188401815,"results":"8701","hashOfConfig":"4558"},{"size":167,"mtime":1675188401815,"results":"8702","hashOfConfig":"4558"},{"size":2146,"mtime":1678221097470,"results":"8703","hashOfConfig":"4558"},{"size":2074,"mtime":1675188401815,"results":"8704","hashOfConfig":"4558"},{"size":2973,"mtime":1675188401815,"results":"8705","hashOfConfig":"4558"},{"size":557,"mtime":1675694258902,"results":"8706","hashOfConfig":"4558"},{"size":900,"mtime":1675188401815,"results":"8707","hashOfConfig":"4558"},{"size":712,"mtime":1675188401815,"results":"8708","hashOfConfig":"4558"},{"size":2571,"mtime":1678221097470,"results":"8709","hashOfConfig":"4558"},{"size":863,"mtime":1678221097470,"results":"8710","hashOfConfig":"4558"},{"size":2995,"mtime":1678282296181,"results":"8711","hashOfConfig":"4558"},{"size":2951,"mtime":1678221097471,"results":"8712","hashOfConfig":"4558"},{"size":1263,"mtime":1678221097471,"results":"8713","hashOfConfig":"4558"},{"size":763,"mtime":1678221097471,"results":"8714","hashOfConfig":"4558"},{"size":5181,"mtime":1678221097471,"results":"8715","hashOfConfig":"4558"},{"size":3414,"mtime":1678221097471,"results":"8716","hashOfConfig":"4558"},{"size":255,"mtime":1675188401816,"results":"8717","hashOfConfig":"4558"},{"size":527,"mtime":1678221097472,"results":"8718","hashOfConfig":"4558"},{"size":1505,"mtime":1678221097472,"results":"8719","hashOfConfig":"4558"},{"size":2728,"mtime":1678221097472,"results":"8720","hashOfConfig":"4558"},{"size":681,"mtime":1678221097472,"results":"8721","hashOfConfig":"4558"},{"size":557,"mtime":1678221097472,"results":"8722","hashOfConfig":"4558"},{"size":8622,"mtime":1678221097473,"results":"8723","hashOfConfig":"4558"},{"size":1729,"mtime":1678221097473,"results":"8724","hashOfConfig":"4558"},{"size":1660,"mtime":1675188401817,"results":"8725","hashOfConfig":"4558"},{"size":894,"mtime":1675188401817,"results":"8726","hashOfConfig":"4558"},{"size":4819,"mtime":1678221097473,"results":"8727","hashOfConfig":"4558"},{"size":743,"mtime":1678221097473,"results":"8728","hashOfConfig":"4558"},{"size":166,"mtime":1678221097473,"results":"8729","hashOfConfig":"4558"},{"size":15053,"mtime":1678221097473,"results":"8730","hashOfConfig":"4558"},{"size":886,"mtime":1678221097474,"results":"8731","hashOfConfig":"4558"},{"size":1875,"mtime":1678221097475,"results":"8732","hashOfConfig":"4558"},{"size":417,"mtime":1675188401818,"results":"8733","hashOfConfig":"4558"},{"size":888,"mtime":1678221097475,"results":"8734","hashOfConfig":"4558"},{"size":402,"mtime":1678221097475,"results":"8735","hashOfConfig":"4558"},{"size":3339,"mtime":1678221097476,"results":"8736","hashOfConfig":"4558"},{"size":28905,"mtime":1678221097476,"results":"8737","hashOfConfig":"4558"},{"size":1436,"mtime":1678221097476,"results":"8738","hashOfConfig":"4558"},{"size":1308,"mtime":1678221097476,"results":"8739","hashOfConfig":"4558"},{"size":1514,"mtime":1678221097477,"results":"8740","hashOfConfig":"4558"},{"size":477,"mtime":1675188401818,"results":"8741","hashOfConfig":"4558"},{"size":29294,"mtime":1678221097477,"results":"8742","hashOfConfig":"4558"},{"size":2431,"mtime":1675188401819,"results":"8743","hashOfConfig":"4558"},{"size":6176,"mtime":1675188401819,"results":"8744","hashOfConfig":"4558"},{"size":328,"mtime":1675188401819,"results":"8745","hashOfConfig":"4558"},{"size":691,"mtime":1675188401819,"results":"8746","hashOfConfig":"4558"},{"size":1336,"mtime":1675188401819,"results":"8747","hashOfConfig":"4558"},{"size":6738,"mtime":1675188401819,"results":"8748","hashOfConfig":"4558"},{"size":10930,"mtime":1675188401819,"results":"8749","hashOfConfig":"4558"},{"size":1965,"mtime":1675188401819,"results":"8750","hashOfConfig":"4558"},{"size":1383,"mtime":1675188401820,"results":"8751","hashOfConfig":"4558"},{"size":14251,"mtime":1678221097477,"results":"8752","hashOfConfig":"4558"},{"size":10080,"mtime":1675188401820,"results":"8753","hashOfConfig":"4558"},{"size":1999,"mtime":1675188401820,"results":"8754","hashOfConfig":"4558"},{"size":1250,"mtime":1675188401820,"results":"8755","hashOfConfig":"4558"},{"size":8250,"mtime":1678221097477,"results":"8756","hashOfConfig":"4558"},{"size":75,"mtime":1678221097477,"results":"8757","hashOfConfig":"4558"},{"size":6022,"mtime":1675188401820,"results":"8758","hashOfConfig":"4558"},{"size":771,"mtime":1678221097478,"results":"8759","hashOfConfig":"4558"},{"size":497,"mtime":1675188401821,"results":"8760","hashOfConfig":"4558"},{"size":173,"mtime":1675188401821,"results":"8761","hashOfConfig":"4558"},{"size":752,"mtime":1675188401821,"results":"8762","hashOfConfig":"4558"},{"size":371,"mtime":1675188401821,"results":"8763","hashOfConfig":"4558"},{"size":881,"mtime":1678221097478,"results":"8764","hashOfConfig":"4558"},{"size":467,"mtime":1678221097479,"results":"8765","hashOfConfig":"4558"},{"size":6473,"mtime":1675188401821,"results":"8766","hashOfConfig":"4558"},{"size":354,"mtime":1678221097479,"results":"8767","hashOfConfig":"4558"},{"size":503,"mtime":1678221097479,"results":"8768","hashOfConfig":"4558"},{"size":566,"mtime":1675188401821,"results":"8769","hashOfConfig":"4558"},{"size":508,"mtime":1678221097479,"results":"8770","hashOfConfig":"4558"},{"size":657,"mtime":1675188401823,"results":"8771","hashOfConfig":"4558"},{"size":275,"mtime":1675188401823,"results":"8772","hashOfConfig":"4558"},{"size":247,"mtime":1675188401823,"results":"8773","hashOfConfig":"4558"},{"size":471,"mtime":1675188401823,"results":"8774","hashOfConfig":"4558"},{"size":306,"mtime":1675188401823,"results":"8775","hashOfConfig":"4558"},{"size":268,"mtime":1675188401824,"results":"8776","hashOfConfig":"4558"},{"size":391,"mtime":1675188401824,"results":"8777","hashOfConfig":"4558"},{"size":495,"mtime":1675188401824,"results":"8778","hashOfConfig":"4558"},{"size":941,"mtime":1675188401824,"results":"8779","hashOfConfig":"4558"},{"size":485,"mtime":1675188401824,"results":"8780","hashOfConfig":"4558"},{"size":908,"mtime":1675188401824,"results":"8781","hashOfConfig":"4558"},{"size":887,"mtime":1675188401824,"results":"8782","hashOfConfig":"4558"},{"size":222,"mtime":1675188401824,"results":"8783","hashOfConfig":"4558"},{"size":1771,"mtime":1675188401824,"results":"8784","hashOfConfig":"4558"},{"size":320,"mtime":1675188401824,"results":"8785","hashOfConfig":"4558"},{"size":479,"mtime":1678221097479,"results":"8786","hashOfConfig":"4558"},{"size":1134,"mtime":1678221097479,"results":"8787","hashOfConfig":"4558"},{"size":251,"mtime":1678221097479,"results":"8788","hashOfConfig":"4558"},{"size":237,"mtime":1678221097479,"results":"8789","hashOfConfig":"4558"},{"size":222,"mtime":1678221097480,"results":"8790","hashOfConfig":"4558"},{"size":1536,"mtime":1678221097480,"results":"8791","hashOfConfig":"4558"},{"size":222,"mtime":1678221097480,"results":"8792","hashOfConfig":"4558"},{"size":474,"mtime":1678221097480,"results":"8793","hashOfConfig":"4558"},{"size":2364,"mtime":1678221097480,"results":"8794","hashOfConfig":"4558"},{"size":1034,"mtime":1678221097480,"results":"8795","hashOfConfig":"4558"},{"size":942,"mtime":1678221097480,"results":"8796","hashOfConfig":"4558"},{"size":409,"mtime":1675188401824,"results":"8797","hashOfConfig":"4558"},{"size":382,"mtime":1678221097480,"results":"8798","hashOfConfig":"4558"},{"size":4095,"mtime":1678221097480,"results":"8799","hashOfConfig":"4558"},{"size":1047,"mtime":1678221097481,"results":"8800","hashOfConfig":"4558"},{"size":1782,"mtime":1675188401825,"results":"8801","hashOfConfig":"4558"},{"size":1347,"mtime":1678221097483,"results":"8802","hashOfConfig":"8803"},{"size":2616,"mtime":1678221097483,"results":"8804","hashOfConfig":"8803"},{"size":1703,"mtime":1678221097484,"results":"8805","hashOfConfig":"8803"},{"size":884,"mtime":1678221097484,"results":"8806","hashOfConfig":"8803"},{"size":5544,"mtime":1678221097484,"results":"8807","hashOfConfig":"8803"},{"size":581,"mtime":1678221097484,"results":"8808","hashOfConfig":"8803"},{"size":216,"mtime":1678221097484,"results":"8809","hashOfConfig":"8803"},{"size":159,"mtime":1678221097484,"results":"8810","hashOfConfig":"8803"},{"size":1185,"mtime":1678221097484,"results":"8811","hashOfConfig":"8803"},{"size":831,"mtime":1678221097484,"results":"8812","hashOfConfig":"8803"},{"size":1031,"mtime":1678221097485,"results":"8813","hashOfConfig":"8803"},{"size":7754,"mtime":1678221097485,"results":"8814","hashOfConfig":"8803"},{"size":1795,"mtime":1678282296181,"results":"8815","hashOfConfig":"8803"},{"size":1425,"mtime":1678221097485,"results":"8816","hashOfConfig":"8803"},{"size":2073,"mtime":1678221097485,"results":"8817","hashOfConfig":"8803"},{"size":829,"mtime":1678221097485,"results":"8818","hashOfConfig":"8803"},{"size":752,"mtime":1678221097485,"results":"8819","hashOfConfig":"8803"},{"size":2062,"mtime":1678221097490,"results":"8820","hashOfConfig":"8803"},{"size":2365,"mtime":1678221097490,"results":"8821","hashOfConfig":"8803"},{"size":3675,"mtime":1678221097490,"results":"8822","hashOfConfig":"8803"},{"size":278,"mtime":1678221097490,"results":"8823","hashOfConfig":"8803"},{"size":1274,"mtime":1678221097491,"results":"8824","hashOfConfig":"8803"},{"size":288,"mtime":1678221097491,"results":"8825","hashOfConfig":"8803"},{"size":8493,"mtime":1678221097491,"results":"8826","hashOfConfig":"8803"},{"size":470,"mtime":1678221097491,"results":"8827","hashOfConfig":"8803"},{"size":357,"mtime":1678221097491,"results":"8828","hashOfConfig":"8803"},{"size":1814,"mtime":1678221097491,"results":"8829","hashOfConfig":"8803"},{"size":1200,"mtime":1678221097491,"results":"8830","hashOfConfig":"8803"},{"size":1392,"mtime":1678221097491,"results":"8831","hashOfConfig":"8803"},{"size":3249,"mtime":1678221097491,"results":"8832","hashOfConfig":"8803"},{"size":4920,"mtime":1678221097491,"results":"8833","hashOfConfig":"8803"},{"size":3487,"mtime":1678221097491,"results":"8834","hashOfConfig":"8803"},{"size":5891,"mtime":1678221097491,"results":"8835","hashOfConfig":"8803"},{"size":3684,"mtime":1678221097492,"results":"8836","hashOfConfig":"8803"},{"size":38890,"mtime":1678221097492,"results":"8837","hashOfConfig":"8803"},{"size":56676,"mtime":1678221097492,"results":"8838","hashOfConfig":"8803"},{"size":62270,"mtime":1678221097492,"results":"8839","hashOfConfig":"8803"},{"size":68675,"mtime":1678221097492,"results":"8840","hashOfConfig":"8803"},{"size":56493,"mtime":1678221097492,"results":"8841","hashOfConfig":"8803"},{"size":56773,"mtime":1678221097493,"results":"8842","hashOfConfig":"8803"},{"size":5189,"mtime":1678221097493,"results":"8843","hashOfConfig":"8803"},{"size":659,"mtime":1678221097493,"results":"8844","hashOfConfig":"8803"},{"size":1999,"mtime":1678221097493,"results":"8845","hashOfConfig":"8803"},{"size":283,"mtime":1678221097493,"results":"8846","hashOfConfig":"8803"},{"size":399,"mtime":1678221097493,"results":"8847","hashOfConfig":"8803"},{"size":2817,"mtime":1678221097493,"results":"8848","hashOfConfig":"8803"},{"size":1583,"mtime":1678221097493,"results":"8849","hashOfConfig":"8803"},{"size":1137,"mtime":1678221097493,"results":"8850","hashOfConfig":"8803"},{"size":382,"mtime":1678221097494,"results":"8851","hashOfConfig":"8803"},{"size":1539,"mtime":1678221097494,"results":"8852","hashOfConfig":"8803"},{"size":680,"mtime":1678221097494,"results":"8853","hashOfConfig":"8803"},{"size":2271,"mtime":1678221097494,"results":"8854","hashOfConfig":"8803"},{"size":1430,"mtime":1678221097494,"results":"8855","hashOfConfig":"8803"},{"size":9121,"mtime":1678221097494,"results":"8856","hashOfConfig":"8803"},{"size":1399,"mtime":1678221097494,"results":"8857","hashOfConfig":"8803"},{"size":770,"mtime":1678221097494,"results":"8858","hashOfConfig":"8803"},{"size":4710,"mtime":1678221097494,"results":"8859","hashOfConfig":"8803"},{"size":781,"mtime":1678221097495,"results":"8860","hashOfConfig":"8803"},{"size":1887,"mtime":1678221097495,"results":"8861","hashOfConfig":"8803"},{"size":1612,"mtime":1678221097495,"results":"8862","hashOfConfig":"8803"},{"size":3519,"mtime":1678221097495,"results":"8863","hashOfConfig":"8803"},{"size":2997,"mtime":1678221097495,"results":"8864","hashOfConfig":"8803"},{"size":2105,"mtime":1678221097495,"results":"8865","hashOfConfig":"8803"},{"size":4281,"mtime":1678221097495,"results":"8866","hashOfConfig":"8803"},{"size":2999,"mtime":1678221097496,"results":"8867","hashOfConfig":"8803"},{"size":2186,"mtime":1678221097496,"results":"8868","hashOfConfig":"8803"},{"size":8744,"mtime":1678221097496,"results":"8869","hashOfConfig":"8803"},{"size":2016,"mtime":1678221097496,"results":"8870","hashOfConfig":"8803"},{"size":3281,"mtime":1678221097496,"results":"8871","hashOfConfig":"8803"},{"size":1831,"mtime":1678221097496,"results":"8872","hashOfConfig":"8803"},{"size":1743,"mtime":1678221097496,"results":"8873","hashOfConfig":"8803"},{"size":8170,"mtime":1678221097496,"results":"8874","hashOfConfig":"8803"},{"size":3625,"mtime":1678221097497,"results":"8875","hashOfConfig":"8803"},{"size":1136,"mtime":1678221097497,"results":"8876","hashOfConfig":"8803"},{"size":5596,"mtime":1678221097497,"results":"8877","hashOfConfig":"8803"},{"size":2541,"mtime":1678221097497,"results":"8878","hashOfConfig":"8803"},{"size":6438,"mtime":1678221097497,"results":"8879","hashOfConfig":"8803"},{"size":3287,"mtime":1678221097497,"results":"8880","hashOfConfig":"8803"},{"size":4225,"mtime":1678221097497,"results":"8881","hashOfConfig":"8803"},{"size":2934,"mtime":1678221097497,"results":"8882","hashOfConfig":"8803"},{"size":2697,"mtime":1678221097497,"results":"8883","hashOfConfig":"8803"},{"size":1537,"mtime":1678282296182,"results":"8884","hashOfConfig":"8803"},{"size":4042,"mtime":1678221097498,"results":"8885","hashOfConfig":"8803"},{"size":1878,"mtime":1675694258911,"results":"8886","hashOfConfig":"8803"},{"size":268,"mtime":1675188401832,"results":"8887","hashOfConfig":"8803"},{"size":1179,"mtime":1675188401832,"results":"8888","hashOfConfig":"8803"},{"size":248,"mtime":1675188401832,"results":"8889","hashOfConfig":"8803"},{"size":8276,"mtime":1678221097498,"results":"8890","hashOfConfig":"8803"},{"size":476,"mtime":1678221097498,"results":"8891","hashOfConfig":"8803"},{"size":1691,"mtime":1675188401832,"results":"8892","hashOfConfig":"8803"},{"size":1190,"mtime":1675188401832,"results":"8893","hashOfConfig":"8803"},{"size":1025,"mtime":1675188401832,"results":"8894","hashOfConfig":"8803"},{"size":1713,"mtime":1678221097498,"results":"8895","hashOfConfig":"8803"},{"size":740,"mtime":1675188401832,"results":"8896","hashOfConfig":"8803"},{"size":3862,"mtime":1678221097498,"results":"8897","hashOfConfig":"8803"},{"size":227,"mtime":1675188401832,"results":"8898","hashOfConfig":"8803"},{"size":370,"mtime":1675188401833,"results":"8899","hashOfConfig":"8803"},{"size":975,"mtime":1678221097498,"results":"8900","hashOfConfig":"8803"},{"size":659,"mtime":1675188401833,"results":"8901","hashOfConfig":"8803"},{"size":900,"mtime":1675188401833,"results":"8902","hashOfConfig":"8803"},{"size":1280,"mtime":1678221097498,"results":"8903","hashOfConfig":"8803"},{"size":924,"mtime":1678221097498,"results":"8904","hashOfConfig":"8803"},{"size":530,"mtime":1675188401833,"results":"8905","hashOfConfig":"8803"},{"size":1266,"mtime":1675188401833,"results":"8906","hashOfConfig":"8803"},{"size":909,"mtime":1675188401833,"results":"8907","hashOfConfig":"8803"},{"size":2679,"mtime":1675188401833,"results":"8908","hashOfConfig":"8803"},{"size":1224,"mtime":1675188401833,"results":"8909","hashOfConfig":"8803"},{"size":3423,"mtime":1678221097499,"results":"8910","hashOfConfig":"8803"},{"size":367,"mtime":1675188401833,"results":"8911","hashOfConfig":"8803"},{"size":1618,"mtime":1678221097499,"results":"8912","hashOfConfig":"8803"},{"size":1009,"mtime":1675188401833,"results":"8913","hashOfConfig":"8803"},{"size":1042,"mtime":1678221097499,"results":"8914","hashOfConfig":"8803"},{"size":1607,"mtime":1678221097499,"results":"8915","hashOfConfig":"8803"},{"size":573,"mtime":1675188401834,"results":"8916","hashOfConfig":"8803"},{"size":1867,"mtime":1678221097499,"results":"8917","hashOfConfig":"8803"},{"size":3184,"mtime":1678221097499,"results":"8918","hashOfConfig":"8803"},{"size":546,"mtime":1678221097499,"results":"8919","hashOfConfig":"8803"},{"size":7117,"mtime":1678221097499,"results":"8920","hashOfConfig":"8803"},{"size":7402,"mtime":1678221097499,"results":"8921","hashOfConfig":"8803"},{"size":3895,"mtime":1678221097499,"results":"8922","hashOfConfig":"8803"},{"size":2583,"mtime":1678221097500,"results":"8923","hashOfConfig":"8803"},{"size":2784,"mtime":1678221097500,"results":"8924","hashOfConfig":"8803"},{"size":2546,"mtime":1678221097500,"results":"8925","hashOfConfig":"8803"},{"size":3478,"mtime":1678221097500,"results":"8926","hashOfConfig":"8803"},{"size":658,"mtime":1678221097500,"results":"8927","hashOfConfig":"8803"},{"size":855,"mtime":1678221097500,"results":"8928","hashOfConfig":"8803"},{"size":41,"mtime":1675188401834,"results":"8929","hashOfConfig":"8803"},{"size":628,"mtime":1678221097500,"results":"8930","hashOfConfig":"8803"},{"size":872,"mtime":1678221097500,"results":"8931","hashOfConfig":"8803"},{"size":261,"mtime":1678221097501,"results":"8932","hashOfConfig":"8803"},{"size":4436,"mtime":1678221097501,"results":"8933","hashOfConfig":"8803"},{"size":1225,"mtime":1678221097501,"results":"8934","hashOfConfig":"8803"},{"size":3696,"mtime":1678221097501,"results":"8935","hashOfConfig":"8803"},{"size":9874,"mtime":1675188401835,"results":"8936","hashOfConfig":"8937"},{"size":22465,"mtime":1678221097501,"results":"8938","hashOfConfig":"8937"},{"size":111836,"mtime":1678326700561,"results":"8939","hashOfConfig":"8937"},{"size":61679,"mtime":1678221097502,"results":"8940","hashOfConfig":"8937"},{"size":48554,"mtime":1675694258913,"results":"8941","hashOfConfig":"8937"},{"size":25417,"mtime":1675694258913,"results":"8942","hashOfConfig":"8937"},{"size":88290,"mtime":1678221097502,"results":"8943","hashOfConfig":"8937"},{"size":18655,"mtime":1675188401836,"results":"8944","hashOfConfig":"8937"},{"size":17314,"mtime":1675188401836,"results":"8945","hashOfConfig":"8937"},{"size":3212,"mtime":1675188401836,"results":"8946","hashOfConfig":"8937"},{"size":46877,"mtime":1678326770970,"results":"8947","hashOfConfig":"8937"},{"size":10458,"mtime":1675694258914,"results":"8948","hashOfConfig":"8937"},{"size":3736,"mtime":1675188401836,"results":"8949","hashOfConfig":"8937"},{"size":10357,"mtime":1675188401837,"results":"8950","hashOfConfig":"8937"},{"size":2153,"mtime":1675188401837,"results":"8951","hashOfConfig":"8937"},{"size":7116,"mtime":1675188401837,"results":"8952","hashOfConfig":"8937"},{"size":1178,"mtime":1675188401837,"results":"8953","hashOfConfig":"8937"},{"size":1211,"mtime":1675188401837,"results":"8954","hashOfConfig":"8937"},{"size":1352,"mtime":1675188401837,"results":"8955","hashOfConfig":"8937"},{"size":4835,"mtime":1678221097503,"results":"8956","hashOfConfig":"8937"},{"size":3413,"mtime":1678221097503,"results":"8957","hashOfConfig":"8937"},{"size":3831,"mtime":1678221097503,"results":"8958","hashOfConfig":"8937"},{"size":3103,"mtime":1675188401837,"results":"8959","hashOfConfig":"8937"},{"size":4846,"mtime":1675188401837,"results":"8960","hashOfConfig":"8937"},{"size":6041,"mtime":1675188401838,"results":"8961","hashOfConfig":"8937"},{"size":59996,"mtime":1678221097503,"results":"8962","hashOfConfig":"8937"},{"size":52805,"mtime":1678221097503,"results":"8963","hashOfConfig":"8937"},{"size":1463,"mtime":1675188401838,"results":"8964","hashOfConfig":"8937"},{"size":4092,"mtime":1678221097503,"results":"8965","hashOfConfig":"8937"},{"size":4409,"mtime":1678221097504,"results":"8966","hashOfConfig":"8937"},{"size":3401,"mtime":1675188401838,"results":"8967","hashOfConfig":"8937"},{"size":66643,"mtime":1678221097504,"results":"8968","hashOfConfig":"8937"},{"size":19055,"mtime":1678221097504,"results":"8969","hashOfConfig":"8937"},{"size":1267,"mtime":1675188401838,"results":"8970","hashOfConfig":"8937"},{"size":7166,"mtime":1678221097504,"results":"8971","hashOfConfig":"8937"},{"size":11791,"mtime":1675188401839,"results":"8972","hashOfConfig":"8937"},{"size":7184,"mtime":1675188401839,"results":"8973","hashOfConfig":"8937"},{"size":5794,"mtime":1675694258915,"results":"8974","hashOfConfig":"8937"},{"size":2062,"mtime":1675188401839,"results":"8975","hashOfConfig":"8937"},{"size":3610,"mtime":1675188401839,"results":"8976","hashOfConfig":"8937"},{"size":34489,"mtime":1678221097504,"results":"8977","hashOfConfig":"8937"},{"size":25099,"mtime":1678221097505,"results":"8978","hashOfConfig":"8937"},{"size":7784,"mtime":1678221097505,"results":"8979","hashOfConfig":"8937"},{"size":11561,"mtime":1678221097505,"results":"8980","hashOfConfig":"8937"},{"size":2906,"mtime":1675694258915,"results":"8981","hashOfConfig":"8937"},{"size":31562,"mtime":1678221097505,"results":"8982","hashOfConfig":"8937"},{"size":2934,"mtime":1675188401839,"results":"8983","hashOfConfig":"8937"},{"size":10872,"mtime":1678221097505,"results":"8984","hashOfConfig":"8937"},{"size":7801,"mtime":1675188401840,"results":"8985","hashOfConfig":"8937"},{"size":5331,"mtime":1678221097505,"results":"8986","hashOfConfig":"8937"},{"size":31451,"mtime":1678221097505,"results":"8987","hashOfConfig":"8937"},{"size":3703,"mtime":1678221097506,"results":"8988","hashOfConfig":"8937"},{"size":5867,"mtime":1675188401840,"results":"8989","hashOfConfig":"8937"},{"size":8179,"mtime":1675188401840,"results":"8990","hashOfConfig":"8937"},{"size":3753,"mtime":1678221097506,"results":"8991","hashOfConfig":"8937"},{"size":3533,"mtime":1675188401840,"results":"8992","hashOfConfig":"8937"},{"size":4843,"mtime":1675188401840,"results":"8993","hashOfConfig":"8937"},{"size":2104,"mtime":1675188401840,"results":"8994","hashOfConfig":"8937"},{"size":1342,"mtime":1675188401840,"results":"8995","hashOfConfig":"8937"},{"size":13563,"mtime":1678221097506,"results":"8996","hashOfConfig":"8937"},{"size":1337,"mtime":1675188401841,"results":"8997","hashOfConfig":"8937"},{"size":484,"mtime":1675188401841,"results":"8998","hashOfConfig":"8937"},{"size":608,"mtime":1678221097506,"results":"8999","hashOfConfig":"8937"},{"size":1193,"mtime":1678221097506,"results":"9000","hashOfConfig":"8937"},{"size":564,"mtime":1678221097506,"results":"9001","hashOfConfig":"8937"},{"size":2356,"mtime":1678221097506,"results":"9002","hashOfConfig":"8937"},{"size":534,"mtime":1675188401841,"results":"9003","hashOfConfig":"8937"},{"size":271,"mtime":1675188401841,"results":"9004","hashOfConfig":"8937"},{"size":2924,"mtime":1678221097506,"results":"9005","hashOfConfig":"8937"},{"size":184,"mtime":1675188401841,"results":"9006","hashOfConfig":"8937"},{"size":273,"mtime":1675188401841,"results":"9007","hashOfConfig":"8937"},{"size":726,"mtime":1675188401841,"results":"9008","hashOfConfig":"8937"},{"size":632,"mtime":1675188401841,"results":"9009","hashOfConfig":"8937"},{"size":154,"mtime":1675188401841,"results":"9010","hashOfConfig":"8937"},{"size":4360,"mtime":1675188401842,"results":"9011","hashOfConfig":"8937"},{"size":4041,"mtime":1675188401842,"results":"9012","hashOfConfig":"8937"},{"size":6066,"mtime":1675188401842,"results":"9013","hashOfConfig":"8937"},{"size":5631,"mtime":1675188401842,"results":"9014","hashOfConfig":"8937"},{"size":77,"mtime":1675188401842,"results":"9015","hashOfConfig":"8937"},{"size":806,"mtime":1675188401842,"results":"9016","hashOfConfig":"8937"},{"size":2940,"mtime":1675188401842,"results":"9017","hashOfConfig":"8937"},{"size":878,"mtime":1675188401842,"results":"9018","hashOfConfig":"8937"},{"size":253,"mtime":1675188401842,"results":"9019","hashOfConfig":"8937"},{"size":2024,"mtime":1675188401843,"results":"9020","hashOfConfig":"8937"},{"size":3739,"mtime":1675188401843,"results":"9021","hashOfConfig":"8937"},{"size":6059,"mtime":1678221097507,"results":"9022","hashOfConfig":"8937"},{"size":5029,"mtime":1678221097507,"results":"9023","hashOfConfig":"8937"},{"size":65254,"mtime":1678221097507,"results":"9024","hashOfConfig":"8937"},{"size":6362,"mtime":1678221097507,"results":"9025","hashOfConfig":"8937"},{"size":8586,"mtime":1675188401843,"results":"9026","hashOfConfig":"8937"},{"size":11204,"mtime":1675188401843,"results":"9027","hashOfConfig":"8937"},{"size":8242,"mtime":1675188401843,"results":"9028","hashOfConfig":"8937"},{"size":49533,"mtime":1678221097507,"results":"9029","hashOfConfig":"8937"},{"size":11933,"mtime":1675694258916,"results":"9030","hashOfConfig":"8937"},{"size":19782,"mtime":1678221097508,"results":"9031","hashOfConfig":"8937"},{"size":7947,"mtime":1675694258916,"results":"9032","hashOfConfig":"8937"},{"size":1769,"mtime":1675188401844,"results":"9033","hashOfConfig":"8937"},{"size":39198,"mtime":1678221097508,"results":"9034","hashOfConfig":"8937"},{"size":34183,"mtime":1678221097508,"results":"9035","hashOfConfig":"8937"},{"size":1078,"mtime":1678221097508,"results":"9036","hashOfConfig":"8937"},{"size":1265,"mtime":1675188401844,"results":"9037","hashOfConfig":"8937"},{"size":874,"mtime":1675188401845,"results":"9038","hashOfConfig":"8937"},{"size":2243,"mtime":1678221097508,"results":"9039","hashOfConfig":"8937"},{"size":1136,"mtime":1675188401845,"results":"9040","hashOfConfig":"8937"},{"size":57820,"mtime":1678221097508,"results":"9041","hashOfConfig":"8937"},{"size":4846,"mtime":1678221097509,"results":"9042","hashOfConfig":"8937"},{"size":23418,"mtime":1678221097509,"results":"9043","hashOfConfig":"8937"},{"size":3281,"mtime":1678221097509,"results":"9044","hashOfConfig":"8937"},{"size":810,"mtime":1675188401845,"results":"9045","hashOfConfig":"8937"},{"size":1961,"mtime":1675188401845,"results":"9046","hashOfConfig":"8937"},{"size":9574,"mtime":1675188401845,"results":"9047","hashOfConfig":"8937"},{"size":2490,"mtime":1675188401846,"results":"9048","hashOfConfig":"8937"},{"size":666,"mtime":1678221097509,"results":"9049","hashOfConfig":"8937"},{"size":20349,"mtime":1675188401846,"results":"9050","hashOfConfig":"8937"},{"size":12624,"mtime":1675188401846,"results":"9051","hashOfConfig":"8937"},{"size":7154,"mtime":1675188401846,"results":"9052","hashOfConfig":"8937"},{"size":47003,"mtime":1675188401846,"results":"9053","hashOfConfig":"8937"},{"size":35914,"mtime":1675188401846,"results":"9054","hashOfConfig":"8937"},{"size":34038,"mtime":1675188401847,"results":"9055","hashOfConfig":"8937"},{"size":3269,"mtime":1675188401847,"results":"9056","hashOfConfig":"8937"},{"size":1135,"mtime":1675188401847,"results":"9057","hashOfConfig":"8937"},{"size":12123,"mtime":1675188401847,"results":"9058","hashOfConfig":"8937"},{"size":1527,"mtime":1675188401847,"results":"9059","hashOfConfig":"8937"},{"size":1927,"mtime":1675188401847,"results":"9060","hashOfConfig":"8937"},{"size":1191,"mtime":1678221097509,"results":"9061","hashOfConfig":"8937"},{"size":423,"mtime":1676418804629,"results":"9062","hashOfConfig":"8937"},{"size":5405,"mtime":1678221097509,"results":"9063","hashOfConfig":"8937"},{"size":1844,"mtime":1678221097509,"results":"9064","hashOfConfig":"8937"},{"size":1366,"mtime":1675188401848,"results":"9065","hashOfConfig":"8937"},{"size":14896,"mtime":1678221097510,"results":"9066","hashOfConfig":"8937"},{"size":1581,"mtime":1675188401848,"results":"9067","hashOfConfig":"8937"},{"size":3683,"mtime":1675188401848,"results":"9068","hashOfConfig":"8937"},{"size":593,"mtime":1675188401848,"results":"9069","hashOfConfig":"8937"},{"size":708,"mtime":1675188401848,"results":"9070","hashOfConfig":"8937"},{"size":2291,"mtime":1675188401848,"results":"9071","hashOfConfig":"8937"},{"size":3219,"mtime":1675188401848,"results":"9072","hashOfConfig":"8937"},{"size":838,"mtime":1678221097511,"results":"9073","hashOfConfig":"8937"},{"size":1329,"mtime":1678221097511,"results":"9074","hashOfConfig":"8937"},{"size":1328,"mtime":1678221097511,"results":"9075","hashOfConfig":"8937"},{"size":642,"mtime":1678221097511,"results":"9076","hashOfConfig":"8937"},{"size":1054,"mtime":1678221097511,"results":"9077","hashOfConfig":"8937"},{"size":1164,"mtime":1678221097511,"results":"9078","hashOfConfig":"8937"},{"size":1426,"mtime":1675188401849,"results":"9079","hashOfConfig":"8937"},{"size":2293,"mtime":1678221097512,"results":"9080","hashOfConfig":"8937"},{"size":2563,"mtime":1678221097512,"results":"9081","hashOfConfig":"8937"},{"size":1650,"mtime":1678221097512,"results":"9082","hashOfConfig":"8937"},{"size":1228,"mtime":1678221097512,"results":"9083","hashOfConfig":"8937"},{"size":1332,"mtime":1675188401849,"results":"9084","hashOfConfig":"8937"},{"size":1521,"mtime":1675188401849,"results":"9085","hashOfConfig":"8937"},{"size":4678,"mtime":1675188401849,"results":"9086","hashOfConfig":"8937"},{"size":1480,"mtime":1675188401850,"results":"9087","hashOfConfig":"8937"},{"size":1052,"mtime":1675188401850,"results":"9088","hashOfConfig":"8937"},{"size":697,"mtime":1675188401850,"results":"9089","hashOfConfig":"8937"},{"size":6584,"mtime":1678221097512,"results":"9090","hashOfConfig":"8937"},{"size":5292,"mtime":1678221097512,"results":"9091","hashOfConfig":"8937"},{"size":4280,"mtime":1678221097512,"results":"9092","hashOfConfig":"8937"},{"size":1400,"mtime":1678221097512,"results":"9093","hashOfConfig":"8937"},{"size":1931,"mtime":1678221097512,"results":"9094","hashOfConfig":"8937"},{"size":1109,"mtime":1678221097512,"results":"9095","hashOfConfig":"8937"},{"size":1454,"mtime":1678221097512,"results":"9096","hashOfConfig":"8937"},{"size":3240,"mtime":1675188401850,"results":"9097","hashOfConfig":"8937"},{"size":1414,"mtime":1675188401850,"results":"9098","hashOfConfig":"8937"},{"size":2716,"mtime":1675188401850,"results":"9099","hashOfConfig":"8937"},{"size":2817,"mtime":1675188401850,"results":"9100","hashOfConfig":"8937"},{"size":3340,"mtime":1675188401850,"results":"9101","hashOfConfig":"8937"},{"size":1147,"mtime":1675188401850,"results":"9102","hashOfConfig":"8937"},{"size":2560,"mtime":1675188401850,"results":"9103","hashOfConfig":"8937"},{"size":4609,"mtime":1675188401850,"results":"9104","hashOfConfig":"8937"},{"size":1303,"mtime":1675188401851,"results":"9105","hashOfConfig":"8937"},{"size":1267,"mtime":1675188401851,"results":"9106","hashOfConfig":"8937"},{"size":1495,"mtime":1675188401851,"results":"9107","hashOfConfig":"8937"},{"size":1451,"mtime":1675188401851,"results":"9108","hashOfConfig":"8937"},{"size":1620,"mtime":1675188401851,"results":"9109","hashOfConfig":"8937"},{"size":470,"mtime":1675188401851,"results":"9110","hashOfConfig":"8937"},{"size":2088,"mtime":1675188401851,"results":"9111","hashOfConfig":"8937"},{"size":2377,"mtime":1675188401851,"results":"9112","hashOfConfig":"8937"},{"size":555,"mtime":1675188401851,"results":"9113","hashOfConfig":"8937"},{"size":720,"mtime":1675188401851,"results":"9114","hashOfConfig":"8937"},{"size":613,"mtime":1675188401851,"results":"9115","hashOfConfig":"8937"},{"size":1267,"mtime":1675188401851,"results":"9116","hashOfConfig":"8937"},{"size":5666,"mtime":1675188401851,"results":"9117","hashOfConfig":"8937"},{"size":771,"mtime":1675188401851,"results":"9118","hashOfConfig":"8937"},{"size":623,"mtime":1675188401851,"results":"9119","hashOfConfig":"8937"},{"size":1334,"mtime":1675188401852,"results":"9120","hashOfConfig":"8937"},{"size":2181,"mtime":1678221097513,"results":"9121","hashOfConfig":"8937"},{"filePath":"9122","messages":"9123","suppressedMessages":"9124","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1p807zb",{"filePath":"9125","messages":"9126","suppressedMessages":"9127","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9128","messages":"9129","suppressedMessages":"9130","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9131","messages":"9132","suppressedMessages":"9133","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9134","messages":"9135","suppressedMessages":"9136","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9137","messages":"9138","suppressedMessages":"9139","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9140","messages":"9141","suppressedMessages":"9142","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9143","messages":"9144","suppressedMessages":"9145","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9146","messages":"9147","suppressedMessages":"9148","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9149","messages":"9150","suppressedMessages":"9151","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9152","messages":"9153","suppressedMessages":"9154","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1ugy4ig",{"filePath":"9155","messages":"9156","suppressedMessages":"9157","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9158","messages":"9159","suppressedMessages":"9160","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9161","messages":"9162","suppressedMessages":"9163","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9164","messages":"9165","suppressedMessages":"9166","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9167","messages":"9168","suppressedMessages":"9169","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9170","messages":"9171","suppressedMessages":"9172","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9173","messages":"9174","suppressedMessages":"9175","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9176","messages":"9177","suppressedMessages":"9178","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9179","messages":"9180","suppressedMessages":"9181","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9182","messages":"9183","suppressedMessages":"9184","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9185","messages":"9186","suppressedMessages":"9187","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9188","messages":"9189","suppressedMessages":"9190","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9191","messages":"9192","suppressedMessages":"9193","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9194","messages":"9195","suppressedMessages":"9196","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9197","messages":"9198","suppressedMessages":"9199","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9200","messages":"9201","suppressedMessages":"9202","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9203","messages":"9204","suppressedMessages":"9205","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9206","messages":"9207","suppressedMessages":"9208","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9209","messages":"9210","suppressedMessages":"9211","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9212","messages":"9213","suppressedMessages":"9214","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9215","messages":"9216","suppressedMessages":"9217","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9218","messages":"9219","suppressedMessages":"9220","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9221","messages":"9222","suppressedMessages":"9223","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9224","messages":"9225","suppressedMessages":"9226","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9227","messages":"9228","suppressedMessages":"9229","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9230"},{"filePath":"9231","messages":"9232","suppressedMessages":"9233","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9234"},{"filePath":"9235","messages":"9236","suppressedMessages":"9237","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9238","messages":"9239","suppressedMessages":"9240","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9241"},{"filePath":"9242","messages":"9243","suppressedMessages":"9244","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9245"},{"filePath":"9246","messages":"9247","suppressedMessages":"9248","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9249"},{"filePath":"9250","messages":"9251","suppressedMessages":"9252","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9253","messages":"9254","suppressedMessages":"9255","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9256","messages":"9257","suppressedMessages":"9258","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9259","messages":"9260","suppressedMessages":"9261","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9262","messages":"9263","suppressedMessages":"9264","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9265","messages":"9266","suppressedMessages":"9267","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9268","messages":"9269","suppressedMessages":"9270","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9271","messages":"9272","suppressedMessages":"9273","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9274","messages":"9275","suppressedMessages":"9276","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9277","messages":"9278","suppressedMessages":"9279","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9280","messages":"9281","suppressedMessages":"9282","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9283","messages":"9284","suppressedMessages":"9285","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9286","messages":"9287","suppressedMessages":"9288","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9289","messages":"9290","suppressedMessages":"9291","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9292","messages":"9293","suppressedMessages":"9294","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9295","messages":"9296","suppressedMessages":"9297","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9298","messages":"9299","suppressedMessages":"9300","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9301","messages":"9302","suppressedMessages":"9303","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9304","messages":"9305","suppressedMessages":"9306","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9307","messages":"9308","suppressedMessages":"9309","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9310","messages":"9311","suppressedMessages":"9312","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9313","messages":"9314","suppressedMessages":"9315","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9316","messages":"9317","suppressedMessages":"9318","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9319","messages":"9320","suppressedMessages":"9321","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9322","messages":"9323","suppressedMessages":"9324","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9325","messages":"9326","suppressedMessages":"9327","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9328","messages":"9329","suppressedMessages":"9330","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9331","messages":"9332","suppressedMessages":"9333","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9334","messages":"9335","suppressedMessages":"9336","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9337","messages":"9338","suppressedMessages":"9339","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9340","messages":"9341","suppressedMessages":"9342","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9343","messages":"9344","suppressedMessages":"9345","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9346","messages":"9347","suppressedMessages":"9348","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9349","messages":"9350","suppressedMessages":"9351","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9352","messages":"9353","suppressedMessages":"9354","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9355","messages":"9356","suppressedMessages":"9357","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9358","messages":"9359","suppressedMessages":"9360","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9361","messages":"9362","suppressedMessages":"9363","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9364","messages":"9365","suppressedMessages":"9366","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9367","messages":"9368","suppressedMessages":"9369","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9370","messages":"9371","suppressedMessages":"9372","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9373","messages":"9374","suppressedMessages":"9375","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9376","messages":"9377","suppressedMessages":"9378","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9379","messages":"9380","suppressedMessages":"9381","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9382","messages":"9383","suppressedMessages":"9384","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9385","messages":"9386","suppressedMessages":"9387","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9388","messages":"9389","suppressedMessages":"9390","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9391","messages":"9392","suppressedMessages":"9393","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9394","messages":"9395","suppressedMessages":"9396","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9397","messages":"9398","suppressedMessages":"9399","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9400","messages":"9401","suppressedMessages":"9402","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9403","messages":"9404","suppressedMessages":"9405","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9406","messages":"9407","suppressedMessages":"9408","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9409","messages":"9410","suppressedMessages":"9411","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9412","messages":"9413","suppressedMessages":"9414","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9415","messages":"9416","suppressedMessages":"9417","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9418","messages":"9419","suppressedMessages":"9420","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9421","messages":"9422","suppressedMessages":"9423","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9424","messages":"9425","suppressedMessages":"9426","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9427","messages":"9428","suppressedMessages":"9429","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9430","messages":"9431","suppressedMessages":"9432","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9433","messages":"9434","suppressedMessages":"9435","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9436"},{"filePath":"9437","messages":"9438","suppressedMessages":"9439","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9440","messages":"9441","suppressedMessages":"9442","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9443","messages":"9444","suppressedMessages":"9445","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9446","messages":"9447","suppressedMessages":"9448","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9449","messages":"9450","suppressedMessages":"9451","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9452","messages":"9453","suppressedMessages":"9454","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9455","messages":"9456","suppressedMessages":"9457","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9458","messages":"9459","suppressedMessages":"9460","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9461"},{"filePath":"9462","messages":"9463","suppressedMessages":"9464","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9465","messages":"9466","suppressedMessages":"9467","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9468","messages":"9469","suppressedMessages":"9470","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9471","messages":"9472","suppressedMessages":"9473","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9474","messages":"9475","suppressedMessages":"9476","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9477","messages":"9478","suppressedMessages":"9479","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9480","messages":"9481","suppressedMessages":"9482","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9483","messages":"9484","suppressedMessages":"9485","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9486","messages":"9487","suppressedMessages":"9488","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9489","messages":"9490","suppressedMessages":"9491","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9492","messages":"9493","suppressedMessages":"9494","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9495","messages":"9496","suppressedMessages":"9497","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9498","messages":"9499","suppressedMessages":"9500","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9501","messages":"9502","suppressedMessages":"9503","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9504","messages":"9505","suppressedMessages":"9506","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9507","messages":"9508","suppressedMessages":"9509","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9510","messages":"9511","suppressedMessages":"9512","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9513","messages":"9514","suppressedMessages":"9515","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9516","messages":"9517","suppressedMessages":"9518","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9519","messages":"9520","suppressedMessages":"9521","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9522","messages":"9523","suppressedMessages":"9524","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9525","messages":"9526","suppressedMessages":"9527","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9528","messages":"9529","suppressedMessages":"9530","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9531","messages":"9532","suppressedMessages":"9533","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9534","messages":"9535","suppressedMessages":"9536","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9537","messages":"9538","suppressedMessages":"9539","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9540","messages":"9541","suppressedMessages":"9542","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9543","messages":"9544","suppressedMessages":"9545","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9546","messages":"9547","suppressedMessages":"9548","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9549","messages":"9550","suppressedMessages":"9551","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9552","messages":"9553","suppressedMessages":"9554","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9555","messages":"9556","suppressedMessages":"9557","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9558","messages":"9559","suppressedMessages":"9560","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9561","messages":"9562","suppressedMessages":"9563","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9564","messages":"9565","suppressedMessages":"9566","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9567"},{"filePath":"9568","messages":"9569","suppressedMessages":"9570","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9571","messages":"9572","suppressedMessages":"9573","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9574","messages":"9575","suppressedMessages":"9576","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9577"},{"filePath":"9578","messages":"9579","suppressedMessages":"9580","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9581","messages":"9582","suppressedMessages":"9583","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9584","messages":"9585","suppressedMessages":"9586","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9587","messages":"9588","suppressedMessages":"9589","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9590","messages":"9591","suppressedMessages":"9592","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9593","messages":"9594","suppressedMessages":"9595","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9596","messages":"9597","suppressedMessages":"9598","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9599","messages":"9600","suppressedMessages":"9601","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9602","messages":"9603","suppressedMessages":"9604","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9605","messages":"9606","suppressedMessages":"9607","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9608","messages":"9609","suppressedMessages":"9610","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9611","messages":"9612","suppressedMessages":"9613","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9614","messages":"9615","suppressedMessages":"9616","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9617","messages":"9618","suppressedMessages":"9619","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9620","messages":"9621","suppressedMessages":"9622","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9623","messages":"9624","suppressedMessages":"9625","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9626"},{"filePath":"9627","messages":"9628","suppressedMessages":"9629","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9630","messages":"9631","suppressedMessages":"9632","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9633","messages":"9634","suppressedMessages":"9635","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9636","messages":"9637","suppressedMessages":"9638","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9639","messages":"9640","suppressedMessages":"9641","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9642","messages":"9643","suppressedMessages":"9644","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9645"},{"filePath":"9646","messages":"9647","suppressedMessages":"9648","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9649","messages":"9650","suppressedMessages":"9651","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9652","messages":"9653","suppressedMessages":"9654","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9655","messages":"9656","suppressedMessages":"9657","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9658","messages":"9659","suppressedMessages":"9660","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9661","messages":"9662","suppressedMessages":"9663","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9664","messages":"9665","suppressedMessages":"9666","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9667","messages":"9668","suppressedMessages":"9669","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9670","messages":"9671","suppressedMessages":"9672","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9673","messages":"9674","suppressedMessages":"9675","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9676"},{"filePath":"9677","messages":"9678","suppressedMessages":"9679","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9680","messages":"9681","suppressedMessages":"9682","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9683","messages":"9684","suppressedMessages":"9685","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9686","messages":"9687","suppressedMessages":"9688","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9689","messages":"9690","suppressedMessages":"9691","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9692","messages":"9693","suppressedMessages":"9694","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9695","messages":"9696","suppressedMessages":"9697","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9698","messages":"9699","suppressedMessages":"9700","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9701","messages":"9702","suppressedMessages":"9703","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9704","messages":"9705","suppressedMessages":"9706","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9707","messages":"9708","suppressedMessages":"9709","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9710","messages":"9711","suppressedMessages":"9712","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9713"},{"filePath":"9714","messages":"9715","suppressedMessages":"9716","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9717","messages":"9718","suppressedMessages":"9719","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9720","messages":"9721","suppressedMessages":"9722","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9723"},{"filePath":"9724","messages":"9725","suppressedMessages":"9726","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9727","messages":"9728","suppressedMessages":"9729","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9730","messages":"9731","suppressedMessages":"9732","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9733","messages":"9734","suppressedMessages":"9735","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9736","messages":"9737","suppressedMessages":"9738","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9739","messages":"9740","suppressedMessages":"9741","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9742","messages":"9743","suppressedMessages":"9744","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9745","messages":"9746","suppressedMessages":"9747","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9748","messages":"9749","suppressedMessages":"9750","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9751","messages":"9752","suppressedMessages":"9753","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9754","messages":"9755","suppressedMessages":"9756","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9757","messages":"9758","suppressedMessages":"9759","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9760","messages":"9761","suppressedMessages":"9762","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9763","messages":"9764","suppressedMessages":"9765","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9766","messages":"9767","suppressedMessages":"9768","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9769","messages":"9770","suppressedMessages":"9771","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9772","messages":"9773","suppressedMessages":"9774","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9775","messages":"9776","suppressedMessages":"9777","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9778","messages":"9779","suppressedMessages":"9780","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9781","messages":"9782","suppressedMessages":"9783","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9784","messages":"9785","suppressedMessages":"9786","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9787","messages":"9788","suppressedMessages":"9789","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9790","messages":"9791","suppressedMessages":"9792","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9793"},{"filePath":"9794","messages":"9795","suppressedMessages":"9796","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9797","messages":"9798","suppressedMessages":"9799","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9800","messages":"9801","suppressedMessages":"9802","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9803","messages":"9804","suppressedMessages":"9805","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9806","messages":"9807","suppressedMessages":"9808","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9809","messages":"9810","suppressedMessages":"9811","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9812","messages":"9813","suppressedMessages":"9814","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9815","messages":"9816","suppressedMessages":"9817","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9818","messages":"9819","suppressedMessages":"9820","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9821","messages":"9822","suppressedMessages":"9823","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9824","messages":"9825","suppressedMessages":"9826","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9827","messages":"9828","suppressedMessages":"9829","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9830","messages":"9831","suppressedMessages":"9832","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9833","messages":"9834","suppressedMessages":"9835","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9836","messages":"9837","suppressedMessages":"9838","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9839","messages":"9840","suppressedMessages":"9841","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9842","messages":"9843","suppressedMessages":"9844","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9845","messages":"9846","suppressedMessages":"9847","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9848","messages":"9849","suppressedMessages":"9850","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9851","messages":"9852","suppressedMessages":"9853","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9854","messages":"9855","suppressedMessages":"9856","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9857","messages":"9858","suppressedMessages":"9859","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9860","messages":"9861","suppressedMessages":"9862","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9863","messages":"9864","suppressedMessages":"9865","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9866","messages":"9867","suppressedMessages":"9868","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9869","messages":"9870","suppressedMessages":"9871","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9872","messages":"9873","suppressedMessages":"9874","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9875","messages":"9876","suppressedMessages":"9877","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9878","messages":"9879","suppressedMessages":"9880","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9881","messages":"9882","suppressedMessages":"9883","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9884","messages":"9885","suppressedMessages":"9886","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9887"},{"filePath":"9888","messages":"9889","suppressedMessages":"9890","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9891","messages":"9892","suppressedMessages":"9893","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9894","messages":"9895","suppressedMessages":"9896","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9897","messages":"9898","suppressedMessages":"9899","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9900","messages":"9901","suppressedMessages":"9902","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9903","messages":"9904","suppressedMessages":"9905","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9906","messages":"9907","suppressedMessages":"9908","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9909","messages":"9910","suppressedMessages":"9911","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9912","messages":"9913","suppressedMessages":"9914","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9915","messages":"9916","suppressedMessages":"9917","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9918","messages":"9919","suppressedMessages":"9920","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9921","messages":"9922","suppressedMessages":"9923","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9924","messages":"9925","suppressedMessages":"9926","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9927","messages":"9928","suppressedMessages":"9929","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9930","messages":"9931","suppressedMessages":"9932","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9933","messages":"9934","suppressedMessages":"9935","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9936","messages":"9937","suppressedMessages":"9938","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9939","messages":"9940","suppressedMessages":"9941","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9942","messages":"9943","suppressedMessages":"9944","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9945","messages":"9946","suppressedMessages":"9947","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"9948"},{"filePath":"9949","messages":"9950","suppressedMessages":"9951","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9952","messages":"9953","suppressedMessages":"9954","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9955","messages":"9956","suppressedMessages":"9957","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9958","messages":"9959","suppressedMessages":"9960","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9961","messages":"9962","suppressedMessages":"9963","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9964","messages":"9965","suppressedMessages":"9966","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9967","messages":"9968","suppressedMessages":"9969","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9970","messages":"9971","suppressedMessages":"9972","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9973","messages":"9974","suppressedMessages":"9975","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9976","messages":"9977","suppressedMessages":"9978","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9979","messages":"9980","suppressedMessages":"9981","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9982","messages":"9983","suppressedMessages":"9984","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9985","messages":"9986","suppressedMessages":"9987","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9988","messages":"9989","suppressedMessages":"9990","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9991","messages":"9992","suppressedMessages":"9993","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9994","messages":"9995","suppressedMessages":"9996","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"9997","messages":"9998","suppressedMessages":"9999","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10000","messages":"10001","suppressedMessages":"10002","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10003","messages":"10004","suppressedMessages":"10005","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10006","messages":"10007","suppressedMessages":"10008","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10009","messages":"10010","suppressedMessages":"10011","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10012","messages":"10013","suppressedMessages":"10014","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10015","messages":"10016","suppressedMessages":"10017","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10018","messages":"10019","suppressedMessages":"10020","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10021","messages":"10022","suppressedMessages":"10023","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10024","messages":"10025","suppressedMessages":"10026","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10027","messages":"10028","suppressedMessages":"10029","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10030","messages":"10031","suppressedMessages":"10032","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10033","messages":"10034","suppressedMessages":"10035","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10036","messages":"10037","suppressedMessages":"10038","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10039","messages":"10040","suppressedMessages":"10041","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10042","messages":"10043","suppressedMessages":"10044","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10045","messages":"10046","suppressedMessages":"10047","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10048","messages":"10049","suppressedMessages":"10050","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10051","messages":"10052","suppressedMessages":"10053","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10054","messages":"10055","suppressedMessages":"10056","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10057","messages":"10058","suppressedMessages":"10059","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10060","messages":"10061","suppressedMessages":"10062","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10063","messages":"10064","suppressedMessages":"10065","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10066","messages":"10067","suppressedMessages":"10068","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10069","messages":"10070","suppressedMessages":"10071","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10072","messages":"10073","suppressedMessages":"10074","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10075","messages":"10076","suppressedMessages":"10077","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10078","messages":"10079","suppressedMessages":"10080","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10081","messages":"10082","suppressedMessages":"10083","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10084","messages":"10085","suppressedMessages":"10086","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10087","messages":"10088","suppressedMessages":"10089","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10090","messages":"10091","suppressedMessages":"10092","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10093","messages":"10094","suppressedMessages":"10095","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10096","messages":"10097","suppressedMessages":"10098","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10099","messages":"10100","suppressedMessages":"10101","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10102","messages":"10103","suppressedMessages":"10104","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10105","messages":"10106","suppressedMessages":"10107","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10108","messages":"10109","suppressedMessages":"10110","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10111","messages":"10112","suppressedMessages":"10113","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10114","messages":"10115","suppressedMessages":"10116","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10117","messages":"10118","suppressedMessages":"10119","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10120","messages":"10121","suppressedMessages":"10122","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10123","messages":"10124","suppressedMessages":"10125","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10126","messages":"10127","suppressedMessages":"10128","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10129","messages":"10130","suppressedMessages":"10131","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10132","messages":"10133","suppressedMessages":"10134","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10135","messages":"10136","suppressedMessages":"10137","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10138","messages":"10139","suppressedMessages":"10140","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10141","messages":"10142","suppressedMessages":"10143","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10144","messages":"10145","suppressedMessages":"10146","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10147","messages":"10148","suppressedMessages":"10149","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10150","messages":"10151","suppressedMessages":"10152","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10153","messages":"10154","suppressedMessages":"10155","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10156","messages":"10157","suppressedMessages":"10158","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10159","messages":"10160","suppressedMessages":"10161","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10162","messages":"10163","suppressedMessages":"10164","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10165","messages":"10166","suppressedMessages":"10167","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10168","messages":"10169","suppressedMessages":"10170","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10171","messages":"10172","suppressedMessages":"10173","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10174","messages":"10175","suppressedMessages":"10176","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10177","messages":"10178","suppressedMessages":"10179","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10180","messages":"10181","suppressedMessages":"10182","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10183","messages":"10184","suppressedMessages":"10185","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10186","messages":"10187","suppressedMessages":"10188","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10189","messages":"10190","suppressedMessages":"10191","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10192","messages":"10193","suppressedMessages":"10194","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10195","messages":"10196","suppressedMessages":"10197","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10198","messages":"10199","suppressedMessages":"10200","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10201","messages":"10202","suppressedMessages":"10203","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10204","messages":"10205","suppressedMessages":"10206","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10207","messages":"10208","suppressedMessages":"10209","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10210","messages":"10211","suppressedMessages":"10212","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10213","messages":"10214","suppressedMessages":"10215","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10216","messages":"10217","suppressedMessages":"10218","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10219","messages":"10220","suppressedMessages":"10221","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10222","messages":"10223","suppressedMessages":"10224","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10225","messages":"10226","suppressedMessages":"10227","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10228","messages":"10229","suppressedMessages":"10230","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10231","messages":"10232","suppressedMessages":"10233","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10234","messages":"10235","suppressedMessages":"10236","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10237","messages":"10238","suppressedMessages":"10239","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10240","messages":"10241","suppressedMessages":"10242","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10243","messages":"10244","suppressedMessages":"10245","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10246","messages":"10247","suppressedMessages":"10248","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10249","messages":"10250","suppressedMessages":"10251","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10252","messages":"10253","suppressedMessages":"10254","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10255","messages":"10256","suppressedMessages":"10257","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10258","messages":"10259","suppressedMessages":"10260","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10261","messages":"10262","suppressedMessages":"10263","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10264","messages":"10265","suppressedMessages":"10266","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10267","messages":"10268","suppressedMessages":"10269","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10270","messages":"10271","suppressedMessages":"10272","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10273","messages":"10274","suppressedMessages":"10275","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10276","messages":"10277","suppressedMessages":"10278","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10279","messages":"10280","suppressedMessages":"10281","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10282","messages":"10283","suppressedMessages":"10284","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10285","messages":"10286","suppressedMessages":"10287","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10288","messages":"10289","suppressedMessages":"10290","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10291","messages":"10292","suppressedMessages":"10293","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10294","messages":"10295","suppressedMessages":"10296","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10297","messages":"10298","suppressedMessages":"10299","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10300","messages":"10301","suppressedMessages":"10302","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10303","messages":"10304","suppressedMessages":"10305","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10306","messages":"10307","suppressedMessages":"10308","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10309","messages":"10310","suppressedMessages":"10311","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10312","messages":"10313","suppressedMessages":"10314","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10315","messages":"10316","suppressedMessages":"10317","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10318","messages":"10319","suppressedMessages":"10320","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10321","messages":"10322","suppressedMessages":"10323","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10324","messages":"10325","suppressedMessages":"10326","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10327","messages":"10328","suppressedMessages":"10329","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10330","messages":"10331","suppressedMessages":"10332","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10333","messages":"10334","suppressedMessages":"10335","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10336","messages":"10337","suppressedMessages":"10338","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10339","messages":"10340","suppressedMessages":"10341","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10342","messages":"10343","suppressedMessages":"10344","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10345","messages":"10346","suppressedMessages":"10347","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10348","messages":"10349","suppressedMessages":"10350","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10351","messages":"10352","suppressedMessages":"10353","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10354","messages":"10355","suppressedMessages":"10356","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10357","messages":"10358","suppressedMessages":"10359","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10360","messages":"10361","suppressedMessages":"10362","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10363","messages":"10364","suppressedMessages":"10365","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10366","messages":"10367","suppressedMessages":"10368","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"10369"},{"filePath":"10370","messages":"10371","suppressedMessages":"10372","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10373","messages":"10374","suppressedMessages":"10375","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10376","messages":"10377","suppressedMessages":"10378","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"10379"},{"filePath":"10380","messages":"10381","suppressedMessages":"10382","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10383","messages":"10384","suppressedMessages":"10385","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10386","messages":"10387","suppressedMessages":"10388","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10389","messages":"10390","suppressedMessages":"10391","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10392","messages":"10393","suppressedMessages":"10394","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"10395"},{"filePath":"10396","messages":"10397","suppressedMessages":"10398","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10399","messages":"10400","suppressedMessages":"10401","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10402","messages":"10403","suppressedMessages":"10404","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10405","messages":"10406","suppressedMessages":"10407","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10408","messages":"10409","suppressedMessages":"10410","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10411","messages":"10412","suppressedMessages":"10413","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10414","messages":"10415","suppressedMessages":"10416","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10417","messages":"10418","suppressedMessages":"10419","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10420","messages":"10421","suppressedMessages":"10422","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10423","messages":"10424","suppressedMessages":"10425","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10426","messages":"10427","suppressedMessages":"10428","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10429","messages":"10430","suppressedMessages":"10431","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10432","messages":"10433","suppressedMessages":"10434","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10435","messages":"10436","suppressedMessages":"10437","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10438","messages":"10439","suppressedMessages":"10440","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10441","messages":"10442","suppressedMessages":"10443","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10444","messages":"10445","suppressedMessages":"10446","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10447","messages":"10448","suppressedMessages":"10449","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10450","messages":"10451","suppressedMessages":"10452","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10453","messages":"10454","suppressedMessages":"10455","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10456","messages":"10457","suppressedMessages":"10458","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10459","messages":"10460","suppressedMessages":"10461","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10462","messages":"10463","suppressedMessages":"10464","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10465","messages":"10466","suppressedMessages":"10467","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10468","messages":"10469","suppressedMessages":"10470","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10471","messages":"10472","suppressedMessages":"10473","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10474","messages":"10475","suppressedMessages":"10476","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10477","messages":"10478","suppressedMessages":"10479","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10480","messages":"10481","suppressedMessages":"10482","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10483","messages":"10484","suppressedMessages":"10485","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10486","messages":"10487","suppressedMessages":"10488","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10489","messages":"10490","suppressedMessages":"10491","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10492","messages":"10493","suppressedMessages":"10494","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10495","messages":"10496","suppressedMessages":"10497","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10498","messages":"10499","suppressedMessages":"10500","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10501","messages":"10502","suppressedMessages":"10503","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10504","messages":"10505","suppressedMessages":"10506","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10507","messages":"10508","suppressedMessages":"10509","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10510","messages":"10511","suppressedMessages":"10512","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10513","messages":"10514","suppressedMessages":"10515","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10516","messages":"10517","suppressedMessages":"10518","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10519","messages":"10520","suppressedMessages":"10521","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10522","messages":"10523","suppressedMessages":"10524","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10525","messages":"10526","suppressedMessages":"10527","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"10528"},{"filePath":"10529","messages":"10530","suppressedMessages":"10531","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10532","messages":"10533","suppressedMessages":"10534","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10535","messages":"10536","suppressedMessages":"10537","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10538","messages":"10539","suppressedMessages":"10540","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10541","messages":"10542","suppressedMessages":"10543","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10544","messages":"10545","suppressedMessages":"10546","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10547","messages":"10548","suppressedMessages":"10549","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10550","messages":"10551","suppressedMessages":"10552","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10553","messages":"10554","suppressedMessages":"10555","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10556","messages":"10557","suppressedMessages":"10558","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10559","messages":"10560","suppressedMessages":"10561","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10562","messages":"10563","suppressedMessages":"10564","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10565","messages":"10566","suppressedMessages":"10567","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10568","messages":"10569","suppressedMessages":"10570","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10571","messages":"10572","suppressedMessages":"10573","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10574","messages":"10575","suppressedMessages":"10576","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10577","messages":"10578","suppressedMessages":"10579","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10580","messages":"10581","suppressedMessages":"10582","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10583","messages":"10584","suppressedMessages":"10585","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10586","messages":"10587","suppressedMessages":"10588","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10589","messages":"10590","suppressedMessages":"10591","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10592","messages":"10593","suppressedMessages":"10594","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10595","messages":"10596","suppressedMessages":"10597","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10598","messages":"10599","suppressedMessages":"10600","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10601","messages":"10602","suppressedMessages":"10603","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10604","messages":"10605","suppressedMessages":"10606","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10607","messages":"10608","suppressedMessages":"10609","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10610","messages":"10611","suppressedMessages":"10612","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10613","messages":"10614","suppressedMessages":"10615","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10616","messages":"10617","suppressedMessages":"10618","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10619","messages":"10620","suppressedMessages":"10621","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10622","messages":"10623","suppressedMessages":"10624","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10625","messages":"10626","suppressedMessages":"10627","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10628","messages":"10629","suppressedMessages":"10630","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10631","messages":"10632","suppressedMessages":"10633","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10634","messages":"10635","suppressedMessages":"10636","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10637","messages":"10638","suppressedMessages":"10639","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10640","messages":"10641","suppressedMessages":"10642","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10643","messages":"10644","suppressedMessages":"10645","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10646","messages":"10647","suppressedMessages":"10648","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10649","messages":"10650","suppressedMessages":"10651","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10652","messages":"10653","suppressedMessages":"10654","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10655","messages":"10656","suppressedMessages":"10657","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10658","messages":"10659","suppressedMessages":"10660","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10661","messages":"10662","suppressedMessages":"10663","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10664","messages":"10665","suppressedMessages":"10666","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10667","messages":"10668","suppressedMessages":"10669","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10670","messages":"10671","suppressedMessages":"10672","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10673","messages":"10674","suppressedMessages":"10675","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10676","messages":"10677","suppressedMessages":"10678","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10679","messages":"10680","suppressedMessages":"10681","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10682","messages":"10683","suppressedMessages":"10684","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10685","messages":"10686","suppressedMessages":"10687","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10688","messages":"10689","suppressedMessages":"10690","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10691","messages":"10692","suppressedMessages":"10693","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10694","messages":"10695","suppressedMessages":"10696","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10697","messages":"10698","suppressedMessages":"10699","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10700","messages":"10701","suppressedMessages":"10702","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10703","messages":"10704","suppressedMessages":"10705","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10706","messages":"10707","suppressedMessages":"10708","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10709","messages":"10710","suppressedMessages":"10711","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10712","messages":"10713","suppressedMessages":"10714","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10715","messages":"10716","suppressedMessages":"10717","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10718","messages":"10719","suppressedMessages":"10720","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10721","messages":"10722","suppressedMessages":"10723","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10724","messages":"10725","suppressedMessages":"10726","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10727","messages":"10728","suppressedMessages":"10729","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10730","messages":"10731","suppressedMessages":"10732","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10733","messages":"10734","suppressedMessages":"10735","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10736","messages":"10737","suppressedMessages":"10738","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10739","messages":"10740","suppressedMessages":"10741","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10742","messages":"10743","suppressedMessages":"10744","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10745","messages":"10746","suppressedMessages":"10747","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10748","messages":"10749","suppressedMessages":"10750","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10751","messages":"10752","suppressedMessages":"10753","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10754","messages":"10755","suppressedMessages":"10756","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10757","messages":"10758","suppressedMessages":"10759","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10760","messages":"10761","suppressedMessages":"10762","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10763","messages":"10764","suppressedMessages":"10765","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10766","messages":"10767","suppressedMessages":"10768","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10769","messages":"10770","suppressedMessages":"10771","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10772","messages":"10773","suppressedMessages":"10774","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10775","messages":"10776","suppressedMessages":"10777","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10778","messages":"10779","suppressedMessages":"10780","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10781","messages":"10782","suppressedMessages":"10783","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10784","messages":"10785","suppressedMessages":"10786","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10787","messages":"10788","suppressedMessages":"10789","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10790","messages":"10791","suppressedMessages":"10792","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10793","messages":"10794","suppressedMessages":"10795","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10796","messages":"10797","suppressedMessages":"10798","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10799","messages":"10800","suppressedMessages":"10801","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10802","messages":"10803","suppressedMessages":"10804","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10805","messages":"10806","suppressedMessages":"10807","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10808","messages":"10809","suppressedMessages":"10810","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10811","messages":"10812","suppressedMessages":"10813","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10814","messages":"10815","suppressedMessages":"10816","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10817","messages":"10818","suppressedMessages":"10819","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10820","messages":"10821","suppressedMessages":"10822","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10823","messages":"10824","suppressedMessages":"10825","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10826","messages":"10827","suppressedMessages":"10828","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10829","messages":"10830","suppressedMessages":"10831","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10832","messages":"10833","suppressedMessages":"10834","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10835","messages":"10836","suppressedMessages":"10837","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10838","messages":"10839","suppressedMessages":"10840","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10841","messages":"10842","suppressedMessages":"10843","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10844","messages":"10845","suppressedMessages":"10846","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10847","messages":"10848","suppressedMessages":"10849","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10850","messages":"10851","suppressedMessages":"10852","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"10853"},{"filePath":"10854","messages":"10855","suppressedMessages":"10856","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10857","messages":"10858","suppressedMessages":"10859","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10860","messages":"10861","suppressedMessages":"10862","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10863","messages":"10864","suppressedMessages":"10865","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10866","messages":"10867","suppressedMessages":"10868","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10869","messages":"10870","suppressedMessages":"10871","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10872","messages":"10873","suppressedMessages":"10874","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10875","messages":"10876","suppressedMessages":"10877","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10878","messages":"10879","suppressedMessages":"10880","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10881","messages":"10882","suppressedMessages":"10883","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10884","messages":"10885","suppressedMessages":"10886","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10887","messages":"10888","suppressedMessages":"10889","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10890","messages":"10891","suppressedMessages":"10892","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10893","messages":"10894","suppressedMessages":"10895","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10896","messages":"10897","suppressedMessages":"10898","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10899","messages":"10900","suppressedMessages":"10901","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10902","messages":"10903","suppressedMessages":"10904","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10905","messages":"10906","suppressedMessages":"10907","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10908","messages":"10909","suppressedMessages":"10910","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10911","messages":"10912","suppressedMessages":"10913","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10914","messages":"10915","suppressedMessages":"10916","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10917","messages":"10918","suppressedMessages":"10919","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10920","messages":"10921","suppressedMessages":"10922","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10923","messages":"10924","suppressedMessages":"10925","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10926","messages":"10927","suppressedMessages":"10928","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10929","messages":"10930","suppressedMessages":"10931","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10932","messages":"10933","suppressedMessages":"10934","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10935","messages":"10936","suppressedMessages":"10937","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10938","messages":"10939","suppressedMessages":"10940","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10941","messages":"10942","suppressedMessages":"10943","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10944","messages":"10945","suppressedMessages":"10946","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10947","messages":"10948","suppressedMessages":"10949","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10950","messages":"10951","suppressedMessages":"10952","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10953","messages":"10954","suppressedMessages":"10955","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10956","messages":"10957","suppressedMessages":"10958","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10959","messages":"10960","suppressedMessages":"10961","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10962","messages":"10963","suppressedMessages":"10964","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10965","messages":"10966","suppressedMessages":"10967","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10968","messages":"10969","suppressedMessages":"10970","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10971","messages":"10972","suppressedMessages":"10973","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10974","messages":"10975","suppressedMessages":"10976","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10977","messages":"10978","suppressedMessages":"10979","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10980","messages":"10981","suppressedMessages":"10982","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10983","messages":"10984","suppressedMessages":"10985","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10986","messages":"10987","suppressedMessages":"10988","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10989","messages":"10990","suppressedMessages":"10991","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10992","messages":"10993","suppressedMessages":"10994","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10995","messages":"10996","suppressedMessages":"10997","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"10998","messages":"10999","suppressedMessages":"11000","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11001","messages":"11002","suppressedMessages":"11003","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11004","messages":"11005","suppressedMessages":"11006","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11007","messages":"11008","suppressedMessages":"11009","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11010","messages":"11011","suppressedMessages":"11012","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11013","messages":"11014","suppressedMessages":"11015","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11016","messages":"11017","suppressedMessages":"11018","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11019","messages":"11020","suppressedMessages":"11021","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11022","messages":"11023","suppressedMessages":"11024","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11025","messages":"11026","suppressedMessages":"11027","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11028","messages":"11029","suppressedMessages":"11030","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11031","messages":"11032","suppressedMessages":"11033","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11034","messages":"11035","suppressedMessages":"11036","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11037","messages":"11038","suppressedMessages":"11039","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11040","messages":"11041","suppressedMessages":"11042","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11043","messages":"11044","suppressedMessages":"11045","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11046","messages":"11047","suppressedMessages":"11048","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11049","messages":"11050","suppressedMessages":"11051","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11052","messages":"11053","suppressedMessages":"11054","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"11055"},{"filePath":"11056","messages":"11057","suppressedMessages":"11058","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11059","messages":"11060","suppressedMessages":"11061","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11062","messages":"11063","suppressedMessages":"11064","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11065","messages":"11066","suppressedMessages":"11067","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11068","messages":"11069","suppressedMessages":"11070","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11071","messages":"11072","suppressedMessages":"11073","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11074","messages":"11075","suppressedMessages":"11076","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11077","messages":"11078","suppressedMessages":"11079","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11080","messages":"11081","suppressedMessages":"11082","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11083","messages":"11084","suppressedMessages":"11085","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11086","messages":"11087","suppressedMessages":"11088","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11089","messages":"11090","suppressedMessages":"11091","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11092","messages":"11093","suppressedMessages":"11094","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11095","messages":"11096","suppressedMessages":"11097","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11098","messages":"11099","suppressedMessages":"11100","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11101","messages":"11102","suppressedMessages":"11103","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11104","messages":"11105","suppressedMessages":"11106","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11107","messages":"11108","suppressedMessages":"11109","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11110","messages":"11111","suppressedMessages":"11112","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11113","messages":"11114","suppressedMessages":"11115","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11116","messages":"11117","suppressedMessages":"11118","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11119","messages":"11120","suppressedMessages":"11121","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11122","messages":"11123","suppressedMessages":"11124","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11125","messages":"11126","suppressedMessages":"11127","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11128","messages":"11129","suppressedMessages":"11130","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11131","messages":"11132","suppressedMessages":"11133","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11134","messages":"11135","suppressedMessages":"11136","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11137","messages":"11138","suppressedMessages":"11139","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11140","messages":"11141","suppressedMessages":"11142","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11143","messages":"11144","suppressedMessages":"11145","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11146","messages":"11147","suppressedMessages":"11148","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11149","messages":"11150","suppressedMessages":"11151","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11152","messages":"11153","suppressedMessages":"11154","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11155","messages":"11156","suppressedMessages":"11157","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11158","messages":"11159","suppressedMessages":"11160","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11161","messages":"11162","suppressedMessages":"11163","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11164","messages":"11165","suppressedMessages":"11166","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11167","messages":"11168","suppressedMessages":"11169","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11170","messages":"11171","suppressedMessages":"11172","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11173","messages":"11174","suppressedMessages":"11175","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11176","messages":"11177","suppressedMessages":"11178","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11179","messages":"11180","suppressedMessages":"11181","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11182","messages":"11183","suppressedMessages":"11184","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"11185"},{"filePath":"11186","messages":"11187","suppressedMessages":"11188","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11189","messages":"11190","suppressedMessages":"11191","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"11192"},{"filePath":"11193","messages":"11194","suppressedMessages":"11195","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11196","messages":"11197","suppressedMessages":"11198","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11199","messages":"11200","suppressedMessages":"11201","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11202","messages":"11203","suppressedMessages":"11204","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11205","messages":"11206","suppressedMessages":"11207","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11208","messages":"11209","suppressedMessages":"11210","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11211","messages":"11212","suppressedMessages":"11213","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11214","messages":"11215","suppressedMessages":"11216","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11217","messages":"11218","suppressedMessages":"11219","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11220","messages":"11221","suppressedMessages":"11222","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11223","messages":"11224","suppressedMessages":"11225","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11226","messages":"11227","suppressedMessages":"11228","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11229","messages":"11230","suppressedMessages":"11231","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11232","messages":"11233","suppressedMessages":"11234","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11235","messages":"11236","suppressedMessages":"11237","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11238","messages":"11239","suppressedMessages":"11240","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11241","messages":"11242","suppressedMessages":"11243","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11244","messages":"11245","suppressedMessages":"11246","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11247","messages":"11248","suppressedMessages":"11249","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11250","messages":"11251","suppressedMessages":"11252","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11253","messages":"11254","suppressedMessages":"11255","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11256","messages":"11257","suppressedMessages":"11258","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11259","messages":"11260","suppressedMessages":"11261","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11262","messages":"11263","suppressedMessages":"11264","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11265","messages":"11266","suppressedMessages":"11267","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11268","messages":"11269","suppressedMessages":"11270","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11271","messages":"11272","suppressedMessages":"11273","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"11274"},{"filePath":"11275","messages":"11276","suppressedMessages":"11277","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11278","messages":"11279","suppressedMessages":"11280","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11281","messages":"11282","suppressedMessages":"11283","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11284","messages":"11285","suppressedMessages":"11286","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11287","messages":"11288","suppressedMessages":"11289","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11290","messages":"11291","suppressedMessages":"11292","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11293","messages":"11294","suppressedMessages":"11295","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11296","messages":"11297","suppressedMessages":"11298","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"11299"},{"filePath":"11300","messages":"11301","suppressedMessages":"11302","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"11303"},{"filePath":"11304","messages":"11305","suppressedMessages":"11306","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11307","messages":"11308","suppressedMessages":"11309","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11310","messages":"11311","suppressedMessages":"11312","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11313","messages":"11314","suppressedMessages":"11315","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11316","messages":"11317","suppressedMessages":"11318","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11319","messages":"11320","suppressedMessages":"11321","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11322","messages":"11323","suppressedMessages":"11324","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11325","messages":"11326","suppressedMessages":"11327","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11328","messages":"11329","suppressedMessages":"11330","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11331","messages":"11332","suppressedMessages":"11333","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11334","messages":"11335","suppressedMessages":"11336","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11337","messages":"11338","suppressedMessages":"11339","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11340","messages":"11341","suppressedMessages":"11342","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11343","messages":"11344","suppressedMessages":"11345","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11346","messages":"11347","suppressedMessages":"11348","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11349","messages":"11350","suppressedMessages":"11351","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11352","messages":"11353","suppressedMessages":"11354","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11355","messages":"11356","suppressedMessages":"11357","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11358","messages":"11359","suppressedMessages":"11360","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11361","messages":"11362","suppressedMessages":"11363","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11364","messages":"11365","suppressedMessages":"11366","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11367","messages":"11368","suppressedMessages":"11369","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11370","messages":"11371","suppressedMessages":"11372","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11373","messages":"11374","suppressedMessages":"11375","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"11376"},{"filePath":"11377","messages":"11378","suppressedMessages":"11379","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11380","messages":"11381","suppressedMessages":"11382","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11383","messages":"11384","suppressedMessages":"11385","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11386","messages":"11387","suppressedMessages":"11388","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11389","messages":"11390","suppressedMessages":"11391","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11392","messages":"11393","suppressedMessages":"11394","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"11395"},{"filePath":"11396","messages":"11397","suppressedMessages":"11398","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11399","messages":"11400","suppressedMessages":"11401","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11402","messages":"11403","suppressedMessages":"11404","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11405","messages":"11406","suppressedMessages":"11407","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11408","messages":"11409","suppressedMessages":"11410","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11411","messages":"11412","suppressedMessages":"11413","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11414","messages":"11415","suppressedMessages":"11416","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11417","messages":"11418","suppressedMessages":"11419","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11420","messages":"11421","suppressedMessages":"11422","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11423","messages":"11424","suppressedMessages":"11425","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11426","messages":"11427","suppressedMessages":"11428","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11429","messages":"11430","suppressedMessages":"11431","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11432","messages":"11433","suppressedMessages":"11434","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11435","messages":"11436","suppressedMessages":"11437","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11438","messages":"11439","suppressedMessages":"11440","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11441","messages":"11442","suppressedMessages":"11443","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11444","messages":"11445","suppressedMessages":"11446","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11447","messages":"11448","suppressedMessages":"11449","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11450","messages":"11451","suppressedMessages":"11452","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11453","messages":"11454","suppressedMessages":"11455","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11456","messages":"11457","suppressedMessages":"11458","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11459","messages":"11460","suppressedMessages":"11461","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11462","messages":"11463","suppressedMessages":"11464","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11465","messages":"11466","suppressedMessages":"11467","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11468","messages":"11469","suppressedMessages":"11470","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11471","messages":"11472","suppressedMessages":"11473","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11474","messages":"11475","suppressedMessages":"11476","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11477","messages":"11478","suppressedMessages":"11479","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11480","messages":"11481","suppressedMessages":"11482","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11483","messages":"11484","suppressedMessages":"11485","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11486","messages":"11487","suppressedMessages":"11488","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11489","messages":"11490","suppressedMessages":"11491","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11492","messages":"11493","suppressedMessages":"11494","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11495","messages":"11496","suppressedMessages":"11497","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11498","messages":"11499","suppressedMessages":"11500","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11501","messages":"11502","suppressedMessages":"11503","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11504","messages":"11505","suppressedMessages":"11506","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11507","messages":"11508","suppressedMessages":"11509","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11510","messages":"11511","suppressedMessages":"11512","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11513","messages":"11514","suppressedMessages":"11515","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11516","messages":"11517","suppressedMessages":"11518","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11519","messages":"11520","suppressedMessages":"11521","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11522","messages":"11523","suppressedMessages":"11524","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11525","messages":"11526","suppressedMessages":"11527","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11528","messages":"11529","suppressedMessages":"11530","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11531","messages":"11532","suppressedMessages":"11533","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11534","messages":"11535","suppressedMessages":"11536","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11537","messages":"11538","suppressedMessages":"11539","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11540","messages":"11541","suppressedMessages":"11542","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11543","messages":"11544","suppressedMessages":"11545","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11546","messages":"11547","suppressedMessages":"11548","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11549","messages":"11550","suppressedMessages":"11551","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11552","messages":"11553","suppressedMessages":"11554","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11555","messages":"11556","suppressedMessages":"11557","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11558","messages":"11559","suppressedMessages":"11560","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11561","messages":"11562","suppressedMessages":"11563","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11564","messages":"11565","suppressedMessages":"11566","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11567","messages":"11568","suppressedMessages":"11569","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11570","messages":"11571","suppressedMessages":"11572","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11573","messages":"11574","suppressedMessages":"11575","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11576","messages":"11577","suppressedMessages":"11578","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11579","messages":"11580","suppressedMessages":"11581","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11582","messages":"11583","suppressedMessages":"11584","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11585","messages":"11586","suppressedMessages":"11587","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11588","messages":"11589","suppressedMessages":"11590","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11591","messages":"11592","suppressedMessages":"11593","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"11594"},{"filePath":"11595","messages":"11596","suppressedMessages":"11597","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11598","messages":"11599","suppressedMessages":"11600","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11601","messages":"11602","suppressedMessages":"11603","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"11604"},{"filePath":"11605","messages":"11606","suppressedMessages":"11607","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11608","messages":"11609","suppressedMessages":"11610","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11611","messages":"11612","suppressedMessages":"11613","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11614","messages":"11615","suppressedMessages":"11616","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11617","messages":"11618","suppressedMessages":"11619","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11620","messages":"11621","suppressedMessages":"11622","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11623","messages":"11624","suppressedMessages":"11625","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11626","messages":"11627","suppressedMessages":"11628","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11629","messages":"11630","suppressedMessages":"11631","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11632","messages":"11633","suppressedMessages":"11634","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11635","messages":"11636","suppressedMessages":"11637","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11638","messages":"11639","suppressedMessages":"11640","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11641","messages":"11642","suppressedMessages":"11643","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11644","messages":"11645","suppressedMessages":"11646","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11647","messages":"11648","suppressedMessages":"11649","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11650","messages":"11651","suppressedMessages":"11652","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11653","messages":"11654","suppressedMessages":"11655","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11656","messages":"11657","suppressedMessages":"11658","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11659","messages":"11660","suppressedMessages":"11661","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11662","messages":"11663","suppressedMessages":"11664","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11665","messages":"11666","suppressedMessages":"11667","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11668","messages":"11669","suppressedMessages":"11670","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11671","messages":"11672","suppressedMessages":"11673","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11674","messages":"11675","suppressedMessages":"11676","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11677","messages":"11678","suppressedMessages":"11679","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11680","messages":"11681","suppressedMessages":"11682","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11683","messages":"11684","suppressedMessages":"11685","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11686","messages":"11687","suppressedMessages":"11688","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11689","messages":"11690","suppressedMessages":"11691","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11692","messages":"11693","suppressedMessages":"11694","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11695","messages":"11696","suppressedMessages":"11697","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11698","messages":"11699","suppressedMessages":"11700","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11701","messages":"11702","suppressedMessages":"11703","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11704","messages":"11705","suppressedMessages":"11706","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11707","messages":"11708","suppressedMessages":"11709","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11710","messages":"11711","suppressedMessages":"11712","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11713","messages":"11714","suppressedMessages":"11715","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11716","messages":"11717","suppressedMessages":"11718","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11719","messages":"11720","suppressedMessages":"11721","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11722","messages":"11723","suppressedMessages":"11724","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11725","messages":"11726","suppressedMessages":"11727","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11728","messages":"11729","suppressedMessages":"11730","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11731","messages":"11732","suppressedMessages":"11733","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11734","messages":"11735","suppressedMessages":"11736","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11737","messages":"11738","suppressedMessages":"11739","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11740","messages":"11741","suppressedMessages":"11742","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11743","messages":"11744","suppressedMessages":"11745","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"11746"},{"filePath":"11747","messages":"11748","suppressedMessages":"11749","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11750","messages":"11751","suppressedMessages":"11752","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11753","messages":"11754","suppressedMessages":"11755","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11756","messages":"11757","suppressedMessages":"11758","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11759","messages":"11760","suppressedMessages":"11761","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"11762"},{"filePath":"11763","messages":"11764","suppressedMessages":"11765","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11766","messages":"11767","suppressedMessages":"11768","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11769","messages":"11770","suppressedMessages":"11771","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11772","messages":"11773","suppressedMessages":"11774","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11775","messages":"11776","suppressedMessages":"11777","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11778","messages":"11779","suppressedMessages":"11780","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11781","messages":"11782","suppressedMessages":"11783","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11784","messages":"11785","suppressedMessages":"11786","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11787","messages":"11788","suppressedMessages":"11789","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11790","messages":"11791","suppressedMessages":"11792","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11793","messages":"11794","suppressedMessages":"11795","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11796","messages":"11797","suppressedMessages":"11798","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11799","messages":"11800","suppressedMessages":"11801","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11802","messages":"11803","suppressedMessages":"11804","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11805","messages":"11806","suppressedMessages":"11807","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11808","messages":"11809","suppressedMessages":"11810","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11811","messages":"11812","suppressedMessages":"11813","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11814","messages":"11815","suppressedMessages":"11816","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11817","messages":"11818","suppressedMessages":"11819","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11820","messages":"11821","suppressedMessages":"11822","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11823","messages":"11824","suppressedMessages":"11825","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11826","messages":"11827","suppressedMessages":"11828","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11829","messages":"11830","suppressedMessages":"11831","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11832","messages":"11833","suppressedMessages":"11834","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11835","messages":"11836","suppressedMessages":"11837","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11838","messages":"11839","suppressedMessages":"11840","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11841","messages":"11842","suppressedMessages":"11843","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11844","messages":"11845","suppressedMessages":"11846","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11847","messages":"11848","suppressedMessages":"11849","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11850","messages":"11851","suppressedMessages":"11852","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11853","messages":"11854","suppressedMessages":"11855","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11856","messages":"11857","suppressedMessages":"11858","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"11859"},{"filePath":"11860","messages":"11861","suppressedMessages":"11862","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11863","messages":"11864","suppressedMessages":"11865","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11866","messages":"11867","suppressedMessages":"11868","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11869","messages":"11870","suppressedMessages":"11871","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11872","messages":"11873","suppressedMessages":"11874","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11875","messages":"11876","suppressedMessages":"11877","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11878","messages":"11879","suppressedMessages":"11880","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11881","messages":"11882","suppressedMessages":"11883","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11884","messages":"11885","suppressedMessages":"11886","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11887","messages":"11888","suppressedMessages":"11889","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11890","messages":"11891","suppressedMessages":"11892","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11893","messages":"11894","suppressedMessages":"11895","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11896","messages":"11897","suppressedMessages":"11898","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11899","messages":"11900","suppressedMessages":"11901","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11902","messages":"11903","suppressedMessages":"11904","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11905","messages":"11906","suppressedMessages":"11907","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11908","messages":"11909","suppressedMessages":"11910","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11911","messages":"11912","suppressedMessages":"11913","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11914","messages":"11915","suppressedMessages":"11916","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11917","messages":"11918","suppressedMessages":"11919","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11920","messages":"11921","suppressedMessages":"11922","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11923","messages":"11924","suppressedMessages":"11925","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11926","messages":"11927","suppressedMessages":"11928","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11929","messages":"11930","suppressedMessages":"11931","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11932","messages":"11933","suppressedMessages":"11934","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11935","messages":"11936","suppressedMessages":"11937","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11938","messages":"11939","suppressedMessages":"11940","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11941","messages":"11942","suppressedMessages":"11943","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11944","messages":"11945","suppressedMessages":"11946","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11947","messages":"11948","suppressedMessages":"11949","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11950","messages":"11951","suppressedMessages":"11952","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11953","messages":"11954","suppressedMessages":"11955","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11956","messages":"11957","suppressedMessages":"11958","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11959","messages":"11960","suppressedMessages":"11961","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11962","messages":"11963","suppressedMessages":"11964","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11965","messages":"11966","suppressedMessages":"11967","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11968","messages":"11969","suppressedMessages":"11970","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11971","messages":"11972","suppressedMessages":"11973","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11974","messages":"11975","suppressedMessages":"11976","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11977","messages":"11978","suppressedMessages":"11979","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11980","messages":"11981","suppressedMessages":"11982","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11983","messages":"11984","suppressedMessages":"11985","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11986","messages":"11987","suppressedMessages":"11988","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11989","messages":"11990","suppressedMessages":"11991","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11992","messages":"11993","suppressedMessages":"11994","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11995","messages":"11996","suppressedMessages":"11997","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"11998","messages":"11999","suppressedMessages":"12000","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12001","messages":"12002","suppressedMessages":"12003","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12004","messages":"12005","suppressedMessages":"12006","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12007","messages":"12008","suppressedMessages":"12009","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12010","messages":"12011","suppressedMessages":"12012","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12013","messages":"12014","suppressedMessages":"12015","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12016","messages":"12017","suppressedMessages":"12018","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12019","messages":"12020","suppressedMessages":"12021","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12022","messages":"12023","suppressedMessages":"12024","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12025","messages":"12026","suppressedMessages":"12027","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12028","messages":"12029","suppressedMessages":"12030","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12031","messages":"12032","suppressedMessages":"12033","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12034","messages":"12035","suppressedMessages":"12036","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12037","messages":"12038","suppressedMessages":"12039","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12040","messages":"12041","suppressedMessages":"12042","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12043","messages":"12044","suppressedMessages":"12045","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12046","messages":"12047","suppressedMessages":"12048","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12049","messages":"12050","suppressedMessages":"12051","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12052","messages":"12053","suppressedMessages":"12054","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12055","messages":"12056","suppressedMessages":"12057","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12058","messages":"12059","suppressedMessages":"12060","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12061","messages":"12062","suppressedMessages":"12063","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12064","messages":"12065","suppressedMessages":"12066","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12067","messages":"12068","suppressedMessages":"12069","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12070","messages":"12071","suppressedMessages":"12072","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12073","messages":"12074","suppressedMessages":"12075","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12076","messages":"12077","suppressedMessages":"12078","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12079","messages":"12080","suppressedMessages":"12081","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12082","messages":"12083","suppressedMessages":"12084","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12085","messages":"12086","suppressedMessages":"12087","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12088","messages":"12089","suppressedMessages":"12090","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12091","messages":"12092","suppressedMessages":"12093","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12094","messages":"12095","suppressedMessages":"12096","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12097","messages":"12098","suppressedMessages":"12099","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12100","messages":"12101","suppressedMessages":"12102","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12103","messages":"12104","suppressedMessages":"12105","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12106","messages":"12107","suppressedMessages":"12108","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12109","messages":"12110","suppressedMessages":"12111","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12112","messages":"12113","suppressedMessages":"12114","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12115","messages":"12116","suppressedMessages":"12117","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"12118"},{"filePath":"12119","messages":"12120","suppressedMessages":"12121","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12122","messages":"12123","suppressedMessages":"12124","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12125","messages":"12126","suppressedMessages":"12127","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12128","messages":"12129","suppressedMessages":"12130","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12131","messages":"12132","suppressedMessages":"12133","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12134","messages":"12135","suppressedMessages":"12136","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12137","messages":"12138","suppressedMessages":"12139","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12140","messages":"12141","suppressedMessages":"12142","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12143","messages":"12144","suppressedMessages":"12145","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12146","messages":"12147","suppressedMessages":"12148","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"12149"},{"filePath":"12150","messages":"12151","suppressedMessages":"12152","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12153","messages":"12154","suppressedMessages":"12155","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12156","messages":"12157","suppressedMessages":"12158","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"12159"},{"filePath":"12160","messages":"12161","suppressedMessages":"12162","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12163","messages":"12164","suppressedMessages":"12165","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12166","messages":"12167","suppressedMessages":"12168","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12169","messages":"12170","suppressedMessages":"12171","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12172","messages":"12173","suppressedMessages":"12174","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12175","messages":"12176","suppressedMessages":"12177","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12178","messages":"12179","suppressedMessages":"12180","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12181","messages":"12182","suppressedMessages":"12183","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12184","messages":"12185","suppressedMessages":"12186","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12187","messages":"12188","suppressedMessages":"12189","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12190","messages":"12191","suppressedMessages":"12192","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12193","messages":"12194","suppressedMessages":"12195","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12196","messages":"12197","suppressedMessages":"12198","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12199","messages":"12200","suppressedMessages":"12201","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12202","messages":"12203","suppressedMessages":"12204","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12205","messages":"12206","suppressedMessages":"12207","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12208","messages":"12209","suppressedMessages":"12210","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12211","messages":"12212","suppressedMessages":"12213","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12214","messages":"12215","suppressedMessages":"12216","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12217","messages":"12218","suppressedMessages":"12219","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12220","messages":"12221","suppressedMessages":"12222","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12223","messages":"12224","suppressedMessages":"12225","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12226","messages":"12227","suppressedMessages":"12228","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12229","messages":"12230","suppressedMessages":"12231","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12232","messages":"12233","suppressedMessages":"12234","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12235","messages":"12236","suppressedMessages":"12237","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12238","messages":"12239","suppressedMessages":"12240","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12241","messages":"12242","suppressedMessages":"12243","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12244","messages":"12245","suppressedMessages":"12246","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12247","messages":"12248","suppressedMessages":"12249","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12250","messages":"12251","suppressedMessages":"12252","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12253","messages":"12254","suppressedMessages":"12255","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12256","messages":"12257","suppressedMessages":"12258","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12259","messages":"12260","suppressedMessages":"12261","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12262","messages":"12263","suppressedMessages":"12264","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12265","messages":"12266","suppressedMessages":"12267","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12268","messages":"12269","suppressedMessages":"12270","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12271","messages":"12272","suppressedMessages":"12273","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12274","messages":"12275","suppressedMessages":"12276","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12277","messages":"12278","suppressedMessages":"12279","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12280","messages":"12281","suppressedMessages":"12282","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12283","messages":"12284","suppressedMessages":"12285","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12286","messages":"12287","suppressedMessages":"12288","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12289","messages":"12290","suppressedMessages":"12291","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12292","messages":"12293","suppressedMessages":"12294","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12295","messages":"12296","suppressedMessages":"12297","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"12298"},{"filePath":"12299","messages":"12300","suppressedMessages":"12301","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12302","messages":"12303","suppressedMessages":"12304","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12305","messages":"12306","suppressedMessages":"12307","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12308","messages":"12309","suppressedMessages":"12310","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12311","messages":"12312","suppressedMessages":"12313","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12314","messages":"12315","suppressedMessages":"12316","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12317","messages":"12318","suppressedMessages":"12319","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12320","messages":"12321","suppressedMessages":"12322","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12323","messages":"12324","suppressedMessages":"12325","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12326","messages":"12327","suppressedMessages":"12328","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12329","messages":"12330","suppressedMessages":"12331","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12332","messages":"12333","suppressedMessages":"12334","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12335","messages":"12336","suppressedMessages":"12337","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12338","messages":"12339","suppressedMessages":"12340","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12341","messages":"12342","suppressedMessages":"12343","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12344","messages":"12345","suppressedMessages":"12346","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12347","messages":"12348","suppressedMessages":"12349","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12350","messages":"12351","suppressedMessages":"12352","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12353","messages":"12354","suppressedMessages":"12355","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12356","messages":"12357","suppressedMessages":"12358","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"12359"},{"filePath":"12360","messages":"12361","suppressedMessages":"12362","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12363","messages":"12364","suppressedMessages":"12365","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12366","messages":"12367","suppressedMessages":"12368","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12369","messages":"12370","suppressedMessages":"12371","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12372","messages":"12373","suppressedMessages":"12374","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12375","messages":"12376","suppressedMessages":"12377","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12378","messages":"12379","suppressedMessages":"12380","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12381","messages":"12382","suppressedMessages":"12383","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12384","messages":"12385","suppressedMessages":"12386","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"12387"},{"filePath":"12388","messages":"12389","suppressedMessages":"12390","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"12391"},{"filePath":"12392","messages":"12393","suppressedMessages":"12394","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12395","messages":"12396","suppressedMessages":"12397","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12398","messages":"12399","suppressedMessages":"12400","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12401","messages":"12402","suppressedMessages":"12403","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12404","messages":"12405","suppressedMessages":"12406","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12407","messages":"12408","suppressedMessages":"12409","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12410","messages":"12411","suppressedMessages":"12412","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12413","messages":"12414","suppressedMessages":"12415","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12416","messages":"12417","suppressedMessages":"12418","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12419","messages":"12420","suppressedMessages":"12421","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12422","messages":"12423","suppressedMessages":"12424","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12425","messages":"12426","suppressedMessages":"12427","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12428","messages":"12429","suppressedMessages":"12430","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12431","messages":"12432","suppressedMessages":"12433","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12434","messages":"12435","suppressedMessages":"12436","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12437","messages":"12438","suppressedMessages":"12439","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12440","messages":"12441","suppressedMessages":"12442","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12443","messages":"12444","suppressedMessages":"12445","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12446","messages":"12447","suppressedMessages":"12448","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12449","messages":"12450","suppressedMessages":"12451","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12452","messages":"12453","suppressedMessages":"12454","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12455","messages":"12456","suppressedMessages":"12457","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12458","messages":"12459","suppressedMessages":"12460","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12461","messages":"12462","suppressedMessages":"12463","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12464","messages":"12465","suppressedMessages":"12466","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12467","messages":"12468","suppressedMessages":"12469","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12470","messages":"12471","suppressedMessages":"12472","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12473","messages":"12474","suppressedMessages":"12475","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12476","messages":"12477","suppressedMessages":"12478","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12479","messages":"12480","suppressedMessages":"12481","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12482","messages":"12483","suppressedMessages":"12484","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12485","messages":"12486","suppressedMessages":"12487","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12488","messages":"12489","suppressedMessages":"12490","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12491","messages":"12492","suppressedMessages":"12493","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12494","messages":"12495","suppressedMessages":"12496","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12497","messages":"12498","suppressedMessages":"12499","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12500","messages":"12501","suppressedMessages":"12502","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12503","messages":"12504","suppressedMessages":"12505","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12506","messages":"12507","suppressedMessages":"12508","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12509","messages":"12510","suppressedMessages":"12511","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12512","messages":"12513","suppressedMessages":"12514","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12515","messages":"12516","suppressedMessages":"12517","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12518","messages":"12519","suppressedMessages":"12520","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12521","messages":"12522","suppressedMessages":"12523","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12524","messages":"12525","suppressedMessages":"12526","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12527","messages":"12528","suppressedMessages":"12529","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12530","messages":"12531","suppressedMessages":"12532","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12533","messages":"12534","suppressedMessages":"12535","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12536","messages":"12537","suppressedMessages":"12538","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12539","messages":"12540","suppressedMessages":"12541","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12542","messages":"12543","suppressedMessages":"12544","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12545","messages":"12546","suppressedMessages":"12547","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12548","messages":"12549","suppressedMessages":"12550","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12551","messages":"12552","suppressedMessages":"12553","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12554","messages":"12555","suppressedMessages":"12556","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12557","messages":"12558","suppressedMessages":"12559","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12560","messages":"12561","suppressedMessages":"12562","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12563","messages":"12564","suppressedMessages":"12565","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12566","messages":"12567","suppressedMessages":"12568","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12569","messages":"12570","suppressedMessages":"12571","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12572","messages":"12573","suppressedMessages":"12574","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12575","messages":"12576","suppressedMessages":"12577","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12578","messages":"12579","suppressedMessages":"12580","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12581","messages":"12582","suppressedMessages":"12583","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12584","messages":"12585","suppressedMessages":"12586","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12587","messages":"12588","suppressedMessages":"12589","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12590","messages":"12591","suppressedMessages":"12592","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12593","messages":"12594","suppressedMessages":"12595","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12596","messages":"12597","suppressedMessages":"12598","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12599","messages":"12600","suppressedMessages":"12601","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12602","messages":"12603","suppressedMessages":"12604","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12605","messages":"12606","suppressedMessages":"12607","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12608","messages":"12609","suppressedMessages":"12610","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12611","messages":"12612","suppressedMessages":"12613","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12614","messages":"12615","suppressedMessages":"12616","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12617","messages":"12618","suppressedMessages":"12619","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12620","messages":"12621","suppressedMessages":"12622","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12623","messages":"12624","suppressedMessages":"12625","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12626","messages":"12627","suppressedMessages":"12628","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12629","messages":"12630","suppressedMessages":"12631","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12632","messages":"12633","suppressedMessages":"12634","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12635","messages":"12636","suppressedMessages":"12637","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12638","messages":"12639","suppressedMessages":"12640","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12641","messages":"12642","suppressedMessages":"12643","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12644","messages":"12645","suppressedMessages":"12646","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12647","messages":"12648","suppressedMessages":"12649","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12650","messages":"12651","suppressedMessages":"12652","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12653","messages":"12654","suppressedMessages":"12655","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12656","messages":"12657","suppressedMessages":"12658","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12659","messages":"12660","suppressedMessages":"12661","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12662","messages":"12663","suppressedMessages":"12664","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12665","messages":"12666","suppressedMessages":"12667","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12668","messages":"12669","suppressedMessages":"12670","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12671","messages":"12672","suppressedMessages":"12673","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12674","messages":"12675","suppressedMessages":"12676","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12677","messages":"12678","suppressedMessages":"12679","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12680","messages":"12681","suppressedMessages":"12682","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12683","messages":"12684","suppressedMessages":"12685","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12686","messages":"12687","suppressedMessages":"12688","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12689","messages":"12690","suppressedMessages":"12691","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12692","messages":"12693","suppressedMessages":"12694","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12695","messages":"12696","suppressedMessages":"12697","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12698","messages":"12699","suppressedMessages":"12700","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12701","messages":"12702","suppressedMessages":"12703","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12704","messages":"12705","suppressedMessages":"12706","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12707","messages":"12708","suppressedMessages":"12709","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12710","messages":"12711","suppressedMessages":"12712","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12713","messages":"12714","suppressedMessages":"12715","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12716","messages":"12717","suppressedMessages":"12718","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12719","messages":"12720","suppressedMessages":"12721","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12722","messages":"12723","suppressedMessages":"12724","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12725","messages":"12726","suppressedMessages":"12727","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12728","messages":"12729","suppressedMessages":"12730","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12731","messages":"12732","suppressedMessages":"12733","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12734","messages":"12735","suppressedMessages":"12736","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12737","messages":"12738","suppressedMessages":"12739","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12740","messages":"12741","suppressedMessages":"12742","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12743","messages":"12744","suppressedMessages":"12745","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12746","messages":"12747","suppressedMessages":"12748","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12749","messages":"12750","suppressedMessages":"12751","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12752","messages":"12753","suppressedMessages":"12754","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12755","messages":"12756","suppressedMessages":"12757","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12758","messages":"12759","suppressedMessages":"12760","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12761","messages":"12762","suppressedMessages":"12763","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12764","messages":"12765","suppressedMessages":"12766","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12767","messages":"12768","suppressedMessages":"12769","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12770","messages":"12771","suppressedMessages":"12772","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12773","messages":"12774","suppressedMessages":"12775","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12776","messages":"12777","suppressedMessages":"12778","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12779","messages":"12780","suppressedMessages":"12781","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12782","messages":"12783","suppressedMessages":"12784","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12785","messages":"12786","suppressedMessages":"12787","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12788","messages":"12789","suppressedMessages":"12790","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12791","messages":"12792","suppressedMessages":"12793","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12794","messages":"12795","suppressedMessages":"12796","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12797","messages":"12798","suppressedMessages":"12799","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"12800"},{"filePath":"12801","messages":"12802","suppressedMessages":"12803","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12804","messages":"12805","suppressedMessages":"12806","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12807","messages":"12808","suppressedMessages":"12809","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12810","messages":"12811","suppressedMessages":"12812","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12813","messages":"12814","suppressedMessages":"12815","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12816","messages":"12817","suppressedMessages":"12818","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12819","messages":"12820","suppressedMessages":"12821","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12822","messages":"12823","suppressedMessages":"12824","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12825","messages":"12826","suppressedMessages":"12827","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12828","messages":"12829","suppressedMessages":"12830","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12831","messages":"12832","suppressedMessages":"12833","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12834","messages":"12835","suppressedMessages":"12836","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12837","messages":"12838","suppressedMessages":"12839","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12840","messages":"12841","suppressedMessages":"12842","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12843","messages":"12844","suppressedMessages":"12845","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12846","messages":"12847","suppressedMessages":"12848","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12849","messages":"12850","suppressedMessages":"12851","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12852","messages":"12853","suppressedMessages":"12854","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12855","messages":"12856","suppressedMessages":"12857","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12858","messages":"12859","suppressedMessages":"12860","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12861","messages":"12862","suppressedMessages":"12863","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12864","messages":"12865","suppressedMessages":"12866","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12867","messages":"12868","suppressedMessages":"12869","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12870","messages":"12871","suppressedMessages":"12872","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12873","messages":"12874","suppressedMessages":"12875","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12876","messages":"12877","suppressedMessages":"12878","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12879","messages":"12880","suppressedMessages":"12881","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"12882"},{"filePath":"12883","messages":"12884","suppressedMessages":"12885","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12886","messages":"12887","suppressedMessages":"12888","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12889","messages":"12890","suppressedMessages":"12891","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12892","messages":"12893","suppressedMessages":"12894","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12895","messages":"12896","suppressedMessages":"12897","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12898","messages":"12899","suppressedMessages":"12900","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12901","messages":"12902","suppressedMessages":"12903","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12904","messages":"12905","suppressedMessages":"12906","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12907","messages":"12908","suppressedMessages":"12909","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12910","messages":"12911","suppressedMessages":"12912","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12913","messages":"12914","suppressedMessages":"12915","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12916","messages":"12917","suppressedMessages":"12918","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12919","messages":"12920","suppressedMessages":"12921","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12922","messages":"12923","suppressedMessages":"12924","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12925","messages":"12926","suppressedMessages":"12927","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12928","messages":"12929","suppressedMessages":"12930","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12931","messages":"12932","suppressedMessages":"12933","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12934","messages":"12935","suppressedMessages":"12936","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12937","messages":"12938","suppressedMessages":"12939","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12940","messages":"12941","suppressedMessages":"12942","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12943","messages":"12944","suppressedMessages":"12945","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12946","messages":"12947","suppressedMessages":"12948","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12949","messages":"12950","suppressedMessages":"12951","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12952","messages":"12953","suppressedMessages":"12954","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12955","messages":"12956","suppressedMessages":"12957","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12958","messages":"12959","suppressedMessages":"12960","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12961","messages":"12962","suppressedMessages":"12963","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12964","messages":"12965","suppressedMessages":"12966","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12967","messages":"12968","suppressedMessages":"12969","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12970","messages":"12971","suppressedMessages":"12972","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12973","messages":"12974","suppressedMessages":"12975","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12976","messages":"12977","suppressedMessages":"12978","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12979","messages":"12980","suppressedMessages":"12981","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12982","messages":"12983","suppressedMessages":"12984","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12985","messages":"12986","suppressedMessages":"12987","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12988","messages":"12989","suppressedMessages":"12990","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12991","messages":"12992","suppressedMessages":"12993","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12994","messages":"12995","suppressedMessages":"12996","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12997","messages":"12998","suppressedMessages":"12999","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13000","messages":"13001","suppressedMessages":"13002","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13003","messages":"13004","suppressedMessages":"13005","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13006","messages":"13007","suppressedMessages":"13008","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13009","messages":"13010","suppressedMessages":"13011","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13012","messages":"13013","suppressedMessages":"13014","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13015","messages":"13016","suppressedMessages":"13017","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13018","messages":"13019","suppressedMessages":"13020","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13021","messages":"13022","suppressedMessages":"13023","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13024","messages":"13025","suppressedMessages":"13026","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13027","messages":"13028","suppressedMessages":"13029","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13030","messages":"13031","suppressedMessages":"13032","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13033","messages":"13034","suppressedMessages":"13035","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13036","messages":"13037","suppressedMessages":"13038","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13039","messages":"13040","suppressedMessages":"13041","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13042","messages":"13043","suppressedMessages":"13044","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13045","messages":"13046","suppressedMessages":"13047","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13048","messages":"13049","suppressedMessages":"13050","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13051","messages":"13052","suppressedMessages":"13053","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13054","messages":"13055","suppressedMessages":"13056","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13057","messages":"13058","suppressedMessages":"13059","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13060","messages":"13061","suppressedMessages":"13062","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13063","messages":"13064","suppressedMessages":"13065","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13066","messages":"13067","suppressedMessages":"13068","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13069","messages":"13070","suppressedMessages":"13071","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13072","messages":"13073","suppressedMessages":"13074","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13075","messages":"13076","suppressedMessages":"13077","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13078","messages":"13079","suppressedMessages":"13080","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13081","messages":"13082","suppressedMessages":"13083","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13084","messages":"13085","suppressedMessages":"13086","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13087","messages":"13088","suppressedMessages":"13089","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13090","messages":"13091","suppressedMessages":"13092","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13093","messages":"13094","suppressedMessages":"13095","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13096","messages":"13097","suppressedMessages":"13098","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13099","messages":"13100","suppressedMessages":"13101","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13102","messages":"13103","suppressedMessages":"13104","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13105","messages":"13106","suppressedMessages":"13107","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"13108"},{"filePath":"13109","messages":"13110","suppressedMessages":"13111","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13112","messages":"13113","suppressedMessages":"13114","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"13115"},{"filePath":"13116","messages":"13117","suppressedMessages":"13118","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13119","messages":"13120","suppressedMessages":"13121","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13122","messages":"13123","suppressedMessages":"13124","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13125","messages":"13126","suppressedMessages":"13127","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13128","messages":"13129","suppressedMessages":"13130","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13131","messages":"13132","suppressedMessages":"13133","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13134","messages":"13135","suppressedMessages":"13136","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13137","messages":"13138","suppressedMessages":"13139","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13140","messages":"13141","suppressedMessages":"13142","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13143","messages":"13144","suppressedMessages":"13145","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13146","messages":"13147","suppressedMessages":"13148","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13149","messages":"13150","suppressedMessages":"13151","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13152","messages":"13153","suppressedMessages":"13154","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13155","messages":"13156","suppressedMessages":"13157","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13158","messages":"13159","suppressedMessages":"13160","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13161","messages":"13162","suppressedMessages":"13163","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13164","messages":"13165","suppressedMessages":"13166","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"13167"},{"filePath":"13168","messages":"13169","suppressedMessages":"13170","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13171","messages":"13172","suppressedMessages":"13173","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13174","messages":"13175","suppressedMessages":"13176","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13177","messages":"13178","suppressedMessages":"13179","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13180","messages":"13181","suppressedMessages":"13182","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13183","messages":"13184","suppressedMessages":"13185","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13186","messages":"13187","suppressedMessages":"13188","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13189","messages":"13190","suppressedMessages":"13191","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13192","messages":"13193","suppressedMessages":"13194","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13195","messages":"13196","suppressedMessages":"13197","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13198","messages":"13199","suppressedMessages":"13200","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13201","messages":"13202","suppressedMessages":"13203","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13204","messages":"13205","suppressedMessages":"13206","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13207","messages":"13208","suppressedMessages":"13209","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13210","messages":"13211","suppressedMessages":"13212","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13213","messages":"13214","suppressedMessages":"13215","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13216","messages":"13217","suppressedMessages":"13218","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13219","messages":"13220","suppressedMessages":"13221","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13222","messages":"13223","suppressedMessages":"13224","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13225","messages":"13226","suppressedMessages":"13227","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13228","messages":"13229","suppressedMessages":"13230","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13231","messages":"13232","suppressedMessages":"13233","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13234","messages":"13235","suppressedMessages":"13236","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13237","messages":"13238","suppressedMessages":"13239","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13240","messages":"13241","suppressedMessages":"13242","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13243","messages":"13244","suppressedMessages":"13245","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13246","messages":"13247","suppressedMessages":"13248","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13249","messages":"13250","suppressedMessages":"13251","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13252","messages":"13253","suppressedMessages":"13254","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13255","messages":"13256","suppressedMessages":"13257","errorCount":0,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":"13258"},{"filePath":"13259","messages":"13260","suppressedMessages":"13261","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13262","messages":"13263","suppressedMessages":"13264","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13265","messages":"13266","suppressedMessages":"13267","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13268","messages":"13269","suppressedMessages":"13270","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13271","messages":"13272","suppressedMessages":"13273","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13274","messages":"13275","suppressedMessages":"13276","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13277","messages":"13278","suppressedMessages":"13279","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13280","messages":"13281","suppressedMessages":"13282","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13283","messages":"13284","suppressedMessages":"13285","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13286","messages":"13287","suppressedMessages":"13288","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13289","messages":"13290","suppressedMessages":"13291","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"13292"},{"filePath":"13293","messages":"13294","suppressedMessages":"13295","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13296","messages":"13297","suppressedMessages":"13298","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13299","messages":"13300","suppressedMessages":"13301","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13302","messages":"13303","suppressedMessages":"13304","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13305","messages":"13306","suppressedMessages":"13307","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13308","messages":"13309","suppressedMessages":"13310","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13311","messages":"13312","suppressedMessages":"13313","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13314","messages":"13315","suppressedMessages":"13316","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13317","messages":"13318","suppressedMessages":"13319","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13320","messages":"13321","suppressedMessages":"13322","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13323","messages":"13324","suppressedMessages":"13325","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13326","messages":"13327","suppressedMessages":"13328","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13329","messages":"13330","suppressedMessages":"13331","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"13332"},{"filePath":"13333","messages":"13334","suppressedMessages":"13335","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13336","messages":"13337","suppressedMessages":"13338","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13339","messages":"13340","suppressedMessages":"13341","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13342","messages":"13343","suppressedMessages":"13344","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13345","messages":"13346","suppressedMessages":"13347","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13348","messages":"13349","suppressedMessages":"13350","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13351","messages":"13352","suppressedMessages":"13353","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13354","messages":"13355","suppressedMessages":"13356","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13357","messages":"13358","suppressedMessages":"13359","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13360","messages":"13361","suppressedMessages":"13362","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13363","messages":"13364","suppressedMessages":"13365","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13366","messages":"13367","suppressedMessages":"13368","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13369","messages":"13370","suppressedMessages":"13371","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13372","messages":"13373","suppressedMessages":"13374","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13375","messages":"13376","suppressedMessages":"13377","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13378","messages":"13379","suppressedMessages":"13380","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13381","messages":"13382","suppressedMessages":"13383","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13384","messages":"13385","suppressedMessages":"13386","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13387","messages":"13388","suppressedMessages":"13389","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13390","messages":"13391","suppressedMessages":"13392","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13393","messages":"13394","suppressedMessages":"13395","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13396","messages":"13397","suppressedMessages":"13398","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13399","messages":"13400","suppressedMessages":"13401","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13402","messages":"13403","suppressedMessages":"13404","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13405","messages":"13406","suppressedMessages":"13407","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13408","messages":"13409","suppressedMessages":"13410","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13411","messages":"13412","suppressedMessages":"13413","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13414","messages":"13415","suppressedMessages":"13416","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13417","messages":"13418","suppressedMessages":"13419","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13420","messages":"13421","suppressedMessages":"13422","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13423","messages":"13424","suppressedMessages":"13425","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13426","messages":"13427","suppressedMessages":"13428","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13429","messages":"13430","suppressedMessages":"13431","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13432","messages":"13433","suppressedMessages":"13434","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13435","messages":"13436","suppressedMessages":"13437","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13438","messages":"13439","suppressedMessages":"13440","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13441","messages":"13442","suppressedMessages":"13443","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13444","messages":"13445","suppressedMessages":"13446","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13447","messages":"13448","suppressedMessages":"13449","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"18w142m",{"filePath":"13450","messages":"13451","suppressedMessages":"13452","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13453","messages":"13454","suppressedMessages":"13455","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13456","messages":"13457","suppressedMessages":"13458","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13459","messages":"13460","suppressedMessages":"13461","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13462","messages":"13463","suppressedMessages":"13464","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13465","messages":"13466","suppressedMessages":"13467","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13468","messages":"13469","suppressedMessages":"13470","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13471","messages":"13472","suppressedMessages":"13473","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13474","messages":"13475","suppressedMessages":"13476","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13477","messages":"13478","suppressedMessages":"13479","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13480","messages":"13481","suppressedMessages":"13482","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13483","messages":"13484","suppressedMessages":"13485","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13486","messages":"13487","suppressedMessages":"13488","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13489","messages":"13490","suppressedMessages":"13491","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13492","messages":"13493","suppressedMessages":"13494","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13495","messages":"13496","suppressedMessages":"13497","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13498","messages":"13499","suppressedMessages":"13500","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13501","messages":"13502","suppressedMessages":"13503","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13504","messages":"13505","suppressedMessages":"13506","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13507","messages":"13508","suppressedMessages":"13509","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13510","messages":"13511","suppressedMessages":"13512","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13513","messages":"13514","suppressedMessages":"13515","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13516","messages":"13517","suppressedMessages":"13518","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13519","messages":"13520","suppressedMessages":"13521","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13522","messages":"13523","suppressedMessages":"13524","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13525","messages":"13526","suppressedMessages":"13527","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13528","messages":"13529","suppressedMessages":"13530","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13531","messages":"13532","suppressedMessages":"13533","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"13534"},{"filePath":"13535","messages":"13536","suppressedMessages":"13537","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13538","messages":"13539","suppressedMessages":"13540","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13541","messages":"13542","suppressedMessages":"13543","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13544","messages":"13545","suppressedMessages":"13546","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13547","messages":"13548","suppressedMessages":"13549","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13550","messages":"13551","suppressedMessages":"13552","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13553","messages":"13554","suppressedMessages":"13555","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13556","messages":"13557","suppressedMessages":"13558","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13559","messages":"13560","suppressedMessages":"13561","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13562","messages":"13563","suppressedMessages":"13564","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13565","messages":"13566","suppressedMessages":"13567","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13568","messages":"13569","suppressedMessages":"13570","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13571","messages":"13572","suppressedMessages":"13573","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13574","messages":"13575","suppressedMessages":"13576","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13577","messages":"13578","suppressedMessages":"13579","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13580","messages":"13581","suppressedMessages":"13582","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13583","messages":"13584","suppressedMessages":"13585","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13586","messages":"13587","suppressedMessages":"13588","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13589","messages":"13590","suppressedMessages":"13591","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13592","messages":"13593","suppressedMessages":"13594","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13595","messages":"13596","suppressedMessages":"13597","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13598","messages":"13599","suppressedMessages":"13600","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13601","messages":"13602","suppressedMessages":"13603","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13604","messages":"13605","suppressedMessages":"13606","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13607","messages":"13608","suppressedMessages":"13609","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13610","messages":"13611","suppressedMessages":"13612","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13613","messages":"13614","suppressedMessages":"13615","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13616","messages":"13617","suppressedMessages":"13618","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13619","messages":"13620","suppressedMessages":"13621","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13622","messages":"13623","suppressedMessages":"13624","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13625","messages":"13626","suppressedMessages":"13627","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13628","messages":"13629","suppressedMessages":"13630","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13631","messages":"13632","suppressedMessages":"13633","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13634","messages":"13635","suppressedMessages":"13636","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13637","messages":"13638","suppressedMessages":"13639","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13640","messages":"13641","suppressedMessages":"13642","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13643","messages":"13644","suppressedMessages":"13645","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13646","messages":"13647","suppressedMessages":"13648","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13649","messages":"13650","suppressedMessages":"13651","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13652","messages":"13653","suppressedMessages":"13654","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13655","messages":"13656","suppressedMessages":"13657","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13658","messages":"13659","suppressedMessages":"13660","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13661","messages":"13662","suppressedMessages":"13663","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13664","messages":"13665","suppressedMessages":"13666","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13667","messages":"13668","suppressedMessages":"13669","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13670","messages":"13671","suppressedMessages":"13672","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13673","messages":"13674","suppressedMessages":"13675","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13676","messages":"13677","suppressedMessages":"13678","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13679","messages":"13680","suppressedMessages":"13681","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13682","messages":"13683","suppressedMessages":"13684","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13685","messages":"13686","suppressedMessages":"13687","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13688","messages":"13689","suppressedMessages":"13690","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13691","messages":"13692","suppressedMessages":"13693","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13694","messages":"13695","suppressedMessages":"13696","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13697","messages":"13698","suppressedMessages":"13699","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13700","messages":"13701","suppressedMessages":"13702","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13703","messages":"13704","suppressedMessages":"13705","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13706","messages":"13707","suppressedMessages":"13708","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13709","messages":"13710","suppressedMessages":"13711","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13712","messages":"13713","suppressedMessages":"13714","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13715","messages":"13716","suppressedMessages":"13717","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13718","messages":"13719","suppressedMessages":"13720","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13721","messages":"13722","suppressedMessages":"13723","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13724","messages":"13725","suppressedMessages":"13726","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13727","messages":"13728","suppressedMessages":"13729","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13730","messages":"13731","suppressedMessages":"13732","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13733","messages":"13734","suppressedMessages":"13735","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13736","messages":"13737","suppressedMessages":"13738","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13739","messages":"13740","suppressedMessages":"13741","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13742","messages":"13743","suppressedMessages":"13744","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13745","messages":"13746","suppressedMessages":"13747","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13748","messages":"13749","suppressedMessages":"13750","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13751","messages":"13752","suppressedMessages":"13753","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13754","messages":"13755","suppressedMessages":"13756","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13757","messages":"13758","suppressedMessages":"13759","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13760","messages":"13761","suppressedMessages":"13762","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13763","messages":"13764","suppressedMessages":"13765","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13766","messages":"13767","suppressedMessages":"13768","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13769","messages":"13770","suppressedMessages":"13771","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13772","messages":"13773","suppressedMessages":"13774","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13775","messages":"13776","suppressedMessages":"13777","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13778","messages":"13779","suppressedMessages":"13780","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13781","messages":"13782","suppressedMessages":"13783","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13784","messages":"13785","suppressedMessages":"13786","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13787","messages":"13788","suppressedMessages":"13789","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13790","messages":"13791","suppressedMessages":"13792","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13793","messages":"13794","suppressedMessages":"13795","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13796","messages":"13797","suppressedMessages":"13798","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13799","messages":"13800","suppressedMessages":"13801","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13802","messages":"13803","suppressedMessages":"13804","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13805","messages":"13806","suppressedMessages":"13807","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13808","messages":"13809","suppressedMessages":"13810","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13811","messages":"13812","suppressedMessages":"13813","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13814","messages":"13815","suppressedMessages":"13816","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13817","messages":"13818","suppressedMessages":"13819","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13820","messages":"13821","suppressedMessages":"13822","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13823","messages":"13824","suppressedMessages":"13825","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13826","messages":"13827","suppressedMessages":"13828","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13829","messages":"13830","suppressedMessages":"13831","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13832","messages":"13833","suppressedMessages":"13834","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13835","messages":"13836","suppressedMessages":"13837","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13838","messages":"13839","suppressedMessages":"13840","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13841","messages":"13842","suppressedMessages":"13843","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13844","messages":"13845","suppressedMessages":"13846","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13847","messages":"13848","suppressedMessages":"13849","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13850","messages":"13851","suppressedMessages":"13852","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13853","messages":"13854","suppressedMessages":"13855","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13856","messages":"13857","suppressedMessages":"13858","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13859","messages":"13860","suppressedMessages":"13861","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13862","messages":"13863","suppressedMessages":"13864","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13865","messages":"13866","suppressedMessages":"13867","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13868","messages":"13869","suppressedMessages":"13870","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13871","messages":"13872","suppressedMessages":"13873","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13874","messages":"13875","suppressedMessages":"13876","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13877","messages":"13878","suppressedMessages":"13879","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13880","messages":"13881","suppressedMessages":"13882","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13883","messages":"13884","suppressedMessages":"13885","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13886","messages":"13887","suppressedMessages":"13888","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13889","messages":"13890","suppressedMessages":"13891","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13892","messages":"13893","suppressedMessages":"13894","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13895","messages":"13896","suppressedMessages":"13897","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13898","messages":"13899","suppressedMessages":"13900","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13901","messages":"13902","suppressedMessages":"13903","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13904","messages":"13905","suppressedMessages":"13906","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13907","messages":"13908","suppressedMessages":"13909","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13910","messages":"13911","suppressedMessages":"13912","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13913","messages":"13914","suppressedMessages":"13915","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13916","messages":"13917","suppressedMessages":"13918","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13919","messages":"13920","suppressedMessages":"13921","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13922","messages":"13923","suppressedMessages":"13924","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13925","messages":"13926","suppressedMessages":"13927","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13928","messages":"13929","suppressedMessages":"13930","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13931","messages":"13932","suppressedMessages":"13933","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13934","messages":"13935","suppressedMessages":"13936","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13937","messages":"13938","suppressedMessages":"13939","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13940","messages":"13941","suppressedMessages":"13942","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13943","messages":"13944","suppressedMessages":"13945","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13946","messages":"13947","suppressedMessages":"13948","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13949","messages":"13950","suppressedMessages":"13951","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13952","messages":"13953","suppressedMessages":"13954","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13955","messages":"13956","suppressedMessages":"13957","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13958","messages":"13959","suppressedMessages":"13960","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13961","messages":"13962","suppressedMessages":"13963","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13964","messages":"13965","suppressedMessages":"13966","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13967","messages":"13968","suppressedMessages":"13969","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13970","messages":"13971","suppressedMessages":"13972","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13973","messages":"13974","suppressedMessages":"13975","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13976","messages":"13977","suppressedMessages":"13978","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13979","messages":"13980","suppressedMessages":"13981","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13982","messages":"13983","suppressedMessages":"13984","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13985","messages":"13986","suppressedMessages":"13987","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13988","messages":"13989","suppressedMessages":"13990","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13991","messages":"13992","suppressedMessages":"13993","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13994","messages":"13995","suppressedMessages":"13996","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"13997","messages":"13998","suppressedMessages":"13999","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14000","messages":"14001","suppressedMessages":"14002","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14003","messages":"14004","suppressedMessages":"14005","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14006","messages":"14007","suppressedMessages":"14008","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14009","messages":"14010","suppressedMessages":"14011","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14012","messages":"14013","suppressedMessages":"14014","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14015","messages":"14016","suppressedMessages":"14017","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14018","messages":"14019","suppressedMessages":"14020","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14021","messages":"14022","suppressedMessages":"14023","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14024","messages":"14025","suppressedMessages":"14026","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14027","messages":"14028","suppressedMessages":"14029","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14030","messages":"14031","suppressedMessages":"14032","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14033","messages":"14034","suppressedMessages":"14035","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14036","messages":"14037","suppressedMessages":"14038","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14039","messages":"14040","suppressedMessages":"14041","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14042","messages":"14043","suppressedMessages":"14044","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14045","messages":"14046","suppressedMessages":"14047","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14048","messages":"14049","suppressedMessages":"14050","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14051","messages":"14052","suppressedMessages":"14053","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14054","messages":"14055","suppressedMessages":"14056","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14057","messages":"14058","suppressedMessages":"14059","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14060","messages":"14061","suppressedMessages":"14062","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14063","messages":"14064","suppressedMessages":"14065","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14066","messages":"14067","suppressedMessages":"14068","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14069","messages":"14070","suppressedMessages":"14071","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14072","messages":"14073","suppressedMessages":"14074","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14075","messages":"14076","suppressedMessages":"14077","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14078","messages":"14079","suppressedMessages":"14080","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14081","messages":"14082","suppressedMessages":"14083","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14084","messages":"14085","suppressedMessages":"14086","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14087","messages":"14088","suppressedMessages":"14089","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14090","messages":"14091","suppressedMessages":"14092","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14093","messages":"14094","suppressedMessages":"14095","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14096","messages":"14097","suppressedMessages":"14098","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14099","messages":"14100","suppressedMessages":"14101","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14102","messages":"14103","suppressedMessages":"14104","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14105","messages":"14106","suppressedMessages":"14107","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14108","messages":"14109","suppressedMessages":"14110","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14111","messages":"14112","suppressedMessages":"14113","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14114","messages":"14115","suppressedMessages":"14116","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14117","messages":"14118","suppressedMessages":"14119","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14120","messages":"14121","suppressedMessages":"14122","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14123","messages":"14124","suppressedMessages":"14125","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14126","messages":"14127","suppressedMessages":"14128","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14129","messages":"14130","suppressedMessages":"14131","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14132","messages":"14133","suppressedMessages":"14134","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14135","messages":"14136","suppressedMessages":"14137","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14138","messages":"14139","suppressedMessages":"14140","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14141","messages":"14142","suppressedMessages":"14143","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14144","messages":"14145","suppressedMessages":"14146","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14147","messages":"14148","suppressedMessages":"14149","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14150","messages":"14151","suppressedMessages":"14152","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14153","messages":"14154","suppressedMessages":"14155","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14156","messages":"14157","suppressedMessages":"14158","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14159","messages":"14160","suppressedMessages":"14161","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14162","messages":"14163","suppressedMessages":"14164","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14165","messages":"14166","suppressedMessages":"14167","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14168","messages":"14169","suppressedMessages":"14170","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14171","messages":"14172","suppressedMessages":"14173","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14174","messages":"14175","suppressedMessages":"14176","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14177","messages":"14178","suppressedMessages":"14179","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14180","messages":"14181","suppressedMessages":"14182","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14183","messages":"14184","suppressedMessages":"14185","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14186","messages":"14187","suppressedMessages":"14188","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14189","messages":"14190","suppressedMessages":"14191","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14192","messages":"14193","suppressedMessages":"14194","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14195","messages":"14196","suppressedMessages":"14197","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14198","messages":"14199","suppressedMessages":"14200","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14201","messages":"14202","suppressedMessages":"14203","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14204","messages":"14205","suppressedMessages":"14206","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14207","messages":"14208","suppressedMessages":"14209","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14210","messages":"14211","suppressedMessages":"14212","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14213","messages":"14214","suppressedMessages":"14215","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14216","messages":"14217","suppressedMessages":"14218","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14219","messages":"14220","suppressedMessages":"14221","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14222","messages":"14223","suppressedMessages":"14224","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14225","messages":"14226","suppressedMessages":"14227","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14228","messages":"14229","suppressedMessages":"14230","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14231","messages":"14232","suppressedMessages":"14233","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14234","messages":"14235","suppressedMessages":"14236","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14237","messages":"14238","suppressedMessages":"14239","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14240","messages":"14241","suppressedMessages":"14242","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14243","messages":"14244","suppressedMessages":"14245","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14246","messages":"14247","suppressedMessages":"14248","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14249","messages":"14250","suppressedMessages":"14251","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14252","messages":"14253","suppressedMessages":"14254","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14255","messages":"14256","suppressedMessages":"14257","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14258","messages":"14259","suppressedMessages":"14260","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14261","messages":"14262","suppressedMessages":"14263","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14264","messages":"14265","suppressedMessages":"14266","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14267","messages":"14268","suppressedMessages":"14269","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14270","messages":"14271","suppressedMessages":"14272","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14273","messages":"14274","suppressedMessages":"14275","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14276","messages":"14277","suppressedMessages":"14278","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14279","messages":"14280","suppressedMessages":"14281","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14282","messages":"14283","suppressedMessages":"14284","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14285","messages":"14286","suppressedMessages":"14287","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14288","messages":"14289","suppressedMessages":"14290","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14291","messages":"14292","suppressedMessages":"14293","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14294","messages":"14295","suppressedMessages":"14296","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14297","messages":"14298","suppressedMessages":"14299","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14300","messages":"14301","suppressedMessages":"14302","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14303","messages":"14304","suppressedMessages":"14305","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14306","messages":"14307","suppressedMessages":"14308","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14309","messages":"14310","suppressedMessages":"14311","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14312","messages":"14313","suppressedMessages":"14314","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14315","messages":"14316","suppressedMessages":"14317","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14318","messages":"14319","suppressedMessages":"14320","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14321","messages":"14322","suppressedMessages":"14323","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14324","messages":"14325","suppressedMessages":"14326","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14327","messages":"14328","suppressedMessages":"14329","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14330","messages":"14331","suppressedMessages":"14332","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14333","messages":"14334","suppressedMessages":"14335","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14336","messages":"14337","suppressedMessages":"14338","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14339","messages":"14340","suppressedMessages":"14341","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14342","messages":"14343","suppressedMessages":"14344","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14345","messages":"14346","suppressedMessages":"14347","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14348","messages":"14349","suppressedMessages":"14350","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14351","messages":"14352","suppressedMessages":"14353","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14354","messages":"14355","suppressedMessages":"14356","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14357","messages":"14358","suppressedMessages":"14359","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14360","messages":"14361","suppressedMessages":"14362","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14363","messages":"14364","suppressedMessages":"14365","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14366","messages":"14367","suppressedMessages":"14368","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14369","messages":"14370","suppressedMessages":"14371","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14372","messages":"14373","suppressedMessages":"14374","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14375","messages":"14376","suppressedMessages":"14377","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14378","messages":"14379","suppressedMessages":"14380","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14381","messages":"14382","suppressedMessages":"14383","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14384","messages":"14385","suppressedMessages":"14386","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14387","messages":"14388","suppressedMessages":"14389","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14390","messages":"14391","suppressedMessages":"14392","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14393","messages":"14394","suppressedMessages":"14395","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14396","messages":"14397","suppressedMessages":"14398","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14399","messages":"14400","suppressedMessages":"14401","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14402","messages":"14403","suppressedMessages":"14404","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14405","messages":"14406","suppressedMessages":"14407","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14408","messages":"14409","suppressedMessages":"14410","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14411","messages":"14412","suppressedMessages":"14413","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14414","messages":"14415","suppressedMessages":"14416","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14417","messages":"14418","suppressedMessages":"14419","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14420","messages":"14421","suppressedMessages":"14422","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14423","messages":"14424","suppressedMessages":"14425","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14426","messages":"14427","suppressedMessages":"14428","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14429","messages":"14430","suppressedMessages":"14431","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14432","messages":"14433","suppressedMessages":"14434","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14435","messages":"14436","suppressedMessages":"14437","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14438","messages":"14439","suppressedMessages":"14440","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14441","messages":"14442","suppressedMessages":"14443","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14444","messages":"14445","suppressedMessages":"14446","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14447","messages":"14448","suppressedMessages":"14449","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14450","messages":"14451","suppressedMessages":"14452","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14453","messages":"14454","suppressedMessages":"14455","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14456","messages":"14457","suppressedMessages":"14458","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14459","messages":"14460","suppressedMessages":"14461","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14462","messages":"14463","suppressedMessages":"14464","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14465","messages":"14466","suppressedMessages":"14467","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14468","messages":"14469","suppressedMessages":"14470","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14471","messages":"14472","suppressedMessages":"14473","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14474","messages":"14475","suppressedMessages":"14476","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14477","messages":"14478","suppressedMessages":"14479","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14480","messages":"14481","suppressedMessages":"14482","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14483","messages":"14484","suppressedMessages":"14485","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14486","messages":"14487","suppressedMessages":"14488","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14489","messages":"14490","suppressedMessages":"14491","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14492","messages":"14493","suppressedMessages":"14494","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14495","messages":"14496","suppressedMessages":"14497","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14498","messages":"14499","suppressedMessages":"14500","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14501","messages":"14502","suppressedMessages":"14503","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14504","messages":"14505","suppressedMessages":"14506","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14507","messages":"14508","suppressedMessages":"14509","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14510","messages":"14511","suppressedMessages":"14512","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14513","messages":"14514","suppressedMessages":"14515","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14516","messages":"14517","suppressedMessages":"14518","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14519","messages":"14520","suppressedMessages":"14521","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14522","messages":"14523","suppressedMessages":"14524","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14525","messages":"14526","suppressedMessages":"14527","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14528","messages":"14529","suppressedMessages":"14530","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14531","messages":"14532","suppressedMessages":"14533","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14534","messages":"14535","suppressedMessages":"14536","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14537","messages":"14538","suppressedMessages":"14539","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14540","messages":"14541","suppressedMessages":"14542","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14543","messages":"14544","suppressedMessages":"14545","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14546","messages":"14547","suppressedMessages":"14548","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14549","messages":"14550","suppressedMessages":"14551","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14552","messages":"14553","suppressedMessages":"14554","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14555","messages":"14556","suppressedMessages":"14557","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14558","messages":"14559","suppressedMessages":"14560","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14561","messages":"14562","suppressedMessages":"14563","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14564","messages":"14565","suppressedMessages":"14566","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14567","messages":"14568","suppressedMessages":"14569","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14570","messages":"14571","suppressedMessages":"14572","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14573","messages":"14574","suppressedMessages":"14575","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14576","messages":"14577","suppressedMessages":"14578","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14579","messages":"14580","suppressedMessages":"14581","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14582","messages":"14583","suppressedMessages":"14584","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14585","messages":"14586","suppressedMessages":"14587","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14588","messages":"14589","suppressedMessages":"14590","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14591","messages":"14592","suppressedMessages":"14593","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14594","messages":"14595","suppressedMessages":"14596","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14597","messages":"14598","suppressedMessages":"14599","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14600","messages":"14601","suppressedMessages":"14602","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14603","messages":"14604","suppressedMessages":"14605","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14606","messages":"14607","suppressedMessages":"14608","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14609","messages":"14610","suppressedMessages":"14611","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14612","messages":"14613","suppressedMessages":"14614","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14615","messages":"14616","suppressedMessages":"14617","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14618","messages":"14619","suppressedMessages":"14620","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14621","messages":"14622","suppressedMessages":"14623","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14624","messages":"14625","suppressedMessages":"14626","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14627","messages":"14628","suppressedMessages":"14629","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14630","messages":"14631","suppressedMessages":"14632","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14633","messages":"14634","suppressedMessages":"14635","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14636","messages":"14637","suppressedMessages":"14638","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14639","messages":"14640","suppressedMessages":"14641","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14642","messages":"14643","suppressedMessages":"14644","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14645","messages":"14646","suppressedMessages":"14647","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14648","messages":"14649","suppressedMessages":"14650","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14651","messages":"14652","suppressedMessages":"14653","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14654","messages":"14655","suppressedMessages":"14656","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14657","messages":"14658","suppressedMessages":"14659","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14660","messages":"14661","suppressedMessages":"14662","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14663","messages":"14664","suppressedMessages":"14665","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14666","messages":"14667","suppressedMessages":"14668","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14669","messages":"14670","suppressedMessages":"14671","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14672","messages":"14673","suppressedMessages":"14674","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14675","messages":"14676","suppressedMessages":"14677","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14678","messages":"14679","suppressedMessages":"14680","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14681","messages":"14682","suppressedMessages":"14683","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14684","messages":"14685","suppressedMessages":"14686","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14687","messages":"14688","suppressedMessages":"14689","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14690","messages":"14691","suppressedMessages":"14692","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14693","messages":"14694","suppressedMessages":"14695","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14696","messages":"14697","suppressedMessages":"14698","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14699","messages":"14700","suppressedMessages":"14701","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14702","messages":"14703","suppressedMessages":"14704","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14705","messages":"14706","suppressedMessages":"14707","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14708","messages":"14709","suppressedMessages":"14710","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14711","messages":"14712","suppressedMessages":"14713","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14714","messages":"14715","suppressedMessages":"14716","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14717","messages":"14718","suppressedMessages":"14719","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14720","messages":"14721","suppressedMessages":"14722","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14723","messages":"14724","suppressedMessages":"14725","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14726","messages":"14727","suppressedMessages":"14728","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14729","messages":"14730","suppressedMessages":"14731","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14732","messages":"14733","suppressedMessages":"14734","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14735","messages":"14736","suppressedMessages":"14737","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14738","messages":"14739","suppressedMessages":"14740","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14741","messages":"14742","suppressedMessages":"14743","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14744","messages":"14745","suppressedMessages":"14746","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14747","messages":"14748","suppressedMessages":"14749","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14750","messages":"14751","suppressedMessages":"14752","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14753","messages":"14754","suppressedMessages":"14755","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14756","messages":"14757","suppressedMessages":"14758","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14759","messages":"14760","suppressedMessages":"14761","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14762","messages":"14763","suppressedMessages":"14764","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14765","messages":"14766","suppressedMessages":"14767","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"14768"},{"filePath":"14769","messages":"14770","suppressedMessages":"14771","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14772","messages":"14773","suppressedMessages":"14774","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14775","messages":"14776","suppressedMessages":"14777","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14778","messages":"14779","suppressedMessages":"14780","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14781","messages":"14782","suppressedMessages":"14783","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14784","messages":"14785","suppressedMessages":"14786","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14787","messages":"14788","suppressedMessages":"14789","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14790","messages":"14791","suppressedMessages":"14792","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"14793"},{"filePath":"14794","messages":"14795","suppressedMessages":"14796","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14797","messages":"14798","suppressedMessages":"14799","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14800","messages":"14801","suppressedMessages":"14802","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14803","messages":"14804","suppressedMessages":"14805","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14806","messages":"14807","suppressedMessages":"14808","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14809","messages":"14810","suppressedMessages":"14811","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14812","messages":"14813","suppressedMessages":"14814","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14815","messages":"14816","suppressedMessages":"14817","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14818","messages":"14819","suppressedMessages":"14820","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14821","messages":"14822","suppressedMessages":"14823","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14824","messages":"14825","suppressedMessages":"14826","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14827","messages":"14828","suppressedMessages":"14829","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14830","messages":"14831","suppressedMessages":"14832","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14833","messages":"14834","suppressedMessages":"14835","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14836","messages":"14837","suppressedMessages":"14838","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14839","messages":"14840","suppressedMessages":"14841","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14842","messages":"14843","suppressedMessages":"14844","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14845","messages":"14846","suppressedMessages":"14847","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"14848"},{"filePath":"14849","messages":"14850","suppressedMessages":"14851","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14852","messages":"14853","suppressedMessages":"14854","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14855","messages":"14856","suppressedMessages":"14857","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14858","messages":"14859","suppressedMessages":"14860","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14861","messages":"14862","suppressedMessages":"14863","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14864","messages":"14865","suppressedMessages":"14866","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14867","messages":"14868","suppressedMessages":"14869","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14870","messages":"14871","suppressedMessages":"14872","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14873","messages":"14874","suppressedMessages":"14875","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14876","messages":"14877","suppressedMessages":"14878","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14879","messages":"14880","suppressedMessages":"14881","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14882","messages":"14883","suppressedMessages":"14884","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14885","messages":"14886","suppressedMessages":"14887","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14888","messages":"14889","suppressedMessages":"14890","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14891","messages":"14892","suppressedMessages":"14893","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14894","messages":"14895","suppressedMessages":"14896","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14897","messages":"14898","suppressedMessages":"14899","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14900","messages":"14901","suppressedMessages":"14902","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14903","messages":"14904","suppressedMessages":"14905","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14906","messages":"14907","suppressedMessages":"14908","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14909","messages":"14910","suppressedMessages":"14911","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14912","messages":"14913","suppressedMessages":"14914","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14915","messages":"14916","suppressedMessages":"14917","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14918","messages":"14919","suppressedMessages":"14920","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14921","messages":"14922","suppressedMessages":"14923","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14924","messages":"14925","suppressedMessages":"14926","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14927","messages":"14928","suppressedMessages":"14929","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14930","messages":"14931","suppressedMessages":"14932","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14933","messages":"14934","suppressedMessages":"14935","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14936","messages":"14937","suppressedMessages":"14938","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14939","messages":"14940","suppressedMessages":"14941","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14942","messages":"14943","suppressedMessages":"14944","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14945","messages":"14946","suppressedMessages":"14947","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14948","messages":"14949","suppressedMessages":"14950","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14951","messages":"14952","suppressedMessages":"14953","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14954","messages":"14955","suppressedMessages":"14956","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14957","messages":"14958","suppressedMessages":"14959","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14960","messages":"14961","suppressedMessages":"14962","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14963","messages":"14964","suppressedMessages":"14965","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"14966"},{"filePath":"14967","messages":"14968","suppressedMessages":"14969","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14970","messages":"14971","suppressedMessages":"14972","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14973","messages":"14974","suppressedMessages":"14975","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14976","messages":"14977","suppressedMessages":"14978","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14979","messages":"14980","suppressedMessages":"14981","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14982","messages":"14983","suppressedMessages":"14984","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14985","messages":"14986","suppressedMessages":"14987","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14988","messages":"14989","suppressedMessages":"14990","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14991","messages":"14992","suppressedMessages":"14993","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14994","messages":"14995","suppressedMessages":"14996","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14997","messages":"14998","suppressedMessages":"14999","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15000","messages":"15001","suppressedMessages":"15002","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15003","messages":"15004","suppressedMessages":"15005","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15006","messages":"15007","suppressedMessages":"15008","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15009","messages":"15010","suppressedMessages":"15011","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15012","messages":"15013","suppressedMessages":"15014","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15015","messages":"15016","suppressedMessages":"15017","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15018","messages":"15019","suppressedMessages":"15020","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15021","messages":"15022","suppressedMessages":"15023","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15024","messages":"15025","suppressedMessages":"15026","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15027","messages":"15028","suppressedMessages":"15029","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15030","messages":"15031","suppressedMessages":"15032","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15033","messages":"15034","suppressedMessages":"15035","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15036","messages":"15037","suppressedMessages":"15038","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15039","messages":"15040","suppressedMessages":"15041","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15042","messages":"15043","suppressedMessages":"15044","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15045","messages":"15046","suppressedMessages":"15047","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15048","messages":"15049","suppressedMessages":"15050","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15051","messages":"15052","suppressedMessages":"15053","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15054","messages":"15055","suppressedMessages":"15056","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15057","messages":"15058","suppressedMessages":"15059","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15060","messages":"15061","suppressedMessages":"15062","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15063","messages":"15064","suppressedMessages":"15065","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15066","messages":"15067","suppressedMessages":"15068","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15069","messages":"15070","suppressedMessages":"15071","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15072","messages":"15073","suppressedMessages":"15074","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15075","messages":"15076","suppressedMessages":"15077","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15078","messages":"15079","suppressedMessages":"15080","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15081","messages":"15082","suppressedMessages":"15083","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15084","messages":"15085","suppressedMessages":"15086","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15087","messages":"15088","suppressedMessages":"15089","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15090","messages":"15091","suppressedMessages":"15092","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15093","messages":"15094","suppressedMessages":"15095","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15096","messages":"15097","suppressedMessages":"15098","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15099","messages":"15100","suppressedMessages":"15101","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15102","messages":"15103","suppressedMessages":"15104","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15105","messages":"15106","suppressedMessages":"15107","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15108","messages":"15109","suppressedMessages":"15110","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15111","messages":"15112","suppressedMessages":"15113","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15114","messages":"15115","suppressedMessages":"15116","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15117","messages":"15118","suppressedMessages":"15119","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15120","messages":"15121","suppressedMessages":"15122","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15123","messages":"15124","suppressedMessages":"15125","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15126","messages":"15127","suppressedMessages":"15128","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15129","messages":"15130","suppressedMessages":"15131","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15132","messages":"15133","suppressedMessages":"15134","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15135","messages":"15136","suppressedMessages":"15137","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15138","messages":"15139","suppressedMessages":"15140","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15141","messages":"15142","suppressedMessages":"15143","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15144","messages":"15145","suppressedMessages":"15146","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15147","messages":"15148","suppressedMessages":"15149","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15150","messages":"15151","suppressedMessages":"15152","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15153","messages":"15154","suppressedMessages":"15155","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15156","messages":"15157","suppressedMessages":"15158","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15159","messages":"15160","suppressedMessages":"15161","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15162","messages":"15163","suppressedMessages":"15164","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15165","messages":"15166","suppressedMessages":"15167","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15168","messages":"15169","suppressedMessages":"15170","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15171","messages":"15172","suppressedMessages":"15173","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15174","messages":"15175","suppressedMessages":"15176","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15177","messages":"15178","suppressedMessages":"15179","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15180","messages":"15181","suppressedMessages":"15182","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15183","messages":"15184","suppressedMessages":"15185","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15186","messages":"15187","suppressedMessages":"15188","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15189","messages":"15190","suppressedMessages":"15191","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15192","messages":"15193","suppressedMessages":"15194","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15195","messages":"15196","suppressedMessages":"15197","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15198","messages":"15199","suppressedMessages":"15200","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15201","messages":"15202","suppressedMessages":"15203","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15204","messages":"15205","suppressedMessages":"15206","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15207","messages":"15208","suppressedMessages":"15209","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15210","messages":"15211","suppressedMessages":"15212","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15213","messages":"15214","suppressedMessages":"15215","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15216","messages":"15217","suppressedMessages":"15218","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15219","messages":"15220","suppressedMessages":"15221","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15222","messages":"15223","suppressedMessages":"15224","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15225","messages":"15226","suppressedMessages":"15227","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15228","messages":"15229","suppressedMessages":"15230","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15231","messages":"15232","suppressedMessages":"15233","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15234","messages":"15235","suppressedMessages":"15236","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15237","messages":"15238","suppressedMessages":"15239","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15240","messages":"15241","suppressedMessages":"15242","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15243","messages":"15244","suppressedMessages":"15245","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15246","messages":"15247","suppressedMessages":"15248","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15249","messages":"15250","suppressedMessages":"15251","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15252","messages":"15253","suppressedMessages":"15254","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15255","messages":"15256","suppressedMessages":"15257","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15258","messages":"15259","suppressedMessages":"15260","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15261","messages":"15262","suppressedMessages":"15263","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15264","messages":"15265","suppressedMessages":"15266","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15267","messages":"15268","suppressedMessages":"15269","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15270","messages":"15271","suppressedMessages":"15272","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15273","messages":"15274","suppressedMessages":"15275","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15276","messages":"15277","suppressedMessages":"15278","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15279","messages":"15280","suppressedMessages":"15281","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15282","messages":"15283","suppressedMessages":"15284","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15285","messages":"15286","suppressedMessages":"15287","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15288","messages":"15289","suppressedMessages":"15290","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15291","messages":"15292","suppressedMessages":"15293","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15294","messages":"15295","suppressedMessages":"15296","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15297","messages":"15298","suppressedMessages":"15299","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15300","messages":"15301","suppressedMessages":"15302","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15303","messages":"15304","suppressedMessages":"15305","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15306","messages":"15307","suppressedMessages":"15308","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15309","messages":"15310","suppressedMessages":"15311","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15312","messages":"15313","suppressedMessages":"15314","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15315","messages":"15316","suppressedMessages":"15317","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15318","messages":"15319","suppressedMessages":"15320","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15321","messages":"15322","suppressedMessages":"15323","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15324","messages":"15325","suppressedMessages":"15326","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15327","messages":"15328","suppressedMessages":"15329","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15330","messages":"15331","suppressedMessages":"15332","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15333","messages":"15334","suppressedMessages":"15335","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"15336"},{"filePath":"15337","messages":"15338","suppressedMessages":"15339","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15340","messages":"15341","suppressedMessages":"15342","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15343","messages":"15344","suppressedMessages":"15345","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15346","messages":"15347","suppressedMessages":"15348","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15349","messages":"15350","suppressedMessages":"15351","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15352","messages":"15353","suppressedMessages":"15354","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15355","messages":"15356","suppressedMessages":"15357","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15358","messages":"15359","suppressedMessages":"15360","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15361","messages":"15362","suppressedMessages":"15363","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15364","messages":"15365","suppressedMessages":"15366","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15367","messages":"15368","suppressedMessages":"15369","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15370","messages":"15371","suppressedMessages":"15372","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15373","messages":"15374","suppressedMessages":"15375","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15376","messages":"15377","suppressedMessages":"15378","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15379","messages":"15380","suppressedMessages":"15381","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15382","messages":"15383","suppressedMessages":"15384","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15385","messages":"15386","suppressedMessages":"15387","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15388","messages":"15389","suppressedMessages":"15390","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15391","messages":"15392","suppressedMessages":"15393","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15394","messages":"15395","suppressedMessages":"15396","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15397","messages":"15398","suppressedMessages":"15399","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15400","messages":"15401","suppressedMessages":"15402","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15403","messages":"15404","suppressedMessages":"15405","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15406","messages":"15407","suppressedMessages":"15408","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15409","messages":"15410","suppressedMessages":"15411","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15412","messages":"15413","suppressedMessages":"15414","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15415","messages":"15416","suppressedMessages":"15417","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15418","messages":"15419","suppressedMessages":"15420","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15421","messages":"15422","suppressedMessages":"15423","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15424","messages":"15425","suppressedMessages":"15426","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15427","messages":"15428","suppressedMessages":"15429","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15430","messages":"15431","suppressedMessages":"15432","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15433","messages":"15434","suppressedMessages":"15435","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15436","messages":"15437","suppressedMessages":"15438","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15439","messages":"15440","suppressedMessages":"15441","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15442","messages":"15443","suppressedMessages":"15444","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15445","messages":"15446","suppressedMessages":"15447","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15448","messages":"15449","suppressedMessages":"15450","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15451","messages":"15452","suppressedMessages":"15453","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15454","messages":"15455","suppressedMessages":"15456","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15457","messages":"15458","suppressedMessages":"15459","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15460","messages":"15461","suppressedMessages":"15462","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15463","messages":"15464","suppressedMessages":"15465","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15466","messages":"15467","suppressedMessages":"15468","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15469","messages":"15470","suppressedMessages":"15471","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15472","messages":"15473","suppressedMessages":"15474","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15475","messages":"15476","suppressedMessages":"15477","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15478","messages":"15479","suppressedMessages":"15480","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15481","messages":"15482","suppressedMessages":"15483","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15484","messages":"15485","suppressedMessages":"15486","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15487","messages":"15488","suppressedMessages":"15489","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15490","messages":"15491","suppressedMessages":"15492","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15493","messages":"15494","suppressedMessages":"15495","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15496","messages":"15497","suppressedMessages":"15498","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15499","messages":"15500","suppressedMessages":"15501","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15502","messages":"15503","suppressedMessages":"15504","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15505","messages":"15506","suppressedMessages":"15507","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15508","messages":"15509","suppressedMessages":"15510","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15511","messages":"15512","suppressedMessages":"15513","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15514","messages":"15515","suppressedMessages":"15516","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15517","messages":"15518","suppressedMessages":"15519","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15520","messages":"15521","suppressedMessages":"15522","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15523","messages":"15524","suppressedMessages":"15525","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15526","messages":"15527","suppressedMessages":"15528","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15529","messages":"15530","suppressedMessages":"15531","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15532","messages":"15533","suppressedMessages":"15534","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15535","messages":"15536","suppressedMessages":"15537","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15538","messages":"15539","suppressedMessages":"15540","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15541","messages":"15542","suppressedMessages":"15543","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15544","messages":"15545","suppressedMessages":"15546","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15547","messages":"15548","suppressedMessages":"15549","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15550","messages":"15551","suppressedMessages":"15552","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15553","messages":"15554","suppressedMessages":"15555","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15556","messages":"15557","suppressedMessages":"15558","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15559","messages":"15560","suppressedMessages":"15561","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15562","messages":"15563","suppressedMessages":"15564","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15565","messages":"15566","suppressedMessages":"15567","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15568","messages":"15569","suppressedMessages":"15570","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15571","messages":"15572","suppressedMessages":"15573","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15574","messages":"15575","suppressedMessages":"15576","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15577","messages":"15578","suppressedMessages":"15579","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15580","messages":"15581","suppressedMessages":"15582","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15583","messages":"15584","suppressedMessages":"15585","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15586","messages":"15587","suppressedMessages":"15588","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15589","messages":"15590","suppressedMessages":"15591","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15592","messages":"15593","suppressedMessages":"15594","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15595","messages":"15596","suppressedMessages":"15597","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15598","messages":"15599","suppressedMessages":"15600","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15601","messages":"15602","suppressedMessages":"15603","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15604","messages":"15605","suppressedMessages":"15606","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15607","messages":"15608","suppressedMessages":"15609","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15610","messages":"15611","suppressedMessages":"15612","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15613","messages":"15614","suppressedMessages":"15615","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15616","messages":"15617","suppressedMessages":"15618","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15619","messages":"15620","suppressedMessages":"15621","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15622","messages":"15623","suppressedMessages":"15624","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15625","messages":"15626","suppressedMessages":"15627","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15628","messages":"15629","suppressedMessages":"15630","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15631","messages":"15632","suppressedMessages":"15633","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15634","messages":"15635","suppressedMessages":"15636","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15637","messages":"15638","suppressedMessages":"15639","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15640","messages":"15641","suppressedMessages":"15642","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15643","messages":"15644","suppressedMessages":"15645","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15646","messages":"15647","suppressedMessages":"15648","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15649","messages":"15650","suppressedMessages":"15651","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15652","messages":"15653","suppressedMessages":"15654","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15655","messages":"15656","suppressedMessages":"15657","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15658","messages":"15659","suppressedMessages":"15660","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15661","messages":"15662","suppressedMessages":"15663","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15664","messages":"15665","suppressedMessages":"15666","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15667","messages":"15668","suppressedMessages":"15669","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15670","messages":"15671","suppressedMessages":"15672","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15673","messages":"15674","suppressedMessages":"15675","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15676","messages":"15677","suppressedMessages":"15678","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15679","messages":"15680","suppressedMessages":"15681","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"15682"},{"filePath":"15683","messages":"15684","suppressedMessages":"15685","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"15686"},{"filePath":"15687","messages":"15688","suppressedMessages":"15689","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15690","messages":"15691","suppressedMessages":"15692","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"15693"},{"filePath":"15694","messages":"15695","suppressedMessages":"15696","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15697","messages":"15698","suppressedMessages":"15699","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"15700"},{"filePath":"15701","messages":"15702","suppressedMessages":"15703","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15704","messages":"15705","suppressedMessages":"15706","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"15707"},{"filePath":"15708","messages":"15709","suppressedMessages":"15710","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"15711"},{"filePath":"15712","messages":"15713","suppressedMessages":"15714","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15715","messages":"15716","suppressedMessages":"15717","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15718","messages":"15719","suppressedMessages":"15720","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15721","messages":"15722","suppressedMessages":"15723","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15724","messages":"15725","suppressedMessages":"15726","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15727","messages":"15728","suppressedMessages":"15729","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15730","messages":"15731","suppressedMessages":"15732","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15733","messages":"15734","suppressedMessages":"15735","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15736","messages":"15737","suppressedMessages":"15738","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15739","messages":"15740","suppressedMessages":"15741","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15742","messages":"15743","suppressedMessages":"15744","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15745","messages":"15746","suppressedMessages":"15747","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15748","messages":"15749","suppressedMessages":"15750","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15751","messages":"15752","suppressedMessages":"15753","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15754","messages":"15755","suppressedMessages":"15756","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15757","messages":"15758","suppressedMessages":"15759","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15760","messages":"15761","suppressedMessages":"15762","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15763","messages":"15764","suppressedMessages":"15765","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15766","messages":"15767","suppressedMessages":"15768","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15769","messages":"15770","suppressedMessages":"15771","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15772","messages":"15773","suppressedMessages":"15774","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15775","messages":"15776","suppressedMessages":"15777","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15778","messages":"15779","suppressedMessages":"15780","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15781","messages":"15782","suppressedMessages":"15783","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15784","messages":"15785","suppressedMessages":"15786","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15787","messages":"15788","suppressedMessages":"15789","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15790","messages":"15791","suppressedMessages":"15792","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15793","messages":"15794","suppressedMessages":"15795","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15796","messages":"15797","suppressedMessages":"15798","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15799","messages":"15800","suppressedMessages":"15801","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15802","messages":"15803","suppressedMessages":"15804","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15805","messages":"15806","suppressedMessages":"15807","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15808","messages":"15809","suppressedMessages":"15810","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15811","messages":"15812","suppressedMessages":"15813","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15814","messages":"15815","suppressedMessages":"15816","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15817","messages":"15818","suppressedMessages":"15819","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15820","messages":"15821","suppressedMessages":"15822","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15823","messages":"15824","suppressedMessages":"15825","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15826","messages":"15827","suppressedMessages":"15828","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15829","messages":"15830","suppressedMessages":"15831","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15832","messages":"15833","suppressedMessages":"15834","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15835","messages":"15836","suppressedMessages":"15837","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15838","messages":"15839","suppressedMessages":"15840","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15841","messages":"15842","suppressedMessages":"15843","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15844","messages":"15845","suppressedMessages":"15846","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15847","messages":"15848","suppressedMessages":"15849","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15850","messages":"15851","suppressedMessages":"15852","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15853","messages":"15854","suppressedMessages":"15855","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15856","messages":"15857","suppressedMessages":"15858","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15859","messages":"15860","suppressedMessages":"15861","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15862","messages":"15863","suppressedMessages":"15864","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15865","messages":"15866","suppressedMessages":"15867","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15868","messages":"15869","suppressedMessages":"15870","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15871","messages":"15872","suppressedMessages":"15873","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15874","messages":"15875","suppressedMessages":"15876","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15877","messages":"15878","suppressedMessages":"15879","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15880","messages":"15881","suppressedMessages":"15882","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15883","messages":"15884","suppressedMessages":"15885","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15886","messages":"15887","suppressedMessages":"15888","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15889","messages":"15890","suppressedMessages":"15891","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15892","messages":"15893","suppressedMessages":"15894","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15895","messages":"15896","suppressedMessages":"15897","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15898","messages":"15899","suppressedMessages":"15900","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15901","messages":"15902","suppressedMessages":"15903","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15904","messages":"15905","suppressedMessages":"15906","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15907","messages":"15908","suppressedMessages":"15909","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15910","messages":"15911","suppressedMessages":"15912","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15913","messages":"15914","suppressedMessages":"15915","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15916","messages":"15917","suppressedMessages":"15918","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15919","messages":"15920","suppressedMessages":"15921","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15922","messages":"15923","suppressedMessages":"15924","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15925","messages":"15926","suppressedMessages":"15927","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15928","messages":"15929","suppressedMessages":"15930","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15931","messages":"15932","suppressedMessages":"15933","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15934","messages":"15935","suppressedMessages":"15936","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15937","messages":"15938","suppressedMessages":"15939","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15940","messages":"15941","suppressedMessages":"15942","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15943","messages":"15944","suppressedMessages":"15945","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15946","messages":"15947","suppressedMessages":"15948","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15949","messages":"15950","suppressedMessages":"15951","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15952","messages":"15953","suppressedMessages":"15954","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15955","messages":"15956","suppressedMessages":"15957","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15958","messages":"15959","suppressedMessages":"15960","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15961","messages":"15962","suppressedMessages":"15963","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15964","messages":"15965","suppressedMessages":"15966","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15967","messages":"15968","suppressedMessages":"15969","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15970","messages":"15971","suppressedMessages":"15972","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15973","messages":"15974","suppressedMessages":"15975","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15976","messages":"15977","suppressedMessages":"15978","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15979","messages":"15980","suppressedMessages":"15981","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15982","messages":"15983","suppressedMessages":"15984","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15985","messages":"15986","suppressedMessages":"15987","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15988","messages":"15989","suppressedMessages":"15990","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15991","messages":"15992","suppressedMessages":"15993","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15994","messages":"15995","suppressedMessages":"15996","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"15997","messages":"15998","suppressedMessages":"15999","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16000","messages":"16001","suppressedMessages":"16002","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16003","messages":"16004","suppressedMessages":"16005","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16006","messages":"16007","suppressedMessages":"16008","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16009","messages":"16010","suppressedMessages":"16011","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16012","messages":"16013","suppressedMessages":"16014","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16015","messages":"16016","suppressedMessages":"16017","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16018","messages":"16019","suppressedMessages":"16020","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16021","messages":"16022","suppressedMessages":"16023","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16024","messages":"16025","suppressedMessages":"16026","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16027","messages":"16028","suppressedMessages":"16029","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16030","messages":"16031","suppressedMessages":"16032","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16033","messages":"16034","suppressedMessages":"16035","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16036","messages":"16037","suppressedMessages":"16038","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16039","messages":"16040","suppressedMessages":"16041","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16042","messages":"16043","suppressedMessages":"16044","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16045","messages":"16046","suppressedMessages":"16047","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16048","messages":"16049","suppressedMessages":"16050","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16051","messages":"16052","suppressedMessages":"16053","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16054","messages":"16055","suppressedMessages":"16056","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16057","messages":"16058","suppressedMessages":"16059","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16060","messages":"16061","suppressedMessages":"16062","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16063","messages":"16064","suppressedMessages":"16065","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16066","messages":"16067","suppressedMessages":"16068","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16069","messages":"16070","suppressedMessages":"16071","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16072","messages":"16073","suppressedMessages":"16074","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16075","messages":"16076","suppressedMessages":"16077","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16078","messages":"16079","suppressedMessages":"16080","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16081","messages":"16082","suppressedMessages":"16083","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16084","messages":"16085","suppressedMessages":"16086","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16087","messages":"16088","suppressedMessages":"16089","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16090","messages":"16091","suppressedMessages":"16092","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16093","messages":"16094","suppressedMessages":"16095","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16096","messages":"16097","suppressedMessages":"16098","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16099","messages":"16100","suppressedMessages":"16101","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16102","messages":"16103","suppressedMessages":"16104","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16105","messages":"16106","suppressedMessages":"16107","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16108","messages":"16109","suppressedMessages":"16110","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16111","messages":"16112","suppressedMessages":"16113","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16114","messages":"16115","suppressedMessages":"16116","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16117","messages":"16118","suppressedMessages":"16119","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16120","messages":"16121","suppressedMessages":"16122","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16123","messages":"16124","suppressedMessages":"16125","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16126","messages":"16127","suppressedMessages":"16128","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16129","messages":"16130","suppressedMessages":"16131","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16132","messages":"16133","suppressedMessages":"16134","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16135","messages":"16136","suppressedMessages":"16137","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16138","messages":"16139","suppressedMessages":"16140","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16141","messages":"16142","suppressedMessages":"16143","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16144","messages":"16145","suppressedMessages":"16146","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16147","messages":"16148","suppressedMessages":"16149","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16150","messages":"16151","suppressedMessages":"16152","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16153","messages":"16154","suppressedMessages":"16155","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16156","messages":"16157","suppressedMessages":"16158","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16159","messages":"16160","suppressedMessages":"16161","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16162","messages":"16163","suppressedMessages":"16164","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16165","messages":"16166","suppressedMessages":"16167","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16168","messages":"16169","suppressedMessages":"16170","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16171","messages":"16172","suppressedMessages":"16173","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16174","messages":"16175","suppressedMessages":"16176","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16177","messages":"16178","suppressedMessages":"16179","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16180","messages":"16181","suppressedMessages":"16182","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16183","messages":"16184","suppressedMessages":"16185","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16186","messages":"16187","suppressedMessages":"16188","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16189","messages":"16190","suppressedMessages":"16191","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16192","messages":"16193","suppressedMessages":"16194","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16195","messages":"16196","suppressedMessages":"16197","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16198","messages":"16199","suppressedMessages":"16200","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16201","messages":"16202","suppressedMessages":"16203","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16204","messages":"16205","suppressedMessages":"16206","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16207","messages":"16208","suppressedMessages":"16209","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16210","messages":"16211","suppressedMessages":"16212","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16213","messages":"16214","suppressedMessages":"16215","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16216","messages":"16217","suppressedMessages":"16218","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16219","messages":"16220","suppressedMessages":"16221","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16222","messages":"16223","suppressedMessages":"16224","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16225","messages":"16226","suppressedMessages":"16227","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16228","messages":"16229","suppressedMessages":"16230","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16231","messages":"16232","suppressedMessages":"16233","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16234","messages":"16235","suppressedMessages":"16236","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16237","messages":"16238","suppressedMessages":"16239","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16240","messages":"16241","suppressedMessages":"16242","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16243","messages":"16244","suppressedMessages":"16245","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16246","messages":"16247","suppressedMessages":"16248","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16249","messages":"16250","suppressedMessages":"16251","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16252","messages":"16253","suppressedMessages":"16254","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16255","messages":"16256","suppressedMessages":"16257","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16258","messages":"16259","suppressedMessages":"16260","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16261","messages":"16262","suppressedMessages":"16263","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16264","messages":"16265","suppressedMessages":"16266","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16267","messages":"16268","suppressedMessages":"16269","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16270","messages":"16271","suppressedMessages":"16272","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16273","messages":"16274","suppressedMessages":"16275","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16276","messages":"16277","suppressedMessages":"16278","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16279","messages":"16280","suppressedMessages":"16281","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16282","messages":"16283","suppressedMessages":"16284","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16285","messages":"16286","suppressedMessages":"16287","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16288","messages":"16289","suppressedMessages":"16290","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16291","messages":"16292","suppressedMessages":"16293","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16294","messages":"16295","suppressedMessages":"16296","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16297","messages":"16298","suppressedMessages":"16299","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16300","messages":"16301","suppressedMessages":"16302","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16303","messages":"16304","suppressedMessages":"16305","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16306","messages":"16307","suppressedMessages":"16308","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16309","messages":"16310","suppressedMessages":"16311","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16312","messages":"16313","suppressedMessages":"16314","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16315","messages":"16316","suppressedMessages":"16317","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16318","messages":"16319","suppressedMessages":"16320","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16321","messages":"16322","suppressedMessages":"16323","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16324","messages":"16325","suppressedMessages":"16326","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16327","messages":"16328","suppressedMessages":"16329","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16330","messages":"16331","suppressedMessages":"16332","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16333","messages":"16334","suppressedMessages":"16335","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16336","messages":"16337","suppressedMessages":"16338","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16339","messages":"16340","suppressedMessages":"16341","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16342","messages":"16343","suppressedMessages":"16344","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16345","messages":"16346","suppressedMessages":"16347","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16348","messages":"16349","suppressedMessages":"16350","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16351","messages":"16352","suppressedMessages":"16353","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16354","messages":"16355","suppressedMessages":"16356","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16357","messages":"16358","suppressedMessages":"16359","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16360","messages":"16361","suppressedMessages":"16362","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16363","messages":"16364","suppressedMessages":"16365","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16366","messages":"16367","suppressedMessages":"16368","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16369","messages":"16370","suppressedMessages":"16371","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16372","messages":"16373","suppressedMessages":"16374","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16375","messages":"16376","suppressedMessages":"16377","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16378","messages":"16379","suppressedMessages":"16380","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16381","messages":"16382","suppressedMessages":"16383","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16384","messages":"16385","suppressedMessages":"16386","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16387","messages":"16388","suppressedMessages":"16389","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16390","messages":"16391","suppressedMessages":"16392","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16393","messages":"16394","suppressedMessages":"16395","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16396","messages":"16397","suppressedMessages":"16398","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16399","messages":"16400","suppressedMessages":"16401","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16402","messages":"16403","suppressedMessages":"16404","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16405","messages":"16406","suppressedMessages":"16407","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16408","messages":"16409","suppressedMessages":"16410","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16411","messages":"16412","suppressedMessages":"16413","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16414","messages":"16415","suppressedMessages":"16416","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16417","messages":"16418","suppressedMessages":"16419","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16420","messages":"16421","suppressedMessages":"16422","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16423","messages":"16424","suppressedMessages":"16425","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16426","messages":"16427","suppressedMessages":"16428","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16429","messages":"16430","suppressedMessages":"16431","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16432","messages":"16433","suppressedMessages":"16434","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16435","messages":"16436","suppressedMessages":"16437","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16438","messages":"16439","suppressedMessages":"16440","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16441","messages":"16442","suppressedMessages":"16443","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16444","messages":"16445","suppressedMessages":"16446","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16447","messages":"16448","suppressedMessages":"16449","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16450","messages":"16451","suppressedMessages":"16452","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16453","messages":"16454","suppressedMessages":"16455","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16456","messages":"16457","suppressedMessages":"16458","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16459","messages":"16460","suppressedMessages":"16461","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16462","messages":"16463","suppressedMessages":"16464","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16465","messages":"16466","suppressedMessages":"16467","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16468","messages":"16469","suppressedMessages":"16470","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16471","messages":"16472","suppressedMessages":"16473","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16474","messages":"16475","suppressedMessages":"16476","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16477","messages":"16478","suppressedMessages":"16479","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16480","messages":"16481","suppressedMessages":"16482","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16483","messages":"16484","suppressedMessages":"16485","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16486","messages":"16487","suppressedMessages":"16488","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16489","messages":"16490","suppressedMessages":"16491","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16492","messages":"16493","suppressedMessages":"16494","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16495","messages":"16496","suppressedMessages":"16497","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16498","messages":"16499","suppressedMessages":"16500","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16501","messages":"16502","suppressedMessages":"16503","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16504","messages":"16505","suppressedMessages":"16506","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16507","messages":"16508","suppressedMessages":"16509","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16510","messages":"16511","suppressedMessages":"16512","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16513","messages":"16514","suppressedMessages":"16515","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16516","messages":"16517","suppressedMessages":"16518","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16519","messages":"16520","suppressedMessages":"16521","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16522","messages":"16523","suppressedMessages":"16524","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16525","messages":"16526","suppressedMessages":"16527","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16528","messages":"16529","suppressedMessages":"16530","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16531","messages":"16532","suppressedMessages":"16533","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16534","messages":"16535","suppressedMessages":"16536","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16537","messages":"16538","suppressedMessages":"16539","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16540","messages":"16541","suppressedMessages":"16542","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16543","messages":"16544","suppressedMessages":"16545","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16546","messages":"16547","suppressedMessages":"16548","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16549","messages":"16550","suppressedMessages":"16551","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16552","messages":"16553","suppressedMessages":"16554","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16555","messages":"16556","suppressedMessages":"16557","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16558","messages":"16559","suppressedMessages":"16560","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16561","messages":"16562","suppressedMessages":"16563","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16564","messages":"16565","suppressedMessages":"16566","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16567","messages":"16568","suppressedMessages":"16569","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16570","messages":"16571","suppressedMessages":"16572","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16573","messages":"16574","suppressedMessages":"16575","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16576","messages":"16577","suppressedMessages":"16578","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16579","messages":"16580","suppressedMessages":"16581","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16582","messages":"16583","suppressedMessages":"16584","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16585","messages":"16586","suppressedMessages":"16587","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16588","messages":"16589","suppressedMessages":"16590","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16591","messages":"16592","suppressedMessages":"16593","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16594","messages":"16595","suppressedMessages":"16596","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16597","messages":"16598","suppressedMessages":"16599","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16600","messages":"16601","suppressedMessages":"16602","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16603","messages":"16604","suppressedMessages":"16605","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16606","messages":"16607","suppressedMessages":"16608","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16609","messages":"16610","suppressedMessages":"16611","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16612","messages":"16613","suppressedMessages":"16614","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16615","messages":"16616","suppressedMessages":"16617","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16618","messages":"16619","suppressedMessages":"16620","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16621","messages":"16622","suppressedMessages":"16623","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16624","messages":"16625","suppressedMessages":"16626","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16627","messages":"16628","suppressedMessages":"16629","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16630","messages":"16631","suppressedMessages":"16632","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16633","messages":"16634","suppressedMessages":"16635","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16636","messages":"16637","suppressedMessages":"16638","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16639","messages":"16640","suppressedMessages":"16641","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16642","messages":"16643","suppressedMessages":"16644","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16645","messages":"16646","suppressedMessages":"16647","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16648","messages":"16649","suppressedMessages":"16650","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16651","messages":"16652","suppressedMessages":"16653","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16654","messages":"16655","suppressedMessages":"16656","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16657","messages":"16658","suppressedMessages":"16659","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16660","messages":"16661","suppressedMessages":"16662","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16663","messages":"16664","suppressedMessages":"16665","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16666","messages":"16667","suppressedMessages":"16668","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16669","messages":"16670","suppressedMessages":"16671","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16672","messages":"16673","suppressedMessages":"16674","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16675","messages":"16676","suppressedMessages":"16677","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16678","messages":"16679","suppressedMessages":"16680","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16681","messages":"16682","suppressedMessages":"16683","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16684","messages":"16685","suppressedMessages":"16686","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16687","messages":"16688","suppressedMessages":"16689","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16690","messages":"16691","suppressedMessages":"16692","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16693","messages":"16694","suppressedMessages":"16695","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16696","messages":"16697","suppressedMessages":"16698","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16699","messages":"16700","suppressedMessages":"16701","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16702","messages":"16703","suppressedMessages":"16704","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16705","messages":"16706","suppressedMessages":"16707","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16708","messages":"16709","suppressedMessages":"16710","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16711","messages":"16712","suppressedMessages":"16713","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16714","messages":"16715","suppressedMessages":"16716","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16717","messages":"16718","suppressedMessages":"16719","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16720","messages":"16721","suppressedMessages":"16722","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16723","messages":"16724","suppressedMessages":"16725","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16726","messages":"16727","suppressedMessages":"16728","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16729","messages":"16730","suppressedMessages":"16731","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16732","messages":"16733","suppressedMessages":"16734","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16735","messages":"16736","suppressedMessages":"16737","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16738","messages":"16739","suppressedMessages":"16740","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16741","messages":"16742","suppressedMessages":"16743","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16744","messages":"16745","suppressedMessages":"16746","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16747","messages":"16748","suppressedMessages":"16749","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16750","messages":"16751","suppressedMessages":"16752","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16753","messages":"16754","suppressedMessages":"16755","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16756","messages":"16757","suppressedMessages":"16758","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16759","messages":"16760","suppressedMessages":"16761","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16762","messages":"16763","suppressedMessages":"16764","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16765","messages":"16766","suppressedMessages":"16767","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16768","messages":"16769","suppressedMessages":"16770","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16771","messages":"16772","suppressedMessages":"16773","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16774","messages":"16775","suppressedMessages":"16776","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16777","messages":"16778","suppressedMessages":"16779","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16780","messages":"16781","suppressedMessages":"16782","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16783","messages":"16784","suppressedMessages":"16785","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16786","messages":"16787","suppressedMessages":"16788","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16789","messages":"16790","suppressedMessages":"16791","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16792","messages":"16793","suppressedMessages":"16794","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16795","messages":"16796","suppressedMessages":"16797","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16798","messages":"16799","suppressedMessages":"16800","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16801","messages":"16802","suppressedMessages":"16803","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16804","messages":"16805","suppressedMessages":"16806","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16807","messages":"16808","suppressedMessages":"16809","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16810","messages":"16811","suppressedMessages":"16812","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16813","messages":"16814","suppressedMessages":"16815","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16816","messages":"16817","suppressedMessages":"16818","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16819","messages":"16820","suppressedMessages":"16821","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16822","messages":"16823","suppressedMessages":"16824","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16825","messages":"16826","suppressedMessages":"16827","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16828","messages":"16829","suppressedMessages":"16830","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16831","messages":"16832","suppressedMessages":"16833","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16834","messages":"16835","suppressedMessages":"16836","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16837","messages":"16838","suppressedMessages":"16839","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16840","messages":"16841","suppressedMessages":"16842","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16843","messages":"16844","suppressedMessages":"16845","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16846","messages":"16847","suppressedMessages":"16848","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16849","messages":"16850","suppressedMessages":"16851","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16852","messages":"16853","suppressedMessages":"16854","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16855","messages":"16856","suppressedMessages":"16857","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16858","messages":"16859","suppressedMessages":"16860","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16861","messages":"16862","suppressedMessages":"16863","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16864","messages":"16865","suppressedMessages":"16866","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16867","messages":"16868","suppressedMessages":"16869","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16870","messages":"16871","suppressedMessages":"16872","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16873","messages":"16874","suppressedMessages":"16875","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16876","messages":"16877","suppressedMessages":"16878","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16879","messages":"16880","suppressedMessages":"16881","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"16882"},{"filePath":"16883","messages":"16884","suppressedMessages":"16885","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16886","messages":"16887","suppressedMessages":"16888","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16889","messages":"16890","suppressedMessages":"16891","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16892","messages":"16893","suppressedMessages":"16894","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16895","messages":"16896","suppressedMessages":"16897","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16898","messages":"16899","suppressedMessages":"16900","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16901","messages":"16902","suppressedMessages":"16903","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16904","messages":"16905","suppressedMessages":"16906","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16907","messages":"16908","suppressedMessages":"16909","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16910","messages":"16911","suppressedMessages":"16912","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16913","messages":"16914","suppressedMessages":"16915","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16916","messages":"16917","suppressedMessages":"16918","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16919","messages":"16920","suppressedMessages":"16921","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16922","messages":"16923","suppressedMessages":"16924","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16925","messages":"16926","suppressedMessages":"16927","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16928","messages":"16929","suppressedMessages":"16930","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16931","messages":"16932","suppressedMessages":"16933","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16934","messages":"16935","suppressedMessages":"16936","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16937","messages":"16938","suppressedMessages":"16939","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16940","messages":"16941","suppressedMessages":"16942","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16943","messages":"16944","suppressedMessages":"16945","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16946","messages":"16947","suppressedMessages":"16948","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16949","messages":"16950","suppressedMessages":"16951","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16952","messages":"16953","suppressedMessages":"16954","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16955","messages":"16956","suppressedMessages":"16957","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16958","messages":"16959","suppressedMessages":"16960","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16961","messages":"16962","suppressedMessages":"16963","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16964","messages":"16965","suppressedMessages":"16966","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16967","messages":"16968","suppressedMessages":"16969","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16970","messages":"16971","suppressedMessages":"16972","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16973","messages":"16974","suppressedMessages":"16975","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16976","messages":"16977","suppressedMessages":"16978","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16979","messages":"16980","suppressedMessages":"16981","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16982","messages":"16983","suppressedMessages":"16984","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16985","messages":"16986","suppressedMessages":"16987","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16988","messages":"16989","suppressedMessages":"16990","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16991","messages":"16992","suppressedMessages":"16993","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16994","messages":"16995","suppressedMessages":"16996","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"16997","messages":"16998","suppressedMessages":"16999","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17000","messages":"17001","suppressedMessages":"17002","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17003","messages":"17004","suppressedMessages":"17005","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17006","messages":"17007","suppressedMessages":"17008","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17009","messages":"17010","suppressedMessages":"17011","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17012","messages":"17013","suppressedMessages":"17014","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17015","messages":"17016","suppressedMessages":"17017","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17018","messages":"17019","suppressedMessages":"17020","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17021","messages":"17022","suppressedMessages":"17023","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17024","messages":"17025","suppressedMessages":"17026","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17027","messages":"17028","suppressedMessages":"17029","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17030","messages":"17031","suppressedMessages":"17032","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17033","messages":"17034","suppressedMessages":"17035","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17036","messages":"17037","suppressedMessages":"17038","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17039","messages":"17040","suppressedMessages":"17041","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17042","messages":"17043","suppressedMessages":"17044","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17045","messages":"17046","suppressedMessages":"17047","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17048","messages":"17049","suppressedMessages":"17050","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17051","messages":"17052","suppressedMessages":"17053","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17054","messages":"17055","suppressedMessages":"17056","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"17057"},{"filePath":"17058","messages":"17059","suppressedMessages":"17060","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17061","messages":"17062","suppressedMessages":"17063","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17064","messages":"17065","suppressedMessages":"17066","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17067","messages":"17068","suppressedMessages":"17069","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17070","messages":"17071","suppressedMessages":"17072","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17073","messages":"17074","suppressedMessages":"17075","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17076","messages":"17077","suppressedMessages":"17078","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17079","messages":"17080","suppressedMessages":"17081","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17082","messages":"17083","suppressedMessages":"17084","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17085","messages":"17086","suppressedMessages":"17087","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17088","messages":"17089","suppressedMessages":"17090","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17091","messages":"17092","suppressedMessages":"17093","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17094","messages":"17095","suppressedMessages":"17096","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17097","messages":"17098","suppressedMessages":"17099","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17100","messages":"17101","suppressedMessages":"17102","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17103","messages":"17104","suppressedMessages":"17105","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17106","messages":"17107","suppressedMessages":"17108","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17109","messages":"17110","suppressedMessages":"17111","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17112","messages":"17113","suppressedMessages":"17114","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17115","messages":"17116","suppressedMessages":"17117","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17118","messages":"17119","suppressedMessages":"17120","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17121","messages":"17122","suppressedMessages":"17123","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17124","messages":"17125","suppressedMessages":"17126","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17127","messages":"17128","suppressedMessages":"17129","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17130","messages":"17131","suppressedMessages":"17132","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17133","messages":"17134","suppressedMessages":"17135","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17136","messages":"17137","suppressedMessages":"17138","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17139","messages":"17140","suppressedMessages":"17141","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17142","messages":"17143","suppressedMessages":"17144","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17145","messages":"17146","suppressedMessages":"17147","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17148","messages":"17149","suppressedMessages":"17150","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17151","messages":"17152","suppressedMessages":"17153","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17154","messages":"17155","suppressedMessages":"17156","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17157","messages":"17158","suppressedMessages":"17159","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17160","messages":"17161","suppressedMessages":"17162","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17163","messages":"17164","suppressedMessages":"17165","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17166","messages":"17167","suppressedMessages":"17168","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17169","messages":"17170","suppressedMessages":"17171","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17172","messages":"17173","suppressedMessages":"17174","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17175","messages":"17176","suppressedMessages":"17177","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17178","messages":"17179","suppressedMessages":"17180","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17181","messages":"17182","suppressedMessages":"17183","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17184","messages":"17185","suppressedMessages":"17186","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17187","messages":"17188","suppressedMessages":"17189","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17190","messages":"17191","suppressedMessages":"17192","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17193","messages":"17194","suppressedMessages":"17195","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17196","messages":"17197","suppressedMessages":"17198","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17199","messages":"17200","suppressedMessages":"17201","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17202","messages":"17203","suppressedMessages":"17204","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17205","messages":"17206","suppressedMessages":"17207","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17208","messages":"17209","suppressedMessages":"17210","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17211","messages":"17212","suppressedMessages":"17213","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17214","messages":"17215","suppressedMessages":"17216","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17217","messages":"17218","suppressedMessages":"17219","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17220","messages":"17221","suppressedMessages":"17222","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17223","messages":"17224","suppressedMessages":"17225","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17226","messages":"17227","suppressedMessages":"17228","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17229","messages":"17230","suppressedMessages":"17231","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17232","messages":"17233","suppressedMessages":"17234","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17235","messages":"17236","suppressedMessages":"17237","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17238","messages":"17239","suppressedMessages":"17240","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17241","messages":"17242","suppressedMessages":"17243","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17244","messages":"17245","suppressedMessages":"17246","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17247","messages":"17248","suppressedMessages":"17249","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17250","messages":"17251","suppressedMessages":"17252","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17253","messages":"17254","suppressedMessages":"17255","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17256","messages":"17257","suppressedMessages":"17258","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17259","messages":"17260","suppressedMessages":"17261","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17262","messages":"17263","suppressedMessages":"17264","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17265","messages":"17266","suppressedMessages":"17267","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17268","messages":"17269","suppressedMessages":"17270","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17271","messages":"17272","suppressedMessages":"17273","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17274","messages":"17275","suppressedMessages":"17276","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17277","messages":"17278","suppressedMessages":"17279","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17280","messages":"17281","suppressedMessages":"17282","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17283","messages":"17284","suppressedMessages":"17285","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17286","messages":"17287","suppressedMessages":"17288","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17289","messages":"17290","suppressedMessages":"17291","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17292","messages":"17293","suppressedMessages":"17294","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17295","messages":"17296","suppressedMessages":"17297","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17298","messages":"17299","suppressedMessages":"17300","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17301","messages":"17302","suppressedMessages":"17303","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17304","messages":"17305","suppressedMessages":"17306","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17307","messages":"17308","suppressedMessages":"17309","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17310","messages":"17311","suppressedMessages":"17312","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17313","messages":"17314","suppressedMessages":"17315","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17316","messages":"17317","suppressedMessages":"17318","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17319","messages":"17320","suppressedMessages":"17321","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17322","messages":"17323","suppressedMessages":"17324","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17325","messages":"17326","suppressedMessages":"17327","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17328","messages":"17329","suppressedMessages":"17330","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17331","messages":"17332","suppressedMessages":"17333","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17334","messages":"17335","suppressedMessages":"17336","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17337","messages":"17338","suppressedMessages":"17339","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17340","messages":"17341","suppressedMessages":"17342","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17343","messages":"17344","suppressedMessages":"17345","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17346","messages":"17347","suppressedMessages":"17348","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17349","messages":"17350","suppressedMessages":"17351","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17352","messages":"17353","suppressedMessages":"17354","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17355","messages":"17356","suppressedMessages":"17357","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17358","messages":"17359","suppressedMessages":"17360","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17361","messages":"17362","suppressedMessages":"17363","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17364","messages":"17365","suppressedMessages":"17366","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17367","messages":"17368","suppressedMessages":"17369","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17370","messages":"17371","suppressedMessages":"17372","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17373","messages":"17374","suppressedMessages":"17375","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17376","messages":"17377","suppressedMessages":"17378","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17379","messages":"17380","suppressedMessages":"17381","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17382","messages":"17383","suppressedMessages":"17384","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17385","messages":"17386","suppressedMessages":"17387","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17388","messages":"17389","suppressedMessages":"17390","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17391","messages":"17392","suppressedMessages":"17393","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17394","messages":"17395","suppressedMessages":"17396","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17397","messages":"17398","suppressedMessages":"17399","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17400","messages":"17401","suppressedMessages":"17402","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17403","messages":"17404","suppressedMessages":"17405","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17406","messages":"17407","suppressedMessages":"17408","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17409","messages":"17410","suppressedMessages":"17411","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17412","messages":"17413","suppressedMessages":"17414","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17415","messages":"17416","suppressedMessages":"17417","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17418","messages":"17419","suppressedMessages":"17420","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17421","messages":"17422","suppressedMessages":"17423","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17424","messages":"17425","suppressedMessages":"17426","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17427","messages":"17428","suppressedMessages":"17429","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17430","messages":"17431","suppressedMessages":"17432","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17433","messages":"17434","suppressedMessages":"17435","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17436","messages":"17437","suppressedMessages":"17438","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17439","messages":"17440","suppressedMessages":"17441","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17442","messages":"17443","suppressedMessages":"17444","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17445","messages":"17446","suppressedMessages":"17447","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17448","messages":"17449","suppressedMessages":"17450","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17451","messages":"17452","suppressedMessages":"17453","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17454","messages":"17455","suppressedMessages":"17456","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17457","messages":"17458","suppressedMessages":"17459","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17460","messages":"17461","suppressedMessages":"17462","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17463","messages":"17464","suppressedMessages":"17465","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17466","messages":"17467","suppressedMessages":"17468","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17469","messages":"17470","suppressedMessages":"17471","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17472","messages":"17473","suppressedMessages":"17474","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17475","messages":"17476","suppressedMessages":"17477","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17478","messages":"17479","suppressedMessages":"17480","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17481","messages":"17482","suppressedMessages":"17483","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17484","messages":"17485","suppressedMessages":"17486","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17487","messages":"17488","suppressedMessages":"17489","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17490","messages":"17491","suppressedMessages":"17492","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17493","messages":"17494","suppressedMessages":"17495","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17496","messages":"17497","suppressedMessages":"17498","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17499","messages":"17500","suppressedMessages":"17501","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17502","messages":"17503","suppressedMessages":"17504","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17505","messages":"17506","suppressedMessages":"17507","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17508","messages":"17509","suppressedMessages":"17510","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17511","messages":"17512","suppressedMessages":"17513","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17514","messages":"17515","suppressedMessages":"17516","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17517","messages":"17518","suppressedMessages":"17519","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17520","messages":"17521","suppressedMessages":"17522","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17523","messages":"17524","suppressedMessages":"17525","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17526","messages":"17527","suppressedMessages":"17528","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17529","messages":"17530","suppressedMessages":"17531","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17532","messages":"17533","suppressedMessages":"17534","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17535","messages":"17536","suppressedMessages":"17537","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17538","messages":"17539","suppressedMessages":"17540","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17541","messages":"17542","suppressedMessages":"17543","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17544","messages":"17545","suppressedMessages":"17546","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17547","messages":"17548","suppressedMessages":"17549","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17550","messages":"17551","suppressedMessages":"17552","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17553","messages":"17554","suppressedMessages":"17555","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17556","messages":"17557","suppressedMessages":"17558","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17559","messages":"17560","suppressedMessages":"17561","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17562","messages":"17563","suppressedMessages":"17564","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17565","messages":"17566","suppressedMessages":"17567","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17568","messages":"17569","suppressedMessages":"17570","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17571","messages":"17572","suppressedMessages":"17573","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17574","messages":"17575","suppressedMessages":"17576","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17577","messages":"17578","suppressedMessages":"17579","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17580","messages":"17581","suppressedMessages":"17582","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17583","messages":"17584","suppressedMessages":"17585","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17586","messages":"17587","suppressedMessages":"17588","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17589","messages":"17590","suppressedMessages":"17591","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17592","messages":"17593","suppressedMessages":"17594","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17595","messages":"17596","suppressedMessages":"17597","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17598","messages":"17599","suppressedMessages":"17600","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17601","messages":"17602","suppressedMessages":"17603","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17604","messages":"17605","suppressedMessages":"17606","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17607","messages":"17608","suppressedMessages":"17609","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17610","messages":"17611","suppressedMessages":"17612","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17613","messages":"17614","suppressedMessages":"17615","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17616","messages":"17617","suppressedMessages":"17618","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17619","messages":"17620","suppressedMessages":"17621","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17622","messages":"17623","suppressedMessages":"17624","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17625","messages":"17626","suppressedMessages":"17627","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17628","messages":"17629","suppressedMessages":"17630","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17631","messages":"17632","suppressedMessages":"17633","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17634","messages":"17635","suppressedMessages":"17636","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17637","messages":"17638","suppressedMessages":"17639","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17640","messages":"17641","suppressedMessages":"17642","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17643","messages":"17644","suppressedMessages":"17645","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17646","messages":"17647","suppressedMessages":"17648","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17649","messages":"17650","suppressedMessages":"17651","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17652","messages":"17653","suppressedMessages":"17654","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17655","messages":"17656","suppressedMessages":"17657","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17658","messages":"17659","suppressedMessages":"17660","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17661","messages":"17662","suppressedMessages":"17663","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17664","messages":"17665","suppressedMessages":"17666","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17667","messages":"17668","suppressedMessages":"17669","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17670","messages":"17671","suppressedMessages":"17672","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17673","messages":"17674","suppressedMessages":"17675","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17676","messages":"17677","suppressedMessages":"17678","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17679","messages":"17680","suppressedMessages":"17681","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17682","messages":"17683","suppressedMessages":"17684","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17685","messages":"17686","suppressedMessages":"17687","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17688","messages":"17689","suppressedMessages":"17690","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17691","messages":"17692","suppressedMessages":"17693","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17694","messages":"17695","suppressedMessages":"17696","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17697","messages":"17698","suppressedMessages":"17699","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17700","messages":"17701","suppressedMessages":"17702","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17703","messages":"17704","suppressedMessages":"17705","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17706","messages":"17707","suppressedMessages":"17708","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17709","messages":"17710","suppressedMessages":"17711","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17712","messages":"17713","suppressedMessages":"17714","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17715","messages":"17716","suppressedMessages":"17717","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17718","messages":"17719","suppressedMessages":"17720","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17721","messages":"17722","suppressedMessages":"17723","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17724","messages":"17725","suppressedMessages":"17726","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17727","messages":"17728","suppressedMessages":"17729","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17730","messages":"17731","suppressedMessages":"17732","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17733","messages":"17734","suppressedMessages":"17735","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17736","messages":"17737","suppressedMessages":"17738","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17739","messages":"17740","suppressedMessages":"17741","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17742","messages":"17743","suppressedMessages":"17744","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17745","messages":"17746","suppressedMessages":"17747","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17748","messages":"17749","suppressedMessages":"17750","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17751","messages":"17752","suppressedMessages":"17753","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17754","messages":"17755","suppressedMessages":"17756","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17757","messages":"17758","suppressedMessages":"17759","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17760","messages":"17761","suppressedMessages":"17762","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17763","messages":"17764","suppressedMessages":"17765","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17766","messages":"17767","suppressedMessages":"17768","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17769","messages":"17770","suppressedMessages":"17771","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17772","messages":"17773","suppressedMessages":"17774","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17775","messages":"17776","suppressedMessages":"17777","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17778","messages":"17779","suppressedMessages":"17780","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17781","messages":"17782","suppressedMessages":"17783","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17784","messages":"17785","suppressedMessages":"17786","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17787","messages":"17788","suppressedMessages":"17789","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17790","messages":"17791","suppressedMessages":"17792","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17793","messages":"17794","suppressedMessages":"17795","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17796","messages":"17797","suppressedMessages":"17798","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17799","messages":"17800","suppressedMessages":"17801","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17802","messages":"17803","suppressedMessages":"17804","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17805","messages":"17806","suppressedMessages":"17807","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17808","messages":"17809","suppressedMessages":"17810","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17811","messages":"17812","suppressedMessages":"17813","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17814","messages":"17815","suppressedMessages":"17816","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17817","messages":"17818","suppressedMessages":"17819","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17820","messages":"17821","suppressedMessages":"17822","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17823","messages":"17824","suppressedMessages":"17825","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17826","messages":"17827","suppressedMessages":"17828","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17829","messages":"17830","suppressedMessages":"17831","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17832","messages":"17833","suppressedMessages":"17834","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17835","messages":"17836","suppressedMessages":"17837","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17838","messages":"17839","suppressedMessages":"17840","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17841","messages":"17842","suppressedMessages":"17843","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17844","messages":"17845","suppressedMessages":"17846","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17847","messages":"17848","suppressedMessages":"17849","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17850","messages":"17851","suppressedMessages":"17852","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17853","messages":"17854","suppressedMessages":"17855","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17856","messages":"17857","suppressedMessages":"17858","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17859","messages":"17860","suppressedMessages":"17861","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17862","messages":"17863","suppressedMessages":"17864","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17865","messages":"17866","suppressedMessages":"17867","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17868","messages":"17869","suppressedMessages":"17870","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17871","messages":"17872","suppressedMessages":"17873","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17874","messages":"17875","suppressedMessages":"17876","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17877","messages":"17878","suppressedMessages":"17879","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"17880"},{"filePath":"17881","messages":"17882","suppressedMessages":"17883","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17884","messages":"17885","suppressedMessages":"17886","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17887","messages":"17888","suppressedMessages":"17889","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17890","messages":"17891","suppressedMessages":"17892","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17893","messages":"17894","suppressedMessages":"17895","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17896","messages":"17897","suppressedMessages":"17898","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17899","messages":"17900","suppressedMessages":"17901","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17902","messages":"17903","suppressedMessages":"17904","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17905","messages":"17906","suppressedMessages":"17907","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17908","messages":"17909","suppressedMessages":"17910","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17911","messages":"17912","suppressedMessages":"17913","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17914","messages":"17915","suppressedMessages":"17916","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17917","messages":"17918","suppressedMessages":"17919","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17920","messages":"17921","suppressedMessages":"17922","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17923","messages":"17924","suppressedMessages":"17925","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17926","messages":"17927","suppressedMessages":"17928","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17929","messages":"17930","suppressedMessages":"17931","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17932","messages":"17933","suppressedMessages":"17934","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17935","messages":"17936","suppressedMessages":"17937","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17938","messages":"17939","suppressedMessages":"17940","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17941","messages":"17942","suppressedMessages":"17943","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17944","messages":"17945","suppressedMessages":"17946","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17947","messages":"17948","suppressedMessages":"17949","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17950","messages":"17951","suppressedMessages":"17952","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17953","messages":"17954","suppressedMessages":"17955","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17956","messages":"17957","suppressedMessages":"17958","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17959","messages":"17960","suppressedMessages":"17961","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17962","messages":"17963","suppressedMessages":"17964","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17965","messages":"17966","suppressedMessages":"17967","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17968","messages":"17969","suppressedMessages":"17970","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17971","messages":"17972","suppressedMessages":"17973","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17974","messages":"17975","suppressedMessages":"17976","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17977","messages":"17978","suppressedMessages":"17979","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17980","messages":"17981","suppressedMessages":"17982","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17983","messages":"17984","suppressedMessages":"17985","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17986","messages":"17987","suppressedMessages":"17988","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17989","messages":"17990","suppressedMessages":"17991","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17992","messages":"17993","suppressedMessages":"17994","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17995","messages":"17996","suppressedMessages":"17997","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"17998","messages":"17999","suppressedMessages":"18000","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18001","messages":"18002","suppressedMessages":"18003","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18004","messages":"18005","suppressedMessages":"18006","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18007","messages":"18008","suppressedMessages":"18009","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18010","messages":"18011","suppressedMessages":"18012","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18013","messages":"18014","suppressedMessages":"18015","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18016","messages":"18017","suppressedMessages":"18018","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18019","messages":"18020","suppressedMessages":"18021","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18022","messages":"18023","suppressedMessages":"18024","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18025","messages":"18026","suppressedMessages":"18027","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18028","messages":"18029","suppressedMessages":"18030","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18031","messages":"18032","suppressedMessages":"18033","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18034","messages":"18035","suppressedMessages":"18036","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18037","messages":"18038","suppressedMessages":"18039","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18040","messages":"18041","suppressedMessages":"18042","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18043","messages":"18044","suppressedMessages":"18045","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18046","messages":"18047","suppressedMessages":"18048","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18049","messages":"18050","suppressedMessages":"18051","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18052","messages":"18053","suppressedMessages":"18054","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18055","messages":"18056","suppressedMessages":"18057","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18058","messages":"18059","suppressedMessages":"18060","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18061","messages":"18062","suppressedMessages":"18063","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18064","messages":"18065","suppressedMessages":"18066","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18067","messages":"18068","suppressedMessages":"18069","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18070","messages":"18071","suppressedMessages":"18072","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18073","messages":"18074","suppressedMessages":"18075","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18076","messages":"18077","suppressedMessages":"18078","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18079","messages":"18080","suppressedMessages":"18081","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18082","messages":"18083","suppressedMessages":"18084","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18085","messages":"18086","suppressedMessages":"18087","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18088","messages":"18089","suppressedMessages":"18090","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18091","messages":"18092","suppressedMessages":"18093","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18094","messages":"18095","suppressedMessages":"18096","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18097","messages":"18098","suppressedMessages":"18099","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18100","messages":"18101","suppressedMessages":"18102","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18103","messages":"18104","suppressedMessages":"18105","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18106","messages":"18107","suppressedMessages":"18108","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18109","messages":"18110","suppressedMessages":"18111","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18112","messages":"18113","suppressedMessages":"18114","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18115","messages":"18116","suppressedMessages":"18117","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18118","messages":"18119","suppressedMessages":"18120","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18121","messages":"18122","suppressedMessages":"18123","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18124","messages":"18125","suppressedMessages":"18126","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18127","messages":"18128","suppressedMessages":"18129","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18130","messages":"18131","suppressedMessages":"18132","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18133","messages":"18134","suppressedMessages":"18135","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18136","messages":"18137","suppressedMessages":"18138","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18139","messages":"18140","suppressedMessages":"18141","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18142","messages":"18143","suppressedMessages":"18144","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18145","messages":"18146","suppressedMessages":"18147","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18148","messages":"18149","suppressedMessages":"18150","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18151","messages":"18152","suppressedMessages":"18153","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18154","messages":"18155","suppressedMessages":"18156","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"18157"},{"filePath":"18158","messages":"18159","suppressedMessages":"18160","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18161","messages":"18162","suppressedMessages":"18163","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18164","messages":"18165","suppressedMessages":"18166","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18167","messages":"18168","suppressedMessages":"18169","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18170","messages":"18171","suppressedMessages":"18172","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18173","messages":"18174","suppressedMessages":"18175","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18176","messages":"18177","suppressedMessages":"18178","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18179","messages":"18180","suppressedMessages":"18181","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18182","messages":"18183","suppressedMessages":"18184","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18185","messages":"18186","suppressedMessages":"18187","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18188","messages":"18189","suppressedMessages":"18190","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18191","messages":"18192","suppressedMessages":"18193","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18194","messages":"18195","suppressedMessages":"18196","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18197","messages":"18198","suppressedMessages":"18199","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18200","messages":"18201","suppressedMessages":"18202","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18203","messages":"18204","suppressedMessages":"18205","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18206","messages":"18207","suppressedMessages":"18208","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18209","messages":"18210","suppressedMessages":"18211","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18212","messages":"18213","suppressedMessages":"18214","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18215","messages":"18216","suppressedMessages":"18217","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18218","messages":"18219","suppressedMessages":"18220","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18221","messages":"18222","suppressedMessages":"18223","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18224","messages":"18225","suppressedMessages":"18226","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18227","messages":"18228","suppressedMessages":"18229","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18230","messages":"18231","suppressedMessages":"18232","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18233","messages":"18234","suppressedMessages":"18235","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18236","messages":"18237","suppressedMessages":"18238","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18239","messages":"18240","suppressedMessages":"18241","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18242","messages":"18243","suppressedMessages":"18244","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18245","messages":"18246","suppressedMessages":"18247","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18248","messages":"18249","suppressedMessages":"18250","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18251","messages":"18252","suppressedMessages":"18253","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18254","messages":"18255","suppressedMessages":"18256","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18257","messages":"18258","suppressedMessages":"18259","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18260","messages":"18261","suppressedMessages":"18262","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18263","messages":"18264","suppressedMessages":"18265","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18266","messages":"18267","suppressedMessages":"18268","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18269","messages":"18270","suppressedMessages":"18271","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18272","messages":"18273","suppressedMessages":"18274","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18275","messages":"18276","suppressedMessages":"18277","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18278","messages":"18279","suppressedMessages":"18280","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18281","messages":"18282","suppressedMessages":"18283","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18284","messages":"18285","suppressedMessages":"18286","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18287","messages":"18288","suppressedMessages":"18289","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18290","messages":"18291","suppressedMessages":"18292","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18293","messages":"18294","suppressedMessages":"18295","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18296","messages":"18297","suppressedMessages":"18298","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18299","messages":"18300","suppressedMessages":"18301","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18302","messages":"18303","suppressedMessages":"18304","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18305","messages":"18306","suppressedMessages":"18307","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18308","messages":"18309","suppressedMessages":"18310","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18311","messages":"18312","suppressedMessages":"18313","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18314","messages":"18315","suppressedMessages":"18316","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18317","messages":"18318","suppressedMessages":"18319","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18320","messages":"18321","suppressedMessages":"18322","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18323","messages":"18324","suppressedMessages":"18325","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18326","messages":"18327","suppressedMessages":"18328","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18329","messages":"18330","suppressedMessages":"18331","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18332","messages":"18333","suppressedMessages":"18334","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18335","messages":"18336","suppressedMessages":"18337","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18338","messages":"18339","suppressedMessages":"18340","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18341","messages":"18342","suppressedMessages":"18343","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18344","messages":"18345","suppressedMessages":"18346","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18347","messages":"18348","suppressedMessages":"18349","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18350","messages":"18351","suppressedMessages":"18352","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18353","messages":"18354","suppressedMessages":"18355","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18356","messages":"18357","suppressedMessages":"18358","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18359","messages":"18360","suppressedMessages":"18361","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18362","messages":"18363","suppressedMessages":"18364","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18365","messages":"18366","suppressedMessages":"18367","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18368","messages":"18369","suppressedMessages":"18370","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18371","messages":"18372","suppressedMessages":"18373","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18374","messages":"18375","suppressedMessages":"18376","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18377","messages":"18378","suppressedMessages":"18379","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18380","messages":"18381","suppressedMessages":"18382","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18383","messages":"18384","suppressedMessages":"18385","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18386","messages":"18387","suppressedMessages":"18388","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18389","messages":"18390","suppressedMessages":"18391","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18392","messages":"18393","suppressedMessages":"18394","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18395","messages":"18396","suppressedMessages":"18397","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18398","messages":"18399","suppressedMessages":"18400","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18401","messages":"18402","suppressedMessages":"18403","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18404","messages":"18405","suppressedMessages":"18406","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18407","messages":"18408","suppressedMessages":"18409","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18410","messages":"18411","suppressedMessages":"18412","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18413","messages":"18414","suppressedMessages":"18415","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18416","messages":"18417","suppressedMessages":"18418","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18419","messages":"18420","suppressedMessages":"18421","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18422","messages":"18423","suppressedMessages":"18424","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18425","messages":"18426","suppressedMessages":"18427","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18428","messages":"18429","suppressedMessages":"18430","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18431","messages":"18432","suppressedMessages":"18433","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18434","messages":"18435","suppressedMessages":"18436","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18437","messages":"18438","suppressedMessages":"18439","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18440","messages":"18441","suppressedMessages":"18442","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18443","messages":"18444","suppressedMessages":"18445","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18446","messages":"18447","suppressedMessages":"18448","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18449","messages":"18450","suppressedMessages":"18451","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18452","messages":"18453","suppressedMessages":"18454","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18455","messages":"18456","suppressedMessages":"18457","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18458","messages":"18459","suppressedMessages":"18460","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18461","messages":"18462","suppressedMessages":"18463","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18464","messages":"18465","suppressedMessages":"18466","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18467","messages":"18468","suppressedMessages":"18469","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18470","messages":"18471","suppressedMessages":"18472","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18473","messages":"18474","suppressedMessages":"18475","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18476","messages":"18477","suppressedMessages":"18478","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18479","messages":"18480","suppressedMessages":"18481","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18482","messages":"18483","suppressedMessages":"18484","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18485","messages":"18486","suppressedMessages":"18487","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18488","messages":"18489","suppressedMessages":"18490","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"18491"},{"filePath":"18492","messages":"18493","suppressedMessages":"18494","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18495","messages":"18496","suppressedMessages":"18497","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18498","messages":"18499","suppressedMessages":"18500","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18501","messages":"18502","suppressedMessages":"18503","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18504","messages":"18505","suppressedMessages":"18506","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18507","messages":"18508","suppressedMessages":"18509","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18510","messages":"18511","suppressedMessages":"18512","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18513","messages":"18514","suppressedMessages":"18515","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18516","messages":"18517","suppressedMessages":"18518","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18519","messages":"18520","suppressedMessages":"18521","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18522","messages":"18523","suppressedMessages":"18524","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18525","messages":"18526","suppressedMessages":"18527","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18528","messages":"18529","suppressedMessages":"18530","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18531","messages":"18532","suppressedMessages":"18533","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18534","messages":"18535","suppressedMessages":"18536","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18537","messages":"18538","suppressedMessages":"18539","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18540","messages":"18541","suppressedMessages":"18542","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18543","messages":"18544","suppressedMessages":"18545","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18546","messages":"18547","suppressedMessages":"18548","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18549","messages":"18550","suppressedMessages":"18551","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18552","messages":"18553","suppressedMessages":"18554","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18555","messages":"18556","suppressedMessages":"18557","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18558","messages":"18559","suppressedMessages":"18560","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18561","messages":"18562","suppressedMessages":"18563","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18564","messages":"18565","suppressedMessages":"18566","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18567","messages":"18568","suppressedMessages":"18569","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18570","messages":"18571","suppressedMessages":"18572","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18573","messages":"18574","suppressedMessages":"18575","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18576","messages":"18577","suppressedMessages":"18578","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18579","messages":"18580","suppressedMessages":"18581","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"18582"},{"filePath":"18583","messages":"18584","suppressedMessages":"18585","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18586","messages":"18587","suppressedMessages":"18588","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18589","messages":"18590","suppressedMessages":"18591","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18592","messages":"18593","suppressedMessages":"18594","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18595","messages":"18596","suppressedMessages":"18597","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18598","messages":"18599","suppressedMessages":"18600","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18601","messages":"18602","suppressedMessages":"18603","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18604","messages":"18605","suppressedMessages":"18606","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18607","messages":"18608","suppressedMessages":"18609","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18610","messages":"18611","suppressedMessages":"18612","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18613","messages":"18614","suppressedMessages":"18615","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18616","messages":"18617","suppressedMessages":"18618","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18619","messages":"18620","suppressedMessages":"18621","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18622","messages":"18623","suppressedMessages":"18624","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18625","messages":"18626","suppressedMessages":"18627","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18628","messages":"18629","suppressedMessages":"18630","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18631","messages":"18632","suppressedMessages":"18633","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18634","messages":"18635","suppressedMessages":"18636","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18637","messages":"18638","suppressedMessages":"18639","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18640","messages":"18641","suppressedMessages":"18642","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18643","messages":"18644","suppressedMessages":"18645","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18646","messages":"18647","suppressedMessages":"18648","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18649","messages":"18650","suppressedMessages":"18651","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18652","messages":"18653","suppressedMessages":"18654","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18655","messages":"18656","suppressedMessages":"18657","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18658","messages":"18659","suppressedMessages":"18660","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18661","messages":"18662","suppressedMessages":"18663","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18664","messages":"18665","suppressedMessages":"18666","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18667","messages":"18668","suppressedMessages":"18669","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18670","messages":"18671","suppressedMessages":"18672","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18673","messages":"18674","suppressedMessages":"18675","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18676","messages":"18677","suppressedMessages":"18678","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18679","messages":"18680","suppressedMessages":"18681","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18682","messages":"18683","suppressedMessages":"18684","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18685","messages":"18686","suppressedMessages":"18687","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18688","messages":"18689","suppressedMessages":"18690","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18691","messages":"18692","suppressedMessages":"18693","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18694","messages":"18695","suppressedMessages":"18696","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18697","messages":"18698","suppressedMessages":"18699","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18700","messages":"18701","suppressedMessages":"18702","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18703","messages":"18704","suppressedMessages":"18705","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18706","messages":"18707","suppressedMessages":"18708","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18709","messages":"18710","suppressedMessages":"18711","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18712","messages":"18713","suppressedMessages":"18714","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18715","messages":"18716","suppressedMessages":"18717","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18718","messages":"18719","suppressedMessages":"18720","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18721","messages":"18722","suppressedMessages":"18723","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18724","messages":"18725","suppressedMessages":"18726","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18727","messages":"18728","suppressedMessages":"18729","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18730","messages":"18731","suppressedMessages":"18732","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18733","messages":"18734","suppressedMessages":"18735","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18736","messages":"18737","suppressedMessages":"18738","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18739","messages":"18740","suppressedMessages":"18741","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18742","messages":"18743","suppressedMessages":"18744","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18745","messages":"18746","suppressedMessages":"18747","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18748","messages":"18749","suppressedMessages":"18750","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18751","messages":"18752","suppressedMessages":"18753","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18754","messages":"18755","suppressedMessages":"18756","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18757","messages":"18758","suppressedMessages":"18759","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18760","messages":"18761","suppressedMessages":"18762","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18763","messages":"18764","suppressedMessages":"18765","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18766","messages":"18767","suppressedMessages":"18768","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18769","messages":"18770","suppressedMessages":"18771","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18772","messages":"18773","suppressedMessages":"18774","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18775","messages":"18776","suppressedMessages":"18777","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18778","messages":"18779","suppressedMessages":"18780","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18781","messages":"18782","suppressedMessages":"18783","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18784","messages":"18785","suppressedMessages":"18786","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18787","messages":"18788","suppressedMessages":"18789","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18790","messages":"18791","suppressedMessages":"18792","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18793","messages":"18794","suppressedMessages":"18795","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18796","messages":"18797","suppressedMessages":"18798","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18799","messages":"18800","suppressedMessages":"18801","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18802","messages":"18803","suppressedMessages":"18804","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18805","messages":"18806","suppressedMessages":"18807","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18808","messages":"18809","suppressedMessages":"18810","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18811","messages":"18812","suppressedMessages":"18813","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18814","messages":"18815","suppressedMessages":"18816","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18817","messages":"18818","suppressedMessages":"18819","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18820","messages":"18821","suppressedMessages":"18822","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18823","messages":"18824","suppressedMessages":"18825","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18826","messages":"18827","suppressedMessages":"18828","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18829","messages":"18830","suppressedMessages":"18831","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18832","messages":"18833","suppressedMessages":"18834","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18835","messages":"18836","suppressedMessages":"18837","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18838","messages":"18839","suppressedMessages":"18840","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18841","messages":"18842","suppressedMessages":"18843","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18844","messages":"18845","suppressedMessages":"18846","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18847","messages":"18848","suppressedMessages":"18849","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18850","messages":"18851","suppressedMessages":"18852","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18853","messages":"18854","suppressedMessages":"18855","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18856","messages":"18857","suppressedMessages":"18858","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18859","messages":"18860","suppressedMessages":"18861","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18862","messages":"18863","suppressedMessages":"18864","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18865","messages":"18866","suppressedMessages":"18867","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18868","messages":"18869","suppressedMessages":"18870","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18871","messages":"18872","suppressedMessages":"18873","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18874","messages":"18875","suppressedMessages":"18876","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18877","messages":"18878","suppressedMessages":"18879","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18880","messages":"18881","suppressedMessages":"18882","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18883","messages":"18884","suppressedMessages":"18885","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18886","messages":"18887","suppressedMessages":"18888","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18889","messages":"18890","suppressedMessages":"18891","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18892","messages":"18893","suppressedMessages":"18894","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18895","messages":"18896","suppressedMessages":"18897","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18898","messages":"18899","suppressedMessages":"18900","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18901","messages":"18902","suppressedMessages":"18903","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18904","messages":"18905","suppressedMessages":"18906","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18907","messages":"18908","suppressedMessages":"18909","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18910","messages":"18911","suppressedMessages":"18912","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18913","messages":"18914","suppressedMessages":"18915","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"18916"},{"filePath":"18917","messages":"18918","suppressedMessages":"18919","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18920","messages":"18921","suppressedMessages":"18922","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18923","messages":"18924","suppressedMessages":"18925","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18926","messages":"18927","suppressedMessages":"18928","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18929","messages":"18930","suppressedMessages":"18931","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18932","messages":"18933","suppressedMessages":"18934","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18935","messages":"18936","suppressedMessages":"18937","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18938","messages":"18939","suppressedMessages":"18940","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18941","messages":"18942","suppressedMessages":"18943","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18944","messages":"18945","suppressedMessages":"18946","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18947","messages":"18948","suppressedMessages":"18949","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18950","messages":"18951","suppressedMessages":"18952","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18953","messages":"18954","suppressedMessages":"18955","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18956","messages":"18957","suppressedMessages":"18958","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18959","messages":"18960","suppressedMessages":"18961","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18962","messages":"18963","suppressedMessages":"18964","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"18965"},{"filePath":"18966","messages":"18967","suppressedMessages":"18968","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18969","messages":"18970","suppressedMessages":"18971","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18972","messages":"18973","suppressedMessages":"18974","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18975","messages":"18976","suppressedMessages":"18977","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18978","messages":"18979","suppressedMessages":"18980","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18981","messages":"18982","suppressedMessages":"18983","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18984","messages":"18985","suppressedMessages":"18986","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18987","messages":"18988","suppressedMessages":"18989","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18990","messages":"18991","suppressedMessages":"18992","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18993","messages":"18994","suppressedMessages":"18995","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"18996","messages":"18997","suppressedMessages":"18998","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"18999"},{"filePath":"19000","messages":"19001","suppressedMessages":"19002","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19003","messages":"19004","suppressedMessages":"19005","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19006","messages":"19007","suppressedMessages":"19008","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19009","messages":"19010","suppressedMessages":"19011","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19012","messages":"19013","suppressedMessages":"19014","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19015","messages":"19016","suppressedMessages":"19017","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19018","messages":"19019","suppressedMessages":"19020","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19021","messages":"19022","suppressedMessages":"19023","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19024","messages":"19025","suppressedMessages":"19026","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19027","messages":"19028","suppressedMessages":"19029","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19030","messages":"19031","suppressedMessages":"19032","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19033","messages":"19034","suppressedMessages":"19035","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19036","messages":"19037","suppressedMessages":"19038","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19039","messages":"19040","suppressedMessages":"19041","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19042","messages":"19043","suppressedMessages":"19044","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19045","messages":"19046","suppressedMessages":"19047","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19048","messages":"19049","suppressedMessages":"19050","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19051","messages":"19052","suppressedMessages":"19053","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19054","messages":"19055","suppressedMessages":"19056","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19057","messages":"19058","suppressedMessages":"19059","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19060","messages":"19061","suppressedMessages":"19062","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19063","messages":"19064","suppressedMessages":"19065","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19066","messages":"19067","suppressedMessages":"19068","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19069","messages":"19070","suppressedMessages":"19071","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19072","messages":"19073","suppressedMessages":"19074","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19075","messages":"19076","suppressedMessages":"19077","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19078","messages":"19079","suppressedMessages":"19080","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19081","messages":"19082","suppressedMessages":"19083","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19084","messages":"19085","suppressedMessages":"19086","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19087","messages":"19088","suppressedMessages":"19089","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19090","messages":"19091","suppressedMessages":"19092","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19093","messages":"19094","suppressedMessages":"19095","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19096","messages":"19097","suppressedMessages":"19098","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19099","messages":"19100","suppressedMessages":"19101","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19102","messages":"19103","suppressedMessages":"19104","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19105","messages":"19106","suppressedMessages":"19107","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19108","messages":"19109","suppressedMessages":"19110","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19111","messages":"19112","suppressedMessages":"19113","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19114","messages":"19115","suppressedMessages":"19116","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19117","messages":"19118","suppressedMessages":"19119","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"19120"},{"filePath":"19121","messages":"19122","suppressedMessages":"19123","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19124","messages":"19125","suppressedMessages":"19126","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19127","messages":"19128","suppressedMessages":"19129","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19130","messages":"19131","suppressedMessages":"19132","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19133","messages":"19134","suppressedMessages":"19135","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19136","messages":"19137","suppressedMessages":"19138","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19139","messages":"19140","suppressedMessages":"19141","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19142","messages":"19143","suppressedMessages":"19144","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19145","messages":"19146","suppressedMessages":"19147","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19148","messages":"19149","suppressedMessages":"19150","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19151","messages":"19152","suppressedMessages":"19153","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19154","messages":"19155","suppressedMessages":"19156","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19157","messages":"19158","suppressedMessages":"19159","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19160","messages":"19161","suppressedMessages":"19162","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19163","messages":"19164","suppressedMessages":"19165","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19166","messages":"19167","suppressedMessages":"19168","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19169","messages":"19170","suppressedMessages":"19171","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19172","messages":"19173","suppressedMessages":"19174","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19175","messages":"19176","suppressedMessages":"19177","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19178","messages":"19179","suppressedMessages":"19180","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19181","messages":"19182","suppressedMessages":"19183","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19184","messages":"19185","suppressedMessages":"19186","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19187","messages":"19188","suppressedMessages":"19189","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"19190"},{"filePath":"19191","messages":"19192","suppressedMessages":"19193","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"19194"},{"filePath":"19195","messages":"19196","suppressedMessages":"19197","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19198","messages":"19199","suppressedMessages":"19200","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19201","messages":"19202","suppressedMessages":"19203","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19204","messages":"19205","suppressedMessages":"19206","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19207","messages":"19208","suppressedMessages":"19209","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19210","messages":"19211","suppressedMessages":"19212","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19213","messages":"19214","suppressedMessages":"19215","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19216","messages":"19217","suppressedMessages":"19218","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19219","messages":"19220","suppressedMessages":"19221","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19222","messages":"19223","suppressedMessages":"19224","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19225","messages":"19226","suppressedMessages":"19227","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19228","messages":"19229","suppressedMessages":"19230","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19231","messages":"19232","suppressedMessages":"19233","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19234","messages":"19235","suppressedMessages":"19236","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19237","messages":"19238","suppressedMessages":"19239","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19240","messages":"19241","suppressedMessages":"19242","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19243","messages":"19244","suppressedMessages":"19245","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19246","messages":"19247","suppressedMessages":"19248","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19249","messages":"19250","suppressedMessages":"19251","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19252","messages":"19253","suppressedMessages":"19254","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19255","messages":"19256","suppressedMessages":"19257","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19258","messages":"19259","suppressedMessages":"19260","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19261","messages":"19262","suppressedMessages":"19263","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19264","messages":"19265","suppressedMessages":"19266","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"19267"},{"filePath":"19268","messages":"19269","suppressedMessages":"19270","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19271","messages":"19272","suppressedMessages":"19273","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19274","messages":"19275","suppressedMessages":"19276","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19277","messages":"19278","suppressedMessages":"19279","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19280","messages":"19281","suppressedMessages":"19282","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19283","messages":"19284","suppressedMessages":"19285","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19286","messages":"19287","suppressedMessages":"19288","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19289","messages":"19290","suppressedMessages":"19291","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19292","messages":"19293","suppressedMessages":"19294","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19295","messages":"19296","suppressedMessages":"19297","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19298","messages":"19299","suppressedMessages":"19300","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19301","messages":"19302","suppressedMessages":"19303","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19304","messages":"19305","suppressedMessages":"19306","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19307","messages":"19308","suppressedMessages":"19309","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19310","messages":"19311","suppressedMessages":"19312","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19313","messages":"19314","suppressedMessages":"19315","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19316","messages":"19317","suppressedMessages":"19318","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19319","messages":"19320","suppressedMessages":"19321","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19322","messages":"19323","suppressedMessages":"19324","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19325","messages":"19326","suppressedMessages":"19327","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19328","messages":"19329","suppressedMessages":"19330","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19331","messages":"19332","suppressedMessages":"19333","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19334","messages":"19335","suppressedMessages":"19336","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19337","messages":"19338","suppressedMessages":"19339","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19340","messages":"19341","suppressedMessages":"19342","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19343","messages":"19344","suppressedMessages":"19345","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19346","messages":"19347","suppressedMessages":"19348","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19349","messages":"19350","suppressedMessages":"19351","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19352","messages":"19353","suppressedMessages":"19354","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19355","messages":"19356","suppressedMessages":"19357","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19358","messages":"19359","suppressedMessages":"19360","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19361","messages":"19362","suppressedMessages":"19363","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19364","messages":"19365","suppressedMessages":"19366","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19367","messages":"19368","suppressedMessages":"19369","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19370","messages":"19371","suppressedMessages":"19372","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19373","messages":"19374","suppressedMessages":"19375","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19376","messages":"19377","suppressedMessages":"19378","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19379","messages":"19380","suppressedMessages":"19381","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19382","messages":"19383","suppressedMessages":"19384","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19385","messages":"19386","suppressedMessages":"19387","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19388","messages":"19389","suppressedMessages":"19390","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19391","messages":"19392","suppressedMessages":"19393","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19394","messages":"19395","suppressedMessages":"19396","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19397","messages":"19398","suppressedMessages":"19399","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19400","messages":"19401","suppressedMessages":"19402","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19403","messages":"19404","suppressedMessages":"19405","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19406","messages":"19407","suppressedMessages":"19408","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19409","messages":"19410","suppressedMessages":"19411","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19412","messages":"19413","suppressedMessages":"19414","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19415","messages":"19416","suppressedMessages":"19417","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19418","messages":"19419","suppressedMessages":"19420","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19421","messages":"19422","suppressedMessages":"19423","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19424","messages":"19425","suppressedMessages":"19426","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19427","messages":"19428","suppressedMessages":"19429","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19430","messages":"19431","suppressedMessages":"19432","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19433","messages":"19434","suppressedMessages":"19435","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"19gk6p0",{"filePath":"19436","messages":"19437","suppressedMessages":"19438","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19439","messages":"19440","suppressedMessages":"19441","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19442","messages":"19443","suppressedMessages":"19444","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19445","messages":"19446","suppressedMessages":"19447","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19448","messages":"19449","suppressedMessages":"19450","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19451","messages":"19452","suppressedMessages":"19453","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19454","messages":"19455","suppressedMessages":"19456","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19457","messages":"19458","suppressedMessages":"19459","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19460","messages":"19461","suppressedMessages":"19462","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19463","messages":"19464","suppressedMessages":"19465","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19466","messages":"19467","suppressedMessages":"19468","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19469","messages":"19470","suppressedMessages":"19471","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19472","messages":"19473","suppressedMessages":"19474","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19475","messages":"19476","suppressedMessages":"19477","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19478","messages":"19479","suppressedMessages":"19480","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19481","messages":"19482","suppressedMessages":"19483","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19484","messages":"19485","suppressedMessages":"19486","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19487","messages":"19488","suppressedMessages":"19489","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19490","messages":"19491","suppressedMessages":"19492","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19493","messages":"19494","suppressedMessages":"19495","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19496","messages":"19497","suppressedMessages":"19498","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19499","messages":"19500","suppressedMessages":"19501","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19502","messages":"19503","suppressedMessages":"19504","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19505","messages":"19506","suppressedMessages":"19507","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19508","messages":"19509","suppressedMessages":"19510","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19511","messages":"19512","suppressedMessages":"19513","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19514","messages":"19515","suppressedMessages":"19516","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19517","messages":"19518","suppressedMessages":"19519","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19520","messages":"19521","suppressedMessages":"19522","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19523","messages":"19524","suppressedMessages":"19525","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19526","messages":"19527","suppressedMessages":"19528","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19529","messages":"19530","suppressedMessages":"19531","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19532","messages":"19533","suppressedMessages":"19534","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19535","messages":"19536","suppressedMessages":"19537","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19538","messages":"19539","suppressedMessages":"19540","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19541","messages":"19542","suppressedMessages":"19543","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19544","messages":"19545","suppressedMessages":"19546","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19547","messages":"19548","suppressedMessages":"19549","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19550","messages":"19551","suppressedMessages":"19552","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19553","messages":"19554","suppressedMessages":"19555","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19556","messages":"19557","suppressedMessages":"19558","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19559","messages":"19560","suppressedMessages":"19561","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19562","messages":"19563","suppressedMessages":"19564","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19565","messages":"19566","suppressedMessages":"19567","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19568","messages":"19569","suppressedMessages":"19570","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19571","messages":"19572","suppressedMessages":"19573","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19574","messages":"19575","suppressedMessages":"19576","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19577","messages":"19578","suppressedMessages":"19579","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19580","messages":"19581","suppressedMessages":"19582","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19583","messages":"19584","suppressedMessages":"19585","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19586","messages":"19587","suppressedMessages":"19588","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19589","messages":"19590","suppressedMessages":"19591","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19592","messages":"19593","suppressedMessages":"19594","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19595","messages":"19596","suppressedMessages":"19597","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19598","messages":"19599","suppressedMessages":"19600","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19601","messages":"19602","suppressedMessages":"19603","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19604","messages":"19605","suppressedMessages":"19606","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19607","messages":"19608","suppressedMessages":"19609","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19610","messages":"19611","suppressedMessages":"19612","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19613","messages":"19614","suppressedMessages":"19615","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19616","messages":"19617","suppressedMessages":"19618","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19619","messages":"19620","suppressedMessages":"19621","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19622","messages":"19623","suppressedMessages":"19624","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19625","messages":"19626","suppressedMessages":"19627","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19628","messages":"19629","suppressedMessages":"19630","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19631","messages":"19632","suppressedMessages":"19633","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19634","messages":"19635","suppressedMessages":"19636","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19637","messages":"19638","suppressedMessages":"19639","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19640","messages":"19641","suppressedMessages":"19642","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19643","messages":"19644","suppressedMessages":"19645","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19646","messages":"19647","suppressedMessages":"19648","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19649","messages":"19650","suppressedMessages":"19651","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19652","messages":"19653","suppressedMessages":"19654","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19655","messages":"19656","suppressedMessages":"19657","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19658","messages":"19659","suppressedMessages":"19660","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19661","messages":"19662","suppressedMessages":"19663","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19664","messages":"19665","suppressedMessages":"19666","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19667","messages":"19668","suppressedMessages":"19669","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19670","messages":"19671","suppressedMessages":"19672","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19673","messages":"19674","suppressedMessages":"19675","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19676","messages":"19677","suppressedMessages":"19678","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19679","messages":"19680","suppressedMessages":"19681","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19682","messages":"19683","suppressedMessages":"19684","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19685","messages":"19686","suppressedMessages":"19687","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19688","messages":"19689","suppressedMessages":"19690","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19691","messages":"19692","suppressedMessages":"19693","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19694","messages":"19695","suppressedMessages":"19696","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19697","messages":"19698","suppressedMessages":"19699","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19700","messages":"19701","suppressedMessages":"19702","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19703","messages":"19704","suppressedMessages":"19705","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19706","messages":"19707","suppressedMessages":"19708","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19709","messages":"19710","suppressedMessages":"19711","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19712","messages":"19713","suppressedMessages":"19714","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19715","messages":"19716","suppressedMessages":"19717","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19718","messages":"19719","suppressedMessages":"19720","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19721","messages":"19722","suppressedMessages":"19723","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19724","messages":"19725","suppressedMessages":"19726","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19727","messages":"19728","suppressedMessages":"19729","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19730","messages":"19731","suppressedMessages":"19732","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19733","messages":"19734","suppressedMessages":"19735","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19736","messages":"19737","suppressedMessages":"19738","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19739","messages":"19740","suppressedMessages":"19741","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19742","messages":"19743","suppressedMessages":"19744","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19745","messages":"19746","suppressedMessages":"19747","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19748","messages":"19749","suppressedMessages":"19750","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19751","messages":"19752","suppressedMessages":"19753","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19754","messages":"19755","suppressedMessages":"19756","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19757","messages":"19758","suppressedMessages":"19759","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19760","messages":"19761","suppressedMessages":"19762","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19763","messages":"19764","suppressedMessages":"19765","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19766","messages":"19767","suppressedMessages":"19768","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19769","messages":"19770","suppressedMessages":"19771","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19772","messages":"19773","suppressedMessages":"19774","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19775","messages":"19776","suppressedMessages":"19777","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19778","messages":"19779","suppressedMessages":"19780","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19781","messages":"19782","suppressedMessages":"19783","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19784","messages":"19785","suppressedMessages":"19786","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19787","messages":"19788","suppressedMessages":"19789","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19790","messages":"19791","suppressedMessages":"19792","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19793","messages":"19794","suppressedMessages":"19795","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19796","messages":"19797","suppressedMessages":"19798","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19799","messages":"19800","suppressedMessages":"19801","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19802","messages":"19803","suppressedMessages":"19804","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19805","messages":"19806","suppressedMessages":"19807","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19808","messages":"19809","suppressedMessages":"19810","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19811","messages":"19812","suppressedMessages":"19813","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19814","messages":"19815","suppressedMessages":"19816","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19817","messages":"19818","suppressedMessages":"19819","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19820","messages":"19821","suppressedMessages":"19822","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19823","messages":"19824","suppressedMessages":"19825","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19826","messages":"19827","suppressedMessages":"19828","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19829","messages":"19830","suppressedMessages":"19831","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19832","messages":"19833","suppressedMessages":"19834","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19835","messages":"19836","suppressedMessages":"19837","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19838","messages":"19839","suppressedMessages":"19840","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19841","messages":"19842","suppressedMessages":"19843","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19844","messages":"19845","suppressedMessages":"19846","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19847","messages":"19848","suppressedMessages":"19849","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19850","messages":"19851","suppressedMessages":"19852","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19853","messages":"19854","suppressedMessages":"19855","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19856","messages":"19857","suppressedMessages":"19858","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19859","messages":"19860","suppressedMessages":"19861","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19862","messages":"19863","suppressedMessages":"19864","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19865","messages":"19866","suppressedMessages":"19867","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19868","messages":"19869","suppressedMessages":"19870","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19871","messages":"19872","suppressedMessages":"19873","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19874","messages":"19875","suppressedMessages":"19876","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19877","messages":"19878","suppressedMessages":"19879","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19880","messages":"19881","suppressedMessages":"19882","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19883","messages":"19884","suppressedMessages":"19885","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19886","messages":"19887","suppressedMessages":"19888","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19889","messages":"19890","suppressedMessages":"19891","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19892","messages":"19893","suppressedMessages":"19894","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19895","messages":"19896","suppressedMessages":"19897","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19898","messages":"19899","suppressedMessages":"19900","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19901","messages":"19902","suppressedMessages":"19903","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19904","messages":"19905","suppressedMessages":"19906","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19907","messages":"19908","suppressedMessages":"19909","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19910","messages":"19911","suppressedMessages":"19912","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19913","messages":"19914","suppressedMessages":"19915","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19916","messages":"19917","suppressedMessages":"19918","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19919","messages":"19920","suppressedMessages":"19921","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19922","messages":"19923","suppressedMessages":"19924","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19925","messages":"19926","suppressedMessages":"19927","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19928","messages":"19929","suppressedMessages":"19930","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19931","messages":"19932","suppressedMessages":"19933","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"19934"},{"filePath":"19935","messages":"19936","suppressedMessages":"19937","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"19938"},{"filePath":"19939","messages":"19940","suppressedMessages":"19941","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19942","messages":"19943","suppressedMessages":"19944","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19945","messages":"19946","suppressedMessages":"19947","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19948","messages":"19949","suppressedMessages":"19950","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19951","messages":"19952","suppressedMessages":"19953","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19954","messages":"19955","suppressedMessages":"19956","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19957","messages":"19958","suppressedMessages":"19959","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19960","messages":"19961","suppressedMessages":"19962","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"19963"},{"filePath":"19964","messages":"19965","suppressedMessages":"19966","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"19967"},{"filePath":"19968","messages":"19969","suppressedMessages":"19970","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"19971"},{"filePath":"19972","messages":"19973","suppressedMessages":"19974","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19975","messages":"19976","suppressedMessages":"19977","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19978","messages":"19979","suppressedMessages":"19980","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19981","messages":"19982","suppressedMessages":"19983","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19984","messages":"19985","suppressedMessages":"19986","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19987","messages":"19988","suppressedMessages":"19989","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19990","messages":"19991","suppressedMessages":"19992","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19993","messages":"19994","suppressedMessages":"19995","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19996","messages":"19997","suppressedMessages":"19998","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"19999","messages":"20000","suppressedMessages":"20001","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20002","messages":"20003","suppressedMessages":"20004","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20005","messages":"20006","suppressedMessages":"20007","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20008","messages":"20009","suppressedMessages":"20010","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20011","messages":"20012","suppressedMessages":"20013","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20014","messages":"20015","suppressedMessages":"20016","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20017","messages":"20018","suppressedMessages":"20019","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20020","messages":"20021","suppressedMessages":"20022","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20023","messages":"20024","suppressedMessages":"20025","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20026","messages":"20027","suppressedMessages":"20028","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20029","messages":"20030","suppressedMessages":"20031","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20032","messages":"20033","suppressedMessages":"20034","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20035","messages":"20036","suppressedMessages":"20037","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20038","messages":"20039","suppressedMessages":"20040","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20041","messages":"20042","suppressedMessages":"20043","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20044","messages":"20045","suppressedMessages":"20046","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20047","messages":"20048","suppressedMessages":"20049","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20050","messages":"20051","suppressedMessages":"20052","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20053","messages":"20054","suppressedMessages":"20055","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20056","messages":"20057","suppressedMessages":"20058","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20059","messages":"20060","suppressedMessages":"20061","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20062","messages":"20063","suppressedMessages":"20064","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20065","messages":"20066","suppressedMessages":"20067","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20068","messages":"20069","suppressedMessages":"20070","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20071","messages":"20072","suppressedMessages":"20073","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20074","messages":"20075","suppressedMessages":"20076","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20077","messages":"20078","suppressedMessages":"20079","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20080","messages":"20081","suppressedMessages":"20082","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20083","messages":"20084","suppressedMessages":"20085","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20086","messages":"20087","suppressedMessages":"20088","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20089","messages":"20090","suppressedMessages":"20091","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20092","messages":"20093","suppressedMessages":"20094","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20095","messages":"20096","suppressedMessages":"20097","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20098","messages":"20099","suppressedMessages":"20100","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20101","messages":"20102","suppressedMessages":"20103","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20104","messages":"20105","suppressedMessages":"20106","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20107","messages":"20108","suppressedMessages":"20109","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20110","messages":"20111","suppressedMessages":"20112","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20113","messages":"20114","suppressedMessages":"20115","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20116","messages":"20117","suppressedMessages":"20118","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20119","messages":"20120","suppressedMessages":"20121","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1qfd3wi",{"filePath":"20122","messages":"20123","suppressedMessages":"20124","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20125","messages":"20126","suppressedMessages":"20127","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20128","messages":"20129","suppressedMessages":"20130","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20131","messages":"20132","suppressedMessages":"20133","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20134","messages":"20135","suppressedMessages":"20136","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20137","messages":"20138","suppressedMessages":"20139","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20140","messages":"20141","suppressedMessages":"20142","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20143","messages":"20144","suppressedMessages":"20145","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20146","messages":"20147","suppressedMessages":"20148","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20149","messages":"20150","suppressedMessages":"20151","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20152","messages":"20153","suppressedMessages":"20154","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20155","messages":"20156","suppressedMessages":"20157","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20158","messages":"20159","suppressedMessages":"20160","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20161","messages":"20162","suppressedMessages":"20163","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20164","messages":"20165","suppressedMessages":"20166","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20167","messages":"20168","suppressedMessages":"20169","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20170","messages":"20171","suppressedMessages":"20172","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20173","messages":"20174","suppressedMessages":"20175","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20176","messages":"20177","suppressedMessages":"20178","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20179","messages":"20180","suppressedMessages":"20181","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20182","messages":"20183","suppressedMessages":"20184","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20185","messages":"20186","suppressedMessages":"20187","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20188","messages":"20189","suppressedMessages":"20190","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20191","messages":"20192","suppressedMessages":"20193","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20194","messages":"20195","suppressedMessages":"20196","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20197","messages":"20198","suppressedMessages":"20199","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20200","messages":"20201","suppressedMessages":"20202","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20203","messages":"20204","suppressedMessages":"20205","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20206","messages":"20207","suppressedMessages":"20208","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20209","messages":"20210","suppressedMessages":"20211","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20212","messages":"20213","suppressedMessages":"20214","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20215","messages":"20216","suppressedMessages":"20217","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20218","messages":"20219","suppressedMessages":"20220","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20221","messages":"20222","suppressedMessages":"20223","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20224","messages":"20225","suppressedMessages":"20226","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20227","messages":"20228","suppressedMessages":"20229","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20230","messages":"20231","suppressedMessages":"20232","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20233","messages":"20234","suppressedMessages":"20235","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20236","messages":"20237","suppressedMessages":"20238","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20239","messages":"20240","suppressedMessages":"20241","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20242","messages":"20243","suppressedMessages":"20244","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20245","messages":"20246","suppressedMessages":"20247","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20248","messages":"20249","suppressedMessages":"20250","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20251","messages":"20252","suppressedMessages":"20253","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20254","messages":"20255","suppressedMessages":"20256","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20257","messages":"20258","suppressedMessages":"20259","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20260","messages":"20261","suppressedMessages":"20262","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20263","messages":"20264","suppressedMessages":"20265","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20266","messages":"20267","suppressedMessages":"20268","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20269","messages":"20270","suppressedMessages":"20271","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20272","messages":"20273","suppressedMessages":"20274","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20275","messages":"20276","suppressedMessages":"20277","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20278","messages":"20279","suppressedMessages":"20280","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20281","messages":"20282","suppressedMessages":"20283","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20284","messages":"20285","suppressedMessages":"20286","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20287","messages":"20288","suppressedMessages":"20289","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20290","messages":"20291","suppressedMessages":"20292","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20293","messages":"20294","suppressedMessages":"20295","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20296","messages":"20297","suppressedMessages":"20298","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20299","messages":"20300","suppressedMessages":"20301","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20302","messages":"20303","suppressedMessages":"20304","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20305","messages":"20306","suppressedMessages":"20307","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20308","messages":"20309","suppressedMessages":"20310","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20311","messages":"20312","suppressedMessages":"20313","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20314","messages":"20315","suppressedMessages":"20316","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20317","messages":"20318","suppressedMessages":"20319","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20320","messages":"20321","suppressedMessages":"20322","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20323","messages":"20324","suppressedMessages":"20325","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20326","messages":"20327","suppressedMessages":"20328","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20329","messages":"20330","suppressedMessages":"20331","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20332","messages":"20333","suppressedMessages":"20334","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20335","messages":"20336","suppressedMessages":"20337","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20338","messages":"20339","suppressedMessages":"20340","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20341","messages":"20342","suppressedMessages":"20343","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20344","messages":"20345","suppressedMessages":"20346","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20347","messages":"20348","suppressedMessages":"20349","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20350","messages":"20351","suppressedMessages":"20352","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20353","messages":"20354","suppressedMessages":"20355","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20356","messages":"20357","suppressedMessages":"20358","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20359","messages":"20360","suppressedMessages":"20361","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20362","messages":"20363","suppressedMessages":"20364","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20365","messages":"20366","suppressedMessages":"20367","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"20368"},{"filePath":"20369","messages":"20370","suppressedMessages":"20371","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20372","messages":"20373","suppressedMessages":"20374","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20375","messages":"20376","suppressedMessages":"20377","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20378","messages":"20379","suppressedMessages":"20380","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20381","messages":"20382","suppressedMessages":"20383","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20384","messages":"20385","suppressedMessages":"20386","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20387","messages":"20388","suppressedMessages":"20389","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"20390"},{"filePath":"20391","messages":"20392","suppressedMessages":"20393","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20394","messages":"20395","suppressedMessages":"20396","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20397","messages":"20398","suppressedMessages":"20399","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20400","messages":"20401","suppressedMessages":"20402","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20403","messages":"20404","suppressedMessages":"20405","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20406","messages":"20407","suppressedMessages":"20408","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20409","messages":"20410","suppressedMessages":"20411","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20412","messages":"20413","suppressedMessages":"20414","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20415","messages":"20416","suppressedMessages":"20417","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20418","messages":"20419","suppressedMessages":"20420","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20421","messages":"20422","suppressedMessages":"20423","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20424","messages":"20425","suppressedMessages":"20426","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20427","messages":"20428","suppressedMessages":"20429","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20430","messages":"20431","suppressedMessages":"20432","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20433","messages":"20434","suppressedMessages":"20435","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20436","messages":"20437","suppressedMessages":"20438","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20439","messages":"20440","suppressedMessages":"20441","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20442","messages":"20443","suppressedMessages":"20444","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20445","messages":"20446","suppressedMessages":"20447","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20448","messages":"20449","suppressedMessages":"20450","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20451","messages":"20452","suppressedMessages":"20453","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20454","messages":"20455","suppressedMessages":"20456","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20457","messages":"20458","suppressedMessages":"20459","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20460","messages":"20461","suppressedMessages":"20462","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20463","messages":"20464","suppressedMessages":"20465","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20466","messages":"20467","suppressedMessages":"20468","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20469","messages":"20470","suppressedMessages":"20471","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20472","messages":"20473","suppressedMessages":"20474","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20475","messages":"20476","suppressedMessages":"20477","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20478","messages":"20479","suppressedMessages":"20480","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20481","messages":"20482","suppressedMessages":"20483","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20484","messages":"20485","suppressedMessages":"20486","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20487","messages":"20488","suppressedMessages":"20489","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20490","messages":"20491","suppressedMessages":"20492","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20493","messages":"20494","suppressedMessages":"20495","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20496","messages":"20497","suppressedMessages":"20498","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20499","messages":"20500","suppressedMessages":"20501","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20502","messages":"20503","suppressedMessages":"20504","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20505","messages":"20506","suppressedMessages":"20507","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20508","messages":"20509","suppressedMessages":"20510","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20511","messages":"20512","suppressedMessages":"20513","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20514","messages":"20515","suppressedMessages":"20516","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20517","messages":"20518","suppressedMessages":"20519","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20520","messages":"20521","suppressedMessages":"20522","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20523","messages":"20524","suppressedMessages":"20525","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20526","messages":"20527","suppressedMessages":"20528","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20529","messages":"20530","suppressedMessages":"20531","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20532","messages":"20533","suppressedMessages":"20534","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20535","messages":"20536","suppressedMessages":"20537","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20538","messages":"20539","suppressedMessages":"20540","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20541","messages":"20542","suppressedMessages":"20543","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20544","messages":"20545","suppressedMessages":"20546","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20547","messages":"20548","suppressedMessages":"20549","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20550","messages":"20551","suppressedMessages":"20552","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20553","messages":"20554","suppressedMessages":"20555","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20556","messages":"20557","suppressedMessages":"20558","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20559","messages":"20560","suppressedMessages":"20561","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20562","messages":"20563","suppressedMessages":"20564","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20565","messages":"20566","suppressedMessages":"20567","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20568","messages":"20569","suppressedMessages":"20570","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20571","messages":"20572","suppressedMessages":"20573","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20574","messages":"20575","suppressedMessages":"20576","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20577","messages":"20578","suppressedMessages":"20579","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20580","messages":"20581","suppressedMessages":"20582","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20583","messages":"20584","suppressedMessages":"20585","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20586","messages":"20587","suppressedMessages":"20588","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20589","messages":"20590","suppressedMessages":"20591","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20592","messages":"20593","suppressedMessages":"20594","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20595","messages":"20596","suppressedMessages":"20597","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20598","messages":"20599","suppressedMessages":"20600","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20601","messages":"20602","suppressedMessages":"20603","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20604","messages":"20605","suppressedMessages":"20606","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20607","messages":"20608","suppressedMessages":"20609","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20610","messages":"20611","suppressedMessages":"20612","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20613","messages":"20614","suppressedMessages":"20615","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20616","messages":"20617","suppressedMessages":"20618","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20619","messages":"20620","suppressedMessages":"20621","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20622","messages":"20623","suppressedMessages":"20624","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20625","messages":"20626","suppressedMessages":"20627","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20628","messages":"20629","suppressedMessages":"20630","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20631","messages":"20632","suppressedMessages":"20633","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20634","messages":"20635","suppressedMessages":"20636","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20637","messages":"20638","suppressedMessages":"20639","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20640","messages":"20641","suppressedMessages":"20642","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20643","messages":"20644","suppressedMessages":"20645","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20646","messages":"20647","suppressedMessages":"20648","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20649","messages":"20650","suppressedMessages":"20651","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20652","messages":"20653","suppressedMessages":"20654","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20655","messages":"20656","suppressedMessages":"20657","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20658","messages":"20659","suppressedMessages":"20660","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20661","messages":"20662","suppressedMessages":"20663","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20664","messages":"20665","suppressedMessages":"20666","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20667","messages":"20668","suppressedMessages":"20669","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20670","messages":"20671","suppressedMessages":"20672","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20673","messages":"20674","suppressedMessages":"20675","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20676","messages":"20677","suppressedMessages":"20678","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20679","messages":"20680","suppressedMessages":"20681","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20682","messages":"20683","suppressedMessages":"20684","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20685","messages":"20686","suppressedMessages":"20687","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20688","messages":"20689","suppressedMessages":"20690","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20691","messages":"20692","suppressedMessages":"20693","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20694","messages":"20695","suppressedMessages":"20696","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1wtd92j",{"filePath":"20697","messages":"20698","suppressedMessages":"20699","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20700","messages":"20701","suppressedMessages":"20702","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20703","messages":"20704","suppressedMessages":"20705","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20706","messages":"20707","suppressedMessages":"20708","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20709","messages":"20710","suppressedMessages":"20711","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20712","messages":"20713","suppressedMessages":"20714","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20715","messages":"20716","suppressedMessages":"20717","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20718","messages":"20719","suppressedMessages":"20720","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20721","messages":"20722","suppressedMessages":"20723","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20724","messages":"20725","suppressedMessages":"20726","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20727","messages":"20728","suppressedMessages":"20729","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20730","messages":"20731","suppressedMessages":"20732","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20733","messages":"20734","suppressedMessages":"20735","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20736","messages":"20737","suppressedMessages":"20738","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20739","messages":"20740","suppressedMessages":"20741","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20742","messages":"20743","suppressedMessages":"20744","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20745","messages":"20746","suppressedMessages":"20747","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20748","messages":"20749","suppressedMessages":"20750","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20751","messages":"20752","suppressedMessages":"20753","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1emjek9",{"filePath":"20754","messages":"20755","suppressedMessages":"20756","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20757","messages":"20758","suppressedMessages":"20759","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20760","messages":"20761","suppressedMessages":"20762","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20763","messages":"20764","suppressedMessages":"20765","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20766","messages":"20767","suppressedMessages":"20768","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20769","messages":"20770","suppressedMessages":"20771","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20772","messages":"20773","suppressedMessages":"20774","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20775","messages":"20776","suppressedMessages":"20777","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20778","messages":"20779","suppressedMessages":"20780","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20781","messages":"20782","suppressedMessages":"20783","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20784","messages":"20785","suppressedMessages":"20786","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20787","messages":"20788","suppressedMessages":"20789","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20790","messages":"20791","suppressedMessages":"20792","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20793","messages":"20794","suppressedMessages":"20795","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20796","messages":"20797","suppressedMessages":"20798","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20799","messages":"20800","suppressedMessages":"20801","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20802","messages":"20803","suppressedMessages":"20804","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20805","messages":"20806","suppressedMessages":"20807","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20808","messages":"20809","suppressedMessages":"20810","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"20811"},{"filePath":"20812","messages":"20813","suppressedMessages":"20814","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20815","messages":"20816","suppressedMessages":"20817","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20818","messages":"20819","suppressedMessages":"20820","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20821","messages":"20822","suppressedMessages":"20823","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20824","messages":"20825","suppressedMessages":"20826","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20827","messages":"20828","suppressedMessages":"20829","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20830","messages":"20831","suppressedMessages":"20832","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20833","messages":"20834","suppressedMessages":"20835","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20836","messages":"20837","suppressedMessages":"20838","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20839","messages":"20840","suppressedMessages":"20841","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"20842"},{"filePath":"20843","messages":"20844","suppressedMessages":"20845","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20846","messages":"20847","suppressedMessages":"20848","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20849","messages":"20850","suppressedMessages":"20851","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20852","messages":"20853","suppressedMessages":"20854","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20855","messages":"20856","suppressedMessages":"20857","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20858","messages":"20859","suppressedMessages":"20860","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20861","messages":"20862","suppressedMessages":"20863","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20864","messages":"20865","suppressedMessages":"20866","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20867","messages":"20868","suppressedMessages":"20869","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20870","messages":"20871","suppressedMessages":"20872","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"20873"},{"filePath":"20874","messages":"20875","suppressedMessages":"20876","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20877","messages":"20878","suppressedMessages":"20879","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20880","messages":"20881","suppressedMessages":"20882","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20883","messages":"20884","suppressedMessages":"20885","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20886","messages":"20887","suppressedMessages":"20888","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20889","messages":"20890","suppressedMessages":"20891","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20892","messages":"20893","suppressedMessages":"20894","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20895","messages":"20896","suppressedMessages":"20897","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20898","messages":"20899","suppressedMessages":"20900","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20901","messages":"20902","suppressedMessages":"20903","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20904","messages":"20905","suppressedMessages":"20906","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20907","messages":"20908","suppressedMessages":"20909","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20910","messages":"20911","suppressedMessages":"20912","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20913","messages":"20914","suppressedMessages":"20915","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20916","messages":"20917","suppressedMessages":"20918","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20919","messages":"20920","suppressedMessages":"20921","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20922","messages":"20923","suppressedMessages":"20924","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20925","messages":"20926","suppressedMessages":"20927","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20928","messages":"20929","suppressedMessages":"20930","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"20931"},{"filePath":"20932","messages":"20933","suppressedMessages":"20934","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20935","messages":"20936","suppressedMessages":"20937","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20938","messages":"20939","suppressedMessages":"20940","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20941","messages":"20942","suppressedMessages":"20943","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20944","messages":"20945","suppressedMessages":"20946","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20947","messages":"20948","suppressedMessages":"20949","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20950","messages":"20951","suppressedMessages":"20952","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20953","messages":"20954","suppressedMessages":"20955","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20956","messages":"20957","suppressedMessages":"20958","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20959","messages":"20960","suppressedMessages":"20961","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20962","messages":"20963","suppressedMessages":"20964","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20965","messages":"20966","suppressedMessages":"20967","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20968","messages":"20969","suppressedMessages":"20970","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20971","messages":"20972","suppressedMessages":"20973","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20974","messages":"20975","suppressedMessages":"20976","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20977","messages":"20978","suppressedMessages":"20979","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20980","messages":"20981","suppressedMessages":"20982","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20983","messages":"20984","suppressedMessages":"20985","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20986","messages":"20987","suppressedMessages":"20988","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20989","messages":"20990","suppressedMessages":"20991","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20992","messages":"20993","suppressedMessages":"20994","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20995","messages":"20996","suppressedMessages":"20997","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"20998","messages":"20999","suppressedMessages":"21000","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21001","messages":"21002","suppressedMessages":"21003","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21004","messages":"21005","suppressedMessages":"21006","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21007","messages":"21008","suppressedMessages":"21009","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21010","messages":"21011","suppressedMessages":"21012","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21013","messages":"21014","suppressedMessages":"21015","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21016","messages":"21017","suppressedMessages":"21018","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21019","messages":"21020","suppressedMessages":"21021","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21022","messages":"21023","suppressedMessages":"21024","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21025","messages":"21026","suppressedMessages":"21027","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21028","messages":"21029","suppressedMessages":"21030","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21031","messages":"21032","suppressedMessages":"21033","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21034","messages":"21035","suppressedMessages":"21036","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21037","messages":"21038","suppressedMessages":"21039","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21040","messages":"21041","suppressedMessages":"21042","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21043","messages":"21044","suppressedMessages":"21045","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21046","messages":"21047","suppressedMessages":"21048","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21049","messages":"21050","suppressedMessages":"21051","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21052","messages":"21053","suppressedMessages":"21054","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21055","messages":"21056","suppressedMessages":"21057","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21058","messages":"21059","suppressedMessages":"21060","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21061","messages":"21062","suppressedMessages":"21063","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21064","messages":"21065","suppressedMessages":"21066","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21067","messages":"21068","suppressedMessages":"21069","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21070","messages":"21071","suppressedMessages":"21072","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21073","messages":"21074","suppressedMessages":"21075","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21076","messages":"21077","suppressedMessages":"21078","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21079","messages":"21080","suppressedMessages":"21081","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21082","messages":"21083","suppressedMessages":"21084","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21085","messages":"21086","suppressedMessages":"21087","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21088","messages":"21089","suppressedMessages":"21090","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21091","messages":"21092","suppressedMessages":"21093","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21094","messages":"21095","suppressedMessages":"21096","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21097","messages":"21098","suppressedMessages":"21099","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21100","messages":"21101","suppressedMessages":"21102","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21103","messages":"21104","suppressedMessages":"21105","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21106","messages":"21107","suppressedMessages":"21108","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21109","messages":"21110","suppressedMessages":"21111","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21112","messages":"21113","suppressedMessages":"21114","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21115","messages":"21116","suppressedMessages":"21117","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21118","messages":"21119","suppressedMessages":"21120","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21121","messages":"21122","suppressedMessages":"21123","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21124","messages":"21125","suppressedMessages":"21126","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21127","messages":"21128","suppressedMessages":"21129","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21130","messages":"21131","suppressedMessages":"21132","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21133","messages":"21134","suppressedMessages":"21135","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21136","messages":"21137","suppressedMessages":"21138","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21139","messages":"21140","suppressedMessages":"21141","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21142","messages":"21143","suppressedMessages":"21144","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21145","messages":"21146","suppressedMessages":"21147","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21148","messages":"21149","suppressedMessages":"21150","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21151","messages":"21152","suppressedMessages":"21153","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21154","messages":"21155","suppressedMessages":"21156","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21157","messages":"21158","suppressedMessages":"21159","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21160","messages":"21161","suppressedMessages":"21162","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21163","messages":"21164","suppressedMessages":"21165","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"21166"},{"filePath":"21167","messages":"21168","suppressedMessages":"21169","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21170","messages":"21171","suppressedMessages":"21172","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21173","messages":"21174","suppressedMessages":"21175","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21176","messages":"21177","suppressedMessages":"21178","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21179","messages":"21180","suppressedMessages":"21181","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21182","messages":"21183","suppressedMessages":"21184","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21185","messages":"21186","suppressedMessages":"21187","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21188","messages":"21189","suppressedMessages":"21190","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21191","messages":"21192","suppressedMessages":"21193","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21194","messages":"21195","suppressedMessages":"21196","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21197","messages":"21198","suppressedMessages":"21199","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21200","messages":"21201","suppressedMessages":"21202","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21203","messages":"21204","suppressedMessages":"21205","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21206","messages":"21207","suppressedMessages":"21208","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21209","messages":"21210","suppressedMessages":"21211","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21212","messages":"21213","suppressedMessages":"21214","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21215","messages":"21216","suppressedMessages":"21217","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21218","messages":"21219","suppressedMessages":"21220","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21221","messages":"21222","suppressedMessages":"21223","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21224","messages":"21225","suppressedMessages":"21226","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21227","messages":"21228","suppressedMessages":"21229","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21230","messages":"21231","suppressedMessages":"21232","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21233","messages":"21234","suppressedMessages":"21235","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21236","messages":"21237","suppressedMessages":"21238","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21239","messages":"21240","suppressedMessages":"21241","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21242","messages":"21243","suppressedMessages":"21244","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21245","messages":"21246","suppressedMessages":"21247","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21248","messages":"21249","suppressedMessages":"21250","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21251","messages":"21252","suppressedMessages":"21253","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21254","messages":"21255","suppressedMessages":"21256","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21257","messages":"21258","suppressedMessages":"21259","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21260","messages":"21261","suppressedMessages":"21262","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21263","messages":"21264","suppressedMessages":"21265","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21266","messages":"21267","suppressedMessages":"21268","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21269","messages":"21270","suppressedMessages":"21271","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21272","messages":"21273","suppressedMessages":"21274","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21275","messages":"21276","suppressedMessages":"21277","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21278","messages":"21279","suppressedMessages":"21280","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21281","messages":"21282","suppressedMessages":"21283","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21284","messages":"21285","suppressedMessages":"21286","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21287","messages":"21288","suppressedMessages":"21289","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21290","messages":"21291","suppressedMessages":"21292","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21293","messages":"21294","suppressedMessages":"21295","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21296","messages":"21297","suppressedMessages":"21298","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21299","messages":"21300","suppressedMessages":"21301","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21302","messages":"21303","suppressedMessages":"21304","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21305","messages":"21306","suppressedMessages":"21307","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21308","messages":"21309","suppressedMessages":"21310","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21311","messages":"21312","suppressedMessages":"21313","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21314","messages":"21315","suppressedMessages":"21316","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21317","messages":"21318","suppressedMessages":"21319","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21320","messages":"21321","suppressedMessages":"21322","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21323","messages":"21324","suppressedMessages":"21325","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21326","messages":"21327","suppressedMessages":"21328","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21329","messages":"21330","suppressedMessages":"21331","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21332","messages":"21333","suppressedMessages":"21334","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21335","messages":"21336","suppressedMessages":"21337","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21338","messages":"21339","suppressedMessages":"21340","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21341","messages":"21342","suppressedMessages":"21343","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21344","messages":"21345","suppressedMessages":"21346","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21347","messages":"21348","suppressedMessages":"21349","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21350","messages":"21351","suppressedMessages":"21352","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21353","messages":"21354","suppressedMessages":"21355","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21356","messages":"21357","suppressedMessages":"21358","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21359","messages":"21360","suppressedMessages":"21361","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21362","messages":"21363","suppressedMessages":"21364","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21365","messages":"21366","suppressedMessages":"21367","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21368","messages":"21369","suppressedMessages":"21370","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21371","messages":"21372","suppressedMessages":"21373","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21374","messages":"21375","suppressedMessages":"21376","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21377","messages":"21378","suppressedMessages":"21379","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21380","messages":"21381","suppressedMessages":"21382","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21383","messages":"21384","suppressedMessages":"21385","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21386","messages":"21387","suppressedMessages":"21388","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21389","messages":"21390","suppressedMessages":"21391","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21392","messages":"21393","suppressedMessages":"21394","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21395","messages":"21396","suppressedMessages":"21397","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21398","messages":"21399","suppressedMessages":"21400","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21401","messages":"21402","suppressedMessages":"21403","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21404","messages":"21405","suppressedMessages":"21406","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21407","messages":"21408","suppressedMessages":"21409","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21410","messages":"21411","suppressedMessages":"21412","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21413","messages":"21414","suppressedMessages":"21415","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21416","messages":"21417","suppressedMessages":"21418","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21419","messages":"21420","suppressedMessages":"21421","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21422","messages":"21423","suppressedMessages":"21424","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21425","messages":"21426","suppressedMessages":"21427","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21428","messages":"21429","suppressedMessages":"21430","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21431","messages":"21432","suppressedMessages":"21433","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21434","messages":"21435","suppressedMessages":"21436","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21437","messages":"21438","suppressedMessages":"21439","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21440","messages":"21441","suppressedMessages":"21442","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21443","messages":"21444","suppressedMessages":"21445","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21446","messages":"21447","suppressedMessages":"21448","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21449","messages":"21450","suppressedMessages":"21451","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21452","messages":"21453","suppressedMessages":"21454","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21455","messages":"21456","suppressedMessages":"21457","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21458","messages":"21459","suppressedMessages":"21460","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21461","messages":"21462","suppressedMessages":"21463","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21464","messages":"21465","suppressedMessages":"21466","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21467","messages":"21468","suppressedMessages":"21469","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21470","messages":"21471","suppressedMessages":"21472","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21473","messages":"21474","suppressedMessages":"21475","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21476","messages":"21477","suppressedMessages":"21478","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21479","messages":"21480","suppressedMessages":"21481","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21482","messages":"21483","suppressedMessages":"21484","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21485","messages":"21486","suppressedMessages":"21487","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21488","messages":"21489","suppressedMessages":"21490","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21491","messages":"21492","suppressedMessages":"21493","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21494","messages":"21495","suppressedMessages":"21496","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21497","messages":"21498","suppressedMessages":"21499","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21500","messages":"21501","suppressedMessages":"21502","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21503","messages":"21504","suppressedMessages":"21505","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21506","messages":"21507","suppressedMessages":"21508","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21509","messages":"21510","suppressedMessages":"21511","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21512","messages":"21513","suppressedMessages":"21514","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21515","messages":"21516","suppressedMessages":"21517","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21518","messages":"21519","suppressedMessages":"21520","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21521","messages":"21522","suppressedMessages":"21523","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21524","messages":"21525","suppressedMessages":"21526","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21527","messages":"21528","suppressedMessages":"21529","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21530","messages":"21531","suppressedMessages":"21532","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21533","messages":"21534","suppressedMessages":"21535","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21536","messages":"21537","suppressedMessages":"21538","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21539","messages":"21540","suppressedMessages":"21541","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21542","messages":"21543","suppressedMessages":"21544","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21545","messages":"21546","suppressedMessages":"21547","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21548","messages":"21549","suppressedMessages":"21550","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21551","messages":"21552","suppressedMessages":"21553","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21554","messages":"21555","suppressedMessages":"21556","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21557","messages":"21558","suppressedMessages":"21559","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21560","messages":"21561","suppressedMessages":"21562","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21563","messages":"21564","suppressedMessages":"21565","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21566","messages":"21567","suppressedMessages":"21568","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21569","messages":"21570","suppressedMessages":"21571","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21572","messages":"21573","suppressedMessages":"21574","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21575","messages":"21576","suppressedMessages":"21577","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21578","messages":"21579","suppressedMessages":"21580","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21581","messages":"21582","suppressedMessages":"21583","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21584","messages":"21585","suppressedMessages":"21586","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21587","messages":"21588","suppressedMessages":"21589","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"21590"},{"filePath":"21591","messages":"21592","suppressedMessages":"21593","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21594","messages":"21595","suppressedMessages":"21596","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"21597"},{"filePath":"21598","messages":"21599","suppressedMessages":"21600","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21601","messages":"21602","suppressedMessages":"21603","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21604","messages":"21605","suppressedMessages":"21606","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21607","messages":"21608","suppressedMessages":"21609","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21610","messages":"21611","suppressedMessages":"21612","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21613","messages":"21614","suppressedMessages":"21615","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21616","messages":"21617","suppressedMessages":"21618","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21619","messages":"21620","suppressedMessages":"21621","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21622","messages":"21623","suppressedMessages":"21624","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21625","messages":"21626","suppressedMessages":"21627","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21628","messages":"21629","suppressedMessages":"21630","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21631","messages":"21632","suppressedMessages":"21633","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21634","messages":"21635","suppressedMessages":"21636","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21637","messages":"21638","suppressedMessages":"21639","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21640","messages":"21641","suppressedMessages":"21642","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21643","messages":"21644","suppressedMessages":"21645","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21646","messages":"21647","suppressedMessages":"21648","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21649","messages":"21650","suppressedMessages":"21651","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21652","messages":"21653","suppressedMessages":"21654","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21655","messages":"21656","suppressedMessages":"21657","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21658","messages":"21659","suppressedMessages":"21660","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21661","messages":"21662","suppressedMessages":"21663","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21664","messages":"21665","suppressedMessages":"21666","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21667","messages":"21668","suppressedMessages":"21669","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21670","messages":"21671","suppressedMessages":"21672","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21673","messages":"21674","suppressedMessages":"21675","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21676","messages":"21677","suppressedMessages":"21678","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21679","messages":"21680","suppressedMessages":"21681","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21682","messages":"21683","suppressedMessages":"21684","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21685","messages":"21686","suppressedMessages":"21687","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21688","messages":"21689","suppressedMessages":"21690","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21691","messages":"21692","suppressedMessages":"21693","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21694","messages":"21695","suppressedMessages":"21696","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21697","messages":"21698","suppressedMessages":"21699","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21700","messages":"21701","suppressedMessages":"21702","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21703","messages":"21704","suppressedMessages":"21705","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21706","messages":"21707","suppressedMessages":"21708","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21709","messages":"21710","suppressedMessages":"21711","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21712","messages":"21713","suppressedMessages":"21714","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21715","messages":"21716","suppressedMessages":"21717","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"21718"},{"filePath":"21719","messages":"21720","suppressedMessages":"21721","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21722","messages":"21723","suppressedMessages":"21724","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21725","messages":"21726","suppressedMessages":"21727","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21728","messages":"21729","suppressedMessages":"21730","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21731","messages":"21732","suppressedMessages":"21733","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21734","messages":"21735","suppressedMessages":"21736","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21737","messages":"21738","suppressedMessages":"21739","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21740","messages":"21741","suppressedMessages":"21742","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21743","messages":"21744","suppressedMessages":"21745","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21746","messages":"21747","suppressedMessages":"21748","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21749","messages":"21750","suppressedMessages":"21751","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21752","messages":"21753","suppressedMessages":"21754","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"21755"},{"filePath":"21756","messages":"21757","suppressedMessages":"21758","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21759","messages":"21760","suppressedMessages":"21761","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21762","messages":"21763","suppressedMessages":"21764","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21765","messages":"21766","suppressedMessages":"21767","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21768","messages":"21769","suppressedMessages":"21770","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21771","messages":"21772","suppressedMessages":"21773","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21774","messages":"21775","suppressedMessages":"21776","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21777","messages":"21778","suppressedMessages":"21779","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21780","messages":"21781","suppressedMessages":"21782","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21783","messages":"21784","suppressedMessages":"21785","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21786","messages":"21787","suppressedMessages":"21788","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21789","messages":"21790","suppressedMessages":"21791","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"21792"},{"filePath":"21793","messages":"21794","suppressedMessages":"21795","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21796","messages":"21797","suppressedMessages":"21798","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21799","messages":"21800","suppressedMessages":"21801","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21802","messages":"21803","suppressedMessages":"21804","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21805","messages":"21806","suppressedMessages":"21807","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21808","messages":"21809","suppressedMessages":"21810","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21811","messages":"21812","suppressedMessages":"21813","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21814","messages":"21815","suppressedMessages":"21816","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21817","messages":"21818","suppressedMessages":"21819","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21820","messages":"21821","suppressedMessages":"21822","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21823","messages":"21824","suppressedMessages":"21825","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21826","messages":"21827","suppressedMessages":"21828","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21829","messages":"21830","suppressedMessages":"21831","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21832","messages":"21833","suppressedMessages":"21834","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21835","messages":"21836","suppressedMessages":"21837","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21838","messages":"21839","suppressedMessages":"21840","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21841","messages":"21842","suppressedMessages":"21843","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21844","messages":"21845","suppressedMessages":"21846","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21847","messages":"21848","suppressedMessages":"21849","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21850","messages":"21851","suppressedMessages":"21852","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21853","messages":"21854","suppressedMessages":"21855","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21856","messages":"21857","suppressedMessages":"21858","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21859","messages":"21860","suppressedMessages":"21861","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21862","messages":"21863","suppressedMessages":"21864","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21865","messages":"21866","suppressedMessages":"21867","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21868","messages":"21869","suppressedMessages":"21870","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21871","messages":"21872","suppressedMessages":"21873","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21874","messages":"21875","suppressedMessages":"21876","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21877","messages":"21878","suppressedMessages":"21879","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21880","messages":"21881","suppressedMessages":"21882","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21883","messages":"21884","suppressedMessages":"21885","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21886","messages":"21887","suppressedMessages":"21888","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21889","messages":"21890","suppressedMessages":"21891","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21892","messages":"21893","suppressedMessages":"21894","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21895","messages":"21896","suppressedMessages":"21897","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21898","messages":"21899","suppressedMessages":"21900","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21901","messages":"21902","suppressedMessages":"21903","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21904","messages":"21905","suppressedMessages":"21906","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21907","messages":"21908","suppressedMessages":"21909","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21910","messages":"21911","suppressedMessages":"21912","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21913","messages":"21914","suppressedMessages":"21915","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21916","messages":"21917","suppressedMessages":"21918","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21919","messages":"21920","suppressedMessages":"21921","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21922","messages":"21923","suppressedMessages":"21924","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21925","messages":"21926","suppressedMessages":"21927","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21928","messages":"21929","suppressedMessages":"21930","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"171xqow",{"filePath":"21931","messages":"21932","suppressedMessages":"21933","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21934","messages":"21935","suppressedMessages":"21936","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21937","messages":"21938","suppressedMessages":"21939","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21940","messages":"21941","suppressedMessages":"21942","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21943","messages":"21944","suppressedMessages":"21945","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21946","messages":"21947","suppressedMessages":"21948","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21949","messages":"21950","suppressedMessages":"21951","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21952","messages":"21953","suppressedMessages":"21954","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21955","messages":"21956","suppressedMessages":"21957","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21958","messages":"21959","suppressedMessages":"21960","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21961","messages":"21962","suppressedMessages":"21963","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21964","messages":"21965","suppressedMessages":"21966","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21967","messages":"21968","suppressedMessages":"21969","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21970","messages":"21971","suppressedMessages":"21972","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21973","messages":"21974","suppressedMessages":"21975","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21976","messages":"21977","suppressedMessages":"21978","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21979","messages":"21980","suppressedMessages":"21981","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21982","messages":"21983","suppressedMessages":"21984","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21985","messages":"21986","suppressedMessages":"21987","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21988","messages":"21989","suppressedMessages":"21990","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21991","messages":"21992","suppressedMessages":"21993","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21994","messages":"21995","suppressedMessages":"21996","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"21997","messages":"21998","suppressedMessages":"21999","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22000","messages":"22001","suppressedMessages":"22002","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22003","messages":"22004","suppressedMessages":"22005","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22006","messages":"22007","suppressedMessages":"22008","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22009","messages":"22010","suppressedMessages":"22011","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22012","messages":"22013","suppressedMessages":"22014","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22015","messages":"22016","suppressedMessages":"22017","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22018","messages":"22019","suppressedMessages":"22020","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22021","messages":"22022","suppressedMessages":"22023","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22024","messages":"22025","suppressedMessages":"22026","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22027","messages":"22028","suppressedMessages":"22029","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22030","messages":"22031","suppressedMessages":"22032","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22033","messages":"22034","suppressedMessages":"22035","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22036","messages":"22037","suppressedMessages":"22038","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22039","messages":"22040","suppressedMessages":"22041","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"22042"},{"filePath":"22043","messages":"22044","suppressedMessages":"22045","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"22046"},{"filePath":"22047","messages":"22048","suppressedMessages":"22049","errorCount":0,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":0,"fixableWarningCount":0,"source":"22050"},{"filePath":"22051","messages":"22052","suppressedMessages":"22053","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22054","messages":"22055","suppressedMessages":"22056","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22057","messages":"22058","suppressedMessages":"22059","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22060","messages":"22061","suppressedMessages":"22062","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22063","messages":"22064","suppressedMessages":"22065","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22066","messages":"22067","suppressedMessages":"22068","errorCount":0,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"22069"},{"filePath":"22070","messages":"22071","suppressedMessages":"22072","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22073","messages":"22074","suppressedMessages":"22075","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22076","messages":"22077","suppressedMessages":"22078","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22079","messages":"22080","suppressedMessages":"22081","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22082","messages":"22083","suppressedMessages":"22084","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22085","messages":"22086","suppressedMessages":"22087","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22088","messages":"22089","suppressedMessages":"22090","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22091","messages":"22092","suppressedMessages":"22093","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22094","messages":"22095","suppressedMessages":"22096","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22097","messages":"22098","suppressedMessages":"22099","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22100","messages":"22101","suppressedMessages":"22102","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22103","messages":"22104","suppressedMessages":"22105","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22106","messages":"22107","suppressedMessages":"22108","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22109","messages":"22110","suppressedMessages":"22111","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22112","messages":"22113","suppressedMessages":"22114","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22115","messages":"22116","suppressedMessages":"22117","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22118","messages":"22119","suppressedMessages":"22120","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22121","messages":"22122","suppressedMessages":"22123","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22124","messages":"22125","suppressedMessages":"22126","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22127","messages":"22128","suppressedMessages":"22129","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22130","messages":"22131","suppressedMessages":"22132","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22133","messages":"22134","suppressedMessages":"22135","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22136","messages":"22137","suppressedMessages":"22138","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22139","messages":"22140","suppressedMessages":"22141","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22142","messages":"22143","suppressedMessages":"22144","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22145","messages":"22146","suppressedMessages":"22147","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22148","messages":"22149","suppressedMessages":"22150","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22151","messages":"22152","suppressedMessages":"22153","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22154","messages":"22155","suppressedMessages":"22156","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22157","messages":"22158","suppressedMessages":"22159","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22160","messages":"22161","suppressedMessages":"22162","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22163","messages":"22164","suppressedMessages":"22165","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22166","messages":"22167","suppressedMessages":"22168","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22169","messages":"22170","suppressedMessages":"22171","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22172","messages":"22173","suppressedMessages":"22174","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22175","messages":"22176","suppressedMessages":"22177","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22178","messages":"22179","suppressedMessages":"22180","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22181","messages":"22182","suppressedMessages":"22183","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22184","messages":"22185","suppressedMessages":"22186","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22187","messages":"22188","suppressedMessages":"22189","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22190","messages":"22191","suppressedMessages":"22192","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22193","messages":"22194","suppressedMessages":"22195","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22196","messages":"22197","suppressedMessages":"22198","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22199","messages":"22200","suppressedMessages":"22201","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22202","messages":"22203","suppressedMessages":"22204","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22205","messages":"22206","suppressedMessages":"22207","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22208","messages":"22209","suppressedMessages":"22210","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22211","messages":"22212","suppressedMessages":"22213","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22214","messages":"22215","suppressedMessages":"22216","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22217","messages":"22218","suppressedMessages":"22219","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22220","messages":"22221","suppressedMessages":"22222","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22223","messages":"22224","suppressedMessages":"22225","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22226","messages":"22227","suppressedMessages":"22228","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22229","messages":"22230","suppressedMessages":"22231","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22232","messages":"22233","suppressedMessages":"22234","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22235","messages":"22236","suppressedMessages":"22237","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22238","messages":"22239","suppressedMessages":"22240","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22241","messages":"22242","suppressedMessages":"22243","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22244","messages":"22245","suppressedMessages":"22246","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22247","messages":"22248","suppressedMessages":"22249","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22250","messages":"22251","suppressedMessages":"22252","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22253","messages":"22254","suppressedMessages":"22255","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22256","messages":"22257","suppressedMessages":"22258","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22259","messages":"22260","suppressedMessages":"22261","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22262","messages":"22263","suppressedMessages":"22264","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22265","messages":"22266","suppressedMessages":"22267","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22268","messages":"22269","suppressedMessages":"22270","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22271","messages":"22272","suppressedMessages":"22273","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22274","messages":"22275","suppressedMessages":"22276","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22277","messages":"22278","suppressedMessages":"22279","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22280","messages":"22281","suppressedMessages":"22282","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22283","messages":"22284","suppressedMessages":"22285","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22286","messages":"22287","suppressedMessages":"22288","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22289","messages":"22290","suppressedMessages":"22291","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22292","messages":"22293","suppressedMessages":"22294","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22295","messages":"22296","suppressedMessages":"22297","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22298","messages":"22299","suppressedMessages":"22300","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22301","messages":"22302","suppressedMessages":"22303","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22304","messages":"22305","suppressedMessages":"22306","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22307","messages":"22308","suppressedMessages":"22309","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22310","messages":"22311","suppressedMessages":"22312","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22313","messages":"22314","suppressedMessages":"22315","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22316","messages":"22317","suppressedMessages":"22318","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22319","messages":"22320","suppressedMessages":"22321","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22322","messages":"22323","suppressedMessages":"22324","errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"22325"},{"filePath":"22326","messages":"22327","suppressedMessages":"22328","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22329","messages":"22330","suppressedMessages":"22331","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22332","messages":"22333","suppressedMessages":"22334","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"14rkzey",{"filePath":"22335","messages":"22336","suppressedMessages":"22337","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22338","messages":"22339","suppressedMessages":"22340","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22341","messages":"22342","suppressedMessages":"22343","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22344","messages":"22345","suppressedMessages":"22346","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22347","messages":"22348","suppressedMessages":"22349","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22350","messages":"22351","suppressedMessages":"22352","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22353","messages":"22354","suppressedMessages":"22355","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22356","messages":"22357","suppressedMessages":"22358","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22359","messages":"22360","suppressedMessages":"22361","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22362","messages":"22363","suppressedMessages":"22364","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22365","messages":"22366","suppressedMessages":"22367","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22368","messages":"22369","suppressedMessages":"22370","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22371","messages":"22372","suppressedMessages":"22373","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22374","messages":"22375","suppressedMessages":"22376","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22377","messages":"22378","suppressedMessages":"22379","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22380","messages":"22381","suppressedMessages":"22382","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22383","messages":"22384","suppressedMessages":"22385","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22386","messages":"22387","suppressedMessages":"22388","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22389","messages":"22390","suppressedMessages":"22391","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22392","messages":"22393","suppressedMessages":"22394","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22395","messages":"22396","suppressedMessages":"22397","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22398","messages":"22399","suppressedMessages":"22400","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22401","messages":"22402","suppressedMessages":"22403","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22404","messages":"22405","suppressedMessages":"22406","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22407","messages":"22408","suppressedMessages":"22409","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22410","messages":"22411","suppressedMessages":"22412","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22413","messages":"22414","suppressedMessages":"22415","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22416","messages":"22417","suppressedMessages":"22418","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22419","messages":"22420","suppressedMessages":"22421","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22422","messages":"22423","suppressedMessages":"22424","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22425","messages":"22426","suppressedMessages":"22427","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22428","messages":"22429","suppressedMessages":"22430","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22431","messages":"22432","suppressedMessages":"22433","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22434","messages":"22435","suppressedMessages":"22436","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22437","messages":"22438","suppressedMessages":"22439","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22440","messages":"22441","suppressedMessages":"22442","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22443","messages":"22444","suppressedMessages":"22445","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22446","messages":"22447","suppressedMessages":"22448","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22449","messages":"22450","suppressedMessages":"22451","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22452","messages":"22453","suppressedMessages":"22454","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22455","messages":"22456","suppressedMessages":"22457","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22458","messages":"22459","suppressedMessages":"22460","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22461","messages":"22462","suppressedMessages":"22463","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22464","messages":"22465","suppressedMessages":"22466","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22467","messages":"22468","suppressedMessages":"22469","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22470","messages":"22471","suppressedMessages":"22472","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22473","messages":"22474","suppressedMessages":"22475","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22476","messages":"22477","suppressedMessages":"22478","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22479","messages":"22480","suppressedMessages":"22481","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22482","messages":"22483","suppressedMessages":"22484","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22485","messages":"22486","suppressedMessages":"22487","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22488","messages":"22489","suppressedMessages":"22490","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22491","messages":"22492","suppressedMessages":"22493","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22494","messages":"22495","suppressedMessages":"22496","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22497","messages":"22498","suppressedMessages":"22499","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22500","messages":"22501","suppressedMessages":"22502","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22503","messages":"22504","suppressedMessages":"22505","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22506","messages":"22507","suppressedMessages":"22508","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22509","messages":"22510","suppressedMessages":"22511","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22512","messages":"22513","suppressedMessages":"22514","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22515","messages":"22516","suppressedMessages":"22517","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22518","messages":"22519","suppressedMessages":"22520","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22521","messages":"22522","suppressedMessages":"22523","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22524","messages":"22525","suppressedMessages":"22526","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22527","messages":"22528","suppressedMessages":"22529","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22530","messages":"22531","suppressedMessages":"22532","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22533","messages":"22534","suppressedMessages":"22535","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22536","messages":"22537","suppressedMessages":"22538","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22539","messages":"22540","suppressedMessages":"22541","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22542","messages":"22543","suppressedMessages":"22544","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22545","messages":"22546","suppressedMessages":"22547","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22548","messages":"22549","suppressedMessages":"22550","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22551","messages":"22552","suppressedMessages":"22553","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22554","messages":"22555","suppressedMessages":"22556","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22557","messages":"22558","suppressedMessages":"22559","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22560","messages":"22561","suppressedMessages":"22562","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22563","messages":"22564","suppressedMessages":"22565","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22566","messages":"22567","suppressedMessages":"22568","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22569","messages":"22570","suppressedMessages":"22571","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22572","messages":"22573","suppressedMessages":"22574","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22575","messages":"22576","suppressedMessages":"22577","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22578","messages":"22579","suppressedMessages":"22580","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22581","messages":"22582","suppressedMessages":"22583","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22584","messages":"22585","suppressedMessages":"22586","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22587","messages":"22588","suppressedMessages":"22589","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22590","messages":"22591","suppressedMessages":"22592","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22593","messages":"22594","suppressedMessages":"22595","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22596","messages":"22597","suppressedMessages":"22598","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22599","messages":"22600","suppressedMessages":"22601","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22602","messages":"22603","suppressedMessages":"22604","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22605","messages":"22606","suppressedMessages":"22607","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22608","messages":"22609","suppressedMessages":"22610","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22611","messages":"22612","suppressedMessages":"22613","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22614","messages":"22615","suppressedMessages":"22616","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22617","messages":"22618","suppressedMessages":"22619","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22620","messages":"22621","suppressedMessages":"22622","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22623","messages":"22624","suppressedMessages":"22625","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22626","messages":"22627","suppressedMessages":"22628","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22629","messages":"22630","suppressedMessages":"22631","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22632","messages":"22633","suppressedMessages":"22634","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22635","messages":"22636","suppressedMessages":"22637","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22638","messages":"22639","suppressedMessages":"22640","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22641","messages":"22642","suppressedMessages":"22643","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22644","messages":"22645","suppressedMessages":"22646","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22647","messages":"22648","suppressedMessages":"22649","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22650","messages":"22651","suppressedMessages":"22652","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22653","messages":"22654","suppressedMessages":"22655","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22656","messages":"22657","suppressedMessages":"22658","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22659","messages":"22660","suppressedMessages":"22661","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22662","messages":"22663","suppressedMessages":"22664","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22665","messages":"22666","suppressedMessages":"22667","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22668","messages":"22669","suppressedMessages":"22670","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22671","messages":"22672","suppressedMessages":"22673","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22674","messages":"22675","suppressedMessages":"22676","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22677","messages":"22678","suppressedMessages":"22679","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22680","messages":"22681","suppressedMessages":"22682","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22683","messages":"22684","suppressedMessages":"22685","errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"22686"},{"filePath":"22687","messages":"22688","suppressedMessages":"22689","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22690","messages":"22691","suppressedMessages":"22692","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22693","messages":"22694","suppressedMessages":"22695","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22696","messages":"22697","suppressedMessages":"22698","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22699","messages":"22700","suppressedMessages":"22701","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22702","messages":"22703","suppressedMessages":"22704","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22705","messages":"22706","suppressedMessages":"22707","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22708","messages":"22709","suppressedMessages":"22710","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22711","messages":"22712","suppressedMessages":"22713","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22714","messages":"22715","suppressedMessages":"22716","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22717","messages":"22718","suppressedMessages":"22719","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22720","messages":"22721","suppressedMessages":"22722","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22723","messages":"22724","suppressedMessages":"22725","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22726","messages":"22727","suppressedMessages":"22728","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22729","messages":"22730","suppressedMessages":"22731","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22732","messages":"22733","suppressedMessages":"22734","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22735","messages":"22736","suppressedMessages":"22737","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22738","messages":"22739","suppressedMessages":"22740","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22741","messages":"22742","suppressedMessages":"22743","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22744","messages":"22745","suppressedMessages":"22746","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22747","messages":"22748","suppressedMessages":"22749","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22750","messages":"22751","suppressedMessages":"22752","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22753","messages":"22754","suppressedMessages":"22755","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22756","messages":"22757","suppressedMessages":"22758","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22759","messages":"22760","suppressedMessages":"22761","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22762","messages":"22763","suppressedMessages":"22764","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22765","messages":"22766","suppressedMessages":"22767","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22768","messages":"22769","suppressedMessages":"22770","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22771","messages":"22772","suppressedMessages":"22773","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22774","messages":"22775","suppressedMessages":"22776","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22777","messages":"22778","suppressedMessages":"22779","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22780","messages":"22781","suppressedMessages":"22782","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22783","messages":"22784","suppressedMessages":"22785","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22786","messages":"22787","suppressedMessages":"22788","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22789","messages":"22790","suppressedMessages":"22791","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22792","messages":"22793","suppressedMessages":"22794","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22795","messages":"22796","suppressedMessages":"22797","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22798","messages":"22799","suppressedMessages":"22800","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22801","messages":"22802","suppressedMessages":"22803","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22804","messages":"22805","suppressedMessages":"22806","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22807","messages":"22808","suppressedMessages":"22809","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22810","messages":"22811","suppressedMessages":"22812","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22813","messages":"22814","suppressedMessages":"22815","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22816","messages":"22817","suppressedMessages":"22818","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22819","messages":"22820","suppressedMessages":"22821","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22822","messages":"22823","suppressedMessages":"22824","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22825","messages":"22826","suppressedMessages":"22827","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22828","messages":"22829","suppressedMessages":"22830","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22831","messages":"22832","suppressedMessages":"22833","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22834","messages":"22835","suppressedMessages":"22836","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22837","messages":"22838","suppressedMessages":"22839","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22840","messages":"22841","suppressedMessages":"22842","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22843","messages":"22844","suppressedMessages":"22845","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22846","messages":"22847","suppressedMessages":"22848","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22849","messages":"22850","suppressedMessages":"22851","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22852","messages":"22853","suppressedMessages":"22854","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22855","messages":"22856","suppressedMessages":"22857","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22858","messages":"22859","suppressedMessages":"22860","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22861","messages":"22862","suppressedMessages":"22863","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22864","messages":"22865","suppressedMessages":"22866","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22867","messages":"22868","suppressedMessages":"22869","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22870","messages":"22871","suppressedMessages":"22872","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22873","messages":"22874","suppressedMessages":"22875","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22876","messages":"22877","suppressedMessages":"22878","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22879","messages":"22880","suppressedMessages":"22881","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22882","messages":"22883","suppressedMessages":"22884","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22885","messages":"22886","suppressedMessages":"22887","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.mocharc.api.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.mocharc.client.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.mocharc.definition.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.mocharc.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.scripts/check-i18n.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.scripts/fix-i18n.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.scripts/make-migration.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.scripts/run-ha.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.scripts/translationDiff.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.scripts/version.js",[],["22888"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/babel.config.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/decorators.tsx",[],["22889","22890"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/logo.svg.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/main.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/manager.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/mocks/empty.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/mocks/meteor.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/.storybook/preview.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/TOTPCrowd.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/TOTPGoogle.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/TOTPLDAP.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/TOTPOAuth.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/TOTPPassword.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/TOTPSaml.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/client/overrideMeteorCall.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/MethodInvocationOverride.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/code/EmailCheck.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/code/ICodeCheck.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/code/PasswordCheckFallback.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/code/TOTPCheck.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/code/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/functions/resetTOTP.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/lib/totp.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/loginHandler.ts",["22891"],[],"import { Meteor } from 'meteor/meteor';\nimport { Accounts } from 'meteor/accounts-base';\nimport { OAuth } from 'meteor/oauth';\nimport { check } from 'meteor/check';\n\nimport { callbacks } from '../../../lib/callbacks';\nimport { checkCodeForUser } from './code/index';\n\nconst isMeteorError = (error: any): error is Meteor.Error => {\n\treturn error?.meteorError !== undefined;\n};\n\nconst isCredentialWithError = (credential: any): credential is { error: Error } => {\n\treturn credential?.error !== undefined;\n};\n\nAccounts.registerLoginHandler('totp', function (options) {\n\tif (!options.totp || !options.totp.code) {\n\t\treturn;\n\t}\n\n\t// @ts-expect-error - not sure how to type this yet\n\treturn Accounts._runLoginHandlers(this, options.totp.login);\n});\n\ncallbacks.add(\n\t'onValidateLogin',\n\t(login) => {\n\t\tif (login.methodName === 'verifyEmail') {\n\t\t\tthrow new Meteor.Error('verify-email', 'E-mail verified');\n\t\t}\n\n\t\tif (login.type === 'resume' || login.type === 'proxy') {\n\t\t\treturn login;\n\t\t}\n\t\t// CAS login doesn't yet support 2FA.\n\t\tif (login.type === 'cas') {\n\t\t\treturn login;\n\t\t}\n\n\t\tif (!login.user) {\n\t\t\treturn login;\n\t\t}\n\n\t\tconst [loginArgs] = login.methodArguments;\n\t\tconst { totp } = loginArgs;\n\n\t\tcheckCodeForUser({\n\t\t\tuser: login.user,\n\t\t\tcode: totp?.code,\n\t\t\toptions: { disablePasswordFallback: true },\n\t\t});\n\n\t\treturn login;\n\t},\n\tcallbacks.priority.MEDIUM,\n\t'2fa',\n);\n\nconst copyTo = (from: T, to: T): T => {\n\tObject.getOwnPropertyNames(to).forEach((key) => {\n\t\tconst idx: keyof T = key as keyof T;\n\t\tto[idx] = from[idx];\n\t});\n\n\treturn to;\n};\n\nconst recreateError = (errorDoc: Error | Meteor.Error): Error | Meteor.Error => {\n\tif (isMeteorError(errorDoc)) {\n\t\tconst error = new Meteor.Error('');\n\t\treturn copyTo(errorDoc, error);\n\t}\n\n\tconst error = new Error();\n\treturn copyTo(errorDoc, error);\n};\n\nOAuth._retrievePendingCredential = function (key, ...args): string | Error | void {\n\tconst credentialSecret = args.length > 0 && args[0] !== undefined ? args[0] : undefined;\n\tcheck(key, String);\n\n\tconst pendingCredential = OAuth._pendingCredentials.findOne({\n\t\tkey,\n\t\tcredentialSecret,\n\t});\n\n\tif (!pendingCredential) {\n\t\treturn;\n\t}\n\n\tif (isCredentialWithError(pendingCredential.credential)) {\n\t\tOAuth._pendingCredentials.remove({\n\t\t\t_id: pendingCredential._id,\n\t\t});\n\t\treturn recreateError(pendingCredential.credential.error);\n\t}\n\n\t// Work-around to make the credentials reusable for 2FA\n\tconst future = new Date();\n\tfuture.setMinutes(future.getMinutes() + 2);\n\n\tOAuth._pendingCredentials.update(\n\t\t{\n\t\t\t_id: pendingCredential._id,\n\t\t},\n\t\t{\n\t\t\t$set: {\n\t\t\t\tcreatedAt: future,\n\t\t\t},\n\t\t},\n\t);\n\n\treturn OAuth.openSecret(pendingCredential.credential);\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/methods/checkCodesRemaining.ts",["22892"],[],"import { Meteor } from 'meteor/meteor';\n\nMeteor.methods({\n\t'2fa:checkCodesRemaining'() {\n\t\tif (!Meteor.userId()) {\n\t\t\tthrow new Meteor.Error('not-authorized');\n\t\t}\n\n\t\tconst user = Meteor.user();\n\n\t\tif (!user) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tmethod: '2fa:checkCodesRemaining',\n\t\t\t});\n\t\t}\n\n\t\tif (!user.services || !user.services.totp || !user.services.totp.enabled) {\n\t\t\tthrow new Meteor.Error('invalid-totp');\n\t\t}\n\n\t\treturn {\n\t\t\tremaining: user.services.totp.hashedBackup.length,\n\t\t};\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/methods/disable.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/methods/enable.ts",["22893"],[],"import { Meteor } from 'meteor/meteor';\n\nimport { Users } from '../../../models/server';\nimport { TOTP } from '../lib/totp';\n\nMeteor.methods({\n\t'2fa:enable'() {\n\t\tconst userId = Meteor.userId();\n\t\tif (!userId) {\n\t\t\tthrow new Meteor.Error('not-authorized');\n\t\t}\n\n\t\tconst user = Meteor.user();\n\n\t\tif (!user || !user.username) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tmethod: '2fa:enable',\n\t\t\t});\n\t\t}\n\n\t\tconst hasUnverifiedEmail = user.emails?.some((email) => !email.verified);\n\n\t\tif (hasUnverifiedEmail) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'You need to verify your emails before setting up 2FA', {\n\t\t\t\tmethod: '2fa:enable',\n\t\t\t});\n\t\t}\n\n\t\tconst secret = TOTP.generateSecret();\n\n\t\tUsers.disable2FAAndSetTempSecretByUserId(userId, secret.base32);\n\n\t\treturn {\n\t\t\tsecret: secret.base32,\n\t\t\turl: TOTP.generateOtpauthURL(secret, user.username),\n\t\t};\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/methods/regenerateCodes.ts",["22894"],[],"import { Meteor } from 'meteor/meteor';\n\nimport { Users } from '../../../models/server';\nimport { TOTP } from '../lib/totp';\n\nMeteor.methods({\n\t'2fa:regenerateCodes'(userToken) {\n\t\tconst userId = Meteor.userId();\n\t\tif (!userId) {\n\t\t\tthrow new Meteor.Error('not-authorized');\n\t\t}\n\n\t\tconst user = Meteor.user();\n\t\tif (!user) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tmethod: '2fa:regenerateCodes',\n\t\t\t});\n\t\t}\n\n\t\tif (!user.services || !user.services.totp || !user.services.totp.enabled) {\n\t\t\tthrow new Meteor.Error('invalid-totp');\n\t\t}\n\n\t\tconst verified = TOTP.verify({\n\t\t\tsecret: user.services.totp.secret,\n\t\t\ttoken: userToken,\n\t\t\tuserId,\n\t\t\tbackupTokens: user.services.totp.hashedBackup,\n\t\t});\n\n\t\tif (verified) {\n\t\t\tconst { codes, hashedCodes } = TOTP.generateCodes();\n\n\t\t\tUsers.update2FABackupCodesByUserId(Meteor.userId(), hashedCodes);\n\t\t\treturn { codes };\n\t\t}\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/methods/validateTempToken.ts",["22895"],[],"import { Meteor } from 'meteor/meteor';\n\nimport { Users } from '../../../models/server';\nimport { TOTP } from '../lib/totp';\n\nMeteor.methods({\n\t'2fa:validateTempToken'(userToken) {\n\t\tconst userId = Meteor.userId();\n\t\tif (!userId) {\n\t\t\tthrow new Meteor.Error('not-authorized');\n\t\t}\n\n\t\tconst user = Meteor.user();\n\t\tif (!user) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tmethod: '2fa:validateTempToken',\n\t\t\t});\n\t\t}\n\n\t\tif (!user.services || !user.services.totp || !user.services.totp.tempSecret) {\n\t\t\tthrow new Meteor.Error('invalid-totp');\n\t\t}\n\n\t\tconst verified = TOTP.verify({\n\t\t\tsecret: user.services.totp.tempSecret,\n\t\t\ttoken: userToken,\n\t\t});\n\n\t\tif (verified) {\n\t\t\tconst { codes, hashedCodes } = TOTP.generateCodes();\n\n\t\t\tUsers.enable2FAAndSetSecretAndCodesByUserId(Meteor.userId(), user.services.totp.tempSecret, hashedCodes);\n\t\t\treturn { codes };\n\t\t}\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/startup/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/2fa/server/twoFactorRequired.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/action-links/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/action-links/client/lib/actionLinks.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/analytics/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/analytics/client/loadScript.ts",[],["22896","22897","22898","22899","22900","22901"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/analytics/client/trackEvents.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/analytics/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/analytics/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/api.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/api.helpers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/api.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/default/info.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/addUserToFileObj.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/composeRoomWithLastMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/deprecationWarning.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/getLoggedInUser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/getPaginationItems.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/getUserFromParams.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/getUserInfo.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/isUserFromParams.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/isWidget.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/parseJsonQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/helpers/requestParams.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/cleanQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/emailInbox.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/emoji-custom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/getServerInfo.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/getUploadFormData.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/integrations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/isValidQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/messages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/rooms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/users.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/lib/webdav.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/middlewares/authentication.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/assets.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/autotranslate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/banners.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/channels.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/channels.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/chat.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/cloud.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/commands.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/connection.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/custom-sounds.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/custom-user-status.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/dns.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/e2e.ts",[],["22902","22903"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/email-inbox.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/emoji-custom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/groups.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/im.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/import.ts",[],["22904","22905"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/instances.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/integrations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/invites.ts",[],["22906"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/ldap.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/mailer.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/misc.ts",["22907"],["22908"],"import crypto from 'crypto';\n\nimport { Meteor } from 'meteor/meteor';\nimport { check } from 'meteor/check';\nimport { TAPi18n } from 'meteor/rocketchat:tap-i18n';\nimport { EJSON } from 'meteor/ejson';\nimport { DDPRateLimiter } from 'meteor/ddp-rate-limiter';\nimport { escapeHTML } from '@rocket.chat/string-helpers';\nimport {\n\tisShieldSvgProps,\n\tisSpotlightProps,\n\tisDirectoryProps,\n\tisMethodCallProps,\n\tisMethodCallAnonProps,\n\tisMeteorCall,\n\tvalidateParamsPwGetPolicyRest,\n} from '@rocket.chat/rest-typings';\nimport type { IUser } from '@rocket.chat/core-typings';\nimport { Users as UsersRaw } from '@rocket.chat/models';\n\nimport { hasPermission } from '../../../authorization/server';\nimport { Users } from '../../../models/server';\nimport { settings } from '../../../settings/server';\nimport { API } from '../api';\nimport { getDefaultUserFields } from '../../../utils/server/functions/getDefaultUserFields';\nimport { getURL } from '../../../utils/lib/getURL';\nimport { getLogs } from '../../../../server/stream/stdout';\nimport { SystemLogger } from '../../../../server/lib/logger/system';\nimport { passwordPolicy } from '../../../lib/server';\n\n/**\n * @openapi\n * /api/v1/me:\n * get:\n * description: Gets user data of the authenticated user\n * security:\n * - authenticated: []\n * responses:\n * 200:\n * description: The user data of the authenticated user\n * content:\n * application/json:\n * schema:\n * allOf:\n * - $ref: '#/components/schemas/ApiSuccessV1'\n * - type: object\n * properties:\n * name:\n * type: string\n * username:\n * type: string\n * nickname:\n * type: string\n * emails:\n * type: array\n * items:\n * type: object\n * properties:\n * address:\n * type: string\n * verified:\n * type: boolean\n * email:\n * type: string\n * status:\n * $ref: '#/components/schemas/UserStatus'\n * statusDefault:\n * $ref: '#/components/schemas/UserStatus'\n * statusText:\n * $ref: '#/components/schemas/UserStatus'\n * statusConnection:\n * $ref: '#/components/schemas/UserStatus'\n * bio:\n * type: string\n * avatarOrigin:\n * type: string\n * enum: [none, local, upload, url]\n * utcOffset:\n * type: number\n * language:\n * type: string\n * settings:\n * type: object\n * properties:\n * preferences:\n * type: object\n * enableAutoAway:\n * type: boolean\n * idleTimeLimit:\n * type: number\n * roles:\n * type: array\n * active:\n * type: boolean\n * defaultRoom:\n * type: string\n * customFields:\n * type: array\n * requirePasswordChange:\n * type: boolean\n * requirePasswordChangeReason:\n * type: string\n * services:\n * type: object\n * properties:\n * github:\n * type: object\n * gitlab:\n * type: object\n * password:\n * type: object\n * properties:\n * exists:\n * type: boolean\n * totp:\n * type: object\n * properties:\n * enabled:\n * type: boolean\n * email2fa:\n * type: object\n * properties:\n * enabled:\n * type: boolean\n * statusLivechat:\n * type: string\n * enum: [available, 'not-available']\n * banners:\n * type: array\n * items:\n * type: object\n * properties:\n * id:\n * type: string\n * title:\n * type: string\n * text:\n * type: string\n * textArguments:\n * type: array\n * items: {}\n * modifiers:\n * type: array\n * items:\n * type: string\n * infoUrl:\n * type: string\n * oauth:\n * type: object\n * properties:\n * authorizedClients:\n * type: array\n * items:\n * type: string\n * _updatedAt:\n * type: string\n * format: date-time\n * avatarETag:\n * type: string\n * default:\n * description: Unexpected error\n * content:\n * application/json:\n * schema:\n * $ref: '#/components/schemas/ApiFailureV1'\n */\nAPI.v1.addRoute(\n\t'me',\n\t{ authRequired: true },\n\t{\n\t\tasync get() {\n\t\t\tconst fields = getDefaultUserFields();\n\t\t\tconst { services, ...user } = Users.findOneById(this.userId, { fields }) as IUser;\n\n\t\t\treturn API.v1.success(\n\t\t\t\tthis.getUserInfo({\n\t\t\t\t\t...user,\n\t\t\t\t\t...(services && {\n\t\t\t\t\t\tservices: {\n\t\t\t\t\t\t\t...services,\n\t\t\t\t\t\t\tpassword: {\n\t\t\t\t\t\t\t\t// The password hash shouldn't be leaked but the client may need to know if it exists.\n\t\t\t\t\t\t\t\texists: Boolean(services?.password?.bcrypt),\n\t\t\t\t\t\t\t} as any,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t},\n);\n\nlet onlineCache = 0;\nlet onlineCacheDate = 0;\nconst cacheInvalid = 60000; // 1 minute\n\nAPI.v1.addRoute(\n\t'shield.svg',\n\t{\n\t\tauthRequired: false,\n\t\trateLimiterOptions: {\n\t\t\tnumRequestsAllowed: 60,\n\t\t\tintervalTimeInMS: 60000,\n\t\t},\n\t\tvalidateParams: isShieldSvgProps,\n\t},\n\t{\n\t\tget() {\n\t\t\tconst { type, icon } = this.queryParams;\n\t\t\tlet { channel, name } = this.queryParams;\n\t\t\tif (!settings.get('API_Enable_Shields')) {\n\t\t\t\tthrow new Meteor.Error('error-endpoint-disabled', 'This endpoint is disabled', {\n\t\t\t\t\troute: '/api/v1/shield.svg',\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst types = settings.get('API_Shield_Types');\n\t\t\tif (\n\t\t\t\ttype &&\n\t\t\t\ttypes !== '*' &&\n\t\t\t\t!types\n\t\t\t\t\t.split(',')\n\t\t\t\t\t.map((t: string) => t.trim())\n\t\t\t\t\t.includes(type)\n\t\t\t) {\n\t\t\t\tthrow new Meteor.Error('error-shield-disabled', 'This shield type is disabled', {\n\t\t\t\t\troute: '/api/v1/shield.svg',\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst hideIcon = icon === 'false';\n\t\t\tif (hideIcon && (!name || !name.trim())) {\n\t\t\t\treturn API.v1.failure('Name cannot be empty when icon is hidden');\n\t\t\t}\n\n\t\t\tlet text;\n\t\t\tlet backgroundColor = '#4c1';\n\t\t\tswitch (type) {\n\t\t\t\tcase 'online':\n\t\t\t\t\tif (Date.now() - onlineCacheDate > cacheInvalid) {\n\t\t\t\t\t\tonlineCache = Users.findUsersNotOffline().count();\n\t\t\t\t\t\tonlineCacheDate = Date.now();\n\t\t\t\t\t}\n\n\t\t\t\t\ttext = `${onlineCache} ${TAPi18n.__('Online')}`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'channel':\n\t\t\t\t\tif (!channel) {\n\t\t\t\t\t\treturn API.v1.failure('Shield channel is required for type \"channel\"');\n\t\t\t\t\t}\n\n\t\t\t\t\ttext = `#${channel}`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'user':\n\t\t\t\t\tif (settings.get('API_Shield_user_require_auth') && !this.getLoggedInUser()) {\n\t\t\t\t\t\treturn API.v1.failure('You must be logged in to do this.');\n\t\t\t\t\t}\n\t\t\t\t\tconst user = this.getUserFromParams();\n\n\t\t\t\t\t// Respect the server's choice for using their real names or not\n\t\t\t\t\tif (user.name && settings.get('UI_Use_Real_Name')) {\n\t\t\t\t\t\ttext = `${user.name}`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext = `@${user.username}`;\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (user.status) {\n\t\t\t\t\t\tcase 'online':\n\t\t\t\t\t\t\tbackgroundColor = '#1fb31f';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'away':\n\t\t\t\t\t\t\tbackgroundColor = '#dc9b01';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'busy':\n\t\t\t\t\t\t\tbackgroundColor = '#bc2031';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'offline':\n\t\t\t\t\t\t\tbackgroundColor = '#a5a1a1';\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\ttext = TAPi18n.__('Join_Chat').toUpperCase();\n\t\t\t}\n\n\t\t\tconst iconSize = hideIcon ? 7 : 24;\n\t\t\tconst leftSize = name ? name.length * 6 + 7 + iconSize : iconSize;\n\t\t\tconst rightSize = text.length * 6 + 20;\n\t\t\tconst width = leftSize + rightSize;\n\t\t\tconst height = 20;\n\n\t\t\tchannel = escapeHTML(channel);\n\t\t\ttext = escapeHTML(text);\n\t\t\tname = escapeHTML(name);\n\n\t\t\treturn {\n\t\t\t\theaders: { 'Content-Type': 'image/svg+xml;charset=utf-8' },\n\t\t\t\tbody: `\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t${hideIcon ? '' : ``}\n\t\t\t\t\t\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tname\n\t\t\t\t\t\t\t\t? `${name}\n\t\t\t\t\t\t${name}`\n\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${text}\n\t\t\t\t\t\t${text}\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t`\n\t\t\t\t\t.trim()\n\t\t\t\t\t.replace(/\\>[\\s]+\\<'),\n\t\t\t} as any;\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'spotlight',\n\t{\n\t\tauthRequired: true,\n\t\tvalidateParams: isSpotlightProps,\n\t},\n\t{\n\t\tget() {\n\t\t\tconst { query } = this.queryParams;\n\n\t\t\tconst result = Meteor.call('spotlight', query);\n\n\t\t\treturn API.v1.success(result);\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'directory',\n\t{\n\t\tauthRequired: true,\n\t\tvalidateParams: isDirectoryProps,\n\t},\n\t{\n\t\tget() {\n\t\t\tconst { offset, count } = this.getPaginationItems();\n\t\t\tconst { sort, query } = this.parseJsonQuery();\n\n\t\t\tconst { text, type, workspace = 'local' } = query;\n\n\t\t\tif (sort && Object.keys(sort).length > 1) {\n\t\t\t\treturn API.v1.failure('This method support only one \"sort\" parameter');\n\t\t\t}\n\t\t\tconst sortBy = sort ? Object.keys(sort)[0] : undefined;\n\t\t\tconst sortDirection = sort && Object.values(sort)[0] === 1 ? 'asc' : 'desc';\n\n\t\t\tconst result = Meteor.call('browseChannels', {\n\t\t\t\ttext,\n\t\t\t\ttype,\n\t\t\t\tworkspace,\n\t\t\t\tsortBy,\n\t\t\t\tsortDirection,\n\t\t\t\toffset: Math.max(0, offset),\n\t\t\t\tlimit: Math.max(0, count),\n\t\t\t});\n\n\t\t\tif (!result) {\n\t\t\t\treturn API.v1.failure('Please verify the parameters');\n\t\t\t}\n\t\t\treturn API.v1.success({\n\t\t\t\tresult: result.results,\n\t\t\t\tcount: result.results.length,\n\t\t\t\toffset,\n\t\t\t\ttotal: result.total,\n\t\t\t});\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'pw.getPolicy',\n\t{\n\t\tauthRequired: true,\n\t},\n\t{\n\t\tget() {\n\t\t\treturn API.v1.success(passwordPolicy.getPasswordPolicy());\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'pw.getPolicyReset',\n\t{\n\t\tauthRequired: false,\n\t\tvalidateParams: validateParamsPwGetPolicyRest,\n\t},\n\t{\n\t\tasync get() {\n\t\t\tcheck(\n\t\t\t\tthis.queryParams,\n\t\t\t\tMatch.ObjectIncluding({\n\t\t\t\t\ttoken: String,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tconst { token } = this.queryParams;\n\n\t\t\tconst user = await UsersRaw.findOneByResetToken(token, { projection: { _id: 1 } });\n\t\t\tif (!user) {\n\t\t\t\treturn API.v1.unauthorized();\n\t\t\t}\n\n\t\t\treturn API.v1.success(passwordPolicy.getPasswordPolicy());\n\t\t},\n\t},\n);\n\n/**\n * @openapi\n * /api/v1/stdout.queue:\n * get:\n * description: Retrieves last 1000 lines of server logs\n * security:\n * - authenticated: ['view-logs']\n * responses:\n * 200:\n * description: The user data of the authenticated user\n * content:\n * application/json:\n * schema:\n * allOf:\n * - $ref: '#/components/schemas/ApiSuccessV1'\n * - type: object\n * properties:\n * queue:\n * type: array\n * items:\n * type: object\n * properties:\n * id:\n * type: string\n * string:\n * type: string\n * ts:\n * type: string\n * format: date-time\n * default:\n * description: Unexpected error\n * content:\n * application/json:\n * schema:\n * $ref: '#/components/schemas/ApiFailureV1'\n */\nAPI.v1.addRoute(\n\t'stdout.queue',\n\t{ authRequired: true },\n\t{\n\t\tget() {\n\t\t\tif (!hasPermission(this.userId, 'view-logs')) {\n\t\t\t\treturn API.v1.unauthorized();\n\t\t\t}\n\t\t\treturn API.v1.success({ queue: getLogs() });\n\t\t},\n\t},\n);\n\ndeclare module '@rocket.chat/rest-typings' {\n\t// eslint-disable-next-line @typescript-eslint/naming-convention\n\tinterface Endpoints {\n\t\t'method.call/:method': {\n\t\t\tPOST: (params: { method: string; args: any[] }) => any;\n\t\t};\n\t\t'method.callAnon/:method': {\n\t\t\tPOST: (params: { method: string; args: any[] }) => any;\n\t\t};\n\t}\n}\n\nconst mountResult = ({\n\tid,\n\terror,\n\tresult,\n}: {\n\tid: string;\n\terror?: unknown;\n\tresult?: unknown;\n}): {\n\tmessage: string;\n} => ({\n\tmessage: EJSON.stringify({\n\t\tmsg: 'result',\n\t\tid,\n\t\terror: error as any,\n\t\tresult: result as any,\n\t}),\n});\n\n// had to create two different endpoints for authenticated and non-authenticated calls\n// because restivus does not provide 'this.userId' if 'authRequired: false'\nAPI.v1.addRoute(\n\t'method.call/:method',\n\t{\n\t\tauthRequired: true,\n\t\trateLimiterOptions: false,\n\t\tvalidateParams: isMeteorCall,\n\t},\n\t{\n\t\tpost() {\n\t\t\tcheck(this.bodyParams, {\n\t\t\t\tmessage: String,\n\t\t\t});\n\n\t\t\tconst data = EJSON.parse(this.bodyParams.message);\n\n\t\t\tif (!isMethodCallProps(data)) {\n\t\t\t\treturn API.v1.failure('Invalid method call');\n\t\t\t}\n\n\t\t\tconst { method, params, id } = data;\n\n\t\t\tconst connectionId =\n\t\t\t\tthis.token ||\n\t\t\t\tcrypto\n\t\t\t\t\t.createHash('md5')\n\t\t\t\t\t.update(this.requestIp + this.request.headers['user-agent'])\n\t\t\t\t\t.digest('hex');\n\n\t\t\tconst rateLimiterInput = {\n\t\t\t\tuserId: this.userId,\n\t\t\t\tclientAddress: this.requestIp,\n\t\t\t\ttype: 'method',\n\t\t\t\tname: method,\n\t\t\t\tconnectionId,\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\tDDPRateLimiter._increment(rateLimiterInput);\n\t\t\t\tconst rateLimitResult = DDPRateLimiter._check(rateLimiterInput);\n\t\t\t\tif (!rateLimitResult.allowed) {\n\t\t\t\t\tthrow new Meteor.Error('too-many-requests', DDPRateLimiter.getErrorMessage(rateLimitResult), {\n\t\t\t\t\t\ttimeToReset: rateLimitResult.timeToReset,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst result = Meteor.call(method, ...params);\n\t\t\t\treturn API.v1.success(mountResult({ id, result }));\n\t\t\t} catch (err) {\n\t\t\t\tSystemLogger.error({ msg: `Exception while invoking method ${method}`, err });\n\n\t\t\t\tif (settings.get('Log_Level') === '2') {\n\t\t\t\t\tMeteor._debug(`Exception while invoking method ${method}`, err);\n\t\t\t\t}\n\t\t\t\treturn API.v1.success(mountResult({ id, error: err }));\n\t\t\t}\n\t\t},\n\t},\n);\nAPI.v1.addRoute(\n\t'method.callAnon/:method',\n\t{\n\t\tauthRequired: false,\n\t\trateLimiterOptions: false,\n\t\tvalidateParams: isMeteorCall,\n\t},\n\t{\n\t\tpost() {\n\t\t\tcheck(this.bodyParams, {\n\t\t\t\tmessage: String,\n\t\t\t});\n\n\t\t\tconst data = EJSON.parse(this.bodyParams.message);\n\n\t\t\tif (!isMethodCallAnonProps(data)) {\n\t\t\t\treturn API.v1.failure('Invalid method call');\n\t\t\t}\n\n\t\t\tconst { method, params, id } = data;\n\n\t\t\tconst connectionId =\n\t\t\t\tthis.token ||\n\t\t\t\tcrypto\n\t\t\t\t\t.createHash('md5')\n\t\t\t\t\t.update(this.requestIp + this.request.headers['user-agent'])\n\t\t\t\t\t.digest('hex');\n\n\t\t\tconst rateLimiterInput = {\n\t\t\t\tuserId: this.userId || undefined,\n\t\t\t\tclientAddress: this.requestIp,\n\t\t\t\ttype: 'method',\n\t\t\t\tname: method,\n\t\t\t\tconnectionId,\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\tDDPRateLimiter._increment(rateLimiterInput);\n\t\t\t\tconst rateLimitResult = DDPRateLimiter._check(rateLimiterInput);\n\t\t\t\tif (!rateLimitResult.allowed) {\n\t\t\t\t\tthrow new Meteor.Error('too-many-requests', DDPRateLimiter.getErrorMessage(rateLimitResult), {\n\t\t\t\t\t\ttimeToReset: rateLimitResult.timeToReset,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tconst result = Meteor.call(method, ...params);\n\t\t\t\treturn API.v1.success(mountResult({ id, result }));\n\t\t\t} catch (err) {\n\t\t\t\tSystemLogger.error({ msg: `Exception while invoking method ${method}`, err });\n\n\t\t\t\tif (settings.get('Log_Level') === '2') {\n\t\t\t\t\tMeteor._debug(`Exception while invoking method ${method}`, err);\n\t\t\t\t}\n\t\t\t\treturn API.v1.success(mountResult({ id, error: err }));\n\t\t\t}\n\t\t},\n\t},\n);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/oauthapps.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/permissions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/presence.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/push.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/roles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/rooms.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/rooms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/settings.ts",["22909"],[],"import { Meteor } from 'meteor/meteor';\nimport { ServiceConfiguration } from 'meteor/service-configuration';\nimport _ from 'underscore';\nimport type { ISetting, ISettingColor } from '@rocket.chat/core-typings';\nimport { isSettingAction, isSettingColor } from '@rocket.chat/core-typings';\nimport {\n\tisOauthCustomConfiguration,\n\tisSettingsUpdatePropDefault,\n\tisSettingsUpdatePropsActions,\n\tisSettingsUpdatePropsColor,\n} from '@rocket.chat/rest-typings';\nimport { Settings } from '@rocket.chat/models';\nimport type { FindOptions } from 'mongodb';\n\nimport { hasPermission } from '../../../authorization/server';\nimport type { ResultFor } from '../api';\nimport { API } from '../api';\nimport { SettingsEvents, settings } from '../../../settings/server';\nimport { setValue } from '../../../settings/server/raw';\n\nasync function fetchSettings(\n\tquery: Parameters[0],\n\tsort: FindOptions['sort'],\n\toffset: FindOptions['skip'],\n\tcount: FindOptions['limit'],\n\tfields: FindOptions['projection'],\n): Promise<{ settings: ISetting[]; totalCount: number }> {\n\tconst { cursor, totalCount } = Settings.findPaginated(query || {}, {\n\t\tsort: sort || { _id: 1 },\n\t\tskip: offset,\n\t\tlimit: count,\n\t\tprojection: { _id: 1, value: 1, enterprise: 1, invalidValue: 1, modules: 1, ...fields },\n\t});\n\n\tconst [settings, total] = await Promise.all([cursor.toArray(), totalCount]);\n\n\tSettingsEvents.emit('fetch-settings', settings);\n\treturn { settings, totalCount: total };\n}\n\n// settings endpoints\nAPI.v1.addRoute(\n\t'settings.public',\n\t{ authRequired: false },\n\t{\n\t\tasync get() {\n\t\t\tconst { offset, count } = this.getPaginationItems();\n\t\t\tconst { sort, fields, query } = this.parseJsonQuery();\n\n\t\t\tconst ourQuery = {\n\t\t\t\t...query,\n\t\t\t\thidden: { $ne: true },\n\t\t\t\tpublic: true,\n\t\t\t};\n\n\t\t\tconst { settings, totalCount: total } = await fetchSettings(ourQuery, sort, offset, count, fields);\n\n\t\t\treturn API.v1.success({\n\t\t\t\tsettings,\n\t\t\t\tcount: settings.length,\n\t\t\t\toffset,\n\t\t\t\ttotal,\n\t\t\t});\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'settings.oauth',\n\t{ authRequired: false },\n\t{\n\t\tget() {\n\t\t\tconst oAuthServicesEnabled = ServiceConfiguration.configurations.find({}, { fields: { secret: 0 } }).fetch();\n\n\t\t\treturn API.v1.success({\n\t\t\t\tservices: oAuthServicesEnabled.map((service) => {\n\t\t\t\t\tif (!isOauthCustomConfiguration(service)) {\n\t\t\t\t\t\treturn service;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (service.custom || (service.service && ['saml', 'cas', 'wordpress'].includes(service.service))) {\n\t\t\t\t\t\treturn { ...service };\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\t_id: service._id,\n\t\t\t\t\t\tname: service.service,\n\t\t\t\t\t\tclientId: service.appId || service.clientId || service.consumerKey,\n\t\t\t\t\t\tbuttonLabelText: service.buttonLabelText || '',\n\t\t\t\t\t\tbuttonColor: service.buttonColor || '',\n\t\t\t\t\t\tbuttonLabelColor: service.buttonLabelColor || '',\n\t\t\t\t\t\tcustom: false,\n\t\t\t\t\t};\n\t\t\t\t}),\n\t\t\t});\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'settings.addCustomOAuth',\n\t{ authRequired: true, twoFactorRequired: true },\n\t{\n\t\tasync post() {\n\t\t\tif (!this.bodyParams.name || !this.bodyParams.name.trim()) {\n\t\t\t\tthrow new Meteor.Error('error-name-param-not-provided', 'The parameter \"name\" is required');\n\t\t\t}\n\n\t\t\tawait Meteor.call('addOAuthService', this.bodyParams.name, this.userId);\n\n\t\t\treturn API.v1.success();\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'settings',\n\t{ authRequired: true },\n\t{\n\t\tasync get() {\n\t\t\tconst { offset, count } = this.getPaginationItems();\n\t\t\tconst { sort, fields, query } = this.parseJsonQuery();\n\n\t\t\tlet ourQuery: Parameters[0] = {\n\t\t\t\thidden: { $ne: true },\n\t\t\t};\n\n\t\t\tif (!hasPermission(this.userId, 'view-privileged-setting')) {\n\t\t\t\tourQuery.public = true;\n\t\t\t}\n\n\t\t\tourQuery = Object.assign({}, query, ourQuery);\n\n\t\t\tconst { settings, totalCount: total } = await fetchSettings(ourQuery, sort, offset, count, fields);\n\n\t\t\treturn API.v1.success({\n\t\t\t\tsettings,\n\t\t\t\tcount: settings.length,\n\t\t\t\toffset,\n\t\t\t\ttotal,\n\t\t\t});\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'settings/:_id',\n\t{ authRequired: true },\n\t{\n\t\tasync get() {\n\t\t\tif (!hasPermission(this.userId, 'view-privileged-setting')) {\n\t\t\t\treturn API.v1.unauthorized();\n\t\t\t}\n\t\t\tconst setting = await Settings.findOneNotHiddenById(this.urlParams._id);\n\t\t\tif (!setting) {\n\t\t\t\treturn API.v1.failure();\n\t\t\t}\n\t\t\treturn API.v1.success(_.pick(setting, '_id', 'value'));\n\t\t},\n\t\tpost: {\n\t\t\ttwoFactorRequired: true,\n\t\t\tasync action(): Promise> {\n\t\t\t\tif (!hasPermission(this.userId, 'edit-privileged-setting')) {\n\t\t\t\t\treturn API.v1.unauthorized();\n\t\t\t\t}\n\n\t\t\t\tif (typeof this.urlParams._id !== 'string') {\n\t\t\t\t\tthrow new Meteor.Error('error-id-param-not-provided', 'The parameter \"id\" is required');\n\t\t\t\t}\n\n\t\t\t\t// allow special handling of particular setting types\n\t\t\t\tconst setting = await Settings.findOneNotHiddenById(this.urlParams._id);\n\n\t\t\t\tif (!setting) {\n\t\t\t\t\treturn API.v1.failure();\n\t\t\t\t}\n\n\t\t\t\tif (isSettingAction(setting) && isSettingsUpdatePropsActions(this.bodyParams) && this.bodyParams.execute) {\n\t\t\t\t\t// execute the configured method\n\t\t\t\t\tMeteor.call(setting.value);\n\t\t\t\t\treturn API.v1.success();\n\t\t\t\t}\n\n\t\t\t\tif (isSettingColor(setting) && isSettingsUpdatePropsColor(this.bodyParams)) {\n\t\t\t\t\tSettings.updateOptionsById(this.urlParams._id, {\n\t\t\t\t\t\teditor: this.bodyParams.editor,\n\t\t\t\t\t});\n\t\t\t\t\tSettings.updateValueNotHiddenById(this.urlParams._id, this.bodyParams.value);\n\t\t\t\t\treturn API.v1.success();\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\tisSettingsUpdatePropDefault(this.bodyParams) &&\n\t\t\t\t\t(await Settings.updateValueNotHiddenById(this.urlParams._id, this.bodyParams.value))\n\t\t\t\t) {\n\t\t\t\t\tconst s = await Settings.findOneNotHiddenById(this.urlParams._id);\n\t\t\t\t\tif (!s) {\n\t\t\t\t\t\treturn API.v1.failure();\n\t\t\t\t\t}\n\t\t\t\t\tsettings.set(s);\n\t\t\t\t\tsetValue(this.urlParams._id, this.bodyParams.value);\n\t\t\t\t\treturn API.v1.success();\n\t\t\t\t}\n\n\t\t\t\treturn API.v1.failure();\n\t\t\t},\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'service.configurations',\n\t{ authRequired: false },\n\t{\n\t\tget() {\n\t\t\treturn API.v1.success({\n\t\t\t\tconfigurations: ServiceConfiguration.configurations.find({}, { fields: { secret: 0 } }).fetch(),\n\t\t\t});\n\t\t},\n\t},\n);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/stats.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/subscriptions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/teams.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/users.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/videoConference.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/events.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/extensions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/logger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/omnichannel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/queues.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/rooms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/voip/server-connection.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/api/server/v1/webdav.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/lib/config.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/lib/handleIdentityToken.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/server/AppleCustomOAuth.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/server/appleOauthRegisterService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apple/server/loginHandler.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/activation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/api.ts",[],["22910"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/bridges.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/cloud.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/commands.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/details.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/environmental.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/http.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/internal.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/internalFederation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/listeners.js",[],["22911"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/livechat.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/messages.ts",["22912"],[],"import type { ITypingDescriptor } from '@rocket.chat/apps-engine/server/bridges/MessageBridge';\nimport { MessageBridge } from '@rocket.chat/apps-engine/server/bridges/MessageBridge';\nimport type { IMessage } from '@rocket.chat/apps-engine/definition/messages';\nimport type { IUser } from '@rocket.chat/apps-engine/definition/users';\nimport type { IRoom } from '@rocket.chat/apps-engine/definition/rooms';\nimport type { ISubscription } from '@rocket.chat/core-typings';\nimport { api } from '@rocket.chat/core-services';\n\nimport { Messages, Users, Subscriptions } from '../../../models/server';\nimport { updateMessage } from '../../../lib/server/functions/updateMessage';\nimport { executeSendMessage } from '../../../lib/server/methods/sendMessage';\nimport notifications from '../../../notifications/server/lib/Notifications';\nimport type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator';\n\nexport class AppMessageBridge extends MessageBridge {\n\t// eslint-disable-next-line no-empty-function\n\tconstructor(private readonly orch: AppServerOrchestrator) {\n\t\tsuper();\n\t}\n\n\tprotected async create(message: IMessage, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is creating a new message.`);\n\n\t\tconst convertedMessage = this.orch.getConverters()?.get('messages').convertAppMessage(message);\n\n\t\tconst sentMessage = executeSendMessage(convertedMessage.u._id, convertedMessage);\n\n\t\treturn sentMessage._id;\n\t}\n\n\tprotected async getById(messageId: string, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is getting the message: \"${messageId}\"`);\n\n\t\treturn this.orch.getConverters()?.get('messages').convertById(messageId);\n\t}\n\n\tprotected async update(message: IMessage, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is updating a message.`);\n\n\t\tif (!message.editor) {\n\t\t\tthrow new Error('Invalid editor assigned to the message for the update.');\n\t\t}\n\n\t\tif (!message.id || !Messages.findOneById(message.id)) {\n\t\t\tthrow new Error('A message must exist to update.');\n\t\t}\n\n\t\tconst msg = this.orch.getConverters()?.get('messages').convertAppMessage(message);\n\t\tconst editor = Users.findOneById(message.editor.id);\n\n\t\tupdateMessage(msg, editor);\n\t}\n\n\tprotected async notifyUser(user: IUser, message: IMessage, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is notifying a user.`);\n\n\t\tconst msg = this.orch.getConverters()?.get('messages').convertAppMessage(message);\n\n\t\tif (!msg) {\n\t\t\treturn;\n\t\t}\n\n\t\tapi.broadcast('notify.ephemeralMessage', user.id, msg.rid, {\n\t\t\t...msg,\n\t\t});\n\t}\n\n\tprotected async notifyRoom(room: IRoom, message: IMessage, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is notifying a room's users.`);\n\n\t\tif (!room || !room.id) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst msg = this.orch.getConverters()?.get('messages').convertAppMessage(message);\n\n\t\tconst users = Subscriptions.findByRoomIdWhenUserIdExists(room.id, { fields: { 'u._id': 1 } })\n\t\t\t.fetch()\n\t\t\t.map((s: ISubscription) => s.u._id);\n\n\t\tUsers.findByIds(users, { fields: { _id: 1 } })\n\t\t\t.fetch()\n\t\t\t.forEach(({ _id }: { _id: string }) =>\n\t\t\t\tapi.broadcast('notify.ephemeralMessage', _id, room.id, {\n\t\t\t\t\t...msg,\n\t\t\t\t}),\n\t\t\t);\n\t}\n\n\tprotected async typing({ scope, id, username, isTyping }: ITypingDescriptor): Promise {\n\t\tswitch (scope) {\n\t\t\tcase 'room':\n\t\t\t\tnotifications.notifyRoom(id, 'typing', username, isTyping);\n\t\t\t\treturn;\n\t\t\tdefault:\n\t\t\t\tthrow new Error('Unrecognized typing scope provided');\n\t\t}\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/oauthApps.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/persistence.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/rooms.ts",["22913","22914","22915","22916"],[],"import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms';\nimport { RoomType } from '@rocket.chat/apps-engine/definition/rooms';\nimport { RoomBridge } from '@rocket.chat/apps-engine/server/bridges/RoomBridge';\nimport type { IUser } from '@rocket.chat/apps-engine/definition/users';\nimport type { IMessage } from '@rocket.chat/apps-engine/definition/messages';\nimport { Meteor } from 'meteor/meteor';\nimport type { ISubscription, IUser as ICoreUser } from '@rocket.chat/core-typings';\n\nimport type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator';\nimport { Rooms, Subscriptions, Users } from '../../../models/server';\nimport { addUserToRoom } from '../../../lib/server/functions/addUserToRoom';\nimport { deleteRoom } from '../../../lib/server/functions/deleteRoom';\n\nexport class AppRoomBridge extends RoomBridge {\n\t// eslint-disable-next-line no-empty-function\n\tconstructor(private readonly orch: AppServerOrchestrator) {\n\t\tsuper();\n\t}\n\n\tprotected async create(room: IRoom, members: Array, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is creating a new room.`, room);\n\n\t\tconst rcRoom = this.orch.getConverters()?.get('rooms').convertAppRoom(room);\n\t\tlet method: string;\n\n\t\tswitch (room.type) {\n\t\t\tcase RoomType.CHANNEL:\n\t\t\t\tmethod = 'createChannel';\n\t\t\t\tbreak;\n\t\t\tcase RoomType.PRIVATE_GROUP:\n\t\t\t\tmethod = 'createPrivateGroup';\n\t\t\t\tbreak;\n\t\t\tcase RoomType.DIRECT_MESSAGE:\n\t\t\t\tmethod = 'createDirectMessage';\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error('Only channels, private groups and direct messages can be created.');\n\t\t}\n\n\t\tlet rid = '';\n\t\tMeteor.runAsUser(room.creator.id, () => {\n\t\t\tconst extraData = Object.assign({}, rcRoom);\n\t\t\tdelete extraData.name;\n\t\t\tdelete extraData.t;\n\t\t\tdelete extraData.ro;\n\t\t\tdelete extraData.customFields;\n\t\t\tlet info;\n\t\t\tif (room.type === RoomType.DIRECT_MESSAGE) {\n\t\t\t\tinfo = Meteor.call(method, ...members);\n\t\t\t} else {\n\t\t\t\tinfo = Meteor.call(method, rcRoom.name, members, rcRoom.ro, rcRoom.customFields, extraData);\n\t\t\t}\n\t\t\trid = info.rid;\n\t\t});\n\n\t\treturn rid;\n\t}\n\n\tprotected async getById(roomId: string, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is getting the roomById: \"${roomId}\"`);\n\n\t\treturn this.orch.getConverters()?.get('rooms').convertById(roomId);\n\t}\n\n\tprotected async getByName(roomName: string, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is getting the roomByName: \"${roomName}\"`);\n\n\t\treturn this.orch.getConverters()?.get('rooms').convertByName(roomName);\n\t}\n\n\tprotected async getCreatorById(roomId: string, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is getting the room's creator by id: \"${roomId}\"`);\n\n\t\tconst room = Rooms.findOneById(roomId);\n\n\t\tif (!room || !room.u || !room.u._id) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn this.orch.getConverters()?.get('users').convertById(room.u._id);\n\t}\n\n\tprotected async getCreatorByName(roomName: string, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is getting the room's creator by name: \"${roomName}\"`);\n\n\t\tconst room = Rooms.findOneByName(roomName, {});\n\n\t\tif (!room || !room.u || !room.u._id) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn this.orch.getConverters()?.get('users').convertById(room.u._id);\n\t}\n\n\tprotected async getMembers(roomId: string, appId: string): Promise> {\n\t\tthis.orch.debugLog(`The App ${appId} is getting the room's members by room id: \"${roomId}\"`);\n\t\tconst subscriptions = await Subscriptions.findByRoomId(roomId, {});\n\t\treturn subscriptions.map((sub: ISubscription) => this.orch.getConverters()?.get('users').convertById(sub.u?._id));\n\t}\n\n\tprotected async getDirectByUsernames(usernames: Array, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is getting direct room by usernames: \"${usernames}\"`);\n\t\tconst room = await Rooms.findDirectRoomContainingAllUsernames(usernames, {});\n\t\tif (!room) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.orch.getConverters()?.get('rooms').convertRoom(room);\n\t}\n\n\tprotected async update(room: IRoom, members: Array = [], appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is updating a room.`);\n\n\t\tif (!room.id || !Rooms.findOneById(room.id)) {\n\t\t\tthrow new Error('A room must exist to update.');\n\t\t}\n\n\t\tconst rm = this.orch.getConverters()?.get('rooms').convertAppRoom(room);\n\n\t\tRooms.update(rm._id, rm);\n\n\t\tfor (const username of members) {\n\t\t\tconst member = Users.findOneByUsername(username, {});\n\n\t\t\tif (!member) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\taddUserToRoom(rm._id, member);\n\t\t}\n\t}\n\n\tprotected async delete(roomId: string, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is deleting a room.`);\n\t\tdeleteRoom(roomId);\n\t}\n\n\tprotected async createDiscussion(\n\t\troom: IRoom,\n\t\tparentMessage: IMessage | undefined = undefined,\n\t\treply: string | undefined = '',\n\t\tmembers: Array = [],\n\t\tappId: string,\n\t): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is creating a new discussion.`, room);\n\n\t\tconst rcRoom = this.orch.getConverters()?.get('rooms').convertAppRoom(room);\n\n\t\tlet rcMessage;\n\t\tif (parentMessage) {\n\t\t\trcMessage = this.orch.getConverters()?.get('messages').convertAppMessage(parentMessage);\n\t\t}\n\n\t\tif (!rcRoom.prid || !Rooms.findOneById(rcRoom.prid)) {\n\t\t\tthrow new Error('There must be a parent room to create a discussion.');\n\t\t}\n\n\t\tconst discussion = {\n\t\t\tprid: rcRoom.prid,\n\t\t\tt_name: rcRoom.fname,\n\t\t\tpmid: rcMessage ? rcMessage._id : undefined,\n\t\t\treply: reply && reply.trim() !== '' ? reply : undefined,\n\t\t\tusers: members.length > 0 ? members : [],\n\t\t};\n\n\t\tlet rid = '';\n\t\tMeteor.runAsUser(room.creator.id, () => {\n\t\t\tconst info = Meteor.call('createDiscussion', discussion);\n\t\t\trid = info.rid;\n\t\t});\n\n\t\treturn rid;\n\t}\n\n\tprotected getModerators(roomId: string, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is getting room moderators for room id: ${roomId}`);\n\t\treturn this.getUsersByRoomIdAndSubscriptionRole(roomId, 'moderator');\n\t}\n\n\tprotected getOwners(roomId: string, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is getting room owners for room id: ${roomId}`);\n\t\treturn this.getUsersByRoomIdAndSubscriptionRole(roomId, 'owner');\n\t}\n\n\tprotected getLeaders(roomId: string, appId: string): Promise {\n\t\tthis.orch.debugLog(`The App ${appId} is getting room leaders for room id: ${roomId}`);\n\t\treturn this.getUsersByRoomIdAndSubscriptionRole(roomId, 'leader');\n\t}\n\n\tprivate async getUsersByRoomIdAndSubscriptionRole(roomId: string, role: string): Promise {\n\t\tconst subs = await Subscriptions.findByRoomIdAndRoles(roomId, [role], { projection: { uid: '$u._id', _id: 0 } });\n\t\tconst users = await Users.findByIds(subs.map((user: { uid: string }) => user.uid));\n\t\tconst userConverter = this.orch.getConverters()!.get('users');\n\t\treturn users.map((user: ICoreUser) => userConverter!.convertToApp(user));\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/scheduler.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/uiInteraction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/uploads.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/users.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/bridges/videoConferences.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/departments.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/messages.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/rooms.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/settings.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/uploads.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/users.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/videoConferences.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/apps/server/converters/visitors.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/assets/server/assets.ts",["22917"],[],"import crypto from 'crypto';\nimport type { ServerResponse, IncomingMessage } from 'http';\n\nimport { Meteor } from 'meteor/meteor';\nimport { WebApp, WebAppInternals } from 'meteor/webapp';\nimport { WebAppHashing } from 'meteor/webapp-hashing';\nimport _ from 'underscore';\nimport sizeOf from 'image-size';\nimport sharp from 'sharp';\nimport type { NextHandleFunction } from 'connect';\nimport type { IRocketChatAssets, IRocketChatAsset, IRocketChatAssetCache } from '@rocket.chat/core-typings';\nimport { Settings } from '@rocket.chat/models';\n\nimport { settings, settingsRegistry } from '../../settings/server';\nimport { getURL } from '../../utils/lib/getURL';\nimport { getExtension } from '../../utils/lib/mimeTypes';\nimport { hasPermission } from '../../authorization/server';\nimport { RocketChatFile } from '../../file';\nimport { methodDeprecationLogger } from '../../lib/server/lib/deprecationWarningLogger';\n\nconst RocketChatAssetsInstance = new RocketChatFile.GridFS({\n\tname: 'assets',\n});\nconst assets: IRocketChatAssets = {\n\tlogo: {\n\t\tlabel: 'logo (svg, png, jpg)',\n\t\tdefaultUrl: 'images/logo/logo.svg',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['svg', 'png', 'jpg', 'jpeg'],\n\t\t},\n\t\twizard: {\n\t\t\tstep: 3,\n\t\t\torder: 2,\n\t\t},\n\t},\n\tlogo_dark: {\n\t\tlabel: 'logo - dark theme (svg, png, jpg)',\n\t\tdefaultUrl: 'images/logo/logo_dark.svg',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['svg', 'png', 'jpg', 'jpeg'],\n\t\t},\n\t},\n\tbackground: {\n\t\tlabel: 'login background (svg, png, jpg)',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['svg', 'png', 'jpg', 'jpeg'],\n\t\t},\n\t},\n\tbackground_dark: {\n\t\tlabel: 'login background - dark theme (svg, png, jpg)',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['svg', 'png', 'jpg', 'jpeg'],\n\t\t},\n\t},\n\tfavicon_ico: {\n\t\tlabel: 'favicon (ico)',\n\t\tdefaultUrl: 'favicon.ico',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['ico'],\n\t\t},\n\t},\n\tfavicon: {\n\t\tlabel: 'favicon (svg)',\n\t\tdefaultUrl: 'images/logo/icon.svg',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['svg'],\n\t\t},\n\t},\n\tfavicon_16: {\n\t\tlabel: 'favicon 16x16 (png)',\n\t\tdefaultUrl: 'images/logo/favicon-16x16.png',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['png'],\n\t\t\twidth: 16,\n\t\t\theight: 16,\n\t\t},\n\t},\n\tfavicon_32: {\n\t\tlabel: 'favicon 32x32 (png)',\n\t\tdefaultUrl: 'images/logo/favicon-32x32.png',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['png'],\n\t\t\twidth: 32,\n\t\t\theight: 32,\n\t\t},\n\t},\n\tfavicon_192: {\n\t\tlabel: 'android-chrome 192x192 (png)',\n\t\tdefaultUrl: 'images/logo/android-chrome-192x192.png',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['png'],\n\t\t\twidth: 192,\n\t\t\theight: 192,\n\t\t},\n\t},\n\tfavicon_512: {\n\t\tlabel: 'android-chrome 512x512 (png)',\n\t\tdefaultUrl: 'images/logo/android-chrome-512x512.png',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['png'],\n\t\t\twidth: 512,\n\t\t\theight: 512,\n\t\t},\n\t},\n\ttouchicon_180: {\n\t\tlabel: 'apple-touch-icon 180x180 (png)',\n\t\tdefaultUrl: 'images/logo/apple-touch-icon.png',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['png'],\n\t\t\twidth: 180,\n\t\t\theight: 180,\n\t\t},\n\t},\n\ttouchicon_180_pre: {\n\t\tlabel: 'apple-touch-icon-precomposed 180x180 (png)',\n\t\tdefaultUrl: 'images/logo/apple-touch-icon-precomposed.png',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['png'],\n\t\t\twidth: 180,\n\t\t\theight: 180,\n\t\t},\n\t},\n\ttile_70: {\n\t\tlabel: 'mstile 70x70 (png)',\n\t\tdefaultUrl: 'images/logo/mstile-70x70.png',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['png'],\n\t\t\twidth: 70,\n\t\t\theight: 70,\n\t\t},\n\t},\n\ttile_144: {\n\t\tlabel: 'mstile 144x144 (png)',\n\t\tdefaultUrl: 'images/logo/mstile-144x144.png',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['png'],\n\t\t\twidth: 144,\n\t\t\theight: 144,\n\t\t},\n\t},\n\ttile_150: {\n\t\tlabel: 'mstile 150x150 (png)',\n\t\tdefaultUrl: 'images/logo/mstile-150x150.png',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['png'],\n\t\t\twidth: 150,\n\t\t\theight: 150,\n\t\t},\n\t},\n\ttile_310_square: {\n\t\tlabel: 'mstile 310x310 (png)',\n\t\tdefaultUrl: 'images/logo/mstile-310x310.png',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['png'],\n\t\t\twidth: 310,\n\t\t\theight: 310,\n\t\t},\n\t},\n\ttile_310_wide: {\n\t\tlabel: 'mstile 310x150 (png)',\n\t\tdefaultUrl: 'images/logo/mstile-310x150.png',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['png'],\n\t\t\twidth: 310,\n\t\t\theight: 150,\n\t\t},\n\t},\n\tsafari_pinned: {\n\t\tlabel: 'safari pinned tab (svg)',\n\t\tdefaultUrl: 'images/logo/safari-pinned-tab.svg',\n\t\tconstraints: {\n\t\t\ttype: 'image',\n\t\t\textensions: ['svg'],\n\t\t},\n\t},\n};\n\nfunction getAssetByKey(key: string): IRocketChatAsset {\n\treturn assets[key as keyof IRocketChatAssets];\n}\n\nclass RocketChatAssetsClass {\n\tget assets(): IRocketChatAssets {\n\t\treturn assets;\n\t}\n\n\tpublic setAsset(binaryContent: BufferEncoding, contentType: string, asset: string): void {\n\t\tconst assetInstance = getAssetByKey(asset);\n\t\tif (!assetInstance) {\n\t\t\tthrow new Meteor.Error('error-invalid-asset', 'Invalid asset', {\n\t\t\t\tfunction: 'RocketChat.Assets.setAsset',\n\t\t\t});\n\t\t}\n\n\t\tconst extension = getExtension(contentType);\n\t\tif (assetInstance.constraints.extensions.includes(extension) === false) {\n\t\t\tthrow new Meteor.Error('error-invalid-file-type', `Invalid file type: ${contentType}`, {\n\t\t\t\tfunction: 'RocketChat.Assets.setAsset',\n\t\t\t});\n\t\t}\n\n\t\tconst file = Buffer.from(binaryContent, 'binary');\n\t\tif (assetInstance.constraints.width || assetInstance.constraints.height) {\n\t\t\tconst dimensions = sizeOf(file);\n\t\t\tif (assetInstance.constraints.width && assetInstance.constraints.width !== dimensions.width) {\n\t\t\t\tthrow new Meteor.Error('error-invalid-file-width', 'Invalid file width', {\n\t\t\t\t\tfunction: 'Invalid file width',\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (assetInstance.constraints.height && assetInstance.constraints.height !== dimensions.height) {\n\t\t\t\tthrow new Meteor.Error('error-invalid-file-height');\n\t\t\t}\n\t\t}\n\n\t\tconst rs = RocketChatFile.bufferToStream(file);\n\t\tRocketChatAssetsInstance.deleteFile(asset);\n\n\t\tconst ws = RocketChatAssetsInstance.createWriteStream(asset, contentType);\n\t\tws.on(\n\t\t\t'end',\n\t\t\tMeteor.bindEnvironment(function () {\n\t\t\t\treturn Meteor.setTimeout(function () {\n\t\t\t\t\tconst key = `Assets_${asset}`;\n\t\t\t\t\tconst value = {\n\t\t\t\t\t\turl: `assets/${asset}.${extension}`,\n\t\t\t\t\t\tdefaultUrl: assetInstance.defaultUrl,\n\t\t\t\t\t};\n\n\t\t\t\t\tSettings.updateValueById(key, value);\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-use-before-define\n\t\t\t\t\treturn RocketChatAssets.processAsset(key, value);\n\t\t\t\t}, 200);\n\t\t\t}),\n\t\t);\n\n\t\trs.pipe(ws);\n\t}\n\n\tpublic unsetAsset(asset: string): void {\n\t\tif (!getAssetByKey(asset)) {\n\t\t\tthrow new Meteor.Error('error-invalid-asset', 'Invalid asset', {\n\t\t\t\tfunction: 'RocketChat.Assets.unsetAsset',\n\t\t\t});\n\t\t}\n\n\t\tRocketChatAssetsInstance.deleteFile(asset);\n\t\tconst key = `Assets_${asset}`;\n\t\tconst value = {\n\t\t\tdefaultUrl: getAssetByKey(asset).defaultUrl,\n\t\t};\n\n\t\tSettings.updateValueById(key, value);\n\t\t// eslint-disable-next-line @typescript-eslint/no-use-before-define\n\t\tRocketChatAssets.processAsset(key, value);\n\t}\n\n\tpublic refreshClients(): boolean {\n\t\treturn process.emit('message', {\n\t\t\trefresh: 'client',\n\t\t});\n\t}\n\n\tpublic processAsset(settingKey: string, settingValue: any): Record | undefined {\n\t\tif (settingKey.indexOf('Assets_') !== 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst assetKey = settingKey.replace(/^Assets_/, '');\n\t\tconst assetValue = getAssetByKey(assetKey);\n\n\t\tif (!assetValue) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!settingValue || !settingValue.url) {\n\t\t\tassetValue.cache = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\tconst file = RocketChatAssetsInstance.getFileSync(assetKey);\n\t\tif (!file) {\n\t\t\tassetValue.cache = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\tconst hash = crypto.createHash('sha1').update(file.buffer).digest('hex');\n\t\tconst extension = settingValue.url.split('.').pop();\n\n\t\tassetValue.cache = {\n\t\t\tpath: `assets/${assetKey}.${extension}`,\n\t\t\tcacheable: false,\n\t\t\tsourceMapUrl: undefined,\n\t\t\twhere: 'client',\n\t\t\ttype: 'asset',\n\t\t\tcontent: file.buffer,\n\t\t\textension,\n\t\t\turl: `/assets/${assetKey}.${extension}?${hash}`,\n\t\t\tsize: file.length,\n\t\t\tuploadDate: file.uploadDate,\n\t\t\tcontentType: file.contentType,\n\t\t\thash,\n\t\t};\n\n\t\treturn assetValue.cache;\n\t}\n\n\tpublic getURL(assetName: string, options = { cdn: false, full: true }): string {\n\t\tconst asset = settings.get(assetName);\n\t\tconst url = asset.url || asset.defaultUrl;\n\n\t\treturn getURL(url, options);\n\t}\n}\n\nexport const RocketChatAssets = new RocketChatAssetsClass();\n\nsettingsRegistry.addGroup('Assets', function () {\n\tthis.add('Assets_SvgFavicon_Enable', true, {\n\t\ttype: 'boolean',\n\t\tgroup: 'Assets',\n\t\ti18nLabel: 'Enable_Svg_Favicon',\n\t});\n});\n\nfunction addAssetToSetting(asset: string, value: IRocketChatAsset): void {\n\tconst key = `Assets_${asset}`;\n\n\tsettingsRegistry.add(\n\t\tkey,\n\t\t{\n\t\t\tdefaultUrl: value.defaultUrl,\n\t\t},\n\t\t{\n\t\t\ttype: 'asset',\n\t\t\tgroup: 'Assets',\n\t\t\tfileConstraints: value.constraints,\n\t\t\ti18nLabel: value.label,\n\t\t\tasset,\n\t\t\tpublic: true,\n\t\t\twizard: value.wizard,\n\t\t},\n\t);\n\n\tconst currentValue = settings.get(key);\n\n\tif (typeof currentValue === 'object' && currentValue.defaultUrl !== getAssetByKey(asset).defaultUrl) {\n\t\tcurrentValue.defaultUrl = getAssetByKey(asset).defaultUrl;\n\t\tPromise.await(Settings.updateValueById(key, currentValue));\n\t}\n}\n\nfor (const key of Object.keys(assets)) {\n\tconst value = getAssetByKey(key);\n\taddAssetToSetting(key, value);\n}\n\nsettings.watchByRegex(/^Assets_/, (key, value) => RocketChatAssets.processAsset(key, value));\n\nMeteor.startup(() => {\n\tMeteor.setTimeout(() => {\n\t\tprocess.emit('message', {\n\t\t\trefresh: 'client',\n\t\t});\n\t}, 200);\n});\n\nconst { calculateClientHash } = WebAppHashing;\n\nWebAppHashing.calculateClientHash = function (manifest, includeFilter, runtimeConfigOverride): string {\n\tfor (const key of Object.keys(assets)) {\n\t\tconst value = getAssetByKey(key);\n\t\tif (!value.cache && !value.defaultUrl) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet cache: IRocketChatAssetCache;\n\t\tif (value.cache) {\n\t\t\tcache = {\n\t\t\t\tpath: value.cache.path,\n\t\t\t\tcacheable: value.cache.cacheable,\n\t\t\t\tsourceMapUrl: value.cache.sourceMapUrl,\n\t\t\t\twhere: value.cache.where,\n\t\t\t\ttype: value.cache.type,\n\t\t\t\turl: value.cache.url,\n\t\t\t\tsize: value.cache.size,\n\t\t\t\thash: value.cache.hash,\n\t\t\t};\n\t\t} else {\n\t\t\tconst extension = value.defaultUrl?.split('.').pop();\n\t\t\tcache = {\n\t\t\t\tpath: `assets/${key}.${extension}`,\n\t\t\t\tcacheable: false,\n\t\t\t\tsourceMapUrl: undefined,\n\t\t\t\twhere: 'client',\n\t\t\t\ttype: 'asset',\n\t\t\t\turl: `/assets/${key}.${extension}?v3`,\n\t\t\t\thash: 'v3',\n\t\t\t};\n\t\t}\n\n\t\tconst manifestItem = _.findWhere(manifest, {\n\t\t\tpath: key,\n\t\t});\n\n\t\tif (manifestItem) {\n\t\t\tconst index = manifest.indexOf(manifestItem);\n\t\t\tmanifest[index] = cache;\n\t\t} else {\n\t\t\tmanifest.push(cache);\n\t\t}\n\t}\n\n\treturn calculateClientHash.call(this, manifest, includeFilter, runtimeConfigOverride);\n};\n\nMeteor.methods({\n\trefreshClients() {\n\t\tmethodDeprecationLogger.warn('refreshClients will be deprecated in future versions of Rocket.Chat');\n\n\t\tif (!Meteor.userId()) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tmethod: 'refreshClients',\n\t\t\t});\n\t\t}\n\n\t\tconst _hasPermission = hasPermission(Meteor.userId() as string, 'manage-assets');\n\t\tif (!_hasPermission) {\n\t\t\tthrow new Meteor.Error('error-action-not-allowed', 'Managing assets not allowed', {\n\t\t\t\tmethod: 'refreshClients',\n\t\t\t\taction: 'Managing_assets',\n\t\t\t});\n\t\t}\n\n\t\treturn RocketChatAssets.refreshClients();\n\t},\n\n\tunsetAsset(asset) {\n\t\tif (!Meteor.userId()) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tmethod: 'unsetAsset',\n\t\t\t});\n\t\t}\n\n\t\tconst _hasPermission = hasPermission(Meteor.userId() as string, 'manage-assets');\n\t\tif (!_hasPermission) {\n\t\t\tthrow new Meteor.Error('error-action-not-allowed', 'Managing assets not allowed', {\n\t\t\t\tmethod: 'unsetAsset',\n\t\t\t\taction: 'Managing_assets',\n\t\t\t});\n\t\t}\n\n\t\treturn RocketChatAssets.unsetAsset(asset);\n\t},\n\n\tsetAsset(binaryContent, contentType, asset) {\n\t\tif (!Meteor.userId()) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tmethod: 'setAsset',\n\t\t\t});\n\t\t}\n\n\t\tconst _hasPermission = hasPermission(Meteor.userId() as string, 'manage-assets');\n\t\tif (!_hasPermission) {\n\t\t\tthrow new Meteor.Error('error-action-not-allowed', 'Managing assets not allowed', {\n\t\t\t\tmethod: 'setAsset',\n\t\t\t\taction: 'Managing_assets',\n\t\t\t});\n\t\t}\n\n\t\tRocketChatAssets.setAsset(binaryContent, contentType, asset);\n\t},\n});\n\nconst listener = Meteor.bindEnvironment((req: IncomingMessage, res: ServerResponse, next: NextHandleFunction) => {\n\tif (!req.url) {\n\t\treturn;\n\t}\n\tconst params = {\n\t\tasset: decodeURIComponent(req.url.replace(/^\\//, '').replace(/\\?.*$/, '')).replace(/\\.[^.]*$/, ''),\n\t};\n\n\tconst asset = getAssetByKey(params.asset);\n\tconst file = asset?.cache;\n\n\tconst format = req.url.replace(/.*\\.([a-z]+)(?:$|\\?.*)/i, '$1');\n\n\tif (asset && Array.isArray(asset.constraints.extensions) && !asset.constraints.extensions.includes(format)) {\n\t\tres.writeHead(403);\n\t\treturn res.end();\n\t}\n\tif (!file) {\n\t\tconst defaultUrl = asset?.defaultUrl;\n\t\tif (defaultUrl) {\n\t\t\tconst assetUrl = format && ['png', 'svg'].includes(format) ? defaultUrl.replace(/(svg|png)$/, format) : defaultUrl;\n\t\t\treq.url = `/${assetUrl}`;\n\t\t\tWebAppInternals.staticFilesMiddleware((WebAppInternals as Record).staticFilesByArch, req, res, next);\n\t\t} else {\n\t\t\tres.writeHead(404);\n\t\t\tres.end();\n\t\t}\n\n\t\treturn;\n\t}\n\n\tconst reqModifiedHeader = req.headers['if-modified-since'];\n\tif (reqModifiedHeader) {\n\t\tif (reqModifiedHeader === file.uploadDate?.toUTCString()) {\n\t\t\tres.setHeader('Last-Modified', reqModifiedHeader);\n\t\t\tres.writeHead(304);\n\t\t\tres.end();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tres.setHeader('Cache-Control', 'public, max-age=0');\n\tres.setHeader('Expires', '-1');\n\n\tif (format && format !== file.extension && ['png', 'jpg', 'jpeg'].includes(format)) {\n\t\tres.setHeader('Content-Type', `image/${format}`);\n\t\tsharp(file.content)\n\t\t\t.toFormat(format as any)\n\t\t\t.pipe(res);\n\t\treturn;\n\t}\n\n\tres.setHeader('Last-Modified', file.uploadDate?.toUTCString() || new Date().toUTCString());\n\tif (file.contentType) res.setHeader('Content-Type', file.contentType);\n\tif (file.size) res.setHeader('Content-Length', file.size);\n\tres.writeHead(200);\n\tres.end(file.content);\n});\n\nWebApp.connectHandlers.use('/assets/', listener);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/assets/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/ILoginAttempt.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/hooks/login.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/lib/logLoginAttempts.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/lib/restrictLoginAttempts.ts",["22918"],[],"import type { IServerEvent } from '@rocket.chat/core-typings';\nimport { ServerEventType } from '@rocket.chat/core-typings';\nimport { Rooms, ServerEvents, Sessions, Users } from '@rocket.chat/models';\nimport moment from 'moment';\n\nimport { addMinutesToADate } from '../../../../lib/utils/addMinutesToADate';\nimport { getClientAddress } from '../../../../server/lib/getClientAddress';\nimport { sendMessage } from '../../../lib/server/functions';\nimport { Logger } from '../../../logger/server';\nimport { settings } from '../../../settings/server';\nimport type { ILoginAttempt } from '../ILoginAttempt';\n\nconst logger = new Logger('LoginProtection');\n\nexport const notifyFailedLogin = async (ipOrUsername: string, blockedUntil: Date, failedAttempts: number): Promise => {\n\tconst channelToNotify = settings.get('Block_Multiple_Failed_Logins_Notify_Failed_Channel');\n\tif (!channelToNotify) {\n\t\tlogger.error('Cannot notify failed logins: channel provided is invalid');\n\t\treturn;\n\t}\n\t// verify channel exists\n\t// to avoid issues when \"fname\" is presented in the UI, check if the name matches it as well\n\tconst room = await Rooms.findOneByNameOrFname(channelToNotify);\n\tif (!room) {\n\t\tlogger.error(\"Cannot notify failed logins: channel provided doesn't exists\");\n\t\treturn;\n\t}\n\n\tconst rocketCat = await Users.findOneById('rocket.cat');\n\t// send message\n\tconst message = {\n\t\tattachments: [\n\t\t\t{\n\t\t\t\tfields: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttitle: 'Failed login attempt threshold exceeded',\n\t\t\t\t\t\tvalue: `User or IP: ${ipOrUsername}\\nBlocked until: ${blockedUntil}\\nFailed Attempts: ${failedAttempts}`,\n\t\t\t\t\t\tshort: true,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tcolor: 'red',\n\t\t\t},\n\t\t],\n\t};\n\n\tawait sendMessage(rocketCat, message, room, false);\n};\n\nexport const isValidLoginAttemptByIp = async (ip: string): Promise => {\n\tconst whitelist = String(settings.get('Block_Multiple_Failed_Logins_Ip_Whitelist')).split(',');\n\n\tif (\n\t\t!settings.get('Block_Multiple_Failed_Logins_Enabled') ||\n\t\t!settings.get('Block_Multiple_Failed_Logins_By_Ip') ||\n\t\twhitelist.includes(ip)\n\t) {\n\t\treturn true;\n\t}\n\n\tconst lastLogin = await Sessions.findLastLoginByIp(ip);\n\tlet failedAttemptsSinceLastLogin;\n\n\tif (!lastLogin || !lastLogin.loginAt) {\n\t\tfailedAttemptsSinceLastLogin = await ServerEvents.countFailedAttemptsByIp(ip);\n\t} else {\n\t\tfailedAttemptsSinceLastLogin = await ServerEvents.countFailedAttemptsByIpSince(ip, new Date(lastLogin.loginAt));\n\t}\n\n\tconst attemptsUntilBlock = settings.get('Block_Multiple_Failed_Logins_Attempts_Until_Block_By_Ip');\n\n\tif (attemptsUntilBlock && failedAttemptsSinceLastLogin < attemptsUntilBlock) {\n\t\treturn true;\n\t}\n\n\tconst lastAttemptAt = (await ServerEvents.findLastFailedAttemptByIp(ip))?.ts;\n\n\tif (!lastAttemptAt) {\n\t\treturn true;\n\t}\n\n\tconst minutesUntilUnblock = settings.get('Block_Multiple_Failed_Logins_Time_To_Unblock_By_Ip_In_Minutes') as number;\n\tconst willBeBlockedUntil = addMinutesToADate(new Date(lastAttemptAt), minutesUntilUnblock);\n\tconst isValid = moment(new Date()).isSameOrAfter(willBeBlockedUntil);\n\n\tif (settings.get('Block_Multiple_Failed_Logins_Notify_Failed') && !isValid) {\n\t\tnotifyFailedLogin(ip, willBeBlockedUntil, failedAttemptsSinceLastLogin);\n\t}\n\n\treturn isValid;\n};\n\nexport const isValidAttemptByUser = async (login: ILoginAttempt): Promise => {\n\tif (!settings.get('Block_Multiple_Failed_Logins_Enabled') || !settings.get('Block_Multiple_Failed_Logins_By_User')) {\n\t\treturn true;\n\t}\n\n\tconst loginUsername = login.methodArguments[0].user?.username;\n\tconst user = login.user || (loginUsername && (await Users.findOneByUsername(loginUsername))) || undefined;\n\n\tif (!user?.username) {\n\t\treturn true;\n\t}\n\n\tlet failedAttemptsSinceLastLogin;\n\n\tif (!user?.lastLogin) {\n\t\tfailedAttemptsSinceLastLogin = await ServerEvents.countFailedAttemptsByUsername(user.username);\n\t} else {\n\t\tfailedAttemptsSinceLastLogin = await ServerEvents.countFailedAttemptsByUsernameSince(user.username, new Date(user.lastLogin));\n\t}\n\n\tconst attemptsUntilBlock = settings.get('Block_Multiple_Failed_Logins_Attempts_Until_Block_by_User');\n\n\tif (attemptsUntilBlock && failedAttemptsSinceLastLogin < attemptsUntilBlock) {\n\t\treturn true;\n\t}\n\n\tconst lastAttemptAt = (await ServerEvents.findLastFailedAttemptByUsername(user.username as string))?.ts;\n\n\tif (!lastAttemptAt) {\n\t\treturn true;\n\t}\n\n\tconst minutesUntilUnblock = settings.get('Block_Multiple_Failed_Logins_Time_To_Unblock_By_User_In_Minutes') as number;\n\tconst willBeBlockedUntil = addMinutesToADate(new Date(lastAttemptAt), minutesUntilUnblock);\n\tconst isValid = moment(new Date()).isSameOrAfter(willBeBlockedUntil);\n\n\tif (settings.get('Block_Multiple_Failed_Logins_Notify_Failed') && !isValid) {\n\t\tnotifyFailedLogin(user.username, willBeBlockedUntil, failedAttemptsSinceLastLogin);\n\t}\n\n\treturn isValid;\n};\n\nexport const saveFailedLoginAttempts = async (login: ILoginAttempt): Promise => {\n\tconst user: IServerEvent['u'] = {\n\t\t_id: login.user?._id,\n\t\tusername: login.user?.username || login.methodArguments[0].user?.username,\n\t};\n\n\tawait ServerEvents.insertOne({\n\t\tip: getClientAddress(login.connection),\n\t\tt: ServerEventType.FAILED_LOGIN_ATTEMPT,\n\t\tts: new Date(),\n\t\tu: user,\n\t});\n};\n\nexport const saveSuccessfulLogin = async (login: ILoginAttempt): Promise => {\n\tconst user: IServerEvent['u'] = {\n\t\t_id: login.user?._id,\n\t\tusername: login.user?.username || login.methodArguments[0].user?.username,\n\t};\n\n\tawait ServerEvents.insertOne({\n\t\tip: getClientAddress(login.connection),\n\t\tt: ServerEventType.LOGIN,\n\t\tts: new Date(),\n\t\tu: user,\n\t});\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/startup/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authentication/server/startup/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/client/hasPermission.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/client/hasRole.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/client/lib/ChatPermissions.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/client/lib/streamer.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/client/startup.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/lib/AuthorizationUtils.ts",["22919"],[],"const restrictedRolePermissions = new Map();\n\nexport const AuthorizationUtils = class {\n\tstatic addRolePermissionWhiteList(roleId: string, list: string[]): void {\n\t\tif (!roleId) {\n\t\t\tthrow new Error('invalid-param');\n\t\t}\n\n\t\tif (!list) {\n\t\t\tthrow new Error('invalid-param');\n\t\t}\n\n\t\tif (!restrictedRolePermissions.has(roleId)) {\n\t\t\trestrictedRolePermissions.set(roleId, new Set());\n\t\t}\n\n\t\tconst rules = restrictedRolePermissions.get(roleId);\n\n\t\tfor (const permissionId of list) {\n\t\t\trules.add(permissionId);\n\t\t}\n\t}\n\n\tstatic isPermissionRestrictedForRole(permissionId: string, roleId: string): boolean {\n\t\tif (!roleId || !permissionId) {\n\t\t\tthrow new Error('invalid-param');\n\t\t}\n\n\t\tif (!restrictedRolePermissions.has(roleId)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst rules = restrictedRolePermissions.get(roleId);\n\t\tif (!rules || !rules.size) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !rules.has(permissionId);\n\t}\n\n\tstatic isPermissionRestrictedForRoleList(permissionId: string, roleList: string[]): boolean {\n\t\tif (!roleList || !permissionId) {\n\t\t\tthrow new Error('invalid-param');\n\t\t}\n\n\t\tfor (const roleId of roleList) {\n\t\t\tif (this.isPermissionRestrictedForRole(permissionId, roleId)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/lib/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/canAccessRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/canDeleteMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/canSendMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/getRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/getUsersInRole.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/hasPermission.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/hasRole.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/functions/upsertPermissions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/methods/addPermissionToRole.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/methods/addUserToRole.ts",["22920"],[],"import { Meteor } from 'meteor/meteor';\nimport type { IRole, IUser, IRoom } from '@rocket.chat/core-typings';\nimport { Roles } from '@rocket.chat/models';\nimport { api } from '@rocket.chat/core-services';\n\nimport { Users } from '../../../models/server';\nimport { settings } from '../../../settings/server';\nimport { hasPermission } from '../functions/hasPermission';\nimport { apiDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';\n\nMeteor.methods({\n\tasync 'authorization:addUserToRole'(roleId: IRole['_id'], username: IUser['username'], scope: IRoom['_id'] | undefined) {\n\t\tconst userId = Meteor.userId();\n\n\t\tif (!userId || !hasPermission(userId, 'access-permissions')) {\n\t\t\tthrow new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed', {\n\t\t\t\tmethod: 'authorization:addUserToRole',\n\t\t\t\taction: 'Accessing_permissions',\n\t\t\t});\n\t\t}\n\n\t\tif (!roleId || typeof roleId.valueOf() !== 'string' || !username || typeof username.valueOf() !== 'string') {\n\t\t\tthrow new Meteor.Error('error-invalid-arguments', 'Invalid arguments', {\n\t\t\t\tmethod: 'authorization:addUserToRole',\n\t\t\t});\n\t\t}\n\n\t\tlet role = await Roles.findOneById>(roleId, { projection: { _id: 1 } });\n\t\tif (!role) {\n\t\t\trole = await Roles.findOneByName>(roleId, { projection: { _id: 1 } });\n\n\t\t\tif (!role) {\n\t\t\t\tthrow new Meteor.Error('error-invalid-role', 'Invalid Role', {\n\t\t\t\t\tmethod: 'authorization:addUserToRole',\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tapiDeprecationLogger.warn(`Calling authorization:addUserToRole with role names will be deprecated in future versions of Rocket.Chat`);\n\t\t}\n\n\t\tif (role._id === 'admin' && !hasPermission(userId, 'assign-admin-role')) {\n\t\t\tthrow new Meteor.Error('error-action-not-allowed', 'Assigning admin is not allowed', {\n\t\t\t\tmethod: 'authorization:addUserToRole',\n\t\t\t\taction: 'Assign_admin',\n\t\t\t});\n\t\t}\n\n\t\tconst user = Users.findOneByUsernameIgnoringCase(username, {\n\t\t\tfields: {\n\t\t\t\t_id: 1,\n\t\t\t},\n\t\t});\n\n\t\tif (!user || !user._id) {\n\t\t\tthrow new Meteor.Error('error-user-not-found', 'User not found', {\n\t\t\t\tmethod: 'authorization:addUserToRole',\n\t\t\t});\n\t\t}\n\n\t\t// verify if user can be added to given scope\n\t\tif (scope && !(await Roles.canAddUserToRole(user._id, role._id, scope))) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'User is not part of given room', {\n\t\t\t\tmethod: 'authorization:addUserToRole',\n\t\t\t});\n\t\t}\n\n\t\tconst add = await Roles.addUserRoles(user._id, [role._id], scope);\n\n\t\tif (settings.get('UI_DisplayRoles')) {\n\t\t\tapi.broadcast('user.roleUpdate', {\n\t\t\t\ttype: 'added',\n\t\t\t\t_id: role._id,\n\t\t\t\tu: {\n\t\t\t\t\t_id: user._id,\n\t\t\t\t\tusername,\n\t\t\t\t},\n\t\t\t\tscope,\n\t\t\t});\n\t\t}\n\n\t\treturn add;\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/methods/deleteRole.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/methods/removeRoleFromPermission.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/methods/removeUserFromRole.ts",["22921"],[],"import { Meteor } from 'meteor/meteor';\nimport type { IRole, IUser } from '@rocket.chat/core-typings';\nimport { Roles } from '@rocket.chat/models';\nimport { api } from '@rocket.chat/core-services';\n\nimport { Users } from '../../../models/server';\nimport { settings } from '../../../settings/server';\nimport { hasPermission } from '../functions/hasPermission';\nimport { apiDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';\n\nMeteor.methods({\n\tasync 'authorization:removeUserFromRole'(roleId, username, scope) {\n\t\tconst userId = Meteor.userId();\n\n\t\tif (!userId || !hasPermission(userId, 'access-permissions')) {\n\t\t\tthrow new Meteor.Error('error-action-not-allowed', 'Access permissions is not allowed', {\n\t\t\t\tmethod: 'authorization:removeUserFromRole',\n\t\t\t\taction: 'Accessing_permissions',\n\t\t\t});\n\t\t}\n\n\t\tif (!roleId || typeof roleId.valueOf() !== 'string' || !username || typeof username.valueOf() !== 'string') {\n\t\t\tthrow new Meteor.Error('error-invalid-arguments', 'Invalid arguments', {\n\t\t\t\tmethod: 'authorization:removeUserFromRole',\n\t\t\t});\n\t\t}\n\n\t\tlet role = await Roles.findOneById>(roleId, { projection: { _id: 1 } });\n\t\tif (!role) {\n\t\t\trole = await Roles.findOneByName>(roleId, { projection: { _id: 1 } });\n\t\t\tif (!role) {\n\t\t\t\tthrow new Meteor.Error('error-invalid-role', 'Invalid Role', {\n\t\t\t\t\tmethod: 'authorization:removeUserFromRole',\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tapiDeprecationLogger.warn(\n\t\t\t\t`Calling authorization:removeUserFromRole with role names will be deprecated in future versions of Rocket.Chat`,\n\t\t\t);\n\t\t}\n\n\t\tconst user = Users.findOneByUsernameIgnoringCase(username, {\n\t\t\tfields: {\n\t\t\t\t_id: 1,\n\t\t\t\troles: 1,\n\t\t\t},\n\t\t}) as Pick;\n\n\t\tif (!user || !user._id) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tmethod: 'authorization:removeUserFromRole',\n\t\t\t});\n\t\t}\n\n\t\t// prevent removing last user from admin role\n\t\tif (role._id === 'admin') {\n\t\t\tconst adminCount = Meteor.users\n\t\t\t\t.find({\n\t\t\t\t\troles: {\n\t\t\t\t\t\t$in: ['admin'],\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t.count();\n\n\t\t\tconst userIsAdmin = user.roles?.indexOf('admin') > -1;\n\t\t\tif (adminCount === 1 && userIsAdmin) {\n\t\t\t\tthrow new Meteor.Error('error-action-not-allowed', 'Leaving the app without admins is not allowed', {\n\t\t\t\t\tmethod: 'removeUserFromRole',\n\t\t\t\t\taction: 'Remove_last_admin',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst remove = await Roles.removeUserRoles(user._id, [role._id], scope);\n\t\tconst event = {\n\t\t\ttype: 'removed',\n\t\t\t_id: role._id,\n\t\t\tu: {\n\t\t\t\t_id: user._id,\n\t\t\t\tusername,\n\t\t\t},\n\t\t\tscope,\n\t\t};\n\t\tif (settings.get('UI_DisplayRoles')) {\n\t\t\tapi.broadcast('user.roleUpdate', event);\n\t\t}\n\t\tapi.broadcast('federation.userRoleChanged', { ...event, givenByUserId: userId });\n\n\t\treturn remove;\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/authorization/server/streamer/permissions/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/client/lib/actionButton.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/client/lib/autotranslate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/client/lib/tabBar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/autotranslate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/deeplTranslate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/googleTranslate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/index.ts",[],["22922","22923"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/logger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/methods/getProviderUiMetadata.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/methods/getSupportedLanguages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/methods/saveSettings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/methods/translateMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/msTranslate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/permissions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/bot-helpers/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/bot-helpers/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cas/client/cas_client.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cas/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cas/server/cas_rocketchat.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cas/server/cas_server.js",["22924","22925","22926","22927"],[],"import url from 'url';\n\nimport { Meteor } from 'meteor/meteor';\nimport { Accounts } from 'meteor/accounts-base';\nimport { WebApp } from 'meteor/webapp';\nimport { RoutePolicy } from 'meteor/routepolicy';\nimport _ from 'underscore';\nimport fiber from 'fibers';\nimport { CredentialTokens } from '@rocket.chat/models';\nimport { validate } from '@rocket.chat/cas-validate';\n\nimport { logger } from './cas_rocketchat';\nimport { settings } from '../../settings/server';\nimport { Rooms } from '../../models/server';\nimport { _setRealName } from '../../lib';\nimport { createRoom } from '../../lib/server/functions/createRoom';\n\nRoutePolicy.declare('/_cas/', 'network');\n\nconst closePopup = function (res) {\n\tres.writeHead(200, { 'Content-Type': 'text/html' });\n\tconst content = '';\n\tres.end(content, 'utf-8');\n};\n\nconst casTicket = function (req, token, callback) {\n\t// get configuration\n\tif (!settings.get('CAS_enabled')) {\n\t\tlogger.error('Got ticket validation request, but CAS is not enabled');\n\t\tcallback();\n\t}\n\n\t// get ticket and validate.\n\tconst parsedUrl = url.parse(req.url, true);\n\tconst ticketId = parsedUrl.query.ticket;\n\tconst baseUrl = settings.get('CAS_base_url');\n\tconst cas_version = parseFloat(settings.get('CAS_version'));\n\tconst appUrl = Meteor.absoluteUrl().replace(/\\/$/, '') + __meteor_runtime_config__.ROOT_URL_PATH_PREFIX;\n\tlogger.debug(`Using CAS_base_url: ${baseUrl}`);\n\n\tvalidate(\n\t\t{\n\t\t\tbase_url: baseUrl,\n\t\t\tversion: cas_version,\n\t\t\tservice: `${appUrl}/_cas/${token}`,\n\t\t},\n\t\tticketId,\n\t\tMeteor.bindEnvironment(async function (err, status, username, details) {\n\t\t\tif (err) {\n\t\t\t\tlogger.error(`error when trying to validate: ${err.message}`);\n\t\t\t} else if (status) {\n\t\t\t\tlogger.info(`Validated user: ${username}`);\n\t\t\t\tconst user_info = { username };\n\n\t\t\t\t// CAS 2.0 attributes handling\n\t\t\t\tif (details && details.attributes) {\n\t\t\t\t\t_.extend(user_info, { attributes: details.attributes });\n\t\t\t\t}\n\t\t\t\tawait CredentialTokens.create(token, user_info);\n\t\t\t} else {\n\t\t\t\tlogger.error(`Unable to validate ticket: ${ticketId}`);\n\t\t\t}\n\t\t\t// logger.debug(\"Received response: \" + JSON.stringify(details, null , 4));\n\n\t\t\tcallback();\n\t\t}),\n\t);\n};\n\nconst middleware = function (req, res, next) {\n\t// Make sure to catch any exceptions because otherwise we'd crash\n\t// the runner\n\ttry {\n\t\tconst barePath = req.url.substring(0, req.url.indexOf('?'));\n\t\tconst splitPath = barePath.split('/');\n\n\t\t// Any non-cas request will continue down the default\n\t\t// middlewares.\n\t\tif (splitPath[1] !== '_cas') {\n\t\t\tnext();\n\t\t\treturn;\n\t\t}\n\n\t\t// get auth token\n\t\tconst credentialToken = splitPath[2];\n\t\tif (!credentialToken) {\n\t\t\tclosePopup(res);\n\t\t\treturn;\n\t\t}\n\n\t\t// validate ticket\n\t\tcasTicket(req, credentialToken, function () {\n\t\t\tclosePopup(res);\n\t\t});\n\t} catch (err) {\n\t\tlogger.error({ msg: 'Unexpected error', err });\n\t\tclosePopup(res);\n\t}\n};\n\n// Listen to incoming OAuth http requests\nWebApp.connectHandlers.use(function (req, res, next) {\n\t// Need to create a fiber since we're using synchronous http calls and nothing\n\t// else is wrapping this in a fiber automatically\n\tfiber(function () {\n\t\tmiddleware(req, res, next);\n\t}).run();\n});\n\n/*\n * Register a server-side login handle.\n * It is call after Accounts.callLoginMethod() is call from client.\n *\n */\nAccounts.registerLoginHandler('cas', function (options) {\n\tif (!options.cas) {\n\t\treturn undefined;\n\t}\n\n\t// TODO: Sync wrapper due to the chain conversion to async models\n\tconst credentials = Promise.await(CredentialTokens.findOneNotExpiredById(options.cas.credentialToken));\n\tif (credentials === undefined) {\n\t\tthrow new Meteor.Error(Accounts.LoginCancelledError.numericError, 'no matching login attempt found');\n\t}\n\n\tconst result = credentials.userInfo;\n\tconst syncUserDataFieldMap = settings.get('CAS_Sync_User_Data_FieldMap').trim();\n\tconst cas_version = parseFloat(settings.get('CAS_version'));\n\tconst sync_enabled = settings.get('CAS_Sync_User_Data_Enabled');\n\tconst trustUsername = settings.get('CAS_trust_username');\n\tconst verified = settings.get('Accounts_Verify_Email_For_External_Accounts');\n\tconst userCreationEnabled = settings.get('CAS_Creation_User_Enabled');\n\n\t// We have these\n\tconst ext_attrs = {\n\t\tusername: result.username,\n\t};\n\n\t// We need these\n\tconst int_attrs = {\n\t\temail: undefined,\n\t\tname: undefined,\n\t\tusername: undefined,\n\t\trooms: undefined,\n\t};\n\n\t// Import response attributes\n\tif (cas_version >= 2.0) {\n\t\t// Clean & import external attributes\n\t\t_.each(result.attributes, function (value, ext_name) {\n\t\t\tif (value) {\n\t\t\t\text_attrs[ext_name] = value[0];\n\t\t\t}\n\t\t});\n\t}\n\n\t// Source internal attributes\n\tif (syncUserDataFieldMap) {\n\t\t// Our mapping table: key(int_attr) -> value(ext_attr)\n\t\t// Spoken: Source this internal attribute from these external attributes\n\t\tconst attr_map = JSON.parse(syncUserDataFieldMap);\n\n\t\t_.each(attr_map, function (source, int_name) {\n\t\t\t// Source is our String to interpolate\n\t\t\tif (source && typeof source.valueOf() === 'string') {\n\t\t\t\tlet replacedValue = source;\n\t\t\t\t_.each(ext_attrs, function (value, ext_name) {\n\t\t\t\t\treplacedValue = replacedValue.replace(`%${ext_name}%`, ext_attrs[ext_name]);\n\t\t\t\t});\n\n\t\t\t\tif (source !== replacedValue) {\n\t\t\t\t\tint_attrs[int_name] = replacedValue;\n\t\t\t\t\tlogger.debug(`Sourced internal attribute: ${int_name} = ${replacedValue}`);\n\t\t\t\t} else {\n\t\t\t\t\tlogger.debug(`Sourced internal attribute: ${int_name} skipped.`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t// Search existing user by its external service id\n\tlogger.debug(`Looking up user by id: ${result.username}`);\n\t// First, look for a user that has logged in from CAS with this username before\n\tlet user = Meteor.users.findOne({ 'services.cas.external_id': result.username });\n\tif (!user) {\n\t\t// If that user was not found, check if there's any Rocket.Chat user with that username\n\t\t// With this, CAS login will continue to work if the user is renamed on both sides and also if the user is renamed only on Rocket.Chat.\n\t\t// It'll also allow non-CAS users to switch to CAS based login\n\t\tif (trustUsername) {\n\t\t\tconst username = new RegExp(`^${result.username}$`, 'i');\n\t\t\tuser = Meteor.users.findOne({ username });\n\t\t\tif (user) {\n\t\t\t\t// Update the user's external_id to reflect this new username.\n\t\t\t\tMeteor.users.update(user, { $set: { 'services.cas.external_id': result.username } });\n\t\t\t}\n\t\t}\n\t}\n\n\tif (user) {\n\t\tlogger.debug(`Using existing user for '${result.username}' with id: ${user._id}`);\n\t\tif (sync_enabled) {\n\t\t\tlogger.debug('Syncing user attributes');\n\t\t\t// Update name\n\t\t\tif (int_attrs.name) {\n\t\t\t\t_setRealName(user._id, int_attrs.name);\n\t\t\t}\n\n\t\t\t// Update email\n\t\t\tif (int_attrs.email) {\n\t\t\t\tMeteor.users.update(user, { $set: { emails: [{ address: int_attrs.email, verified }] } });\n\t\t\t}\n\t\t}\n\t} else if (userCreationEnabled) {\n\t\t// Define new user\n\t\tconst newUser = {\n\t\t\tusername: result.username,\n\t\t\tactive: true,\n\t\t\tglobalRoles: ['user'],\n\t\t\temails: [],\n\t\t\tservices: {\n\t\t\t\tcas: {\n\t\t\t\t\texternal_id: result.username,\n\t\t\t\t\tversion: cas_version,\n\t\t\t\t\tattrs: int_attrs,\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\n\t\t// Add username\n\t\tif (int_attrs.username) {\n\t\t\t_.extend(newUser, {\n\t\t\t\tusername: int_attrs.username,\n\t\t\t});\n\t\t}\n\n\t\t// Add User.name\n\t\tif (int_attrs.name) {\n\t\t\t_.extend(newUser, {\n\t\t\t\tname: int_attrs.name,\n\t\t\t});\n\t\t}\n\n\t\t// Add email\n\t\tif (int_attrs.email) {\n\t\t\t_.extend(newUser, {\n\t\t\t\temails: [{ address: int_attrs.email, verified }],\n\t\t\t});\n\t\t}\n\n\t\t// Create the user\n\t\tlogger.debug(`User \"${result.username}\" does not exist yet, creating it`);\n\t\tconst userId = Accounts.insertUserDoc({}, newUser);\n\n\t\t// Fetch and use it\n\t\tuser = Meteor.users.findOne(userId);\n\t\tlogger.debug(`Created new user for '${result.username}' with id: ${user._id}`);\n\t\t// logger.debug(JSON.stringify(user, undefined, 4));\n\n\t\tlogger.debug(`Joining user to attribute channels: ${int_attrs.rooms}`);\n\t\tif (int_attrs.rooms) {\n\t\t\t_.each(int_attrs.rooms.split(','), function (room_name) {\n\t\t\t\tif (room_name) {\n\t\t\t\t\tlet room = Rooms.findOneByNameAndType(room_name, 'c');\n\t\t\t\t\tif (!room) {\n\t\t\t\t\t\troom = createRoom('c', room_name, user.username);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t} else {\n\t\t// Should fail as no user exist and can't be created\n\t\tlogger.debug(`User \"${result.username}\" does not exist yet, will fail as no user creation is enabled`);\n\t\tthrow new Meteor.Error(Accounts.LoginCancelledError.numericError, 'no matching user account found');\n\t}\n\n\treturn { userId: user._id };\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cas/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/client/lib/ChannelSettings.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/client/tabBar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveReactWhenReadOnly.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomAnnouncement.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomCustomFields.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomDescription.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomEncrypted.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomName.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomReadOnly.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomSystemMessages.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomTopic.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveRoomType.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/functions/saveStreamingOptions.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/buildRegistrationData.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/checkUserHasCloudLogin.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/connectWorkspace.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/disconnectWorkspace.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/finishOAuthAuthorization.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getConfirmationPoll.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getOAuthAuthorizationUrl.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getRedirectUri.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getUserCloudAccessToken.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getWorkspaceAccessTokenWithScope.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getWorkspaceKey.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts",["22928"],[],"import { HTTP } from 'meteor/http';\nimport { Settings } from '@rocket.chat/models';\n\nimport { getWorkspaceAccessToken } from './getWorkspaceAccessToken';\nimport { settings } from '../../../settings/server';\nimport { callbacks } from '../../../../lib/callbacks';\nimport { LICENSE_VERSION } from '../license';\nimport { SystemLogger } from '../../../../server/lib/logger/system';\n\nexport async function getWorkspaceLicense(): Promise<{ updated: boolean; license: string }> {\n\tconst currentLicense = await Settings.findOne('Cloud_Workspace_License');\n\n\tconst cachedLicenseReturn = () => {\n\t\tconst license = currentLicense?.value as string;\n\t\tif (license) {\n\t\t\tcallbacks.run('workspaceLicenseChanged', license);\n\t\t}\n\n\t\treturn { updated: false, license };\n\t};\n\n\tconst token = await getWorkspaceAccessToken();\n\tif (!token) {\n\t\treturn cachedLicenseReturn();\n\t}\n\n\tlet licenseResult;\n\ttry {\n\t\tlicenseResult = HTTP.get(`${settings.get('Cloud_Workspace_Registration_Client_Uri')}/license?version=${LICENSE_VERSION}`, {\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\t},\n\t\t});\n\t} catch (err: any) {\n\t\tSystemLogger.error({\n\t\t\tmsg: 'Failed to update license from Rocket.Chat Cloud',\n\t\t\turl: '/license',\n\t\t\t...(err.response?.data && { cloudError: err.response.data }),\n\t\t\terr,\n\t\t});\n\n\t\treturn cachedLicenseReturn();\n\t}\n\n\tconst remoteLicense = licenseResult.data;\n\n\tif (!currentLicense || !currentLicense._updatedAt) {\n\t\tthrow new Error('Failed to retrieve current license');\n\t}\n\n\tif (remoteLicense.updatedAt <= currentLicense._updatedAt) {\n\t\treturn cachedLicenseReturn();\n\t}\n\n\tawait Settings.updateValueById('Cloud_Workspace_License', remoteLicense.license);\n\n\tcallbacks.run('workspaceLicenseChanged', remoteLicense.license);\n\n\treturn { updated: true, license: remoteLicense.license };\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/reconnectWorkspace.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/registerPreIntentWorkspaceWizard.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/removeWorkspaceRegistrationInfo.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/retrieveRegistrationStatus.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/saveRegistrationData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/startRegisterWorkspaceSetupWizard.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/syncWorkspace.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/userLoggedOut.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/functions/userLogout.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/license.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/methods.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cloud/server/oauthScopes.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/colors/client/client.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/colors/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/colors/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/colors/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cors/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cors/server/cors.js",["22929"],[],"import url from 'url';\n\nimport { Meteor } from 'meteor/meteor';\nimport { WebApp, WebAppInternals } from 'meteor/webapp';\nimport _ from 'underscore';\n\nimport { settings } from '../../settings/server';\nimport { Logger } from '../../logger/server';\n\nconst logger = new Logger('CORS');\n\nsettings.watch('Enable_CSP', (enabled) => {\n\tWebAppInternals.setInlineScriptsAllowed(!enabled);\n});\n\nWebApp.rawConnectHandlers.use(function (req, res, next) {\n\t// XSS Protection for old browsers (IE)\n\tres.setHeader('X-XSS-Protection', '1');\n\n\t// X-Content-Type-Options header to prevent MIME Sniffing\n\tres.setHeader('X-Content-Type-Options', 'nosniff');\n\n\tif (settings.get('Iframe_Restrict_Access')) {\n\t\tres.setHeader('X-Frame-Options', settings.get('Iframe_X_Frame_Options'));\n\t}\n\n\tif (settings.get('Enable_CSP')) {\n\t\tconst cdn_prefixes = [settings.get('CDN_PREFIX'), settings.get('CDN_PREFIX_ALL') ? null : settings.get('CDN_JSCSS_PREFIX')]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\n\t\tconst inlineHashes = [\n\t\t\t// Hash for `window.close()`, required by the CAS login popup.\n\t\t\t\"'sha256-jqxtvDkBbRAl9Hpqv68WdNOieepg8tJSYu1xIy7zT34='\",\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\t\tconst external = [\n\t\t\tsettings.get('Accounts_OAuth_Apple') && 'https://appleid.cdn-apple.com',\n\t\t\tsettings.get('PiwikAnalytics_enabled') && settings.get('PiwikAnalytics_url'),\n\t\t\tsettings.get('GoogleAnalytics_enabled' && 'https://www.google-analytics.com'),\n\t\t\t...settings\n\t\t\t\t.get('Extra_CSP_Domains')\n\t\t\t\t.split(/[ \\n\\,]/gim)\n\t\t\t\t.filter((e) => Boolean(e.trim())),\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(' ');\n\t\tres.setHeader(\n\t\t\t'Content-Security-Policy',\n\t\t\t[\n\t\t\t\t`default-src 'self' ${cdn_prefixes}`,\n\t\t\t\t'connect-src *',\n\t\t\t\t`font-src 'self' ${cdn_prefixes} data:`,\n\t\t\t\t'frame-src *',\n\t\t\t\t'img-src * data: blob:',\n\t\t\t\t'media-src * data:',\n\t\t\t\t`script-src 'self' 'unsafe-eval' ${inlineHashes} ${cdn_prefixes} ${external}`,\n\t\t\t\t`style-src 'self' 'unsafe-inline' ${cdn_prefixes}`,\n\t\t\t].join('; '),\n\t\t);\n\t}\n\n\treturn next();\n});\n\nconst _staticFilesMiddleware = WebAppInternals.staticFilesMiddleware;\n\nWebAppInternals._staticFilesMiddleware = function (staticFiles, req, res, next) {\n\tres.setHeader('Access-Control-Allow-Origin', '*');\n\treturn _staticFilesMiddleware(staticFiles, req, res, next);\n};\n\nconst oldHttpServerListeners = WebApp.httpServer.listeners('request').slice(0);\n\nWebApp.httpServer.removeAllListeners('request');\n\nWebApp.httpServer.addListener('request', function (req, res, ...args) {\n\tconst next = () => {\n\t\tfor (const oldListener of oldHttpServerListeners) {\n\t\t\toldListener.apply(WebApp.httpServer, [req, res, ...args]);\n\t\t}\n\t};\n\n\tif (settings.get('Force_SSL') !== true) {\n\t\tnext();\n\t\treturn;\n\t}\n\n\tconst remoteAddress = req.connection.remoteAddress || req.socket.remoteAddress;\n\tconst localhostRegexp = /^\\s*(127\\.0\\.0\\.1|::1)\\s*$/;\n\tconst localhostTest = function (x) {\n\t\treturn localhostRegexp.test(x);\n\t};\n\n\tconst isLocal =\n\t\tlocalhostRegexp.test(remoteAddress) &&\n\t\t(!req.headers['x-forwarded-for'] || _.all(req.headers['x-forwarded-for'].split(','), localhostTest));\n\tconst isSsl = req.connection.pair || (req.headers['x-forwarded-proto'] && req.headers['x-forwarded-proto'].indexOf('https') !== -1);\n\n\tlogger.debug('req.url', req.url);\n\tlogger.debug('remoteAddress', remoteAddress);\n\tlogger.debug('isLocal', isLocal);\n\tlogger.debug('isSsl', isSsl);\n\tlogger.debug('req.headers', req.headers);\n\n\tif (!isLocal && !isSsl) {\n\t\tlet host = req.headers.host || url.parse(Meteor.absoluteUrl()).hostname;\n\t\thost = host.replace(/:\\d+$/, '');\n\t\tres.writeHead(302, {\n\t\t\tLocation: `https://${host}${req.url}`,\n\t\t});\n\t\tres.end();\n\t\treturn;\n\t}\n\n\treturn next();\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/cors/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/crowd/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/crowd/client/loginHelper.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/crowd/server/crowd.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/crowd/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/crowd/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-oauth/client/custom_oauth_client.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-oauth/client/swapSessionStorage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-oauth/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-oauth/server/custom_oauth_server.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-oauth/server/custom_oauth_server.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-oauth/server/transform_helpers.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/client/lib/CustomSounds.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/client/notifications/deleteCustomSound.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/client/notifications/updateCustomSound.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/methods/deleteCustomSound.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/methods/insertOrUpdateSound.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/methods/listCustomSounds.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/methods/uploadCustomSound.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/startup/custom-sounds.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/custom-sounds/server/startup/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/client/createDiscussionMessageAction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/client/lib/messageTypes/discussionMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/client/tabBar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/server/config.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/server/hooks/joinDiscussionOnMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/server/hooks/propagateDiscussionMetadata.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/server/methods/createDiscussion.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/discussion/server/permissions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/dolphin/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/dolphin/lib/common.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/dolphin/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/dolphin/server/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/drupal/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/drupal/lib/common.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/drupal/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/drupal/server/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/E2ERoomState.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/events.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/helper.js",[],["22930","22931","22932","22933"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/logger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/rocketchat.e2e.room.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/rocketchat.e2e.ts",[],["22934","22935","22936","22937","22938","22939","22940","22941","22942","22943"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/tabbar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/client/wordList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/beforeCreateRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/functions/handleSuggestedGroupKey.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/fetchMyKeys.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/getUsersOfRoomWithoutKey.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/requestSubscriptionKeys.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/resetOwnE2EKey.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/setRoomKeyID.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/setUserPublicAndPrivateKeys.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/methods/updateGroupKey.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/e2e/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/client/emojiParser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/client/emojiPicker.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/client/function-isSet.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/client/lib/EmojiPicker.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/lib/rocketchat.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/client/lib/emojiCustom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/client/lib/function-isSet.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/client/notifications/deleteEmojiCustom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/client/notifications/updateEmojiCustom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/methods/deleteEmojiCustom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/methods/insertOrUpdateEmoji.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/methods/listEmojiCustom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/methods/uploadEmojiCustom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/startup/emoji-custom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-custom/server/startup/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-emojione/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-emojione/lib/emojiPicker.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-emojione/lib/emojioneRender.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-emojione/lib/rocketchat.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-emojione/server/callbacks.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/emoji-emojione/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/error-handler/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/error-handler/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/error-handler/server/lib/RocketChat.ErrorHandler.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/error-handler/server/startup/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/constants.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/endpoints/dispatch.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/endpoints/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/endpoints/requestFromLatest.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/endpoints/uploads.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/endpoints/users.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/functions/addUser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/functions/dashboard.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/functions/errors.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/functions/helpers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/functions/resolveDNS.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/functions/searchUsers.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/handler/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterAddedToRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterCreateDirectRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterCreateRoom.js",[],["22944"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterDeleteMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterLeaveRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterMuteUser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterRemoveFromRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterSaveMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterSetReaction.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterUnmuteUser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/afterUnsetReaction.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/hooks/beforeDeleteRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/callbacks.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/crypt.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/dns.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/getFederationDiscoveryMethod.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/getFederationDomain.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/http.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/isFederationEnabled.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/lib/logger.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/methods/dashboard.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/methods/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/methods/loadContextEvents.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/methods/testSetup.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/normalizers/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/normalizers/message.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/normalizers/room.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/normalizers/subscription.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/normalizers/user.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/startup/generateKeys.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/startup/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/startup/registerCallbacks.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation/server/startup/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/Federation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/AbstractFederationService.ts",["22945"],[],"import type { IUser } from '@rocket.chat/core-typings';\n\nimport { FederatedUser } from '../domain/FederatedUser';\nimport type { IFederationBridge } from '../domain/IFederationBridge';\nimport type { RocketChatFileAdapter } from '../infrastructure/rocket-chat/adapters/File';\nimport type { RocketChatSettingsAdapter } from '../infrastructure/rocket-chat/adapters/Settings';\nimport type { RocketChatUserAdapter } from '../infrastructure/rocket-chat/adapters/User';\n\nexport abstract class FederationService {\n\tprotected internalHomeServerDomain: string;\n\n\tconstructor(\n\t\tprotected bridge: IFederationBridge,\n\t\tprotected internalUserAdapter: RocketChatUserAdapter,\n\t\tprotected internalFileAdapter: RocketChatFileAdapter,\n\t\tprotected internalSettingsAdapter: RocketChatSettingsAdapter,\n\t) {\n\t\tthis.internalHomeServerDomain = this.internalSettingsAdapter.getHomeServerDomain();\n\t}\n\n\tprotected async createFederatedUserInternallyOnly(\n\t\texternalUserId: string,\n\t\tusername: string,\n\t\texistsOnlyOnProxyServer = false,\n\t\tprovidedName?: string,\n\t): Promise {\n\t\tconst internalUser = await this.internalUserAdapter.getInternalUserByUsername(username);\n\t\tconst externalUserProfileInformation = await this.bridge.getUserProfileInformation(externalUserId);\n\t\tlet federatedUser;\n\t\tif (internalUser) {\n\t\t\tfederatedUser = FederatedUser.createWithInternalReference(externalUserId, existsOnlyOnProxyServer, internalUser);\n\t\t} else {\n\t\t\tconst name = externalUserProfileInformation?.displayName || providedName || username;\n\t\t\tfederatedUser = FederatedUser.createInstance(externalUserId, {\n\t\t\t\tname,\n\t\t\t\tusername,\n\t\t\t\texistsOnlyOnProxyServer,\n\t\t\t});\n\t\t}\n\t\tawait this.internalUserAdapter.createFederatedUser(federatedUser);\n\t\tconst insertedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalUserId);\n\t\tif (!insertedUser) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.updateUserAvatarInternally(insertedUser, externalUserProfileInformation?.avatarUrl);\n\t\tawait this.updateUserDisplayNameInternally(insertedUser, externalUserProfileInformation?.displayName);\n\t}\n\n\tprotected async updateUserAvatarInternally(federatedUser: FederatedUser, avatarUrl?: string): Promise {\n\t\tif (!avatarUrl) {\n\t\t\treturn;\n\t\t}\n\t\tif (!federatedUser.isRemote()) {\n\t\t\treturn;\n\t\t}\n\t\tif (federatedUser.shouldUpdateFederationAvatar(avatarUrl)) {\n\t\t\tawait this.internalUserAdapter.setAvatar(federatedUser, this.bridge.convertMatrixUrlToHttp(federatedUser.getExternalId(), avatarUrl));\n\t\t\tawait this.internalUserAdapter.updateFederationAvatar(federatedUser.getInternalId(), avatarUrl);\n\t\t}\n\t}\n\n\tprotected async updateUserDisplayNameInternally(federatedUser: FederatedUser, displayName?: string): Promise {\n\t\tif (!displayName) {\n\t\t\treturn;\n\t\t}\n\t\tif (!federatedUser.isRemote()) {\n\t\t\treturn;\n\t\t}\n\t\tif (federatedUser.shouldUpdateDisplayName(displayName)) {\n\t\t\tawait this.internalUserAdapter.updateRealName(federatedUser.getInternalReference(), displayName);\n\t\t}\n\t}\n\n\tprotected async createFederatedUserIncludingHomeserverUsingLocalInformation(internalInviterId: string): Promise {\n\t\tconst internalUser = await this.internalUserAdapter.getInternalUserById(internalInviterId);\n\t\tif (!internalUser || !internalUser?.username) {\n\t\t\tthrow new Error(`Could not find user id for ${internalInviterId}`);\n\t\t}\n\t\tconst name = internalUser.name || internalUser.username;\n\t\tconst externalInviterId = await this.bridge.createUser(internalUser.username, name, this.internalHomeServerDomain);\n\t\tconst existsOnlyOnProxyServer = true;\n\t\tawait this.createFederatedUserInternallyOnly(externalInviterId, internalUser.username, existsOnlyOnProxyServer, name);\n\t\tawait this.updateUserAvatarExternally(\n\t\t\tinternalUser,\n\t\t\t(await this.internalUserAdapter.getFederatedUserByExternalId(externalInviterId)) as FederatedUser,\n\t\t);\n\n\t\treturn externalInviterId;\n\t}\n\n\tprotected async updateUserAvatarExternally(internalUser: IUser, externalInviter: FederatedUser): Promise {\n\t\tif (!internalUser.username) {\n\t\t\treturn;\n\t\t}\n\t\tconst buffer = await this.internalFileAdapter.getBufferForAvatarFile(internalUser.username);\n\t\tif (!buffer) {\n\t\t\treturn;\n\t\t}\n\t\tconst avatarFileRecord = await this.internalFileAdapter.getFileMetadataForAvatarFile(internalUser.username);\n\t\tif (!avatarFileRecord?.type || !avatarFileRecord?.name) {\n\t\t\treturn;\n\t\t}\n\t\tconst externalFileUri = await this.bridge.uploadContent(externalInviter.getExternalId(), buffer, {\n\t\t\ttype: avatarFileRecord.type,\n\t\t\tname: avatarFileRecord.name,\n\t\t});\n\t\tif (!externalFileUri) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.internalUserAdapter.updateFederationAvatar(internalUser._id, externalFileUri);\n\t\tawait this.bridge.setUserAvatar(externalInviter.getExternalId(), externalFileUri);\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/MessageServiceListener.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/RoomRedactionHandlers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/RoomServiceListener.ts",["22946"],[],"import { isDirectMessageRoom, isQuoteAttachment } from '@rocket.chat/core-typings';\n\nimport { DirectMessageFederatedRoom, FederatedRoom } from '../../domain/FederatedRoom';\nimport { FederatedUser } from '../../domain/FederatedUser';\nimport { EVENT_ORIGIN } from '../../domain/IFederationBridge';\nimport type { IFederationBridge } from '../../domain/IFederationBridge';\nimport type { RocketChatMessageAdapter } from '../../infrastructure/rocket-chat/adapters/Message';\nimport type { RocketChatRoomAdapter } from '../../infrastructure/rocket-chat/adapters/Room';\nimport type { RocketChatSettingsAdapter } from '../../infrastructure/rocket-chat/adapters/Settings';\nimport type { RocketChatUserAdapter } from '../../infrastructure/rocket-chat/adapters/User';\nimport type {\n\tFederationRoomCreateInputDto,\n\tFederationRoomChangeMembershipDto,\n\tFederationRoomReceiveExternalMessageDto,\n\tFederationRoomChangeJoinRulesDto,\n\tFederationRoomChangeNameDto,\n\tFederationRoomChangeTopicDto,\n\tFederationRoomReceiveExternalFileMessageDto,\n\tFederationRoomRedactEventDto,\n\tFederationRoomEditExternalMessageDto,\n\tFederationRoomRoomChangePowerLevelsEventDto,\n} from './input/RoomReceiverDto';\nimport { FederationService } from '../AbstractFederationService';\nimport type { RocketChatFileAdapter } from '../../infrastructure/rocket-chat/adapters/File';\nimport { getRedactMessageHandler } from './RoomRedactionHandlers';\nimport type { RocketChatNotificationAdapter } from '../../infrastructure/rocket-chat/adapters/Notification';\nimport type { InMemoryQueue } from '../../infrastructure/queue/InMemoryQueue';\n\nexport class FederationRoomServiceListener extends FederationService {\n\tconstructor(\n\t\tprotected internalRoomAdapter: RocketChatRoomAdapter,\n\t\tprotected internalUserAdapter: RocketChatUserAdapter,\n\t\tprotected internalMessageAdapter: RocketChatMessageAdapter,\n\t\tprotected internalFileAdapter: RocketChatFileAdapter,\n\t\tprotected internalSettingsAdapter: RocketChatSettingsAdapter,\n\t\tprotected internalNotificationAdapter: RocketChatNotificationAdapter,\n\t\tprotected federationQueueInstance: InMemoryQueue,\n\t\tprotected bridge: IFederationBridge,\n\t) {\n\t\tsuper(bridge, internalUserAdapter, internalFileAdapter, internalSettingsAdapter);\n\t}\n\n\tpublic async onCreateRoom(roomCreateInput: FederationRoomCreateInputDto): Promise {\n\t\tconst { externalRoomId, wasInternallyProgramaticallyCreated = false, internalRoomId = '' } = roomCreateInput;\n\t\tif (await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId)) {\n\t\t\treturn;\n\t\t}\n\t\tif (!wasInternallyProgramaticallyCreated) {\n\t\t\treturn;\n\t\t}\n\t\tconst room = await this.internalRoomAdapter.getInternalRoomById(internalRoomId);\n\t\tif (!room || !isDirectMessageRoom(room)) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.internalRoomAdapter.updateFederatedRoomByInternalRoomId(internalRoomId, externalRoomId);\n\t}\n\n\tpublic async onChangeRoomMembership(roomChangeMembershipInput: FederationRoomChangeMembershipDto): Promise {\n\t\tconst {\n\t\t\texternalRoomId,\n\t\t\tnormalizedInviteeId,\n\t\t\tnormalizedRoomId,\n\t\t\tnormalizedInviterId,\n\t\t\texternalInviteeId,\n\t\t\texternalInviterId,\n\t\t\tinviteeUsernameOnly,\n\t\t\tinviterUsernameOnly,\n\t\t\teventOrigin,\n\t\t\troomType,\n\t\t\tleave,\n\t\t\tuserProfile,\n\t\t\tallInviteesExternalIdsWhenDM,\n\t\t\texternalRoomName,\n\t\t\texternalEventId,\n\t\t} = roomChangeMembershipInput;\n\t\tconst wasGeneratedOnTheProxyServer = eventOrigin === EVENT_ORIGIN.LOCAL;\n\t\tconst affectedFederatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId);\n\t\tconst isUserJoiningByHimself = externalInviterId === externalInviteeId && !leave;\n\n\t\tif (userProfile?.avatarUrl) {\n\t\t\tconst federatedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalInviteeId);\n\t\t\tfederatedUser && (await this.updateUserAvatarInternally(federatedUser, userProfile?.avatarUrl));\n\t\t}\n\t\tif (userProfile?.displayName) {\n\t\t\tconst federatedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalInviteeId);\n\t\t\tfederatedUser && (await this.updateUserDisplayNameInternally(federatedUser, userProfile?.displayName));\n\t\t}\n\n\t\tif (wasGeneratedOnTheProxyServer && (isUserJoiningByHimself || !affectedFederatedRoom)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isInviterFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer(\n\t\t\tthis.bridge.extractHomeserverOrigin(externalInviterId),\n\t\t\tthis.internalHomeServerDomain,\n\t\t);\n\t\tconst isInviteeFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer(\n\t\t\tthis.bridge.extractHomeserverOrigin(externalInviteeId),\n\t\t\tthis.internalHomeServerDomain,\n\t\t);\n\t\tconst inviterUsername = isInviterFromTheSameHomeServer ? inviterUsernameOnly : normalizedInviterId;\n\t\tconst inviteeUsername = isInviteeFromTheSameHomeServer ? inviteeUsernameOnly : normalizedInviteeId;\n\n\t\tconst inviterUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalInviterId);\n\t\tif (!inviterUser) {\n\t\t\tawait this.createFederatedUserInternallyOnly(externalInviterId, inviterUsername, isInviterFromTheSameHomeServer);\n\t\t}\n\n\t\tconst inviteeUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalInviteeId);\n\t\tif (!inviteeUser) {\n\t\t\tawait this.createFederatedUserInternallyOnly(externalInviteeId, inviteeUsername, isInviteeFromTheSameHomeServer);\n\t\t}\n\t\tconst federatedInviteeUser = inviteeUser || (await this.internalUserAdapter.getFederatedUserByExternalId(externalInviteeId));\n\t\tconst federatedInviterUser = inviterUser || (await this.internalUserAdapter.getFederatedUserByExternalId(externalInviterId));\n\n\t\tif (!federatedInviteeUser || !federatedInviterUser) {\n\t\t\tthrow new Error('Invitee or inviter user not found');\n\t\t}\n\n\t\tif (!wasGeneratedOnTheProxyServer && !affectedFederatedRoom) {\n\t\t\tif (!roomType) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (isDirectMessageRoom({ t: roomType })) {\n\t\t\t\tconst wereAllInviteesProvidedByCreationalEventAtOnce = allInviteesExternalIdsWhenDM && allInviteesExternalIdsWhenDM.length > 0;\n\t\t\t\tif (wereAllInviteesProvidedByCreationalEventAtOnce) {\n\t\t\t\t\treturn this.handleDMRoomInviteWhenAllUsersWereBeingProvidedInTheCreationalEvent(\n\t\t\t\t\t\tallInviteesExternalIdsWhenDM,\n\t\t\t\t\t\texternalRoomId,\n\t\t\t\t\t\tfederatedInviterUser,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn this.handleDMRoomInviteWhenNotifiedByRegularEventsOnly(federatedInviteeUser, federatedInviterUser, externalRoomId);\n\t\t\t}\n\n\t\t\tconst newFederatedRoom = FederatedRoom.createInstance(externalRoomId, normalizedRoomId, federatedInviterUser, roomType);\n\t\t\tconst createdInternalRoomId = await this.internalRoomAdapter.createFederatedRoom(newFederatedRoom);\n\n\t\t\tawait this.bridge.joinRoom(externalRoomId, externalInviteeId);\n\t\t\tif (externalRoomName) {\n\t\t\t\tawait this.onChangeRoomName({\n\t\t\t\t\texternalRoomId,\n\t\t\t\t\tnormalizedRoomName: externalRoomName,\n\t\t\t\t\texternalEventId,\n\t\t\t\t\texternalSenderId: externalInviterId,\n\t\t\t\t\tnormalizedRoomId,\n\t\t\t\t});\n\t\t\t}\n\t\t\tawait this.internalNotificationAdapter.subscribeToUserTypingEventsOnFederatedRoomId(\n\t\t\t\tcreatedInternalRoomId,\n\t\t\t\tthis.internalNotificationAdapter.broadcastUserTypingOnRoom.bind(this.internalNotificationAdapter),\n\t\t\t);\n\t\t\tconst roomHistoricalJoinEvents = await this.bridge.getRoomHistoricalJoinEvents(externalRoomId, externalInviteeId, [\n\t\t\t\texternalInviterId,\n\t\t\t\texternalInviteeId,\n\t\t\t]);\n\t\t\troomHistoricalJoinEvents.forEach((event) => this.federationQueueInstance.addToQueue(event));\n\t\t}\n\n\t\tconst federatedRoom = affectedFederatedRoom || (await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId));\n\t\tif (!federatedRoom) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst inviteeAlreadyJoinedTheInternalRoom = await this.internalRoomAdapter.isUserAlreadyJoined(\n\t\t\tfederatedRoom.getInternalId(),\n\t\t\tfederatedInviteeUser.getInternalId(),\n\t\t);\n\t\tif (!leave && inviteeAlreadyJoinedTheInternalRoom) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (leave) {\n\t\t\tconst inviteeAlreadyJoinedTheInternalRoom = await this.internalRoomAdapter.isUserAlreadyJoined(\n\t\t\t\tfederatedRoom.getInternalId(),\n\t\t\t\tfederatedInviteeUser.getInternalId(),\n\t\t\t);\n\t\t\tif (!inviteeAlreadyJoinedTheInternalRoom) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait this.internalRoomAdapter.removeUserFromRoom(federatedRoom, federatedInviteeUser, federatedInviterUser);\n\t\t\treturn;\n\t\t}\n\t\tif (!wasGeneratedOnTheProxyServer && federatedRoom.isDirectMessage()) {\n\t\t\tconst directMessageRoom = federatedRoom as DirectMessageFederatedRoom;\n\t\t\tif (directMessageRoom.isUserPartOfTheRoom(federatedInviteeUser)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdirectMessageRoom.addMember(federatedInviteeUser);\n\t\t\tconst newFederatedRoom = DirectMessageFederatedRoom.createInstance(\n\t\t\t\texternalRoomId,\n\t\t\t\tfederatedInviterUser,\n\t\t\t\tdirectMessageRoom.getMembers(),\n\t\t\t);\n\t\t\tawait this.internalRoomAdapter.removeDirectMessageRoom(federatedRoom);\n\t\t\tconst createdInternalRoomId = await this.internalRoomAdapter.createFederatedRoomForDirectMessage(newFederatedRoom);\n\t\t\tawait this.internalNotificationAdapter.subscribeToUserTypingEventsOnFederatedRoomId(\n\t\t\t\tcreatedInternalRoomId,\n\t\t\t\tthis.internalNotificationAdapter.broadcastUserTypingOnRoom.bind(this.internalNotificationAdapter),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tif (isUserJoiningByHimself) {\n\t\t\tawait this.internalRoomAdapter.addUserToRoom(federatedRoom, federatedInviteeUser);\n\t\t\treturn;\n\t\t}\n\t\tawait this.internalRoomAdapter.addUserToRoom(federatedRoom, federatedInviteeUser, federatedInviterUser);\n\t\tif (isInviteeFromTheSameHomeServer) {\n\t\t\tawait this.bridge.joinRoom(externalRoomId, externalInviteeId);\n\t\t}\n\t}\n\n\tprivate async handleDMRoomInviteWhenAllUsersWereBeingProvidedInTheCreationalEvent(\n\t\tallInviteesExternalIds: {\n\t\t\texternalInviteeId: string;\n\t\t\tnormalizedInviteeId: string;\n\t\t\tinviteeUsernameOnly: string;\n\t\t}[],\n\t\texternalRoomId: string,\n\t\tfederatedInviterUser: FederatedUser,\n\t): Promise {\n\t\tconst allInvitees = await Promise.all(\n\t\t\tallInviteesExternalIds.map(async (dmExternalInviteeId) => {\n\t\t\t\tconst invitee = await this.internalUserAdapter.getFederatedUserByExternalId(dmExternalInviteeId.externalInviteeId);\n\t\t\t\tif (!invitee) {\n\t\t\t\t\tconst isDMInviteeFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer(\n\t\t\t\t\t\tthis.bridge.extractHomeserverOrigin(dmExternalInviteeId.externalInviteeId),\n\t\t\t\t\t\tthis.internalHomeServerDomain,\n\t\t\t\t\t);\n\t\t\t\t\tconst dmInviteeUsername = isDMInviteeFromTheSameHomeServer\n\t\t\t\t\t\t? dmExternalInviteeId.inviteeUsernameOnly\n\t\t\t\t\t\t: dmExternalInviteeId.normalizedInviteeId;\n\t\t\t\t\tawait this.createFederatedUserInternallyOnly(\n\t\t\t\t\t\tdmExternalInviteeId.externalInviteeId,\n\t\t\t\t\t\tdmInviteeUsername,\n\t\t\t\t\t\tisDMInviteeFromTheSameHomeServer,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn (invitee ||\n\t\t\t\t\t(await this.internalUserAdapter.getFederatedUserByExternalId(dmExternalInviteeId.externalInviteeId))) as FederatedUser;\n\t\t\t}),\n\t\t);\n\t\tconst newFederatedRoom = DirectMessageFederatedRoom.createInstance(externalRoomId, federatedInviterUser, [\n\t\t\tfederatedInviterUser,\n\t\t\t...allInvitees,\n\t\t]);\n\t\tconst createdInternalRoomId = await this.internalRoomAdapter.createFederatedRoomForDirectMessage(newFederatedRoom);\n\t\tawait this.internalNotificationAdapter.subscribeToUserTypingEventsOnFederatedRoomId(\n\t\t\tcreatedInternalRoomId,\n\t\t\tthis.internalNotificationAdapter.broadcastUserTypingOnRoom.bind(this.internalNotificationAdapter),\n\t\t);\n\t\tawait Promise.all(\n\t\t\tallInvitees\n\t\t\t\t.filter((invitee) =>\n\t\t\t\t\tFederatedUser.isOriginalFromTheProxyServer(\n\t\t\t\t\t\tthis.bridge.extractHomeserverOrigin(invitee.getExternalId()),\n\t\t\t\t\t\tthis.internalHomeServerDomain,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.map((invitee) => this.bridge.joinRoom(externalRoomId, invitee.getExternalId())),\n\t\t);\n\t}\n\n\tprivate async handleDMRoomInviteWhenNotifiedByRegularEventsOnly(\n\t\tfederatedInviteeUser: FederatedUser,\n\t\tfederatedInviterUser: FederatedUser,\n\t\texternalRoomId: string,\n\t): Promise {\n\t\tconst members = [federatedInviterUser, federatedInviteeUser];\n\t\tconst newFederatedRoom = DirectMessageFederatedRoom.createInstance(externalRoomId, federatedInviterUser, members);\n\t\tconst createdInternalRoomId = await this.internalRoomAdapter.createFederatedRoomForDirectMessage(newFederatedRoom);\n\t\tconst isInviteeFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer(\n\t\t\tthis.bridge.extractHomeserverOrigin(federatedInviteeUser.getExternalId()),\n\t\t\tthis.internalHomeServerDomain,\n\t\t);\n\t\tawait this.internalNotificationAdapter.subscribeToUserTypingEventsOnFederatedRoomId(\n\t\t\tcreatedInternalRoomId,\n\t\t\tthis.internalNotificationAdapter.broadcastUserTypingOnRoom.bind(this.internalNotificationAdapter),\n\t\t);\n\t\tif (isInviteeFromTheSameHomeServer) {\n\t\t\tawait this.bridge.joinRoom(externalRoomId, federatedInviteeUser.getExternalId());\n\t\t}\n\t}\n\n\tpublic async onExternalMessageReceived(roomReceiveExternalMessageInput: FederationRoomReceiveExternalMessageDto): Promise {\n\t\tconst { externalRoomId, externalSenderId, rawMessage, externalFormattedText, externalEventId, replyToEventId } =\n\t\t\troomReceiveExternalMessageInput;\n\t\tconst federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId);\n\t\tif (!federatedRoom) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst senderUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId);\n\t\tif (!senderUser) {\n\t\t\treturn;\n\t\t}\n\t\tconst message = await this.internalMessageAdapter.getMessageByFederationId(externalEventId);\n\t\tif (message) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (replyToEventId) {\n\t\t\tconst messageToReplyTo = await this.internalMessageAdapter.getMessageByFederationId(replyToEventId);\n\t\t\tif (!messageToReplyTo) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait this.internalMessageAdapter.sendQuoteMessage(\n\t\t\t\tsenderUser,\n\t\t\t\tfederatedRoom,\n\t\t\t\texternalFormattedText,\n\t\t\t\trawMessage,\n\t\t\t\texternalEventId,\n\t\t\t\tmessageToReplyTo,\n\t\t\t\tthis.internalHomeServerDomain,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.internalMessageAdapter.sendMessage(\n\t\t\tsenderUser,\n\t\t\tfederatedRoom,\n\t\t\trawMessage,\n\t\t\texternalFormattedText,\n\t\t\texternalEventId,\n\t\t\tthis.internalHomeServerDomain,\n\t\t);\n\t}\n\n\tpublic async onExternalMessageEditedReceived(roomEditExternalMessageInput: FederationRoomEditExternalMessageDto): Promise {\n\t\tconst { externalRoomId, externalSenderId, editsEvent, newExternalFormattedText, newRawMessage } = roomEditExternalMessageInput;\n\n\t\tconst federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId);\n\t\tif (!federatedRoom) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst senderUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId);\n\t\tif (!senderUser) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst message = await this.internalMessageAdapter.getMessageByFederationId(editsEvent);\n\t\tif (!message) {\n\t\t\treturn;\n\t\t}\n\n\t\t// TODO: leaked business logic, move this to its proper place\n\t\tconst isAQuotedMessage = message.attachments?.some((attachment) => isQuoteAttachment(attachment) && Boolean(attachment.message_link));\n\t\tif (isAQuotedMessage) {\n\t\t\tconst wasGeneratedLocally = FederatedUser.isOriginalFromTheProxyServer(\n\t\t\t\tthis.bridge.extractHomeserverOrigin(externalSenderId),\n\t\t\t\tthis.internalHomeServerDomain,\n\t\t\t);\n\t\t\tif (wasGeneratedLocally) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst internalFormattedMessageToBeEdited = await this.internalMessageAdapter.getMessageToEditWhenReplyAndQuote(\n\t\t\t\tmessage,\n\t\t\t\tnewExternalFormattedText,\n\t\t\t\tnewRawMessage,\n\t\t\t\tthis.internalHomeServerDomain,\n\t\t\t\tsenderUser,\n\t\t\t);\n\t\t\t// TODO: create an entity to abstract all the message logic\n\t\t\tif (!FederatedRoom.shouldUpdateMessage(internalFormattedMessageToBeEdited, message)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait this.internalMessageAdapter.editQuotedMessage(\n\t\t\t\tsenderUser,\n\t\t\t\tnewRawMessage,\n\t\t\t\tnewExternalFormattedText,\n\t\t\t\tmessage,\n\t\t\t\tthis.internalHomeServerDomain,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tif (!FederatedRoom.shouldUpdateMessage(newRawMessage, message)) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.internalMessageAdapter.editMessage(\n\t\t\tsenderUser,\n\t\t\tnewRawMessage,\n\t\t\tnewExternalFormattedText,\n\t\t\tmessage,\n\t\t\tthis.internalHomeServerDomain,\n\t\t);\n\t}\n\n\tpublic async onExternalFileMessageReceived(roomReceiveExternalMessageInput: FederationRoomReceiveExternalFileMessageDto): Promise {\n\t\tconst { externalRoomId, externalSenderId, messageBody, externalEventId, replyToEventId } = roomReceiveExternalMessageInput;\n\n\t\tconst federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId);\n\t\tif (!federatedRoom) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst senderUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId);\n\t\tif (!senderUser) {\n\t\t\treturn;\n\t\t}\n\t\tconst message = await this.internalMessageAdapter.getMessageByFederationId(externalEventId);\n\t\tif (message) {\n\t\t\treturn;\n\t\t}\n\t\tconst fileDetails = {\n\t\t\tname: messageBody.filename,\n\t\t\tsize: messageBody.size,\n\t\t\ttype: messageBody.mimetype,\n\t\t\trid: federatedRoom.getInternalId(),\n\t\t\tuserId: senderUser.getInternalId(),\n\t\t};\n\t\tconst readableStream = await this.bridge.getReadStreamForFileFromUrl(senderUser.getExternalId(), messageBody.url);\n\t\tconst { files = [], attachments } = await this.internalFileAdapter.uploadFile(\n\t\t\treadableStream,\n\t\t\tfederatedRoom.getInternalId(),\n\t\t\tsenderUser.getInternalReference(),\n\t\t\tfileDetails,\n\t\t);\n\n\t\tif (replyToEventId) {\n\t\t\tconst messageToReplyTo = await this.internalMessageAdapter.getMessageByFederationId(replyToEventId);\n\t\t\tif (!messageToReplyTo) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait this.internalMessageAdapter.sendQuoteFileMessage(\n\t\t\t\tsenderUser,\n\t\t\t\tfederatedRoom,\n\t\t\t\tfiles,\n\t\t\t\tattachments,\n\t\t\t\texternalEventId,\n\t\t\t\tmessageToReplyTo,\n\t\t\t\tthis.internalHomeServerDomain,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.internalMessageAdapter.sendFileMessage(senderUser, federatedRoom, files, attachments, externalEventId);\n\t}\n\n\tpublic async onChangeJoinRules(roomJoinRulesChangeInput: FederationRoomChangeJoinRulesDto): Promise {\n\t\tconst { externalRoomId, roomType } = roomJoinRulesChangeInput;\n\n\t\tconst federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId);\n\t\tif (!federatedRoom) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst notAllowedChangeJoinRules = federatedRoom.isDirectMessage();\n\t\tif (notAllowedChangeJoinRules) {\n\t\t\treturn;\n\t\t}\n\n\t\tfederatedRoom.changeRoomType(roomType);\n\t\tawait this.internalRoomAdapter.updateRoomType(federatedRoom);\n\t}\n\n\tpublic async onChangeRoomName(roomChangeNameInput: FederationRoomChangeNameDto): Promise {\n\t\tconst { externalRoomId, normalizedRoomName, externalSenderId } = roomChangeNameInput;\n\t\tconst federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId);\n\t\tif (!federatedRoom) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst federatedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId);\n\t\tif (!federatedUser) {\n\t\t\treturn;\n\t\t}\n\t\tconst shouldUseExternalRoomIdAsRoomName = !FederatedRoom.isOriginalFromTheProxyServer(\n\t\t\tthis.bridge.extractHomeserverOrigin(externalRoomId),\n\t\t\tthis.internalHomeServerDomain,\n\t\t);\n\t\tif (shouldUseExternalRoomIdAsRoomName) {\n\t\t\tfederatedRoom.changeRoomName(externalRoomId);\n\t\t\tawait this.internalRoomAdapter.updateRoomName(federatedRoom);\n\t\t}\n\t\tif (!federatedRoom.shouldUpdateDisplayRoomName(normalizedRoomName)) {\n\t\t\treturn;\n\t\t}\n\n\t\tfederatedRoom.changeDisplayRoomName(normalizedRoomName);\n\n\t\tawait this.internalRoomAdapter.updateDisplayRoomName(federatedRoom, federatedUser);\n\t}\n\n\tpublic async onChangeRoomTopic(roomChangeTopicInput: FederationRoomChangeTopicDto): Promise {\n\t\tconst { externalRoomId, roomTopic, externalSenderId } = roomChangeTopicInput;\n\n\t\tconst federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId);\n\t\tif (!federatedRoom) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!federatedRoom.shouldUpdateRoomTopic(roomTopic)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst federatedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId);\n\t\tif (!federatedUser) {\n\t\t\treturn;\n\t\t}\n\n\t\tfederatedRoom.changeRoomTopic(roomTopic);\n\n\t\tawait this.internalRoomAdapter.updateRoomTopic(federatedRoom, federatedUser);\n\t}\n\n\tpublic async onRedactEvent(roomRedactEventInput: FederationRoomRedactEventDto): Promise {\n\t\tconst { externalRoomId, redactsEvent, externalSenderId } = roomRedactEventInput;\n\n\t\tconst federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId);\n\t\tif (!federatedRoom) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst federatedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId);\n\t\tif (!federatedUser) {\n\t\t\treturn;\n\t\t}\n\t\tconst handler = await getRedactMessageHandler(this.internalMessageAdapter, redactsEvent, federatedUser);\n\t\tif (!handler) {\n\t\t\treturn;\n\t\t}\n\t\tawait handler.handle();\n\t}\n\n\tpublic async onChangeRoomPowerLevels(roomPowerLevelsInput: FederationRoomRoomChangePowerLevelsEventDto): Promise {\n\t\tconst { externalRoomId, roleChangesToApply = {}, externalSenderId } = roomPowerLevelsInput;\n\n\t\tconst federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId);\n\t\tif (!federatedRoom) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst federatedUserWhoChangedThePermission = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId);\n\t\tif (!federatedUserWhoChangedThePermission) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst federatedUsers = await this.internalUserAdapter.getFederatedUsersByExternalIds(Object.keys(roleChangesToApply));\n\n\t\tawait Promise.all(\n\t\t\tfederatedUsers.map((targetFederatedUser) => {\n\t\t\t\tconst changes = roleChangesToApply[targetFederatedUser.getExternalId()];\n\t\t\t\tif (!changes) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst rolesToRemove = changes.filter((change) => change.action === 'remove').map((change) => change.role);\n\t\t\t\tconst rolesToAdd = changes.filter((change) => change.action === 'add').map((change) => change.role);\n\n\t\t\t\treturn this.internalRoomAdapter.applyRoomRolesToUser({\n\t\t\t\t\tfederatedRoom,\n\t\t\t\t\ttargetFederatedUser,\n\t\t\t\t\tfromUser: federatedUserWhoChangedThePermission,\n\t\t\t\t\trolesToAdd,\n\t\t\t\t\trolesToRemove,\n\t\t\t\t\tnotifyChannel: true,\n\t\t\t\t});\n\t\t\t}),\n\t\t);\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/UserServiceListener.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/input/MessageReceiverDto.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/input/RoomReceiverDto.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/listener/input/UserReceiverDto.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/sender/MessageSenders.ts",["22947","22948"],[],"import type { IMessage } from '@rocket.chat/core-typings';\n\nimport type { IFederationBridge } from '../../domain/IFederationBridge';\nimport type { RocketChatFileAdapter } from '../../infrastructure/rocket-chat/adapters/File';\nimport type { RocketChatMessageAdapter } from '../../infrastructure/rocket-chat/adapters/Message';\nimport type { RocketChatUserAdapter } from '../../infrastructure/rocket-chat/adapters/User';\n\nexport interface IExternalMessageSender {\n\tsendMessage(externalRoomId: string, externalSenderId: string, message: IMessage): Promise;\n\tsendQuoteMessage(externalRoomId: string, externalSenderId: string, message: IMessage, messageToReplyTo: IMessage): Promise;\n}\n\nclass TextExternalMessageSender implements IExternalMessageSender {\n\tconstructor(\n\t\tprivate readonly bridge: IFederationBridge,\n\t\tprivate readonly internalMessageAdapter: RocketChatMessageAdapter,\n\t\tprivate readonly internalUserAdapter: RocketChatUserAdapter,\n\t) {}\n\n\tpublic async sendMessage(externalRoomId: string, externalSenderId: string, message: IMessage): Promise {\n\t\tconst externalMessageId = await this.bridge.sendMessage(externalRoomId, externalSenderId, message);\n\n\t\tawait this.internalMessageAdapter.setExternalFederationEventOnMessage(message._id, externalMessageId);\n\t}\n\n\tpublic async sendQuoteMessage(\n\t\texternalRoomId: string,\n\t\texternalSenderId: string,\n\t\tmessage: IMessage,\n\t\tmessageToReplyTo: IMessage,\n\t): Promise {\n\t\tconst originalSender = await this.internalUserAdapter.getFederatedUserByInternalId(messageToReplyTo?.u?._id);\n\t\tconst externalMessageId = await this.bridge.sendReplyToMessage(\n\t\t\texternalRoomId,\n\t\t\texternalSenderId,\n\t\t\tmessageToReplyTo.federation?.eventId as string,\n\t\t\toriginalSender?.getExternalId() as string,\n\t\t\tmessage.msg,\n\t\t);\n\t\tawait this.internalMessageAdapter.setExternalFederationEventOnMessage(message._id, externalMessageId);\n\t}\n}\n\nclass FileExternalMessageSender implements IExternalMessageSender {\n\tconstructor(\n\t\tprivate readonly bridge: IFederationBridge,\n\t\tprivate readonly internalFileHelper: RocketChatFileAdapter,\n\t\tprivate readonly internalMessageAdapter: RocketChatMessageAdapter,\n\t) {}\n\n\tpublic async sendMessage(externalRoomId: string, externalSenderId: string, message: IMessage): Promise {\n\t\tconst file = await this.internalFileHelper.getFileRecordById((message.files || [])[0]?._id);\n\t\tif (!file || !file.size || !file.type) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst buffer = await this.internalFileHelper.getBufferFromFileRecord(file);\n\t\tconst metadata = await this.internalFileHelper.extractMetadataFromFile(file);\n\n\t\tconst externalMessageId = await this.bridge.sendMessageFileToRoom(externalRoomId, externalSenderId, buffer, {\n\t\t\tfilename: file.name,\n\t\t\tfileSize: file.size,\n\t\t\tmimeType: file.type,\n\t\t\tmetadata: {\n\t\t\t\twidth: metadata?.width,\n\t\t\t\theight: metadata?.height,\n\t\t\t\tformat: metadata?.format,\n\t\t\t},\n\t\t});\n\n\t\tawait this.internalMessageAdapter.setExternalFederationEventOnMessage(message._id, externalMessageId);\n\t}\n\n\tpublic async sendQuoteMessage(\n\t\texternalRoomId: string,\n\t\texternalSenderId: string,\n\t\tmessage: IMessage,\n\t\tmessageToReplyTo: IMessage,\n\t): Promise {\n\t\tconst file = await this.internalFileHelper.getFileRecordById((message.files || [])[0]?._id);\n\t\tif (!file || !file.size || !file.type) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst buffer = await this.internalFileHelper.getBufferFromFileRecord(file);\n\t\tconst metadata = await this.internalFileHelper.extractMetadataFromFile(file);\n\n\t\tconst externalMessageId = await this.bridge.sendReplyMessageFileToRoom(\n\t\t\texternalRoomId,\n\t\t\texternalSenderId,\n\t\t\tbuffer,\n\t\t\t{\n\t\t\t\tfilename: file.name,\n\t\t\t\tfileSize: file.size,\n\t\t\t\tmimeType: file.type,\n\t\t\t\tmetadata: {\n\t\t\t\t\twidth: metadata?.width,\n\t\t\t\t\theight: metadata?.height,\n\t\t\t\t\tformat: metadata?.format,\n\t\t\t\t},\n\t\t\t},\n\t\t\tmessageToReplyTo.federation?.eventId as string,\n\t\t);\n\n\t\tawait this.internalMessageAdapter.setExternalFederationEventOnMessage(message._id, externalMessageId);\n\t}\n}\n\nexport const getExternalMessageSender = (\n\tmessage: IMessage,\n\tbridge: IFederationBridge,\n\tinternalFileHelper: RocketChatFileAdapter,\n\tinternalMessageAdapter: RocketChatMessageAdapter,\n\tinternalUserAdapter: RocketChatUserAdapter,\n): IExternalMessageSender => {\n\treturn message.files\n\t\t? new FileExternalMessageSender(bridge, internalFileHelper, internalMessageAdapter)\n\t\t: new TextExternalMessageSender(bridge, internalMessageAdapter, internalUserAdapter);\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/sender/MessageServiceSender.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/sender/RoomInternalHooksValidator.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/sender/RoomServiceSender.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/sender/UserServiceSender.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/application/sender/input/RoomSenderDto.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/domain/FederatedRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/domain/FederatedUser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/domain/IFederationBridge.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/Factory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/Bridge.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/MessageReceiver.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/MessageTextParser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/RoomReceiver.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/UserReceiver.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/AbstractMatrixEvent.ts",[],["22949"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixEventType.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixPowerLevels.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomJoinRules.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomType.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomVisibility.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/MessageReacted.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomCreated.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomEventRedacted.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomJoinRulesChanged.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomMembershipChanged.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomMessageSent.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomNameChanged.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomPowerLevelsChanged.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomTopicChanged.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/UserTypingStatusChanged.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/BaseEvent.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/Message.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/Room.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/User.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/queue/InMemoryQueue.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/File.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Message.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/MessageConverter.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Notification.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Room.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/User.ts",["22950"],[],"import { Meteor } from 'meteor/meteor';\nimport type { IUser } from '@rocket.chat/core-typings';\nimport { Users, MatrixBridgedUser } from '@rocket.chat/models';\n\nimport { setUserAvatar, _setRealName as setRealName } from '../../../../../lib/server';\nimport { FederatedUser } from '../../../domain/FederatedUser';\n\nconst createFederatedUserInstance = (externalUserId: string, user: IUser, remote = true): FederatedUser => {\n\tconst federatedUser = FederatedUser.createWithInternalReference(externalUserId, !remote, user);\n\n\treturn federatedUser;\n};\n\nexport const getFederatedUserByInternalUsername = async (username: string): Promise => {\n\tconst user = await Users.findOneByUsername(username);\n\tif (!user) {\n\t\treturn;\n\t}\n\tconst internalBridgedUser = await MatrixBridgedUser.getBridgedUserByLocalId(user._id);\n\tif (!internalBridgedUser) {\n\t\treturn;\n\t}\n\tconst { mui: externalUserId, remote } = internalBridgedUser;\n\n\treturn createFederatedUserInstance(externalUserId, user, remote);\n};\n\nexport class RocketChatUserAdapter {\n\tpublic async getFederatedUserByExternalId(externalUserId: string): Promise {\n\t\tconst internalBridgedUser = await MatrixBridgedUser.getBridgedUserByExternalUserId(externalUserId);\n\t\tif (!internalBridgedUser) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst user = await Users.findOneById(internalBridgedUser.uid);\n\n\t\tif (user) {\n\t\t\treturn createFederatedUserInstance(externalUserId, user, internalBridgedUser.remote);\n\t\t}\n\t}\n\n\tpublic async getFederatedUsersByExternalIds(externalUserIds: string[]): Promise {\n\t\tconst internalBridgedUsers = await MatrixBridgedUser.getLocalUsersByExternalIds(externalUserIds);\n\t\tif (internalBridgedUsers.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst internalUserIds = internalBridgedUsers.map((bridgedUser) => bridgedUser.uid);\n\t\tconst internalUserIdsMap: Record> = internalBridgedUsers.reduce(\n\t\t\t(acc, bridgedUser) => ({ ...acc, [bridgedUser.uid]: { mui: bridgedUser.mui, remote: bridgedUser.remote } }),\n\t\t\t{},\n\t\t);\n\t\tconst users = await Users.findByIds(internalUserIds).toArray();\n\n\t\tif (users.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\treturn users.map((user) => createFederatedUserInstance(internalUserIdsMap[user._id].mui, user, internalUserIdsMap[user._id].remote));\n\t}\n\n\tpublic async getFederatedUserByInternalId(internalUserId: string): Promise {\n\t\tconst internalBridgedUser = await MatrixBridgedUser.getBridgedUserByLocalId(internalUserId);\n\t\tif (!internalBridgedUser) {\n\t\t\treturn;\n\t\t}\n\t\tconst { uid: userId, mui: externalUserId, remote } = internalBridgedUser;\n\t\tconst user = await Users.findOneById(userId);\n\n\t\tif (user) {\n\t\t\treturn createFederatedUserInstance(externalUserId, user, remote);\n\t\t}\n\t}\n\n\tpublic async getFederatedUserByInternalUsername(username: string): Promise {\n\t\tconst user = await Users.findOneByUsername(username);\n\t\tif (!user) {\n\t\t\treturn;\n\t\t}\n\t\tconst internalBridgedUser = await MatrixBridgedUser.getBridgedUserByLocalId(user._id);\n\t\tif (!internalBridgedUser) {\n\t\t\treturn;\n\t\t}\n\t\tconst { mui: externalUserId, remote } = internalBridgedUser;\n\n\t\treturn createFederatedUserInstance(externalUserId, user, remote);\n\t}\n\n\tpublic async getInternalUserById(userId: string): Promise {\n\t\tconst user = await Users.findOneById(userId);\n\t\tif (!user || !user.username) {\n\t\t\tthrow new Error(`User with internalId ${userId} not found`);\n\t\t}\n\t\treturn user;\n\t}\n\n\tpublic async getInternalUserByUsername(username: string): Promise {\n\t\treturn Users.findOneByUsername(username);\n\t}\n\n\tpublic async createFederatedUser(federatedUser: FederatedUser): Promise {\n\t\tconst existingLocalUser = federatedUser.getUsername() && (await Users.findOneByUsername(federatedUser.getUsername() as string));\n\t\tif (existingLocalUser) {\n\t\t\treturn MatrixBridgedUser.createOrUpdateByLocalId(existingLocalUser._id, federatedUser.getExternalId(), federatedUser.isRemote());\n\t\t}\n\t\tconst { insertedId } = await Users.insertOne(federatedUser.getStorageRepresentation());\n\t\treturn MatrixBridgedUser.createOrUpdateByLocalId(insertedId, federatedUser.getExternalId(), federatedUser.isRemote());\n\t}\n\n\tpublic async setAvatar(federatedUser: FederatedUser, avatarUrl: string): Promise {\n\t\tMeteor.runAsUser(federatedUser.getInternalId(), () => {\n\t\t\tsetUserAvatar(federatedUser.getInternalReference(), avatarUrl, 'image/jpeg', 'url'); // this mimetype is fixed here, but the function when called with a url as source don't use that mimetype\n\t\t});\n\t}\n\n\tpublic async updateFederationAvatar(internalUserId: string, externalAvatarUrl: string): Promise {\n\t\tawait Users.setFederationAvatarUrlById(internalUserId, externalAvatarUrl);\n\t}\n\n\tpublic async updateRealName(internalUser: IUser, name: string): Promise {\n\t\tsetRealName(internalUser._id, name, internalUser);\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/logger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/MessageTextParser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/definitions/InternalFederatedRoomRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/hooks/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/slash-commands/action.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/slash-commands/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/statistics.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file/server/file.server.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/client/lib/fileUploadHandler.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/lib/FileUploadBase.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/config/AmazonS3.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/config/FileSystem.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/config/GoogleStorage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/config/GridFS.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/config/Webdav.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/config/_configUploadStorage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/lib/FileUpload.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/lib/proxy.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/lib/ranges.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/lib/requests.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/lib/streamToBuffer.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/methods/getS3FileUrl.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/methods/sendFileMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/server/startup/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/ufs/AmazonS3/server.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/ufs/GoogleStorage/server.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/file-upload/ufs/Webdav/server.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/github-enterprise/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/github-enterprise/lib/common.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/github-enterprise/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/github-enterprise/server/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/gitlab/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/gitlab/lib/common.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/gitlab/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/gitlab/server/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/google-oauth/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/highlight-words/client/client.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/highlight-words/client/helper.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/highlight-words/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/highlight-words/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/iframe-login/client/iframe_client.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/iframe-login/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/iframe-login/server/iframe_rocketchat.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/iframe-login/server/iframe_server.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/iframe-login/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/lib/ImporterInfo.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/lib/ImporterProgressStep.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/lib/Importers.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImportDataConverter.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImporterBase.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImporterProgress.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImporterSelection.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImporterSelectionChannel.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImporterSelectionUser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/ImporterWebsocket.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/classes/VirtualDataConverter.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/definitions/IConversionCallbacks.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/downloadPublicImportFile.ts",[],["22951"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/getImportFileData.ts",[],["22952"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/getImportProgress.ts",[],["22953"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/getLatestImportOperations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/startImport.ts",[],["22954"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/methods/uploadImportFile.ts",[],["22955"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/models/RawImports.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/startup/setImportsToInvalid.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer/server/startup/store.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-csv/client/adder.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-csv/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-csv/lib/info.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-csv/server/importer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-csv/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-hipchat-enterprise/client/adder.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-hipchat-enterprise/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-hipchat-enterprise/lib/info.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-hipchat-enterprise/server/importer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-hipchat-enterprise/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-pending-avatars/server/importer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-pending-avatars/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-pending-avatars/server/info.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-pending-files/server/importer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-pending-files/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-pending-files/server/info.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack/client/adder.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack/lib/info.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack/server/importer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack-users/client/adder.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack-users/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack-users/lib/info.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack-users/server/importer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/importer-slack-users/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/client/streamer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/lib/outgoingEvents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/api/api.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/lib/mountQueriesBasedOnPermission.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/lib/triggerHandler.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/lib/validateOutgoingIntegration.ts",["22956"],[],"import { Meteor } from 'meteor/meteor';\nimport { Match } from 'meteor/check';\nimport { Babel } from 'meteor/babel-compiler';\nimport _ from 'underscore';\nimport type { IUser, INewOutgoingIntegration, IOutgoingIntegration, IUpdateOutgoingIntegration } from '@rocket.chat/core-typings';\n\nimport { Rooms, Users, Subscriptions } from '../../../models/server';\nimport { hasPermission, hasAllPermission } from '../../../authorization/server';\nimport { outgoingEvents } from '../../lib/outgoingEvents';\nimport { parseCSV } from '../../../../lib/utils/parseCSV';\n\nconst scopedChannels = ['all_public_channels', 'all_private_groups', 'all_direct_messages'];\nconst validChannelChars = ['@', '#'];\n\nfunction _verifyRequiredFields(integration: INewOutgoingIntegration | IUpdateOutgoingIntegration): void {\n\tif (\n\t\t!integration.event ||\n\t\t!Match.test(integration.event, String) ||\n\t\tintegration.event.trim() === '' ||\n\t\t!outgoingEvents[integration.event]\n\t) {\n\t\tthrow new Meteor.Error('error-invalid-event-type', 'Invalid event type', {\n\t\t\tfunction: 'validateOutgoing._verifyRequiredFields',\n\t\t});\n\t}\n\n\tif (!integration.username || !Match.test(integration.username, String) || integration.username.trim() === '') {\n\t\tthrow new Meteor.Error('error-invalid-username', 'Invalid username', {\n\t\t\tfunction: 'validateOutgoing._verifyRequiredFields',\n\t\t});\n\t}\n\n\tif (outgoingEvents[integration.event].use.targetRoom && !integration.targetRoom) {\n\t\tthrow new Meteor.Error('error-invalid-targetRoom', 'Invalid Target Room', {\n\t\t\tfunction: 'validateOutgoing._verifyRequiredFields',\n\t\t});\n\t}\n\n\tif (!Match.test(integration.urls, [String])) {\n\t\tthrow new Meteor.Error('error-invalid-urls', 'Invalid URLs', {\n\t\t\tfunction: 'validateOutgoing._verifyRequiredFields',\n\t\t});\n\t}\n\n\tintegration.urls = integration.urls.filter((url) => url && url.trim() !== '');\n\n\tif (integration.urls.length === 0) {\n\t\tthrow new Meteor.Error('error-invalid-urls', 'Invalid URLs', {\n\t\t\tfunction: 'validateOutgoing._verifyRequiredFields',\n\t\t});\n\t}\n}\n\nfunction _verifyUserHasPermissionForChannels(userId: IUser['_id'], channels: string[]): void {\n\tfor (let channel of channels) {\n\t\tif (scopedChannels.includes(channel)) {\n\t\t\tif (channel === 'all_public_channels') {\n\t\t\t\t// No special permissions needed to add integration to public channels\n\t\t\t} else if (!hasPermission(userId, 'manage-outgoing-integrations')) {\n\t\t\t\tthrow new Meteor.Error('error-invalid-channel', 'Invalid Channel', {\n\t\t\t\t\tfunction: 'validateOutgoing._verifyUserHasPermissionForChannels',\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tlet record;\n\t\t\tconst channelType = channel[0];\n\t\t\tchannel = channel.substr(1);\n\n\t\t\tswitch (channelType) {\n\t\t\t\tcase '#':\n\t\t\t\t\trecord = Rooms.findOne({\n\t\t\t\t\t\t$or: [{ _id: channel }, { name: channel }],\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\tcase '@':\n\t\t\t\t\trecord = Users.findOne({\n\t\t\t\t\t\t$or: [{ _id: channel }, { username: channel }],\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (!record) {\n\t\t\t\tthrow new Meteor.Error('error-invalid-room', 'Invalid room', {\n\t\t\t\t\tfunction: 'validateOutgoing._verifyUserHasPermissionForChannels',\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t!hasAllPermission(userId, ['manage-outgoing-integrations', 'manage-own-outgoing-integrations']) &&\n\t\t\t\t!Subscriptions.findOneByRoomIdAndUserId(record._id, userId, { fields: { _id: 1 } })\n\t\t\t) {\n\t\t\t\tthrow new Meteor.Error('error-invalid-channel', 'Invalid Channel', {\n\t\t\t\t\tfunction: 'validateOutgoing._verifyUserHasPermissionForChannels',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction _verifyRetryInformation(integration: IOutgoingIntegration): void {\n\tif (!integration.retryFailedCalls) {\n\t\treturn;\n\t}\n\n\t// Don't allow negative retry counts\n\tintegration.retryCount =\n\t\tintegration.retryCount && parseInt(String(integration.retryCount)) > 0 ? parseInt(String(integration.retryCount)) : 4;\n\tintegration.retryDelay =\n\t\t!integration.retryDelay || !integration.retryDelay.trim() ? 'powers-of-ten' : integration.retryDelay.toLowerCase();\n}\n\nexport const validateOutgoingIntegration = function (\n\tintegration: INewOutgoingIntegration | IUpdateOutgoingIntegration,\n\tuserId: IUser['_id'],\n): IOutgoingIntegration {\n\tif (integration.channel && Match.test(integration.channel, String) && integration.channel.trim() === '') {\n\t\tdelete integration.channel;\n\t}\n\n\t// Moved to it's own function to statisfy the complexity rule\n\t_verifyRequiredFields(integration);\n\n\tlet channels: string[] = [];\n\tif (outgoingEvents[integration.event].use.channel) {\n\t\tif (!Match.test(integration.channel, String)) {\n\t\t\tthrow new Meteor.Error('error-invalid-channel', 'Invalid Channel', {\n\t\t\t\tfunction: 'validateOutgoing',\n\t\t\t});\n\t\t} else {\n\t\t\tchannels = parseCSV(integration.channel);\n\n\t\t\tfor (const channel of channels) {\n\t\t\t\tif (!validChannelChars.includes(channel[0]) && !scopedChannels.includes(channel.toLowerCase())) {\n\t\t\t\t\tthrow new Meteor.Error('error-invalid-channel-start-with-chars', 'Invalid channel. Start with @ or #', {\n\t\t\t\t\t\tfunction: 'validateOutgoing',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else if (!hasPermission(userId, 'manage-outgoing-integrations')) {\n\t\tthrow new Meteor.Error('error-invalid-permissions', 'Invalid permission for required Integration creation.', {\n\t\t\tfunction: 'validateOutgoing',\n\t\t});\n\t}\n\n\tconst user = Users.findOne({ username: integration.username });\n\n\tif (!user) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user (did you delete the `rocket.cat` user?)', { function: 'validateOutgoing' });\n\t}\n\n\tconst integrationData: IOutgoingIntegration = {\n\t\t...integration,\n\t\ttype: 'webhook-outgoing',\n\t\tchannel: channels,\n\t\tuserId: user._id,\n\t\t_createdAt: new Date(),\n\t\t_createdBy: Users.findOne(userId, { fields: { username: 1 } }),\n\t};\n\n\tif (outgoingEvents[integration.event].use.triggerWords && integration.triggerWords) {\n\t\tif (!Match.test(integration.triggerWords, [String])) {\n\t\t\tthrow new Meteor.Error('error-invalid-triggerWords', 'Invalid triggerWords', {\n\t\t\t\tfunction: 'validateOutgoing',\n\t\t\t});\n\t\t}\n\n\t\tintegrationData.triggerWords = integration.triggerWords.filter((word) => word && word.trim() !== '');\n\t} else {\n\t\tdelete integrationData.triggerWords;\n\t}\n\n\tif (integration.scriptEnabled === true && integration.script && integration.script.trim() !== '') {\n\t\ttry {\n\t\t\tconst babelOptions = Object.assign(Babel.getDefaultOptions({ runtime: false }), {\n\t\t\t\tcompact: true,\n\t\t\t\tminified: true,\n\t\t\t\tcomments: false,\n\t\t\t});\n\n\t\t\tintegrationData.scriptCompiled = Babel.compile(integration.script, babelOptions).code;\n\t\t\tintegrationData.scriptError = undefined;\n\t\t} catch (e) {\n\t\t\tintegrationData.scriptCompiled = undefined;\n\t\t\tintegrationData.scriptError = e instanceof Error ? _.pick(e, 'name', 'message', 'stack') : undefined;\n\t\t}\n\t}\n\n\tif (typeof integration.runOnEdits !== 'undefined') {\n\t\t// Verify this value is only true/false\n\t\tintegrationData.runOnEdits = integration.runOnEdits === true;\n\t}\n\n\t_verifyUserHasPermissionForChannels(userId, channels);\n\t_verifyRetryInformation(integrationData);\n\n\treturn integrationData;\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/logger.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/clearIntegrationHistory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/incoming/addIncomingIntegration.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/incoming/deleteIncomingIntegration.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/outgoing/addOutgoingIntegration.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/outgoing/deleteOutgoingIntegration.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/outgoing/replayOutgoingIntegration.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/methods/outgoing/updateOutgoingIntegration.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/integrations/server/triggers.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/invites/server/functions/findOrCreateInvite.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/invites/server/functions/listInvites.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/invites/server/functions/removeInvite.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/invites/server/functions/sendInvitationEmail.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/invites/server/functions/useInviteToken.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/invites/server/functions/validateInviteToken.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onCreateRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onCreateUser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onJoinRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onLeaveRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onLogin.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onLogout.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/localHandlers/onSaveMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/disconnected.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/joinedChannel.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/leftChannel.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/nickChanged.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/sentMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-bridge/peerHandlers/userRegistered.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc-settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/irc.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/methods/resetIrcConnection.ts",[],["22957"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/servers/RFC2813/codes.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/servers/RFC2813/index.js",[],["22958"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/servers/RFC2813/localCommandHandlers.js",[],["22959"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/servers/RFC2813/parseMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/servers/RFC2813/peerCommandHandlers.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/irc/server/servers/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/katex/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/katex/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/katex/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/OAuthProxy.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/lib/LoginPresence.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/lib/RocketChatAnnouncement.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/lib/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/methods/sendMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/startup/settingsOnLoadSiteUrl.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/client/views/customFieldsForm.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/lib/MessageTypes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/addOAuthService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/addUserToDefaultChannels.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/addUserToRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/archiveRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/attachMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/checkEmailAvailability.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/checkUsernameAvailability.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/cleanRoomHistory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/closeOmnichannelConversations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/createDirectRoom.ts",[],["22960","22961","22962","22963","22964","22965","22966"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/createRoom.ts",["22967"],[],"import { AppsEngineException } from '@rocket.chat/apps-engine/definition/exceptions';\nimport { Meteor } from 'meteor/meteor';\nimport _ from 'underscore';\nimport type { ICreatedRoom, IUser, IRoom, RoomType } from '@rocket.chat/core-typings';\nimport { Team } from '@rocket.chat/core-services';\nimport type { ICreateRoomParams, ISubscriptionExtraData } from '@rocket.chat/core-services';\n\nimport { Apps } from '../../../../ee/server/apps';\nimport { addUserRoles } from '../../../../server/lib/roles/addUserRoles';\nimport { callbacks } from '../../../../lib/callbacks';\nimport { Messages, Rooms, Subscriptions, Users } from '../../../models/server';\nimport { getValidRoomName } from '../../../utils/server';\nimport { createDirectRoom } from './createDirectRoom';\n\nconst isValidName = (name: unknown): name is string => {\n\treturn typeof name === 'string' && name.trim().length > 0;\n};\n\nexport const createRoom = function (\n\ttype: T,\n\tname: T extends 'd' ? undefined : string,\n\townerUsername: string,\n\tmembers: T extends 'd' ? IUser[] : string[] = [],\n\treadOnly?: boolean,\n\troomExtraData?: Partial,\n\toptions?: ICreateRoomParams['options'],\n): ICreatedRoom {\n\tconst { teamId, ...extraData } = roomExtraData || ({} as IRoom);\n\tcallbacks.run('beforeCreateRoom', { type, name, owner: ownerUsername, members, readOnly, extraData, options });\n\n\tif (type === 'd') {\n\t\treturn createDirectRoom(members as IUser[], extraData, { ...options, creator: options?.creator || ownerUsername });\n\t}\n\n\tif (!isValidName(name)) {\n\t\tthrow new Meteor.Error('error-invalid-name', 'Invalid name', {\n\t\t\tfunction: 'RocketChat.createRoom',\n\t\t});\n\t}\n\n\tconst owner = Users.findOneByUsernameIgnoringCase(ownerUsername, { fields: { username: 1 } });\n\n\tif (!owner) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\tfunction: 'RocketChat.createRoom',\n\t\t});\n\t}\n\n\tif (!_.contains(members, owner)) {\n\t\tmembers.push(owner.username);\n\t}\n\n\tif (extraData.broadcast) {\n\t\treadOnly = true;\n\t\tdelete extraData.reactWhenReadOnly;\n\t}\n\n\tconst now = new Date();\n\n\tconst roomProps: Omit = {\n\t\tfname: name,\n\t\t...extraData,\n\t\tname: getValidRoomName(name.trim(), undefined, {\n\t\t\t...(options?.nameValidationRegex && { nameValidationRegex: options.nameValidationRegex }),\n\t\t}),\n\t\tt: type,\n\t\tmsgs: 0,\n\t\tusersCount: 0,\n\t\tu: {\n\t\t\t_id: owner._id,\n\t\t\tusername: owner.username,\n\t\t},\n\t\tts: now,\n\t\tro: readOnly === true,\n\t};\n\n\tif (teamId) {\n\t\tconst team = Promise.await(Team.getOneById(teamId, { projection: { _id: 1 } }));\n\t\tif (team) {\n\t\t\troomProps.teamId = team._id;\n\t\t}\n\t}\n\n\tconst tmp = {\n\t\t...roomProps,\n\t\t_USERNAMES: members,\n\t};\n\n\tconst prevent = Promise.await(\n\t\tApps.triggerEvent('IPreRoomCreatePrevent', tmp).catch((error) => {\n\t\t\tif (error instanceof AppsEngineException) {\n\t\t\t\tthrow new Meteor.Error('error-app-prevented', error.message);\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}),\n\t);\n\n\tif (prevent) {\n\t\tthrow new Meteor.Error('error-app-prevented', 'A Rocket.Chat App prevented the room creation.');\n\t}\n\n\tconst eventResult = Promise.await(\n\t\tApps.triggerEvent('IPreRoomCreateModify', Promise.await(Apps.triggerEvent('IPreRoomCreateExtend', tmp))),\n\t);\n\n\tif (eventResult && typeof eventResult === 'object' && delete eventResult._USERNAMES) {\n\t\tObject.assign(roomProps, eventResult);\n\t}\n\n\tif (type === 'c') {\n\t\tcallbacks.run('beforeCreateChannel', owner, roomProps);\n\t}\n\tconst room = Rooms.createWithFullRoomData(roomProps);\n\tconst shouldBeHandledByFederation = room.federated === true || ownerUsername.includes(':');\n\tif (shouldBeHandledByFederation) {\n\t\tconst extra: Partial = options?.subscriptionExtra || {};\n\t\textra.open = true;\n\t\textra.ls = now;\n\n\t\tif (room.prid) {\n\t\t\textra.prid = room.prid;\n\t\t}\n\n\t\tSubscriptions.createWithRoomAndUser(room, owner, extra);\n\t} else {\n\t\tfor (const username of [...new Set(members as string[])]) {\n\t\t\tconst member = Users.findOneByUsername(username, {\n\t\t\t\tfields: { 'username': 1, 'settings.preferences': 1, 'federated': 1 },\n\t\t\t});\n\t\t\tif (!member) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcallbacks.run('federation.beforeAddUserToARoom', { user: member, inviter: owner }, room);\n\t\t\t} catch (error) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst extra: Partial = options?.subscriptionExtra || {};\n\n\t\t\textra.open = true;\n\n\t\t\tif (room.prid) {\n\t\t\t\textra.prid = room.prid;\n\t\t\t}\n\n\t\t\tif (username === owner.username) {\n\t\t\t\textra.ls = now;\n\t\t\t}\n\n\t\t\tSubscriptions.createWithRoomAndUser(room, member, extra);\n\t\t}\n\t}\n\n\taddUserRoles(owner._id, ['owner'], room._id);\n\n\tif (type === 'c') {\n\t\tif (room.teamId) {\n\t\t\tconst team = Promise.await(Team.getOneById(room.teamId));\n\t\t\tteam && Messages.createUserAddRoomToTeamWithRoomIdAndUser(team.roomId, room.name, owner);\n\t\t}\n\t\tcallbacks.run('afterCreateChannel', owner, room);\n\t} else if (type === 'p') {\n\t\tcallbacks.runAsync('afterCreatePrivateGroup', owner, room);\n\t}\n\tcallbacks.runAsync('afterCreateRoom', owner, room);\n\tif (shouldBeHandledByFederation) {\n\t\tcallbacks.runAsync('federation.afterCreateFederatedRoom', room, { owner, originalMemberList: members as string[] });\n\t}\n\n\tApps.triggerEvent('IPostRoomCreate', room);\n\n\treturn {\n\t\trid: room._id, // backwards compatible\n\t\t...room,\n\t};\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/deleteMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/deleteRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/deleteUser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getAvatarSuggestionForUser.ts",[],["22968"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getFullUserData.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getRoomByNameOrIdWithOptionToJoin.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getRoomsWithSingleOwner.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getStatusText.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getUserCreatedByApp.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getUserSingleOwnedRooms.ts",[],["22969","22970"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/getUsernameSuggestion.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/insertMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/isTheLastMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/loadMessageHistory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/notifications/desktop.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/notifications/email.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/notifications/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/notifications/mobile.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/parseUrlsInMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/processWebhookMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/relinquishRoomOwnerships.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/removeUserFromRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/saveCustomFields.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/saveCustomFieldsWithoutValidation.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/saveUser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/saveUserIdentity.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/sendMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setEmail.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setRealName.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setRoomAvatar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setStatusText.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setUserActiveStatus.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setUserAvatar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/setUsername.ts",[],["22971","22972","22973","22974","22975"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/unarchiveRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/updateGroupDMsName.ts",[],["22976","22977","22978","22979"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/updateMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/validateCustomFields.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/functions/validateName.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/PasswordPolicyClass.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/RateLimiter.js",["22980","22981"],[],"import { Meteor } from 'meteor/meteor';\nimport { DDPRateLimiter } from 'meteor/ddp-rate-limiter';\nimport { RateLimiter } from 'meteor/rate-limit';\nimport _ from 'underscore';\n\nexport const RateLimiterClass = new (class {\n\tlimitFunction(fn, numRequests, timeInterval, matchers) {\n\t\tif (process.env.TEST_MODE === 'true') {\n\t\t\treturn fn;\n\t\t}\n\t\tconst rateLimiter = new RateLimiter();\n\t\trateLimiter.addRule(matchers, numRequests, timeInterval);\n\t\treturn function (...args) {\n\t\t\tconst match = {};\n\t\t\t_.each(matchers, function (matcher, key) {\n\t\t\t\tmatch[key] = args[key];\n\t\t\t});\n\t\t\trateLimiter.increment(match);\n\t\t\tconst rateLimitResult = rateLimiter.check(match);\n\t\t\tif (rateLimitResult.allowed) {\n\t\t\t\treturn fn.apply(null, args);\n\t\t\t}\n\t\t\tthrow new Meteor.Error(\n\t\t\t\t'error-too-many-requests',\n\t\t\t\t`Error, too many requests. Please slow down. You must wait ${Math.ceil(\n\t\t\t\t\trateLimitResult.timeToReset / 1000,\n\t\t\t\t)} seconds before trying again.`,\n\t\t\t\t{\n\t\t\t\t\ttimeToReset: rateLimitResult.timeToReset,\n\t\t\t\t\tseconds: Math.ceil(rateLimitResult.timeToReset / 1000),\n\t\t\t\t},\n\t\t\t);\n\t\t};\n\t}\n\n\tlimitMethod(methodName, numRequests, timeInterval, matchers) {\n\t\tif (process.env.TEST_MODE === 'true') {\n\t\t\treturn;\n\t\t}\n\t\tconst match = {\n\t\t\ttype: 'method',\n\t\t\tname: methodName,\n\t\t};\n\t\t_.each(matchers, function (matcher, key) {\n\t\t\tmatch[key] = matchers[key];\n\t\t});\n\t\treturn DDPRateLimiter.addRule(match, numRequests, timeInterval);\n\t}\n})();\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/bugsnag.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/debug.js",["22982"],[],"import { Meteor } from 'meteor/meteor';\nimport { WebApp } from 'meteor/webapp';\nimport { InstanceStatus } from '@rocket.chat/instance-status';\nimport _ from 'underscore';\n\nimport { settings } from '../../../settings/server';\nimport { metrics } from '../../../metrics/server';\nimport { Logger } from '../../../../server/lib/logger/Logger';\nimport { getMethodArgs } from '../../../../server/lib/logger/logPayloads';\n\nconst logger = new Logger('Meteor');\n\nlet Log_Trace_Methods;\nlet Log_Trace_Subscriptions;\nsettings.watch('Log_Trace_Methods', (value) => {\n\tLog_Trace_Methods = value;\n});\nsettings.watch('Log_Trace_Subscriptions', (value) => {\n\tLog_Trace_Subscriptions = value;\n});\n\nlet Log_Trace_Methods_Filter;\nlet Log_Trace_Subscriptions_Filter;\nsettings.watch('Log_Trace_Methods_Filter', (value) => {\n\tLog_Trace_Methods_Filter = value ? new RegExp(value) : undefined;\n});\nsettings.watch('Log_Trace_Subscriptions_Filter', (value) => {\n\tLog_Trace_Subscriptions_Filter = value ? new RegExp(value) : undefined;\n});\n\nconst traceConnection = (enable, filter, prefix, name, connection, userId) => {\n\tif (!enable) {\n\t\treturn;\n\t}\n\n\tif (filter && !filter.test(name)) {\n\t\treturn;\n\t}\n\n\tif (connection) {\n\t\tconsole.log(name, {\n\t\t\tid: connection.id,\n\t\t\tclientAddress: connection.clientAddress,\n\t\t\thttpHeaders: connection.httpHeaders,\n\t\t\tuserId,\n\t\t});\n\t} else {\n\t\tconsole.log(name, 'no-connection');\n\t}\n};\n\nconst wrapMethods = function (name, originalHandler, methodsMap) {\n\tmethodsMap[name] = function (...originalArgs) {\n\t\ttraceConnection(Log_Trace_Methods, Log_Trace_Methods_Filter, 'method', name, this.connection, this.userId);\n\n\t\tconst method = name === 'stream' ? `${name}:${originalArgs[0]}` : name;\n\n\t\tconst end = metrics.meteorMethods.startTimer({\n\t\t\tmethod,\n\t\t\thas_connection: this.connection != null,\n\t\t\thas_user: this.userId != null,\n\t\t});\n\n\t\tlogger.method({\n\t\t\tmethod,\n\t\t\tuserId: Meteor.userId(),\n\t\t\tuserAgent: this.connection?.httpHeaders['user-agent'],\n\t\t\treferer: this.connection?.httpHeaders.referer,\n\t\t\tremoteIP: this.connection?.clientAddress,\n\t\t\tinstanceId: InstanceStatus.id(),\n\t\t\t...getMethodArgs(name, originalArgs),\n\t\t});\n\n\t\tconst result = originalHandler.apply(this, originalArgs);\n\t\tend();\n\t\treturn result;\n\t};\n};\n\nconst originalMeteorMethods = Meteor.methods;\n\nMeteor.methods = function (methodMap) {\n\t_.each(methodMap, function (handler, name) {\n\t\twrapMethods(name, handler, methodMap);\n\t});\n\toriginalMeteorMethods(methodMap);\n};\n\nconst originalMeteorPublish = Meteor.publish;\n\nMeteor.publish = function (name, func) {\n\treturn originalMeteorPublish(name, function (...args) {\n\t\ttraceConnection(Log_Trace_Subscriptions, Log_Trace_Subscriptions_Filter, 'subscription', name, this.connection, this.userId);\n\n\t\tlogger.subscription({\n\t\t\tpublication: name,\n\t\t\tuserId: this.userId,\n\t\t\tuserAgent: this.connection?.httpHeaders['user-agent'],\n\t\t\treferer: this.connection?.httpHeaders.referer,\n\t\t\tremoteIP: this.connection?.clientAddress,\n\t\t\tinstanceId: InstanceStatus.id(),\n\t\t});\n\n\t\tconst end = metrics.meteorSubscriptions.startTimer({ subscription: name });\n\n\t\tconst originalReady = this.ready;\n\t\tthis.ready = function () {\n\t\t\tend();\n\t\t\treturn originalReady.apply(this, args);\n\t\t};\n\n\t\treturn func.apply(this, args);\n\t});\n};\n\nWebApp.rawConnectHandlers.use(function (req, res, next) {\n\tres.setHeader('X-Instance-ID', InstanceStatus.id());\n\treturn next();\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/defaultBlockedDomainsList.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/deprecationWarningLogger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/getHiddenSystemMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/interceptDirectReplyEmails.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/loginErrorMessageOverride.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/meteorFixes.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/msgStream.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/passwordPolicy.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/processDirectEmail.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/lib/validateEmailDomain.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/addOAuthService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/addUserToRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/addUsersToRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/archiveRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/blockUser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/checkRegistrationSecretURL.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/checkUsernameAvailability.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/cleanRoomHistory.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/createChannel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/createPrivateGroup.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/createToken.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/deleteMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/deleteUserOwnAccount.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/executeSlashCommandPreview.ts",["22983"],["22984"],"import type { IMessage, SlashCommandPreviewItem } from '@rocket.chat/core-typings';\nimport { Meteor } from 'meteor/meteor';\n\nimport { slashCommands } from '../../../utils/server';\n\ndeclare module '@rocket.chat/ui-contexts' {\n\t// eslint-disable-next-line @typescript-eslint/naming-convention\n\texport interface ServerMethods {\n\t\texecuteSlashCommandPreview(\n\t\t\tcommand: { cmd: string; params: string; msg: Pick },\n\t\t\tpreview: SlashCommandPreviewItem,\n\t\t): Promise;\n\t}\n}\n\nMeteor.methods({\n\texecuteSlashCommandPreview(command, preview) {\n\t\tif (!Meteor.userId()) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tmethod: 'getSlashCommandPreview',\n\t\t\t});\n\t\t}\n\n\t\tif (!command || !command.cmd || !slashCommands.commands[command.cmd]) {\n\t\t\tthrow new Meteor.Error('error-invalid-command', 'Invalid Command Provided', {\n\t\t\t\tmethod: 'executeSlashCommandPreview',\n\t\t\t});\n\t\t}\n\n\t\tconst theCmd = slashCommands.commands[command.cmd];\n\t\tif (!theCmd.providesPreview) {\n\t\t\tthrow new Meteor.Error('error-invalid-command', 'Command Does Not Provide Previews', {\n\t\t\t\tmethod: 'executeSlashCommandPreview',\n\t\t\t});\n\t\t}\n\n\t\tif (!preview) {\n\t\t\tthrow new Meteor.Error('error-invalid-command-preview', 'Invalid Preview Provided', {\n\t\t\t\tmethod: 'executeSlashCommandPreview',\n\t\t\t});\n\t\t}\n\n\t\treturn slashCommands.executePreview(command.cmd, command.params, command.msg, preview, command.triggerId);\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/filterATAllTag.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/filterATHereTag.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/filterBadWords.ts",[],["22985"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getChannelHistory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getRoomJoinCode.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getRoomRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getSingleMessage.ts",["22986"],[],"import { Meteor } from 'meteor/meteor';\nimport { check } from 'meteor/check';\n\nimport { canAccessRoomId } from '../../../authorization/server';\nimport { Messages } from '../../../models/server';\n\nMeteor.methods({\n\tgetSingleMessage(msgId) {\n\t\tcheck(msgId, String);\n\n\t\tconst uid = Meteor.userId();\n\n\t\tif (!uid) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getSingleMessage' });\n\t\t}\n\n\t\tconst msg = Messages.findOneById(msgId);\n\n\t\tif (!msg || !msg.rid) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!canAccessRoomId(msg.rid, uid)) {\n\t\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'getSingleMessage' });\n\t\t}\n\n\t\treturn msg;\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getSlashCommandPreviews.ts",["22987"],["22988"],"import type { IMessage, SlashCommandPreviews } from '@rocket.chat/core-typings';\nimport { Meteor } from 'meteor/meteor';\n\nimport { slashCommands } from '../../../utils/server';\n\ndeclare module '@rocket.chat/ui-contexts' {\n\t// eslint-disable-next-line @typescript-eslint/naming-convention\n\texport interface ServerMethods {\n\t\tgetSlashCommandPreviews(command: { cmd: string; params: string; msg: Pick }): Promise;\n\t}\n}\n\nMeteor.methods({\n\tgetSlashCommandPreviews(command) {\n\t\tif (!Meteor.userId()) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tmethod: 'getSlashCommandPreview',\n\t\t\t});\n\t\t}\n\n\t\tif (!command || !command.cmd || !slashCommands.commands[command.cmd]) {\n\t\t\tthrow new Meteor.Error('error-invalid-command', 'Invalid Command Provided', {\n\t\t\t\tmethod: 'executeSlashCommandPreview',\n\t\t\t});\n\t\t}\n\n\t\tconst theCmd = slashCommands.commands[command.cmd];\n\t\tif (!theCmd.providesPreview) {\n\t\t\tthrow new Meteor.Error('error-invalid-command', 'Command Does Not Provide Previews', {\n\t\t\t\tmethod: 'executeSlashCommandPreview',\n\t\t\t});\n\t\t}\n\n\t\treturn slashCommands.getPreviews(command.cmd, command.params, command.msg);\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getUserRoles.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/getUsernameSuggestion.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/insertOrUpdateUser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/joinDefaultChannels.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/joinRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/leaveRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/refreshOAuthService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/removeOAuthService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/restartServer.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/saveCustomFields.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/saveSetting.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/saveSettings.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/sendMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/sendSMTPTestEmail.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/setAdminStatus.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/setEmail.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/setRealName.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/setUsername.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/unarchiveRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/unblockUser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/methods/updateMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/oauth/facebook.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/oauth/google.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/oauth/oauth.js",["22989"],[],"import { Meteor } from 'meteor/meteor';\nimport { Match, check } from 'meteor/check';\nimport { Accounts } from 'meteor/accounts-base';\nimport { ServiceConfiguration } from 'meteor/service-configuration';\nimport _ from 'underscore';\n\nconst AccessTokenServices = {};\n\nexport const registerAccessTokenService = function (serviceName, handleAccessTokenRequest) {\n\tAccessTokenServices[serviceName] = {\n\t\tserviceName,\n\t\thandleAccessTokenRequest,\n\t};\n};\n\n// Listen to calls to `login` with an oauth option set. This is where\n// users actually get logged in to meteor via oauth.\nAccounts.registerLoginHandler(function (options) {\n\tif (!options.accessToken) {\n\t\treturn undefined; // don't handle\n\t}\n\n\tcheck(\n\t\toptions,\n\t\tMatch.ObjectIncluding({\n\t\t\tserviceName: String,\n\t\t}),\n\t);\n\n\tconst service = AccessTokenServices[options.serviceName];\n\n\t// Skip everything if there's no service set by the oauth middleware\n\tif (!service) {\n\t\tthrow new Error(`Unexpected AccessToken service ${options.serviceName}`);\n\t}\n\n\t// Make sure we're configured\n\tif (!ServiceConfiguration.configurations.findOne({ service: options.serviceName })) {\n\t\tthrow new ServiceConfiguration.ConfigError();\n\t}\n\n\tif (!_.contains(Accounts.oauth.serviceNames(), service.serviceName)) {\n\t\t// serviceName was not found in the registered services list.\n\t\t// This could happen because the service never registered itself or\n\t\t// unregisterService was called on it.\n\t\treturn {\n\t\t\ttype: 'oauth',\n\t\t\terror: new Meteor.Error(Accounts.LoginCancelledError.numericError, `No registered oauth service found for: ${service.serviceName}`),\n\t\t};\n\t}\n\n\tconst oauthResult = service.handleAccessTokenRequest(options);\n\n\treturn Accounts.updateOrCreateUserFromExternalService(service.serviceName, oauthResult.serviceData, oauthResult.options);\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/oauth/proxy.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/oauth/twitter.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/email.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/oAuthServicesUpdate.js",[],["22990","22991"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/rateLimiter.js",["22992"],[],"import _ from 'underscore';\nimport { Meteor } from 'meteor/meteor';\nimport { DDPRateLimiter } from 'meteor/ddp-rate-limiter';\nimport { RateLimiter } from 'meteor/rate-limit';\n\nimport { settings } from '../../../settings/server';\nimport { metrics } from '../../../metrics/server';\nimport { Logger } from '../../../logger/server';\n\nconst logger = new Logger('RateLimiter');\n\nconst slowDownRate = parseInt(process.env.RATE_LIMITER_SLOWDOWN_RATE);\n\nconst rateLimiterConsoleLog = ({ msg, reply, input }) => {\n\tconsole.warn('DDP RATE LIMIT:', msg);\n\tconsole.warn(JSON.stringify({ reply, input }, null, 2));\n};\n\nconst rateLimiterLogger = ({ msg, reply, input }) => logger.info({ msg, reply, input });\n\nconst rateLimiterLog = String(process.env.RATE_LIMITER_LOGGER) === 'console' ? rateLimiterConsoleLog : rateLimiterLogger;\n\n// Get initial set of names already registered for rules\nconst names = new Set(\n\tObject.values(DDPRateLimiter.printRules())\n\t\t.map((rule) => rule._matchers)\n\t\t.filter((match) => typeof match.name === 'string')\n\t\t.map((match) => match.name),\n);\n\n// Override the addRule to save new names added after this point\nconst { addRule } = DDPRateLimiter;\nDDPRateLimiter.addRule = (matcher, calls, time, callback) => {\n\tif (matcher && typeof matcher.name === 'string') {\n\t\tnames.add(matcher.name);\n\t}\n\treturn addRule.call(DDPRateLimiter, matcher, calls, time, callback);\n};\n\nconst { _increment } = DDPRateLimiter;\nDDPRateLimiter._increment = function (input) {\n\tconst session = Meteor.server.sessions.get(input.connectionId);\n\tinput.broadcastAuth = (session && session.connectionHandle && session.connectionHandle.broadcastAuth) === true;\n\n\treturn _increment.call(DDPRateLimiter, input);\n};\n\n// Need to override the meteor's code duo to a problem with the callback reply\n// being shared among all matchs\nRateLimiter.prototype.check = function (input) {\n\t// ==== BEGIN OVERRIDE ====\n\tconst session = Meteor.server.sessions.get(input.connectionId);\n\tinput.broadcastAuth = (session && session.connectionHandle && session.connectionHandle.broadcastAuth) === true;\n\t// ==== END OVERRIDE ====\n\n\tconst self = this;\n\tconst reply = {\n\t\tallowed: true,\n\t\ttimeToReset: 0,\n\t\tnumInvocationsLeft: Infinity,\n\t};\n\n\tconst matchedRules = self._findAllMatchingRules(input);\n\t_.each(matchedRules, function (rule) {\n\t\t// ==== BEGIN OVERRIDE ====\n\t\tconst callbackReply = {\n\t\t\tallowed: true,\n\t\t\ttimeToReset: 0,\n\t\t\tnumInvocationsLeft: Infinity,\n\t\t};\n\t\t// ==== END OVERRIDE ====\n\n\t\tconst ruleResult = rule.apply(input);\n\t\tlet numInvocations = rule.counters[ruleResult.key];\n\n\t\tif (ruleResult.timeToNextReset < 0) {\n\t\t\t// Reset all the counters since the rule has reset\n\t\t\trule.resetCounter();\n\t\t\truleResult.timeSinceLastReset = new Date().getTime() - rule._lastResetTime;\n\t\t\truleResult.timeToNextReset = rule.options.intervalTime;\n\t\t\tnumInvocations = 0;\n\t\t}\n\n\t\tif (numInvocations > rule.options.numRequestsAllowed) {\n\t\t\t// Only update timeToReset if the new time would be longer than the\n\t\t\t// previously set time. This is to ensure that if this input triggers\n\t\t\t// multiple rules, we return the longest period of time until they can\n\t\t\t// successfully make another call\n\t\t\tif (reply.timeToReset < ruleResult.timeToNextReset) {\n\t\t\t\treply.timeToReset = ruleResult.timeToNextReset;\n\t\t\t}\n\t\t\treply.allowed = false;\n\t\t\treply.numInvocationsLeft = 0;\n\n\t\t\t// ==== BEGIN OVERRIDE ====\n\t\t\tcallbackReply.timeToReset = ruleResult.timeToNextReset;\n\t\t\tcallbackReply.allowed = false;\n\t\t\tcallbackReply.numInvocationsLeft = 0;\n\t\t\tcallbackReply.numInvocationsExceeded = numInvocations - rule.options.numRequestsAllowed;\n\t\t\trule._executeCallback(callbackReply, input);\n\t\t\t// ==== END OVERRIDE ====\n\t\t} else {\n\t\t\t// If this is an allowed attempt and we haven't failed on any of the\n\t\t\t// other rules that match, update the reply field.\n\t\t\tif (rule.options.numRequestsAllowed - numInvocations < reply.numInvocationsLeft && reply.allowed) {\n\t\t\t\treply.timeToReset = ruleResult.timeToNextReset;\n\t\t\t\treply.numInvocationsLeft = rule.options.numRequestsAllowed - numInvocations;\n\t\t\t}\n\n\t\t\t// ==== BEGIN OVERRIDE ====\n\t\t\tcallbackReply.timeToReset = ruleResult.timeToNextReset;\n\t\t\tcallbackReply.numInvocationsLeft = rule.options.numRequestsAllowed - numInvocations;\n\t\t\trule._executeCallback(callbackReply, input);\n\t\t\t// ==== END OVERRIDE ====\n\t\t}\n\t});\n\treturn reply;\n};\n\nconst checkNameNonStream = (name) => name && !names.has(name) && !name.startsWith('stream-');\nconst checkNameForStream = (name) => name && !names.has(name) && name.startsWith('stream-');\n\nconst ruleIds = {};\n\nconst callback = (msg, name) => (reply, input) => {\n\tif (reply.allowed === false) {\n\t\trateLimiterLog({ msg, reply, input });\n\t\tmetrics.ddpRateLimitExceeded.inc({\n\t\t\tlimit_name: name,\n\t\t\tuser_id: input.userId,\n\t\t\tclient_address: input.clientAddress,\n\t\t\ttype: input.type,\n\t\t\tname: input.name,\n\t\t\tconnection_id: input.connectionId,\n\t\t});\n\t\t// sleep before sending the error to slow down next requests\n\t\tif (slowDownRate > 0 && reply.numInvocationsExceeded) {\n\t\t\tMeteor._sleepForMs(slowDownRate * reply.numInvocationsExceeded);\n\t\t}\n\t\t// } else {\n\t\t// \tconsole.log('DDP RATE LIMIT:', message);\n\t\t// \tconsole.log(JSON.stringify({ ...reply, ...input }, null, 2));\n\t}\n};\n\nconst messages = {\n\tIP: 'address',\n\tUser: 'userId',\n\tConnection: 'connectionId',\n\tUser_By_Method: 'userId per method',\n\tConnection_By_Method: 'connectionId per method',\n};\n\nconst reconfigureLimit = Meteor.bindEnvironment((name, rules, factor = 1) => {\n\tif (ruleIds[name + factor]) {\n\t\tDDPRateLimiter.removeRule(ruleIds[name + factor]);\n\t}\n\n\tif (!settings.get(`DDP_Rate_Limit_${name}_Enabled`)) {\n\t\treturn;\n\t}\n\n\truleIds[name + factor] = addRule(\n\t\trules,\n\t\tsettings.get(`DDP_Rate_Limit_${name}_Requests_Allowed`) * factor,\n\t\tsettings.get(`DDP_Rate_Limit_${name}_Interval_Time`) * factor,\n\t\tcallback(`limit by ${messages[name]}`, name),\n\t);\n});\n\nconst configIP = _.debounce(() => {\n\treconfigureLimit('IP', {\n\t\tbroadcastAuth: false,\n\t\tclientAddress: (clientAddress) => clientAddress !== '127.0.0.1',\n\t});\n}, 1000);\n\nconst configUser = _.debounce(() => {\n\treconfigureLimit('User', {\n\t\tbroadcastAuth: false,\n\t\tuserId: (userId) => userId != null,\n\t});\n}, 1000);\n\nconst configConnection = _.debounce(() => {\n\treconfigureLimit('Connection', {\n\t\tbroadcastAuth: false,\n\t\tconnectionId: () => true,\n\t});\n}, 1000);\n\nconst configUserByMethod = _.debounce(() => {\n\treconfigureLimit('User_By_Method', {\n\t\tbroadcastAuth: false,\n\t\ttype: () => true,\n\t\tname: checkNameNonStream,\n\t\tuserId: (userId) => userId != null,\n\t});\n\treconfigureLimit(\n\t\t'User_By_Method',\n\t\t{\n\t\t\tbroadcastAuth: false,\n\t\t\ttype: () => true,\n\t\t\tname: checkNameForStream,\n\t\t\tuserId: (userId) => userId != null,\n\t\t},\n\t\t4,\n\t);\n}, 1000);\n\nconst configConnectionByMethod = _.debounce(() => {\n\treconfigureLimit('Connection_By_Method', {\n\t\tbroadcastAuth: false,\n\t\ttype: () => true,\n\t\tname: checkNameNonStream,\n\t\tconnectionId: () => true,\n\t});\n\treconfigureLimit(\n\t\t'Connection_By_Method',\n\t\t{\n\t\t\tbroadcastAuth: false,\n\t\t\ttype: () => true,\n\t\t\tname: checkNameForStream,\n\t\t\tconnectionId: () => true,\n\t\t},\n\t\t4,\n\t);\n}, 1000);\n\nif (!process.env.TEST_MODE) {\n\tsettings.watchByRegex(/^DDP_Rate_Limit_IP_.+/, configIP);\n\tsettings.watchByRegex(/^DDP_Rate_Limit_User_[^B].+/, configUser);\n\tsettings.watchByRegex(/^DDP_Rate_Limit_Connection_[^B].+/, configConnection);\n\tsettings.watchByRegex(/^DDP_Rate_Limit_User_By_Method_.+/, configUserByMethod);\n\tsettings.watchByRegex(/^DDP_Rate_Limit_Connection_By_Method_.+/, configConnectionByMethod);\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/robots.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/settingsOnLoadCdnPrefix.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/settingsOnLoadDirectReply.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/settingsOnLoadSMTP.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/lib/server/startup/settingsOnLoadSiteUrl.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/collections/LivechatCustomField.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/collections/LivechatInquiry.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/collections/LivechatTrigger.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/externalFrame/crypto.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/externalFrame/externalFrameContainer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/externalFrame/generateNewKey.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/externalFrame/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/externalFrame/tabBar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/lib/chartHandler.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/lib/stream/inquiry.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/lib/stream/queueManager.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/startup/notifyUnreadRooms.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/tabBar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/ui.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/views/app/business-hours/BusinessHours.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/views/app/business-hours/IBusinessHourBehavior.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/views/app/business-hours/Single.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/client/voip.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/agent.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/appearance.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/businessHours.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/dashboards.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/departments.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/inquiries.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/integrations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/queue.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/rooms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/sms.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/triggers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/upload.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/users.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/imports/server/rest/visitors.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/lib/Assets.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/lib/inquiries.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/lib/messageTypes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/lib/stream/constants.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/agents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/appearance.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/businessHours.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/customFields.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/departments.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/inquiries.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/integrations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/livechat.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/queue.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/rooms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/transfer.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/triggers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/users.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/lib/visitors.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/rest.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/agent.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/config.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/contact.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/customField.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/message.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/offlineMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/pageVisited.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/room.ts",["22993"],[],"import { Meteor } from 'meteor/meteor';\nimport { check } from 'meteor/check';\nimport { Random } from 'meteor/random';\nimport { TAPi18n } from 'meteor/rocketchat:tap-i18n';\nimport type { ILivechatAgent, IOmnichannelRoom, IUser } from '@rocket.chat/core-typings';\nimport { isOmnichannelRoom, OmnichannelSourceType } from '@rocket.chat/core-typings';\nimport { LivechatVisitors, Users, LivechatRooms as LivechatRoomsRaw, Subscriptions } from '@rocket.chat/models';\nimport {\n\tisLiveChatRoomForwardProps,\n\tisPOSTLivechatRoomCloseParams,\n\tisPOSTLivechatRoomTransferParams,\n\tisPOSTLivechatRoomSurveyParams,\n\tisLiveChatRoomJoinProps,\n\tisPUTLivechatRoomVisitorParams,\n\tisLiveChatRoomSaveInfoProps,\n\tisPOSTLivechatRoomCloseByUserParams,\n} from '@rocket.chat/rest-typings';\n\nimport { settings as rcSettings } from '../../../../settings/server';\nimport { Messages, LivechatRooms } from '../../../../models/server';\nimport { API } from '../../../../api/server';\nimport { findGuest, findRoom, getRoom, settings, findAgent, onCheckRoomParams } from '../lib/livechat';\nimport { Livechat } from '../../lib/Livechat';\nimport { Livechat as LivechatTyped } from '../../lib/LivechatTyped';\nimport { normalizeTransferredByData } from '../../lib/Helper';\nimport { findVisitorInfo } from '../lib/visitors';\nimport { canAccessRoom, hasPermission } from '../../../../authorization/server';\nimport { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission';\nimport { addUserToRoom } from '../../../../lib/server/functions';\nimport { apiDeprecationLogger } from '../../../../lib/server/lib/deprecationWarningLogger';\nimport { deprecationWarning } from '../../../../api/server/helpers/deprecationWarning';\nimport { callbacks } from '../../../../../lib/callbacks';\nimport type { CloseRoomParams } from '../../lib/LivechatTyped.d';\n\nconst isAgentWithInfo = (agentObj: ILivechatAgent | { hiddenInfo: true }): agentObj is ILivechatAgent => !('hiddenInfo' in agentObj);\n\nAPI.v1.addRoute('livechat/room', {\n\tasync get() {\n\t\t// I'll temporary use check for validation, as validateParams doesnt support what's being done here\n\t\tconst extraCheckParams = onCheckRoomParams({\n\t\t\ttoken: String,\n\t\t\trid: Match.Maybe(String),\n\t\t\tagentId: Match.Maybe(String),\n\t\t});\n\n\t\tcheck(this.queryParams, extraCheckParams);\n\n\t\tconst { token, rid: roomId, agentId, ...extraParams } = this.queryParams;\n\n\t\tconst guest = token && (await findGuest(token));\n\t\tif (!guest) {\n\t\t\tthrow new Error('invalid-token');\n\t\t}\n\n\t\tlet room: IOmnichannelRoom;\n\t\tif (!roomId) {\n\t\t\troom = LivechatRooms.findOneOpenByVisitorToken(token, {});\n\t\t\tif (room) {\n\t\t\t\treturn API.v1.success({ room, newRoom: false });\n\t\t\t}\n\n\t\t\tlet agent;\n\t\t\tconst agentObj = agentId && findAgent(agentId);\n\t\t\tif (agentObj) {\n\t\t\t\tif (isAgentWithInfo(agentObj)) {\n\t\t\t\t\tconst { username = undefined } = agentObj;\n\t\t\t\t\tagent = { agentId, username };\n\t\t\t\t} else {\n\t\t\t\t\tagent = { agentId };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst rid = Random.id();\n\t\t\tconst roomInfo = {\n\t\t\t\tsource: {\n\t\t\t\t\ttype: this.isWidget() ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API,\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tconst newRoom = await getRoom({ guest, rid, agent, roomInfo, extraParams });\n\t\t\treturn API.v1.success(newRoom);\n\t\t}\n\n\t\troom = LivechatRooms.findOneOpenByRoomIdAndVisitorToken(roomId, token, {});\n\t\tif (!room) {\n\t\t\tthrow new Error('invalid-room');\n\t\t}\n\n\t\treturn API.v1.success({ room, newRoom: false });\n\t},\n});\n\n// Note: use this route if a visitor is closing a room\n// If a RC user(like eg agent) is closing a room, use the `livechat/room.closeByUser` route\nAPI.v1.addRoute(\n\t'livechat/room.close',\n\t{ validateParams: isPOSTLivechatRoomCloseParams },\n\t{\n\t\tasync post() {\n\t\t\tconst { rid, token } = this.bodyParams;\n\n\t\t\tconst visitor = await findGuest(token);\n\t\t\tif (!visitor) {\n\t\t\t\tthrow new Error('invalid-token');\n\t\t\t}\n\n\t\t\tconst room = findRoom(token, rid);\n\t\t\tif (!room) {\n\t\t\t\tthrow new Error('invalid-room');\n\t\t\t}\n\n\t\t\tif (!room.open) {\n\t\t\t\tthrow new Error('room-closed');\n\t\t\t}\n\n\t\t\tconst language = rcSettings.get('Language') || 'en';\n\t\t\tconst comment = TAPi18n.__('Closed_by_visitor', { lng: language });\n\n\t\t\tconst options: CloseRoomParams['options'] = {};\n\t\t\tif (room.servedBy) {\n\t\t\t\tconst servingAgent: Pick | null =\n\t\t\t\t\tawait Users.findOneById(room.servedBy._id, {\n\t\t\t\t\t\tprojection: {\n\t\t\t\t\t\t\tname: 1,\n\t\t\t\t\t\t\tusername: 1,\n\t\t\t\t\t\t\tutcOffset: 1,\n\t\t\t\t\t\t\tsettings: 1,\n\t\t\t\t\t\t\tlanguage: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\tif (servingAgent?.settings?.preferences?.omnichannelTranscriptPDF) {\n\t\t\t\t\toptions.pdfTranscript = {\n\t\t\t\t\t\trequestedBy: servingAgent._id,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// We'll send the transcript by email only if the setting is disabled (that means, we're not asking the user if he wants to receive the transcript by email)\n\t\t\t\t// And the agent has the preference enabled to send the transcript by email and the visitor has an email address\n\t\t\t\t// When Livechat_enable_transcript is enabled, the email will be sent via livechat/transcript route\n\t\t\t\tif (\n\t\t\t\t\t!rcSettings.get('Livechat_enable_transcript') &&\n\t\t\t\t\tservingAgent?.settings?.preferences?.omnichannelTranscriptEmail &&\n\t\t\t\t\tvisitor.visitorEmails?.length &&\n\t\t\t\t\tvisitor.visitorEmails?.[0]?.address\n\t\t\t\t) {\n\t\t\t\t\tconst visitorEmail = visitor.visitorEmails?.[0]?.address;\n\n\t\t\t\t\tconst language = servingAgent.language || rcSettings.get('Language') || 'en';\n\t\t\t\t\tconst t = (s: string): string => TAPi18n.__(s, { lng: language });\n\t\t\t\t\tconst subject = t('Transcript_of_your_livechat_conversation');\n\n\t\t\t\t\toptions.emailTranscript = {\n\t\t\t\t\t\tsendToVisitor: true,\n\t\t\t\t\t\trequestData: {\n\t\t\t\t\t\t\temail: visitorEmail,\n\t\t\t\t\t\t\trequestedAt: new Date(),\n\t\t\t\t\t\t\trequestedBy: servingAgent,\n\t\t\t\t\t\t\tsubject,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait LivechatTyped.closeRoom({ visitor, room, comment, options });\n\n\t\t\treturn API.v1.success({ rid, comment });\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'livechat/room.closeByUser',\n\t{\n\t\tvalidateParams: isPOSTLivechatRoomCloseByUserParams,\n\t\tauthRequired: true,\n\t\tpermissionsRequired: ['close-livechat-room'],\n\t},\n\t{\n\t\tasync post() {\n\t\t\tconst { rid, comment, tags, generateTranscriptPdf, transcriptEmail } = this.bodyParams;\n\n\t\t\tconst room = await LivechatRoomsRaw.findOneById(rid);\n\t\t\tif (!room || !isOmnichannelRoom(room)) {\n\t\t\t\tthrow new Error('error-invalid-room');\n\t\t\t}\n\n\t\t\tif (!room.open) {\n\t\t\t\tthrow new Error('error-room-already-closed');\n\t\t\t}\n\n\t\t\tconst subscription = await Subscriptions.findOneByRoomIdAndUserId(rid, this.userId, { projection: { _id: 1 } });\n\t\t\tif (!subscription && !(await hasPermissionAsync(this.userId, 'close-others-livechat-room'))) {\n\t\t\t\tthrow new Error('error-not-authorized');\n\t\t\t}\n\n\t\t\tconst options: CloseRoomParams['options'] = {\n\t\t\t\tclientAction: true,\n\t\t\t\ttags,\n\t\t\t\t...(generateTranscriptPdf && { pdfTranscript: { requestedBy: this.userId } }),\n\t\t\t\t...(transcriptEmail && {\n\t\t\t\t\t...(transcriptEmail.sendToVisitor\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\temailTranscript: {\n\t\t\t\t\t\t\t\t\tsendToVisitor: true,\n\t\t\t\t\t\t\t\t\trequestData: {\n\t\t\t\t\t\t\t\t\t\temail: transcriptEmail.requestData.email,\n\t\t\t\t\t\t\t\t\t\tsubject: transcriptEmail.requestData.subject,\n\t\t\t\t\t\t\t\t\t\trequestedAt: new Date(),\n\t\t\t\t\t\t\t\t\t\trequestedBy: this.user,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t }\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\temailTranscript: {\n\t\t\t\t\t\t\t\t\tsendToVisitor: false,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t }),\n\t\t\t\t}),\n\t\t\t};\n\n\t\t\tawait LivechatTyped.closeRoom({\n\t\t\t\troom,\n\t\t\t\tuser: this.user,\n\t\t\t\toptions,\n\t\t\t\tcomment,\n\t\t\t});\n\n\t\t\treturn API.v1.success();\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'livechat/room.transfer',\n\t{ validateParams: isPOSTLivechatRoomTransferParams },\n\t{\n\t\tasync post() {\n\t\t\tapiDeprecationLogger.warn('livechat/room.transfer has been deprecated. Use livechat/room.forward instead.');\n\n\t\t\tconst { rid, token, department } = this.bodyParams;\n\n\t\t\tconst guest = await findGuest(token);\n\t\t\tif (!guest) {\n\t\t\t\tthrow new Error('invalid-token');\n\t\t\t}\n\n\t\t\tlet room = findRoom(token, rid);\n\t\t\tif (!room) {\n\t\t\t\tthrow new Error('invalid-room');\n\t\t\t}\n\n\t\t\t// update visited page history to not expire\n\t\t\tMessages.keepHistoryForToken(token);\n\n\t\t\tconst { _id, username, name } = guest;\n\t\t\tconst transferredBy = normalizeTransferredByData({ _id, username, name, userType: 'visitor' }, room);\n\n\t\t\tif (!(await Livechat.transfer(room, guest, { roomId: rid, departmentId: department, transferredBy }))) {\n\t\t\t\treturn API.v1.failure();\n\t\t\t}\n\n\t\t\troom = findRoom(token, rid);\n\t\t\treturn API.v1.success(\n\t\t\t\tdeprecationWarning({\n\t\t\t\t\tendpoint: 'livechat/room.transfer',\n\t\t\t\t\tversionWillBeRemoved: '6.0',\n\t\t\t\t\tresponse: { room },\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'livechat/room.survey',\n\t{ validateParams: isPOSTLivechatRoomSurveyParams },\n\t{\n\t\tasync post() {\n\t\t\tconst { rid, token, data } = this.bodyParams;\n\n\t\t\tconst visitor = await findGuest(token);\n\t\t\tif (!visitor) {\n\t\t\t\tthrow new Error('invalid-token');\n\t\t\t}\n\n\t\t\tconst room = findRoom(token, rid);\n\t\t\tif (!room) {\n\t\t\t\tthrow new Error('invalid-room');\n\t\t\t}\n\n\t\t\tconst config = await settings();\n\t\t\tif (!config.survey || !config.survey.items || !config.survey.values) {\n\t\t\t\tthrow new Error('invalid-livechat-config');\n\t\t\t}\n\n\t\t\tconst updateData: { [k: string]: string } = {};\n\t\t\tfor (const item of data) {\n\t\t\t\tif ((config.survey.items.includes(item.name) && config.survey.values.includes(item.value)) || item.name === 'additionalFeedback') {\n\t\t\t\t\tupdateData[item.name] = item.value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Object.keys(updateData).length === 0) {\n\t\t\t\tthrow new Error('invalid-data');\n\t\t\t}\n\n\t\t\tif (!LivechatRooms.updateSurveyFeedbackById(room._id, updateData)) {\n\t\t\t\treturn API.v1.failure();\n\t\t\t}\n\n\t\t\treturn API.v1.success({ rid, data: updateData });\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'livechat/room.forward',\n\t{ authRequired: true, permissionsRequired: ['view-l-room', 'transfer-livechat-guest'], validateParams: isLiveChatRoomForwardProps },\n\t{\n\t\tasync post() {\n\t\t\tconst transferData: typeof this.bodyParams & {\n\t\t\t\ttransferredBy?: unknown;\n\t\t\t\ttransferredTo?: { _id: string; username?: string; name?: string };\n\t\t\t} = this.bodyParams;\n\n\t\t\tconst room = await LivechatRooms.findOneById(this.bodyParams.roomId);\n\t\t\tif (!room || room.t !== 'l') {\n\t\t\t\tthrow new Error('error-invalid-room');\n\t\t\t}\n\n\t\t\tif (!room.open) {\n\t\t\t\tthrow new Error('This_conversation_is_already_closed');\n\t\t\t}\n\n\t\t\tconst guest = await LivechatVisitors.findOneById(room.v?._id);\n\t\t\ttransferData.transferredBy = normalizeTransferredByData(Meteor.user() || {}, room);\n\t\t\tif (transferData.userId) {\n\t\t\t\tconst userToTransfer = await Users.findOneById(transferData.userId);\n\t\t\t\tif (userToTransfer) {\n\t\t\t\t\ttransferData.transferredTo = {\n\t\t\t\t\t\t_id: userToTransfer._id,\n\t\t\t\t\t\tusername: userToTransfer.username,\n\t\t\t\t\t\tname: userToTransfer.name,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst chatForwardedResult = await Livechat.transfer(room, guest, transferData);\n\n\t\t\treturn chatForwardedResult ? API.v1.success() : API.v1.failure();\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'livechat/room.visitor',\n\t{ authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isPUTLivechatRoomVisitorParams },\n\t{\n\t\tasync put() {\n\t\t\t// This endpoint is deprecated and will be removed in future versions.\n\t\t\tconst { rid, newVisitorId, oldVisitorId } = this.bodyParams;\n\n\t\t\tconst { visitor } = await findVisitorInfo({ visitorId: newVisitorId });\n\t\t\tif (!visitor) {\n\t\t\t\tthrow new Error('invalid-visitor');\n\t\t\t}\n\n\t\t\tlet room = LivechatRooms.findOneById(rid, { _id: 1, v: 1 }); // TODO: check _id\n\t\t\tif (!room) {\n\t\t\t\tthrow new Error('invalid-room');\n\t\t\t}\n\n\t\t\tconst { v: { _id: roomVisitorId = undefined } = {} } = room; // TODO: v it will be undefined\n\t\t\tif (roomVisitorId !== oldVisitorId) {\n\t\t\t\tthrow new Error('invalid-room-visitor');\n\t\t\t}\n\n\t\t\troom = Livechat.changeRoomVisitor(this.userId, rid, visitor);\n\n\t\t\treturn API.v1.success(deprecationWarning({ endpoint: 'livechat/room.visitor', versionWillBeRemoved: '6.0', response: { room } }));\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'livechat/room.join',\n\t{ authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isLiveChatRoomJoinProps },\n\t{\n\t\tasync get() {\n\t\t\tconst { roomId } = this.queryParams;\n\n\t\t\tconst { user } = this;\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new Error('error-invalid-user');\n\t\t\t}\n\n\t\t\tconst room = LivechatRooms.findOneById(roomId);\n\n\t\t\tif (!room) {\n\t\t\t\tthrow new Error('error-invalid-room');\n\t\t\t}\n\n\t\t\tif (!canAccessRoom(room, user)) {\n\t\t\t\tthrow new Error('error-not-allowed');\n\t\t\t}\n\n\t\t\taddUserToRoom(roomId, user);\n\n\t\t\treturn API.v1.success();\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'livechat/room.saveInfo',\n\t{ authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isLiveChatRoomSaveInfoProps },\n\t{\n\t\tasync post() {\n\t\t\tconst { roomData, guestData } = this.bodyParams;\n\t\t\tconst room = await LivechatRooms.findOneById(roomData._id);\n\t\t\tif (!room || !isOmnichannelRoom(room)) {\n\t\t\t\tthrow new Error('error-invalid-room');\n\t\t\t}\n\n\t\t\tif ((!room.servedBy || room.servedBy._id !== this.userId) && !hasPermission(this.userId, 'save-others-livechat-room-info')) {\n\t\t\t\treturn API.v1.unauthorized();\n\t\t\t}\n\n\t\t\tif (room.sms) {\n\t\t\t\tdelete guestData.phone;\n\t\t\t}\n\n\t\t\tawait Promise.allSettled([Livechat.saveGuest(guestData, this.userId), Livechat.saveRoomInfo(roomData)]);\n\n\t\t\tcallbacks.run('livechat.saveInfo', LivechatRooms.findOneById(roomData._id), {\n\t\t\t\tuser: this.user,\n\t\t\t\toldRoom: room,\n\t\t\t});\n\n\t\t\treturn API.v1.success();\n\t\t},\n\t},\n);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/transcript.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/transfer.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/videoCall.ts",["22994"],[],"import { isGETWebRTCCall, isPUTWebRTCCallId } from '@rocket.chat/rest-typings';\nimport { TAPi18n } from 'meteor/rocketchat:tap-i18n';\nimport { Settings } from '@rocket.chat/models';\n\nimport { Messages, Rooms } from '../../../../models/server';\nimport { settings as rcSettings } from '../../../../settings/server';\nimport { API } from '../../../../api/server';\nimport { settings } from '../lib/livechat';\nimport { canSendMessage } from '../../../../authorization/server';\nimport { Livechat } from '../../lib/Livechat';\n\nAPI.v1.addRoute(\n\t'livechat/webrtc.call',\n\t{ authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isGETWebRTCCall },\n\t{\n\t\tasync get() {\n\t\t\tconst room = canSendMessage(\n\t\t\t\tthis.queryParams.rid,\n\t\t\t\t{\n\t\t\t\t\tuid: this.userId,\n\t\t\t\t\tusername: this.user.username,\n\t\t\t\t\ttype: this.user.type,\n\t\t\t\t},\n\t\t\t\t{},\n\t\t\t);\n\t\t\tif (!room) {\n\t\t\t\tthrow new Error('invalid-room');\n\t\t\t}\n\n\t\t\tconst webrtcCallingAllowed = rcSettings.get('WebRTC_Enabled') === true && rcSettings.get('Omnichannel_call_provider') === 'WebRTC';\n\t\t\tif (!webrtcCallingAllowed) {\n\t\t\t\tthrow new Error('webRTC calling not enabled');\n\t\t\t}\n\n\t\t\tconst config = await settings();\n\t\t\tif (!config.theme || !config.theme.actionLinks || !config.theme.actionLinks.webrtc) {\n\t\t\t\tthrow new Error('invalid-livechat-config');\n\t\t\t}\n\n\t\t\tlet { callStatus } = room;\n\n\t\t\tif (!callStatus || callStatus === 'ended' || callStatus === 'declined') {\n\t\t\t\tawait Settings.incrementValueById('WebRTC_Calls_Count');\n\t\t\t\tcallStatus = 'ringing';\n\t\t\t\tawait Rooms.setCallStatusAndCallStartTime(room._id, callStatus);\n\t\t\t\tawait Messages.createWithTypeRoomIdMessageAndUser(\n\t\t\t\t\t'livechat_webrtc_video_call',\n\t\t\t\t\troom._id,\n\t\t\t\t\tTAPi18n.__('Join_my_room_to_start_the_video_call'),\n\t\t\t\t\tthis.user,\n\t\t\t\t\t{\n\t\t\t\t\t\tactionLinks: config.theme.actionLinks.webrtc,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst videoCall = {\n\t\t\t\trid: room._id,\n\t\t\t\tprovider: 'webrtc',\n\t\t\t\tcallStatus,\n\t\t\t};\n\t\t\treturn API.v1.success({ videoCall });\n\t\t},\n\t},\n);\n\nAPI.v1.addRoute(\n\t'livechat/webrtc.call/:callId',\n\t{ authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isPUTWebRTCCallId },\n\t{\n\t\tasync put() {\n\t\t\tconst { callId } = this.urlParams;\n\t\t\tconst { rid, status } = this.bodyParams;\n\n\t\t\tconst room = canSendMessage(\n\t\t\t\trid,\n\t\t\t\t{\n\t\t\t\t\tuid: this.userId,\n\t\t\t\t\tusername: this.user.username,\n\t\t\t\t\ttype: this.user.type,\n\t\t\t\t},\n\t\t\t\t{},\n\t\t\t);\n\t\t\tif (!room) {\n\t\t\t\tthrow new Error('invalid-room');\n\t\t\t}\n\n\t\t\tconst call = await Messages.findOneById(callId);\n\t\t\tif (!call || call.t !== 'livechat_webrtc_video_call') {\n\t\t\t\tthrow new Error('invalid-callId');\n\t\t\t}\n\n\t\t\tLivechat.updateCallStatus(callId, rid, status, this.user);\n\n\t\t\treturn API.v1.success({ status });\n\t\t},\n\t},\n);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/visitor.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api/v1/webhooks.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/api.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/business-hour/AbstractBusinessHour.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/business-hour/BusinessHourManager.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/business-hour/Default.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/business-hour/Helper.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/business-hour/Single.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/business-hour/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/config.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/externalFrame/generateNewKey.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/externalFrame/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/externalFrame/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/afterUserActions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/beforeDelegateAgent.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/leadCapture.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/markRoomNotResponded.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/markRoomResponded.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/offlineMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/offlineMessageToChannel.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/saveAnalyticsData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/saveContactLastChat.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/saveLastMessageToInquiry.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/saveLastVisitorMessageTs.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/sendEmailTranscriptOnClose.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/hooks/sendToCRM.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/Analytics.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/Contacts.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/Departments.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/Helper.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/Livechat.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/LivechatTyped.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/LivechatTyped.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/QueueManager.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/RoutingManager.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/analytics/agents.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/analytics/dashboards.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/analytics/departments.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/callbackLogger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/routing/AutoSelection.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/routing/External.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/routing/ManualSelection.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/lib/stream/agentStatus.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/livechat.js",["22995","22996"],[],"import url from 'url';\n\nimport _ from 'underscore';\nimport { Meteor } from 'meteor/meteor';\nimport { WebApp } from 'meteor/webapp';\n\nimport { settings } from '../../settings/server';\nimport { addServerUrlToIndex } from '../lib/Assets';\n\nconst indexHtmlWithServerURL = addServerUrlToIndex(Assets.getText('livechat/index.html'));\n\nWebApp.connectHandlers.use(\n\t'/livechat',\n\tMeteor.bindEnvironment((req, res, next) => {\n\t\tconst reqUrl = url.parse(req.url);\n\t\tif (reqUrl.pathname !== '/') {\n\t\t\treturn next();\n\t\t}\n\n\t\tres.setHeader('content-type', 'text/html; charset=utf-8');\n\n\t\tlet domainWhiteList = settings.get('Livechat_AllowedDomainsList');\n\t\tif (req.headers.referer && !_.isEmpty(domainWhiteList.trim())) {\n\t\t\tdomainWhiteList = _.map(domainWhiteList.split(','), function (domain) {\n\t\t\t\treturn domain.trim();\n\t\t\t});\n\n\t\t\tconst referer = url.parse(req.headers.referer);\n\t\t\tif (!_.contains(domainWhiteList, referer.host)) {\n\t\t\t\tres.setHeader('Content-Security-Policy', \"frame-ancestors 'none'\");\n\t\t\t\treturn next();\n\t\t\t}\n\n\t\t\tres.setHeader('Content-Security-Policy', `frame-ancestors ${referer.protocol}//${referer.host}`);\n\t\t} else {\n\t\t\t// TODO need to remove inline scripts from this route to be able to enable CSP here as well\n\t\t\tres.removeHeader('Content-Security-Policy');\n\t\t}\n\n\t\tres.write(indexHtmlWithServerURL);\n\t\tres.end();\n\t}),\n);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/addAgent.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/addManager.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/changeLivechatStatus.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/closeRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/discardTranscript.ts",["22997"],[],"import { Meteor } from 'meteor/meteor';\nimport { check } from 'meteor/check';\nimport { LivechatRooms } from '@rocket.chat/models';\n\nimport { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';\n\nMeteor.methods({\n\tasync 'livechat:discardTranscript'(rid: string) {\n\t\tcheck(rid, String);\n\n\t\tconst user = Meteor.userId();\n\n\t\tif (!user || !(await hasPermissionAsync(user, 'send-omnichannel-chat-transcript'))) {\n\t\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', {\n\t\t\t\tmethod: 'livechat:requestTranscript',\n\t\t\t});\n\t\t}\n\n\t\tconst room = await LivechatRooms.findOneById(rid);\n\t\tif (!room || !room.open) {\n\t\t\tthrow new Meteor.Error('error-invalid-room', 'Invalid room', {\n\t\t\t\tmethod: 'livechat:discardTranscript',\n\t\t\t});\n\t\t}\n\n\t\tif (!room.transcriptRequest) {\n\t\t\tthrow new Meteor.Error('error-transcript-not-requested', 'No transcript requested for this chat', {\n\t\t\t\tmethod: 'livechat:discardTranscript',\n\t\t\t});\n\t\t}\n\n\t\tawait LivechatRooms.unsetEmailTranscriptRequestedByRoomId(rid);\n\n\t\treturn true;\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getAgentData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getAgentOverviewData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getAnalyticsChartData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getAnalyticsOverviewData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getCustomFields.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getDepartmentForwardRestrictions.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getFirstRoomMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getNextAgent.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getRoutingConfig.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/getTagsList.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/loadHistory.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/loginByToken.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/pageVisited.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/registerGuest.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeAgent.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeAllClosedRooms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeCustomField.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeDepartment.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeManager.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/removeTrigger.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/requestTranscript.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/returnAsInquiry.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveAgentInfo.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveAppearance.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveBusinessHour.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveCustomField.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveDepartment.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveDepartmentAgents.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveInfo.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveIntegration.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveSurveyFeedback.js",["22998","22999"],[],"import { Meteor } from 'meteor/meteor';\nimport { Match, check } from 'meteor/check';\nimport _ from 'underscore';\nimport { LivechatRooms, LivechatVisitors } from '@rocket.chat/models';\n\nimport { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';\n\nMeteor.methods({\n\tasync 'livechat:saveSurveyFeedback'(visitorToken, visitorRoom, formData) {\n\t\tmethodDeprecationLogger.warn('livechat:saveSurveyFeedback will be deprecated in future versions of Rocket.Chat');\n\n\t\tcheck(visitorToken, String);\n\t\tcheck(visitorRoom, String);\n\t\tcheck(formData, [Match.ObjectIncluding({ name: String, value: String })]);\n\n\t\tconst visitor = await LivechatVisitors.getVisitorByToken(visitorToken);\n\t\tconst room = await LivechatRooms.findOneById(visitorRoom);\n\n\t\tif (visitor !== undefined && room !== undefined && room.v !== undefined && room.v.token === visitor.token) {\n\t\t\tconst updateData = {};\n\t\t\tfor (const item of formData) {\n\t\t\t\tif (\n\t\t\t\t\t_.contains(['satisfaction', 'agentKnowledge', 'agentResposiveness', 'agentFriendliness'], item.name) &&\n\t\t\t\t\t_.contains(['1', '2', '3', '4', '5'], item.value)\n\t\t\t\t) {\n\t\t\t\t\tupdateData[item.name] = item.value;\n\t\t\t\t} else if (item.name === 'additionalFeedback') {\n\t\t\t\t\tupdateData[item.name] = item.value;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!_.isEmpty(updateData)) {\n\t\t\t\treturn LivechatRooms.updateSurveyFeedbackById(room._id, updateData);\n\t\t\t}\n\t\t}\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/saveTrigger.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/searchAgent.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/sendFileLivechatMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/sendMessageLivechat.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/sendOfflineMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/sendTranscript.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/setCustomField.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/setDepartmentForVisitor.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/setUpConnection.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/takeInquiry.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/transfer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/methods/webhookTest.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/roomAccessValidator.compatibility.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/roomAccessValidator.internalService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/sendMessageBySMS.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/startup.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/livechat/server/statistics/LivechatAgentActivityMonitor.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/logger/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/logger/client/logger.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/logger/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/logger/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mail-messages/server/functions/sendMail.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mail-messages/server/functions/unsubscribe.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mail-messages/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mail-messages/server/lib/Mailer.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mail-messages/server/methods/sendMail.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mail-messages/server/methods/unsubscribe.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mailer/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mailer/server/api.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mailer/server/replaceVariables.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mapview/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mapview/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/client/getGlobalWindow.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/getGlobalWindow.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/hljs.js",[],["23000"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/markdown.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/parser/filtered/filtered.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/parser/original/code.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/parser/original/markdown.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/parser/original/original.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/lib/parser/original/token.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/server/getGlobalWindow.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/markdown/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/client/client.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/lib/MentionsParser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/server/Mentions.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/server/methods/getUserMentionsByChannel.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/mentions/server/server.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-attachments/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-attachments/client/renderField.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-attachments/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-mark-as-unread/client/actionButton.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-mark-as-unread/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-mark-as-unread/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-mark-as-unread/server/logger.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-mark-as-unread/server/unreadMessages.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-pin/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-pin/server/pinMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-pin/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-pin/server/startup/indexes.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-star/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-star/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-star/server/starMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/message-star/server/startup/indexes.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/client/saml_client.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/IAttributeMapping.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/IAuthorizeRequestVariables.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ILogoutRequestVariables.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ILogoutResponse.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ILogoutResponseVariables.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/IMetadataVariables.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ISAMLAction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ISAMLAssertion.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ISAMLGlobalSettings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ISAMLRequest.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/ISAMLUser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/IServiceProviderOptions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/definition/callbacks.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/SAML.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/ServiceProvider.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/Utils.ts",["23001"],[],"import zlib from 'zlib';\nimport { EventEmitter } from 'events';\n\nimport _ from 'underscore';\n\nimport type { IServiceProviderOptions } from '../definition/IServiceProviderOptions';\nimport type { ISAMLUser } from '../definition/ISAMLUser';\nimport type { ISAMLGlobalSettings } from '../definition/ISAMLGlobalSettings';\nimport type { IUserDataMap, IAttributeMapping } from '../definition/IAttributeMapping';\nimport { StatusCode } from './constants';\nimport type { Logger } from '../../../../server/lib/logger/Logger';\nimport { ensureArray } from '../../../../lib/utils/arrayUtils';\n\nlet providerList: Array = [];\nlet debug = false;\nlet relayState: string | null = null;\nlet logger: Logger | undefined;\n\nconst globalSettings: ISAMLGlobalSettings = {\n\tgenerateUsername: false,\n\tnameOverwrite: false,\n\tmailOverwrite: false,\n\timmutableProperty: 'EMail',\n\tdefaultUserRole: 'user',\n\tuserDataFieldMap: '{\"username\":\"username\", \"email\":\"email\", \"cn\": \"name\"}',\n\tusernameNormalize: 'None',\n\tchannelsAttributeUpdate: false,\n\tincludePrivateChannelsInUpdate: false,\n};\n\nexport class SAMLUtils {\n\tpublic static events: EventEmitter;\n\n\tpublic static get isDebugging(): boolean {\n\t\treturn debug;\n\t}\n\n\tpublic static get globalSettings(): ISAMLGlobalSettings {\n\t\treturn globalSettings;\n\t}\n\n\tpublic static get serviceProviders(): Array {\n\t\treturn providerList;\n\t}\n\n\tpublic static get relayState(): string | null {\n\t\treturn relayState;\n\t}\n\n\tpublic static set relayState(value: string | null) {\n\t\trelayState = value;\n\t}\n\n\tpublic static getServiceProviderOptions(providerName: string): IServiceProviderOptions | undefined {\n\t\tthis.log(providerName, providerList);\n\n\t\treturn _.find(providerList, (providerOptions) => providerOptions.provider === providerName);\n\t}\n\n\tpublic static setServiceProvidersList(list: Array): void {\n\t\tproviderList = list;\n\t}\n\n\tpublic static setLoggerInstance(instance: Logger): void {\n\t\tlogger = instance;\n\t}\n\n\t// TODO: Some of those should probably not be global\n\tpublic static updateGlobalSettings(samlConfigs: Record): void {\n\t\tdebug = Boolean(samlConfigs.debug);\n\n\t\tglobalSettings.generateUsername = Boolean(samlConfigs.generateUsername);\n\t\tglobalSettings.nameOverwrite = Boolean(samlConfigs.nameOverwrite);\n\t\tglobalSettings.mailOverwrite = Boolean(samlConfigs.mailOverwrite);\n\t\tglobalSettings.channelsAttributeUpdate = Boolean(samlConfigs.channelsAttributeUpdate);\n\t\tglobalSettings.includePrivateChannelsInUpdate = Boolean(samlConfigs.includePrivateChannelsInUpdate);\n\n\t\tif (samlConfigs.immutableProperty && typeof samlConfigs.immutableProperty === 'string') {\n\t\t\tglobalSettings.immutableProperty = samlConfigs.immutableProperty;\n\t\t}\n\n\t\tif (samlConfigs.usernameNormalize && typeof samlConfigs.usernameNormalize === 'string') {\n\t\t\tglobalSettings.usernameNormalize = samlConfigs.usernameNormalize;\n\t\t}\n\n\t\tif (samlConfigs.defaultUserRole && typeof samlConfigs.defaultUserRole === 'string') {\n\t\t\tglobalSettings.defaultUserRole = samlConfigs.defaultUserRole;\n\t\t}\n\n\t\tif (samlConfigs.userDataFieldMap && typeof samlConfigs.userDataFieldMap === 'string') {\n\t\t\tglobalSettings.userDataFieldMap = samlConfigs.userDataFieldMap;\n\t\t}\n\t}\n\n\tpublic static generateUniqueID(): string {\n\t\tconst chars = 'abcdef0123456789';\n\t\tlet uniqueID = 'id-';\n\t\tfor (let i = 0; i < 20; i++) {\n\t\t\tuniqueID += chars.substr(Math.floor(Math.random() * 15), 1);\n\t\t}\n\t\treturn uniqueID;\n\t}\n\n\tpublic static generateInstant(): string {\n\t\treturn new Date().toISOString();\n\t}\n\n\tpublic static certToPEM(cert: string): string {\n\t\tconst lines = cert.match(/.{1,64}/g);\n\t\tif (!lines) {\n\t\t\tthrow new Error('Invalid Certificate');\n\t\t}\n\n\t\tlines.splice(0, 0, '-----BEGIN CERTIFICATE-----');\n\t\tlines.push('-----END CERTIFICATE-----');\n\n\t\treturn lines.join('\\n');\n\t}\n\n\tpublic static fillTemplateData(template: string, data: Record): string {\n\t\tlet newTemplate = template;\n\n\t\tfor (const variable in data) {\n\t\t\tif (variable in data) {\n\t\t\t\tconst key = `__${variable}__`;\n\t\t\t\twhile (newTemplate.includes(key)) {\n\t\t\t\t\tnewTemplate = newTemplate.replace(key, data[variable]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn newTemplate;\n\t}\n\n\tpublic static log(obj: any, ...args: Array): void {\n\t\tif (debug && logger) {\n\t\t\tlogger.debug(obj, ...args);\n\t\t}\n\t}\n\n\tpublic static error(obj: any, ...args: Array): void {\n\t\tif (logger) {\n\t\t\tlogger.error(obj, ...args);\n\t\t}\n\t}\n\n\tpublic static inflateXml(\n\t\tbase64Data: string,\n\t\tsuccessCallback: (xml: string) => void,\n\t\terrorCallback: (err: string | object | null) => void,\n\t): void {\n\t\tconst buffer = Buffer.from(base64Data, 'base64');\n\t\tzlib.inflateRaw(buffer, (err, decoded) => {\n\t\t\tif (err) {\n\t\t\t\tthis.log(`Error while inflating. ${err}`);\n\t\t\t\treturn errorCallback(err);\n\t\t\t}\n\n\t\t\tif (!decoded) {\n\t\t\t\treturn errorCallback('Failed to extract request data');\n\t\t\t}\n\n\t\t\tconst xmlString = this.convertArrayBufferToString(decoded);\n\t\t\treturn successCallback(xmlString);\n\t\t});\n\t}\n\n\tpublic static validateStatus(doc: Document): {\n\t\tsuccess: boolean;\n\t\tmessage: string;\n\t\tstatusCode: string;\n\t} {\n\t\tlet successStatus = false;\n\t\tlet status = null;\n\t\tlet messageText = '';\n\n\t\tconst statusNodes = doc.getElementsByTagNameNS('urn:oasis:names:tc:SAML:2.0:protocol', 'StatusCode');\n\n\t\tif (statusNodes.length) {\n\t\t\tconst statusNode = statusNodes[0];\n\t\t\tconst statusMessage = doc.getElementsByTagNameNS('urn:oasis:names:tc:SAML:2.0:protocol', 'StatusMessage')[0];\n\n\t\t\tif (statusMessage?.firstChild?.textContent) {\n\t\t\t\tmessageText = statusMessage.firstChild.textContent;\n\t\t\t}\n\n\t\t\tstatus = statusNode.getAttribute('Value');\n\n\t\t\tif (status === StatusCode.success) {\n\t\t\t\tsuccessStatus = true;\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tsuccess: successStatus,\n\t\t\tmessage: messageText,\n\t\t\tstatusCode: status || '',\n\t\t};\n\t}\n\n\tpublic static normalizeCert(cert: string): string {\n\t\tif (!cert) {\n\t\t\treturn cert;\n\t\t}\n\n\t\treturn cert\n\t\t\t.replace(/-+BEGIN CERTIFICATE-+\\r?\\n?/, '')\n\t\t\t.replace(/-+END CERTIFICATE-+\\r?\\n?/, '')\n\t\t\t.replace(/\\r\\n/g, '\\n')\n\t\t\t.trim();\n\t}\n\n\tpublic static getUserDataMapping(): IUserDataMap {\n\t\tconst { userDataFieldMap, immutableProperty } = globalSettings;\n\n\t\tlet map: Record;\n\n\t\ttry {\n\t\t\tmap = JSON.parse(userDataFieldMap);\n\t\t} catch (e) {\n\t\t\tSAMLUtils.log(userDataFieldMap);\n\t\t\tSAMLUtils.log(e);\n\t\t\tthrow new Error('Failed to parse custom user field map');\n\t\t}\n\n\t\tconst parsedMap: IUserDataMap = {\n\t\t\tattributeList: new Set(),\n\t\t\temail: {\n\t\t\t\tfieldName: 'email',\n\t\t\t},\n\t\t\tusername: {\n\t\t\t\tfieldName: 'username',\n\t\t\t},\n\t\t\tname: {\n\t\t\t\tfieldName: 'cn',\n\t\t\t},\n\t\t\tidentifier: {\n\t\t\t\ttype: '',\n\t\t\t},\n\t\t};\n\n\t\tlet identifier = immutableProperty.toLowerCase();\n\n\t\tfor (const spFieldName in map) {\n\t\t\tif (!map.hasOwnProperty(spFieldName)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst attribute = map[spFieldName];\n\t\t\tif (typeof attribute !== 'string' && typeof attribute !== 'object') {\n\t\t\t\tthrow new Error(`SAML User Map: Invalid configuration for ${spFieldName} field.`);\n\t\t\t}\n\n\t\t\tif (spFieldName === '__identifier__') {\n\t\t\t\tif (typeof attribute !== 'string') {\n\t\t\t\t\tthrow new Error('SAML User Map: Invalid identifier.');\n\t\t\t\t}\n\n\t\t\t\tidentifier = attribute;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet attributeMap: IAttributeMapping | null = null;\n\n\t\t\t// If it's a complex type, let's check what's in it\n\t\t\tif (typeof attribute === 'object') {\n\t\t\t\t// A fieldName is mandatory for complex fields. If it's missing, let's skip this one.\n\t\t\t\tif (!attribute.hasOwnProperty('fieldName') && !attribute.hasOwnProperty('fieldNames')) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst fieldName = attribute.fieldName || attribute.fieldNames;\n\t\t\t\tconst { regex, template } = attribute;\n\n\t\t\t\tif (Array.isArray(fieldName)) {\n\t\t\t\t\tif (!fieldName.length) {\n\t\t\t\t\t\tthrow new Error(`SAML User Map: Invalid configuration for ${spFieldName} field.`);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const idpFieldName of fieldName) {\n\t\t\t\t\t\tparsedMap.attributeList.add(idpFieldName);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tparsedMap.attributeList.add(fieldName);\n\t\t\t\t}\n\n\t\t\t\tif (regex && typeof regex !== 'string') {\n\t\t\t\t\tthrow new Error('SAML User Map: Invalid RegEx');\n\t\t\t\t}\n\n\t\t\t\tif (template && typeof template !== 'string') {\n\t\t\t\t\tthrow new Error('SAML User Map: Invalid Template');\n\t\t\t\t}\n\n\t\t\t\tattributeMap = {\n\t\t\t\t\tfieldName,\n\t\t\t\t\t...(regex && { regex }),\n\t\t\t\t\t...(template && { template }),\n\t\t\t\t};\n\t\t\t} else if (typeof attribute === 'string') {\n\t\t\t\tattributeMap = {\n\t\t\t\t\tfieldName: attribute,\n\t\t\t\t};\n\t\t\t\tparsedMap.attributeList.add(attribute);\n\t\t\t}\n\n\t\t\tif (attributeMap) {\n\t\t\t\tif (spFieldName === 'email' || spFieldName === 'username' || spFieldName === 'name') {\n\t\t\t\t\tparsedMap[spFieldName] = attributeMap;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (identifier) {\n\t\t\tconst defaultTypes = ['email', 'username'];\n\n\t\t\tif (defaultTypes.includes(identifier)) {\n\t\t\t\tparsedMap.identifier.type = identifier;\n\t\t\t} else {\n\t\t\t\tparsedMap.identifier.type = 'custom';\n\t\t\t\tparsedMap.identifier.attribute = identifier;\n\t\t\t\tparsedMap.attributeList.add(identifier);\n\t\t\t}\n\t\t}\n\t\treturn parsedMap;\n\t}\n\n\tpublic static getProfileValue(profile: Record, mapping: IAttributeMapping, forceString = false): any {\n\t\tconst values: Record = {\n\t\t\tregex: '',\n\t\t};\n\t\tconst fieldNames = ensureArray(mapping.fieldName);\n\n\t\tlet mainValue;\n\t\tfor (const fieldName of fieldNames) {\n\t\t\tlet profileValue = profile[fieldName];\n\n\t\t\tif (Array.isArray(profileValue)) {\n\t\t\t\tfor (let i = 0; i < profile[fieldName].length; i++) {\n\t\t\t\t\t// Add every index to the list of possible values to be used, both first to last and from last to first\n\t\t\t\t\tvalues[`${fieldName}[${i}]`] = profileValue[i];\n\t\t\t\t\tvalues[`${fieldName}[-${Math.abs(0 - profileValue.length + i)}]`] = profileValue[i];\n\t\t\t\t}\n\t\t\t\tvalues[`${fieldName}[]`] = profileValue.join(' ');\n\t\t\t\tif (forceString) {\n\t\t\t\t\tprofileValue = profileValue.join(' ');\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvalues[fieldName] = profileValue;\n\t\t\t}\n\n\t\t\tvalues[fieldName] = profileValue;\n\n\t\t\tif (!mainValue) {\n\t\t\t\tmainValue = profileValue;\n\t\t\t}\n\t\t}\n\n\t\tlet shouldRunTemplate = false;\n\t\tif (typeof mapping.template === 'string') {\n\t\t\t// unless the regex result is used on the template, we process the template first\n\t\t\tif (mapping.template.includes('__regex__')) {\n\t\t\t\tshouldRunTemplate = true;\n\t\t\t} else {\n\t\t\t\tmainValue = this.fillTemplateData(mapping.template, values);\n\t\t\t}\n\t\t}\n\n\t\tif (mapping.regex && mainValue && mainValue.match) {\n\t\t\tlet regexValue;\n\t\t\tconst match = mainValue.match(new RegExp(mapping.regex));\n\t\t\tif (match?.length) {\n\t\t\t\tif (match.length >= 2) {\n\t\t\t\t\tregexValue = match[1];\n\t\t\t\t} else {\n\t\t\t\t\tregexValue = match[0];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (regexValue) {\n\t\t\t\tvalues.regex = regexValue;\n\t\t\t\tif (!shouldRunTemplate) {\n\t\t\t\t\tmainValue = regexValue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (shouldRunTemplate && typeof mapping.template === 'string') {\n\t\t\tmainValue = this.fillTemplateData(mapping.template, values);\n\t\t}\n\n\t\treturn mainValue;\n\t}\n\n\tpublic static convertArrayBufferToString(buffer: ArrayBuffer, encoding: BufferEncoding = 'utf8'): string {\n\t\treturn Buffer.from(buffer).toString(encoding);\n\t}\n\n\tpublic static normalizeUsername(name: string): string {\n\t\tconst { globalSettings } = this;\n\n\t\tswitch (globalSettings.usernameNormalize) {\n\t\t\tcase 'Lowercase':\n\t\t\t\tname = name.toLowerCase();\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn name;\n\t}\n\n\tpublic static mapProfileToUserObject(profile: Record): ISAMLUser {\n\t\tconst userDataMap = this.getUserDataMapping();\n\t\tSAMLUtils.log('parsed userDataMap', userDataMap);\n\n\t\tif (userDataMap.identifier.type === 'custom') {\n\t\t\tif (!userDataMap.identifier.attribute) {\n\t\t\t\tthrow new Error('SAML User Data Map: invalid Identifier configuration received.');\n\t\t\t}\n\t\t\tif (!profile[userDataMap.identifier.attribute]) {\n\t\t\t\tthrow new Error(`SAML Profile did not have the expected identifier (${userDataMap.identifier.attribute}).`);\n\t\t\t}\n\t\t}\n\n\t\tconst attributeList = new Map();\n\t\tfor (const attributeName of userDataMap.attributeList) {\n\t\t\tif (profile[attributeName] === undefined) {\n\t\t\t\tthis.log(`SAML user profile is missing the attribute ${attributeName}.`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tattributeList.set(attributeName, profile[attributeName]);\n\t\t}\n\t\tconst email = this.getProfileValue(profile, userDataMap.email);\n\t\tconst profileUsername = this.getProfileValue(profile, userDataMap.username, true);\n\t\tconst name = this.getProfileValue(profile, userDataMap.name, true);\n\n\t\t// Even if we're not using the email to identify the user, it is still mandatory because it's a mandatory information on Rocket.Chat\n\t\tif (!email) {\n\t\t\tthrow new Error('SAML Profile did not contain an email address');\n\t\t}\n\n\t\tconst userObject: ISAMLUser = {\n\t\t\tsamlLogin: {\n\t\t\t\tprovider: this.relayState,\n\t\t\t\tidp: profile.issuer,\n\t\t\t\tidpSession: profile.sessionIndex,\n\t\t\t\tnameID: profile.nameID,\n\t\t\t},\n\t\t\temailList: ensureArray(email),\n\t\t\tfullName: name || profile.displayName || profile.username,\n\t\t\teppn: profile.eppn,\n\t\t\tattributeList,\n\t\t\tidentifier: userDataMap.identifier,\n\t\t};\n\n\t\tif (profileUsername) {\n\t\t\tuserObject.username = this.normalizeUsername(profileUsername);\n\t\t}\n\n\t\tif (profile.language) {\n\t\t\tuserObject.language = profile.language;\n\t\t}\n\n\t\tif (profile.channels) {\n\t\t\tif (Array.isArray(profile.channels)) {\n\t\t\t\tuserObject.channels = profile.channels;\n\t\t\t} else {\n\t\t\t\tuserObject.channels = profile.channels.split(',');\n\t\t\t}\n\t\t}\n\n\t\tthis.events.emit('mapUser', { profile, userObject });\n\n\t\treturn userObject;\n\t}\n}\n\nSAMLUtils.events = new EventEmitter();\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/constants.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/generators/AuthorizeRequest.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/generators/LogoutRequest.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/generators/LogoutResponse.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/generators/ServiceProviderMetadata.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/parsers/LogoutRequest.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/parsers/LogoutResponse.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/parsers/Response.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/lib/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/listener.ts",["23002"],[],"import type { IncomingMessage, ServerResponse } from 'http';\n\nimport { Meteor } from 'meteor/meteor';\nimport { WebApp } from 'meteor/webapp';\nimport { RoutePolicy } from 'meteor/routepolicy';\nimport bodyParser from 'body-parser';\nimport fiber from 'fibers';\nimport type { IIncomingMessage } from '@rocket.chat/core-typings';\n\nimport { SystemLogger } from '../../../server/lib/logger/system';\nimport { SAML } from './lib/SAML';\nimport { SAMLUtils } from './lib/Utils';\nimport type { ISAMLAction } from './definition/ISAMLAction';\n\nRoutePolicy.declare('/_saml/', 'network');\n\nconst samlUrlToObject = function (url: string | undefined): ISAMLAction | null {\n\t// req.url will be '/_saml///'\n\tif (!url) {\n\t\treturn null;\n\t}\n\n\tconst splitUrl = url.split('?');\n\tconst splitPath = splitUrl[0].split('/');\n\n\t// Any non-saml request will continue down the default\n\t// middlewares.\n\tif (splitPath[1] !== '_saml') {\n\t\treturn null;\n\t}\n\n\tconst result = {\n\t\tactionName: splitPath[2],\n\t\tserviceName: splitPath[3],\n\t\tcredentialToken: splitPath[4],\n\t};\n\n\tSAMLUtils.log(result);\n\treturn result;\n};\n\nconst middleware = function (req: IIncomingMessage, res: ServerResponse, next: (err?: any) => void): void {\n\t// Make sure to catch any exceptions because otherwise we'd crash\n\t// the runner\n\ttry {\n\t\tconst samlObject = samlUrlToObject(req.url);\n\t\tif (!samlObject || !samlObject.serviceName) {\n\t\t\tnext();\n\t\t\treturn;\n\t\t}\n\n\t\tif (!samlObject.actionName) {\n\t\t\tthrow new Error('Missing SAML action');\n\t\t}\n\n\t\tconst service = SAMLUtils.getServiceProviderOptions(samlObject.serviceName);\n\t\tif (!service) {\n\t\t\tSystemLogger.error(`${samlObject.serviceName} service provider not found`);\n\t\t\tthrow new Error('SAML Service Provider not found.');\n\t\t}\n\n\t\tSAML.processRequest(req, res, service, samlObject);\n\t} catch (err) {\n\t\t// @ToDo: Ideally we should send some error message to the client, but there's no way to do it on a redirect right now.\n\t\tSystemLogger.error(err);\n\n\t\tconst url = Meteor.absoluteUrl('home');\n\t\tres.writeHead(302, {\n\t\t\tLocation: url,\n\t\t});\n\t\tres.end();\n\t}\n};\n\n// Listen to incoming SAML http requests\nWebApp.connectHandlers.use(bodyParser.json()).use(function (req: IncomingMessage, res: ServerResponse, next: (err?: any) => void) {\n\t// Need to create a fiber since we're using synchronous http calls and nothing\n\t// else is wrapping this in a fiber automatically\n\tfiber(function () {\n\t\tmiddleware(req as IIncomingMessage, res, next);\n\t}).run();\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/loginHandler.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/methods/addSamlService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/methods/samlLogout.ts",["23003"],[],"import { Meteor } from 'meteor/meteor';\n\nimport { Users } from '../../../models/server';\nimport { SAMLServiceProvider } from '../lib/ServiceProvider';\nimport { SAMLUtils } from '../lib/Utils';\nimport type { IServiceProviderOptions } from '../definition/IServiceProviderOptions';\n\n/**\n * Fetch SAML provider configs for given 'provider'.\n */\nfunction getSamlServiceProviderOptions(provider: string): IServiceProviderOptions {\n\tif (!provider) {\n\t\tthrow new Meteor.Error('no-saml-provider', 'SAML internal error', {\n\t\t\tmethod: 'getSamlServiceProviderOptions',\n\t\t});\n\t}\n\n\tconst providers = SAMLUtils.serviceProviders;\n\n\tconst samlProvider = function (element: IServiceProviderOptions): boolean {\n\t\treturn element.provider === provider;\n\t};\n\n\treturn providers.filter(samlProvider)[0];\n}\n\nMeteor.methods({\n\tsamlLogout(provider: string) {\n\t\t// Make sure the user is logged in before we initiate SAML Logout\n\t\tif (!Meteor.userId()) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'samlLogout' });\n\t\t}\n\t\tconst providerConfig = getSamlServiceProviderOptions(provider);\n\n\t\tSAMLUtils.log({ msg: 'Logout request', providerConfig });\n\t\t// This query should respect upcoming array of SAML logins\n\t\tconst user = Users.getSAMLByIdAndSAMLProvider(Meteor.userId(), provider);\n\t\tif (!user || !user.services || !user.services.saml) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { nameID, idpSession } = user.services.saml;\n\t\tSAMLUtils.log({ msg: `NameID for user ${Meteor.userId()} found`, nameID });\n\n\t\tconst _saml = new SAMLServiceProvider(providerConfig);\n\n\t\tconst request = _saml.generateLogoutRequest({\n\t\t\tnameID: nameID || idpSession,\n\t\t\tsessionIndex: idpSession,\n\t\t});\n\n\t\tSAMLUtils.log('----Logout Request----');\n\t\tSAMLUtils.log(request);\n\n\t\t// request.request: actual XML SAML Request\n\t\t// request.id: comminucation id which will be mentioned in the ResponseTo field of SAMLResponse\n\n\t\tUsers.setSamlInResponseTo(Meteor.userId(), request.id);\n\n\t\tconst result = _saml.syncRequestToUrl(request.request, 'logout');\n\t\tSAMLUtils.log(`SAML Logout Request ${result}`);\n\n\t\treturn result;\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-accounts-saml/server/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-autocomplete/client/autocomplete-client.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-autocomplete/client/collection.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-autocomplete/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/meteor-autocomplete/client/templates.js",[],["23004","23005"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/metrics/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/metrics/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/metrics/server/lib/collectMetrics.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/metrics/server/lib/metrics.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/metrics/server/lib/statsTracker.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/Avatars.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/Base.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/CachedChannelList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/CachedChatRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/CachedChatSubscription.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/CachedUserList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/ChatMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/ChatPermissions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/ChatRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/ChatSubscription.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/CustomSounds.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/EmojiCustom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/Roles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/RoomRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/Uploads.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/UserAndRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/UserDataFiles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/UserRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/Users.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/client/models/WebdavAccounts.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/lib/setUpdatedAt.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/FederationEvents.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/FederationRoomEvents.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/ImportData.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/Imports.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/LivechatBusinessHours.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/LivechatDepartment.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/LivechatDepartmentAgents.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/LivechatInquiry.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/LivechatRooms.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/Messages.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/Rooms.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/Subscriptions.js",["23006"],[],"import { Meteor } from 'meteor/meteor';\nimport { Match } from 'meteor/check';\nimport _ from 'underscore';\nimport mem from 'mem';\n\nimport { Base } from './_Base';\nimport Rooms from './Rooms';\nimport Users from './Users';\nimport { getDefaultSubscriptionPref } from '../../../utils/lib/getDefaultSubscriptionPref';\n\nexport class Subscriptions extends Base {\n\tconstructor(...args) {\n\t\tsuper(...args);\n\n\t\tthis.tryEnsureIndex({ rid: 1 });\n\t\tthis.tryEnsureIndex({ rid: 1, ls: 1 });\n\t\tthis.tryEnsureIndex({ 'rid': 1, 'u._id': 1 }, { unique: 1 });\n\t\tthis.tryEnsureIndex({ 'rid': 1, 'u._id': 1, 'open': 1 });\n\t\tthis.tryEnsureIndex({ 'rid': 1, 'u.username': 1 });\n\t\tthis.tryEnsureIndex({ 'rid': 1, 'alert': 1, 'u._id': 1 });\n\t\tthis.tryEnsureIndex({ rid: 1, roles: 1 });\n\t\tthis.tryEnsureIndex({ 'u._id': 1, 'name': 1, 't': 1 });\n\t\tthis.tryEnsureIndex({ name: 1, t: 1 });\n\t\tthis.tryEnsureIndex({ open: 1 });\n\t\tthis.tryEnsureIndex({ alert: 1 });\n\t\tthis.tryEnsureIndex({ ts: 1 });\n\t\tthis.tryEnsureIndex({ ls: 1 });\n\t\tthis.tryEnsureIndex({ desktopNotifications: 1 }, { sparse: 1 });\n\t\tthis.tryEnsureIndex({ mobilePushNotifications: 1 }, { sparse: 1 });\n\t\tthis.tryEnsureIndex({ emailNotifications: 1 }, { sparse: 1 });\n\t\tthis.tryEnsureIndex({ autoTranslate: 1 }, { sparse: 1 });\n\t\tthis.tryEnsureIndex({ autoTranslateLanguage: 1 }, { sparse: 1 });\n\t\tthis.tryEnsureIndex({ 'userHighlights.0': 1 }, { sparse: 1 });\n\t\tthis.tryEnsureIndex({ prid: 1 });\n\t\tthis.tryEnsureIndex({ 'u._id': 1, 'open': 1, 'department': 1 });\n\n\t\tconst collectionObj = this.model.rawCollection();\n\t\tthis.distinct = Meteor.wrapAsync(collectionObj.distinct, collectionObj);\n\t}\n\n\tfindByRoomIds(roomIds) {\n\t\tconst query = {\n\t\t\trid: {\n\t\t\t\t$in: roomIds,\n\t\t\t},\n\t\t};\n\t\tconst options = {\n\t\t\tfields: {\n\t\t\t\t'u._id': 1,\n\t\t\t\t'rid': 1,\n\t\t\t},\n\t\t};\n\n\t\treturn this._db.find(query, options);\n\t}\n\n\tremoveByVisitorToken(token) {\n\t\tconst query = {\n\t\t\t'v.token': token,\n\t\t};\n\n\t\tthis.remove(query);\n\t}\n\n\tupdateAutoTranslateById(_id, autoTranslate) {\n\t\tconst query = {\n\t\t\t_id,\n\t\t};\n\n\t\tlet update;\n\t\tif (autoTranslate) {\n\t\t\tupdate = {\n\t\t\t\t$set: {\n\t\t\t\t\tautoTranslate,\n\t\t\t\t},\n\t\t\t};\n\t\t} else {\n\t\t\tupdate = {\n\t\t\t\t$unset: {\n\t\t\t\t\tautoTranslate: 1,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\treturn this.update(query, update);\n\t}\n\n\tupdateAutoTranslateLanguageById(_id, autoTranslateLanguage) {\n\t\tconst query = {\n\t\t\t_id,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tautoTranslateLanguage,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update);\n\t}\n\n\tgetAutoTranslateLanguagesByRoomAndNotUser(rid, userId) {\n\t\tconst query = {\n\t\t\trid,\n\t\t\t'u._id': { $ne: userId },\n\t\t\t'autoTranslate': true,\n\t\t};\n\t\treturn this.distinct('autoTranslateLanguage', query);\n\t}\n\n\t/**\n\t * @param {string} userId\n\t * @param {string} scope the value for the role scope (room id)\n\t */\n\troleBaseQuery(userId, scope) {\n\t\tif (scope == null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst query = { 'u._id': userId };\n\t\tif (scope !== undefined) {\n\t\t\tquery.rid = scope;\n\t\t}\n\t\treturn query;\n\t}\n\n\tfindByRidWithoutE2EKey(rid, options) {\n\t\tconst query = {\n\t\t\trid,\n\t\t\tE2EKey: {\n\t\t\t\t$exists: false,\n\t\t\t},\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\tupdateAudioNotificationValueById(_id, audioNotificationValue) {\n\t\tconst query = {\n\t\t\t_id,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\taudioNotificationValue,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update);\n\t}\n\n\tclearAudioNotificationValueById(_id) {\n\t\tconst query = {\n\t\t\t_id,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$unset: {\n\t\t\t\taudioNotificationValue: 1,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update);\n\t}\n\n\tupdateNotificationsPrefById(_id, notificationPref, notificationField, notificationPrefOrigin) {\n\t\tconst query = {\n\t\t\t_id,\n\t\t};\n\n\t\tconst update = {};\n\n\t\tif (notificationPref === null) {\n\t\t\tupdate.$unset = {\n\t\t\t\t[notificationField]: 1,\n\t\t\t\t[notificationPrefOrigin]: 1,\n\t\t\t};\n\t\t} else {\n\t\t\tupdate.$set = {\n\t\t\t\t[notificationField]: notificationPref.value,\n\t\t\t\t[notificationPrefOrigin]: notificationPref.origin,\n\t\t\t};\n\t\t}\n\n\t\treturn this.update(query, update);\n\t}\n\n\tupdateUnreadAlertById(_id, unreadAlert) {\n\t\tconst query = {\n\t\t\t_id,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tunreadAlert,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update);\n\t}\n\n\tupdateDisableNotificationsById(_id, disableNotifications) {\n\t\tconst query = {\n\t\t\t_id,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tdisableNotifications,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update);\n\t}\n\n\tupdateHideUnreadStatusById(_id, hideUnreadStatus) {\n\t\tconst query = {\n\t\t\t_id,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\thideUnreadStatus,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update);\n\t}\n\n\tupdateHideMentionStatusById(_id, hideMentionStatus) {\n\t\tconst query = {\n\t\t\t_id,\n\t\t};\n\n\t\tconst update =\n\t\t\thideMentionStatus === true\n\t\t\t\t? {\n\t\t\t\t\t\t$set: {\n\t\t\t\t\t\t\thideMentionStatus,\n\t\t\t\t\t\t},\n\t\t\t\t }\n\t\t\t\t: {\n\t\t\t\t\t\t$unset: {\n\t\t\t\t\t\t\thideMentionStatus: 1,\n\t\t\t\t\t\t},\n\t\t\t\t };\n\n\t\treturn this.update(query, update);\n\t}\n\n\tupdateMuteGroupMentions(_id, muteGroupMentions) {\n\t\tconst query = {\n\t\t\t_id,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tmuteGroupMentions,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update);\n\t}\n\n\tchangeDepartmentByRoomId(rid, department) {\n\t\tconst query = {\n\t\t\trid,\n\t\t};\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tdepartment,\n\t\t\t},\n\t\t};\n\n\t\tthis.update(query, update);\n\t}\n\n\tfindAlwaysNotifyDesktopUsersByRoomId(roomId) {\n\t\tconst query = {\n\t\t\trid: roomId,\n\t\t\tdesktopNotifications: 'all',\n\t\t};\n\n\t\treturn this.find(query);\n\t}\n\n\tfindDontNotifyDesktopUsersByRoomId(roomId) {\n\t\tconst query = {\n\t\t\trid: roomId,\n\t\t\tdesktopNotifications: 'nothing',\n\t\t};\n\n\t\treturn this.find(query);\n\t}\n\n\tfindAlwaysNotifyMobileUsersByRoomId(roomId) {\n\t\tconst query = {\n\t\t\trid: roomId,\n\t\t\tmobilePushNotifications: 'all',\n\t\t};\n\n\t\treturn this.find(query);\n\t}\n\n\tfindDontNotifyMobileUsersByRoomId(roomId) {\n\t\tconst query = {\n\t\t\trid: roomId,\n\t\t\tmobilePushNotifications: 'nothing',\n\t\t};\n\n\t\treturn this.find(query);\n\t}\n\n\tfindWithSendEmailByRoomId(roomId) {\n\t\tconst query = {\n\t\t\trid: roomId,\n\t\t\temailNotifications: {\n\t\t\t\t$exists: true,\n\t\t\t},\n\t\t};\n\n\t\treturn this.find(query, { fields: { emailNotifications: 1, u: 1 } });\n\t}\n\n\tresetUserE2EKey(userId) {\n\t\tthis.update(\n\t\t\t{ 'u._id': userId },\n\t\t\t{\n\t\t\t\t$unset: {\n\t\t\t\t\tE2EKey: '',\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tmulti: true,\n\t\t\t},\n\t\t);\n\t}\n\n\tfindByUserIdWithoutE2E(userId, options) {\n\t\tconst query = {\n\t\t\t'u._id': userId,\n\t\t\t'E2EKey': {\n\t\t\t\t$exists: false,\n\t\t\t},\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\t/**\n\t * @param {IRole['_id'][]} roles\n\t * @param {string} scope the value for the role scope (room id)\n\t * @param {any} options\n\t */\n\tfindUsersInRoles(roles, scope, options) {\n\t\troles = [].concat(roles);\n\n\t\tconst query = {\n\t\t\troles: { $in: roles },\n\t\t};\n\n\t\tif (scope) {\n\t\t\tquery.rid = scope;\n\t\t}\n\n\t\tconst subscriptions = this.find(query).fetch();\n\n\t\tconst users = _.compact(\n\t\t\t_.map(subscriptions, function (subscription) {\n\t\t\t\tif (typeof subscription.u !== 'undefined' && typeof subscription.u._id !== 'undefined') {\n\t\t\t\t\treturn subscription.u._id;\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\treturn Users.find({ _id: { $in: users } }, options);\n\t}\n\n\t// FIND ONE\n\tfindOneByRoomIdAndUserId(roomId, userId, options = {}) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': userId,\n\t\t};\n\n\t\treturn this.findOne(query, options);\n\t}\n\n\tfindOneByRoomIdAndUsername(roomId, username, options) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u.username': username,\n\t\t};\n\n\t\treturn this.findOne(query, options);\n\t}\n\n\tfindOneByRoomNameAndUserId(roomName, userId) {\n\t\tconst query = {\n\t\t\t'name': roomName,\n\t\t\t'u._id': userId,\n\t\t};\n\n\t\treturn this.findOne(query);\n\t}\n\n\t// FIND\n\tfindByUserId(userId, options) {\n\t\tconst query = { 'u._id': userId };\n\n\t\treturn this.find(query, options);\n\t}\n\n\tcachedFindByUserId = mem(this.findByUserId.bind(this), { maxAge: 5000 });\n\n\tfindByUserIdExceptType(userId, typeException, options) {\n\t\tconst query = {\n\t\t\t'u._id': userId,\n\t\t\t't': { $ne: typeException },\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\tfindByUserIdAndRoomIds(userId, roomIds, options) {\n\t\tconst query = {\n\t\t\t'u._id': userId,\n\t\t\t'rid': { $in: roomIds },\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\tfindByUserIdAndType(userId, type, options) {\n\t\tconst query = {\n\t\t\t'u._id': userId,\n\t\t\t't': type,\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\tfindByUserIdAndTypes(userId, types, options) {\n\t\tconst query = {\n\t\t\t'u._id': userId,\n\t\t\t't': {\n\t\t\t\t$in: types,\n\t\t\t},\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\t/**\n\t * @param {IUser['_id']} userId\n\t * @param {IRole['_id'][]} roles\n\t * @param {any} options\n\t */\n\tfindByUserIdAndRoles(userId, roles, options) {\n\t\tconst query = {\n\t\t\t'u._id': userId,\n\t\t\t'roles': { $in: roles },\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\tfindByUserIdUpdatedAfter(userId, updatedAt, options) {\n\t\tconst query = {\n\t\t\t'u._id': userId,\n\t\t\t'_updatedAt': {\n\t\t\t\t$gt: updatedAt,\n\t\t\t},\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\t/**\n\t * @param {string} roomId\n\t * @param {IRole['_id'][]} roles the list of roles\n\t * @param {any} options\n\t */\n\tfindByRoomIdAndRoles(roomId, roles, options = undefined) {\n\t\troles = [].concat(roles);\n\t\tconst query = {\n\t\t\trid: roomId,\n\t\t\troles: { $in: roles },\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\tfindByType(types, options) {\n\t\tconst query = {\n\t\t\tt: {\n\t\t\t\t$in: types,\n\t\t\t},\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\tfindByTypeAndUserId(type, userId, options) {\n\t\tconst query = {\n\t\t\t't': type,\n\t\t\t'u._id': userId,\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\tfindByRoomId(roomId, options) {\n\t\tconst query = { rid: roomId };\n\t\treturn this.find(query, options);\n\t}\n\n\tfindByRoomIdAndNotUserId(roomId, userId, options = {}) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': {\n\t\t\t\t$ne: userId,\n\t\t\t},\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\tfindByRoomWithUserHighlights(roomId, options) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'userHighlights.0': { $exists: true },\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\tgetLastSeen(options = { fields: { _id: 0, ls: 1 } }) {\n\t\toptions.sort = { ls: -1 };\n\t\toptions.limit = 1;\n\t\tconst [subscription] = this.find({}, options).fetch();\n\t\treturn subscription?.ls;\n\t}\n\n\tfindByRoomIdAndUserIds(roomId, userIds, options) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': {\n\t\t\t\t$in: userIds,\n\t\t\t},\n\t\t};\n\n\t\treturn this.find(query, options);\n\t}\n\n\tfindByRoomIdAndUserIdsOrAllMessages(roomId, userIds) {\n\t\tconst query = {\n\t\t\trid: roomId,\n\t\t\t$or: [{ 'u._id': { $in: userIds } }, { emailNotifications: 'all' }],\n\t\t};\n\n\t\treturn this.find(query);\n\t}\n\n\tfindByRoomIdWhenUserIdExists(rid, options) {\n\t\tconst query = { rid, 'u._id': { $exists: 1 } };\n\n\t\treturn this.find(query, options);\n\t}\n\n\tfindByRoomIdWhenUsernameExists(rid, options) {\n\t\tconst query = { rid, 'u.username': { $exists: 1 } };\n\n\t\treturn this.find(query, options);\n\t}\n\n\tfindUnreadByUserId(userId) {\n\t\tconst query = {\n\t\t\t'u._id': userId,\n\t\t\t'unread': {\n\t\t\t\t$gt: 0,\n\t\t\t},\n\t\t};\n\n\t\treturn this.find(query, { fields: { unread: 1 } });\n\t}\n\n\tgetMinimumLastSeenByRoomId(rid) {\n\t\treturn this.db.findOne(\n\t\t\t{\n\t\t\t\trid,\n\t\t\t},\n\t\t\t{\n\t\t\t\tsort: {\n\t\t\t\t\tls: 1,\n\t\t\t\t},\n\t\t\t\tfields: {\n\t\t\t\t\tls: 1,\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t}\n\n\t// UPDATE\n\tarchiveByRoomId(roomId) {\n\t\tconst query = { rid: roomId };\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\talert: false,\n\t\t\t\topen: false,\n\t\t\t\tarchived: true,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tunarchiveByRoomId(roomId) {\n\t\tconst query = { rid: roomId };\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\talert: false,\n\t\t\t\topen: true,\n\t\t\t\tarchived: false,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\thideByRoomIdAndUserId(roomId, userId) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': userId,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\talert: false,\n\t\t\t\topen: false,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update);\n\t}\n\n\topenByRoomIdAndUserId(roomId, userId) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': userId,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\topen: true,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update);\n\t}\n\n\tsetAsUnreadByRoomIdAndUserId(roomId, userId, firstMessageUnreadTimestamp) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': userId,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\topen: true,\n\t\t\t\talert: true,\n\t\t\t\tls: firstMessageUnreadTimestamp,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update);\n\t}\n\n\tsetCustomFieldsDirectMessagesByUserId(userId, fields) {\n\t\tconst query = {\n\t\t\t'u._id': userId,\n\t\t\t't': 'd',\n\t\t};\n\t\tconst update = { $set: { customFields: fields } };\n\t\tconst options = { multi: true };\n\n\t\treturn this.update(query, update, options);\n\t}\n\n\tsetFavoriteByRoomIdAndUserId(roomId, userId, favorite) {\n\t\tif (favorite == null) {\n\t\t\tfavorite = true;\n\t\t}\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': userId,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tf: favorite,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update);\n\t}\n\n\tupdateNameAndAlertByRoomId(roomId, name, fname) {\n\t\tconst query = { rid: roomId };\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tname,\n\t\t\t\tfname,\n\t\t\t\talert: true,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tupdateDisplayNameByRoomId(roomId, fname) {\n\t\tconst query = { rid: roomId };\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tfname,\n\t\t\t\tname: fname,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tupdateFnameByRoomId(rid, fname) {\n\t\tconst query = { rid };\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tfname,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tupdateNameAndFnameById(_id, name, fname) {\n\t\tconst query = { _id };\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tname,\n\t\t\t\tfname,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tsetUserUsernameByUserId(userId, username) {\n\t\tconst query = { 'u._id': userId };\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\t'u.username': username,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tsetNameForDirectRoomsWithOldName(oldName, name) {\n\t\tconst query = {\n\t\t\tname: oldName,\n\t\t\tt: 'd',\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tname,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tupdateDirectNameAndFnameByName(name, newName, newFname) {\n\t\tconst query = {\n\t\t\tname,\n\t\t\tt: 'd',\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\t...(newName && { name: newName }),\n\t\t\t\t...(newFname && { fname: newFname }),\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tincUnreadForRoomIdExcludingUserIds(roomId, userIds, inc) {\n\t\tif (inc == null) {\n\t\t\tinc = 1;\n\t\t}\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': {\n\t\t\t\t$nin: userIds,\n\t\t\t},\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\talert: true,\n\t\t\t\topen: true,\n\t\t\t},\n\t\t\t$inc: {\n\t\t\t\tunread: inc,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tincGroupMentionsAndUnreadForRoomIdExcludingUserId(roomId, userId, incGroup = 1, incUnread = 1) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': {\n\t\t\t\t$ne: userId,\n\t\t\t},\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\talert: true,\n\t\t\t\topen: true,\n\t\t\t},\n\t\t\t$inc: {\n\t\t\t\tunread: incUnread,\n\t\t\t\tgroupMentions: incGroup,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tincUserMentionsAndUnreadForRoomIdAndUserIds(roomId, userIds, incUser = 1, incUnread = 1) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': {\n\t\t\t\t$in: userIds,\n\t\t\t},\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\talert: true,\n\t\t\t\topen: true,\n\t\t\t},\n\t\t\t$inc: {\n\t\t\t\tunread: incUnread,\n\t\t\t\tuserMentions: incUser,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tignoreUser({ _id, ignoredUser: ignored, ignore = true }) {\n\t\tconst query = {\n\t\t\t_id,\n\t\t};\n\t\tconst update = {};\n\t\tif (ignore) {\n\t\t\tupdate.$addToSet = { ignored };\n\t\t} else {\n\t\t\tupdate.$pull = { ignored };\n\t\t}\n\n\t\treturn this.update(query, update);\n\t}\n\n\tsetAlertForRoomIdExcludingUserId(roomId, userId) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': {\n\t\t\t\t$ne: userId,\n\t\t\t},\n\t\t\t'alert': { $ne: true },\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\talert: true,\n\t\t\t},\n\t\t};\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tsetOpenForRoomIdExcludingUserId(roomId, userId) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': {\n\t\t\t\t$ne: userId,\n\t\t\t},\n\t\t\t'open': { $ne: true },\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\topen: true,\n\t\t\t},\n\t\t};\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tsetAlertForRoomIdAndUserIds(roomId, uids) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': { $in: uids },\n\t\t\t'alert': { $ne: true },\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\talert: true,\n\t\t\t},\n\t\t};\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tsetOpenForRoomIdAndUserIds(roomId, uids) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': { $in: uids },\n\t\t\t'open': { $ne: true },\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\topen: true,\n\t\t\t},\n\t\t};\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tsetLastReplyForRoomIdAndUserIds(roomId, uids, lr) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': { $in: uids },\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tlr,\n\t\t\t},\n\t\t};\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tsetBlockedByRoomId(rid, blocked, blocker) {\n\t\tconst query = {\n\t\t\trid,\n\t\t\t'u._id': blocked,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tblocked: true,\n\t\t\t},\n\t\t};\n\n\t\tconst query2 = {\n\t\t\trid,\n\t\t\t'u._id': blocker,\n\t\t};\n\n\t\tconst update2 = {\n\t\t\t$set: {\n\t\t\t\tblocker: true,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update) && this.update(query2, update2);\n\t}\n\n\tunsetBlockedByRoomId(rid, blocked, blocker) {\n\t\tconst query = {\n\t\t\trid,\n\t\t\t'u._id': blocked,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$unset: {\n\t\t\t\tblocked: 1,\n\t\t\t},\n\t\t};\n\n\t\tconst query2 = {\n\t\t\trid,\n\t\t\t'u._id': blocker,\n\t\t};\n\n\t\tconst update2 = {\n\t\t\t$unset: {\n\t\t\t\tblocker: 1,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update) && this.update(query2, update2);\n\t}\n\n\tupdateCustomFieldsByRoomId(rid, cfields) {\n\t\tconst query = { rid };\n\t\tconst customFields = cfields || {};\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tcustomFields,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tupdateTypeByRoomId(roomId, type) {\n\t\tconst query = { rid: roomId };\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tt: type,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\t/**\n\t * @param {string} _id the subscription id\n\t * @param {IRole['_id']} role the id of the role\n\t */\n\taddRoleById(_id, role) {\n\t\tconst query = { _id };\n\n\t\tconst update = {\n\t\t\t$addToSet: {\n\t\t\t\troles: role,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update);\n\t}\n\n\t/**\n\t * @param {string} _id the subscription id\n\t * @param {IRole['_id']} role the id of the role\n\t */\n\tremoveRoleById(_id, role) {\n\t\tconst query = { _id };\n\n\t\tconst update = {\n\t\t\t$pull: {\n\t\t\t\troles: role,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update);\n\t}\n\n\tsetArchivedByUsername(username, archived) {\n\t\tconst query = {\n\t\t\tt: 'd',\n\t\t\tname: username,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tarchived,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tclearNotificationUserPreferences(userId, notificationField, notificationOriginField) {\n\t\tconst query = {\n\t\t\t'u._id': userId,\n\t\t\t[notificationOriginField]: 'user',\n\t\t};\n\n\t\tconst update = {\n\t\t\t$unset: {\n\t\t\t\t[notificationOriginField]: 1,\n\t\t\t\t[notificationField]: 1,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tupdateNotificationUserPreferences(userId, userPref, notificationField, notificationOriginField) {\n\t\tconst query = {\n\t\t\t'u._id': userId,\n\t\t\t[notificationOriginField]: {\n\t\t\t\t$ne: 'subscription',\n\t\t\t},\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\t[notificationField]: userPref,\n\t\t\t\t[notificationOriginField]: 'user',\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tupdateUserHighlights(userId, userHighlights) {\n\t\tconst query = {\n\t\t\t'u._id': userId,\n\t\t};\n\n\t\tconst update = {\n\t\t\t$set: {\n\t\t\t\tuserHighlights,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\tupdateDirectFNameByName(name, fname) {\n\t\tconst query = {\n\t\t\tt: 'd',\n\t\t\tname,\n\t\t};\n\n\t\tlet update;\n\t\tif (fname) {\n\t\t\tupdate = {\n\t\t\t\t$set: {\n\t\t\t\t\tfname,\n\t\t\t\t},\n\t\t\t};\n\t\t} else {\n\t\t\tupdate = {\n\t\t\t\t$unset: {\n\t\t\t\t\tfname: true,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n\n\t// INSERT\n\tcreateWithRoomAndUser(room, user, extraData) {\n\t\tconst subscription = {\n\t\t\topen: false,\n\t\t\talert: false,\n\t\t\tunread: 0,\n\t\t\tuserMentions: 0,\n\t\t\tgroupMentions: 0,\n\t\t\tts: room.ts,\n\t\t\trid: room._id,\n\t\t\tname: room.name,\n\t\t\tfname: room.fname,\n\t\t\tcustomFields: room.customFields,\n\t\t\tt: room.t,\n\t\t\tu: {\n\t\t\t\t_id: user._id,\n\t\t\t\tusername: user.username,\n\t\t\t\tname: user.name,\n\t\t\t},\n\t\t\t...getDefaultSubscriptionPref(user),\n\t\t\t...extraData,\n\t\t};\n\n\t\tif (room.prid) {\n\t\t\tsubscription.prid = room.prid;\n\t\t}\n\n\t\tconst result = this.insert(subscription);\n\n\t\tRooms.incUsersCountById(room._id);\n\n\t\tif (!['d', 'l'].includes(room.t)) {\n\t\t\tUsers.addRoomByUserId(user._id, room._id);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t// REMOVE\n\tremoveByUserId(userId) {\n\t\tconst query = {\n\t\t\t'u._id': userId,\n\t\t};\n\n\t\tconst roomIds = this.findByUserId(userId).map((s) => s.rid);\n\n\t\tconst result = this.remove(query);\n\n\t\tif (Match.test(result, Number) && result > 0) {\n\t\t\tRooms.incUsersCountNotDMsByIds(roomIds, -1);\n\t\t}\n\n\t\tUsers.removeAllRoomsByUserId(userId);\n\n\t\treturn result;\n\t}\n\n\tremoveByRoomId(roomId) {\n\t\tconst query = {\n\t\t\trid: roomId,\n\t\t};\n\n\t\tconst result = this.remove(query);\n\n\t\tif (Match.test(result, Number) && result > 0) {\n\t\t\tRooms.incUsersCountById(roomId, -result);\n\t\t}\n\n\t\tUsers.removeRoomByRoomId(roomId);\n\n\t\treturn result;\n\t}\n\n\tremoveByRoomIdAndUserId(roomId, userId) {\n\t\tconst query = {\n\t\t\t'rid': roomId,\n\t\t\t'u._id': userId,\n\t\t};\n\n\t\tconst result = this.remove(query);\n\n\t\tif (Match.test(result, Number) && result > 0) {\n\t\t\tRooms.incUsersCountById(roomId, -result);\n\t\t}\n\n\t\tUsers.removeRoomByUserId(userId, roomId);\n\n\t\treturn result;\n\t}\n\n\tremoveByRoomIds(rids) {\n\t\tconst result = this.remove({ rid: { $in: rids } });\n\n\t\tUsers.removeRoomByRoomIds(rids);\n\n\t\treturn result;\n\t}\n\n\tremoveByRoomIdsAndUserId(rids, userId) {\n\t\tconst result = this.remove({ 'rid': { $in: rids }, 'u._id': userId });\n\n\t\tif (Match.test(result, Number) && result > 0) {\n\t\t\tRooms.incUsersCountByIds(rids, -1);\n\t\t}\n\n\t\tUsers.removeRoomsByRoomIdsAndUserId(rids, userId);\n\n\t\treturn result;\n\t}\n\n\t// //////////////////////////////////////////////////////////////////\n\t// threads\n\n\taddUnreadThreadByRoomIdAndUserIds(rid, users, tmid, { groupMention = false, userMention = false } = {}) {\n\t\tif (!users) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn this.update(\n\t\t\t{\n\t\t\t\t'u._id': { $in: users },\n\t\t\t\trid,\n\t\t\t},\n\t\t\t{\n\t\t\t\t$addToSet: {\n\t\t\t\t\ttunread: tmid,\n\t\t\t\t\t...(groupMention && { tunreadGroup: tmid }),\n\t\t\t\t\t...(userMention && { tunreadUser: tmid }),\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ multi: true },\n\t\t);\n\t}\n\n\tremoveUnreadThreadByRoomIdAndUserId(rid, userId, tmid, clearAlert = false) {\n\t\tconst update = {\n\t\t\t$pull: {\n\t\t\t\ttunread: tmid,\n\t\t\t\ttunreadGroup: tmid,\n\t\t\t\ttunreadUser: tmid,\n\t\t\t},\n\t\t};\n\n\t\tif (clearAlert) {\n\t\t\tupdate.$set = { alert: false };\n\t\t}\n\n\t\treturn this.update(\n\t\t\t{\n\t\t\t\t'u._id': userId,\n\t\t\t\trid,\n\t\t\t},\n\t\t\tupdate,\n\t\t);\n\t}\n\n\tremoveUnreadThreadsByRoomId(rid, tunread) {\n\t\tconst query = {\n\t\t\trid,\n\t\t\ttunread: { $in: tunread },\n\t\t};\n\n\t\tconst update = {\n\t\t\t$pullAll: {\n\t\t\t\ttunread,\n\t\t\t\ttunreadUser: tunread,\n\t\t\t\ttunreadGroup: tunread,\n\t\t\t},\n\t\t};\n\n\t\treturn this.update(query, update, { multi: true });\n\t}\n}\n\nexport default new Subscriptions('subscription', true);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/Users.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/_Base.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/_BaseDb.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/apps-logs-model.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/apps-model.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/models/server/models/apps-persistence-model.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/nextcloud/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/nextcloud/lib/common.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/nextcloud/server/addWebdavServer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/nextcloud/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/nextcloud/server/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notification-queue/server/NotificationQueue.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/client/lib/Notifications.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/client/lib/Presence.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/server/lib/Notifications.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/notifications/server/lib/Presence.ts",[],["23007"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/admin/functions/addOAuthApp.ts",["23008"],[],"import { Meteor } from 'meteor/meteor';\nimport { Random } from 'meteor/random';\nimport { OAuthApps, Users } from '@rocket.chat/models';\nimport type { OauthAppsAddParams } from '@rocket.chat/rest-typings';\nimport type { IOAuthApps, IUser } from '@rocket.chat/core-typings';\n\nimport { hasPermission } from '../../../../authorization/server';\nimport { parseUriList } from './parseUriList';\n\nexport async function addOAuthApp(applicationParams: OauthAppsAddParams, uid: IUser['_id'] | undefined): Promise {\n\tif (!uid) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'addOAuthApp' });\n\t}\n\n\tconst user = await Users.findOne(uid, { projection: { username: 1 } });\n\n\tif (!user || !user.username) {\n\t\t// TODO: username is required, but not always present\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'addOAuthApp' });\n\t}\n\n\tif (!hasPermission(uid, 'manage-oauth-apps')) {\n\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'addOAuthApp' });\n\t}\n\n\tif (!applicationParams.name || typeof applicationParams.name.valueOf() !== 'string' || applicationParams.name.trim() === '') {\n\t\tthrow new Meteor.Error('error-invalid-name', 'Invalid name', { method: 'addOAuthApp' });\n\t}\n\n\tif (\n\t\t!applicationParams.redirectUri ||\n\t\ttypeof applicationParams.redirectUri.valueOf() !== 'string' ||\n\t\tapplicationParams.redirectUri.trim() === ''\n\t) {\n\t\tthrow new Meteor.Error('error-invalid-redirectUri', 'Invalid redirectUri', {\n\t\t\tmethod: 'addOAuthApp',\n\t\t});\n\t}\n\n\tif (typeof applicationParams.active !== 'boolean') {\n\t\tthrow new Meteor.Error('error-invalid-arguments', 'Invalid arguments', {\n\t\t\tmethod: 'addOAuthApp',\n\t\t});\n\t}\n\n\tconst application = {\n\t\t...applicationParams,\n\t\tredirectUri: parseUriList(applicationParams.redirectUri),\n\t\tclientId: Random.id(),\n\t\tclientSecret: Random.secret(),\n\t\t_createdAt: new Date(),\n\t\t_updatedAt: new Date(),\n\t\t_createdBy: {\n\t\t\t_id: user._id,\n\t\t\tusername: user.username,\n\t\t},\n\t};\n\n\tif (application.redirectUri.length === 0) {\n\t\tthrow new Meteor.Error('error-invalid-redirectUri', 'Invalid redirectUri', {\n\t\t\tmethod: 'addOAuthApp',\n\t\t});\n\t}\n\n\treturn {\n\t\t...application,\n\t\t_id: (await OAuthApps.insertOne(application)).insertedId,\n\t};\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/admin/functions/parseUriList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/admin/methods/addOAuthApp.ts",[],["23009"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/admin/methods/deleteOAuthApp.ts",[],["23010"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/admin/methods/updateOAuthApp.ts",[],["23011"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/oauth/default-services.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oauth2-server-config/server/oauth/oauth2-server.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oembed/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oembed/server/jumpToMessage.ts",["23012","23013"],[],"import URL from 'url';\nimport QueryString from 'querystring';\n\nimport { Meteor } from 'meteor/meteor';\nimport type { ITranslatedMessage, MessageAttachment } from '@rocket.chat/core-typings';\nimport { isQuoteAttachment } from '@rocket.chat/core-typings';\n\nimport { createQuoteAttachment } from '../../../lib/createQuoteAttachment';\nimport { Messages, Rooms, Users } from '../../models/server';\nimport { settings } from '../../settings/server';\nimport { callbacks } from '../../../lib/callbacks';\nimport { canAccessRoom } from '../../authorization/server/functions/canAccessRoom';\n\nconst recursiveRemove = (attachments: MessageAttachment, deep = 1): MessageAttachment => {\n\tif (attachments && isQuoteAttachment(attachments)) {\n\t\tif (deep < settings.get('Message_QuoteChainLimit')) {\n\t\t\tattachments.attachments?.map((msg) => recursiveRemove(msg, deep + 1));\n\t\t} else {\n\t\t\tdelete attachments.attachments;\n\t\t}\n\t}\n\n\treturn attachments;\n};\n\nconst validateAttachmentDeepness = (message: ITranslatedMessage): ITranslatedMessage => {\n\tif (!message || !message.attachments) {\n\t\treturn message;\n\t}\n\n\tmessage.attachments = message.attachments?.map((attachment) => recursiveRemove(attachment));\n\n\treturn message;\n};\n\ncallbacks.add(\n\t'beforeSaveMessage',\n\t(msg) => {\n\t\t// if no message is present, or the message doesn't have any URL, skip\n\t\tif (!msg || !msg.urls || !msg.urls.length) {\n\t\t\treturn msg;\n\t\t}\n\n\t\tconst currentUser = Users.findOneById(msg.u._id);\n\n\t\tmsg.urls.forEach((item) => {\n\t\t\t// if the URL is not internal, skip\n\t\t\tif (!item.url.includes(Meteor.absoluteUrl())) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst urlObj = URL.parse(item.url);\n\n\t\t\t// if the URL doesn't have query params (doesn't reference message) skip\n\t\t\tif (!urlObj.query) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { msg: msgId } = QueryString.parse(urlObj.query);\n\n\t\t\tif (typeof msgId !== 'string') {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst jumpToMessage = validateAttachmentDeepness(Messages.findOneById(msgId));\n\t\t\tif (!jumpToMessage) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// validates if user can see the message\n\t\t\t// user has to belong to the room the message was first wrote in\n\t\t\tconst room = Rooms.findOneById(jumpToMessage.rid);\n\t\t\tconst isLiveChatRoomVisitor = !!msg.token && !!room.v?.token && msg.token === room.v.token;\n\t\t\tconst canAccessRoomForUser = isLiveChatRoomVisitor || canAccessRoom(room, currentUser);\n\t\t\tif (!canAccessRoomForUser) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmsg.attachments = msg.attachments || [];\n\t\t\t// Only QuoteAttachments have \"message_link\" property\n\t\t\tconst index = msg.attachments.findIndex((a) => isQuoteAttachment(a) && a.message_link === item.url);\n\t\t\tif (index > -1) {\n\t\t\t\tmsg.attachments.splice(index, 1);\n\t\t\t}\n\n\t\t\tmsg.attachments.push(createQuoteAttachment(jumpToMessage, item.url));\n\t\t\titem.ignoreParse = true;\n\t\t});\n\n\t\treturn msg;\n\t},\n\tcallbacks.priority.LOW,\n\t'jumpToMessage',\n);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oembed/server/providers.ts",["23014","23015"],[],"import URL from 'url';\nimport QueryString from 'querystring';\n\nimport { camelCase } from 'change-case';\nimport _ from 'underscore';\nimport type { OEmbedMeta, OEmbedUrlContent, ParsedUrl, OEmbedProvider } from '@rocket.chat/core-typings';\n\nimport { callbacks } from '../../../lib/callbacks';\nimport { SystemLogger } from '../../../server/lib/logger/system';\n\ntype OEmbedExecutor = {\n\tproviders: Providers;\n};\n\nclass Providers {\n\tprivate providers: OEmbedProvider[];\n\n\tconstructor() {\n\t\tthis.providers = [];\n\t}\n\n\tstatic getConsumerUrl(provider: OEmbedProvider, url: string): string {\n\t\tconst urlObj = new URL.URL(provider.endPoint);\n\t\turlObj.searchParams.set('url', url);\n\n\t\treturn URL.format(urlObj);\n\t}\n\n\tregisterProvider(provider: OEmbedProvider): number {\n\t\treturn this.providers.push(provider);\n\t}\n\n\tgetProviders(): OEmbedProvider[] {\n\t\treturn this.providers;\n\t}\n\n\tgetProviderForUrl(url: string): OEmbedProvider | undefined {\n\t\treturn this.providers?.find(function (provider) {\n\t\t\treturn (\n\t\t\t\tprovider.urls?.some(function (re) {\n\t\t\t\t\treturn re.test(url);\n\t\t\t\t}) ?? false\n\t\t\t);\n\t\t});\n\t}\n}\n\nconst providers = new Providers();\n\nproviders.registerProvider({\n\turls: [new RegExp('https?://soundcloud\\\\.com/\\\\S+')],\n\tendPoint: 'https://soundcloud.com/oembed?format=json&maxheight=150',\n});\n\nproviders.registerProvider({\n\turls: [\n\t\tnew RegExp('https?://vimeo\\\\.com/[^/]+'),\n\t\tnew RegExp('https?://vimeo\\\\.com/channels/[^/]+/[^/]+'),\n\t\tnew RegExp('https://vimeo\\\\.com/groups/[^/]+/videos/[^/]+'),\n\t],\n\tendPoint: 'https://vimeo.com/api/oembed.json?maxheight=200',\n});\n\nproviders.registerProvider({\n\turls: [new RegExp('https?://www\\\\.youtube\\\\.com/\\\\S+'), new RegExp('https?://youtu\\\\.be/\\\\S+')],\n\tendPoint: 'https://www.youtube.com/oembed?maxheight=200',\n});\n\nproviders.registerProvider({\n\turls: [new RegExp('https?://www\\\\.rdio\\\\.com/\\\\S+'), new RegExp('https?://rd\\\\.io/\\\\S+')],\n\tendPoint: 'https://www.rdio.com/api/oembed/?format=json&maxheight=150',\n});\n\nproviders.registerProvider({\n\turls: [new RegExp('https?://www\\\\.slideshare\\\\.net/[^/]+/[^/]+')],\n\tendPoint: 'https://www.slideshare.net/api/oembed/2?format=json&maxheight=200',\n});\n\nproviders.registerProvider({\n\turls: [new RegExp('https?://www\\\\.dailymotion\\\\.com/video/\\\\S+')],\n\tendPoint: 'https://www.dailymotion.com/services/oembed?maxheight=200',\n});\n\nproviders.registerProvider({\n\turls: [new RegExp('https?://twitter\\\\.com/[^/]+/status/\\\\S+')],\n\tendPoint: 'https://publish.twitter.com/oembed',\n});\n\nproviders.registerProvider({\n\turls: [new RegExp('https?://(play|open)\\\\.spotify\\\\.com/(track|album|playlist|show)/\\\\S+')],\n\tendPoint: 'https://open.spotify.com/oembed',\n});\n\nexport const oembed: OEmbedExecutor = {\n\tproviders,\n};\n\ncallbacks.add(\n\t'oembed:beforeGetUrlContent',\n\tfunction (data) {\n\t\tif (data.parsedUrl != null) {\n\t\t\tconst url = URL.format(data.parsedUrl);\n\t\t\tconst provider = providers.getProviderForUrl(url);\n\t\t\tif (provider != null) {\n\t\t\t\tconst consumerUrl = Providers.getConsumerUrl(provider, url);\n\n\t\t\t\tconst parsedConsumerUrl = URL.parse(consumerUrl, true);\n\t\t\t\t_.extend(data.parsedUrl, parsedConsumerUrl);\n\n\t\t\t\tdata.urlObj.port = parsedConsumerUrl.port;\n\t\t\t\tdata.urlObj.hostname = parsedConsumerUrl.hostname;\n\t\t\t\tdata.urlObj.pathname = parsedConsumerUrl.pathname;\n\t\t\t\tdata.urlObj.query = parsedConsumerUrl.query;\n\n\t\t\t\tdelete data.urlObj.search;\n\t\t\t\tdelete data.urlObj.host;\n\t\t\t}\n\t\t}\n\t\treturn data;\n\t},\n\tcallbacks.priority.MEDIUM,\n\t'oembed-providers-before',\n);\n\nconst cleanupOembed = (data: {\n\turl: string;\n\tmeta: OEmbedMeta;\n\theaders: { [k: string]: string };\n\tparsedUrl: ParsedUrl;\n\tcontent: OEmbedUrlContent;\n}): {\n\turl: string;\n\tmeta: Omit;\n\theaders: { [k: string]: string };\n\tparsedUrl: ParsedUrl;\n\tcontent: OEmbedUrlContent;\n} => {\n\tif (!data?.meta) {\n\t\treturn data;\n\t}\n\n\t// remove oembedHtml key from original meta\n\tconst { oembedHtml, ...meta } = data.meta;\n\n\treturn {\n\t\t...data,\n\t\tmeta,\n\t};\n};\n\ncallbacks.add(\n\t'oembed:afterParseContent',\n\tfunction (data) {\n\t\tif (!data || !data.url || !data.content?.body || !data.parsedUrl?.query) {\n\t\t\treturn cleanupOembed(data);\n\t\t}\n\n\t\tconst queryString = typeof data.parsedUrl.query === 'string' ? QueryString.parse(data.parsedUrl.query) : data.parsedUrl.query;\n\n\t\tif (!queryString.url) {\n\t\t\treturn cleanupOembed(data);\n\t\t}\n\n\t\tconst { url: originalUrl } = data;\n\t\tconst provider = providers.getProviderForUrl(originalUrl);\n\t\tif (!provider) {\n\t\t\treturn cleanupOembed(data);\n\t\t}\n\n\t\tconst { url } = queryString;\n\t\tdata.meta.oembedUrl = url;\n\n\t\ttry {\n\t\t\tconst metas = JSON.parse(data.content.body);\n\t\t\t_.each(metas, function (value, key) {\n\t\t\t\tif (value && typeof value.valueOf() === 'string') {\n\t\t\t\t\tdata.meta[camelCase(`oembed_${key}`)] = value;\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tSystemLogger.error(error);\n\t\t}\n\t\treturn data;\n\t},\n\tcallbacks.priority.MEDIUM,\n\t'oembed-providers-after',\n);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/oembed/server/server.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/client/OTR.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/client/OTRRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/client/messageTypes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/client/tabBar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/lib/IOTR.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/lib/OtrRoomState.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/lib/constants.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/lib/functions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/server/methods/deleteOldOTRMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/server/methods/sendSystemMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/server/methods/updateOTRAck.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/otr/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push/server/apn.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push/server/gcm.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push/server/logger.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push/server/methods.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push/server/push.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push-notifications/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push-notifications/client/tabBar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push-notifications/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push-notifications/server/lib/PushNotification.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/push-notifications/server/methods/saveNotificationSettings.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/reactions/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/reactions/client/init.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/reactions/client/methods/setReaction.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/reactions/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/reactions/server/setReaction.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/retention-policy/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/retention-policy/server/cronPruneMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/retention-policy/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/retention-policy/server/startup/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/events/events.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/logger/logger.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/model/provider.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/provider/defaultProvider.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/search.internalService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/service/providerService.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/search/server/service/validationService.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/client/lib/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/lib/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/CachedSettings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/Middleware.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/SettingsRegistry.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/applyMiddlewares.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/cached.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/convertValue.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/getSettingDefaults.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/overrideGenerator.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/overrideSetting.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/overwriteSetting.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/settings.mocks.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/functions/validateSetting.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/raw.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/settings/server/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/client/slackbridge_import.client.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/RocketAdapter.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/SlackAPI.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/SlackAdapter.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/logger.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/removeChannelLinks.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/slackbridge.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slackbridge/server/slackbridge_import.server.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/lib/gimme.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/lib/lenny.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/lib/shrug.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/lib/tableflip.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/lib/unflip.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommand-asciiarts/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-archiveroom/client/client.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-archiveroom/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-archiveroom/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-archiveroom/server/server.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-create/client/client.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-create/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-create/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-create/server/server.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-help/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-help/server/server.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-hide/client/hide.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-hide/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-hide/server/hide.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-hide/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-invite/client/client.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-invite/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-invite/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-invite/server/server.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-inviteall/client/client.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-inviteall/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-inviteall/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-inviteall/server/server.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-join/client/client.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-join/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-join/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-join/server/server.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-kick/client/client.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-kick/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-kick/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-kick/server/server.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-leave/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-leave/server/leave.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-me/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-me/server/me.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-msg/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-msg/server/server.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-mute/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-mute/server/mute.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-mute/server/unmute.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-open/client/client.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-open/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-open/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-status/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-status/client/status.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-status/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-status/server/status.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-topic/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-topic/client/topic.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-topic/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-topic/server/topic.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-unarchiveroom/client/client.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-unarchiveroom/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-unarchiveroom/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/slashcommands-unarchiveroom/server/server.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/server/functions/generateEml.js",["23016"],[],"import { Meteor } from 'meteor/meteor';\nimport { TAPi18n } from 'meteor/rocketchat:tap-i18n';\nimport _ from 'underscore';\nimport moment from 'moment';\nimport { SmarshHistory } from '@rocket.chat/models';\n\nimport { settings } from '../../../settings/server';\nimport { Rooms, Messages, Users } from '../../../models/server';\nimport { MessageTypes } from '../../../ui-utils';\nimport { smarsh } from '../lib/rocketchat';\nimport 'moment-timezone';\n\nconst start =\n\t'';\nconst end = '
';\nconst opentr = '';\nconst closetr = '';\nconst open20td = '';\nconst open60td = '';\nconst closetd = '';\n\nfunction _getLink(attachment) {\n\tconst url = attachment.title_link.replace(/ /g, '%20');\n\n\tif (url.match(/^(https?:)?\\/\\//i)) {\n\t\treturn url;\n\t}\n\treturn Meteor.absoluteUrl().replace(/\\/$/, '') + __meteor_runtime_config__.ROOT_URL_PATH_PREFIX + url;\n}\n\nsmarsh.generateEml = () => {\n\tMeteor.defer(() => {\n\t\tconst smarshMissingEmail = settings.get('Smarsh_MissingEmail_Email');\n\t\tconst timeZone = settings.get('Smarsh_Timezone');\n\n\t\tRooms.find().forEach(async (room) => {\n\t\t\tconst smarshHistory = await SmarshHistory.findOne({ _id: room._id });\n\t\t\tconst query = { rid: room._id };\n\n\t\t\tif (smarshHistory) {\n\t\t\t\tquery.ts = { $gt: smarshHistory.lastRan };\n\t\t\t}\n\n\t\t\tconst date = new Date();\n\t\t\tconst rows = [];\n\t\t\tconst data = {\n\t\t\t\tusers: [],\n\t\t\t\tmsgs: 0,\n\t\t\t\tfiles: [],\n\t\t\t\ttime: smarshHistory ? moment(date).diff(moment(smarshHistory.lastRan), 'minutes') : moment(date).diff(moment(room.ts), 'minutes'),\n\t\t\t\troom: room.name ? `#${room.name}` : `Direct Message Between: ${room.usernames.join(' & ')}`,\n\t\t\t};\n\n\t\t\tMessages.find(query).forEach((message) => {\n\t\t\t\trows.push(opentr);\n\n\t\t\t\t// The timestamp\n\t\t\t\trows.push(open20td);\n\t\t\t\trows.push(moment(message.ts).tz(timeZone).format('YYYY-MM-DD HH-mm-ss z'));\n\t\t\t\trows.push(closetd);\n\n\t\t\t\t// The sender\n\t\t\t\trows.push(open20td);\n\t\t\t\tconst sender = Users.findOne({ _id: message.u._id });\n\t\t\t\tif (data.users.indexOf(sender._id) === -1) {\n\t\t\t\t\tdata.users.push(sender._id);\n\t\t\t\t}\n\n\t\t\t\t// Get the user's email, can be nothing if it is an unconfigured bot account (like rocket.cat)\n\t\t\t\tif (sender.emails && sender.emails[0] && sender.emails[0].address) {\n\t\t\t\t\trows.push(`${sender.name} <${sender.emails[0].address}>`);\n\t\t\t\t} else {\n\t\t\t\t\trows.push(`${sender.name} <${smarshMissingEmail}>`);\n\t\t\t\t}\n\t\t\t\trows.push(closetd);\n\n\t\t\t\t// The message\n\t\t\t\trows.push(open60td);\n\t\t\t\tdata.msgs++;\n\t\t\t\tif (message.t) {\n\t\t\t\t\tconst messageType = MessageTypes.getType(message);\n\t\t\t\t\tif (messageType) {\n\t\t\t\t\t\trows.push(TAPi18n.__(messageType.message, messageType.data ? messageType.data(message) : '', 'en'));\n\t\t\t\t\t} else {\n\t\t\t\t\t\trows.push(`${message.msg} (${message.t})`);\n\t\t\t\t\t}\n\t\t\t\t} else if (message.file) {\n\t\t\t\t\tdata.files.push(message.file._id);\n\t\t\t\t\trows.push(`${message.attachments[0].title} (${_getLink(message.attachments[0])})`);\n\t\t\t\t} else if (message.attachments) {\n\t\t\t\t\tconst attaches = [];\n\t\t\t\t\t_.each(message.attachments, function _loopThroughMessageAttachments(a) {\n\t\t\t\t\t\tif (a.image_url) {\n\t\t\t\t\t\t\tattaches.push(a.image_url);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// TODO: Verify other type of attachments which need to be handled that aren't file uploads and image urls\n\t\t\t\t\t\t// } else {\n\t\t\t\t\t\t// \tconsole.log(a);\n\t\t\t\t\t\t// }\n\t\t\t\t\t});\n\n\t\t\t\t\trows.push(`${message.msg} (${attaches.join(', ')})`);\n\t\t\t\t} else {\n\t\t\t\t\trows.push(message.msg);\n\t\t\t\t}\n\t\t\t\trows.push(closetd);\n\n\t\t\t\trows.push(closetr);\n\t\t\t});\n\n\t\t\tif (rows.length !== 0) {\n\t\t\t\tconst result = start + rows.join('') + end;\n\n\t\t\t\tSmarshHistory.upsert(\n\t\t\t\t\t{ _id: room._id },\n\t\t\t\t\t{\n\t\t\t\t\t\t_id: room._id,\n\t\t\t\t\t\tlastRan: date,\n\t\t\t\t\t\tlastResult: result,\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\tsmarsh.sendEmail({\n\t\t\t\t\tbody: result,\n\t\t\t\t\tsubject: `Rocket.Chat, ${data.users.length} Users, ${data.msgs} Messages, ${data.files.length} Files, ${data.time} Minutes, in ${data.room}`,\n\t\t\t\t\tfiles: data.files,\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t});\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/server/functions/sendEmail.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/server/lib/rocketchat.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/server/settings.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/smarsh-connector/server/startup.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/server/SMS.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/server/services/mobex.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/server/services/twilio.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/server/services/voxtelesys.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/sms/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/spotify/lib/spotify.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/spotify/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/functions/getLastStatistics.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/functions/getStatistics.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/functions/otrStats.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/functions/slashCommandsStats.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/functions/updateStatsCounter.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/SAUMonitor.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/UAParserCustom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/getAppsStatistics.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/getImporterStatistics.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/getServicesStatistics.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/statistics.ts",["23017","23018","23019","23020"],[],"import os from 'os';\nimport { log } from 'console';\n\nimport _ from 'underscore';\nimport { Meteor } from 'meteor/meteor';\nimport { MongoInternals } from 'meteor/mongo';\nimport type { IRoom, IStats } from '@rocket.chat/core-typings';\nimport {\n\tNotificationQueue,\n\tUsers as UsersRaw,\n\tRooms as RoomsRaw,\n\tStatistics,\n\tSessions,\n\tIntegrations,\n\tInvites,\n\tUploads,\n\tLivechatDepartment,\n\tLivechatVisitors,\n\tEmailInbox,\n\tLivechatBusinessHours,\n\tMessages as MessagesRaw,\n\tRoles as RolesRaw,\n\tInstanceStatus,\n\tSettings,\n\tLivechatTrigger,\n\tLivechatCustomField,\n} from '@rocket.chat/models';\nimport { Analytics, Team, VideoConf } from '@rocket.chat/core-services';\n\nimport { Users, Rooms, Subscriptions, Messages } from '../../../models/server';\nimport { settings } from '../../../settings/server';\nimport { Info, getMongoInfo } from '../../../utils/server';\nimport { getControl } from '../../../../server/lib/migrations';\nimport { getStatistics as federationGetStatistics } from '../../../federation/server/functions/dashboard';\nimport { readSecondaryPreferred } from '../../../../server/database/readSecondaryPreferred';\nimport { getAppsStatistics } from './getAppsStatistics';\nimport { getImporterStatistics } from './getImporterStatistics';\nimport { getServicesStatistics } from './getServicesStatistics';\nimport { getStatistics as getEnterpriseStatistics } from '../../../../ee/app/license/server';\nimport { getSettingsStatistics } from '../../../../server/lib/statistics/getSettingsStatistics';\nimport { getMatrixFederationStatistics } from '../../../federation-v2/server/infrastructure/rocket-chat/statistics';\nimport { isRunningMs } from '../../../../server/lib/isRunningMs';\n\nconst wizardFields = ['Organization_Type', 'Industry', 'Size', 'Country', 'Language', 'Server_Type', 'Register_Server'];\n\nconst getUserLanguages = async (totalUsers: number): Promise<{ [key: string]: number }> => {\n\tconst result = await UsersRaw.getUserLanguages();\n\n\tconst languages: { [key: string]: number } = {\n\t\tnone: totalUsers,\n\t};\n\n\tresult.forEach(({ _id, total }: { _id: string; total: number }) => {\n\t\tif (!_id) {\n\t\t\treturn;\n\t\t}\n\t\tlanguages[_id] = total;\n\t\tlanguages.none -= total;\n\t});\n\n\treturn languages;\n};\n\nconst { db } = MongoInternals.defaultRemoteCollectionDriver().mongo;\n\nexport const statistics = {\n\tget: async (): Promise => {\n\t\tconst readPreference = readSecondaryPreferred(db);\n\n\t\tconst statistics = {} as IStats;\n\t\tconst statsPms = [];\n\n\t\t// Setup Wizard\n\t\tstatistics.wizard = {};\n\t\tawait Promise.all(\n\t\t\twizardFields.map(async (field) => {\n\t\t\t\tconst record = await Settings.findOne(field);\n\t\t\t\tif (record) {\n\t\t\t\t\tconst wizardField = field.replace(/_/g, '').replace(field[0], field[0].toLowerCase());\n\t\t\t\t\tstatistics.wizard[wizardField] = record.value;\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\t// Version\n\t\tconst uniqueID = await Settings.findOne('uniqueID');\n\t\tstatistics.uniqueId = settings.get('uniqueID');\n\t\tif (uniqueID) {\n\t\t\tstatistics.installedAt = uniqueID.createdAt.toISOString();\n\t\t}\n\n\t\tif (Info) {\n\t\t\tstatistics.version = Info.version;\n\t\t\tstatistics.tag = Info.tag;\n\t\t\tstatistics.branch = Info.branch;\n\t\t}\n\n\t\t// User statistics\n\t\tstatistics.totalUsers = Users.find().count();\n\t\tstatistics.activeUsers = Users.getActiveLocalUserCount();\n\t\tstatistics.activeGuests = Users.getActiveLocalGuestCount();\n\t\tstatistics.nonActiveUsers = Users.find({ active: false }).count();\n\t\tstatistics.appUsers = Users.find({ type: 'app' }).count();\n\t\tstatistics.onlineUsers = Meteor.users.find({ status: 'online' }).count();\n\t\tstatistics.awayUsers = Meteor.users.find({ status: 'away' }).count();\n\t\tstatistics.busyUsers = Meteor.users.find({ status: 'busy' }).count();\n\t\tstatistics.totalConnectedUsers = statistics.onlineUsers + statistics.awayUsers;\n\t\tstatistics.offlineUsers = statistics.totalUsers - statistics.onlineUsers - statistics.awayUsers - statistics.busyUsers;\n\t\tstatsPms.push(\n\t\t\tgetUserLanguages(statistics.totalUsers).then((total) => {\n\t\t\t\tstatistics.userLanguages = total;\n\t\t\t}),\n\t\t);\n\n\t\t// Room statistics\n\t\tstatistics.totalRooms = Rooms.find().count();\n\t\tstatistics.totalChannels = Rooms.findByType('c').count();\n\t\tstatistics.totalPrivateGroups = Rooms.findByType('p').count();\n\t\tstatistics.totalDirect = Rooms.findByType('d').count();\n\t\tstatistics.totalLivechat = Rooms.findByType('l').count();\n\t\tstatistics.totalDiscussions = Rooms.countDiscussions();\n\t\tstatistics.totalThreads = Messages.countThreads();\n\n\t\t// livechat visitors\n\t\tstatistics.totalLivechatVisitors = await LivechatVisitors.col.estimatedDocumentCount();\n\n\t\t// livechat agents\n\t\tstatistics.totalLivechatAgents = Users.findAgents().count();\n\t\tstatistics.totalLivechatManagers = await UsersRaw.col.countDocuments({ roles: 'livechat-manager' });\n\n\t\t// livechat enabled\n\t\tstatistics.livechatEnabled = settings.get('Livechat_enabled');\n\n\t\t// Count and types of omnichannel rooms\n\t\tstatsPms.push(\n\t\t\tRoomsRaw.allRoomSourcesCount()\n\t\t\t\t.toArray()\n\t\t\t\t.then((roomSources) => {\n\t\t\t\t\tstatistics.omnichannelSources = roomSources.map(({ _id: { id, alias, type }, count }) => ({\n\t\t\t\t\t\tid,\n\t\t\t\t\t\talias,\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\tcount,\n\t\t\t\t\t}));\n\t\t\t\t}),\n\t\t);\n\n\t\t// Number of departments\n\t\tstatsPms.push(\n\t\t\tLivechatDepartment.col.count().then((count) => {\n\t\t\t\tstatistics.departments = count;\n\t\t\t}),\n\t\t);\n\n\t\t// Number of archived departments\n\t\tstatsPms.push(\n\t\t\tLivechatDepartment.col.countDocuments({ archived: true }).then((count) => {\n\t\t\t\tstatistics.archivedDepartments = count;\n\t\t\t}),\n\t\t);\n\n\t\t// Workspace allows dpeartment removal\n\t\tstatistics.isDepartmentRemovalEnabled = settings.get('Omnichannel_enable_department_removal');\n\n\t\t// Number of triggers\n\t\tstatsPms.push(\n\t\t\tLivechatTrigger.col.count().then((count) => {\n\t\t\t\tstatistics.totalTriggers = count;\n\t\t\t}),\n\t\t);\n\n\t\t// Number of custom fields\n\t\tstatsPms.push(\n\t\t\tLivechatCustomField.col.count().then((count) => {\n\t\t\t\tstatistics.totalCustomFields = count;\n\t\t\t}),\n\t\t);\n\n\t\t// Type of routing algorithm used on omnichannel\n\t\tstatistics.routingAlgorithm = settings.get('Livechat_Routing_Method') || '';\n\n\t\t// is on-hold active\n\t\tstatistics.onHoldEnabled = settings.get('Livechat_allow_manual_on_hold');\n\n\t\t// Number of Email Inboxes\n\t\tstatsPms.push(\n\t\t\tEmailInbox.col.count().then((count) => {\n\t\t\t\tstatistics.emailInboxes = count;\n\t\t\t}),\n\t\t);\n\n\t\tstatsPms.push(\n\t\t\tLivechatBusinessHours.col.count().then((count) => {\n\t\t\t\tstatistics.BusinessHours = {\n\t\t\t\t\t// Number of Business Hours\n\t\t\t\t\ttotal: count,\n\t\t\t\t\t// Business Hours strategy\n\t\t\t\t\tstrategy: settings.get('Livechat_enable_business_hours') || '',\n\t\t\t\t};\n\t\t\t}),\n\t\t);\n\n\t\t// Type of routing algorithm used on omnichannel\n\t\tstatistics.routingAlgorithm = settings.get('Livechat_Routing_Method');\n\n\t\t// is on-hold active\n\t\tstatistics.onHoldEnabled = settings.get('Livechat_allow_manual_on_hold');\n\n\t\t// Last-Chatted Agent Preferred (enabled/disabled)\n\t\tstatistics.lastChattedAgentPreferred = settings.get('Livechat_last_chatted_agent_routing');\n\n\t\t// Assign new conversations to the contact manager (enabled/disabled)\n\t\tstatistics.assignNewConversationsToContactManager = settings.get('Omnichannel_contact_manager_routing');\n\n\t\t// How to handle Visitor Abandonment setting\n\t\tstatistics.visitorAbandonment = settings.get('Livechat_abandoned_rooms_action');\n\n\t\t// Amount of chats placed on hold\n\t\tstatsPms.push(\n\t\t\tMessagesRaw.countRoomsWithMessageType('omnichannel_placed_chat_on_hold', { readPreference }).then((total) => {\n\t\t\t\tstatistics.chatsOnHold = total;\n\t\t\t}),\n\t\t);\n\n\t\t// VoIP Enabled\n\t\tstatistics.voipEnabled = settings.get('VoIP_Enabled');\n\n\t\t// Amount of VoIP Calls\n\t\tstatsPms.push(\n\t\t\tRoomsRaw.countByType('v').then((count) => {\n\t\t\t\tstatistics.voipCalls = count;\n\t\t\t}),\n\t\t);\n\n\t\t// Amount of VoIP Extensions connected\n\t\tstatsPms.push(\n\t\t\tUsersRaw.col.countDocuments({ extension: { $exists: true } }).then((count) => {\n\t\t\t\tstatistics.voipExtensions = count;\n\t\t\t}),\n\t\t);\n\n\t\t// Amount of Calls that ended properly\n\t\tstatsPms.push(\n\t\t\tMessagesRaw.countByType('voip-call-wrapup', { readPreference }).then((count) => {\n\t\t\t\tstatistics.voipSuccessfulCalls = count;\n\t\t\t}),\n\t\t);\n\n\t\t// Amount of Calls that ended with an error\n\t\tstatsPms.push(\n\t\t\tMessagesRaw.countByType('voip-call-ended-unexpectedly', { readPreference }).then((count) => {\n\t\t\t\tstatistics.voipErrorCalls = count;\n\t\t\t}),\n\t\t);\n\t\t// Amount of Calls that were put on hold\n\t\tstatsPms.push(\n\t\t\tMessagesRaw.countRoomsWithMessageType('voip-call-on-hold', { readPreference }).then((count) => {\n\t\t\t\tstatistics.voipOnHoldCalls = count;\n\t\t\t}),\n\t\t);\n\n\t\t// Message statistics\n\t\tstatistics.totalChannelMessages = _.reduce(\n\t\t\tRooms.findByType('c', { fields: { msgs: 1 } }).fetch(),\n\t\t\tfunction _countChannelMessages(num: number, room: IRoom) {\n\t\t\t\treturn num + room.msgs;\n\t\t\t},\n\t\t\t0,\n\t\t);\n\t\tstatistics.totalPrivateGroupMessages = _.reduce(\n\t\t\tRooms.findByType('p', { fields: { msgs: 1 } }).fetch(),\n\t\t\tfunction _countPrivateGroupMessages(num: number, room: IRoom) {\n\t\t\t\treturn num + room.msgs;\n\t\t\t},\n\t\t\t0,\n\t\t);\n\t\tstatistics.totalDirectMessages = _.reduce(\n\t\t\tRooms.findByType('d', { fields: { msgs: 1 } }).fetch(),\n\t\t\tfunction _countDirectMessages(num: number, room: IRoom) {\n\t\t\t\treturn num + room.msgs;\n\t\t\t},\n\t\t\t0,\n\t\t);\n\t\tstatistics.totalLivechatMessages = _.reduce(\n\t\t\tRooms.findByType('l', { fields: { msgs: 1 } }).fetch(),\n\t\t\tfunction _countLivechatMessages(num: number, room: IRoom) {\n\t\t\t\treturn num + room.msgs;\n\t\t\t},\n\t\t\t0,\n\t\t);\n\t\tstatistics.totalMessages =\n\t\t\tstatistics.totalChannelMessages +\n\t\t\tstatistics.totalPrivateGroupMessages +\n\t\t\tstatistics.totalDirectMessages +\n\t\t\tstatistics.totalLivechatMessages;\n\n\t\t// Federation statistics\n\t\tstatsPms.push(\n\t\t\tfederationGetStatistics().then((federationOverviewData) => {\n\t\t\t\tstatistics.federatedServers = federationOverviewData.numberOfServers;\n\t\t\t\tstatistics.federatedUsers = federationOverviewData.numberOfFederatedUsers;\n\t\t\t}),\n\t\t);\n\n\t\tstatistics.lastLogin = Users.getLastLogin();\n\t\tstatistics.lastMessageSentAt = Messages.getLastTimestamp();\n\t\tstatistics.lastSeenSubscription = Subscriptions.getLastSeen();\n\n\t\tstatistics.os = {\n\t\t\ttype: os.type(),\n\t\t\tplatform: os.platform(),\n\t\t\tarch: os.arch(),\n\t\t\trelease: os.release(),\n\t\t\tuptime: os.uptime(),\n\t\t\tloadavg: os.loadavg(),\n\t\t\ttotalmem: os.totalmem(),\n\t\t\tfreemem: os.freemem(),\n\t\t\tcpus: os.cpus(),\n\t\t};\n\n\t\tstatistics.process = {\n\t\t\tnodeVersion: process.version,\n\t\t\tpid: process.pid,\n\t\t\tuptime: process.uptime(),\n\t\t};\n\n\t\tstatistics.deploy = {\n\t\t\tmethod: process.env.DEPLOY_METHOD || 'tar',\n\t\t\tplatform: process.env.DEPLOY_PLATFORM || 'selfinstall',\n\t\t};\n\n\t\tstatistics.readReceiptsEnabled = settings.get('Message_Read_Receipt_Enabled');\n\t\tstatistics.readReceiptsDetailed = settings.get('Message_Read_Receipt_Store_Users');\n\n\t\tstatistics.enterpriseReady = true;\n\t\tstatsPms.push(\n\t\t\tUploads.col.estimatedDocumentCount().then((count) => {\n\t\t\t\tstatistics.uploadsTotal = count;\n\t\t\t}),\n\t\t);\n\t\tstatsPms.push(\n\t\t\tUploads.col\n\t\t\t\t.aggregate(\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$group: { _id: 'total', total: { $sum: '$size' } },\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\t{ readPreference },\n\t\t\t\t)\n\t\t\t\t.toArray()\n\t\t\t\t.then((agg) => {\n\t\t\t\t\tconst [result] = agg;\n\t\t\t\t\tstatistics.uploadsTotalSize = result ? (result as any).total : 0;\n\t\t\t\t}),\n\t\t);\n\n\t\tstatistics.migration = getControl();\n\t\tstatsPms.push(\n\t\t\tInstanceStatus.col.countDocuments({ _updatedAt: { $gt: new Date(Date.now() - process.uptime() * 1000 - 2000) } }).then((count) => {\n\t\t\t\tstatistics.instanceCount = count;\n\t\t\t}),\n\t\t);\n\n\t\tconst { oplogEnabled, mongoVersion, mongoStorageEngine } = getMongoInfo();\n\t\tstatistics.msEnabled = isRunningMs();\n\t\tstatistics.oplogEnabled = oplogEnabled;\n\t\tstatistics.mongoVersion = mongoVersion;\n\t\tstatistics.mongoStorageEngine = mongoStorageEngine;\n\n\t\tstatsPms.push(\n\t\t\tSessions.getUniqueUsersOfYesterday().then((result) => {\n\t\t\t\tstatistics.uniqueUsersOfYesterday = result;\n\t\t\t}),\n\t\t);\n\t\tstatsPms.push(\n\t\t\tSessions.getUniqueUsersOfLastWeek().then((result) => {\n\t\t\t\tstatistics.uniqueUsersOfLastWeek = result;\n\t\t\t}),\n\t\t);\n\t\tstatsPms.push(\n\t\t\tSessions.getUniqueUsersOfLastMonth().then((result) => {\n\t\t\t\tstatistics.uniqueUsersOfLastMonth = result;\n\t\t\t}),\n\t\t);\n\t\tstatsPms.push(\n\t\t\tSessions.getUniqueDevicesOfYesterday().then((result) => {\n\t\t\t\tstatistics.uniqueDevicesOfYesterday = result;\n\t\t\t}),\n\t\t);\n\t\tstatsPms.push(\n\t\t\tSessions.getUniqueDevicesOfLastWeek().then((result) => {\n\t\t\t\tstatistics.uniqueDevicesOfLastWeek = result;\n\t\t\t}),\n\t\t);\n\t\tstatsPms.push(\n\t\t\tSessions.getUniqueDevicesOfLastMonth().then((result) => {\n\t\t\t\tstatistics.uniqueDevicesOfLastMonth = result;\n\t\t\t}),\n\t\t);\n\t\tstatsPms.push(\n\t\t\tSessions.getUniqueOSOfYesterday().then((result) => {\n\t\t\t\tstatistics.uniqueOSOfYesterday = result;\n\t\t\t}),\n\t\t);\n\t\tstatsPms.push(\n\t\t\tSessions.getUniqueOSOfLastWeek().then((result) => {\n\t\t\t\tstatistics.uniqueOSOfLastWeek = result;\n\t\t\t}),\n\t\t);\n\t\tstatsPms.push(\n\t\t\tSessions.getUniqueOSOfLastMonth().then((result) => {\n\t\t\t\tstatistics.uniqueOSOfLastMonth = result;\n\t\t\t}),\n\t\t);\n\n\t\tstatistics.apps = getAppsStatistics();\n\t\tstatistics.services = getServicesStatistics();\n\t\tstatistics.importer = getImporterStatistics();\n\t\tstatistics.videoConf = await VideoConf.getStatistics();\n\n\t\t// If getSettingsStatistics() returns an error, save as empty object.\n\t\tstatsPms.push(\n\t\t\tgetSettingsStatistics().then((res) => {\n\t\t\t\tconst settingsStatisticsObject = res || {};\n\t\t\t\tstatistics.settings = settingsStatisticsObject;\n\t\t\t}),\n\t\t);\n\n\t\tstatsPms.push(\n\t\t\tIntegrations.find(\n\t\t\t\t{},\n\t\t\t\t{\n\t\t\t\t\tprojection: {\n\t\t\t\t\t\t_id: 0,\n\t\t\t\t\t\ttype: 1,\n\t\t\t\t\t\tenabled: 1,\n\t\t\t\t\t\tscriptEnabled: 1,\n\t\t\t\t\t},\n\t\t\t\t\treadPreference,\n\t\t\t\t},\n\t\t\t)\n\t\t\t\t.toArray()\n\t\t\t\t.then((found) => {\n\t\t\t\t\tconst integrations = found;\n\n\t\t\t\t\tstatistics.integrations = {\n\t\t\t\t\t\ttotalIntegrations: integrations.length,\n\t\t\t\t\t\ttotalIncoming: integrations.filter((integration) => integration.type === 'webhook-incoming').length,\n\t\t\t\t\t\ttotalIncomingActive: integrations.filter(\n\t\t\t\t\t\t\t(integration) => integration.enabled === true && integration.type === 'webhook-incoming',\n\t\t\t\t\t\t).length,\n\t\t\t\t\t\ttotalOutgoing: integrations.filter((integration) => integration.type === 'webhook-outgoing').length,\n\t\t\t\t\t\ttotalOutgoingActive: integrations.filter(\n\t\t\t\t\t\t\t(integration) => integration.enabled === true && integration.type === 'webhook-outgoing',\n\t\t\t\t\t\t).length,\n\t\t\t\t\t\ttotalWithScriptEnabled: integrations.filter((integration) => integration.scriptEnabled === true).length,\n\t\t\t\t\t};\n\t\t\t\t}),\n\t\t);\n\n\t\tstatsPms.push(\n\t\t\tNotificationQueue.col.estimatedDocumentCount().then((count) => {\n\t\t\t\tstatistics.pushQueue = count;\n\t\t\t}),\n\t\t);\n\n\t\tstatsPms.push(\n\t\t\tgetEnterpriseStatistics().then((result) => {\n\t\t\t\tstatistics.enterprise = result;\n\t\t\t}),\n\t\t);\n\n\t\tstatsPms.push(\n\t\t\tTeam.getStatistics().then((result) => {\n\t\t\t\tstatistics.teams = result;\n\t\t\t}),\n\t\t);\n\n\t\tstatsPms.push(Analytics.resetSeatRequestCount());\n\n\t\t// TODO: Is that the best way to do this? maybe we should use a promise.all()\n\n\t\tstatistics.dashboardCount = settings.get('Engagement_Dashboard_Load_Count');\n\t\tstatistics.messageAuditApply = settings.get('Message_Auditing_Apply_Count');\n\t\tstatistics.messageAuditLoad = settings.get('Message_Auditing_Panel_Load_Count');\n\t\tstatistics.joinJitsiButton = settings.get('Jitsi_Click_To_Join_Count');\n\t\tstatistics.slashCommandsJitsi = settings.get('Jitsi_Start_SlashCommands_Count');\n\t\tstatistics.totalOTRRooms = Rooms.findByCreatedOTR().count();\n\t\tstatistics.totalOTR = settings.get('OTR_Count');\n\t\tstatistics.totalBroadcastRooms = await RoomsRaw.findByBroadcast().count();\n\t\tstatistics.totalRoomsWithActiveLivestream = await RoomsRaw.findByActiveLivestream().count();\n\t\tstatistics.totalTriggeredEmails = settings.get('Triggered_Emails_Count');\n\t\tstatistics.totalRoomsWithStarred = await MessagesRaw.countRoomsWithStarredMessages({ readPreference });\n\t\tstatistics.totalRoomsWithPinned = await MessagesRaw.countRoomsWithPinnedMessages({ readPreference });\n\t\tstatistics.totalUserTOTP = await UsersRaw.findActiveUsersTOTPEnable({ readPreference }).count();\n\t\tstatistics.totalUserEmail2fa = await UsersRaw.findActiveUsersEmail2faEnable({ readPreference }).count();\n\t\tstatistics.totalPinned = await MessagesRaw.findPinned({ readPreference }).count();\n\t\tstatistics.totalStarred = await MessagesRaw.findStarred({ readPreference }).count();\n\t\tstatistics.totalLinkInvitation = await Invites.find().count();\n\t\tstatistics.totalLinkInvitationUses = await Invites.countUses();\n\t\tstatistics.totalEmailInvitation = settings.get('Invitation_Email_Count');\n\t\tstatistics.totalE2ERooms = await RoomsRaw.findByE2E({ readPreference }).count();\n\t\tstatistics.logoChange = Object.keys(settings.get('Assets_logo')).includes('url');\n\t\tstatistics.showHomeButton = settings.get('Layout_Show_Home_Button');\n\t\tstatistics.totalEncryptedMessages = await MessagesRaw.countByType('e2e', { readPreference });\n\t\tstatistics.totalManuallyAddedUsers = settings.get('Manual_Entry_User_Count');\n\t\tstatistics.totalSubscriptionRoles = await RolesRaw.findByScope('Subscriptions').count();\n\t\tstatistics.totalUserRoles = await RolesRaw.findByScope('Users').count();\n\t\tstatistics.totalWebRTCCalls = settings.get('WebRTC_Calls_Count');\n\t\tstatistics.uncaughtExceptionsCount = settings.get('Uncaught_Exceptions_Count');\n\n\t\tconst defaultHomeTitle = (await Settings.findOneById('Layout_Home_Title'))?.packageValue;\n\t\tstatistics.homeTitleChanged = settings.get('Layout_Home_Title') !== defaultHomeTitle;\n\n\t\tconst defaultHomeBody = (await Settings.findOneById('Layout_Home_Body'))?.packageValue;\n\t\tstatistics.homeBodyChanged = settings.get('Layout_Home_Body') !== defaultHomeBody;\n\n\t\tconst defaultCustomCSS = (await Settings.findOneById('theme-custom-css'))?.packageValue;\n\t\tstatistics.customCSSChanged = settings.get('theme-custom-css') !== defaultCustomCSS;\n\n\t\tconst defaultOnLogoutCustomScript = (await Settings.findOneById('Custom_Script_On_Logout'))?.packageValue;\n\t\tstatistics.onLogoutCustomScriptChanged = settings.get('Custom_Script_On_Logout') !== defaultOnLogoutCustomScript;\n\n\t\tconst defaultLoggedOutCustomScript = (await Settings.findOneById('Custom_Script_Logged_Out'))?.packageValue;\n\t\tstatistics.loggedOutCustomScriptChanged = settings.get('Custom_Script_Logged_Out') !== defaultLoggedOutCustomScript;\n\n\t\tconst defaultLoggedInCustomScript = (await Settings.findOneById('Custom_Script_Logged_In'))?.packageValue;\n\t\tstatistics.loggedInCustomScriptChanged = settings.get('Custom_Script_Logged_In') !== defaultLoggedInCustomScript;\n\n\t\tstatistics.matrixFederation = await getMatrixFederationStatistics();\n\n\t\t// Omnichannel call stats\n\t\tstatistics.webRTCEnabled = settings.get('WebRTC_Enabled');\n\t\tstatistics.webRTCEnabledForOmnichannel = settings.get('Omnichannel_call_provider') === 'WebRTC';\n\t\tstatistics.omnichannelWebRTCCalls = await RoomsRaw.findCountOfRoomsWithActiveCalls();\n\n\t\tawait Promise.all(statsPms).catch(log);\n\n\t\treturn statistics;\n\t},\n\tasync save(): Promise {\n\t\tconst rcStatistics = await statistics.get();\n\t\trcStatistics.createdAt = new Date();\n\t\tawait Statistics.insertOne(rcStatistics);\n\t\treturn rcStatistics;\n\t},\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/lib/telemetryEvents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/methods/getStatistics.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/statistics/server/startup/monitor.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/theme/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/theme/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/theme/server/server.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/theme/server/variables.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/client/flextab/threadlist.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/client/lib/normalizeThreadTitle.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/client/messageAction/follow.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/client/messageAction/replyInThread.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/client/messageAction/unfollow.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/functions.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/hooks/aftersavemessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/hooks/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/methods/followMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/methods/getThreadMessages.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/methods/getThreadsList.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/methods/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/methods/unfollowMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/threads/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/token-login/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/token-login/server/login_token_server.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/tokenpass/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/tokenpass/lib/common.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/tokenpass/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/tokenpass/server/startup.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/ChatMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/UserAction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/accounts.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/codeMirror/codeMirror.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/codeMirror/codeMirrorComponent.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/codeMirror/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/collections.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/iframeCommands.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/notification.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/parentTemplate.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/recorderjs/AudioEncoder.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/recorderjs/AudioRecorder.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/recorderjs/videoRecorder.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/rocket.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/userCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/lib/userPopoverStatus.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/views/app/lib/CommonRoomTemplateInstance.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/views/app/lib/scrolling.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/views/app/photoswipeContent.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui/client/views/app/roomSearch.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-cached-collection/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-cached-collection/client/models/CachedCollection.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-cached-collection/client/models/CachedCollectionManager.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-clean-history/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-clean-history/client/lib/tabBar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-clean-history/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-login/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-login/username/username.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/client/loading/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/public/generateHTML.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/public/generateSprite.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/server/inject.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-master/server/scripts.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/ActionButtonSyncer.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/ActionManager.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/actionButtons/dropdownAction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/actionButtons/lib/applyButtonFilters.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/actionButtons/messageAction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/actionButtons/messageBox.ts",[],["23021","23022"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/actionButtons/tabbar.ts",[],["23023"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/findParentMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/messageBox/createComposerAPI.ts",["23024","23025","23026","23027"],[],"import { Meteor } from 'meteor/meteor';\nimport type { IMessage } from '@rocket.chat/core-typings';\nimport { Emitter } from '@rocket.chat/emitter';\nimport $ from 'jquery';\n\nimport { withDebouncing } from '../../../../lib/utils/highOrderFunctions';\nimport type { ComposerAPI } from '../../../../client/lib/chats/ChatAPI';\nimport type { FormattingButton } from './messageBoxFormatting';\nimport { formattingButtons } from './messageBoxFormatting';\n\nexport const createComposerAPI = (input: HTMLTextAreaElement, storageID: string): ComposerAPI => {\n\tconst triggerEvent = (input: HTMLTextAreaElement, evt: string): void => {\n\t\t$(input).trigger(evt);\n\n\t\tconst event = new Event(evt, { bubbles: true });\n\t\t// TODO: Remove this hack for react to trigger onChange\n\t\tconst tracker = (input as any)._valueTracker;\n\t\tif (tracker) {\n\t\t\ttracker.setValue(new Date().toString());\n\t\t}\n\t\tinput.dispatchEvent(event);\n\t};\n\n\tconst emitter = new Emitter<{\n\t\tquotedMessagesUpdate: void;\n\t\tediting: void;\n\t\trecording: void;\n\t\trecordingVideo: void;\n\t\tformatting: void;\n\t\tmircophoneDenied: void;\n\t}>();\n\n\tlet _quotedMessages: IMessage[] = [];\n\n\tconst persist = withDebouncing({ wait: 300 })(() => {\n\t\tif (input.value) {\n\t\t\tMeteor._localStorage.setItem(storageID, input.value);\n\t\t\treturn;\n\t\t}\n\n\t\tMeteor._localStorage.removeItem(storageID);\n\t});\n\n\tconst notifyQuotedMessagesUpdate = (): void => {\n\t\temitter.emit('quotedMessagesUpdate');\n\t};\n\n\tinput.addEventListener('input', persist);\n\n\tconst setText = (\n\t\ttext: string,\n\t\t{\n\t\t\tselection,\n\t\t}: {\n\t\t\tselection?:\n\t\t\t\t| { readonly start?: number; readonly end?: number }\n\t\t\t\t| ((previous: { readonly start: number; readonly end: number }) => { readonly start?: number; readonly end?: number });\n\t\t} = {},\n\t): void => {\n\t\tfocus();\n\n\t\tconst { selectionStart, selectionEnd } = input;\n\t\tconst textAreaTxt = input.value;\n\n\t\tif (typeof selection === 'function') {\n\t\t\tselection = selection({ start: selectionStart, end: selectionEnd });\n\t\t}\n\n\t\tif (selection) {\n\t\t\tif (!document.execCommand || !document.execCommand('insertText', false, text)) {\n\t\t\t\tinput.value = textAreaTxt.substring(0, selectionStart) + text + textAreaTxt.substring(selectionStart);\n\t\t\t\tfocus();\n\t\t\t}\n\t\t\tinput.setSelectionRange(selection.start ?? 0, selection.end ?? text.length);\n\t\t}\n\n\t\tif (!selection) {\n\t\t\tinput.value = text;\n\t\t}\n\n\t\ttriggerEvent(input, 'input');\n\t\ttriggerEvent(input, 'change');\n\n\t\tfocus();\n\t};\n\n\tconst insertText = (text: string): void => {\n\t\tsetText(text, {\n\t\t\tselection: ({ start, end }) => ({\n\t\t\t\tstart: start + text.length,\n\t\t\t\tend: end + text.length,\n\t\t\t}),\n\t\t});\n\t};\n\n\tconst clear = (): void => {\n\t\tsetText('');\n\t};\n\n\tconst focus = (): void => {\n\t\tinput.focus();\n\t};\n\n\tconst replyWith = async (text: string): Promise => {\n\t\tif (input) {\n\t\t\tinput.value = text;\n\t\t\tinput.focus();\n\t\t}\n\t};\n\n\tconst quoteMessage = async (message: IMessage): Promise => {\n\t\t_quotedMessages = [..._quotedMessages.filter((_message) => _message._id !== message._id), message];\n\t\tnotifyQuotedMessagesUpdate();\n\t\tinput.focus();\n\t};\n\n\tconst dismissQuotedMessage = async (mid: IMessage['_id']): Promise => {\n\t\t_quotedMessages = _quotedMessages.filter((message) => message._id !== mid);\n\t\tnotifyQuotedMessagesUpdate();\n\t};\n\n\tconst dismissAllQuotedMessages = async (): Promise => {\n\t\t_quotedMessages = [];\n\t\tnotifyQuotedMessagesUpdate();\n\t};\n\n\tconst quotedMessages = {\n\t\tget: () => _quotedMessages,\n\t\tsubscribe: (callback: () => void) => emitter.on('quotedMessagesUpdate', callback),\n\t};\n\n\tconst [editing, setEditing] = (() => {\n\t\tlet editing = false;\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tget: () => editing,\n\t\t\t\tsubscribe: (callback: () => void) => emitter.on('editing', callback),\n\t\t\t},\n\t\t\t(value: boolean) => {\n\t\t\t\tediting = value;\n\t\t\t\temitter.emit('editing');\n\t\t\t},\n\t\t];\n\t})();\n\n\tconst [recording, setRecordingMode] = (() => {\n\t\tlet recording = false;\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tget: () => recording,\n\t\t\t\tsubscribe: (callback: () => void) => emitter.on('recording', callback),\n\t\t\t},\n\t\t\t(value: boolean) => {\n\t\t\t\trecording = value;\n\t\t\t\temitter.emit('recording');\n\t\t\t},\n\t\t];\n\t})();\n\n\tconst [recordingVideo, setRecordingVideo] = (() => {\n\t\tlet recordingVideo = false;\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tget: () => recordingVideo,\n\t\t\t\tsubscribe: (callback: () => void) => emitter.on('recordingVideo', callback),\n\t\t\t},\n\t\t\t(value: boolean) => {\n\t\t\t\trecordingVideo = value;\n\t\t\t\temitter.emit('recordingVideo');\n\t\t\t},\n\t\t];\n\t})();\n\n\tconst [isMicrophoneDenied, setIsMicrophoneDenied] = (() => {\n\t\tlet isMicrophoneDenied = false;\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tget: () => isMicrophoneDenied,\n\t\t\t\tsubscribe: (callback: () => void) => emitter.on('mircophoneDenied', callback),\n\t\t\t},\n\t\t\t(value: boolean) => {\n\t\t\t\tisMicrophoneDenied = value;\n\t\t\t\temitter.emit('mircophoneDenied');\n\t\t\t},\n\t\t];\n\t})();\n\n\tconst setEditingMode = (editing: boolean): void => {\n\t\tsetEditing(editing);\n\t};\n\n\tconst [formatters, stopFormatterTracker] = (() => {\n\t\tlet actions: FormattingButton[] = [];\n\n\t\tconst c = Tracker.autorun(() => {\n\t\t\tactions = formattingButtons.filter(({ condition }) => !condition || condition());\n\t\t\temitter.emit('formatting');\n\t\t});\n\n\t\treturn [\n\t\t\t{\n\t\t\t\tget: () => actions,\n\t\t\t\tsubscribe: (callback: () => void) => emitter.on('formatting', callback),\n\t\t\t},\n\t\t\tc,\n\t\t];\n\t})();\n\n\tconst release = (): void => {\n\t\tinput.removeEventListener('input', persist);\n\t\tstopFormatterTracker.stop();\n\t};\n\n\tconst wrapSelection = (pattern: string): void => {\n\t\tconst { selectionEnd = input.value.length, selectionStart = 0 } = input;\n\t\tconst initText = input.value.slice(0, selectionStart);\n\t\tconst selectedText = input.value.slice(selectionStart, selectionEnd);\n\t\tconst finalText = input.value.slice(selectionEnd, input.value.length);\n\n\t\tfocus();\n\n\t\tconst startPattern = pattern.slice(0, pattern.indexOf('{{text}}'));\n\t\tconst startPatternFound = [...startPattern].reverse().every((char, index) => input.value.slice(selectionStart - index - 1, 1) === char);\n\n\t\tif (startPatternFound) {\n\t\t\tconst endPattern = pattern.slice(pattern.indexOf('{{text}}') + '{{text}}'.length);\n\t\t\tconst endPatternFound = [...endPattern].every((char, index) => input.value.slice(selectionEnd + index, 1) === char);\n\n\t\t\tif (endPatternFound) {\n\t\t\t\tinsertText(selectedText);\n\t\t\t\tinput.selectionStart = selectionStart - startPattern.length;\n\t\t\t\tinput.selectionEnd = selectionEnd + endPattern.length;\n\n\t\t\t\tif (!document.execCommand || !document.execCommand('insertText', false, selectedText)) {\n\t\t\t\t\tinput.value = initText.slice(0, initText.length - startPattern.length) + selectedText + finalText.slice(endPattern.length);\n\t\t\t\t}\n\n\t\t\t\tinput.selectionStart = selectionStart - startPattern.length;\n\t\t\t\tinput.selectionEnd = input.selectionStart + selectedText.length;\n\t\t\t\ttriggerEvent(input, 'input');\n\t\t\t\ttriggerEvent(input, 'change');\n\n\t\t\t\tfocus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif (!document.execCommand || !document.execCommand('insertText', false, pattern.replace('{{text}}', selectedText))) {\n\t\t\tinput.value = initText + pattern.replace('{{text}}', selectedText) + finalText;\n\t\t}\n\n\t\tinput.selectionStart = selectionStart + pattern.indexOf('{{text}}');\n\t\tinput.selectionEnd = input.selectionStart + selectedText.length;\n\t\ttriggerEvent(input, 'input');\n\t\ttriggerEvent(input, 'change');\n\n\t\tfocus();\n\t};\n\n\tconst insertNewLine = (): void => insertText('\\n');\n\n\tsetText(Meteor._localStorage.getItem(storageID) ?? '');\n\n\t// Gets the text that is connected to the cursor and replaces it with the given text\n\tconst replaceText = (text: string, selection: { readonly start: number; readonly end: number }): void => {\n\t\tconst { selectionStart, selectionEnd } = input;\n\n\t\t// Selects the text that is connected to the cursor\n\t\tinput.setSelectionRange(selection.start ?? 0, selection.end ?? text.length);\n\t\tconst textAreaTxt = input.value;\n\n\t\tif (!document.execCommand || !document.execCommand('insertText', false, text)) {\n\t\t\tinput.value = textAreaTxt.substring(0, selection.start) + text + textAreaTxt.substring(selection.end);\n\t\t}\n\n\t\tinput.selectionStart = selectionStart + text.length;\n\t\tinput.selectionEnd = selectionStart + text.length;\n\t\tif (selectionStart !== selectionEnd) {\n\t\t\tinput.selectionStart = selectionStart;\n\t\t}\n\n\t\ttriggerEvent(input, 'input');\n\t\ttriggerEvent(input, 'change');\n\n\t\tfocus();\n\t};\n\n\treturn {\n\t\treplaceText,\n\t\tinsertNewLine,\n\t\tblur: () => input.blur(),\n\n\t\tsubstring: (start: number, end?: number) => {\n\t\t\treturn input.value.substring(start, end);\n\t\t},\n\n\t\tgetCursorPosition: () => {\n\t\t\treturn input.selectionStart;\n\t\t},\n\t\tsetCursorToEnd: () => {\n\t\t\tinput.selectionEnd = input.value.length;\n\t\t\tinput.selectionStart = input.selectionEnd;\n\t\t\tfocus();\n\t\t},\n\t\tsetCursorToStart: () => {\n\t\t\tinput.selectionStart = 0;\n\t\t\tinput.selectionEnd = input.selectionStart;\n\t\t\tfocus();\n\t\t},\n\t\trelease,\n\t\twrapSelection,\n\t\tget text(): string {\n\t\t\treturn input.value;\n\t\t},\n\t\tget selection(): { start: number; end: number } {\n\t\t\treturn {\n\t\t\t\tstart: input.selectionStart,\n\t\t\t\tend: input.selectionEnd,\n\t\t\t};\n\t\t},\n\n\t\tediting,\n\t\tsetEditingMode,\n\t\trecording,\n\t\tsetRecordingMode,\n\t\trecordingVideo,\n\t\tsetRecordingVideo,\n\t\tinsertText,\n\t\tsetText,\n\t\tclear,\n\t\tfocus,\n\t\treplyWith,\n\t\tquoteMessage,\n\t\tdismissQuotedMessage,\n\t\tdismissAllQuotedMessages,\n\t\tquotedMessages,\n\t\tformatters,\n\t\tisMicrophoneDenied,\n\t\tsetIsMicrophoneDenied,\n\t};\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/messageBox/messageBox.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/messageBox/messageBoxFormatting.ts",["23028","23029"],[],"import type { Icon } from '@rocket.chat/fuselage';\nimport type { TranslationKey } from '@rocket.chat/ui-contexts';\nimport type { ComponentProps } from 'react';\n\nimport { settings } from '../../../settings/client';\n\nexport type FormattingButton =\n\t| {\n\t\t\tlabel: TranslationKey;\n\t\t\ticon: ComponentProps['name'];\n\t\t\tpattern: string;\n\t\t\t// text?: () => string | undefined;\n\t\t\tcommand?: string;\n\t\t\tlink?: string;\n\t\t\tcondition?: () => boolean;\n\t }\n\t| {\n\t\t\tlabel: TranslationKey;\n\t\t\ttext: () => string | undefined;\n\t\t\tlink: string;\n\t\t\tcondition?: () => boolean;\n\t };\n\nexport const formattingButtons: ReadonlyArray = [\n\t{\n\t\tlabel: 'Bold',\n\t\ticon: 'bold',\n\t\tpattern: '*{{text}}*',\n\t\tcommand: 'b',\n\t},\n\t{\n\t\tlabel: 'Italic',\n\t\ticon: 'italic',\n\t\tpattern: '_{{text}}_',\n\t\tcommand: 'i',\n\t},\n\t{\n\t\tlabel: 'Strike',\n\t\ticon: 'strike',\n\t\tpattern: '~{{text}}~',\n\t},\n\t{\n\t\tlabel: 'Inline_code',\n\t\ticon: 'code',\n\t\tpattern: '`{{text}}`',\n\t},\n\t{\n\t\tlabel: 'Multi_line',\n\t\ticon: 'multiline',\n\t\tpattern: '```\\n{{text}}\\n``` ',\n\t},\n\t{\n\t\tlabel: 'KaTeX' as TranslationKey,\n\t\ticon: 'katex',\n\t\ttext: () => {\n\t\t\tif (!settings.get('Katex_Enabled')) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (settings.get('Katex_Dollar_Syntax')) {\n\t\t\t\treturn '$$KaTeX$$';\n\t\t\t}\n\t\t\tif (settings.get('Katex_Parenthesis_Syntax')) {\n\t\t\t\treturn '\\\\[KaTeX\\\\]';\n\t\t\t}\n\t\t},\n\t\tlink: 'https://khan.github.io/KaTeX/function-support.html',\n\t\tcondition: () => settings.get('Katex_Enabled'),\n\t},\n] as const;\n\n/**\n * @deprecated\n */\nexport function applyFormatting(pattern: string, input: HTMLTextAreaElement) {\n\tconst { selectionEnd = input.value.length, selectionStart = 0 } = input;\n\tconst initText = input.value.slice(0, selectionStart);\n\tconst selectedText = input.value.slice(selectionStart, selectionEnd);\n\tconst finalText = input.value.slice(selectionEnd, input.value.length);\n\n\tinput.focus();\n\n\tconst startPattern = pattern.slice(0, pattern.indexOf('{{text}}'));\n\tconst startPatternFound = [...startPattern].reverse().every((char, index) => input.value.slice(selectionStart - index - 1, 1) === char);\n\n\tif (startPatternFound) {\n\t\tconst endPattern = pattern.slice(pattern.indexOf('{{text}}') + '{{text}}'.length);\n\t\tconst endPatternFound = [...endPattern].every((char, index) => input.value.slice(selectionEnd + index, 1) === char);\n\n\t\tif (endPatternFound) {\n\t\t\tinput.selectionStart = selectionStart - startPattern.length;\n\t\t\tinput.selectionEnd = selectionEnd + endPattern.length;\n\n\t\t\tif (!document.execCommand || !document.execCommand('insertText', false, selectedText)) {\n\t\t\t\tinput.value = initText.slice(0, initText.length - startPattern.length) + selectedText + finalText.slice(endPattern.length);\n\t\t\t}\n\n\t\t\tinput.selectionStart = selectionStart - startPattern.length;\n\t\t\tinput.selectionEnd = input.selectionStart + selectedText.length;\n\t\t\t$(input).change();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (!document.execCommand || !document.execCommand('insertText', false, pattern.replace('{{text}}', selectedText))) {\n\t\tinput.value = initText + pattern.replace('{{text}}', selectedText) + finalText;\n\t}\n\n\tinput.selectionStart = selectionStart + pattern.indexOf('{{text}}');\n\tinput.selectionEnd = input.selectionStart + selectedText.length;\n\t$(input).change();\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/messageThread.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/ComposerBoxPopup.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/components/composerBoxPopup/ComposerBoxPopupCannedResponse.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/components/composerBoxPopup/ComposerBoxPopupEmoji.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/components/composerBoxPopup/ComposerBoxPopupRoom.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/components/composerBoxPopup/ComposerBoxPopupSlashCommand.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/components/composerBoxPopup/ComposerBoxPopupUser.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/components/composerBoxPopupPreview/ComposerBoxPopupPreview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/hooks/useComposerBoxPopup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/hooks/useComposerBoxPopupQueries.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/messagePopupConfig.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/client/popup/messagePopupSlashCommandPreview.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-message/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/AccountBox.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/IframeLogin.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/MessageAction.ts",["23030"],[],"import type { ComponentProps, ContextType } from 'react';\nimport mem from 'mem';\nimport { Meteor } from 'meteor/meteor';\nimport { ReactiveVar } from 'meteor/reactive-var';\nimport { Tracker } from 'meteor/tracker';\nimport type { Icon } from '@rocket.chat/fuselage';\nimport type { IMessage, IUser, ISubscription, IRoom, SettingValue, Serialized, ITranslatedMessage } from '@rocket.chat/core-typings';\nimport type { TranslationKey } from '@rocket.chat/ui-contexts';\n\nimport { Messages, Rooms, Subscriptions } from '../../../models/client';\nimport { roomCoordinator } from '../../../../client/lib/rooms/roomCoordinator';\nimport type { ToolboxContextValue } from '../../../../client/views/room/contexts/ToolboxContext';\nimport type { ChatContext } from '../../../../client/views/room/contexts/ChatContext';\nimport { APIClient } from '../../../utils/client';\nimport type { AutoTranslateOptions } from '../../../../client/views/room/MessageList/hooks/useAutoTranslate';\n\nconst getMessage = async (msgId: string): Promise | null> => {\n\ttry {\n\t\tconst { message } = await APIClient.get('/v1/chat.getMessage', { msgId });\n\t\treturn message;\n\t} catch {\n\t\treturn null;\n\t}\n};\n\nexport const addMessageToList = (messagesList: IMessage[], message: IMessage): IMessage[] => {\n\t// checks if the message is not already on the list\n\tif (!messagesList.find(({ _id }) => _id === message._id)) {\n\t\tmessagesList.push(message);\n\t}\n\n\treturn messagesList;\n};\n\ntype MessageActionGroup = 'message' | 'menu';\nexport type MessageActionContext =\n\t| 'message'\n\t| 'threads'\n\t| 'message-mobile'\n\t| 'pinned'\n\t| 'direct'\n\t| 'starred'\n\t| 'mentions'\n\t| 'federated'\n\t| 'videoconf'\n\t| 'search';\n\ntype MessageActionConditionProps = {\n\tmessage: IMessage;\n\tuser: IUser | undefined;\n\troom: IRoom;\n\tsubscription?: ISubscription;\n\tcontext?: MessageActionContext;\n\tsettings: { [key: string]: SettingValue };\n\tchat: ContextType;\n};\n\nexport type MessageActionConfig = {\n\tid: string;\n\ticon: ComponentProps['name'];\n\tvariant?: 'danger' | 'success' | 'warning';\n\tlabel: TranslationKey;\n\torder?: number;\n\t/* @deprecated */\n\tcolor?: string;\n\tgroup?: MessageActionGroup | MessageActionGroup[];\n\tcontext?: MessageActionContext[];\n\taction: (\n\t\te: Pick,\n\t\t{\n\t\t\tmessage,\n\t\t\ttabbar,\n\t\t\troom,\n\t\t\tchat,\n\t\t\tautoTranslateOptions,\n\t\t}: {\n\t\t\tmessage?: IMessage & Partial;\n\t\t\ttabbar: ToolboxContextValue;\n\t\t\troom?: IRoom;\n\t\t\tchat: ContextType;\n\t\t\tautoTranslateOptions?: AutoTranslateOptions;\n\t\t},\n\t) => any;\n\tcondition?: (props: MessageActionConditionProps) => Promise | boolean;\n};\n\ntype MessageActionConfigList = MessageActionConfig[];\n\nexport const MessageAction = new (class {\n\t/*\n \tconfig expects the following keys (only id is mandatory):\n \t\tid (mandatory)\n \t\ticon: string\n \t\tlabel: string\n \t\taction: function(event, instance)\n \t\tcondition: function(message)\n\t\t\torder: integer\n\t\t\tgroup: string (message or menu)\n */\n\n\tbuttons = new ReactiveVar>({});\n\n\taddButton(config: MessageActionConfig): void {\n\t\tif (!config || !config.id) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!config.group) {\n\t\t\tconfig.group = 'menu';\n\t\t}\n\n\t\tif (config.condition) {\n\t\t\tconfig.condition = mem(config.condition, { maxAge: 1000, cacheKey: JSON.stringify });\n\t\t}\n\n\t\treturn Tracker.nonreactive(() => {\n\t\t\tconst btns = this.buttons.get();\n\t\t\tbtns[config.id] = config;\n\t\t\tmem.clear(this._getButtons);\n\t\t\tmem.clear(this.getButtonsByGroup);\n\t\t\treturn this.buttons.set(btns);\n\t\t});\n\t}\n\n\tremoveButton(id: MessageActionConfig['id']): void {\n\t\treturn Tracker.nonreactive(() => {\n\t\t\tconst btns = this.buttons.get();\n\t\t\tdelete btns[id];\n\t\t\treturn this.buttons.set(btns);\n\t\t});\n\t}\n\n\tupdateButton(id: MessageActionConfig['id'], config: MessageActionConfig): void {\n\t\treturn Tracker.nonreactive(() => {\n\t\t\tconst btns = this.buttons.get();\n\t\t\tif (btns[id]) {\n\t\t\t\tbtns[id] = Object.assign(btns[id], config);\n\t\t\t\treturn this.buttons.set(btns);\n\t\t\t}\n\t\t});\n\t}\n\n\tgetButtonById(id: MessageActionConfig['id']): MessageActionConfig | undefined {\n\t\tconst allButtons = this.buttons.get();\n\t\treturn allButtons[id];\n\t}\n\n\t_getButtons = mem((): MessageActionConfigList => Object.values(this.buttons.get()).sort((a, b) => (a.order ?? 0) - (b.order ?? 0)), {\n\t\tmaxAge: 1000,\n\t});\n\n\tasync getButtonsByCondition(\n\t\tprop: MessageActionConditionProps,\n\t\tarr: MessageActionConfigList = MessageAction._getButtons(),\n\t): Promise {\n\t\treturn (\n\t\t\tawait Promise.all(\n\t\t\t\tarr.map(async (button) => {\n\t\t\t\t\treturn [button, !button.condition || (await button.condition(prop))] as const;\n\t\t\t\t}),\n\t\t\t)\n\t\t)\n\t\t\t.filter(([, condition]) => condition)\n\t\t\t.map(([button]) => button);\n\t}\n\n\tgetButtonsByGroup = mem(\n\t\tfunction (group: MessageActionGroup, arr: MessageActionConfigList = MessageAction._getButtons()): MessageActionConfigList {\n\t\t\treturn arr.filter((button) => !button.group || (Array.isArray(button.group) ? button.group.includes(group) : button.group === group));\n\t\t},\n\t\t{ maxAge: 1000 },\n\t);\n\n\tgetButtonsByContext(context: MessageActionContext, arr: MessageActionConfigList): MessageActionConfigList {\n\t\treturn !context ? arr : arr.filter((button) => !button.context || button.context.includes(context));\n\t}\n\n\tasync getButtons(\n\t\tprops: MessageActionConditionProps,\n\t\tcontext: MessageActionContext,\n\t\tgroup: MessageActionGroup,\n\t): Promise {\n\t\tconst allButtons = group ? this.getButtonsByGroup(group) : MessageAction._getButtons();\n\n\t\tif (props.message) {\n\t\t\treturn this.getButtonsByCondition({ ...props, context }, this.getButtonsByContext(context, allButtons));\n\t\t}\n\t\treturn allButtons;\n\t}\n\n\tresetButtons(): void {\n\t\tmem.clear(this._getButtons);\n\t\tmem.clear(this.getButtonsByGroup);\n\t\treturn this.buttons.set({});\n\t}\n\n\tasync getPermaLink(msgId: string): Promise {\n\t\tif (!msgId) {\n\t\t\tthrow new Error('invalid-parameter');\n\t\t}\n\n\t\tconst msg = Messages.findOne(msgId) || (await getMessage(msgId));\n\t\tif (!msg) {\n\t\t\tthrow new Error('message-not-found');\n\t\t}\n\t\tconst roomData = Rooms.findOne({\n\t\t\t_id: msg.rid,\n\t\t});\n\n\t\tif (!roomData) {\n\t\t\tthrow new Error('room-not-found');\n\t\t}\n\n\t\tconst subData = Subscriptions.findOne({ 'rid': roomData._id, 'u._id': Meteor.userId() });\n\t\tconst roomURL = roomCoordinator.getURL(roomData.t, subData || roomData);\n\t\treturn `${roomURL}?msg=${msgId}`;\n\t}\n})();\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/RoomHistoryManager.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/RoomManager.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/mainReady.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageActionDefault.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageBox.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageContext.ts",[],["23031","23032","23033","23034","23035","23036","23037"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/openRoom.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/client/lib/readMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/lib/Message.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/lib/MessageTypes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-utils/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-vrecord/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/ui-vrecord/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/client/lib/customUserStatus.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/client/lib/userStatus.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/client/notifications/deleteCustomUserStatus.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/client/notifications/updateCustomUserStatus.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/server/methods/deleteCustomUserStatus.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/server/methods/getUserStatusText.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/server/methods/insertOrUpdateUserStatus.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/server/methods/listCustomUserStatus.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/user-status/server/methods/setUserStatus.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/client/lib/RestApiClient.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/fileUploadRestrictions.js",["23038","23039","23040","23041","23042"],[],"import { Meteor } from 'meteor/meteor';\nimport _ from 'underscore';\n\nlet settings;\nif (Meteor.isClient) {\n\tsettings = require('../../settings/client').settings;\n} else {\n\tsettings = require('../../settings/server').settings;\n}\n\nexport const fileUploadMediaWhiteList = function (customWhiteList) {\n\tconst mediaTypeWhiteList = customWhiteList || settings.get('FileUpload_MediaTypeWhiteList');\n\n\tif (!mediaTypeWhiteList || mediaTypeWhiteList === '*') {\n\t\treturn;\n\t}\n\treturn _.map(mediaTypeWhiteList.split(','), function (item) {\n\t\treturn item.trim();\n\t});\n};\n\nconst fileUploadMediaBlackList = function () {\n\tconst blacklist = settings.get('FileUpload_MediaTypeBlackList');\n\tif (!blacklist) {\n\t\treturn;\n\t}\n\n\treturn _.map(blacklist.split(','), (item) => item.trim());\n};\n\nconst isTypeOnList = function (type, list) {\n\tif (_.contains(list, type)) {\n\t\treturn true;\n\t}\n\tconst wildCardGlob = '/*';\n\tconst wildcards = _.filter(list, function (item) {\n\t\treturn item.indexOf(wildCardGlob) > 0;\n\t});\n\tif (_.contains(wildcards, type.replace(/(\\/.*)$/, wildCardGlob))) {\n\t\treturn true;\n\t}\n};\n\nexport const fileUploadIsValidContentType = function (type, customWhiteList) {\n\tconst blackList = fileUploadMediaBlackList();\n\tconst whiteList = fileUploadMediaWhiteList(customWhiteList);\n\n\tif (!type && blackList) {\n\t\treturn false;\n\t}\n\n\tif (blackList && isTypeOnList(type, blackList)) {\n\t\treturn false;\n\t}\n\n\tif (!whiteList) {\n\t\treturn true;\n\t}\n\n\treturn isTypeOnList(type, whiteList);\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getAvatarColor.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getAvatarURL.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getDefaultSubscriptionPref.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getRoomAvatarURL.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getURL.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getUserAvatarURL.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getUserNotificationPreference.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/getUserPreference.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/mimeTypes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/placeholders.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/slashCommand.ts",["23043","23044","23045","23046"],[],"import { Meteor } from 'meteor/meteor';\nimport type {\n\tIMessage,\n\tSlashCommand,\n\tSlashCommandOptions,\n\tRequiredField,\n\tSlashCommandPreviewItem,\n\tSlashCommandPreviews,\n} from '@rocket.chat/core-typings';\n\nexport interface ISlashCommandAddParams {\n\tcommand: string;\n\tcallback?: SlashCommand['callback'];\n\toptions?: SlashCommandOptions;\n\tresult?: SlashCommand['result'];\n\tprovidesPreview?: boolean;\n\tpreviewer?: SlashCommand['previewer'];\n\tpreviewCallback?: SlashCommand['previewCallback'];\n\tappId?: string;\n\tdescription?: string;\n}\n\nexport const slashCommands = {\n\tcommands: {} as Record,\n\tadd({\n\t\tcommand,\n\t\tcallback,\n\t\toptions = {},\n\t\tresult,\n\t\tprovidesPreview = false,\n\t\tpreviewer,\n\t\tpreviewCallback,\n\t\tappId,\n\t\tdescription = '',\n\t}: ISlashCommandAddParams): void {\n\t\tthis.commands[command] = {\n\t\t\tcommand,\n\t\t\tcallback,\n\t\t\tparams: options.params,\n\t\t\tdescription: options.description || description,\n\t\t\tpermission: options.permission,\n\t\t\tclientOnly: options.clientOnly || false,\n\t\t\tresult,\n\t\t\tprovidesPreview: Boolean(providesPreview),\n\t\t\tpreviewer,\n\t\t\tpreviewCallback,\n\t\t\tappId,\n\t\t} as SlashCommand;\n\t},\n\trun(command: string, params: string, message: RequiredField, 'rid'>, triggerId?: string | undefined): void {\n\t\tconst cmd = this.commands[command];\n\t\tif (typeof cmd?.callback !== 'function') {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!message || !message.rid) {\n\t\t\tthrow new Meteor.Error('invalid-command-usage', 'Executing a command requires at least a message with a room id.');\n\t\t}\n\n\t\treturn cmd.callback(command, params, message, triggerId);\n\t},\n\tgetPreviews(command: string, params: string, message: IMessage): SlashCommandPreviews | undefined {\n\t\tconst cmd = this.commands[command];\n\t\tif (typeof cmd?.previewer !== 'function') {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!message || !message.rid) {\n\t\t\tthrow new Meteor.Error('invalid-command-usage', 'Executing a command requires at least a message with a room id.');\n\t\t}\n\n\t\tconst previewInfo = cmd.previewer(command, params, message);\n\n\t\tif (!previewInfo?.items?.length) {\n\t\t\treturn;\n\t\t}\n\n\t\t// A limit of ten results, to save time and bandwidth\n\t\tif (previewInfo.items.length >= 10) {\n\t\t\tpreviewInfo.items = previewInfo.items.slice(0, 10);\n\t\t}\n\n\t\treturn previewInfo;\n\t},\n\texecutePreview(command: string, params: string, message: IMessage, preview: SlashCommandPreviewItem, triggerId: string): void {\n\t\tconst cmd = this.commands[command];\n\t\tif (typeof cmd?.previewCallback !== 'function') {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!message || !message.rid) {\n\t\t\tthrow new Meteor.Error('invalid-command-usage', 'Executing a command requires at least a message with a room id.');\n\t\t}\n\n\t\t// { id, type, value }\n\t\tif (!preview.id || !preview.type || !preview.value) {\n\t\t\tthrow new Meteor.Error('error-invalid-preview', 'Preview Item must have an id, type, and value.');\n\t\t}\n\n\t\treturn cmd.previewCallback(command, params, message, preview, triggerId);\n\t},\n};\n\nMeteor.methods({\n\tslashCommand(command) {\n\t\tif (!Meteor.userId()) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tmethod: 'slashCommand',\n\t\t\t});\n\t\t}\n\n\t\tif (!command || !command.cmd || !slashCommands.commands[command.cmd]) {\n\t\t\tthrow new Meteor.Error('error-invalid-command', 'Invalid Command Provided', {\n\t\t\t\tmethod: 'executeSlashCommandPreview',\n\t\t\t});\n\t\t}\n\t\treturn slashCommands.run(command.cmd, command.params, command.msg, command.triggerId);\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/tapi18n.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/lib/templateVarHandler.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/functions/getDefaultUserFields.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/functions/getMongoInfo.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/functions/isDocker.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/functions/normalizeMessageFileUpload.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/functions/safeGetMeteorUser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/lib/JWTHelper.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/lib/cron/Cronjobs.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/lib/getTimezone.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/lib/getValidRoomName.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/utils/server/lib/normalizeMessagesForUser.ts",["23047"],[],"import type { IMessage, IUser } from '@rocket.chat/core-typings';\n\nimport { Users } from '../../../models/server';\nimport { settings } from '../../../settings/server';\n\nconst filterStarred = (message: IMessage, uid: string): IMessage => {\n\t// only return starred field if user has it starred\n\tif (message.starred && Array.isArray(message.starred)) {\n\t\tmessage.starred = message.starred.filter((star) => star._id === uid);\n\t}\n\treturn message;\n};\n\n// TODO: we should let clients get user names on demand instead of doing this\n\nfunction getNameOfUsername(users: Map, username: string): string {\n\treturn users.get(username) || username;\n}\n\nexport const normalizeMessagesForUser = (messages: IMessage[], uid: string): IMessage[] => {\n\t// if not using real names, there is nothing else to do\n\tif (!settings.get('UI_Use_Real_Name')) {\n\t\treturn messages.map((message) => filterStarred(message, uid));\n\t}\n\n\tconst usernames = new Set();\n\n\tmessages.forEach((message) => {\n\t\tmessage = filterStarred(message, uid);\n\n\t\tif (!message.u || !message.u.username) {\n\t\t\treturn;\n\t\t}\n\t\tusernames.add(message.u.username);\n\n\t\t(message.mentions || []).forEach(({ username }) => {\n\t\t\tusernames.add(username);\n\t\t});\n\n\t\tObject.values(message.reactions || {}).forEach((reaction) => reaction.usernames.forEach((username) => usernames.add(username)));\n\t});\n\n\tconst names = new Map();\n\n\t(\n\t\tUsers.findUsersByUsernames([...usernames.values()], {\n\t\t\tfields: {\n\t\t\t\tusername: 1,\n\t\t\t\tname: 1,\n\t\t\t},\n\t\t}) as Pick[]\n\t).forEach((user) => {\n\t\tnames.set(user.username, user.name);\n\t});\n\n\tmessages.forEach((message: IMessage) => {\n\t\tif (!message.u) {\n\t\t\treturn;\n\t\t}\n\t\tmessage.u.name = getNameOfUsername(names, message.u.username);\n\n\t\t(message.mentions || []).forEach((mention) => {\n\t\t\tif (mention.username) {\n\t\t\t\tmention.name = getNameOfUsername(names, mention.username);\n\t\t\t}\n\t\t});\n\n\t\tif (!message.reactions) {\n\t\t\treturn messages;\n\t\t}\n\n\t\tmessage.reactions = Object.fromEntries(\n\t\t\tObject.entries(message.reactions).map(([keys, reaction]) => {\n\t\t\t\treaction.names = reaction.usernames.map((username) => getNameOfUsername(names, username));\n\t\t\t\treturn [keys, reaction];\n\t\t\t}),\n\t\t);\n\t});\n\n\treturn messages;\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/addSettings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/functions/checkVersionUpdate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/functions/getNewUpdates.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/logger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/methods/banner_dismiss.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/version-check/server/sampleUpdateData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/videobridge/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/videobridge/client/tabBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/voip/server/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/client/actionButton.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/client/startup/sync.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/lib/getWebdavCredentials.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/lib/uploadFileToWebdav.ts",[],["23048"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/lib/webdavClientAdapter.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/methods/addWebdavAccount.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/methods/getFileFromWebdav.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/methods/getWebdavFileList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/methods/getWebdavFilePreview.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/methods/removeWebdavAccount.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/methods/uploadFileToWebdav.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webdav/server/startup/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/client/WebRTCClass.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/client/actionLink.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/client/adapter.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/client/screenShare.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/client/tabBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/webrtc/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/wordpress/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/wordpress/lib/common.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/wordpress/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/wordpress/server/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/UIKit/hooks/useUIKitHandleAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/UIKit/hooks/useUIKitHandleClose.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/UIKit/hooks/useUIKitStateManager.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AdministrationList.spec.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AdministrationList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AdministrationModelList.spec.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AdministrationModelList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AppsModelList.spec.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AppsModelList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AuditModelList.spec.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AdministrationList/AuditModelList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AutoCompleteAgent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AutoCompleteAgentWithoutExtension.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AutoCompleteDepartment.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/AutoCompleteDepartmentMultiple.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Backdrop.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerBadge.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerBadge.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerIcon.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerIcon.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerMenu.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerMenuButton.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/BurgerMenuButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/Line.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/Wrapper.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/BurgerMenu/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/ConfirmOwnerChangeModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/CreateDiscussion/DefaultParentRoomField.tsx",["23049"],[],"import { Skeleton, TextInput, Callout } from '@rocket.chat/fuselage';\nimport { useTranslation } from '@rocket.chat/ui-contexts';\nimport type { ReactElement } from 'react';\nimport React, { useMemo } from 'react';\n\nimport { AsyncStatePhase } from '../../hooks/useAsyncState';\nimport { useEndpointData } from '../../hooks/useEndpointData';\nimport { roomCoordinator } from '../../lib/rooms/roomCoordinator';\n\nconst DefaultParentRoomField = ({ defaultParentRoom }: { defaultParentRoom: string }): ReactElement => {\n\tconst t = useTranslation();\n\tconst { value, phase } = useEndpointData('/v1/rooms.info', {\n\t\tparams: useMemo(\n\t\t\t() => ({\n\t\t\t\troomId: defaultParentRoom,\n\t\t\t}),\n\t\t\t[defaultParentRoom],\n\t\t),\n\t});\n\n\tif (phase === AsyncStatePhase.LOADING) {\n\t\treturn ;\n\t}\n\n\tif (!value || !value.room) {\n\t\treturn {t('Error')};\n\t}\n\n\treturn (\n\t\t\n\t);\n};\n\nexport default DefaultParentRoomField;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/CreateDiscussion/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/CustomFieldsForm.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/CustomFieldsFormV2.tsx",[],["23050"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Emoji.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/FilterByText.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GazzodownText.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericModal.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/GenericTable.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/GenericTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/HeaderCell.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/NoResults.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/SortIcon.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableBody.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableCell.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableHeader.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableHeaderCell.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableLoadingRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableLoadingTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/V2/GenericTableRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/hooks/useCurrent.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/hooks/useItemsPerPage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/hooks/useItemsPerPageLabel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/hooks/usePagination.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/hooks/useShowingResultsLabel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/hooks/useSort.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/GenericTable/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanel.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanel.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelActionGroup.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelAvatar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelField.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelLabel.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelText.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/InfoPanelTitle.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/RetentionPolicyCallout.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/InfoPanel/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/LocalTime.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/MarkdownText.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/MarkdownText.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/OmnichannelSortingDisclaimer.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/Skeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/Tags.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/hooks/useAgentsList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/hooks/useAvailableAgentsList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/hooks/useDepartmentsList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/CloseChatModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/CloseChatModalData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/EnterpriseDepartmentsModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/ForwardChatModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/ModalSeparator/ModalSeparator.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/ModalSeparator/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/ReturnChatQueueModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Omnichannel/modals/TranscriptModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/Page.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/Page.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/PageBlockWithBorder.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/PageContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/PageContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/PageHeader.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/PageScrollableContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/PageScrollableContentWithShadow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Page/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/PageSkeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/PlanTag.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RawText.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomAutoComplete/Avatar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomAutoComplete/RoomAutoComplete.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomAutoComplete/hooks/useRoomsList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomAutoComplete/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/OmnichannelAppSourceRoomIcon.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/OmnichannelCoreSourceRoomIcon.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/OmnichannelRoomIcon.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/context/OmnichannelRoomIconContext.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/lib/OmnichannelRoomIcon.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/OmnichannelRoomIcon/provider/OmnichannelRoomIconProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/RoomIcon.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/RoomIcon/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/ScrollableContentWrapper.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/Content.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/Header.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/ListItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/Sidebar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/SidebarGenericItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/SidebarItemsAssembler.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/SidebarNavigationItem.tsx",[],["23051"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Sidebar/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Skeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/SortList/GroupingList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/SortList/SortList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/SortList/SortModeList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/SortList/ViewModeList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/SortList/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/Subtitle.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TextCopy.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TooltipPortal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TwoFactorModal/TwoFactorModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TwoFactorModal/TwoFactorPasswordModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TwoFactorModal/TwoFactorTotpModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/TwoFactorModal/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UTCClock.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UpsellModal.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UpsellModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UrlChangeModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoComplete/UserAutoComplete.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoComplete/UserAutoComplete.tsx",[],["23052"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoComplete/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultipleOption.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultipleOptions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserAutoCompleteMultiple/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCard.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCardAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCardContainer.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCardInfo.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCardRole.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCardRoles.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/UserCardUsername.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserCard/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserInfo/UserInfo.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserInfo/UserInfo.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserInfo/UserInfoAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserInfo/UserInfoAvatar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserInfo/UserInfoUsername.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserInfo/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserStatus/ReactiveUserStatus.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserStatus/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/UserStatusMenu.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarActions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarBack.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarClose.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarFooter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarHeader.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarIcon.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarInnerContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarScrollableContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarSkeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/VerticalBarText.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/VerticalBar/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/WarningModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/AppAvatar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/BaseAvatar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/RoomAvatar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/RoomAvatarEditor.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/UserAvatar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/UserAvatarEditor/UserAvatarEditor.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/UserAvatarEditor/UserAvatarSuggestions.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/avatar/UserAvatarEditor/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/connectionStatus/ConnectionStatusBar.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/connectionStatus/ConnectionStatusBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/Counter.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/Counter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/CounterSet.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/CounterSet.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/Growth.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/Growth.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/NegativeGrowthSymbol.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/NegativeGrowthSymbol.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/PositiveGrowthSymbol.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/dataView/PositiveGrowthSymbol.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/IgnoredContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/MessageCollapsible.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/MessageContentBody.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/MessageHeader.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/ReadReceiptIndicator.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/StatusIndicators.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/ToolboxHolder.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/Action.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/Attachments.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/BroadcastMetrics.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/DiscussionMetrics.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/Location.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/MessageActions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/Reactions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/ThreadMetrics.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/UiKitSurface.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/UrlPreviews.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/actions/MessageAction.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/actions/MessageAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/AttachmentsItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/DefaultAttachment.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/FileAttachment.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/QuoteAttachment.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/default/ActionAttachmentButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/default/ActionAttachtment.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/default/Field.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/default/FieldsAttachment.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/default/ShortField.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/default/hooks/usePerformActionMutation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/file/AudioAttachment.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/file/ImageAttachment.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/file/VideoAttachment.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/file/hooks/useLoadImage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/Attachment.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentAuthor.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentAuthorAvatar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentAuthorName.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentBlock.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentDescription.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentDetails.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentDownload.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentImage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentInner.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentSize.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentText.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentThumb.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentTitle.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/AttachmentTitleLink.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/image/ImageBox.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/image/Load.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/attachments/structure/image/Retry.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/collapsible/CollapsibleContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/location/MapView.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/location/MapViewFallback.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/location/MapViewImage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/location/hooks/useAsyncImage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/reactions/Reaction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/reactions/useToggleReactionMutation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/uikit/ParsedText.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedCollapsible.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedHtmlPreview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedImagePreview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedLinkPreview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedPreviewContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedPreviewMetadata.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/OEmbedResolver.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/UrlAudioPreview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/UrlImagePreview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/UrlPreview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/UrlPreviewMetadata.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/UrlPreviewResolver.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/UrlVideoPreview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/content/urlPreviews/buildImageURL.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/header/MessageRoles.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/header/MessageRoles.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/header/hooks/useMessageRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/helpers/followSyle.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/hooks/useCollapse.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/hooks/useNormalizedMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/hooks/useOembedLayout.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/hooks/useSubscriptionFromMessageQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/list/MessageListContext.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/list/MessageListSkeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/notification/AllMentionNotification.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/notification/MeMentionNotification.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/notification/MessageNotification.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/notification/UnreadMessagesNotification.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/toolbox/DesktopToolboxDropdown.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/toolbox/MessageActionMenu.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/toolbox/MobileToolboxDropdown.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/toolbox/Toolbox.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/toolbox/ToolboxDropdown.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/RoomMessage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/SystemMessage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/ThreadMessage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/ThreadMessagePreview.spec.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/ThreadMessagePreview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/room/RoomMessageContent.spec.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/thread/ThreadMessageContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/message/variants/threadPreview/ThreadMessagePreviewBody.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/modal/ModalBackdrop.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/modal/ModalPortal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/root/ErrorBoundary.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/voip/room/VoipRoomForeword.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/components/withDoNotAskAgain.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/contexts/ActionManagerContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/contexts/CallContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/contexts/OmnichannelContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/contexts/UserPresenceContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/contexts/VideoConfContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/definitions/MinimongoCollection.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/definitions/Subscribable.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/definitions/SubscriptionWithRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/definitions/css.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/definitions/html.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/definitions/info.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/lists/useRecordList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/lists/useScrollableMessageList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/lists/useScrollableRecordList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/lists/useStreamUpdatesForMessageList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useOmnichannel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useOmnichannelAgentAvailable.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useOmnichannelEnabled.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useOmnichannelEnterpriseEnabled.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useOmnichannelRouteConfig.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useOmnichannelShowQueueLink.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/omnichannel/useQueuedInquiries.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useAsyncState.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useClipboardWithToast.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useComponentDidUpdate.ts",[],["23053","23054"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useDecryptedMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useDialModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useDontAskAgain.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useEmbeddedLayout.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useEndpointAction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useEndpointData.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useEndpointUpload.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFileInput.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useForm.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormatDate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormatDateAndTime.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormatDuration.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormatMemorySize.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormatRelativeTime.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormatTime.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useFormattedRelativeTime.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useHighlightedCode.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useIsEnterprise.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useLicense.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useLocalePercentage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/usePresence.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/usePreventPropagation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useReactiveQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useReactiveValue.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useReactiveVar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useRegistrationStatus.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useResizeInlineBreakpoint.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useRoomIcon.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useRoomInfoEndpoint.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useTimeAgo.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useTimeFromNow.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useTimezoneNameList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useTimezoneTime.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useUTCClock.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useUpdateAvatar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useUserCustomFields.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useUserData.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/hooks/useUserDisplayName.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/importPackages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/2fa/overrideLoginMethod.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/2fa/process2faReturn.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/2fa/utils.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/RoomManager.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/VideoConfManager.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/appLayout.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/asyncState/AsyncState.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/asyncState/AsyncStatePhase.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/asyncState/functions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/asyncState/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/banners.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/baseURI.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/ChatAPI.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/Upload.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/data.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/processMessageEditing.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/processSetReaction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/processSlashCommand.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/processTooLongMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/replyBroadcast.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/requestMessageDeletion.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/sendMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/flows/uploadFiles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/chats/uploads.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/clickableItem.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/constants.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/createReactiveSubscriptionFactory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/createRouteGroup.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/createSidebarItems.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/createSubscription.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/download.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/errorHandling.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/federation/Federation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/getLocalePercentage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/getUserDisplayName.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/getWebdavServerName.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/imperativeModal.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/lists/CannedResponseList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/lists/DiscussionsList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/lists/FilesList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/lists/MessageList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/lists/RecordList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/lists/ThreadsList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/meteorCallWrapper.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/bson.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/comparisons.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/lookups.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/query.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/sort.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/minimongo/types.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/normalizeThreadMessage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/onClientBeforeSendMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/onClientMessageReceived.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/parseMessageTextToAstMarkdown.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/portals/blazePortals.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/portals/createTemplateForComponent.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/portals/portalsSubscription.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/presence.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/queryClient.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomCoordinator.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomExit.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/conversation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/direct.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/favorite.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/livechat.ts",["23055"],[],"import type { AtLeast, ValueOf } from '@rocket.chat/core-typings';\nimport { Session } from 'meteor/session';\n\nimport { hasPermission } from '../../../../app/authorization/client';\nimport { LivechatInquiry } from '../../../../app/livechat/client/collections/LivechatInquiry';\nimport { ChatRoom, ChatSubscription } from '../../../../app/models/client';\nimport { settings } from '../../../../app/settings/client';\nimport { getAvatarURL } from '../../../../app/utils/lib/getAvatarURL';\nimport type { IRoomTypeClientDirectives } from '../../../../definition/IRoomTypeConfig';\nimport { RoomSettingsEnum, RoomMemberActions, UiTextContext } from '../../../../definition/IRoomTypeConfig';\nimport { getLivechatRoomType } from '../../../../lib/rooms/roomTypes/livechat';\nimport { roomCoordinator } from '../roomCoordinator';\n\nexport const LivechatRoomType = getLivechatRoomType(roomCoordinator);\n\nroomCoordinator.add(LivechatRoomType, {\n\tallowRoomSettingChange(_room, setting) {\n\t\tswitch (setting) {\n\t\t\tcase RoomSettingsEnum.JOIN_CODE:\n\t\t\t\treturn false;\n\t\t\tdefault:\n\t\t\t\treturn true;\n\t\t}\n\t},\n\n\tallowMemberAction(_room, action) {\n\t\treturn ([RoomMemberActions.INVITE, RoomMemberActions.JOIN] as Array>).includes(action);\n\t},\n\n\troomName(room) {\n\t\treturn room.name || room.fname || (room as any).label;\n\t},\n\n\tgetUiText(context) {\n\t\tswitch (context) {\n\t\t\tcase UiTextContext.HIDE_WARNING:\n\t\t\t\treturn 'Hide_Livechat_Warning';\n\t\t\tcase UiTextContext.LEAVE_WARNING:\n\t\t\t\treturn 'Hide_Livechat_Warning';\n\t\t\tdefault:\n\t\t\t\treturn '';\n\t\t}\n\t},\n\n\tcondition() {\n\t\treturn settings.get('Livechat_enabled') && hasPermission('view-l-room');\n\t},\n\n\tgetAvatarPath(room) {\n\t\treturn getAvatarURL({ username: `@${this.roomName(room)}` }) || '';\n\t},\n\n\tgetUserStatus(rid) {\n\t\tconst room = Session.get(`roomData${rid}`);\n\t\tif (room) {\n\t\t\treturn room.v?.status;\n\t\t}\n\t\tconst inquiry = LivechatInquiry.findOne({ rid });\n\t\treturn inquiry?.v?.status;\n\t},\n\n\tfindRoom(identifier) {\n\t\treturn ChatRoom.findOne({ _id: identifier });\n\t},\n\n\tisLivechatRoom() {\n\t\treturn true;\n\t},\n\n\tcanSendMessage(rid) {\n\t\tconst room = ChatRoom.findOne({ _id: rid }, { fields: { open: 1 } });\n\t\treturn Boolean(room?.open);\n\t},\n\n\treadOnly(rid, _user) {\n\t\tconst room = ChatRoom.findOne({ _id: rid }, { fields: { open: 1, servedBy: 1 } });\n\t\tif (!room || !room.open) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst subscription = ChatSubscription.findOne({ rid });\n\t\treturn !subscription;\n\t},\n} as AtLeast);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/private.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/public.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/unread.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/rooms/roomTypes/voip.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/settings/PrivateSettingsCachedCollection.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/settings/PublicSettingsCachedCollection.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/toast.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/userData.ts",["23056"],[],"import type { ILivechatAgent, IUser, IUserDataEvent, Serialized } from '@rocket.chat/core-typings';\nimport { Meteor } from 'meteor/meteor';\nimport { ReactiveVar } from 'meteor/reactive-var';\n\nimport { Users } from '../../app/models/client';\nimport { Notifications } from '../../app/notifications/client';\nimport { APIClient } from '../../app/utils/client';\n\nexport const isSyncReady = new ReactiveVar(false);\n\ntype RawUserData = Serialized<\n\tPick<\n\t\tIUser,\n\t\t| '_id'\n\t\t| 'type'\n\t\t| 'name'\n\t\t| 'username'\n\t\t| 'emails'\n\t\t| 'status'\n\t\t| 'statusDefault'\n\t\t| 'statusText'\n\t\t| 'statusConnection'\n\t\t| 'avatarOrigin'\n\t\t| 'utcOffset'\n\t\t| 'language'\n\t\t| 'settings'\n\t\t| 'roles'\n\t\t| 'active'\n\t\t| 'defaultRoom'\n\t\t| 'customFields'\n\t\t| 'oauth'\n\t\t| 'createdAt'\n\t\t| '_updatedAt'\n\t\t| 'avatarETag'\n\t> & { statusLivechat?: ILivechatAgent['statusLivechat'] }\n>;\n\nconst updateUser = (userData: IUser): void => {\n\tconst user = Users.findOne({ _id: userData._id }) as IUser | undefined;\n\n\tif (!user || !user._updatedAt || user._updatedAt.getTime() < userData._updatedAt.getTime()) {\n\t\tMeteor.users.upsert({ _id: userData._id }, userData as Meteor.User);\n\t\treturn;\n\t}\n\n\t// delete data already on user's collection as those are newer\n\tObject.keys(user).forEach((key) => {\n\t\tdelete userData[key as keyof IUser];\n\t});\n\tMeteor.users.update({ _id: user._id }, { $set: userData as Meteor.User });\n};\n\nlet cancel: undefined | (() => void);\nexport const synchronizeUserData = async (uid: Meteor.User['_id']): Promise => {\n\tif (!uid) {\n\t\treturn;\n\t}\n\n\t// Remove data from any other user that we may have retained\n\tMeteor.users.remove({ _id: { $ne: uid } });\n\n\tcancel?.();\n\n\tcancel = await Notifications.onUser('userData', (data: IUserDataEvent) => {\n\t\tswitch (data.type) {\n\t\t\tcase 'inserted':\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\t\t\t\tconst { type, id, ...user } = data;\n\t\t\t\tMeteor.users.insert(user as Meteor.User);\n\t\t\t\tbreak;\n\n\t\t\tcase 'updated':\n\t\t\t\tMeteor.users.upsert({ _id: uid }, { $set: data.diff as Meteor.User, $unset: data.unset });\n\t\t\t\tbreak;\n\n\t\t\tcase 'removed':\n\t\t\t\tMeteor.users.remove({ _id: uid });\n\t\t\t\tbreak;\n\t\t}\n\t});\n\n\tconst { ldap, lastLogin, services: rawServices, ...userData } = await APIClient.get('/v1/me');\n\n\t// email?: {\n\t// \tverificationTokens?: IUserEmailVerificationToken[];\n\t// };\n\t// export interface IUserEmailVerificationToken {\n\t// \ttoken: string;\n\t// \taddress: string;\n\t// \twhen: Date;\n\t// }\n\n\tif (userData) {\n\t\tconst { email, cloud, resume, email2fa, emailCode, ...services } = rawServices || {};\n\n\t\tupdateUser({\n\t\t\t...userData,\n\t\t\t...(rawServices && {\n\t\t\t\tservices: {\n\t\t\t\t\t...(services ? { ...services } : {}),\n\t\t\t\t\t...(resume\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tresume: {\n\t\t\t\t\t\t\t\t\t...(resume.loginTokens && {\n\t\t\t\t\t\t\t\t\t\tloginTokens: resume.loginTokens.map((token) => ({\n\t\t\t\t\t\t\t\t\t\t\t...token,\n\t\t\t\t\t\t\t\t\t\t\twhen: new Date('when' in token ? token.when : ''),\n\t\t\t\t\t\t\t\t\t\t\tcreatedAt: ('createdAt' in token ? new Date(token.createdAt) : undefined) as Date,\n\t\t\t\t\t\t\t\t\t\t\ttwoFactorAuthorizedUntil: token.twoFactorAuthorizedUntil ? new Date(token.twoFactorAuthorizedUntil) : undefined,\n\t\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(cloud\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tcloud: {\n\t\t\t\t\t\t\t\t\t...cloud,\n\t\t\t\t\t\t\t\t\texpiresAt: new Date(cloud.expiresAt),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\temailCode: emailCode?.map(({ expire, ...data }) => ({ expire: new Date(expire), ...data })) || [],\n\t\t\t\t\t...(email2fa ? { email2fa: { ...email2fa, changedAt: new Date(email2fa.changedAt) } } : {}),\n\t\t\t\t\t...(email?.verificationTokens && {\n\t\t\t\t\t\temail: {\n\t\t\t\t\t\t\tverificationTokens: email.verificationTokens.map((token) => ({\n\t\t\t\t\t\t\t\t...token,\n\t\t\t\t\t\t\t\twhen: new Date(token.when),\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t}),\n\t\t\t...(lastLogin && {\n\t\t\t\tlastLogin: new Date(lastLogin),\n\t\t\t}),\n\t\t\tldap: Boolean(ldap),\n\t\t\tcreatedAt: new Date(userData.createdAt),\n\t\t\t_updatedAt: new Date(userData._updatedAt),\n\t\t});\n\t}\n\tisSyncReady.set(true);\n\n\treturn userData;\n};\n\nexport const removeLocalUserData = (): number => Meteor.users.remove({});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/applyCustomTranslations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/call.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/callWithErrorHandling.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/createAnchor.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/createToken.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/deleteAnchor.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/detectEmoji.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/domEvents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/filterLanguage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/fireGlobalEvent.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/formatBytes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/formatDate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/formatDateAndTime.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/formatTime.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/getAvatarAsPng.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/getConfig.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/getDateRange.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/getUidDirectMessage.ts",["23057"],[],"import type { IRoom, IUser } from '@rocket.chat/core-typings';\nimport { Meteor } from 'meteor/meteor';\n\nimport { Rooms } from '../../../app/models/client';\n\nexport const getUidDirectMessage = (rid: IRoom['_id'], userId: IUser['_id'] | null = Meteor.userId()): string | undefined => {\n\tconst room = Rooms.findOne({ _id: rid }, { fields: { uids: 1 } });\n\n\tif (!room || !room.uids || room.uids.length > 2) {\n\t\treturn undefined;\n\t}\n\n\treturn room.uids.filter((uid) => uid !== userId)[0];\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/getUserEmailVerified.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/goToRoomById.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/isIE11.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/isIOsDevice.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/isLayoutEmbedded.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/isRTL.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/isRTLScriptLanguage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/isValidImageFormat.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/keyCodes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/legacyJumpToMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/mapMessageFromApi.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/messageArgs.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/prependReplies.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/queueMicrotask.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/renderEmoji.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/renderMessageEmoji.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/setMessageJumpQueryStringParameter.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/timeAgo.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/userAgentMIMETypeFallback.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/waitForElement.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/utils/waitUntilFind.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/voip/Helper.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/voip/LocalStream.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/voip/QueueAggregator.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/voip/RemoteStream.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/voip/Stream.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/lib/voip/VoIPUser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/main.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/hideRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/openRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/pinMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/setUserActiveStatus.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/starMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/toggleFavorite.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/unpinMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/methods/updateMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/polyfills/childNodeRemove.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/polyfills/cssVars.ts",["23058"],[],"import { withDebouncing } from '../../lib/utils/highOrderFunctions';\n\ntype Variables = {\n\t[name: string]: (variables: Variables) => string;\n};\n\nconst findDeclarations = (code: string): [string, Variables[keyof Variables]][] =>\n\t(code.match(/(--[^:; ]+:..*?;)/g) ?? []).map((declaration) => {\n\t\tconst matches = /(.*?):\\s*(.*?)\\s*;/.exec(declaration);\n\n\t\tif (matches === null) {\n\t\t\tthrow new Error();\n\t\t}\n\n\t\tconst [, name, value] = matches;\n\t\treturn [\n\t\t\tname,\n\t\t\tvalue.indexOf('var(') >= 0\n\t\t\t\t? (variables: Variables): string => value.replace(/var\\((--.*?)\\)/gm, (_, name) => variables[name]?.call(null, variables))\n\t\t\t\t: (): string => value,\n\t\t];\n\t});\n\nconst replaceReferences = (code: string, variables: Variables): string =>\n\tcode.replace(/var\\((--.*?)\\)/gm, (_, name) => variables[name]?.call(null, variables));\n\nlet cssVariablesElement: HTMLElement;\nconst originalCodes = new Map();\n\nconst update = withDebouncing({ wait: 100 })(() => {\n\tconst declarations = ([] as [string, Variables[keyof Variables]][]).concat(\n\t\t...Array.from(originalCodes.values(), findDeclarations),\n\t\tfindDeclarations(cssVariablesElement.innerHTML),\n\t);\n\n\tconst variables = Object.fromEntries(declarations);\n\n\toriginalCodes.forEach((originalCode, element) => {\n\t\tconst patchedCode = replaceReferences(originalCode, variables);\n\n\t\tlet patchedElement = element.nextElementSibling;\n\t\tif (!patchedElement || !patchedElement.classList.contains('patched-css-variables')) {\n\t\t\tpatchedElement = document.createElement('style');\n\t\t\tpatchedElement.type = 'text/css';\n\t\t\tpatchedElement.classList.add('patched-css-variables');\n\t\t\telement.insertAdjacentElement('afterend', patchedElement);\n\t\t}\n\n\t\tconst { sheet } = patchedElement;\n\t\twhile (sheet.cssRules.length > 0) {\n\t\t\tsheet.deleteRule(0);\n\t\t}\n\t\tsheet.insertRule(`@media all {${patchedCode}}`, 0);\n\t});\n});\n\nconst findAndPatchFromLinkElements = (): void => {\n\tArray.from(document.querySelectorAll('link[type=\"text/css\"].__meteor-css__')).forEach(async (linkElement) => {\n\t\tconst url = linkElement.getAttribute('href');\n\n\t\tif (url === null) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(url);\n\t\t\tconst code = await response.text();\n\t\t\toriginalCodes.set(linkElement, code);\n\t\t} catch (error) {\n\t\t\tconsole.warn(error);\n\t\t} finally {\n\t\t\tupdate();\n\t\t}\n\t});\n};\n\nconst waitAndInitialize = (): void => {\n\tif (document.readyState !== 'complete') {\n\t\trequestAnimationFrame(waitAndInitialize);\n\t\treturn;\n\t}\n\n\tconst element = document.getElementById('css-variables');\n\n\tif (element === null) {\n\t\trequestAnimationFrame(waitAndInitialize);\n\t\treturn;\n\t}\n\n\tcssVariablesElement = element;\n\n\tconst cssVariablesElementObserver = new MutationObserver(() => {\n\t\tupdate();\n\t});\n\n\tcssVariablesElementObserver.observe(cssVariablesElement, { childList: true });\n\n\tfindAndPatchFromLinkElements();\n};\n\n((): void => {\n\tif (window.CSS?.supports?.('(--foo: red)')) {\n\t\treturn;\n\t}\n\n\twaitAndInitialize();\n})();\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/polyfills/customEventPolyfill.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/polyfills/hoverTouchClick.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/polyfills/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/polyfills/objectFromEntries.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/portals/VideoConfPopupPortal.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/ActionManagerProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/AttachmentProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/AuthorizationProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/AvatarUrlProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/CallProvider/CallProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/CallProvider/definitions/IceServer.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/CallProvider/hooks/useWebRtcServers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/CallProvider/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/CallProvider/lib/parseStringToIceServers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/ConnectionStatusProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/CustomSoundProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/DeviceProvider/DeviceProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/DeviceProvider/lib/isSetSinkIdAvailable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/LayoutProvider.tsx",[],["23059","23060"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/MeteorProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/ModalProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/OmnichannelProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/RouterProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/ServerProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/SessionProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/SettingsProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/ToastMessagesProvider.tsx",[],["23061"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/TooltipProvider.tsx",[],["23062"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/TranslationProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/UserPresenceProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/UserProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/providers/VideoConfProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Item/Condensed.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Item/Condensed.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Item/Extended.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Item/Extended.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Item/Medium.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Item/Medium.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomList/RoomList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomList/RoomListRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomList/ScrollerWithCustomProps.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomList/SideBarItemTemplateWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomList/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomList/normalizeSidebarMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/RoomMenu.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Sidebar.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/Sidebar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/SidebarPortal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/SidebarFooter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/SidebarFooterDefault.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/voip/VoipFooter.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/voip/VoipFooter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/voip/hooks/useOmnichannelContactLabel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/footer/voip/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/CreateChannel/CreateChannelModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/CreateChannel/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/CreateDirectMessage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/CreateTeam/CreateTeamModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/CreateTeam/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/EditStatusModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/UserAvatarButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/UserDropdown.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/Administration.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/CreateRoom.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/CreateRoomList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/Directory.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/Home.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/Login.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/Search.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/actions/Sort.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/hooks/useCreateRoomModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/hooks/useDropdownVisibility.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/header/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/hooks/useAvatarTemplate.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/hooks/usePreventDefault.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/hooks/useQueryOptions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/hooks/useRoomList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/hooks/useShortcutOpenMenu.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/hooks/useTemplateByViewMode.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/search/Row.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/search/ScrollerWithCustomProps.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/search/SearchList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/search/UserItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/OmnichannelSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/StatusDisabledSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/OmnichannelCallDialPad.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/OmnichannelCallToggle.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/OmnichannelCallToggleError.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/OmnichannelCallToggleLoading.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/OmnichannelCallToggleReady.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/OmnichannelLivechatToggle.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/sidebar/sections/actions/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/UserDeleted.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/absoluteUrl.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/jumpToMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/jumpToPinMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/jumpToSearchMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/jumpToStarMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/permalinkPinned.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/permalinkStar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/pinMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/readReceipt.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/starMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/unpinMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/actionButtons/unstarMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/afterLogoutCleanUp/customScriptOnLogout.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/afterLogoutCleanUp/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/afterLogoutCleanUp/purgeAllDrafts.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/afterLogoutCleanUp/roomManager.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/appRoot.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/banners.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/callbacks.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/contextualBar/exportMessagesTab.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/contextualBar/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/contextualBar/mentionsTab.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/contextualBar/pinnedMessagesTab.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/contextualBar/starredMessagesTab.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/customOAuth.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/customTranslations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/e2e.ts",["23063"],[],"import type { AtLeast, IMessage, IRoom, ISubscription } from '@rocket.chat/core-typings';\nimport { FlowRouter } from 'meteor/kadira:flow-router';\nimport { Meteor } from 'meteor/meteor';\nimport { Tracker } from 'meteor/tracker';\n\nimport { e2e } from '../../app/e2e/client/rocketchat.e2e';\nimport { Subscriptions, Rooms } from '../../app/models/client';\nimport { Notifications } from '../../app/notifications/client';\nimport { settings } from '../../app/settings/client';\nimport { onClientBeforeSendMessage } from '../lib/onClientBeforeSendMessage';\nimport { onClientMessageReceived } from '../lib/onClientMessageReceived';\nimport { isLayoutEmbedded } from '../lib/utils/isLayoutEmbedded';\nimport { waitUntilFind } from '../lib/utils/waitUntilFind';\n\nconst handle = async (roomId: IRoom['_id'], keyId: string): Promise => {\n\tconst e2eRoom = await e2e.getInstanceByRoomId(roomId);\n\tif (!e2eRoom) {\n\t\treturn;\n\t}\n\n\te2eRoom.provideKeyToUser(keyId);\n};\n\nMeteor.startup(() => {\n\tTracker.autorun(() => {\n\t\tif (!Meteor.userId()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst adminEmbedded = isLayoutEmbedded() && FlowRouter.current().path.startsWith('/admin');\n\n\t\tif (!adminEmbedded && settings.get('E2E_Enable') && window.crypto) {\n\t\t\te2e.startClient();\n\t\t\te2e.enabled.set(true);\n\t\t} else {\n\t\t\te2e.enabled.set(false);\n\t\t\te2e.closeAlert();\n\t\t}\n\t});\n\n\tlet observable: Meteor.LiveQueryHandle | null = null;\n\tlet offClientMessageReceived: undefined | (() => void);\n\tlet offClientBeforeSendMessage: undefined | (() => void);\n\tTracker.autorun(() => {\n\t\tif (!e2e.isReady()) {\n\t\t\toffClientMessageReceived?.();\n\t\t\tNotifications.unUser('e2ekeyRequest', handle);\n\t\t\tobservable?.stop();\n\t\t\toffClientBeforeSendMessage?.();\n\t\t\treturn;\n\t\t}\n\n\t\tNotifications.onUser('e2ekeyRequest', handle);\n\n\t\tobservable = Subscriptions.find().observe({\n\t\t\tchanged: async (sub: ISubscription) => {\n\t\t\t\tMeteor.defer(async () => {\n\t\t\t\t\tif (!sub.encrypted && !sub.E2EKey) {\n\t\t\t\t\t\te2e.removeInstanceByRoomId(sub.rid);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst e2eRoom = await e2e.getInstanceByRoomId(sub.rid);\n\t\t\t\t\tif (!e2eRoom) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (sub.E2ESuggestedKey) {\n\t\t\t\t\t\tif (await e2eRoom.importGroupKey(sub.E2ESuggestedKey)) {\n\t\t\t\t\t\t\te2e.acceptSuggestedKey(sub.rid);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconsole.warn('Invalid E2ESuggestedKey, rejecting', sub.E2ESuggestedKey);\n\t\t\t\t\t\t\te2e.rejectSuggestedKey(sub.rid);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tsub.encrypted ? e2eRoom.resume() : e2eRoom.pause();\n\n\t\t\t\t\t// Cover private groups and direct messages\n\t\t\t\t\tif (!e2eRoom.isSupportedRoomType(sub.t)) {\n\t\t\t\t\t\te2eRoom.disable();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (sub.E2EKey && e2eRoom.isWaitingKeys()) {\n\t\t\t\t\t\te2eRoom.keyReceived();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!e2eRoom.isReady()) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\te2eRoom.decryptSubscription();\n\t\t\t\t});\n\t\t\t},\n\t\t\tadded: async (sub: ISubscription) => {\n\t\t\t\tMeteor.defer(async () => {\n\t\t\t\t\tif (!sub.encrypted && !sub.E2EKey) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\treturn e2e.getInstanceByRoomId(sub.rid);\n\t\t\t\t});\n\t\t\t},\n\t\t\tremoved: (sub: ISubscription) => {\n\t\t\t\te2e.removeInstanceByRoomId(sub.rid);\n\t\t\t},\n\t\t});\n\n\t\toffClientMessageReceived = onClientMessageReceived.use(async (msg: IMessage) => {\n\t\t\tconst e2eRoom = await e2e.getInstanceByRoomId(msg.rid);\n\t\t\tif (!e2eRoom || !e2eRoom.shouldConvertReceivedMessages()) {\n\t\t\t\treturn msg;\n\t\t\t}\n\t\t\treturn e2e.decryptMessage(msg);\n\t\t});\n\n\t\t// Encrypt messages before sending\n\t\toffClientBeforeSendMessage = onClientBeforeSendMessage.use(async (message: AtLeast) => {\n\t\t\tconst e2eRoom = await e2e.getInstanceByRoomId(message.rid);\n\n\t\t\tif (!e2eRoom) {\n\t\t\t\treturn message;\n\t\t\t}\n\n\t\t\tconst subscription = await waitUntilFind(() => Rooms.findOne({ _id: message.rid }));\n\n\t\t\tsubscription.encrypted ? e2eRoom.resume() : e2eRoom.pause();\n\n\t\t\tconst shouldConvertSentMessages = await e2eRoom.shouldConvertSentMessages(message);\n\n\t\t\tif (!shouldConvertSentMessages) {\n\t\t\t\treturn message;\n\t\t\t}\n\n\t\t\t// Should encrypt this message.\n\t\t\tconst msg = await e2eRoom.encrypt(message);\n\n\t\t\tmessage.msg = msg;\n\t\t\tmessage.t = 'e2e';\n\t\t\tmessage.e2e = 'pending';\n\t\t\treturn message;\n\t\t});\n\t});\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/emailVerification.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/enterRoom/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/enterRoom/readMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/forceLogout.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/i18n.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/incomingMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/ldap.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/loadMissedMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/loginViaQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/messageObserve.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/messageTypes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/notifications/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/notifications/konchatNotifications.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/notifications/updateAvatar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/notifications/usersNameChanged.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/oauth.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/openedRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/otr.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/readMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/reloadRoomAfterLogin.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/autotranslate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/emoji.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/hexcolor.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/highlightWords.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/katex.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderMessage/mentionsMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderNotification/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/renderNotification/markdown.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/roomObserve.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/rootUrlChange.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/routes.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/setupWizard.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/slashCommands/federation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/slashCommands/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/slashCommands/list.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/streamMessage/autotranslate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/streamMessage/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/unread.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/userRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/userStatusManuallySet.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/startup/usersObserve.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/stories/contexts/ModalContextMock.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/stories/contexts/QueryClientProviderMock.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/stories/contexts/RouterContextMock.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/stories/contexts/ServerContextMock.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/stories/contexts/TranslationContextMock.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/stories/hooks/useAutoSequence.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/avatarUrlFromUsername.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/emojiUrlFromName.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/hasPermission.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/log.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/nrrargs.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/preference.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/renderEmoji.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/setting.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templateHelpers/userHasAllPermission.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/templates.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/AccountRouter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/AccountSidebar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/integrations/AccountIntegrationsPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/integrations/AccountIntegrationsRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/omnichannel/OmnichannelPreferencesPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/omnichannel/PreferencesConversationTranscript.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/AccountPreferencesPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/MyDataModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesGlobalSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesHighlightsSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesLocalizationSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesMessagesSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesMyDataSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesNotificationsSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesSoundSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/preferences/PreferencesUserPresenceSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/profile/AccountProfileForm.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/profile/AccountProfilePage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/profile/AccountProfileRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/profile/ActionConfirmModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/routes.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/security/AccountSecurityPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/security/AccountSecurityRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/security/BackupCodesModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/security/EndToEnd.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/security/TwoFactorEmail.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/security/TwoFactorTOTP.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/sidebarItems.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/tokens/AccountTokensPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/tokens/AccountTokensRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/tokens/AccountTokensTable/AccountTokensRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/tokens/AccountTokensTable/AccountTokensTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/tokens/AccountTokensTable/AddToken.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/account/tokens/AccountTokensTable/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/AdministrationLayout.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/AdministrationRouter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/EditableSettingsContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/CloudPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/CloudRoute.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/ConnectToCloudSection.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/CopyStep.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/ManualWorkspaceRegistrationModal.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/PasteStep.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/RegisterWorkspace.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/TroubleshootingSection.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/WhatIsItSection.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/WorkspaceLoginSection.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/WorkspaceRegistrationSection.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/components/RegisterWorkspaceCards.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/components/RegisterWorkspaceMenu.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/constants.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/hooks/useFeatureBullets.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/ConnectWorkspaceModal.tsx",["23064"],[],"import { Box, Button, ButtonGroup, Modal } from '@rocket.chat/fuselage';\nimport { useMethod, useSetModal, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts';\nimport React from 'react';\n\nimport useFeatureBullets from '../hooks/useFeatureBullets';\n\ntype ConnectWorkspaceModalProps = {\n\tonClose: () => void;\n\tonStatusChange?: () => void;\n};\n\nconst ConnectWorkspaceModal = ({ onClose, onStatusChange, ...props }: ConnectWorkspaceModalProps) => {\n\tconst t = useTranslation();\n\tconst setModal = useSetModal();\n\tconst bulletFeatures = useFeatureBullets();\n\tconst dispatchToastMessage = useToastMessageDispatch();\n\n\tconst connectWorkspace = useMethod('cloud:reconnectWorkspace');\n\n\tconst handleConnectWorkspace = async () => {\n\t\ttry {\n\t\t\tawait connectWorkspace();\n\t\t\tsetModal(null);\n\t\t\tdispatchToastMessage({ type: 'success', message: t('Connected') });\n\t\t} catch (error: unknown) {\n\t\t\tconsole.error(error);\n\t\t\tdispatchToastMessage({ type: 'error', message: error });\n\t\t} finally {\n\t\t\tonStatusChange && onStatusChange();\n\t\t}\n\t};\n\n\treturn (\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{t('Workspace_not_connected')}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{`${t('RegisterWorkspace_NotConnected_Subtitle')}:`}\n\t\t\t\t\t
    \n\t\t\t\t\t\t{bulletFeatures.map((features) => (\n\t\t\t\t\t\t\t
  • \n\t\t\t\t\t\t\t\t{features.title}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t{features.description}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t
  • \n\t\t\t\t\t\t))}\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t
\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t
\n\t);\n};\n\nexport default ConnectWorkspaceModal;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/DisconnectWorkspaceModal.tsx",["23065"],[],"import { Box, Button, ButtonGroup, Modal } from '@rocket.chat/fuselage';\nimport { useMethod, useSetModal, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts';\nimport React from 'react';\n\nimport useFeatureBullets from '../hooks/useFeatureBullets';\nimport RegisteredWorkspaceModal from './RegisteredWorkspaceModal';\n\ntype DisconnectWorkspaceModalProps = {\n\tonClose: () => void;\n\tonStatusChange?: () => void;\n};\n\nconst DisconnectWorkspaceModal = ({ onClose, onStatusChange, ...props }: DisconnectWorkspaceModalProps) => {\n\tconst t = useTranslation();\n\tconst setModal = useSetModal();\n\tconst bulletFeatures = useFeatureBullets();\n\tconst dispatchToastMessage = useToastMessageDispatch();\n\n\tconst disconnectWorkspace = useMethod('cloud:disconnectWorkspace');\n\n\tconst handleCancelAction = (): void => {\n\t\tconst handleModalClose = (): void => setModal(null);\n\t\tsetModal();\n\t};\n\n\tconst handleUnregister = async () => {\n\t\ttry {\n\t\t\tconst success = await disconnectWorkspace();\n\n\t\t\tif (!success) {\n\t\t\t\tthrow Error(t('RegisterWorkspace_Disconnect_Error'));\n\t\t\t}\n\n\t\t\tdispatchToastMessage({ type: 'success', message: t('Disconnected') });\n\n\t\t\tsetModal(null);\n\t\t} catch (error) {\n\t\t\tdispatchToastMessage({ type: 'error', message: error });\n\t\t} finally {\n\t\t\tawait (onStatusChange && onStatusChange());\n\t\t}\n\t};\n\n\treturn (\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{t('Are_you_sure')}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{`${t('RegisterWorkspace_Disconnect_Subtitle')}: `}\n\t\t\t\t\t
    \n\t\t\t\t\t\t{bulletFeatures.map((item, index) => (\n\t\t\t\t\t\t\t
  • \n\t\t\t\t\t\t\t\t{item.title}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t{item.disconnect}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t
  • \n\t\t\t\t\t\t))}\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t
\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t
\n\t);\n};\n\nexport default DisconnectWorkspaceModal;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisterWorkspaceModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupModal.tsx",["23066"],[],"import { useSetModal } from '@rocket.chat/ui-contexts';\nimport React, { useEffect, useState } from 'react';\n\nimport { validateEmail } from '../../../../../../lib/emailValidator';\nimport RegisteredWorkspaceModal from '../RegisteredWorkspaceModal';\nimport RegisterWorkspaceSetupStepOneModal from './RegisterWorkspaceSetupStepOneModal';\nimport RegisterWorkspaceSetupStepTwoModal from './RegisterWorkspaceSetupStepTwoModal';\n\ntype RegisterWorkspaceSetupModalProps = {\n\tonClose: () => void;\n\tonStatusChange?: () => void;\n\tisConnectedToCloud: boolean | string;\n};\n\nconst RegisterWorkspaceSetupModal = ({ onClose, isConnectedToCloud }: RegisterWorkspaceSetupModalProps) => {\n\tconst setModal = useSetModal();\n\n\tconst [step, setStep] = useState(1);\n\tconst [email, setEmail] = useState('');\n\tconst [terms, setTerms] = useState(false);\n\tconst [validInfo, setValidInfo] = useState(false);\n\tconst [intentData, setIntentData] = useState({\n\t\tdevice_code: '',\n\t\tinterval: 0,\n\t\tuser_code: '',\n\t});\n\n\t// reset validInfo when users go back to step 1\n\tuseEffect(() => {\n\t\tsetValidInfo(false);\n\t}, [step]);\n\n\tuseEffect(() => {\n\t\tif (step === 1) {\n\t\t\tsetValidInfo(validateEmail(email) && terms);\n\t\t}\n\t}, [email, terms]);\n\n\tconst onSuccess = () => {\n\t\tconst handleModalClose = (): void => setModal(null);\n\t\tsetModal();\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t{step === 1 ? (\n\t\t\t\t\n\t\t\t) : (\n\t\t\t\t\n\t\t\t)}\n\t\t\n\t);\n};\n\nexport default RegisterWorkspaceSetupModal;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupStepOneModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupStepTwoModal.tsx",["23067"],[],"import { Modal, Box, Field, TextInput } from '@rocket.chat/fuselage';\nimport { useEndpoint, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts';\nimport React, { useCallback, useEffect } from 'react';\nimport { Trans } from 'react-i18next';\n\ntype Props = {\n\temail: string;\n\tstep: number;\n\tsetStep: (step: number) => void;\n\tonClose: () => void;\n\tintentData: {\n\t\tdevice_code: string;\n\t\tinterval: number;\n\t\tuser_code: string;\n\t};\n\tonSuccess: () => void;\n};\n\nconst setIntervalTime = (interval?: number): number => (interval ? interval * 1000 : 0);\n\nconst RegisterWorkspaceSetupStepTwoModal = ({ email, step, setStep, onClose, intentData, onSuccess, ...props }: Props) => {\n\tconst t = useTranslation();\n\tconst dispatchToastMessage = useToastMessageDispatch();\n\n\tconst cloudConfirmationPoll = useEndpoint('GET', '/v1/cloud.confirmationPoll');\n\tconst createRegistrationIntent = useEndpoint('POST', '/v1/cloud.createRegistrationIntent');\n\n\tconst handleBackFromConfirmation = (): void => setStep(step - 1);\n\n\tconst handleResendRegistrationEmail = async () => {\n\t\ttry {\n\t\t\tawait createRegistrationIntent({ resend: true, email });\n\t\t\tdispatchToastMessage({ type: 'success', message: t('Email_sent') });\n\t\t} catch (error: unknown) {\n\t\t\tdispatchToastMessage({ type: 'error', message: error });\n\t\t}\n\t};\n\n\tconst getConfirmation = useCallback(async () => {\n\t\ttry {\n\t\t\tconst { pollData } = await cloudConfirmationPoll({\n\t\t\t\tdeviceCode: intentData.device_code,\n\t\t\t});\n\n\t\t\tif ('successful' in pollData && pollData.successful) {\n\t\t\t\tdispatchToastMessage({ type: 'success', message: t('Workspace_registered') });\n\t\t\t\tonSuccess();\n\t\t\t}\n\t\t} catch (error: any) {\n\t\t\tconsole.log(error);\n\t\t}\n\t}, [cloudConfirmationPoll, intentData.device_code, dispatchToastMessage, t]);\n\n\tuseEffect(() => {\n\t\tconst pollInterval = setInterval(() => getConfirmation(), setIntervalTime(intentData.interval));\n\n\t\treturn (): void => clearInterval(pollInterval);\n\t}, [getConfirmation, intentData]);\n\n\treturn (\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{t('RegisterWorkspace_Setup_Steps', { step, numberOfSteps: 2 })}\n\t\t\t\t\t{t('Awaiting_confirmation')}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tEmail sent to{' '}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t{email}{' '}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\twith a confirmation link.\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t{t('RegisterWorkspace_Setup_Email_Verification')}\n\t\t\t\t\t\n\t\t\t\t\t\t{t('Security_code')}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\tDidn’t receive email?{' '}\n\t\t\t\t\t\n\t\t\t\t\t\tResend\n\t\t\t\t\t{' '}\n\t\t\t\t\tor{' '}\n\t\t\t\t\t\n\t\t\t\t\t\tchange email\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\n\t);\n};\n\nexport default RegisterWorkspaceSetupStepTwoModal;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisterWorkspaceSetupModal/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisterWorkspaceTokenModal.tsx",["23068"],[],"import { Box, Button, ButtonGroup, Field, Modal, TextInput } from '@rocket.chat/fuselage';\nimport { useMethod, useSetModal, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts';\nimport type { ChangeEvent } from 'react';\nimport React, { useState } from 'react';\nimport { Trans } from 'react-i18next';\n\nimport WorkspaceRegistrationModal from './RegisterWorkspaceModal';\n\ntype RegisterWorkspaceTokenModalProps = {\n\tonClose: () => void;\n\tonStatusChange?: () => void;\n\tisConnectedToCloud: boolean | string;\n};\n\nconst RegisterWorkspaceTokenModal = ({ onClose, onStatusChange, isConnectedToCloud, ...props }: RegisterWorkspaceTokenModalProps) => {\n\tconst setModal = useSetModal();\n\tconst t = useTranslation();\n\tconst dispatchToastMessage = useToastMessageDispatch();\n\tconst connectWorkspace = useMethod('cloud:connectWorkspace');\n\n\tconst [token, setToken] = useState('');\n\tconst [processing, setProcessing] = useState(false);\n\tconst [error, setError] = useState(false);\n\n\tconst handleBackAction = (): void => {\n\t\tconst handleModalClose = (): void => setModal(null);\n\t\tsetModal();\n\t};\n\n\tconst handleTokenChange = (event: ChangeEvent) => {\n\t\tsetToken(event.target.value);\n\t};\n\n\tconst isToken = token.length > 0;\n\n\tconst handleConnectButtonClick = async () => {\n\t\tsetProcessing(true);\n\t\tsetError(false);\n\n\t\ttry {\n\t\t\tconst isConnected = await connectWorkspace(token);\n\n\t\t\tif (!isConnected) {\n\t\t\t\tthrow Error(t('RegisterWorkspace_Connection_Error'));\n\t\t\t}\n\n\t\t\tsetModal(null);\n\n\t\t\tdispatchToastMessage({ type: 'success', message: t('Connected') });\n\t\t} catch (error) {\n\t\t\tdispatchToastMessage({ type: 'error', message: error });\n\t\t\tsetError(true);\n\t\t} finally {\n\t\t\tawait (onStatusChange && onStatusChange());\n\t\t\tsetProcessing(false);\n\t\t}\n\t};\n\n\treturn (\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{t('RegisterWorkspace_Token_Title')}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t1. Go to:{' '}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tcloud.rocket.chat {'>'} Workspaces\n\t\t\t\t\t\t{' '}\n\t\t\t\t\t\tand click{' '}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\"Register self-managed\"\n\t\t\t\t\t\t\n\t\t\t\t\t\t.\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t{`2. ${t('RegisterWorkspace_Token_Step_Two')}`}\n\t\t\t\t\n\t\t\t\t\t{t('Registration_Token')}\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t{error && {t('Token_Not_Recognized')}}\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\n\t);\n};\n\nexport default RegisterWorkspaceTokenModal;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/cloud/modals/RegisteredWorkspaceModal.tsx",["23069"],[],"import { Box, Button, ButtonGroup, Icon, Modal } from '@rocket.chat/fuselage';\nimport { useSafely } from '@rocket.chat/fuselage-hooks';\nimport { useMethod, useSetModal, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts';\nimport React, { useState } from 'react';\n\nimport useFeatureBullets from '../hooks/useFeatureBullets';\nimport DisconnectWorkspaceModal from './DisconnectWorkspaceModal';\n\ntype RegisteredWorkspaceModalProps = {\n\tonClose: () => void;\n\tonStatusChange?: () => void;\n};\n\nconst RegisteredWorkspaceModal = ({ onClose, onStatusChange, ...props }: RegisteredWorkspaceModalProps) => {\n\tconst t = useTranslation();\n\tconst setModal = useSetModal();\n\tconst dispatchToastMessage = useToastMessageDispatch();\n\tconst bulletFeatures = useFeatureBullets();\n\tconst [isSyncing, setSyncing] = useSafely(useState(false));\n\n\tconst syncWorkspace = useMethod('cloud:syncWorkspace');\n\n\tconst handleDisconnect = (): void => {\n\t\tconst handleModalClose = (): void => setModal(null);\n\t\tsetModal();\n\t};\n\n\tconst handleSyncAction = async () => {\n\t\tsetSyncing(true);\n\n\t\ttry {\n\t\t\tconst isSynced = await syncWorkspace();\n\n\t\t\tif (!isSynced) {\n\t\t\t\tthrow Error(t('RegisterWorkspace_Syncing_Error'));\n\t\t\t}\n\n\t\t\tdispatchToastMessage({ type: 'success', message: t('RegisterWorkspace_Syncing_Complete') });\n\t\t\tsetModal(null);\n\t\t} catch (error) {\n\t\t\tdispatchToastMessage({ type: 'error', message: error });\n\t\t} finally {\n\t\t\tawait (onStatusChange && onStatusChange());\n\t\t\tsetSyncing(false);\n\t\t}\n\t};\n\n\treturn (\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{t('Workspace_registered')}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{`${t('RegisterWorkspace_Registered_Subtitle')}: `}\n\t\t\t\t\t
    \n\t\t\t\t\t\t{bulletFeatures.map((item, index) => (\n\t\t\t\t\t\t\t
  • \n\t\t\t\t\t\t\t\t{item.title}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t{item.description}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t
  • \n\t\t\t\t\t\t))}\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t
\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t
\n\t);\n};\n\nexport default RegisteredWorkspaceModal;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customEmoji/CustomEmoji.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customEmoji/CustomEmojiRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customEmoji/EditCustomEmojiWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customSounds/CustomSoundRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customSounds/CustomSoundsRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customSounds/EditCustomSound.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customSounds/EditSound.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customSounds/lib.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserActiveConnections.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusDisabledModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusFormWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusService.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/CustomUserStatusTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusTable/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/hooks/useActiveConnections.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/customUserStatus/hooks/useStatusDisabledModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/emailInbox/EmailInboxForm.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/emailInbox/EmailInboxFormWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/emailInbox/EmailInboxPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/emailInbox/EmailInboxRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/emailInbox/EmailInboxTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/emailInbox/SendTestButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/FederationDashboardPage.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/FederationDashboardPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/FederationDashboardRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/OverviewSection.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/OverviewSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/ServersSection.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/federationDashboard/ServersSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportHistoryPage.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportHistoryPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportOperationSummary.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportOperationSummary.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportOperationSummarySkeleton.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportProgressPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportRoute.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/ImportTypes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/NewImportPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/NewImportPage.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/PrepareChannels.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/PrepareImportPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/PrepareUsers.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/import/useErrorHandler.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/DeploymentCard.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/DeploymentCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/DescriptionList.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/DescriptionList.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/DescriptionListEntry.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/Feature.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/Feature.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/FederationCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/CardHeader.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/DNSRecordItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/DNSRecords.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/DNSText.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/FederationModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/InviteUsers.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/Types.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/FederationModal/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/Section.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/SectionStatusIcon.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/components/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/FederationCard/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/InformationPage.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/InformationPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/InformationRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/InstancesModal.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/InstancesModal.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/LicenseCard.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/LicenseCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/OfflineLicenseModal.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/OfflineLicenseModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/UsageCard.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/UsageCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/UsagePieGraph.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/info/UsagePieGraph.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/FilterByTypeAndText.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/IncomingWebhookForm.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/IntegrationRow.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/IntegrationsPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/IntegrationsRoute.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/IntegrationsTable.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/OutgoiongWebhookForm.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/EditIncomingWebhook.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/EditIncomingWebhookWithData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/EditIntegrationsPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/EditOutgoingWebhook.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/EditOutgoingWebhookWithData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/HistoryContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/HistoryItem.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/edit/OutgoingWebhookHistoryPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/helpers/triggerWords.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/new/NewBot.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/new/NewIncomingWebhook.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/new/NewIntegrationsPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/new/NewOutgoingWebhook.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/new/NewZapier.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/integrations/useExampleIncomingData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/invites/InviteRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/invites/InvitesPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/invites/InvitesRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/mailer/Mailer.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/mailer/Mailer.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/mailer/MailerRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/oauthApps/EditOauthAppWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/oauthApps/OAuthAddApp.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/oauthApps/OAuthAppsPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/oauthApps/OAuthAppsRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/oauthApps/OAuthAppsTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/CustomRoleUpsellModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/EditRolePage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/EditRolePageWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsContextBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsRouter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsTable/PermissionsTableFilter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsTable/RoleCell.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsTable/RoleHeader.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/PermissionsTable/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/RoleForm.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRolePage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRolePageWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTableRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/UsersInRoleTableWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRoleTable/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/UsersInRole/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/hooks/useChangeRole.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/hooks/usePermissionsAndRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/permissions/hooks/useRole.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/EditRoom.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/EditRoomContextBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/EditRoomWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/FilterByTypeAndText.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/RoomsPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/RoomsRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/rooms/RoomsTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/routes.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/EditableSettingsProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/GroupPage.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/GroupPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/GroupPageSkeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/GroupSelector.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/GroupSelector.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/MemoizedSetting.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/ResetSettingButton.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/ResetSettingButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/Section.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/Section.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/SectionSkeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/Setting.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/Setting.tsx",[],["23070","23071","23072","23073"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/SettingSkeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/SettingsGroupCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/SettingsPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/SettingsRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/AssetsGroupPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/CreateOAuthModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/GenericGroupPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/LDAPGroupPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/OAuthGroupPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/TabbedGroupPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/VoipGroupPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/voip/AssignAgentButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/voip/AssignAgentModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/voip/RemoveAgentButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/groups/voip/VoipExtensionsPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/hooks/useSettingsGroups.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/ActionSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/ActionSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/AssetSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/AssetSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/BooleanSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/BooleanSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/CodeMirror.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/CodeSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/CodeSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/ColorSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/ColorSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/FontSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/FontSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/GenericSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/GenericSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/IntSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/IntSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/LanguageSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/LanguageSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/LookupSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/MultiSelectSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/MultiSelectSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/PasswordSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/PasswordSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/RelativeUrlSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/RelativeUrlSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/RoomPickSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/SelectSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/SelectSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/SelectTimezoneSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/StringSettingInput.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/settings/inputs/StringSettingInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/sidebar/AdminSidebar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/sidebar/AdminSidebarPages.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/sidebar/UpgradeTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/sidebarItems.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/upgrade/UpgradePage/UpgradePage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/upgrade/UpgradePage/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/upgrade/UpgradePageError/UpgradePageError.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/upgrade/UpgradePageError/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/AddUser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/AdminUserInfoActions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/AdminUserInfoWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/EditUser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/EditUserWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/InviteUsers.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/UserForm.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/UsersPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/UsersRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/UsersTable/UsersTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/UsersTable/UsersTableRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/UsersTable/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useChangeAdminStatusAction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useChangeUserStatusAction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useConfirmOwnerChanges.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useDeleteUserAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useResetE2EEKeyAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useResetTOTPAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/users/hooks/useSendInvitationEmailMutation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/viewLogs/ServerLogs.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/viewLogs/ViewLogsPage.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/viewLogs/ViewLogsPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/viewLogs/ViewLogsRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/admin/viewLogs/ansispan.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/banners/BannerRegion.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/banners/LegacyBanner.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/banners/UiKitBanner.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/blocks/ConnectedModalBlock.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/blocks/ModalBlock.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/blocks/getButtonStyle.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/blocks/textParsers.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/composer/AudioMessageRecorder/AudioMessageRecorder.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/composer/AudioMessageRecorder/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/composer/EmojiPickerWrapper.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/composer/VideoMessageRecorder/VideoMessageRecorder.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/composer/VideoMessageRecorder/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/DirectoryPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/RoomTags.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/hooks/useDirectoryQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/channels/ChannelsTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTableRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/teams/TeamsTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTableRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/teams/TeamsTable/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/users/UsersTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTableRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/directory/tabs/users/UsersTable/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/e2e/EnterE2EPasswordModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/e2e/SaveE2EPasswordModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/CustomHomePage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/CustomHomePageContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/DefaultHomePage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/HomePage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/HomePageHeader.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/HomepageGridItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/AddUsersCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/CreateChannelsCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/CustomContentCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/DesktopAppsCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/DocumentationCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/JoinRoomsCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/home/cards/MobileAppsCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useActionSpread.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useDepartmentsByUnitsList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useImperativeModal.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useMembersList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useMonitorsList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useThemeShortcut.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/hooks/useUpgradeTabParams.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/invite/InvitePage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/invite/SecretURLPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/mailer/MailerUnsubscriptionPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AccordionLoading.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/AppDetailsPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/AppDetailsPageHeader.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/AppDetailsPageLoading.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/AppDetailsPageTabs.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/AppDetails.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/AppDetailsAPIs.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogs.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogsItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogsItemEntry.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/AppReleases.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/AppReleasesItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppRequests/AppRequestItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppRequests/AppRequests.tsx",[],["23074"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppRequests/AppRequestsLoading.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppSecurity/AppSecurity.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppSecurity/AppSecurityLabel.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppSettings/AppSetting.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppSettings/AppSettings.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppSettings/AppSettingsAssembler.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppSettings/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatusPriceDisplay.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppInstallPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppMenu.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppPermissionsReviewModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppUpdateModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsContext.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsList/AppRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsList/AppsList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsList/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/AppsFilters.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/AppsPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/AppsPageConnectionError.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/AppsPageContent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/AppsPageContentBody.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/AppsPageContentSkeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/FeaturedAppsSections.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/NoAppRequestsEmptyState.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/NoInstalledAppMatchesEmptyState.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/NoInstalledAppsEmptyState.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/NoMarketplaceOrInstalledAppMatchesEmptyState.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/PrivateEmptyState.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/PrivateEmptyState.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsPage/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsProvider.tsx",[],["23075"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/AppsRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/BundleChips.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/CloudLoginModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/IframeModal.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/MarketplaceRouter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/MarketplaceSidebar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/UnlimitedAppsUpsellModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/AppInstallModal/AppInstallModal.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/AppInstallModal/AppInstallModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/AppPermissionsList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/BannerEnterpriseTrialEnded.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/CategoryFilter/CategoryDropDown.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/CategoryFilter/CategoryDropDown.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/CategoryFilter/CategoryDropDownAnchor.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/CategoryFilter/CategoryDropDownList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/CategoryFilter/TagList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/DropDownListWrapper.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/EnabledAppsCount.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/MarketplaceHeader.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/RadioButtonList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/RadioDropDown/RadioDownAnchor.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/RadioDropDown/RadioDropDown.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/RadioDropDown/RadioDropDown.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/ScreenshotCarousel.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/ScreenshotCarouselAnchor.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/UninstallGrandfatheredAppModal/UninstallGrandfatheredAppModal.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/components/UninstallGrandfatheredAppModal/UninstallGrandfatheredAppModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/definitions/AppInfo.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/definitions/CategoryDropdownDefinitions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/definitions/RadioDropDownDefinitions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/filterAppsByCategories.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/filterAppsByDisabled.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/filterAppsByEnabled.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/filterAppsByFree.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/filterAppsByPaid.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/filterAppsByText.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/installApp.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/isValidReference.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/marketplaceActions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/normalizeFeaturedApps.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/onMouseEventPreventSideEffects.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/sortAppsByAlphabeticalOrInverseOrder.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/sortAppsByClosestOrFarthestModificationDate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers/updateApp.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/helpers.ts",["23076"],["23077"],"import { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus';\nimport type { IApiEndpointMetadata } from '@rocket.chat/apps-engine/definition/api';\nimport type { App, AppPricingPlan, PurchaseType } from '@rocket.chat/core-typings';\nimport semver from 'semver';\n\nimport { t } from '../../../app/utils/client';\nimport { Utilities } from '../../../ee/lib/misc/Utilities';\nimport { dispatchToastMessage } from '../../lib/toast';\n\nexport const appEnabledStatuses = [AppStatus.AUTO_ENABLED, AppStatus.MANUALLY_ENABLED];\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\ninterface ApiError {\n\txhr: {\n\t\tresponseJSON: {\n\t\t\terror: string;\n\t\t\tstatus: string;\n\t\t\tmessages: string[];\n\t\t\tpayload?: any;\n\t\t};\n\t};\n}\n\nconst appErroredStatuses = [\n\tAppStatus.COMPILER_ERROR_DISABLED,\n\tAppStatus.ERROR_DISABLED,\n\tAppStatus.INVALID_SETTINGS_DISABLED,\n\tAppStatus.INVALID_LICENSE_DISABLED,\n];\n\nexport type Actions = 'update' | 'install' | 'purchase' | 'request';\n\ntype appButtonResponseProps = {\n\taction: Actions;\n\ticon?: 'reload' | 'warning';\n\tlabel: 'Update' | 'Install' | 'Subscribe' | 'See Pricing' | 'Try now' | 'Buy' | 'Request' | 'Requested';\n};\n\nexport type appStatusSpanResponseProps = {\n\ttype?: 'failed' | 'warning';\n\ticon?: 'warning' | 'checkmark-circled' | 'check';\n\tlabel:\n\t\t| 'Config Needed'\n\t\t| 'Failed'\n\t\t| 'Disabled'\n\t\t| 'Disabled*'\n\t\t| 'Trial period'\n\t\t| 'Enabled'\n\t\t| 'Enabled*'\n\t\t| 'Incompatible'\n\t\t| 'request'\n\t\t| 'requests'\n\t\t| 'Requested';\n\ttooltipText?: string;\n};\n\ntype PlanType = 'Subscription' | 'Paid' | 'Free';\n\ntype FormattedPriceAndPlan = {\n\ttype: PlanType;\n\tprice: string;\n};\n\nexport const apiCurlGetter =\n\t(absoluteUrl: (path: string) => string) =>\n\t(method: string, api: IApiEndpointMetadata): string[] => {\n\t\tconst example = api.examples?.[method];\n\t\treturn Utilities.curl({\n\t\t\turl: absoluteUrl(api.computedPath),\n\t\t\tmethod,\n\t\t\tparams: example?.params,\n\t\t\tquery: example?.query,\n\t\t\tcontent: example?.content,\n\t\t\theaders: example?.headers,\n\t\t\tauth: '',\n\t\t}).split('\\n');\n\t};\n\nexport function handleInstallError(apiError: ApiError | Error): void {\n\tif (apiError instanceof Error) {\n\t\tdispatchToastMessage({ type: 'error', message: apiError.message });\n\t\treturn;\n\t}\n\n\tif (!apiError.xhr || !apiError.xhr.responseJSON) {\n\t\treturn;\n\t}\n\n\tconst { status, messages, error, payload = null } = apiError.xhr.responseJSON;\n\n\tlet message: string;\n\n\tswitch (status) {\n\t\tcase 'storage_error':\n\t\t\tmessage = messages.join('');\n\t\t\tbreak;\n\t\tcase 'app_user_error':\n\t\t\tmessage = messages.join('');\n\t\t\tif (payload?.username) {\n\t\t\t\tmessage = t('Apps_User_Already_Exists', { username: payload.username });\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tif (error) {\n\t\t\t\tmessage = error;\n\t\t\t} else {\n\t\t\t\tmessage = t('There_has_been_an_error_installing_the_app');\n\t\t\t}\n\t}\n\n\tdispatchToastMessage({ type: 'error', message });\n}\n\nconst shouldHandleErrorAsWarning = (message: string): boolean => {\n\tconst warnings = ['Could not reach the Marketplace'];\n\n\treturn warnings.includes(message);\n};\n\nexport const handleAPIError = (error: unknown): void => {\n\tif (error instanceof Error) {\n\t\tconst { message } = error;\n\n\t\tif (shouldHandleErrorAsWarning(message)) {\n\t\t\tdispatchToastMessage({ type: 'warning', message });\n\t\t\treturn;\n\t\t}\n\n\t\tdispatchToastMessage({ type: 'error', message });\n\t}\n};\n\nexport const warnAppInstall = (appName: string, status: AppStatus): void => {\n\tif (appErroredStatuses.includes(status)) {\n\t\tdispatchToastMessage({ type: 'error', message: (t(`App_status_${status}`), appName) });\n\t\treturn;\n\t}\n\n\tdispatchToastMessage({ type: 'success', message: `${appName} installed` });\n};\n\nexport const warnEnableDisableApp = (appName: string, status: AppStatus, type: string): void => {\n\tif (appErroredStatuses.includes(status)) {\n\t\tdispatchToastMessage({ type: 'error', message: (t(`App_status_${status}`), appName) });\n\t\treturn;\n\t}\n\n\tif (type === 'enable') {\n\t\tdispatchToastMessage({ type: 'success', message: `${appName} enabled` });\n\t\treturn;\n\t}\n\n\tdispatchToastMessage({ type: 'success', message: `${appName} disabled` });\n};\n\nexport const warnStatusChange = (appName: string, status: AppStatus): void => {\n\tif (appErroredStatuses.includes(status)) {\n\t\tdispatchToastMessage({ type: 'error', message: (t(`App_status_${status}`), appName) });\n\t\treturn;\n\t}\n\n\tdispatchToastMessage({ type: 'info', message: (t(`App_status_${status}`), appName) });\n};\n\nexport const appButtonProps = ({\n\tinstalled,\n\tversion,\n\tmarketplaceVersion,\n\tisPurchased,\n\tprice,\n\tpurchaseType,\n\tsubscriptionInfo,\n\tpricingPlans,\n\tisEnterpriseOnly,\n\tversionIncompatible,\n\tisAdminUser,\n\trequestedEndUser,\n}: App & { isAdminUser: boolean }): appButtonResponseProps | undefined => {\n\tif (!isAdminUser) {\n\t\tif (requestedEndUser) {\n\t\t\treturn {\n\t\t\t\taction: 'request',\n\t\t\t\tlabel: 'Requested',\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\taction: 'request',\n\t\t\tlabel: 'Request',\n\t\t};\n\t}\n\n\tconst canUpdate = installed && version && marketplaceVersion && semver.lt(version, marketplaceVersion);\n\tif (canUpdate) {\n\t\tif (versionIncompatible) {\n\t\t\treturn {\n\t\t\t\taction: 'update',\n\t\t\t\ticon: 'warning',\n\t\t\t\tlabel: 'Update',\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\taction: 'update',\n\t\t\ticon: 'reload',\n\t\t\tlabel: 'Update',\n\t\t};\n\t}\n\n\tif (installed) {\n\t\treturn;\n\t}\n\n\tconst canDownload = isPurchased;\n\tif (canDownload) {\n\t\tif (versionIncompatible) {\n\t\t\treturn {\n\t\t\t\taction: 'install',\n\t\t\t\ticon: 'warning',\n\t\t\t\tlabel: 'Install',\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\taction: 'install',\n\t\t\tlabel: 'Install',\n\t\t};\n\t}\n\n\tconst canSubscribe = purchaseType === 'subscription' && !subscriptionInfo.status;\n\tif (canSubscribe) {\n\t\tconst cannotTry = pricingPlans.every((currentPricingPlan) => currentPricingPlan.trialDays === 0);\n\t\tconst isTierBased = pricingPlans.every((currentPricingPlan) => currentPricingPlan.tiers && currentPricingPlan.tiers.length > 0);\n\n\t\tif (versionIncompatible) {\n\t\t\treturn {\n\t\t\t\taction: 'purchase',\n\t\t\t\tlabel: 'Subscribe',\n\t\t\t\ticon: 'warning',\n\t\t\t};\n\t\t}\n\n\t\tif (cannotTry || isEnterpriseOnly) {\n\t\t\treturn {\n\t\t\t\taction: 'purchase',\n\t\t\t\tlabel: 'Subscribe',\n\t\t\t};\n\t\t}\n\n\t\tif (isTierBased) {\n\t\t\treturn {\n\t\t\t\taction: 'purchase',\n\t\t\t\tlabel: 'See Pricing',\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\taction: 'purchase',\n\t\t\tlabel: 'Try now',\n\t\t};\n\t}\n\n\tconst canBuy = price > 0;\n\tif (canBuy) {\n\t\tif (versionIncompatible) {\n\t\t\treturn {\n\t\t\t\taction: 'purchase',\n\t\t\t\tlabel: 'Buy',\n\t\t\t\ticon: 'warning',\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\taction: 'purchase',\n\t\t\tlabel: 'Buy',\n\t\t};\n\t}\n\n\tif (versionIncompatible) {\n\t\treturn {\n\t\t\taction: 'purchase',\n\t\t\tlabel: 'Install',\n\t\t\ticon: 'warning',\n\t\t};\n\t}\n\n\treturn {\n\t\taction: 'purchase',\n\t\tlabel: 'Install',\n\t};\n};\n\nexport const appIncompatibleStatusProps = (): appStatusSpanResponseProps => ({\n\ticon: 'check',\n\tlabel: 'Incompatible',\n\ttooltipText: t('App_version_incompatible_tooltip'),\n});\n\nexport const appStatusSpanProps = (\n\t{ installed, status, subscriptionInfo, appRequestStats, migrated }: App,\n\tcontext?: string,\n\tisAppDetailsPage?: boolean,\n): appStatusSpanResponseProps | undefined => {\n\tconst isEnabled = status && appEnabledStatuses.includes(status);\n\tif (installed) {\n\t\tif (isEnabled) {\n\t\t\treturn migrated\n\t\t\t\t? {\n\t\t\t\t\t\tlabel: 'Enabled*',\n\t\t\t\t\t\ttooltipText: t('Grandfathered_app'),\n\t\t\t\t }\n\t\t\t\t: {\n\t\t\t\t\t\tlabel: 'Enabled',\n\t\t\t\t };\n\t\t}\n\n\t\treturn migrated\n\t\t\t? {\n\t\t\t\t\tlabel: 'Disabled*',\n\t\t\t\t\ttooltipText: t('Grandfathered_app'),\n\t\t\t }\n\t\t\t: {\n\t\t\t\t\ttype: 'warning',\n\t\t\t\t\tlabel: 'Disabled',\n\t\t\t };\n\t}\n\n\tconst isFailed = status && appErroredStatuses.includes(status);\n\tif (isFailed) {\n\t\treturn {\n\t\t\ttype: 'failed',\n\t\t\ticon: 'warning',\n\t\t\tlabel: status === AppStatus.INVALID_SETTINGS_DISABLED ? 'Config Needed' : 'Failed',\n\t\t};\n\t}\n\n\tconst isOnTrialPeriod = subscriptionInfo && subscriptionInfo.status === 'trialing';\n\tif (isOnTrialPeriod) {\n\t\treturn {\n\t\t\ticon: 'checkmark-circled',\n\t\t\tlabel: 'Trial period',\n\t\t};\n\t}\n\n\tif (context === 'requested' && appRequestStats) {\n\t\tif (isAppDetailsPage) {\n\t\t\treturn {\n\t\t\t\tlabel: 'Requested',\n\t\t\t};\n\t\t}\n\n\t\tif (appRequestStats.totalUnseen) {\n\t\t\treturn {\n\t\t\t\tlabel: appRequestStats.totalUnseen > 1 ? 'requests' : 'request',\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tlabel: appRequestStats.totalSeen > 1 ? 'requests' : 'request',\n\t\t};\n\t}\n};\n\nexport const appMultiStatusProps = (app: App, isAppDetailsPage: boolean, context: string): appStatusSpanResponseProps[] => {\n\tconst status = appStatusSpanProps(app, context, isAppDetailsPage);\n\tconst statuses = [];\n\n\tif (app?.versionIncompatible !== undefined && !isAppDetailsPage) {\n\t\tstatuses.push(appIncompatibleStatusProps());\n\t}\n\n\tif (status) {\n\t\tstatuses.push(status);\n\t}\n\n\treturn statuses;\n};\n\nexport const formatPrice = (price: number): string => `\\$${price.toFixed(2)}`;\n\nexport const formatPricingPlan = ({ strategy, price, tiers = [], trialDays }: AppPricingPlan): string => {\n\tconst { perUnit = false } = (Array.isArray(tiers) && tiers.find((tier) => tier.price === price)) || {};\n\n\tconst pricingPlanTranslationString = [\n\t\t'Apps_Marketplace_pricingPlan',\n\t\tArray.isArray(tiers) && tiers.length > 0 && '+*',\n\t\tstrategy,\n\t\ttrialDays && 'trialDays',\n\t\tperUnit && 'perUser',\n\t]\n\t\t.filter(Boolean)\n\t\t.join('_');\n\n\treturn t(pricingPlanTranslationString, {\n\t\tprice: formatPrice(price),\n\t\ttrialDays,\n\t});\n};\n\nexport const formatPriceAndPurchaseType = (\n\tpurchaseType: PurchaseType,\n\tpricingPlans: AppPricingPlan[],\n\tprice: number,\n): FormattedPriceAndPlan => {\n\tif (purchaseType === 'subscription') {\n\t\tconst type = 'Subscription';\n\t\tif (!pricingPlans || !Array.isArray(pricingPlans) || pricingPlans.length === 0) {\n\t\t\treturn { type, price: '-' };\n\t\t}\n\n\t\treturn { type, price: formatPricingPlan(pricingPlans[0]) };\n\t}\n\n\tif (price > 0) {\n\t\treturn { type: 'Paid', price: formatPrice(price) };\n\t}\n\n\treturn { type: 'Free', price: '-' };\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useAppInfo.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useAppInstallationHandler.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useAppRequestStats.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useAppRequests.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useAppsCountQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useCategories.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useCategoryFlatList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useCategoryToggle.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useFeaturedApps.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useFilteredApps.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useLogs.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useOpenAppPermissionsReviewModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useOpenIncompatibleModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/hooks/useRadioToggle.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/lib/getManifestFromZippedApp.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/routes.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/sidebarItems.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/marketplace/types.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/meet/CallPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/meet/MeetPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/meet/OngoingCallDuration.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/modal/ModalRegion.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/notAuthorized/NotAuthorizedPage.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/notAuthorized/NotAuthorizedPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/notFound/NotFoundPage.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/notFound/NotFoundPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/OAuthAuthorizationPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/OAuthErrorPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/components/AuthorizationFormPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/components/CurrentUserDisplay.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/components/ErrorPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/components/Layout.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/oauth/hooks/useOAuthAppQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/OmnichannelRouter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/additionalForms.tsx",[],["23078","23079"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AddAgent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentEdit.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentEditWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentInfo.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentInfoAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentInfoActions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentsPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentsPageRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/AgentsTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/RemoveAgentButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/agents/hooks/useQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/AgentOverview.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/AnalyticsPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/AnalyticsPage.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/DateRangePicker.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/DateRangePicker.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/InterchangeableChart.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/analytics/Overview.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/appearance/AppearanceForm.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/appearance/AppearanceForm.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/appearance/AppearancePage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/appearance/AppearancePageContainer.tsx",["23080"],[],"import { Callout } from '@rocket.chat/fuselage';\nimport { usePermission, useTranslation } from '@rocket.chat/ui-contexts';\nimport type { FC } from 'react';\nimport React from 'react';\n\nimport Page from '../../../components/Page';\nimport PageSkeleton from '../../../components/PageSkeleton';\nimport { AsyncStatePhase } from '../../../hooks/useAsyncState';\nimport { useEndpointData } from '../../../hooks/useEndpointData';\nimport NotAuthorizedPage from '../../notAuthorized/NotAuthorizedPage';\nimport AppearancePage from './AppearancePage';\n\nconst AppearancePageContainer: FC = () => {\n\tconst t = useTranslation();\n\n\tconst { value: data, phase: state, error } = useEndpointData('/v1/livechat/appearance');\n\n\tconst canViewAppearance = usePermission('view-livechat-appearance');\n\n\tif (!canViewAppearance) {\n\t\treturn ;\n\t}\n\n\tif (state === AsyncStatePhase.LOADING) {\n\t\treturn ;\n\t}\n\n\tif (!data || !data.appearance || error) {\n\t\treturn (\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t{t('Error')}\n\t\t\t\t\n\t\t\t\n\t\t);\n\t}\n\n\treturn ;\n};\n\nexport default AppearancePageContainer;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursForm.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursForm.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursFormContainer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursRouter.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/EditBusinessHoursPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/NewBusinessHoursPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/TimeRangeFieldsAssembler.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/TimeRangeInput.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/businessHours/mapBusinessHoursForm.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/components/AgentInfoDetails.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/components/CustomField.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/components/Field.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/components/Info.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/components/Label.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/ContactHistory.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/ContactHistoryItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/ContactHistoryVerticalBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessagesVerticalBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/MessageList/useHistoryMessageList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/contactHistory/useHistoryList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/CurrentChatsRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/CustomFieldsVerticalBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/FilterByText.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/Label.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/RemoveAllClosed.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/RemoveChatButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/hooks/useAllCustomFields.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/hooks/useCurrentChats.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/currentChats/hooks/useRemoveCurrentChatMutation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/CustomFieldsForm.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/CustomFieldsForm.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/CustomFieldsPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/CustomFieldsRoute.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/EditCustomFieldsPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/EditCustomFieldsPageContainer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/NewCustomFieldsPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/customFields/RemoveCustomFieldButton.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/AddAgent.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/AgentRow.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/ArchivedDepartmentsPageWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/ArchivedItemMenu.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/Count.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/DepartmentItemMenu.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/DepartmentsAgentsTable.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/DepartmentsPageWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/DepartmentsRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/DepartmentsTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/EditDepartment.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/EditDepartmentWithAllowedForwardData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/EditDepartmentWithData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/NewDepartment.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/Order.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/PermanentDepartmentRemovalModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/departments/RemoveAgentButton.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/CallsContextualBarDirectory.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/ChatsContextualBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/ContactContextualBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/ContextualBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/OmnichannelDirectoryPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/Call.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/CallTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/CallTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/CallTableRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/contextualBar/CallsContextualBarRoom.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/contextualBar/InfoField.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/contextualBar/VoipInfo.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/calls/contextualBar/VoipInfoCallButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/Chat.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/ChatTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/ChatTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatInfo.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatInfoDirectory.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/ChatsContextualBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/DepartmentField.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit/RoomEdit.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit/RoomEditWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/RoomEdit/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/chats/contextualBar/VisitorClientInfo.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/AgentField.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/CallDialpadButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/ContactField.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/FormSkeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/PriorityField.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/SlaField.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/SourceField.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/components/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/contacts/ContactTab.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/contacts/ContactTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactEditWithData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactInfo.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactNewEdit.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/contacts/contextualBar/ContactsContextualBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/useCustomFieldsMetadata.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/useDepartmentInfo.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/useOmnichannelRoomInfo.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/usePriorityInfo.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/useSlaInfo.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/useSlaPolicies.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/hooks/useVisitorInfo.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/directory/utils/formatCustomFieldsMetadata.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/installation/Installation.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/installation/Installation.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/installation/Wrapper.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/managers/AddManager.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/managers/ManagersRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/managers/RemoveManagerButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/queueList/QueueListFilter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/queueList/QueueListPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/queueList/hooks/useQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/queueList/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/RealTimeMonitoringPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/AgentStatusChart.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/Chart.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatDurationChart.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsChart.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerAgentChart.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ChatsPerDepartmentChart.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/ResponseTimesChart.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/getMomentChartLabelsAndData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/getMomentCurrentLabel.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/charts/useUpdateChartData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/counter/CounterContainer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/counter/CounterContainer.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/counter/CounterItem.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/counter/CounterRow.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/AgentsOverview.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ChatsOverview.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ConversationOverview.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/realTimeMonitoring/overviews/ProductivityOverview.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/routes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/sidebar/OmnichannelSidebar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/sidebarItems.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/EditTriggerPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/EditTriggerPageContainer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/NewTriggerPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/TriggersForm.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/TriggersForm.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/TriggersPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/TriggersRow.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/TriggersTable.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/triggers/TriggersTableContainer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/webhooks/WebhooksPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/omnichannel/webhooks/WebhooksPageContainer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Announcement/Announcement.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Announcement/Announcement.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Announcement/AnnouncementComponent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Announcement/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/DirectRoomHeader.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/FederatedRoomOriginServer.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Header.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/HeaderIconWithRoom.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/BackButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/QuickActions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/ToolBoxActionOptions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/usePutChatOnHoldMutation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useReturnChatToQueueMutation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/Omnichannel/VoipRoomHeader.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/ParentRoom.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/ParentRoomWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/ParentRoomWithEndpointData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/ParentTeam.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/RoomHeader.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/RoomTitle.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/ToolBox/ToolBox.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/ToolBox/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/icons/Encrypted.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/icons/Favorite.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/icons/Translate.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Header/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MemberListRouter.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/MessageList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/MessageListErrorBoundary.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/contexts/MessageHighlightContext.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/contexts/SelectedMessagesContext.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useAutoTranslate.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useAutoTranslate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useJumpToMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useKatex.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useLoadSurroundingMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useMessageBody.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/hooks/useParentMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/autoTranslate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/isMessageFirstUnread.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/isMessageNewDay.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/isMessageSequential.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/isOwnUserMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/isParsedMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/lib/isValidLink.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/providers/MessageHighlightProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/providers/MessageListProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/MessageList/providers/messageHighlightSubscription.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Room/ComposerSkeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/Room/Room.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/RoomNotFound.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/RoomSkeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/ShareLocation/ShareLocationModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/ShareLocation/getGeolocationPermission.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/ShareLocation/getGeolocationPosition.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/UserCard/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/BlazeTemplate.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/VerticalBarOldActions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/DropTargetOverlay.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/ErroredUploadProgressIndicator.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/JumpToRecentMessagesBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/LeaderBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/LoadingMessagesIndicator.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/NewMessagesButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/RetentionPolicyWarning.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/RoomBody.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/RoomForeword.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/UnreadMessagesIndicator.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/UploadProgressIndicator.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerAnonymous.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerBlocked.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerContainer.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerFederation/ComposerFederation.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerFederation/ComposerFederationDisabled.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerFederation/ComposerFederationJoinRoomDisabled.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerFederation/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerJoinWithPassword.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerMessage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/ComposerOmnichannel.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/ComposerOmnichannelInquiry.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/ComposerOmnichannelJoin.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/ComposerOmnichannelOnHold.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/hooks/useResumeChatOnHoldMutation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerOmnichannel/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerReadOnly.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerUserActionIndicator/ComposerUserActionIndicator.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerUserActionIndicator/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerUsersAction/ComposerUsersAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/ComposerVoIP.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/MessageComposer.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/RoomComposer/hooks/useAutoGrow.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/hooks/useMessageComposerCanJoin.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/hooks/useMessageComposerIsAnonymous.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/hooks/useMessageComposerIsBlocked.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/hooks/useMessageComposerIsReadOnly.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/hooks/useMessageComposerMergedRefs.ts",[],["23081","23082"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBox.tsx",[],["23083"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/ActionsToolbarDropdown.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/MessageBoxActionsToolbar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/actions/AudioMessageAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/actions/CreateDiscussionAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/actions/FileUploadAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/actions/ShareLocationAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/actions/VideoMessageAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/actions/WebdavAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxActionsToolbar/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxFormattingToolbar/FormattingToolbarDropdown.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxFormattingToolbar/MessageBoxFormattingToolbar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxFormattingToolbar/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/MessageBoxReplies.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/hooks/useMediaActionTitle.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/hooks/useMediaPermissions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/composer/messageBox/hooks/useMessageBoxAutoFocus.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/useDropTarget.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/useFileUploadDropTarget.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/useRetentionPolicy.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/useRoomMessageContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/useRoomRolesManagement.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/body/useUnreadMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/components/contextualBar/MessageListTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contexts/ChatContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contexts/ComposerPopupContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contexts/RoomAPIContext.ts",["23084"],[],"import { createContext } from 'react';\n\ntype RoomAPIContextValue = {};\n\nexport const RoomAPIContext = createContext(undefined);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contexts/RoomContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contexts/ToolboxContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Apps/Apps.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Apps/AppsWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Apps/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslate.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslate.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/AutoTranslate/AutoTranslateWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/AutoTranslate/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/DiscussionList.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/Row.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/components/DiscussionMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/components/Message.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/mapProps.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/useDiscussionsList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Discussions/withData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/ExportMessages/FileExport.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/ExportMessages/MailExportForm.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/ExportMessages/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/ChannelToTeamModal/ChannelToTeamModal.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/ChannelToTeamModal/StepOne.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/ChannelToTeamModal/StepTwo.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannel.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditChannelWithData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfo.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfoWithData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Info/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcutSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcuts.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcuts.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/KeyboardShortcutsWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/KeyboardShortcuts/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MentionsTab.tsx",[],["23085"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MessageSearchTab/MessageSearchTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearch.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MessageSearchTab/components/MessageSearchForm.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useMessageSearchProviderQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MessageSearchTab/hooks/useMessageSearchQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/MessageSearchTab/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/NotificationPreferences.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/NotificationPreferences.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/NotificationPreferencesWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/components/NotificationByDevice.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/components/NotificationToogle.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/components/Preferences.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/NotificationPreferences/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/OTR/OTR.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/OTR/OTR.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/OTR/OTRWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/OTR/components/OTREstablished.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/OTR/components/OTRStates.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/OTR/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/PinnedMessagesTab.tsx",[],["23086"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessages.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessages.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesDateTimeRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/PruneMessages/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/RoomFiles.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/RoomFiles.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/RoomFilesWithData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/Row.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/components/FileItem.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/components/FileItem.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/components/FileItemIcon.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/components/FileItemIcon.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/components/MenuItem.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useFilesList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/hooks/useMessageDeletionIsAllowed.js",[],["23087"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomFiles/lib/getDifference.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsers.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsers.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/AddUsersWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/AddUsers/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/EditInviteLink.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/InviteLink.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/InviteUsers.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/InviteUsers.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/InviteUsersWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/InviteUsers/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembers.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembers.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersActions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersRow.tsx",["23088"],[],"import type { IUser, IRoom } from '@rocket.chat/core-typings';\nimport type { MouseEvent, ReactElement } from 'react';\nimport React, { memo } from 'react';\n\nimport RoomMembersItem from './RoomMembersItem';\n\ntype RoomMembersRowProps = {\n\tuser: Pick;\n\tdata: {\n\t\tonClickView: (e: MouseEvent) => void;\n\t\trid: IRoom['_id'];\n\t};\n\tindex: number;\n\treload: () => void;\n};\n\nconst RoomMembersRow = ({ user, data: { onClickView, rid }, index, reload }: RoomMembersRowProps): ReactElement => {\n\tif (!user || !user._id) {\n\t\treturn ;\n\t}\n\n\treturn (\n\t\t\n\t);\n};\n\nexport default memo(RoomMembersRow);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/RoomMembersWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/RoomMembers/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/StarredMessagesTab.tsx",[],["23089"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/Thread.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/ThreadList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/Threads.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadChat.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadListItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadListMessage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadMessageList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadSkeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/components/ThreadTitle.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useGetMessageByID.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageJump.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessageListScrolling.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useLegacyThreadMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadMainMessageQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useThreadsList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/hooks/useToggleFollowingThreadMutation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/Threads/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/UserInfo/UserInfoActions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/UserInfo/UserInfoWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/UserInfo/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfBlockModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfConfigModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfListItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfListWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/VideoConfRecordList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfList/useVideoConfList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopup/IncomingPopup.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopup/OutgoingPopup.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopup/StartCallPopup.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopup/TimedVideoConfPopup.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopup/VideoConfPopupRoomInfo.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopup/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/VideoConfPopups.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/VideoConfPopups/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/contextualBar/VideoConference/useVideoConfWarning.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useAppsContextualBar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useGoToRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useGoToThread.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useGoToThreadList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useIsVisible.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useScrollMessageList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserHasRoomRole.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useBlockUserAction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useCallAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useChangeLeaderAction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useChangeModeratorAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useChangeOwnerAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useDirectMessageAction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useIgnoreUserAction.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useMuteUserAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useRemoveUserAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/hooks/useUserInfoActions/useUserInfoActions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/layout/RoomLayout.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/QuickActions/QuickActionsContext.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/QuickActions/defaultActions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/QuickActions/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/Toolbox/IframeButtons.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/Toolbox/defaultActions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/Toolbox/generator.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/Toolbox/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/lib/getRoomDirectives.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/FilePreview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/FileUploadModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/GenericPreview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/ImagePreview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/MediaPreview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/PreviewSkeleton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/FileUploadModal/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReactionListModal/ReactionListModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReactionListModal/ReactionUserTag.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReactionListModal/Reactions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReactionListModal/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReadReceiptsModal/ReadReceiptsModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReadReceiptsModal/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReportMessageModal/ReportMessageModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/modals/ReportMessageModal/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/ChatProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/ComposerPopupProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/RoomProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/SelectedMessagesProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/ToolboxProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/VirtualAction.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/hooks/useChatMessagesInstance.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/hooks/useDepsMatch.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/hooks/useInstance.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/hooks/useToolboxActions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/providers/hooks/useUserCard.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/AddWebdavAccountModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/SaveToWebdavModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/FilePickerBreadcrumbs.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerGrid/WebdavFilePickerGrid.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerGrid/WebdavFilePickerGridItem.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerGrid/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/WebdavFilePickerTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/lib/getNodeFileSize.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/lib/getNodeIconType.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/room/webdav/WebdavFilePickerModal/lib/sortWebdavNodes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/AppLayout.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/AppRoot.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/BlazeTemplate.tsx",["23090"],[],"import { Blaze } from 'meteor/blaze';\nimport type { EJSONable } from 'meteor/ejson';\nimport { ReactiveDict } from 'meteor/reactive-dict';\nimport { Template } from 'meteor/templating';\nimport type { FC } from 'react';\nimport React, { useEffect, useRef } from 'react';\n\ntype BlazeTemplateProps = {\n\ttemplate: keyof typeof Template;\n\tdata?: EJSONable;\n};\n\nconst hiddenStyle = { display: 'none' } as const;\n\nconst BlazeTemplate: FC = ({ template, data }) => {\n\tconst ref = useRef(null);\n\tconst dataRef = useRef(new ReactiveDict());\n\n\tuseEffect(() => {\n\t\tif (data) {\n\t\t\tdataRef.current.set(data);\n\t\t}\n\t});\n\n\tuseEffect(() => {\n\t\tif (!ref.current || !ref.current.parentNode) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst data = dataRef.current;\n\n\t\tconst view = Blaze.renderWithData(Template[template], () => data.all(), ref.current.parentNode, ref.current);\n\n\t\treturn (): void => {\n\t\t\tBlaze.remove(view);\n\t\t};\n\t}, [template]);\n\n\treturn
;\n};\n\nexport default BlazeTemplate;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/AuthenticationCheck.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/LayoutWithSidebar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/LoginPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/MainLayout.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/PasswordChangeCheck.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/Preload.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/TwoFactorAuthSetupCheck.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/UsernameCheck.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/useCustomScript.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/useIframeLogin.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/MainLayout/useViewportScrolling.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/PageLoading.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/PortalWrapper.ts",[],["23091"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/PortalsWrapper.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/hooks/useClearUnreadAllMessagesMutation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/hooks/useEscapeKeyStroke.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/hooks/useGoogleTagManager.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/root/hooks/useMessageLinkClicks.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/SetupWizardPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/SetupWizardRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/contexts/SetupWizardContext.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/hooks/useBodyPosition.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/hooks/useParameters.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/hooks/useRouteLock.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/hooks/useStepRouting.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/providers/SetupWizardProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/steps/AdminInfoStep.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/steps/CloudAccountConfirmation.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/steps/OrganizationInfoStep.tsx",["23092"],[],"import type { ISetting } from '@rocket.chat/core-typings';\nimport { OrganizationInfoPage } from '@rocket.chat/onboarding-ui';\nimport type { TranslationKey } from '@rocket.chat/ui-contexts';\nimport { useRole, useTranslation } from '@rocket.chat/ui-contexts';\nimport type { ComponentProps, ReactElement } from 'react';\nimport React from 'react';\n\nimport { useSetupWizardContext } from '../contexts/SetupWizardContext';\n\nconst getSettingOptions = (\n\tsettings: Array | undefined,\n\tsettingId: ISetting['_id'],\n\tt: ReturnType,\n): Array<[key: string, text: string]> => {\n\tif (!settings) {\n\t\treturn [];\n\t}\n\n\tconst setting = settings.find(({ _id }) => _id === settingId);\n\n\tif (!setting || !setting.values) {\n\t\treturn [];\n\t}\n\n\treturn setting.values.map(({ i18nLabel, key }) => [String(key), t(i18nLabel as TranslationKey)]);\n};\n\nconst OrganizationInfoStep = (): ReactElement => {\n\tconst t = useTranslation();\n\tconst hasAdminRole = useRole('admin');\n\n\tconst {\n\t\tsetupWizardData: { organizationData },\n\t\tsetSetupWizardData,\n\t\tsettings,\n\t\tgoToPreviousStep,\n\t\tgoToNextStep,\n\t\tcompleteSetupWizard,\n\t\tcurrentStep,\n\t\tregisterPreIntent,\n\t\tskipCloudRegistration,\n\t\tmaxSteps,\n\t} = useSetupWizardContext();\n\n\tconst countryOptions = getSettingOptions(settings, 'Country', t);\n\tconst organizationTypeOptions = getSettingOptions(settings, 'Organization_Type', t);\n\tconst organizationIndustryOptions = getSettingOptions(settings, 'Industry', t);\n\tconst organizationSizeOptions = getSettingOptions(settings, 'Size', t);\n\n\tconst handleSubmit: ComponentProps['onSubmit'] = async (data) => {\n\t\tif (skipCloudRegistration) {\n\t\t\treturn completeSetupWizard();\n\t\t}\n\t\tsetSetupWizardData((prevState) => ({ ...prevState, organizationData: data }));\n\t\tawait registerPreIntent();\n\t\tgoToNextStep();\n\t};\n\n\treturn (\n\t\t\n\t);\n};\n\nexport default OrganizationInfoStep;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/setupWizard/steps/RegisterServerStep.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ChannelDesertionTable/ChannelDesertionTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ChannelDesertionTable/ChannelDesertionTableRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ChannelDesertionTable/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ConvertToChannelModal/BaseConvertToChannelModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ConvertToChannelModal/ConvertToChannelModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ConvertToChannelModal/ModalSteps/FirstStep.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ConvertToChannelModal/ModalSteps/SecondStep.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/ConvertToChannelModal/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/RoomLinkList.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/TeamAutocomplete/Avatar.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/TeamAutocomplete/TeamAutocomplete.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/TeamAutocomplete/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/RoomsInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/BaseTeamsChannels.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/ConfirmationModal/ConfirmationModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/ConfirmationModal/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/RoomActions.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/Row.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannelItem.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/TeamsChannels.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/hooks/useTeamsChannelList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/channels/tabBar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/ChannelDeletionTable.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/ChannelRow.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/DeleteTeamModal.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/DeleteTeamModal.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/DeleteTeamModalWithRooms.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/StepOne.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/StepTwo.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/Delete/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamModal/LeaveTeamModal.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamModal/LeaveTeamModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamModal/LeaveTeamModalChannels.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamModal/LeaveTeamModalConfirmation.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/LeaveTeamWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/LeaveTeam/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/TeamsInfo.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/TeamsInfoWithData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/info/tabBar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/BaseRemoveUsersModal.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersFirstStep.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersModal.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/RemoveUsersSecondStep.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/contextualBar/members/RemoveUsersModal/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/client/views/teams/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/IRoomTypeConfig.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/IRoutingManagerConfig.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/express.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/global.d.ts",[],["23093"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/ldap-escape.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/less/browser.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/less-plugin-autoprefixer.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/accounts-base.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/babel-compiler.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/check.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/ddp-common.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/ddp-rate-limiter.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/ejson.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/facts-base.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/htmljs.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/jparker:gravatar.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/kadira-flow-router.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/konecty-user-presence.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/littledata-synced-cron.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/logging.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/meteor.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/meteorhacks-inject-initial.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/mongo.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/mystor-device-detection.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/oauth.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/oauth2server.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/ostrio-cookies.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/random.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/rocketchat-streamer.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/rocketchat-tap-i18n.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/routepolicy.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/session.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/sha.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/templating.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/tracker.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/url.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/meteor/webapp-hashing.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/mongodb.d.ts",[],["23094"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/rocket.chat/fuselage-tokens/colors.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/service-configuration.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/xml-encryption.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/externals/yaqrcode.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/methods/federation.ts",[],["23095"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/methods/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/definition/methods/omnichannel.ts",[],["23096"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/api-enterprise/server/canned-responses.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/api-enterprise/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/api-enterprise/server/lib/canned-responses.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/authorization/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/authorization/lib/addRoleRestrictions.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/authorization/lib/guestPermissions.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/authorization/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/authorization/server/resetEnterprisePermissions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/authorization/server/validateUserRoles.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/client/collections/CannedResponse.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/client/startup/responses.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/client/streamer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/client/tabBar.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/hooks/onMessageSentParsePlaceholder.ts",["23097"],[],"import get from 'lodash.get';\nimport type { IMessage, IOmnichannelRoom } from '@rocket.chat/core-typings';\nimport { isOmnichannelRoom } from '@rocket.chat/core-typings';\nimport { LivechatVisitors } from '@rocket.chat/models';\n\nimport { settings } from '../../../../../app/settings/server';\nimport { callbacks } from '../../../../../lib/callbacks';\nimport { Users, Rooms } from '../../../../../app/models/server';\n\nconst placeholderFields = {\n\t'contact.name': {\n\t\tfrom: 'visitor',\n\t\tdataKey: 'name',\n\t},\n\t'contact.email': {\n\t\tfrom: 'visitor',\n\t\tdataKey: 'visitorEmails[0].address',\n\t},\n\t'contact.phone': {\n\t\tfrom: 'visitor',\n\t\tdataKey: 'phone[0].phoneNumber',\n\t},\n\t'agent.name': {\n\t\tfrom: 'agent',\n\t\tdataKey: 'name',\n\t},\n\t'agent.email': {\n\t\tfrom: 'agent',\n\t\tdataKey: 'emails[0].address',\n\t},\n};\n\nconst replaceAll = (text: string, old: string, replace: string): string => text.replace(new RegExp(old, 'g'), replace);\n\nconst handleBeforeSaveMessage = (message: IMessage, room?: IOmnichannelRoom): IMessage => {\n\tif (!message.msg || message.msg === '') {\n\t\treturn message;\n\t}\n\n\troom = room?._id ? room : Rooms.findOneById(message.rid);\n\tif (!room || !isOmnichannelRoom(room)) {\n\t\treturn message;\n\t}\n\n\tlet messageText = message.msg;\n\tconst agentId = room?.servedBy?._id;\n\tconst visitorId = room?.v?._id;\n\tconst agent = Users.findOneById(agentId, { fields: { name: 1, _id: 1, emails: 1 } }) || {};\n\tconst visitor = visitorId && (Promise.await(LivechatVisitors.findOneById(visitorId, {})) || {});\n\n\tObject.keys(placeholderFields).map((field) => {\n\t\tconst templateKey = `{{${field}}}`;\n\t\tconst placeholderConfig = placeholderFields[field as keyof typeof placeholderFields];\n\t\tconst from = placeholderConfig.from === 'agent' ? agent : visitor;\n\t\tconst data = get(from, placeholderConfig.dataKey, '');\n\t\tmessageText = replaceAll(messageText, templateKey, data);\n\n\t\treturn messageText;\n\t});\n\n\tmessage.msg = messageText;\n\treturn message;\n};\n\nsettings.watch('Canned_Responses_Enable', function (value) {\n\tif (!value) {\n\t\tcallbacks.remove('beforeSaveMessage', 'canned-responses-replace-placeholders');\n\t\treturn;\n\t}\n\n\tcallbacks.add('beforeSaveMessage', handleBeforeSaveMessage, callbacks.priority.HIGH * 2, 'canned-responses-replace-placeholders');\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/hooks/onRemoveAgentDepartment.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/hooks/onSaveAgentDepartment.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/methods/removeCannedResponse.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/methods/saveCannedResponse.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/permissions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/canned-responses/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/ecdh/Session.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/ecdh/client/ClientSession.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/ecdh/server/ServerSession.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/RoomService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/input/RoomInputDto.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/sender/AbstractFederationService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/sender/input/RoomSenderDto.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/sender/room/DMRoomInternalHooksServiceSender.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/sender/room/RoomInternalHooksServiceSender.ts",["23098"],[],"import type { RocketChatFileAdapter } from '../../../../../../../app/federation-v2/server/infrastructure/rocket-chat/adapters/File';\nimport type { RocketChatMessageAdapter } from '../../../../../../../app/federation-v2/server/infrastructure/rocket-chat/adapters/Message';\nimport type { RocketChatSettingsAdapter } from '../../../../../../../app/federation-v2/server/infrastructure/rocket-chat/adapters/Settings';\nimport { ROCKET_CHAT_FEDERATION_ROLES } from '../../../../../../../app/federation-v2/server/infrastructure/rocket-chat/definitions/InternalFederatedRoomRoles';\nimport { FederatedRoomEE } from '../../../domain/FederatedRoom';\nimport { FederatedUserEE } from '../../../domain/FederatedUser';\nimport type { IFederationBridgeEE } from '../../../domain/IFederationBridge';\nimport type { RocketChatRoomAdapterEE } from '../../../infrastructure/rocket-chat/adapters/Room';\nimport type { RocketChatUserAdapterEE } from '../../../infrastructure/rocket-chat/adapters/User';\nimport type {\n\tFederationBeforeAddUserToARoomDto,\n\tFederationOnRoomCreationDto,\n\tFederationOnUsersAddedToARoomDto,\n\tFederationRoomInviteUserDto,\n\tFederationSetupRoomDto,\n\tIFederationInviteeDto,\n} from '../input/RoomSenderDto';\nimport { FederationServiceEE } from '../AbstractFederationService';\n\nexport class FederationRoomInternalHooksServiceSender extends FederationServiceEE {\n\tconstructor(\n\t\tprotected internalRoomAdapter: RocketChatRoomAdapterEE,\n\t\tprotected internalUserAdapter: RocketChatUserAdapterEE,\n\t\tprotected internalFileAdapter: RocketChatFileAdapter,\n\t\tprotected internalSettingsAdapter: RocketChatSettingsAdapter,\n\t\tprotected internalMessageAdapter: RocketChatMessageAdapter,\n\t\tprotected bridge: IFederationBridgeEE,\n\t) {\n\t\tsuper(bridge, internalUserAdapter, internalFileAdapter, internalSettingsAdapter);\n\t}\n\n\tpublic async onRoomCreated(roomOnCreationInput: FederationOnRoomCreationDto): Promise {\n\t\tconst { internalInviterId, internalRoomId, invitees } = roomOnCreationInput;\n\t\tawait this.setupFederatedRoom({ internalInviterId, internalRoomId });\n\n\t\tif (invitees.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.inviteLocalThenExternalUsers(invitees, internalInviterId, internalRoomId);\n\t}\n\n\tpublic async beforeAddUserToARoom(dmBeforeAddUserToARoomInput: FederationBeforeAddUserToARoomDto): Promise {\n\t\tconst { invitees = [], internalInviter, internalRoomId } = dmBeforeAddUserToARoomInput;\n\t\tif (invitees.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tif (internalInviter) {\n\t\t\tconst federatedUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalInviter._id);\n\t\t\tif (!federatedUser) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst federatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalRoomId);\n\t\t\tif (!federatedRoom) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst userRolesInThisRoom = await this.internalRoomAdapter.getInternalRoomRolesByUserId(\n\t\t\t\tfederatedRoom.getInternalId(),\n\t\t\t\tfederatedUser.getInternalId(),\n\t\t\t);\n\t\t\tconst canAddUserToARoom =\n\t\t\t\tuserRolesInThisRoom.includes(ROCKET_CHAT_FEDERATION_ROLES.OWNER) ||\n\t\t\t\tuserRolesInThisRoom.includes(ROCKET_CHAT_FEDERATION_ROLES.MODERATOR) ||\n\t\t\t\tfederatedRoom.isTheCreator(federatedUser.getInternalId());\n\t\t\tif (!canAddUserToARoom) {\n\t\t\t\tthrow new Error('You are not allowed to add users to this room');\n\t\t\t}\n\t\t}\n\n\t\tawait this.createUsersLocallyOnly(invitees);\n\t}\n\n\tprivate async inviteLocalThenExternalUsers(\n\t\tinvitees: IFederationInviteeDto[],\n\t\tinternalInviterId: string,\n\t\tinternalRoomId: string,\n\t): Promise {\n\t\tconst localUsers = invitees.filter((user) =>\n\t\t\tFederatedUserEE.isOriginalFromTheProxyServer(this.bridge.extractHomeserverOrigin(user.rawInviteeId), this.internalHomeServerDomain),\n\t\t);\n\n\t\tconst externalUsers = invitees.filter(\n\t\t\t(user) =>\n\t\t\t\t!FederatedUserEE.isOriginalFromTheProxyServer(\n\t\t\t\t\tthis.bridge.extractHomeserverOrigin(user.rawInviteeId),\n\t\t\t\t\tthis.internalHomeServerDomain,\n\t\t\t\t),\n\t\t);\n\n\t\tfor await (const user of [...localUsers, ...externalUsers]) {\n\t\t\tawait this.inviteUserToAFederatedRoom({\n\t\t\t\tinternalInviterId,\n\t\t\t\tinternalRoomId,\n\t\t\t\tinviteeUsernameOnly: user.inviteeUsernameOnly,\n\t\t\t\tnormalizedInviteeId: user.normalizedInviteeId,\n\t\t\t\trawInviteeId: user.rawInviteeId,\n\t\t\t});\n\t\t}\n\t}\n\n\tpublic async onUsersAddedToARoom(roomOnUsersAddedToARoomInput: FederationOnUsersAddedToARoomDto): Promise {\n\t\tconst { internalInviterId, internalRoomId, invitees, inviteComesFromAnExternalHomeServer } = roomOnUsersAddedToARoomInput;\n\n\t\tif (inviteComesFromAnExternalHomeServer) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.inviteLocalThenExternalUsers(invitees, internalInviterId, internalRoomId);\n\t}\n\n\tpublic async afterRoomNameChanged(internalRoomId: string, internalRoomName: string): Promise {\n\t\tconst federatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalRoomId);\n\t\tif (!federatedRoom) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst federatedUser =\n\t\t\tfederatedRoom.getCreatorId() && (await this.internalUserAdapter.getFederatedUserByInternalId(federatedRoom.getCreatorId() as string));\n\t\tif (!federatedUser) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isRoomFromTheSameHomeServer = FederatedRoomEE.isOriginalFromTheProxyServer(\n\t\t\tthis.bridge.extractHomeserverOrigin(federatedRoom.getExternalId()),\n\t\t\tthis.internalSettingsAdapter.getHomeServerDomain(),\n\t\t);\n\t\tif (!isRoomFromTheSameHomeServer) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst externalRoomName = await this.bridge.getRoomName(federatedRoom.getExternalId(), federatedUser.getExternalId());\n\n\t\tif (!federatedRoom.shouldUpdateDisplayRoomName(externalRoomName || '')) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.bridge.setRoomName(federatedRoom.getExternalId(), federatedUser.getExternalId(), internalRoomName);\n\t}\n\n\tpublic async afterRoomTopicChanged(internalRoomId: string, internalRoomTopic: string): Promise {\n\t\tconst federatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalRoomId);\n\t\tif (!federatedRoom) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst federatedUser =\n\t\t\tfederatedRoom.getCreatorId() && (await this.internalUserAdapter.getFederatedUserByInternalId(federatedRoom.getCreatorId() as string));\n\t\tif (!federatedUser) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isRoomFromTheSameHomeServer = FederatedRoomEE.isOriginalFromTheProxyServer(\n\t\t\tthis.bridge.extractHomeserverOrigin(federatedRoom.getExternalId()),\n\t\t\tthis.internalSettingsAdapter.getHomeServerDomain(),\n\t\t);\n\t\tif (!isRoomFromTheSameHomeServer) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst externalRoomTopic = await this.bridge.getRoomTopic(federatedRoom.getExternalId(), federatedUser.getExternalId());\n\t\tif (!federatedRoom.shouldUpdateRoomTopic(externalRoomTopic || '')) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.bridge.setRoomTopic(federatedRoom.getExternalId(), federatedUser.getExternalId(), internalRoomTopic);\n\t}\n\n\tprivate async setupFederatedRoom(roomInviteUserInput: FederationSetupRoomDto): Promise {\n\t\tconst { internalInviterId, internalRoomId } = roomInviteUserInput;\n\t\tconst inviterUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalInviterId);\n\t\tif (!inviterUser) {\n\t\t\tawait this.createFederatedUserIncludingHomeserverUsingLocalInformation(internalInviterId);\n\t\t}\n\n\t\tconst federatedInviterUser = inviterUser || (await this.internalUserAdapter.getFederatedUserByInternalId(internalInviterId));\n\t\tif (!federatedInviterUser) {\n\t\t\tthrow new Error(`User with internalId ${internalInviterId} not found`);\n\t\t}\n\n\t\tconst internalFederatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalRoomId);\n\t\tif (internalFederatedRoom) {\n\t\t\treturn;\n\t\t}\n\t\tconst internalRoom = await this.internalRoomAdapter.getInternalRoomById(internalRoomId);\n\t\tif (!internalRoom || !internalRoom.name) {\n\t\t\tthrow new Error(`Room with internalId ${internalRoomId} not found`);\n\t\t}\n\t\tconst roomName = internalRoom.fname || internalRoom.name;\n\t\tconst externalRoomId = await this.bridge.createRoom(federatedInviterUser.getExternalId(), internalRoom.t, roomName, internalRoom.topic);\n\n\t\tawait this.internalRoomAdapter.updateFederatedRoomByInternalRoomId(internalRoom._id, externalRoomId);\n\t}\n\n\tprivate async inviteUserToAFederatedRoom(roomInviteUserInput: FederationRoomInviteUserDto): Promise {\n\t\tconst { internalInviterId, internalRoomId, normalizedInviteeId, inviteeUsernameOnly, rawInviteeId } = roomInviteUserInput;\n\t\tconst isUserAutoJoining = Boolean(!internalInviterId);\n\n\t\tconst isInviteeFromTheSameHomeServer = FederatedUserEE.isOriginalFromTheProxyServer(\n\t\t\tthis.bridge.extractHomeserverOrigin(rawInviteeId),\n\t\t\tthis.internalHomeServerDomain,\n\t\t);\n\n\t\tconst federatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalRoomId);\n\t\tif (!federatedRoom) {\n\t\t\tthrow new Error(`Could not find the room to invite. RoomId: ${internalRoomId}`);\n\t\t}\n\n\t\tconst federatedInviterUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalInviterId);\n\t\tif (!federatedInviterUser && !isUserAutoJoining) {\n\t\t\tthrow new Error(`User with internalId ${internalInviterId} not found`);\n\t\t}\n\n\t\tconst username = isInviteeFromTheSameHomeServer ? inviteeUsernameOnly : normalizedInviteeId;\n\t\tconst inviteeUser = await this.internalUserAdapter.getFederatedUserByInternalUsername(username);\n\t\tif (!inviteeUser) {\n\t\t\tconst existsOnlyOnProxyServer = isInviteeFromTheSameHomeServer;\n\t\t\tawait this.createFederatedUserInternallyOnly(rawInviteeId, username, existsOnlyOnProxyServer);\n\t\t}\n\n\t\tconst federatedInviteeUser = inviteeUser || (await this.internalUserAdapter.getFederatedUserByInternalUsername(username));\n\t\tif (!federatedInviteeUser) {\n\t\t\tthrow new Error(`User with internalUsername ${username} not found`);\n\t\t}\n\n\t\tif (isInviteeFromTheSameHomeServer) {\n\t\t\tconst profile = await this.bridge.getUserProfileInformation(federatedInviteeUser.getExternalId());\n\t\t\tif (!profile) {\n\t\t\t\tawait this.bridge.createUser(\n\t\t\t\t\tinviteeUsernameOnly,\n\t\t\t\t\tfederatedInviteeUser.getName() || federatedInviteeUser.getUsername() || username,\n\t\t\t\t\tthis.internalHomeServerDomain,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (!federatedInviterUser && isUserAutoJoining) {\n\t\t\tawait this.bridge.joinRoom(federatedRoom.getExternalId(), federatedInviteeUser.getExternalId());\n\t\t\treturn;\n\t\t}\n\n\t\tif (!federatedInviterUser) {\n\t\t\tthrow new Error(`User with internalId ${internalInviterId} not found`);\n\t\t}\n\n\t\tawait this.bridge.inviteToRoom(\n\t\t\tfederatedRoom.getExternalId(),\n\t\t\tfederatedInviterUser.getExternalId(),\n\t\t\tfederatedInviteeUser.getExternalId(),\n\t\t);\n\t\tif (isInviteeFromTheSameHomeServer) {\n\t\t\tawait this.bridge.joinRoom(federatedRoom.getExternalId(), federatedInviteeUser.getExternalId());\n\t\t}\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/application/sender/room/RoomServiceSender.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/domain/FederatedRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/domain/FederatedUser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/domain/IFederationBridge.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/Factory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/matrix/Bridge.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/rocket-chat/adapters/Room.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/rocket-chat/adapters/User.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/rocket-chat/hooks/index.ts",["23099","23100"],[],"import type { IRoom, IUser, Username } from '@rocket.chat/core-typings';\nimport { isRoomFederated } from '@rocket.chat/core-typings';\n\nimport { callbacks } from '../../../../../../../lib/callbacks';\nimport { settings } from '../../../../../../../app/settings/server';\n\nexport class FederationHooksEE {\n\tpublic static onFederatedRoomCreated(callback: (room: IRoom, owner: IUser, originalMemberList: string[]) => Promise): void {\n\t\tcallbacks.add(\n\t\t\t'federation.afterCreateFederatedRoom',\n\t\t\t(room: IRoom, params: { owner: IUser; originalMemberList: string[] }): void => {\n\t\t\t\tif (\n\t\t\t\t\t!room ||\n\t\t\t\t\t!isRoomFederated(room) ||\n\t\t\t\t\t!params ||\n\t\t\t\t\t!params.owner ||\n\t\t\t\t\t!params.originalMemberList ||\n\t\t\t\t\t!settings.get('Federation_Matrix_enabled')\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tPromise.await(callback(room, params.owner, params.originalMemberList));\n\t\t\t},\n\t\t\tcallbacks.priority.HIGH,\n\t\t\t'federation-v2-after-create-room',\n\t\t);\n\t}\n\n\tpublic static onUsersAddedToARoom(callback: (room: IRoom, addedUsers: IUser[] | Username[], inviter?: IUser) => Promise): void {\n\t\tcallbacks.add(\n\t\t\t'federation.onAddUsersToARoom',\n\t\t\t(params: { invitees: IUser[] | Username[]; inviter: IUser }, room: IRoom): void => {\n\t\t\t\tif (\n\t\t\t\t\t!room ||\n\t\t\t\t\t!isRoomFederated(room) ||\n\t\t\t\t\t!params ||\n\t\t\t\t\t!params.invitees ||\n\t\t\t\t\t!params.inviter ||\n\t\t\t\t\t!settings.get('Federation_Matrix_enabled')\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tPromise.await(callback(room, params.invitees, params.inviter));\n\t\t\t},\n\t\t\tcallbacks.priority.HIGH,\n\t\t\t'federation-v2-on-add-users-to-a-room',\n\t\t);\n\t\tcallbacks.add(\n\t\t\t'afterAddedToRoom',\n\t\t\t(params: { user: IUser; inviter?: IUser }, room: IRoom): void => {\n\t\t\t\tif (!room || !isRoomFederated(room) || !params || !params.user || !params.inviter || !settings.get('Federation_Matrix_enabled')) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tPromise.await(callback(room, [params.user], params?.inviter));\n\t\t\t},\n\t\t\tcallbacks.priority.HIGH,\n\t\t\t'federation-v2-after-add-user-to-a-room',\n\t\t);\n\t}\n\n\tpublic static onDirectMessageRoomCreated(callback: (room: IRoom, creatorId: string, memberList: IUser[]) => Promise): void {\n\t\tcallbacks.add(\n\t\t\t'afterCreateDirectRoom',\n\t\t\t(room: IRoom, params: { members: IUser[]; creatorId: IUser['_id'] }): void => {\n\t\t\t\tif (!room || !params || !params.creatorId || !params.creatorId || !settings.get('Federation_Matrix_enabled')) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tPromise.await(callback(room, params.creatorId, params.members));\n\t\t\t},\n\t\t\tcallbacks.priority.HIGH,\n\t\t\t'federation-v2-after-create-direct-message-room',\n\t\t);\n\t}\n\n\tpublic static beforeDirectMessageRoomCreate(callback: (memberList: IUser[]) => Promise): void {\n\t\tcallbacks.add(\n\t\t\t'beforeCreateDirectRoom',\n\t\t\t(members: IUser[]): void => {\n\t\t\t\tif (!members || !settings.get('Federation_Matrix_enabled')) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tPromise.await(callback(members));\n\t\t\t},\n\t\t\tcallbacks.priority.HIGH,\n\t\t\t'federation-v2-before-create-direct-message-room',\n\t\t);\n\t}\n\n\tpublic static beforeAddUserToARoom(callback: (userToBeAdded: IUser | string, room: IRoom, inviter?: IUser) => Promise): void {\n\t\tcallbacks.add(\n\t\t\t'federation.beforeAddUserToARoom',\n\t\t\t(params: { user: IUser | string; inviter?: IUser }, room: IRoom): void => {\n\t\t\t\tif (!room || !isRoomFederated(room) || !params || !params.user || !settings.get('Federation_Matrix_enabled')) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tPromise.await(callback(params.user, room, params.inviter));\n\t\t\t},\n\t\t\tcallbacks.priority.HIGH,\n\t\t\t'federation-v2-before-add-user-to-the-room',\n\t\t);\n\t}\n\n\tpublic static afterRoomNameChanged(callback: (roomId: string, changedRoomName: string) => Promise): void {\n\t\tcallbacks.add(\n\t\t\t'afterRoomNameChange',\n\t\t\t(params: Record): void => {\n\t\t\t\tif (!params || !params.rid || !params.name || !settings.get('Federation_Matrix_enabled')) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tPromise.await(callback(params.rid, params.name));\n\t\t\t},\n\t\t\tcallbacks.priority.HIGH,\n\t\t\t'federation-v2-after-room-name-changed',\n\t\t);\n\t}\n\n\tpublic static afterRoomTopicChanged(callback: (roomId: string, changedRoomTopic: string) => Promise): void {\n\t\tcallbacks.add(\n\t\t\t'afterRoomTopicChange',\n\t\t\t(params: Record): void => {\n\t\t\t\tif (!params || !params.rid || !params.topic || !settings.get('Federation_Matrix_enabled')) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tPromise.await(callback(params.rid, params.topic));\n\t\t\t},\n\t\t\tcallbacks.priority.HIGH,\n\t\t\t'federation-v2-after-room-topic-changed',\n\t\t);\n\t}\n\n\tpublic static removeAll(): void {\n\t\tcallbacks.remove('beforeCreateDirectRoom', 'federation-v2-before-create-direct-message-room');\n\t\tcallbacks.remove('afterCreateDirectRoom', 'federation-v2-after-create-direct-message-room');\n\t\tcallbacks.remove('federation.onAddUsersToARoom', 'federation-v2-on-add-users-to-a-room');\n\t\tcallbacks.remove('afterAddedToRoom', 'federation-v2-after-add-user-to-a-room');\n\t\tcallbacks.remove('federation.afterCreateFederatedRoom', 'federation-v2-after-create-room');\n\t\tcallbacks.remove('federation.beforeAddUserToARoom', 'federation-v2-before-add-user-to-the-room');\n\t\tcallbacks.remove('afterRoomNameChange', 'federation-v2-after-room-name-changed');\n\t\tcallbacks.remove('afterRoomTopicChange', 'federation-v2-after-room-topic-changed');\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/rocket-chat/slash-commands/action.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/federation-v2/server/infrastructure/rocket-chat/slash-commands/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/definition/ILicense.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/definition/ILicenseTag.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/bundles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/decrypt.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/getSeatsRequestLink.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/getStatistics.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/getTagColor.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/lib/isUnderAppLimits.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/license.internalService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/license.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/maxSeatsBanners.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/methods.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/settings.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/license/server/startup.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat/imports/server/rest/departments.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat/imports/server/rest/inquiries.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat/imports/server/rest/rooms.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat/imports/server/rest/sms.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat/imports/server/rest/upload.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/SingleBusinessHour.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/components/modals/PlaceChatOnHoldModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/messageTypes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/views/business-hours/Multiple.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/client/views/livechatSideNavItems.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/lib/QuickActions/defaultActions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/lib/messageTypes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/agents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/business-hours.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/departments.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/inquiries.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/definition.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/inquiries.ts",["23101"],[],"import { LivechatInquiry, Users, OmnichannelServiceLevelAgreements } from '@rocket.chat/models';\n\nimport { updateRoomSLA } from './sla';\n\nexport async function setSLAToInquiry({ userId, roomId, sla }: { userId: string; roomId: string; sla: string }): Promise {\n\tconst inquiry = await LivechatInquiry.findOneByRoomId(roomId, { projection: { status: 1 } });\n\tif (!inquiry || inquiry.status !== 'queued') {\n\t\tthrow new Error('error-invalid-inquiry');\n\t}\n\n\tconst slaData = sla && (await OmnichannelServiceLevelAgreements.findOneByIdOrName(sla));\n\tif (!slaData) {\n\t\tthrow new Error('error-invalid-sla');\n\t}\n\n\tconst user = await Users.findOneById(userId, { projection: { _id: 1, username: 1, name: 1 } });\n\tif (!user || !user.username) {\n\t\tthrow new Error('error-invalid-user');\n\t}\n\n\tawait updateRoomSLA(\n\t\troomId,\n\t\t{\n\t\t\t_id: user._id,\n\t\t\tname: user.name || '',\n\t\t\tusername: user.username,\n\t\t},\n\t\tslaData,\n\t);\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/monitors.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/priorities.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/sla.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/tags.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/lib/units.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/monitors.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/priorities.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/rooms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/sla.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/tags.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/transcript.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/api/units.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/business-hour/Custom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/business-hour/Helper.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/business-hour/Multiple.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/business-hour/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/business-hour/lib/business-hour.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/addDepartmentAncestors.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterForwardChatToAgent.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterForwardChatToDepartment.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterInquiryQueued.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterOnHold.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterOnHoldChatResumed.ts",["23102"],[],"import { callbacks } from '../../../../../lib/callbacks';\nimport { LivechatEnterprise } from '../lib/LivechatEnterprise';\nimport { cbLogger } from '../lib/logger';\n\nconst handleAfterOnHoldChatResumed = async (room: any): Promise => {\n\tif (!room || !room._id || !room.onHold) {\n\t\tcbLogger.debug('Skipping callback. No room provided or room is not on hold');\n\t\treturn;\n\t}\n\n\tcbLogger.debug(`Removing current on hold timers for room ${room._id}`);\n\tLivechatEnterprise.releaseOnHoldChat(room);\n};\n\ncallbacks.add(\n\t'livechat:afterOnHoldChatResumed',\n\t(room) => Promise.await(handleAfterOnHoldChatResumed(room)),\n\tcallbacks.priority.HIGH,\n\t'livechat-after-on-hold-chat-resumed',\n);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterRemoveDepartment.ts",["23103"],[],"import type { ILivechatAgent, ILivechatDepartmentRecord } from '@rocket.chat/core-typings';\nimport { LivechatDepartment } from '@rocket.chat/models';\n\nimport { callbacks } from '../../../../../lib/callbacks';\nimport { cbLogger } from '../lib/logger';\n\nconst afterRemoveDepartment = async (options: { department: ILivechatDepartmentRecord; agentsId: ILivechatAgent['_id'][] }) => {\n\tcbLogger.debug(`Performing post-department-removal actions in EE: ${options?.department?._id}. Removing department from forward list`);\n\tif (!options || !options.department) {\n\t\tcbLogger.warn('No department found in options', options);\n\t\treturn options;\n\t}\n\n\tconst { department } = options;\n\n\tcbLogger.debug(`Removing department from forward list: ${department._id}`);\n\tawait LivechatDepartment.removeDepartmentFromForwardListById(department._id);\n\tcbLogger.debug(`Removed department from forward list: ${department._id}`);\n\n\tcbLogger.debug(`Post-department-removal actions completed in EE: ${department._id}`);\n\n\treturn options;\n};\n\ncallbacks.add(\n\t'livechat.afterRemoveDepartment',\n\t(options) => Promise.await(afterRemoveDepartment(options)),\n\tcallbacks.priority.HIGH,\n\t'livechat-after-remove-department',\n);\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterReturnRoomAsInquiry.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/afterTakeInquiry.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/applyDepartmentRestrictions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/applySimultaneousChatsRestrictions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/autoCloseQueued.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeForwardRoomToDepartment.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeJoinRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeListTags.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeNewInquiry.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeNewRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/beforeRoutingChat.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/checkAgentBeforeTakeInquiry.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/handleNextAgentPreferredEvents.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onAgentAssignmentFailed.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onBusinessHourStart.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onCheckRoomParamsApi.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onCloseLivechat.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onLoadConfigApi.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onLoadForwardDepartmentRestrictions.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onSaveVisitorInfo.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/onTransferFailure.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/resumeOnHold.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/scheduleAutoTransfer.ts",["23104"],[],"import type { IMessage, IOmnichannelRoom } from '@rocket.chat/core-typings';\n\nimport { AutoTransferChatScheduler } from '../lib/AutoTransferChatScheduler';\nimport { callbacks } from '../../../../../lib/callbacks';\nimport { settings } from '../../../../../app/settings/server';\nimport { LivechatRooms } from '../../../../../app/models/server';\nimport { cbLogger } from '../lib/logger';\nimport type { CloseRoomParams } from '../../../../../app/livechat/server/lib/LivechatTyped.d';\n\ntype LivechatCloseCallbackParams = {\n\troom: IOmnichannelRoom;\n\toptions: CloseRoomParams['options'];\n};\n\nlet autoTransferTimeout = 0;\n\nconst handleAfterTakeInquiryCallback = async (inquiry: any = {}): Promise => {\n\tconst { rid } = inquiry;\n\tif (!rid || !rid.trim()) {\n\t\tcbLogger.debug('Skipping callback. Invalid room id');\n\t\treturn;\n\t}\n\n\tif (!autoTransferTimeout || autoTransferTimeout <= 0) {\n\t\tcbLogger.debug('Skipping callback. No auto transfer timeout or invalid value from setting');\n\t\treturn inquiry;\n\t}\n\n\tconst room = LivechatRooms.findOneById(rid, { autoTransferredAt: 1, autoTransferOngoing: 1 });\n\tif (!room || room.autoTransferredAt || room.autoTransferOngoing) {\n\t\tcbLogger.debug(`Skipping callback. Room ${room._id} already being transfered or not found`);\n\t\treturn inquiry;\n\t}\n\n\tcbLogger.debug(`Callback success. Room ${room._id} will be scheduled to be auto transfered after ${autoTransferTimeout} seconds`);\n\tawait AutoTransferChatScheduler.scheduleRoom(rid, autoTransferTimeout as number);\n\n\treturn inquiry;\n};\n\nconst handleAfterSaveMessage = (message: any = {}, room: any = {}): IMessage => {\n\tconst { _id: rid, t, autoTransferredAt, autoTransferOngoing } = room;\n\tconst { token } = message;\n\n\tif (!autoTransferTimeout || autoTransferTimeout <= 0) {\n\t\treturn message;\n\t}\n\n\tif (!rid || !message || rid === '' || t !== 'l' || token) {\n\t\treturn message;\n\t}\n\n\tif (autoTransferredAt) {\n\t\treturn message;\n\t}\n\n\tif (!autoTransferOngoing) {\n\t\treturn message;\n\t}\n\n\tPromise.await(AutoTransferChatScheduler.unscheduleRoom(rid));\n\treturn message;\n};\n\nconst handleAfterCloseRoom = (params: LivechatCloseCallbackParams): LivechatCloseCallbackParams => {\n\tconst { room } = params;\n\n\tconst { _id: rid, autoTransferredAt, autoTransferOngoing } = room;\n\n\tif (!autoTransferTimeout || autoTransferTimeout <= 0) {\n\t\treturn params;\n\t}\n\n\tif (autoTransferredAt) {\n\t\treturn params;\n\t}\n\n\tif (!autoTransferOngoing) {\n\t\treturn params;\n\t}\n\n\tPromise.await(AutoTransferChatScheduler.unscheduleRoom(rid));\n\treturn params;\n};\n\nsettings.watch('Livechat_auto_transfer_chat_timeout', function (value) {\n\tautoTransferTimeout = value as number;\n\tif (!autoTransferTimeout || autoTransferTimeout === 0) {\n\t\tcallbacks.remove('livechat.afterTakeInquiry', 'livechat-auto-transfer-job-inquiry');\n\t\tcallbacks.remove('afterSaveMessage', 'livechat-cancel-auto-transfer-job-after-message');\n\t\tcallbacks.remove('livechat.closeRoom', 'livechat-cancel-auto-transfer-on-close-room');\n\t\treturn;\n\t}\n\n\tcallbacks.add(\n\t\t'livechat.afterTakeInquiry',\n\t\t(inquiry) => Promise.await(handleAfterTakeInquiryCallback(inquiry)),\n\t\tcallbacks.priority.MEDIUM,\n\t\t'livechat-auto-transfer-job-inquiry',\n\t);\n\tcallbacks.add('afterSaveMessage', handleAfterSaveMessage, callbacks.priority.HIGH, 'livechat-cancel-auto-transfer-job-after-message');\n\tcallbacks.add('livechat.closeRoom', handleAfterCloseRoom, callbacks.priority.HIGH, 'livechat-cancel-auto-transfer-on-close-room');\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/sendPdfTranscriptOnClose.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/hooks/setPredictedVisitorAbandonmentTime.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/AutoCloseOnHoldScheduler.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/AutoTransferChatScheduler.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/Department.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/Helper.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/LivechatEnterprise.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/QueueInactivityMonitor.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/SlaHelper.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/VisitorInactivityMonitor.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/debounceByParams.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/logger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/query.helper.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/routing/LoadBalancing.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/routing/LoadRotation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/runEndpointsAsUser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/lib/units.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/addMonitor.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/getUnitsFromUserRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/removeBusinessHour.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/removeMonitor.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/removeTag.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/removeUnit.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/resumeOnHold.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/saveTag.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/methods/saveUnit.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/permissions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/priorities.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/livechat-enterprise/server/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/message-read-receipt/server/hooks/afterReadMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/message-read-receipt/server/hooks/afterSaveMessage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/message-read-receipt/server/hooks/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/message-read-receipt/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/CannedResponse.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/LivechatDepartment.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/LivechatPriority.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/LivechatTag.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/LivechatUnit.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/LivechatUnitMonitors.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/Messages.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/models/Users.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/models/server/raw/LivechatDepartmentAgents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/settings/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/settings/server/settings.internalService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/settings/server/settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/teams-mention/server/EEMentionQueries.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/teams-mention/server/EESpotlight.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/teams-mention/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/voip-enterprise/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/voip-enterprise/server/lib/calculateOnHoldTimeForRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/app/voip-enterprise/server/services/voipService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/@types/IOrchestrator.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/RealAppsEngineUIHost.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/communication/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/communication/websockets.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/gameCenter/GameCenter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/gameCenter/GameCenterContainer.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/gameCenter/GameCenterList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/gameCenter/hooks/useExternalComponentsQuery.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/gameCenter/tabBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/i18n.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/apps/orchestrator.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/components/deviceManagement/LoggedOutBanner.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/deviceManagement/components/DeviceIcon.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/deviceManagement/components/DeviceManagementTable/DeviceManagementTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/deviceManagement/components/DeviceManagementTable/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/ecdh.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useAgentsList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useDeviceLogout.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useDevicesMenuOption.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useHasLicenseModule.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useOutboundDialer.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useTagsList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useVoipClient.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/hooks/useVoipFooterMenu.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/lib/fetchFeatures.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/lib/onToggledFeature.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/lib/voip/EEVoipClient.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/lib/voip/parseOutboundPhoneNumber.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/BusinessHoursRow.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/BusinessHoursTable.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/BusinessHoursTable.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/BusinessHoursTableContainer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/ContactManagerInfo.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/RemoveBusinessHourButton.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/BusinessHoursMultiple.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/BusinessHoursMultiple.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/BusinessHoursMultipleContainer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/BusinessHoursTimeZone.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/BusinessHoursTimeZone.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/ContactManager.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/CustomFieldsAdditionalForm.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/CustomFieldsAdditionalFormContainer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/DepartmentBusinessHours.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/DepartmentForwarding.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/EeNumberInput.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/EeTextAreaInput.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/EeTextInput.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/MaxChatsPerAgent.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/MaxChatsPerAgentContainer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/MaxChatsPerAgentDisplay.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/PrioritiesSelect.tsx",[],["23105","23106"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/SlaPoliciesSelect.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/additionalForms/register.ts",[],["23107"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEdit.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEditWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseEditWithDepartmentData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseFilter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponseNew.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponsesPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/CannedResponsesRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/IOmnichannelCannedResponse.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/RemoveCannedResponseButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/cannedResponses/components/cannedResponseForm.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/MarkdownTextEditor/InsertPlaceholderDropdown.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/MarkdownTextEditor/MarkdownTextEditor.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/MarkdownTextEditor/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/TextEditor/IconButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/TextEditor/TextButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/TextEditor/TextEditor.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/TextEditor/Textarea.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/TextEditor/Toolbox.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/TextEditor/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/CreateCannedResponseModal.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/CreateCannedResponseModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/PreviewText.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/SharingOptions.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/CreateCannedResponse/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/CannedResponse/modals/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/CannedResponse.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/CannedResponse.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/CannedResponseList.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/CannedResponseList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/Item.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/Item.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/WrapCannedResponse.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/components/contextualBar/CannedResponse/index.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/hooks/useCannedResponseFilterOptions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/hooks/useCannedResponseList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/hooks/useOmnichannelPriorities.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/hooks/useOmnichannelPrioritiesMenu.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/hooks/useScopeDict.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/monitors/MonitorsPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/monitors/MonitorsPageContainer.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/monitors/MonitorsRow.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/monitors/MonitorsTable.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PrioritiesPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PrioritiesResetModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PrioritiesRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PrioritiesTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PriorityEditForm.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PriorityEditFormWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PriorityIcon.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/priorities/PriorityVerticalBar.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/routes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/slaPolicies/RemoveSlaButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/slaPolicies/SlaEdit.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/slaPolicies/SlaEditWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/slaPolicies/SlaNew.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/slaPolicies/SlasPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/slaPolicies/SlasRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/AutoCompleteTags.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/AutoCompleteTagsMultiple.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/CurrentChatTags.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/RemoveTagButton.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/TagEdit.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/TagEditWithData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/TagEditWithDepartmentData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/TagsPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/tags/TagsRoute.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/units/RemoveUnitButton.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/units/UnitEdit.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/units/UnitEditWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/units/UnitsPage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/omnichannel/units/UnitsRoute.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/sidebar/footer/SidebarFooterWatermark.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/audit.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/deviceManagement.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/engagementDashboard.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/readReceipt.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/slashCommands/federation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/startup/slashCommands/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/account/deviceManagement/DeviceManagementAccountPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/account/deviceManagement/DeviceManagementAccountTable/DeviceManagementAccountRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/account/deviceManagement/DeviceManagementAccountTable/DeviceManagementAccountTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/account/deviceManagement/DeviceManagementAccountTable/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementAdminPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementAdminRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementAdminTable/DeviceManagementAdminRow.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementAdminTable/DeviceManagementAdminTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementAdminTable/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementInfo/DeviceManagementInfo.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementInfo/DeviceManagementInfoWithData.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/deviceManagement/DeviceManagementInfo/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardCardErrorBoundary.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardCardFilter.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/EngagementDashboardRoute.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/channels/ChannelsOverview.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/channels/ChannelsTab.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/channels/ChannelsTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/channels/useChannelsList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/DownloadDataButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/LegendSymbol.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/LegendSymbol.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/PeriodSelector.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/colors.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/periods.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/usePeriodLabel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/dataView/usePeriodSelectorState.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/MessagesPerChannelSection.tsx",["23108"],[],"import { ResponsivePie } from '@nivo/pie';\nimport { Box, Flex, Icon, Margins, Skeleton, Table, Tile, Palette } from '@rocket.chat/fuselage';\nimport { useTranslation } from '@rocket.chat/ui-contexts';\nimport type { ReactElement } from 'react';\nimport React, { useMemo } from 'react';\n\nimport EngagementDashboardCardFilter from '../EngagementDashboardCardFilter';\nimport DownloadDataButton from '../dataView/DownloadDataButton';\nimport LegendSymbol from '../dataView/LegendSymbol';\nimport PeriodSelector from '../dataView/PeriodSelector';\nimport { usePeriodSelectorState } from '../dataView/usePeriodSelectorState';\nimport { useMessageOrigins } from './useMessageOrigins';\nimport { useTopFivePopularChannels } from './useTopFivePopularChannels';\n\nconst colors = {\n\twarning: Palette.statusColor['status-font-on-warning'].toString(),\n\tsuccess: Palette.statusColor['status-font-on-success'].toString(),\n\tinfo: Palette.statusColor['status-font-on-info'].toString(),\n};\nconst MessagesPerChannelSection = (): ReactElement => {\n\tconst [period, periodSelectorProps] = usePeriodSelectorState('last 7 days', 'last 30 days', 'last 90 days');\n\n\tconst t = useTranslation();\n\n\tconst { data: messageOriginsData } = useMessageOrigins({ period });\n\tconst { data: topFivePopularChannelsData } = useTopFivePopularChannels({ period });\n\n\tconst pie = useMemo(\n\t\t() => messageOriginsData?.origins?.reduce<{ [roomType: string]: number }>((obj, { messages, t }) => ({ ...obj, [t]: messages }), {}),\n\t\t[messageOriginsData],\n\t);\n\n\tconst table = useMemo(\n\t\t() =>\n\t\t\ttopFivePopularChannelsData?.channels?.reduce<\n\t\t\t\t{\n\t\t\t\t\ti: number;\n\t\t\t\t\tt: string;\n\t\t\t\t\tname?: string;\n\t\t\t\t\tmessages: number;\n\t\t\t\t}[]\n\t\t\t>((entries, { t, messages, name, usernames }, i) => [...entries, { i, t, name: name || usernames?.join(' × '), messages }], []),\n\t\t[topFivePopularChannelsData],\n\t);\n\n\treturn (\n\t\t<>\n\t\t\t\n\t\t\t\t\n\t\t\t\t messageOriginsData?.origins.map(({ t, messages }) => [t, messages])}\n\t\t\t\t/>\n\t\t\t\n\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t{pie ? (\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{t('Value_messages', { value: datum.value })}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{t('Private_Chats')}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{t('Private_Channels')}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{t('Public_Channels')}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t{table ? {t('Most_popular_channels_top_5')} : }\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t{table && !table.length && (\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t{t('Not_enough_data')}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t{(!table || !!table.length) && (\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t{'#'}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{t('Channel')}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{t('Number_of_messages')}\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t{table?.map(({ i, t, name, messages }) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{i + 1}.\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{(t === 'd' && ) ||\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(t === 'p' && ) ||\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(t === 'c' && )}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{name}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{messages}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t\t\t{!table &&\n\t\t\t\t\t\t\t\t\t\t\t\t\tArray.from({ length: 5 }, (_, i) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\n\t);\n};\n\nexport default MessagesPerChannelSection;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/MessagesSentSection.tsx",["23109"],[],"import { ResponsiveBar } from '@nivo/bar';\nimport { Box, Flex, Skeleton, Palette } from '@rocket.chat/fuselage';\nimport colors from '@rocket.chat/fuselage-tokens/colors.json';\nimport { useTranslation } from '@rocket.chat/ui-contexts';\nimport moment from 'moment';\nimport type { ReactElement } from 'react';\nimport React, { useMemo } from 'react';\n\nimport CounterSet from '../../../../../../client/components/dataView/CounterSet';\nimport EngagementDashboardCardFilter from '../EngagementDashboardCardFilter';\nimport DownloadDataButton from '../dataView/DownloadDataButton';\nimport PeriodSelector from '../dataView/PeriodSelector';\nimport { usePeriodLabel } from '../dataView/usePeriodLabel';\nimport { usePeriodSelectorState } from '../dataView/usePeriodSelectorState';\nimport { useMessagesSent } from './useMessagesSent';\n\nconst MessagesSentSection = (): ReactElement => {\n\tconst [period, periodSelectorProps] = usePeriodSelectorState('last 7 days', 'last 30 days', 'last 90 days');\n\tconst periodLabel = usePeriodLabel(period);\n\n\tconst t = useTranslation();\n\n\tconst { data } = useMessagesSent({ period });\n\n\tconst [countFromPeriod, variatonFromPeriod, countFromYesterday, variationFromYesterday, values] = useMemo(() => {\n\t\tif (!data) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst values = Array.from({ length: moment(data.end).diff(data.start, 'days') + 1 }, (_, i) => ({\n\t\t\tdate: moment(data.start).add(i, 'days').toISOString(),\n\t\t\tnewMessages: 0,\n\t\t}));\n\n\t\tfor (const { day, messages } of data.days ?? []) {\n\t\t\tconst i = moment(day).diff(data.start, 'days');\n\t\t\tif (i >= 0) {\n\t\t\t\tvalues[i].newMessages += messages;\n\t\t\t}\n\t\t}\n\n\t\treturn [data.period?.count, data.period?.variation, data.yesterday?.count, data.yesterday?.variation, values];\n\t}, [data]);\n\n\treturn (\n\t\t<>\n\t\t\t\n\t\t\t\t\n\t\t\t\t values?.map(({ date, newMessages }) => [date, newMessages])}\n\t\t\t\t/>\n\t\t\t\n\n\t\t\t,\n\t\t\t\t\t\tvariation: variatonFromPeriod ?? 0,\n\t\t\t\t\t\tdescription: periodLabel,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tcount: countFromYesterday ?? ,\n\t\t\t\t\t\tvariation: variationFromYesterday ?? 0,\n\t\t\t\t\t\tdescription: t('Yesterday'),\n\t\t\t\t\t},\n\t\t\t\t]}\n\t\t\t/>\n\t\t\t\n\t\t\t\t{values ? (\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t moment(date).format('dddd'),\n\t\t\t\t\t\t\t\t\t\t\t}) ||\n\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\taxisLeft={null}\n\t\t\t\t\t\t\t\t\t\tanimate={true}\n\t\t\t\t\t\t\t\t\t\t// @ts-ignore\n\t\t\t\t\t\t\t\t\t\tmotionStiffness={90}\n\t\t\t\t\t\t\t\t\t\tmotionDamping={15}\n\t\t\t\t\t\t\t\t\t\ttheme={{\n\t\t\t\t\t\t\t\t\t\t\t// TODO: Get it from theme\n\t\t\t\t\t\t\t\t\t\t\taxis: {\n\t\t\t\t\t\t\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttext: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfill: colors.n600,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfontFamily:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'Inter, -apple-system, system-ui, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Helvetica Neue\", \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Meiryo UI\", Arial, sans-serif',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfontSize: '10px',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfontStyle: 'normal',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfontWeight: 600,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tletterSpacing: '0.2px',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tlineHeight: '12px',\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\ttooltip: {\n\t\t\t\t\t\t\t\t\t\t\t\tcontainer: {\n\t\t\t\t\t\t\t\t\t\t\t\t\tbackgroundColor: colors.n900,\n\t\t\t\t\t\t\t\t\t\t\t\t\tboxShadow: '0px 0px 12px rgba(47, 52, 61, 0.12), 0px 0px 2px rgba(47, 52, 61, 0.08)',\n\t\t\t\t\t\t\t\t\t\t\t\t\tborderRadius: 2,\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\ttooltip={({ value }): ReactElement => (\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t{t('Value_messages', { value })}\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t) : (\n\t\t\t\t\t\n\t\t\t\t)}\n\t\t\t\n\t\t\n\t);\n};\n\nexport default MessagesSentSection;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/MessagesTab.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/MessagesTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/useMessageOrigins.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/useMessagesSent.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/messages/useTopFivePopularChannels.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/ActiveUsersSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/BusiestChatTimesSection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/ContentForDays.tsx",["23110"],[],"import { ResponsiveBar } from '@nivo/bar';\nimport { Box, Flex, IconButton, Margins, Skeleton } from '@rocket.chat/fuselage';\nimport colors from '@rocket.chat/fuselage-tokens/colors';\nimport moment from 'moment';\nimport type { ReactElement } from 'react';\nimport React, { useMemo } from 'react';\n\nimport { useWeeklyChatActivity } from './useWeeklyChatActivity';\n\ntype ContentForDaysProps = {\n\tdisplacement: number;\n\tonPreviousDateClick: () => void;\n\tonNextDateClick: () => void;\n\ttimezone: 'utc' | 'local';\n};\n\nconst ContentForDays = ({ displacement, onPreviousDateClick, onNextDateClick, timezone }: ContentForDaysProps): ReactElement => {\n\tconst utc = timezone === 'utc';\n\tconst { data } = useWeeklyChatActivity({ displacement, utc });\n\n\tconst formattedCurrentDate = useMemo(() => {\n\t\tif (!data) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst endOfWeek = moment(data.day);\n\t\tconst startOfWeek = moment(data.day).subtract(6, 'days');\n\t\treturn `${startOfWeek.format('L')} - ${endOfWeek.format('L')}`;\n\t}, [data]);\n\n\tconst values = useMemo(\n\t\t() =>\n\t\t\tdata?.month\n\t\t\t\t?.map(({ users, day, month, year }) => ({\n\t\t\t\t\tusers,\n\t\t\t\t\tday: moment({ year, month: month - 1, day }),\n\t\t\t\t}))\n\t\t\t\t?.sort(({ day: a }, { day: b }) => a.diff(b))\n\t\t\t\t?.map(({ users, day }) => ({ users, day: String(day.valueOf()) })) ?? [],\n\t\t[data],\n\t);\n\n\treturn (\n\t\t<>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t{formattedCurrentDate}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t{data ? (\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t moment(parseInt(timestamp, 10)).format('L'),\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\taxisLeft={null}\n\t\t\t\t\t\t\t\t\t\tanimate={true}\n\t\t\t\t\t\t\t\t\t\t// @ts-ignore\n\t\t\t\t\t\t\t\t\t\tmotionStiffness={90}\n\t\t\t\t\t\t\t\t\t\tmotionDamping={15}\n\t\t\t\t\t\t\t\t\t\ttheme={{\n\t\t\t\t\t\t\t\t\t\t\t// TODO: Get it from theme\n\t\t\t\t\t\t\t\t\t\t\taxis: {\n\t\t\t\t\t\t\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttext: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfill: colors.n600,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfontFamily:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'Inter, -apple-system, system-ui, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Helvetica Neue\", \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Meiryo UI\", Arial, sans-serif',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfontSize: '10px',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfontStyle: 'normal',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfontWeight: 600,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tletterSpacing: '0.2px',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tlineHeight: '12px',\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t) : (\n\t\t\t\t\t\n\t\t\t\t)}\n\t\t\t\n\t\t\n\t);\n};\n\nexport default ContentForDays;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/ContentForHours.tsx",["23111"],[],"import { ResponsiveBar } from '@nivo/bar';\nimport { Box, Button, Chevron, Skeleton } from '@rocket.chat/fuselage';\nimport { useBreakpoints } from '@rocket.chat/fuselage-hooks';\nimport colors from '@rocket.chat/fuselage-tokens/colors.json';\nimport { useTranslation } from '@rocket.chat/ui-contexts';\nimport moment from 'moment';\nimport type { ReactElement } from 'react';\nimport React, { useMemo } from 'react';\n\nimport { useHourlyChatActivity } from './useHourlyChatActivity';\n\ntype ContentForHoursProps = {\n\tdisplacement: number;\n\tonPreviousDateClick: () => void;\n\tonNextDateClick: () => void;\n\ttimezone: 'utc' | 'local';\n};\n\nconst ContentForHours = ({ displacement, onPreviousDateClick, onNextDateClick, timezone }: ContentForHoursProps): ReactElement => {\n\tconst utc = timezone === 'utc';\n\tconst { data } = useHourlyChatActivity({ displacement, utc });\n\n\tconst t = useTranslation();\n\tconst isLgScreen = useBreakpoints().includes('lg');\n\n\tconst values = useMemo(() => {\n\t\tif (!data) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst divider = 2;\n\t\tconst values = Array.from({ length: 24 / divider }, (_, i) => ({\n\t\t\thour: String(divider * i),\n\t\t\tusers: 0,\n\t\t}));\n\n\t\tfor (const { hour, users } of data?.hours ?? []) {\n\t\t\tconst i = Math.floor(hour / divider);\n\t\t\tvalues[i] = values[i] || { hour: String(divider * i), users: 0 };\n\t\t\tvalues[i].users += users;\n\t\t}\n\n\t\treturn values;\n\t}, [data]);\n\n\treturn (\n\t\t<>\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t{data ? moment(data.day).format(displacement < 7 ? 'dddd' : 'L') : null}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t{data ? (\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t moment().set({ hour, minute: 0, second: 0 }).format('LT'),\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\taxisLeft={null}\n\t\t\t\t\t\t\t\tanimate={true}\n\t\t\t\t\t\t\t\tmotionStiffness={90}\n\t\t\t\t\t\t\t\tmotionDamping={15}\n\t\t\t\t\t\t\t\ttheme={{\n\t\t\t\t\t\t\t\t\t// TODO: Get it from theme\n\t\t\t\t\t\t\t\t\taxis: {\n\t\t\t\t\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\t\t\t\t\ttext: {\n\t\t\t\t\t\t\t\t\t\t\t\tfill: colors.n600,\n\t\t\t\t\t\t\t\t\t\t\t\tfontFamily:\n\t\t\t\t\t\t\t\t\t\t\t\t\t'Inter, -apple-system, system-ui, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Helvetica Neue\", \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Meiryo UI\", Arial, sans-serif',\n\t\t\t\t\t\t\t\t\t\t\t\tfontSize: '10px',\n\t\t\t\t\t\t\t\t\t\t\t\tfontStyle: 'normal',\n\t\t\t\t\t\t\t\t\t\t\t\tfontWeight: 600,\n\t\t\t\t\t\t\t\t\t\t\t\tletterSpacing: '0.2px',\n\t\t\t\t\t\t\t\t\t\t\t\tlineHeight: '12px',\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\ttooltip: {\n\t\t\t\t\t\t\t\t\t\t// @ts-ignore\n\t\t\t\t\t\t\t\t\t\tbackgroundColor: colors.n900,\n\t\t\t\t\t\t\t\t\t\tboxShadow: '0px 0px 12px rgba(47, 52, 61, 0.12), 0px 0px 2px rgba(47, 52, 61, 0.08)',\n\t\t\t\t\t\t\t\t\t\tborderRadius: 2,\n\t\t\t\t\t\t\t\t\t\tpadding: 4,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\ttooltip={({ value }): ReactElement => (\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t{t('Value_users', { value })}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t) : (\n\t\t\t\t\n\t\t\t)}\n\t\t\n\t);\n};\n\nexport default ContentForHours;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/NewUsersSection.tsx",["23112"],[],"import { ResponsiveBar } from '@nivo/bar';\nimport { Box, Flex, Skeleton } from '@rocket.chat/fuselage';\nimport { useResizeObserver } from '@rocket.chat/fuselage-hooks';\nimport colors from '@rocket.chat/fuselage-tokens/colors.json';\nimport { useTranslation } from '@rocket.chat/ui-contexts';\nimport moment from 'moment';\nimport type { ReactElement } from 'react';\nimport React, { useMemo } from 'react';\n\nimport CounterSet from '../../../../../../client/components/dataView/CounterSet';\nimport { useFormatDate } from '../../../../../../client/hooks/useFormatDate';\nimport EngagementDashboardCardFilter from '../EngagementDashboardCardFilter';\nimport DownloadDataButton from '../dataView/DownloadDataButton';\nimport PeriodSelector from '../dataView/PeriodSelector';\nimport { usePeriodLabel } from '../dataView/usePeriodLabel';\nimport { usePeriodSelectorState } from '../dataView/usePeriodSelectorState';\nimport { useNewUsers } from './useNewUsers';\n\nconst TICK_WIDTH = 45;\n\ntype NewUsersSectionProps = {\n\ttimezone: 'utc' | 'local';\n};\n\nconst NewUsersSection = ({ timezone }: NewUsersSectionProps): ReactElement => {\n\tconst [period, periodSelectorProps] = usePeriodSelectorState('last 7 days', 'last 30 days', 'last 90 days');\n\tconst periodLabel = usePeriodLabel(period);\n\n\tconst utc = timezone === 'utc';\n\tconst { data } = useNewUsers({ period, utc });\n\n\tconst t = useTranslation();\n\n\tconst formatDate = useFormatDate();\n\n\tconst { ref: sizeRef, contentBoxSize: { inlineSize = 600 } = {} } = useResizeObserver();\n\n\tconst maxTicks = Math.ceil(inlineSize / TICK_WIDTH);\n\n\tconst tickValues = useMemo(() => {\n\t\tif (!data) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst arrayLength = moment(data.end).diff(data.start, 'days') + 1;\n\t\tif (arrayLength <= maxTicks || !maxTicks) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst values = Array.from({ length: arrayLength }, (_, i) => moment(data.start).add(i, 'days').format('YYYY-MM-DD'));\n\n\t\tconst relation = Math.ceil(values.length / maxTicks);\n\n\t\treturn values.reduce((acc, cur, i) => {\n\t\t\tif ((i + 1) % relation === 0) {\n\t\t\t\tacc = [...acc, cur];\n\t\t\t}\n\t\t\treturn acc;\n\t\t}, [] as string[]);\n\t}, [data, maxTicks]);\n\n\tconst [countFromPeriod, variatonFromPeriod, countFromYesterday, variationFromYesterday, values] = useMemo(() => {\n\t\tif (!data) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst values = Array.from({ length: moment(data.end).diff(data.start, 'days') + 1 }, (_, i) => ({\n\t\t\tdate: moment(data.start).add(i, 'days').format('YYYY-MM-DD'),\n\t\t\tnewUsers: 0,\n\t\t}));\n\t\tfor (const { day, users } of data.days) {\n\t\t\tconst i = utc ? moment(day).utc().diff(data.start, 'days') : moment(day).diff(data.start, 'days');\n\t\t\tif (i >= 0) {\n\t\t\t\tvalues[i].newUsers += users;\n\t\t\t}\n\t\t}\n\n\t\treturn [data.period.count, data.period.variation, data.yesterday.count, data.yesterday.variation, values];\n\t}, [data, utc]);\n\n\treturn (\n\t\t<>\n\t\t\t\n\t\t\t\t\n\t\t\t\t values?.map(({ date, newUsers }) => [date, newUsers])}\n\t\t\t\t/>\n\t\t\t\n\t\t\t,\n\t\t\t\t\t\tvariation: variatonFromPeriod ?? 0,\n\t\t\t\t\t\tdescription: periodLabel,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tcount: countFromYesterday ?? ,\n\t\t\t\t\t\tvariation: variationFromYesterday ?? 0,\n\t\t\t\t\t\tdescription: t('Yesterday'),\n\t\t\t\t\t},\n\t\t\t\t]}\n\t\t\t/>\n\t\t\t\n\t\t\t\t{values ? (\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t moment(date).format(values?.length === 7 ? 'dddd' : 'DD/MM'),\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\taxisLeft={{\n\t\t\t\t\t\t\t\t\t\t\ttickSize: 0,\n\t\t\t\t\t\t\t\t\t\t\t// TODO: Get it from theme\n\t\t\t\t\t\t\t\t\t\t\ttickPadding: 4,\n\t\t\t\t\t\t\t\t\t\t\ttickRotation: 0,\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\tanimate={true}\n\t\t\t\t\t\t\t\t\t\tmotionStiffness={90}\n\t\t\t\t\t\t\t\t\t\tmotionDamping={15}\n\t\t\t\t\t\t\t\t\t\ttheme={{\n\t\t\t\t\t\t\t\t\t\t\t// TODO: Get it from theme\n\t\t\t\t\t\t\t\t\t\t\taxis: {\n\t\t\t\t\t\t\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttext: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfill: colors.n600,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfontFamily:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'Inter, -apple-system, system-ui, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Helvetica Neue\", \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Meiryo UI\", Arial, sans-serif',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfontSize: '10px',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfontStyle: 'normal',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfontWeight: 600,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tletterSpacing: '0.2px',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tlineHeight: '12px',\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\ttooltip: {\n\t\t\t\t\t\t\t\t\t\t\t\t// @ts-ignore\n\t\t\t\t\t\t\t\t\t\t\t\tbackgroundColor: colors.n900,\n\t\t\t\t\t\t\t\t\t\t\t\tboxShadow: '0px 0px 12px rgba(47, 52, 61, 0.12), 0px 0px 2px rgba(47, 52, 61, 0.08)',\n\t\t\t\t\t\t\t\t\t\t\t\tborderRadius: 2,\n\t\t\t\t\t\t\t\t\t\t\t\tpadding: 4,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\ttooltip={({ value, indexValue }): ReactElement => (\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t{t('Value_users', { value })}, {formatDate(indexValue)}\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t) : (\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t)}\n\t\t\t\n\t\t\n\t);\n};\n\nexport default NewUsersSection;\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersByTimeOfTheDaySection.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersTab.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/UsersTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/useActiveUsers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/useHourlyChatActivity.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/useNewUsers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/useUsersByTimeOfTheDay.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/engagementDashboard/users/useWeeklyChatActivity.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/info/SeatsCard.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/CloseToSeatsCapModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/ReachedSeatsCapModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/SeatsCapUsage/SeatsCapUsage.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/SeatsCapUsage/SeatsCapUsage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/SeatsCapUsage/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/SeatsCapUsage/useUsageLabel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/UserPageHeaderContentWithSeatsCap.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/useRequestSeatsLink.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/admin/users/useSeatsCap.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/AuditLogPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/AuditPage.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/AuditFiltersDisplay.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/AuditForm.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/AuditLogEntry.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/AuditLogTable.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/AuditMessageList.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/AuditResult.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/forms/DateRangePicker.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/forms/RoomAutoComplete.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/forms/UsernamesAutoComplete.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/forms/VisitorAutoComplete.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/tabs/DirectTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/tabs/OmnichannelTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/tabs/RoomsTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/components/tabs/UsersTab.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/hooks/useAuditForm.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/hooks/useAuditMutation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/hooks/useAuditTab.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/hooks/useSendTelemetryMutation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/views/audit/utils/dateRange.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/components/modals/WrapUpCallModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/DialInput.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/DialPadModal.stories.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/DialPadModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/Pad.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/PadButton.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/hooks/useDialPad.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/hooks/useEnterKey.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modal/DialPad/hooks/useLongPress.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/client/voip/modals/DeviceSettingsModal.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/IAuditLog.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/methods/audit.ts",[],["23113"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/methods/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/methods/license.ts",[],["23114"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/chat.ts",[],["23115"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/engagementDashboard.ts",[],["23116"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/omnichannel/businessHours.ts",[],["23117"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/omnichannel/businessUnits.ts",[],["23118"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/omnichannel/cannedResponses.ts",[],["23119"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/omnichannel/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/roles.ts",[],["23120"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/sessions/SessionsPaginateProps.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/sessions/SessionsProps.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/sessions/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/definition/rest/v1/sessions/sessions.ts",[],["23121"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/lib/misc/DeferredValue.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/lib/misc/Utilities.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/lib/misc/determineFileType.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/lib/misc/formatAppInstanceForRest.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/lib/misc/transformMappedData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/NetworkBroker.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/api.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/chat.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/engagementDashboard/channels.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/engagementDashboard/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/engagementDashboard/messages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/engagementDashboard/users.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/federation/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/federation/rooms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/ldap.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/licenses.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/roles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/api/sessions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/appRequestsCron.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/endpoints/actionButtonsHandler.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/endpoints/appsCountHandler.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/events.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/rest.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/uikit.ts",[],["23122","23123"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/communication/websockets.ts",[],["23124","23125","23126","23127","23128","23129","23130"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/cron.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/marketplace/appInstall.ts",[],["23131","23132","23133"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/marketplace/appRequestNotifyUsers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/orchestrator.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/storage/AppFileSystemSourceStorage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/storage/AppGridFSSourceStorage.ts",[],["23134"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/storage/AppRealStorage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/storage/ConfigurableAppSourceStorage.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/storage/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/apps/storage/logs-storage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/configuration/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/configuration/ldap.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/configuration/oauth.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/configuration/saml.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/configuration/videoConference.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/EnterpriseCheck.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/audit/AuditLog.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/audit/methods.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/audit/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/constants.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/deviceManagement/session.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/deviceManagement/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/channels.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/date.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/messages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/users.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/Manager.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/copyCustomFieldsLDAP.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/copyCustomFieldsLDAP.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/getNestedProp.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/getNestedProp.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/replacesNestedValues.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/ldap/replacesNestedValues.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/message-read-receipt/ReadReceipt.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/oauth/Manager.ts",["23135"],[],"import { Roles } from '@rocket.chat/models';\nimport type { IUser } from '@rocket.chat/core-typings';\n\nimport { Rooms } from '../../../../app/models/server';\nimport { addUserToRoom, createRoom } from '../../../../app/lib/server/functions';\nimport { Logger } from '../../../../app/logger/server';\nimport { syncUserRoles } from '../syncUserRoles';\n\nexport const logger = new Logger('OAuth');\n\nexport class OAuthEEManager {\n\tstatic mapSSOGroupsToChannels(\n\t\tuser: IUser,\n\t\tidentity: Record,\n\t\tgroupClaimName: string,\n\t\tchannelsMap: Record | undefined,\n\t\tchannelsAdmin: string,\n\t): void {\n\t\tif (user && identity && groupClaimName) {\n\t\t\tconst groupsFromSSO = identity[groupClaimName] || [];\n\n\t\t\tfor (const ssoGroup in channelsMap) {\n\t\t\t\tif (typeof ssoGroup === 'string') {\n\t\t\t\t\tlet channels = channelsMap[ssoGroup];\n\t\t\t\t\tif (!Array.isArray(channels)) {\n\t\t\t\t\t\tchannels = [channels];\n\t\t\t\t\t}\n\t\t\t\t\tfor (const channel of channels) {\n\t\t\t\t\t\tlet room = Rooms.findOneByNonValidatedName(channel);\n\t\t\t\t\t\tif (!room) {\n\t\t\t\t\t\t\troom = createRoom('c', channel, channelsAdmin, [], false);\n\t\t\t\t\t\t\tif (!room || !room.rid) {\n\t\t\t\t\t\t\t\tlogger.error(`could not create channel ${channel}`);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (Array.isArray(groupsFromSSO) && groupsFromSSO.includes(ssoGroup)) {\n\t\t\t\t\t\t\taddUserToRoom(room._id, user);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic updateRolesFromSSO(user: Record, identity: Record, roleClaimName: string, rolesToSync: string[]): void {\n\t\tif (user && identity && roleClaimName) {\n\t\t\tconst rolesFromSSO = this.mapRolesFromSSO(identity, roleClaimName);\n\n\t\t\tif (!Array.isArray(user.roles)) {\n\t\t\t\tuser.roles = [];\n\t\t\t}\n\n\t\t\tconst rolesIdsFromSSO = Promise.await(Roles.findInIdsOrNames(rolesFromSSO).toArray()).map((role) => role._id);\n\t\t\tconst allowedRoles = Promise.await(Roles.findInIdsOrNames(rolesToSync).toArray()).map((role) => role._id);\n\n\t\t\tPromise.await(\n\t\t\t\tsyncUserRoles(user._id, rolesIdsFromSSO, {\n\t\t\t\t\tallowedRoles,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\t// Returns list of roles from SSO identity\n\tstatic mapRolesFromSSO(identity: Record, roleClaimName: string): string[] {\n\t\tlet roles: string[] = [];\n\t\tif (identity && roleClaimName) {\n\t\t\t// Adding roles\n\t\t\tif (identity[roleClaimName] && Array.isArray(identity[roleClaimName])) {\n\t\t\t\troles = identity[roleClaimName].filter(\n\t\t\t\t\t(val: string) => val !== 'offline_access' && val !== 'uma_authorization' && Promise.await(Roles.findOneByIdOrName(val)),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn roles;\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/registerServiceModels.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/roles/insertRole.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/roles/updateRole.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/lib/syncUserRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/local-services/instance/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/local-services/ldap/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/local-services/message-reads/service.ts",["23136"],[],"import { MessageReads, Subscriptions } from '@rocket.chat/models';\nimport type { ISubscription } from '@rocket.chat/core-typings';\nimport { ServiceClassInternal } from '@rocket.chat/core-services';\n\nimport type { IMessageReadsService } from '../../sdk/types/IMessageReadsService';\nimport { Messages } from '../../../../app/models/server';\nimport { ReadReceipt } from '../../lib/message-read-receipt/ReadReceipt';\nimport { MAX_ROOM_SIZE_CHECK_INDIVIDUAL_READ_RECEIPTS } from '../../lib/constants';\n\nexport class MessageReadsService extends ServiceClassInternal implements IMessageReadsService {\n\tprotected name = 'message-reads';\n\n\tasync readThread(userId: string, tmid: string): Promise {\n\t\tconst read = await MessageReads.findOneByUserIdAndThreadId(userId, tmid);\n\n\t\tconst threadMessage = Messages.findOneById(tmid, { projection: { ts: 1, tlm: 1, rid: 1 } });\n\t\tif (!threadMessage || !threadMessage.tlm) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait MessageReads.updateReadTimestampByUserIdAndThreadId(userId, tmid);\n\t\tReadReceipt.storeThreadMessagesReadReceipts(tmid, userId, read?.ls || threadMessage.ts);\n\n\t\t// doesn't mark as read if not all room members have read the thread\n\t\tconst membersCount = await Subscriptions.countUnarchivedByRoomId(threadMessage.rid);\n\n\t\tif (membersCount <= MAX_ROOM_SIZE_CHECK_INDIVIDUAL_READ_RECEIPTS) {\n\t\t\tconst subscriptions = await Subscriptions.findUnarchivedByRoomId(threadMessage.rid, {\n\t\t\t\tprojection: { 'u._id': 1 },\n\t\t\t}).toArray();\n\t\t\tconst members = subscriptions.map((s: ISubscription) => s.u._id);\n\n\t\t\tconst totalMessageReads = await MessageReads.countByThreadAndUserIds(tmid, members);\n\t\t\tif (totalMessageReads < membersCount) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else {\n\t\t\t// for large rooms, mark as read if there are as many reads as room members to improve performance (instead of checking each read)\n\t\t\tconst totalMessageReads = await MessageReads.countByThreadId(tmid);\n\t\t\tif (totalMessageReads < membersCount) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst firstRead = await MessageReads.getMinimumLastSeenByThreadId(tmid);\n\t\tif (firstRead?.ls) {\n\t\t\tMessages.setThreadMessagesAsRead(tmid, firstRead.ls);\n\t\t}\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/methods/getReadReceipts.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/CannedResponse.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatDepartment.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatInquiry.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatPriority.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatRooms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatTag.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatUnit.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/LivechatUnitMonitors.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/OmnichannelServiceLevelAgreements.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/ReadReceipts.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/CannedResponse.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatDepartment.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatInquiry.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatPriority.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatRooms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatTag.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatUnit.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/LivechatUnitMonitors.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/ReadReceipts.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/raw/ServiceLevelAgreements.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/models/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/requestSeatsRoute.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/sdk/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/sdk/types/IInstanceService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/sdk/types/ILDAPEEService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/sdk/types/IMessageReadsService.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/sdk/types/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/services/ecdh-proxy/ECDHProxy.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/services/ecdh-proxy/lib/server.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/services/ecdh-proxy/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/services/mongo.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/settings/deviceManagement.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/settings/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/settings/ldap.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/settings/saml.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/settings/video-conference.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/audit.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/broker.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/deviceManagement.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/engagementDashboard.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/presence.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/seatsCap.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/services.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/server/startup/upsell.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/application/DMRoomInternalHooksServiceSender.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/application/RoomInternalHooksServiceSender.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/application/RoomService.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/application/input/RoomInputDto.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/infrastructure/rocket-chat/hooks/hooks.spec.ts",[],["23137"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/ee/tests/unit/app/federation-v2/server/infrastructure/rocket-chat/slash-commands/actions.spec.ts",[],["23138","23139","23140","23141","23142","23143","23144","23145"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/imports/personal-access-tokens/server/api/methods/generateToken.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/imports/personal-access-tokens/server/api/methods/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/imports/personal-access-tokens/server/api/methods/regenerateToken.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/imports/personal-access-tokens/server/api/methods/removeToken.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/imports/personal-access-tokens/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/imports/startup/server/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/ClientLogger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/callbacks.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/createQuoteAttachment.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/emailValidator.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/getImageExtensionFromMime.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/getMessageUrlRegex.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/getUserEmailAddress.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/isTruthy.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/oauthRedirectUri.ts",[],["23146"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/random.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/roles/getMostImportantRole.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/roles/isValidRoleScope.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/adminFields.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/coordinator.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/conversation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/direct.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/discussion.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/favorite.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/livechat.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/private.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/public.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/unread.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/rooms/roomTypes/voip.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/transforms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/typedJSONParse.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/upgradeTab.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/addMinutesToADate.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/arrayUtils.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/comparisons.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/getFileExtension.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/highOrderFunctions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/isJSON.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/isRelativeURL.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/isURL.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/omit.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/parseCSV.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/parseParameters.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/promisify.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/safeHtmlDots.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/secondsToHHMMSS.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/utils/stringUtils.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/lib/videoConference/constants.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/accounts-linkedin/linkedin.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/accounts-linkedin/notice.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/accounts-linkedin/package.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/linkedin-oauth/linkedin-client.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/linkedin-oauth/linkedin-server.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/linkedin-oauth/package.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/package.js",[],["23147"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-config.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-filter.js",[],["23148"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-methods.js",[],["23149","23150","23151","23152"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-mime.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-server.js",[],["23153","23154","23155","23156","23157","23158","23159","23160","23161","23162","23163","23164"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-store-permissions.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-store.js",[],["23165","23166","23167","23168","23169","23170","23171","23172","23173","23174","23175","23176","23177","23178","23179","23180"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-tokens.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs-uploader.js",[],["23181","23182","23183","23184","23185","23186","23187","23188","23189","23190"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/meteor-jalik-ufs/ufs.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-ddp/client/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-ddp/package.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-i18n/package.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-livechat/package.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-livechat/plugin/build-livechat.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-mongo-config/package.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-mongo-config/server/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-postcss/build.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-postcss/package.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-version/package.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/packages/rocketchat-version/plugin/compile-version.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/playwright-federation.config.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/playwright.config.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/configuration/accounts_meld.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/configuration/ldap.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/cron/federation.ts",[],["23191"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/cron/nps.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/cron/oembed.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/cron/statistics.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/cron/userDataDownloads.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/cron/videoConferences.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/DatabaseWatcher.ts",["23192"],["23193"],"import EventEmitter from 'events';\n\nimport type { IRocketChatRecord } from '@rocket.chat/core-typings';\nimport type { Timestamp, Db, ChangeStreamDeleteDocument, ChangeStreamInsertDocument, ChangeStreamUpdateDocument } from 'mongodb';\nimport { escapeRegExp } from '@rocket.chat/string-helpers';\nimport { MongoClient } from 'mongodb';\n\nimport type { Logger } from '../lib/logger/Logger';\nimport { convertChangeStreamPayload } from './convertChangeStreamPayload';\nimport { convertOplogPayload } from './convertOplogPayload';\nimport { watchCollections } from './watchCollections';\n\nconst instancePing = parseInt(String(process.env.MULTIPLE_INSTANCES_PING_INTERVAL)) || 10000;\n\nconst maxDocMs = instancePing * 4; // 4 times the ping interval\n\nexport type RealTimeData = {\n\tid: string;\n\taction: 'insert' | 'update' | 'remove';\n\tclientAction: 'inserted' | 'updated' | 'removed';\n\tdata?: T;\n\tdiff?: Record;\n\tunset?: Record;\n\toplog?: true;\n};\n\nconst ignoreChangeStream = ['yes', 'true'].includes(String(process.env.IGNORE_CHANGE_STREAM).toLowerCase());\n\nconst useMeteorOplog = ['yes', 'true'].includes(String(process.env.USE_NATIVE_OPLOG).toLowerCase());\n\nexport class DatabaseWatcher extends EventEmitter {\n\tprivate db: Db;\n\n\tprivate _oplogHandle?: any;\n\n\tprivate metrics?: any;\n\n\tprivate logger: Logger;\n\n\t/**\n\t * Last doc timestamp received from a real time event\n\t */\n\tprivate lastDocTS: Date;\n\n\t// eslint-disable-next-line @typescript-eslint/naming-convention\n\tconstructor({ db, _oplogHandle, metrics, logger: LoggerClass }: { db: Db; _oplogHandle?: any; metrics?: any; logger: typeof Logger }) {\n\t\tsuper();\n\n\t\tthis.db = db;\n\t\tthis._oplogHandle = _oplogHandle;\n\t\tthis.metrics = metrics;\n\t\tthis.logger = new LoggerClass('DatabaseWatcher');\n\t}\n\n\tasync watch(): Promise {\n\t\tif (useMeteorOplog) {\n\t\t\t// TODO remove this when updating to Meteor 2.8\n\t\t\tthis.logger.warn(\n\t\t\t\t'Using USE_NATIVE_OPLOG=true is currently discouraged due to known performance issues. Please use IGNORE_CHANGE_STREAM=true instead.',\n\t\t\t);\n\t\t\tthis.watchMeteorOplog();\n\t\t\treturn;\n\t\t}\n\n\t\tif (ignoreChangeStream) {\n\t\t\tawait this.watchOplog();\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tthis.watchChangeStream();\n\t\t} catch (err: unknown) {\n\t\t\tawait this.watchOplog();\n\t\t}\n\t}\n\n\tprivate async watchOplog(): Promise {\n\t\tif (!process.env.MONGO_OPLOG_URL) {\n\t\t\tthrow Error('No $MONGO_OPLOG_URL provided');\n\t\t}\n\n\t\tconst isMasterDoc = await this.db.admin().command({ ismaster: 1 });\n\t\tif (!isMasterDoc || !isMasterDoc.setName) {\n\t\t\tthrow Error(\"$MONGO_URL should be a replica set's URL\");\n\t\t}\n\n\t\tconst dbName = this.db.databaseName;\n\n\t\tconst client = new MongoClient(process.env.MONGO_OPLOG_URL, {\n\t\t\tmaxPoolSize: 1,\n\t\t});\n\n\t\tif (client.db().databaseName !== 'local') {\n\t\t\tthrow Error(\"$MONGO_OPLOG_URL must be set to the 'local' database of a Mongo replica set\");\n\t\t}\n\n\t\tawait client.connect();\n\n\t\tthis.logger.startup('Using oplog');\n\n\t\tconst db = client.db();\n\n\t\tconst oplogCollection = db.collection('oplog.rs');\n\n\t\tconst lastOplogEntry = await oplogCollection.findOne<{ ts: Timestamp }>({}, { sort: { $natural: -1 }, projection: { _id: 0, ts: 1 } });\n\n\t\tconst oplogSelector = {\n\t\t\tns: new RegExp(`^(?:${[escapeRegExp(`${dbName}.`)].join('|')})`),\n\t\t\top: { $in: ['i', 'u', 'd'] },\n\t\t\t...(lastOplogEntry && { ts: { $gt: lastOplogEntry.ts } }),\n\t\t};\n\n\t\tconst cursor = oplogCollection.find(oplogSelector);\n\n\t\tcursor.addCursorFlag('tailable', true);\n\t\tcursor.addCursorFlag('awaitData', true);\n\t\tcursor.addCursorFlag('oplogReplay', true);\n\n\t\tconst stream = cursor.stream();\n\n\t\tstream.on('data', (doc) => {\n\t\t\tconst doesMatter = watchCollections.some((collection) => doc.ns === `${dbName}.${collection}`);\n\t\t\tif (!doesMatter) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.emitDoc(\n\t\t\t\tdoc.ns.slice(dbName.length + 1),\n\t\t\t\tconvertOplogPayload({\n\t\t\t\t\tid: doc.op === 'u' ? doc.o2._id : doc.o._id,\n\t\t\t\t\top: doc,\n\t\t\t\t}),\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate watchMeteorOplog(): void {\n\t\tif (!this._oplogHandle) {\n\t\t\tthrow new Error('no-oplog-handle');\n\t\t}\n\n\t\tthis.logger.startup('Using Meteor oplog');\n\n\t\twatchCollections.forEach((collection) => {\n\t\t\tthis._oplogHandle.onOplogEntry({ collection }, (event: any) => {\n\t\t\t\tthis.emitDoc(collection, convertOplogPayload(event));\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate watchChangeStream(): void {\n\t\ttry {\n\t\t\tconst changeStream = this.db.watch<\n\t\t\t\tIRocketChatRecord,\n\t\t\t\t| ChangeStreamInsertDocument\n\t\t\t\t| ChangeStreamUpdateDocument\n\t\t\t\t| ChangeStreamDeleteDocument\n\t\t\t>([\n\t\t\t\t{\n\t\t\t\t\t$match: {\n\t\t\t\t\t\t'operationType': { $in: ['insert', 'update', 'delete'] },\n\t\t\t\t\t\t'ns.coll': { $in: watchCollections },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t]);\n\t\t\tchangeStream.on('change', (event) => {\n\t\t\t\tthis.emitDoc(event.ns.coll, convertChangeStreamPayload(event));\n\t\t\t});\n\n\t\t\tchangeStream.on('error', (err) => {\n\t\t\t\tthrow err;\n\t\t\t});\n\n\t\t\tthis.logger.startup('Using change streams');\n\t\t} catch (err: unknown) {\n\t\t\tthis.logger.error(err, 'Change stream error');\n\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\tprivate emitDoc(collection: string, doc: RealTimeData | void): void {\n\t\tif (!doc) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.lastDocTS = new Date();\n\n\t\tthis.metrics?.oplog.inc({\n\t\t\tcollection,\n\t\t\top: doc.action,\n\t\t});\n\n\t\tthis.emit(collection, doc);\n\t}\n\n\ton(collection: string, callback: (event: RealTimeData) => void): this {\n\t\treturn super.on(collection, callback);\n\t}\n\n\t/**\n\t * @returns the last timestamp delta in miliseconds received from a real time event\n\t */\n\tgetLastDocDelta(): number {\n\t\treturn this.lastDocTS ? Date.now() - this.lastDocTS.getTime() : Infinity;\n\t}\n\n\t/**\n\t * @returns Indicates if the last document received is older than it should be. If that happens, it means that the oplog is not working properly\n\t */\n\tisLastDocDelayed(): boolean {\n\t\treturn this.getLastDocDelta() > maxDocMs;\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/convertChangeStreamPayload.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/convertOplogPayload.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/readSecondaryPreferred.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/trash.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/utils.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/database/watchCollections.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/email/IMAPInterceptor.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/features/EmailInbox/EmailInbox.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/features/EmailInbox/EmailInbox_Incoming.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/features/EmailInbox/EmailInbox_Outgoing.ts",["23194"],[],"import type Mail from 'nodemailer/lib/mailer';\nimport { Match } from 'meteor/check';\nimport { TAPi18n } from 'meteor/rocketchat:tap-i18n';\nimport type { IEmailInbox, IUser, IMessage } from '@rocket.chat/core-typings';\nimport { Uploads } from '@rocket.chat/models';\n\nimport { callbacks } from '../../../lib/callbacks';\nimport { FileUpload } from '../../../app/file-upload/server';\nimport { slashCommands } from '../../../app/utils/server';\nimport { Messages, Rooms, Users, LivechatRooms } from '../../../app/models/server';\nimport type { Inbox } from './EmailInbox';\nimport { inboxes } from './EmailInbox';\nimport { sendMessage } from '../../../app/lib/server/functions/sendMessage';\nimport { settings } from '../../../app/settings/server';\nimport { logger } from './logger';\n\nconst livechatQuoteRegExp = /^\\[\\s\\]\\(https?:\\/\\/.+\\/live\\/.+\\?msg=(?.+?)\\)\\s(?.+)/s;\n\nconst user: IUser = Users.findOneById('rocket.cat');\n\nconst language = settings.get('Language') || 'en';\nconst t = (s: string): string => TAPi18n.__(s, { lng: language });\n\n// TODO: change these messages with room notifications\nconst sendErrorReplyMessage = (error: string, options: any): void => {\n\tif (!options?.rid || !options?.msgId) {\n\t\treturn;\n\t}\n\n\tconst message = {\n\t\tgroupable: false,\n\t\tmsg: `@${options.sender} something went wrong when replying email, sorry. **Error:**: ${error}`,\n\t\t_id: String(Date.now()),\n\t\trid: options.rid,\n\t\tts: new Date(),\n\t};\n\n\tsendMessage(user, message, { _id: options.rid });\n};\n\nconst sendSuccessReplyMessage = (options: any): void => {\n\tif (!options?.rid || !options?.msgId) {\n\t\treturn;\n\t}\n\tconst message = {\n\t\tgroupable: false,\n\t\tmsg: `@${options.sender} Attachment was sent successfully`,\n\t\t_id: String(Date.now()),\n\t\trid: options.rid,\n\t\tts: new Date(),\n\t};\n\n\tsendMessage(user, message, { _id: options.rid });\n};\n\nasync function sendEmail(inbox: Inbox, mail: Mail.Options, options?: any): Promise<{ messageId: string }> {\n\treturn inbox.smtp\n\t\t.sendMail({\n\t\t\tfrom: inbox.config.senderInfo\n\t\t\t\t? {\n\t\t\t\t\t\tname: inbox.config.senderInfo,\n\t\t\t\t\t\taddress: inbox.config.email,\n\t\t\t\t }\n\t\t\t\t: inbox.config.email,\n\t\t\t...mail,\n\t\t})\n\t\t.then((info) => {\n\t\t\tlogger.info('Message sent: %s', info.messageId);\n\t\t\treturn info;\n\t\t})\n\t\t.catch((err) => {\n\t\t\tlogger.error({ msg: 'Error sending Email reply', err });\n\n\t\t\tif (!options?.msgId) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsendErrorReplyMessage(err.message, options);\n\t\t});\n}\n\nslashCommands.add({\n\tcommand: 'sendEmailAttachment',\n\tcallback: (command: any, params: string) => {\n\t\tlogger.debug('sendEmailAttachment command: ', command, params);\n\t\tif (command !== 'sendEmailAttachment' || !Match.test(params, String)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst message = Messages.findOneById(params.trim());\n\n\t\tif (!message || !message.file) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst room = Rooms.findOneById(message.rid);\n\n\t\tconst inbox = inboxes.get(room.email.inbox);\n\n\t\tif (!inbox) {\n\t\t\treturn sendErrorReplyMessage(`Email inbox ${room.email.inbox} not found or disabled.`, {\n\t\t\t\tmsgId: message._id,\n\t\t\t\tsender: message.u.username,\n\t\t\t\trid: room._id,\n\t\t\t});\n\t\t}\n\n\t\tconst file = Promise.await(Uploads.findOneById(message.file._id));\n\n\t\tif (!file) {\n\t\t\treturn;\n\t\t}\n\n\t\tFileUpload.getBuffer(file, (_err?: Error, buffer?: Buffer) => {\n\t\t\t!_err &&\n\t\t\t\tbuffer &&\n\t\t\t\tsendEmail(\n\t\t\t\t\tinbox,\n\t\t\t\t\t{\n\t\t\t\t\t\tto: room.email.replyTo,\n\t\t\t\t\t\tsubject: room.email.subject,\n\t\t\t\t\t\ttext: message.attachments[0].description || '',\n\t\t\t\t\t\tattachments: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcontent: buffer,\n\t\t\t\t\t\t\t\tcontentType: file.type,\n\t\t\t\t\t\t\t\tfilename: file.name,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tinReplyTo: room.email.thread,\n\t\t\t\t\t\treferences: [room.email.thread],\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tmsgId: message._id,\n\t\t\t\t\t\tsender: message.u.username,\n\t\t\t\t\t\trid: message.rid,\n\t\t\t\t\t},\n\t\t\t\t).then((info) => LivechatRooms.updateEmailThreadByRoomId(room._id, info.messageId));\n\t\t});\n\n\t\tMessages.update(\n\t\t\t{ _id: message._id },\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\tblocks: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'context',\n\t\t\t\t\t\t\telements: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: 'mrkdwn',\n\t\t\t\t\t\t\t\t\ttext: `**${t('To')}:** ${room.email.replyTo}\\n**${t('Subject')}:** ${room.email.subject}`,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\t$pull: {\n\t\t\t\t\tattachments: { 'actions.0.type': 'button' },\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\n\t\treturn sendSuccessReplyMessage({\n\t\t\tmsgId: message._id,\n\t\t\tsender: message.u.username,\n\t\t\trid: room._id,\n\t\t});\n\t},\n\toptions: {\n\t\tdescription: 'Send attachment as email',\n\t\tparams: 'msg_id',\n\t},\n\tprovidesPreview: false,\n});\n\ncallbacks.add(\n\t'afterSaveMessage',\n\tfunction (message: IMessage, room: any) {\n\t\tif (!room?.email?.inbox) {\n\t\t\treturn message;\n\t\t}\n\n\t\tif (message.files?.length && message.u.username !== 'rocket.cat') {\n\t\t\tsendMessage(\n\t\t\t\tuser,\n\t\t\t\t{\n\t\t\t\t\tmsg: '',\n\t\t\t\t\tattachments: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tactions: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\t\t\t\ttext: t('Send_via_Email_as_attachment'),\n\t\t\t\t\t\t\t\t\tmsg: `/sendEmailAttachment ${message._id}`,\n\t\t\t\t\t\t\t\t\tmsg_in_chat_window: true,\n\t\t\t\t\t\t\t\t\tmsg_processing_type: 'sendMessage',\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\troom,\n\t\t\t\ttrue,\n\t\t\t);\n\t\t\treturn message;\n\t\t}\n\n\t\tconst { msg } = message;\n\n\t\t// Try to identify a quote in a livechat room\n\t\tconst match = msg.match(livechatQuoteRegExp);\n\t\tif (!match?.groups) {\n\t\t\treturn message;\n\t\t}\n\n\t\tconst inbox = inboxes.get(room.email.inbox);\n\n\t\tif (!inbox) {\n\t\t\tsendErrorReplyMessage(`Email inbox ${room.email.inbox} not found or disabled.`, {\n\t\t\t\tmsgId: message._id,\n\t\t\t\tsender: message.u.username,\n\t\t\t\trid: room._id,\n\t\t\t});\n\n\t\t\treturn message;\n\t\t}\n\n\t\tif (!inbox) {\n\t\t\treturn message;\n\t\t}\n\n\t\tconst replyToMessage = Messages.findOneById(match.groups.id);\n\n\t\tif (!replyToMessage?.email?.messageId) {\n\t\t\treturn message;\n\t\t}\n\n\t\tsendEmail(\n\t\t\tinbox,\n\t\t\t{\n\t\t\t\ttext: match.groups.text,\n\t\t\t\tinReplyTo: replyToMessage.email.messageId,\n\t\t\t\treferences: [...(replyToMessage.email.references ?? []), replyToMessage.email.messageId],\n\t\t\t\tto: room.email.replyTo,\n\t\t\t\tsubject: room.email.subject,\n\t\t\t},\n\t\t\t{\n\t\t\t\tmsgId: message._id,\n\t\t\t\tsender: message.u.username,\n\t\t\t\trid: room._id,\n\t\t\t},\n\t\t).then((info) => LivechatRooms.updateEmailThreadByRoomId(room._id, info.messageId));\n\n\t\tmessage.msg = match.groups.text;\n\n\t\tmessage.groupable = false;\n\n\t\tmessage.blocks = [\n\t\t\t{\n\t\t\t\ttype: 'context',\n\t\t\t\telements: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'mrkdwn',\n\t\t\t\t\t\ttext: `**${t('To')}:** ${room.email.replyTo}\\n**${t('Subject')}:** ${room.email.subject}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'section',\n\t\t\t\ttext: {\n\t\t\t\t\ttype: 'mrkdwn',\n\t\t\t\t\ttext: message.msg,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttype: 'section',\n\t\t\t\ttext: {\n\t\t\t\t\ttype: 'mrkdwn',\n\t\t\t\t\ttext: `> ---\\n${replyToMessage.msg.replace(/^/gm, '> ')}`,\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\n\t\tdelete message.urls;\n\n\t\treturn message;\n\t},\n\tcallbacks.priority.LOW,\n\t'ReplyEmail',\n);\n\nexport async function sendTestEmailToInbox(emailInboxRecord: IEmailInbox, user: IUser): Promise {\n\tconst inbox = inboxes.get(emailInboxRecord.email);\n\n\tif (!inbox) {\n\t\tthrow new Error('inbox-not-found');\n\t}\n\n\tconst address = user.emails?.find((email) => email.verified)?.address;\n\n\tif (!address) {\n\t\tthrow new Error('user-without-verified-email');\n\t}\n\n\tlogger.info(`Sending testing email to ${address}`);\n\tsendEmail(inbox, {\n\t\tto: address,\n\t\tsubject: 'Test of inbox configuration',\n\t\ttext: 'Test of inbox configuration successful',\n\t});\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/features/EmailInbox/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/features/EmailInbox/logger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/hooks/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/hooks/messages/markdownParser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/hooks/sauMonitorHooks.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/importPackages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/compareUserPassword.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/compareUserPasswordHistory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/copyFileUpload.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts",["23195"],[],"import { mkdir, writeFile } from 'fs/promises';\n\nimport { TAPi18n } from 'meteor/rocketchat:tap-i18n';\nimport { Messages as MessagesRaw } from '@rocket.chat/models';\nimport type { IMessage, IRoom, IUser, MessageAttachment, FileProp, RoomType } from '@rocket.chat/core-typings';\n\nimport { settings } from '../../../app/settings/server';\nimport { joinPath } from '../fileUtils';\nimport { readSecondaryPreferred } from '../../database/readSecondaryPreferred';\nimport { Messages } from '../../../app/models/server';\n\nconst hideUserName = (\n\tusername: string,\n\tuserData: Pick | undefined,\n\tusersMap: { userNameTable: Record },\n) => {\n\tif (!usersMap.userNameTable) {\n\t\tusersMap.userNameTable = {};\n\t}\n\n\tif (!usersMap.userNameTable[username]) {\n\t\tif (userData && username === userData.username) {\n\t\t\tusersMap.userNameTable[username] = username;\n\t\t} else {\n\t\t\tusersMap.userNameTable[username] = `User_${Object.keys(usersMap.userNameTable).length + 1}`;\n\t\t}\n\t}\n\n\treturn usersMap.userNameTable[username];\n};\n\nconst getAttachmentData = (attachment: MessageAttachment, message: IMessage) => {\n\treturn {\n\t\ttype: 'type' in attachment ? attachment.type : undefined,\n\t\ttitle: attachment.title,\n\t\ttitle_link: attachment.title_link,\n\t\timage_url: 'image_url' in attachment ? attachment.image_url : undefined,\n\t\taudio_url: 'audio_url' in attachment ? attachment.audio_url : undefined,\n\t\tvideo_url: 'video_url' in attachment ? attachment.video_url : undefined,\n\t\tmessage_link: 'message_link' in attachment ? attachment.message_link : undefined,\n\t\timage_type: 'image_type' in attachment ? attachment.image_type : undefined,\n\t\timage_size: 'image_size' in attachment ? attachment.image_size : undefined,\n\t\tvideo_size: 'video_size' in attachment ? attachment.video_size : undefined,\n\t\tvideo_type: 'video_type' in attachment ? attachment.video_type : undefined,\n\t\taudio_size: 'audio_size' in attachment ? attachment.audio_size : undefined,\n\t\taudio_type: 'audio_type' in attachment ? attachment.audio_type : undefined,\n\t\turl:\n\t\t\tattachment.title_link ||\n\t\t\t('image_url' in attachment ? attachment.image_url : undefined) ||\n\t\t\t('audio_url' in attachment ? attachment.audio_url : undefined) ||\n\t\t\t('video_url' in attachment ? attachment.video_url : undefined) ||\n\t\t\t('message_link' in attachment ? attachment.message_link : undefined) ||\n\t\t\tnull,\n\t\tremote: !message.file?._id,\n\t\tfileId: message.file?._id,\n\t\tfileName: message.file?.name,\n\t};\n};\n\ntype MessageData = Pick & {\n\tusername?: IUser['username'] | IUser['name'];\n\tattachments?: ReturnType[];\n\ttype?: IMessage['t'];\n};\n\nconst getMessageData = (\n\tmsg: IMessage,\n\thideUsers: boolean,\n\tuserData: Pick | undefined,\n\tusersMap: { userNameTable: Record },\n): MessageData => {\n\tconst username = hideUsers ? hideUserName(msg.u.username || msg.u.name, userData, usersMap) : msg.u.username;\n\n\tconst messageObject = {\n\t\tmsg: msg.msg,\n\t\tusername,\n\t\tts: msg.ts,\n\t\t...(msg.attachments && {\n\t\t\tattachments: msg.attachments.map((attachment) => getAttachmentData(attachment, msg)),\n\t\t}),\n\t\t...(msg.t && { type: msg.t }),\n\t};\n\n\tswitch (msg.t) {\n\t\tcase 'uj':\n\t\t\tmessageObject.msg = TAPi18n.__('User_joined_the_channel');\n\t\t\tbreak;\n\t\tcase 'ul':\n\t\t\tmessageObject.msg = TAPi18n.__('User_left_this_channel');\n\t\t\tbreak;\n\t\tcase 'ult':\n\t\t\tmessageObject.msg = TAPi18n.__('User_left_this_team');\n\t\t\tbreak;\n\t\tcase 'user-added-room-to-team':\n\t\t\tmessageObject.msg = TAPi18n.__('added__roomName__to_this_team', {\n\t\t\t\troomName: msg.msg,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'user-converted-to-team':\n\t\t\tmessageObject.msg = TAPi18n.__('Converted__roomName__to_a_team', {\n\t\t\t\troomName: msg.msg,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'user-converted-to-channel':\n\t\t\tmessageObject.msg = TAPi18n.__('Converted__roomName__to_a_channel', {\n\t\t\t\troomName: msg.msg,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'user-deleted-room-from-team':\n\t\t\tmessageObject.msg = TAPi18n.__('Deleted__roomName__room', {\n\t\t\t\troomName: msg.msg,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'user-removed-room-from-team':\n\t\t\tmessageObject.msg = TAPi18n.__('Removed__roomName__from_the_team', {\n\t\t\t\troomName: msg.msg,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'ujt':\n\t\t\tmessageObject.msg = TAPi18n.__('User_joined_the_team');\n\t\t\tbreak;\n\t\tcase 'au':\n\t\t\tmessageObject.msg = TAPi18n.__('User_added_to', {\n\t\t\t\tuser_added: hideUserName(msg.msg, userData, usersMap),\n\t\t\t\tuser_by: username,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'added-user-to-team':\n\t\t\tmessageObject.msg = TAPi18n.__('Added__username__to_this_team', {\n\t\t\t\tuser_added: msg.msg,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'r':\n\t\t\tmessageObject.msg = TAPi18n.__('Room_name_changed_to', {\n\t\t\t\troom_name: msg.msg,\n\t\t\t\tuser_by: username,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'ru':\n\t\t\tmessageObject.msg = TAPi18n.__('User_has_been_removed', {\n\t\t\t\tuser_removed: hideUserName(msg.msg, userData, usersMap),\n\t\t\t\tuser_by: username,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'removed-user-from-team':\n\t\t\tmessageObject.msg = TAPi18n.__('Removed__username__from_the_team', {\n\t\t\t\tuser_removed: hideUserName(msg.msg, userData, usersMap),\n\t\t\t});\n\t\t\tbreak;\n\t\tcase 'wm':\n\t\t\tmessageObject.msg = TAPi18n.__('Welcome', { user: username });\n\t\t\tbreak;\n\t\tcase 'livechat-close':\n\t\t\tmessageObject.msg = TAPi18n.__('Conversation_finished');\n\t\t\tbreak;\n\t\tcase 'livechat-started':\n\t\t\tmessageObject.msg = TAPi18n.__('Chat_started');\n\t\t\tbreak;\n\t}\n\n\treturn messageObject;\n};\n\nconst exportMessageObject = (type: 'json' | 'html', messageObject: MessageData, messageFile?: FileProp): string => {\n\tif (type === 'json') {\n\t\treturn JSON.stringify(messageObject);\n\t}\n\n\tconst file = [];\n\n\tconst messageType = messageObject.type;\n\tconst timestamp = messageObject.ts ? new Date(messageObject.ts).toUTCString() : '';\n\n\tconst italicTypes: IMessage['t'][] = ['uj', 'ul', 'au', 'r', 'ru', 'wm', 'livechat-close'];\n\n\tconst message = italicTypes.includes(messageType) ? `${messageObject.msg}` : messageObject.msg;\n\n\tfile.push(`

${messageObject.username} (${timestamp}):
`);\n\tfile.push(message);\n\n\tif (messageFile?._id) {\n\t\tconst attachment = messageObject.attachments?.find((att) => att.type === 'file' && att.title_link?.includes(messageFile._id));\n\n\t\tconst description = attachment?.title || TAPi18n.__('Message_Attachments');\n\n\t\tconst assetUrl = `./assets/${messageFile._id}-${messageFile.name}`;\n\t\tconst link = `
${description}`;\n\t\tfile.push(link);\n\t}\n\n\tfile.push('

');\n\n\treturn file.join('\\n');\n};\n\nconst exportRoomMessages = async (\n\trid: IRoom['_id'],\n\texportType: 'json' | 'html',\n\tskip: number,\n\tlimit: number,\n\tuserData: any,\n\tfilter: any = {},\n\tusersMap: any = {},\n\thideUsers = true,\n) => {\n\tconst readPreference = readSecondaryPreferred(Messages.model.rawDatabase());\n\n\t// @ts-ignore Circular reference on field 'attachments'\n\tconst { cursor, totalCount } = MessagesRaw.findPaginated(\n\t\t{ ...filter, rid },\n\t\t{\n\t\t\tsort: { ts: 1 },\n\t\t\tskip,\n\t\t\tlimit,\n\t\t\treadPreference,\n\t\t},\n\t);\n\n\tconst [results, total] = await Promise.all([cursor.toArray(), totalCount]);\n\n\tconst result = {\n\t\ttotal,\n\t\texported: results.length,\n\t\tmessages: [] as string[],\n\t\tuploads: [] as FileProp[],\n\t};\n\n\tresults.forEach(\n\t\tMeteor.bindEnvironment((msg) => {\n\t\t\tconst messageObject = getMessageData(msg, hideUsers, userData, usersMap);\n\n\t\t\tif (msg.file) {\n\t\t\t\tresult.uploads.push(msg.file);\n\t\t\t}\n\n\t\t\tresult.messages.push(exportMessageObject(exportType, messageObject, msg.file));\n\t\t}),\n\t);\n\n\treturn result;\n};\n\nexport const exportRoomMessagesToFile = async function (\n\texportPath: string,\n\tassetsPath: string,\n\texportType: 'json' | 'html',\n\troomList: (\n\t\t| {\n\t\t\t\troomId: string;\n\t\t\t\troomName: string;\n\t\t\t\tuserId: string | undefined;\n\t\t\t\texportedCount: number;\n\t\t\t\tstatus: string;\n\t\t\t\ttype: RoomType;\n\t\t\t\ttargetFile: string;\n\t\t }\n\t\t| Record\n\t)[],\n\tuserData: IUser,\n\tmessagesFilter = {},\n\tusersMap = {},\n\thideUsers = true,\n) {\n\tawait mkdir(exportPath, { recursive: true });\n\tawait mkdir(assetsPath, { recursive: true });\n\n\tconst result = {\n\t\tfileList: [] as FileProp[],\n\t};\n\n\tconst limit =\n\t\tsettings.get('UserData_MessageLimitPerRequest') > 0 ? settings.get('UserData_MessageLimitPerRequest') : 1000;\n\tfor await (const exportOpRoomData of roomList) {\n\t\tif (!('targetFile' in exportOpRoomData)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst filePath = joinPath(exportPath, exportOpRoomData.targetFile);\n\t\tif (exportOpRoomData.status === 'pending') {\n\t\t\texportOpRoomData.status = 'exporting';\n\t\t\tif (exportType === 'html') {\n\t\t\t\tawait writeFile(filePath, '', { encoding: 'utf8' });\n\t\t\t}\n\t\t}\n\n\t\tconst skip = exportOpRoomData.exportedCount;\n\n\t\tconst { total, exported, uploads, messages } = await exportRoomMessages(\n\t\t\texportOpRoomData.roomId,\n\t\t\texportType,\n\t\t\tskip,\n\t\t\tlimit,\n\t\t\tuserData,\n\t\t\tmessagesFilter,\n\t\t\tusersMap,\n\t\t\thideUsers,\n\t\t);\n\n\t\tresult.fileList.push(...uploads);\n\n\t\texportOpRoomData.exportedCount += exported;\n\n\t\tif (total <= exportOpRoomData.exportedCount) {\n\t\t\texportOpRoomData.status = 'completed';\n\t\t}\n\n\t\tawait writeFile(filePath, `${messages.join('\\n')}\\n`, { encoding: 'utf8', flag: 'a' });\n\t}\n\n\treturn result;\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/getPath.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/getRoomData.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/makeZipFile.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/processDataDownloads.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/sendEmail.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/sendFile.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/sendViaEmail.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/dataExport/uploadZipFile.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/fileUtils.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/findUsersOfRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/getClientAddress.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/getMomentLocale.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/http/call.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/http/fetch.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/isPresenceMonitorEnabled.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/isRunningMs.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/isUserIdFederated.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/ldap/Connection.ts",["23196"],["23197"],"import ldapjs from 'ldapjs';\nimport type {\n\tILDAPConnectionOptions,\n\tLDAPEncryptionType,\n\tLDAPSearchScope,\n\tILDAPEntry,\n\tILDAPCallback,\n\tILDAPPageCallback,\n} from '@rocket.chat/core-typings';\n\nimport { settings } from '../../../app/settings/server';\nimport { logger, connLogger, searchLogger, authLogger, bindLogger, mapLogger } from './Logger';\nimport { getLDAPConditionalSetting } from './getLDAPConditionalSetting';\n\ninterface ILDAPEntryCallback {\n\t(entry: ldapjs.SearchEntry): T | undefined;\n}\n\ninterface ILDAPSearchEndCallback {\n\t(error?: any): void;\n}\n\ninterface ILDAPSearchPageCallback {\n\t(result: ldapjs.SearchEntry[]): void;\n}\n\ninterface ILDAPSearchAllCallbacks {\n\tdataCallback?: ILDAPSearchPageCallback;\n\tendCallback?: ILDAPSearchEndCallback;\n\tentryCallback?: ILDAPEntryCallback;\n}\n\ntype ILDAPExtractedValue = string | Array;\n\nexport class LDAPConnection {\n\tpublic ldapjs: any;\n\n\tpublic connected: boolean;\n\n\tpublic options: ILDAPConnectionOptions;\n\n\tpublic client: ldapjs.Client;\n\n\tprivate _receivedResponse: boolean;\n\n\tprivate _connectionTimedOut: boolean;\n\n\tprivate _connectionCallback: ILDAPCallback;\n\n\tprivate usingAuthentication: boolean;\n\n\tconstructor() {\n\t\tthis.ldapjs = ldapjs;\n\n\t\tthis.connected = false;\n\t\tthis._receivedResponse = false;\n\t\tthis._connectionTimedOut = false;\n\n\t\tthis.options = {\n\t\t\thost: settings.get('LDAP_Host') ?? '',\n\t\t\tport: settings.get('LDAP_Port') ?? 389,\n\t\t\treconnect: settings.get('LDAP_Reconnect') ?? false,\n\t\t\ttimeout: settings.get('LDAP_Timeout') ?? 60000,\n\t\t\tconnectionTimeout: settings.get('LDAP_Connect_Timeout') ?? 1000,\n\t\t\tidleTimeout: settings.get('LDAP_Idle_Timeout') ?? 1000,\n\t\t\tencryption: settings.get('LDAP_Encryption') ?? 'plain',\n\t\t\tcaCert: settings.get('LDAP_CA_Cert'),\n\t\t\trejectUnauthorized: settings.get('LDAP_Reject_Unauthorized') || false,\n\t\t\tbaseDN: settings.get('LDAP_BaseDN') ?? '',\n\t\t\tuserSearchFilter: settings.get('LDAP_User_Search_Filter') ?? '',\n\t\t\tuserSearchScope: settings.get('LDAP_User_Search_Scope') ?? 'sub',\n\t\t\tuserSearchField: getLDAPConditionalSetting('LDAP_User_Search_Field') ?? '',\n\t\t\tsearchPageSize: settings.get('LDAP_Search_Page_Size') ?? 250,\n\t\t\tsearchSizeLimit: settings.get('LDAP_Search_Size_Limit') ?? 1000,\n\t\t\tuniqueIdentifierField: settings.get('LDAP_Unique_Identifier_Field'),\n\t\t\tgroupFilterEnabled: settings.get('LDAP_Group_Filter_Enable') ?? false,\n\t\t\tgroupFilterObjectClass: settings.get('LDAP_Group_Filter_ObjectClass'),\n\t\t\tgroupFilterGroupIdAttribute: settings.get('LDAP_Group_Filter_Group_Id_Attribute'),\n\t\t\tgroupFilterGroupMemberAttribute: settings.get('LDAP_Group_Filter_Group_Member_Attribute'),\n\t\t\tgroupFilterGroupMemberFormat: settings.get('LDAP_Group_Filter_Group_Member_Format'),\n\t\t\tgroupFilterGroupName: settings.get('LDAP_Group_Filter_Group_Name'),\n\t\t\tauthentication: settings.get('LDAP_Authentication') ?? false,\n\t\t\tauthenticationUserDN: settings.get('LDAP_Authentication_UserDN') ?? '',\n\t\t\tauthenticationPassword: settings.get('LDAP_Authentication_Password') ?? '',\n\t\t\tattributesToQuery: this.parseAttributeList(settings.get('LDAP_User_Search_AttributesToQuery')),\n\t\t};\n\n\t\tif (!this.options.host) {\n\t\t\tlogger.warn('LDAP Host is not configured.');\n\t\t}\n\t\tif (!this.options.baseDN) {\n\t\t\tlogger.warn('LDAP Search BaseDN is not configured.');\n\t\t}\n\t}\n\n\tpublic async connect(): Promise {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.initializeConnection((error, result) => {\n\t\t\t\tif (error) {\n\t\t\t\t\treturn reject(error);\n\t\t\t\t}\n\n\t\t\t\treturn resolve(result);\n\t\t\t});\n\t\t});\n\t}\n\n\tpublic disconnect(): void {\n\t\tthis.usingAuthentication = false;\n\t\tthis.connected = false;\n\t\tconnLogger.info('Disconnecting');\n\n\t\tif (this.client) {\n\t\t\tthis.client.unbind();\n\t\t}\n\t}\n\n\tpublic async testConnection(): Promise {\n\t\ttry {\n\t\t\tawait this.connect();\n\t\t\tawait this.maybeBindDN();\n\t\t} finally {\n\t\t\tthis.disconnect();\n\t\t}\n\t}\n\n\tpublic async searchByUsername(escapedUsername: string): Promise {\n\t\tconst searchOptions: ldapjs.SearchOptions = {\n\t\t\tfilter: this.getUserFilter(escapedUsername),\n\t\t\tscope: this.options.userSearchScope || 'sub',\n\t\t\tsizeLimit: this.options.searchSizeLimit,\n\t\t\tattributes: this.options.attributesToQuery,\n\t\t};\n\n\t\tif (this.options.searchPageSize > 0) {\n\t\t\tsearchOptions.paged = {\n\t\t\t\tpageSize: this.options.searchPageSize,\n\t\t\t\tpagePause: false,\n\t\t\t};\n\t\t}\n\n\t\tsearchLogger.info({\n\t\t\tmsg: 'Searching by username',\n\t\t\tusername: escapedUsername,\n\t\t\tbaseDN: this.options.baseDN,\n\t\t\tsearchOptions,\n\t\t});\n\t\treturn this.search(this.options.baseDN, searchOptions);\n\t}\n\n\tpublic async findOneByUsername(username: string): Promise {\n\t\tconst results = await this.searchByUsername(username);\n\n\t\tif (results.length === 1) {\n\t\t\treturn results[0];\n\t\t}\n\t}\n\n\tpublic async searchById(id: string, attribute?: string): Promise {\n\t\tconst searchOptions: ldapjs.SearchOptions = {\n\t\t\tscope: this.options.userSearchScope || 'sub',\n\t\t\tattributes: this.options.attributesToQuery,\n\t\t};\n\n\t\tif (attribute) {\n\t\t\tsearchOptions.filter = new this.ldapjs.filters.EqualityFilter({\n\t\t\t\tattribute,\n\t\t\t\tvalue: Buffer.from(id, 'hex'),\n\t\t\t});\n\t\t} else if (this.options.uniqueIdentifierField) {\n\t\t\t// If we don't know what attribute the id came from, we have to look for all of them.\n\t\t\tconst possibleFields = this.options.uniqueIdentifierField.split(',').concat(this.options.userSearchField.split(','));\n\t\t\tconst filters = [];\n\t\t\tfor (const field of possibleFields) {\n\t\t\t\tif (!field) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tfilters.push(\n\t\t\t\t\tnew this.ldapjs.filters.EqualityFilter({\n\t\t\t\t\t\tattribute: field,\n\t\t\t\t\t\tvalue: Buffer.from(id, 'hex'),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tsearchOptions.filter = new this.ldapjs.filters.OrFilter({ filters });\n\t\t} else {\n\t\t\tthrow new Error('Unique Identifier Field is not configured.');\n\t\t}\n\n\t\tsearchLogger.info({ msg: 'Searching by id', id });\n\t\tsearchLogger.debug({ msg: 'search filter', searchOptions, baseDN: this.options.baseDN });\n\n\t\treturn this.search(this.options.baseDN, searchOptions);\n\t}\n\n\tpublic async findOneById(id: string, attribute?: string): Promise {\n\t\tconst results = await this.searchById(id, attribute);\n\t\tif (results.length === 1) {\n\t\t\treturn results[0];\n\t\t}\n\t}\n\n\tpublic async searchAllUsers({\n\t\tdataCallback,\n\t\tendCallback,\n\t\tentryCallback,\n\t}: ILDAPSearchAllCallbacks): Promise {\n\t\tsearchLogger.info('Searching all users');\n\n\t\tconst searchOptions: ldapjs.SearchOptions = {\n\t\t\tfilter: this.getUserFilter('*'),\n\t\t\tscope: this.options.userSearchScope || 'sub',\n\t\t\tsizeLimit: this.options.searchSizeLimit,\n\t\t\tattributes: this.options.attributesToQuery,\n\t\t};\n\n\t\tif (this.options.searchPageSize > 0) {\n\t\t\tlet count = 0;\n\t\t\tawait this.doPagedSearch(\n\t\t\t\tthis.options.baseDN,\n\t\t\t\tsearchOptions,\n\t\t\t\tthis.options.searchPageSize,\n\t\t\t\t(error, entries: ldapjs.SearchEntry[], { end, next } = { end: false, next: undefined }) => {\n\t\t\t\t\tif (error) {\n\t\t\t\t\t\tendCallback?.(error);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tcount += entries.length;\n\t\t\t\t\tdataCallback?.(entries);\n\t\t\t\t\tif (end) {\n\t\t\t\t\t\tendCallback?.();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (next) {\n\t\t\t\t\t\tnext(count);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tentryCallback,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.doAsyncSearch(\n\t\t\tthis.options.baseDN,\n\t\t\tsearchOptions,\n\t\t\t(error, result) => {\n\t\t\t\tdataCallback?.(result);\n\t\t\t\tendCallback?.(error);\n\t\t\t},\n\t\t\tentryCallback,\n\t\t);\n\t}\n\n\tpublic async authenticate(dn: string, password: string): Promise {\n\t\tauthLogger.info({ msg: 'Authenticating', dn });\n\n\t\ttry {\n\t\t\tawait this.bindDN(dn, password);\n\n\t\t\tauthLogger.info({ msg: 'Authenticated', dn });\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tauthLogger.info({ msg: 'Not authenticated', dn });\n\t\t\tauthLogger.debug({ msg: 'error', error });\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic async search(baseDN: string, searchOptions: ldapjs.SearchOptions): Promise {\n\t\treturn this.doCustomSearch(baseDN, searchOptions, (entry) => this.extractLdapEntryData(entry));\n\t}\n\n\tpublic async searchRaw(baseDN: string, searchOptions: ldapjs.SearchOptions): Promise {\n\t\treturn this.doCustomSearch(baseDN, searchOptions, (entry) => entry);\n\t}\n\n\tpublic async searchAndCount(baseDN: string, searchOptions: ldapjs.SearchOptions): Promise {\n\t\tlet count = 0;\n\t\tawait this.doCustomSearch(baseDN, searchOptions, () => {\n\t\t\tcount++;\n\t\t});\n\n\t\treturn count;\n\t}\n\n\tpublic extractLdapAttribute(value: Buffer | Buffer[] | string): ILDAPExtractedValue {\n\t\tif (Array.isArray(value)) {\n\t\t\treturn value.map((item) => this.extractLdapAttribute(item));\n\t\t}\n\n\t\tif (value instanceof Buffer) {\n\t\t\treturn value.toString();\n\t\t}\n\n\t\treturn value;\n\t}\n\n\tpublic extractLdapEntryData(entry: ldapjs.SearchEntry): ILDAPEntry {\n\t\tconst values: ILDAPEntry = {\n\t\t\t_raw: entry.raw,\n\t\t};\n\n\t\tObject.keys(values._raw).forEach((key) => {\n\t\t\tvalues[key] = this.extractLdapAttribute(values._raw[key]);\n\n\t\t\tconst dataType = typeof values[key];\n\t\t\t// eslint-disable-next-line no-control-regex\n\t\t\tif (dataType === 'string' && values[key].length > 100 && /[\\x00-\\x1F]/.test(values[key])) {\n\t\t\t\tmapLogger.debug({\n\t\t\t\t\tmsg: 'Extracted Attribute',\n\t\t\t\t\tkey,\n\t\t\t\t\ttype: dataType,\n\t\t\t\t\tlength: values[key].length,\n\t\t\t\t\tvalue: `${values[key].substr(0, 100)}...`,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmapLogger.debug({ msg: 'Extracted Attribute', key, type: dataType, value: values[key] });\n\t\t});\n\n\t\treturn values;\n\t}\n\n\tpublic async doCustomSearch(baseDN: string, searchOptions: ldapjs.SearchOptions, entryCallback: ILDAPEntryCallback): Promise {\n\t\tawait this.runBeforeSearch(searchOptions);\n\n\t\tif (!searchOptions.scope) {\n\t\t\tsearchOptions.scope = this.options.userSearchScope || 'sub';\n\t\t}\n\t\tsearchLogger.debug({ msg: 'searchOptions', searchOptions, baseDN });\n\n\t\tlet realEntries = 0;\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.client.search(baseDN, searchOptions, (error, res: ldapjs.SearchCallbackResponse) => {\n\t\t\t\tif (error) {\n\t\t\t\t\tsearchLogger.error(error);\n\t\t\t\t\treject(error);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tres.on('error', (error) => {\n\t\t\t\t\tsearchLogger.error(error);\n\t\t\t\t\treject(error);\n\t\t\t\t});\n\n\t\t\t\tconst entries: T[] = [];\n\n\t\t\t\tres.on('searchEntry', (entry) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst result = entryCallback(entry);\n\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\tentries.push(result as T);\n\t\t\t\t\t\t}\n\t\t\t\t\t\trealEntries++;\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tsearchLogger.error(e);\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tres.on('end', () => {\n\t\t\t\t\tsearchLogger.info(`LDAP Search found ${realEntries} entries and loaded the data of ${entries.length}.`);\n\t\t\t\t\tresolve(entries);\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t}\n\n\t/*\n\t\tCreate an LDAP search filter based on the username\n\t*/\n\tpublic getUserFilter(username: string): string {\n\t\tconst filter: string[] = [];\n\n\t\tthis.addUserFilters(filter, username);\n\n\t\tconst usernameFilter = this.options.userSearchField.split(',').map((item) => `(${item}=${username})`);\n\n\t\tif (usernameFilter.length === 0) {\n\t\t\tlogger.error('LDAP_LDAP_User_Search_Field not defined');\n\t\t} else if (usernameFilter.length === 1) {\n\t\t\tfilter.push(`${usernameFilter[0]}`);\n\t\t} else {\n\t\t\tfilter.push(`(|${usernameFilter.join('')})`);\n\t\t}\n\n\t\treturn `(&${filter.join('')})`;\n\t}\n\n\tpublic async isUserAcceptedByGroupFilter(username: string, userdn: string): Promise {\n\t\tif (!this.options.groupFilterEnabled) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst filter = ['(&'];\n\n\t\tif (this.options.groupFilterObjectClass) {\n\t\t\tfilter.push(`(objectclass=${this.options.groupFilterObjectClass})`);\n\t\t}\n\n\t\tif (this.options.groupFilterGroupMemberAttribute) {\n\t\t\tfilter.push(`(${this.options.groupFilterGroupMemberAttribute}=${this.options.groupFilterGroupMemberFormat})`);\n\t\t}\n\n\t\tif (this.options.groupFilterGroupIdAttribute) {\n\t\t\tfilter.push(`(${this.options.groupFilterGroupIdAttribute}=${this.options.groupFilterGroupName})`);\n\t\t}\n\t\tfilter.push(')');\n\n\t\tconst searchOptions: ldapjs.SearchOptions = {\n\t\t\tfilter: filter\n\t\t\t\t.join('')\n\t\t\t\t.replace(/#{username}/g, username)\n\t\t\t\t.replace(/#{userdn}/g, userdn),\n\t\t\tscope: 'sub',\n\t\t};\n\n\t\tsearchLogger.debug({ msg: 'Group filter LDAP:', filter: searchOptions.filter });\n\n\t\tconst result = await this.searchRaw(this.options.baseDN, searchOptions);\n\n\t\tif (!Array.isArray(result) || result.length === 0) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprotected addUserFilters(filters: string[], _username: string): void {\n\t\tconst { userSearchFilter } = this.options;\n\n\t\tif (userSearchFilter !== '') {\n\t\t\tif (userSearchFilter[0] === '(') {\n\t\t\t\tfilters.push(`${userSearchFilter}`);\n\t\t\t} else {\n\t\t\t\tfilters.push(`(${userSearchFilter})`);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic async bindDN(dn: string, password: string): Promise {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\tthis.client.bind(dn, password, (error) => {\n\t\t\t\t\tif (error) {\n\t\t\t\t\t\treturn reject(error);\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve();\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\treject(error);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate async doAsyncSearch(\n\t\tbaseDN: string,\n\t\tsearchOptions: ldapjs.SearchOptions,\n\t\tcallback: ILDAPCallback,\n\t\tentryCallback?: ILDAPEntryCallback,\n\t): Promise {\n\t\tawait this.runBeforeSearch(searchOptions);\n\n\t\tsearchLogger.debug({ msg: 'searchOptions', searchOptions, baseDN });\n\n\t\tthis.client.search(baseDN, searchOptions, (error: ldapjs.Error | null, res: ldapjs.SearchCallbackResponse): void => {\n\t\t\tif (error) {\n\t\t\t\tsearchLogger.error(error);\n\t\t\t\tcallback(error);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tres.on('error', (error) => {\n\t\t\t\tsearchLogger.error(error);\n\t\t\t\tcallback(error);\n\t\t\t});\n\n\t\t\tconst entries: T[] = [];\n\n\t\t\tres.on('searchEntry', (entry) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = entryCallback ? entryCallback(entry) : entry;\n\t\t\t\t\tentries.push(result as T);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tsearchLogger.error(e);\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tres.on('end', () => {\n\t\t\t\tsearchLogger.info({ msg: 'Search result count', count: entries.length });\n\t\t\t\tcallback(null, entries);\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate processSearchPage(\n\t\t{ entries, title, end, next }: { entries: T[]; title: string; end: boolean; next?: () => void },\n\t\tcallback: ILDAPPageCallback,\n\t): void {\n\t\tsearchLogger.info(title);\n\t\t// Force LDAP idle to wait the record processing\n\t\tthis._updateIdle(true);\n\n\t\tcallback(null, entries, {\n\t\t\tend,\n\t\t\tnext: () => {\n\t\t\t\t// Reset idle timer\n\t\t\t\tthis._updateIdle();\n\t\t\t\tnext?.();\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate async doPagedSearch(\n\t\tbaseDN: string,\n\t\tsearchOptions: ldapjs.SearchOptions,\n\t\tpageSize: number,\n\t\tcallback: ILDAPPageCallback,\n\t\tentryCallback?: ILDAPEntryCallback,\n\t): Promise {\n\t\tsearchOptions.paged = {\n\t\t\tpageSize,\n\t\t\tpagePause: true,\n\t\t};\n\n\t\tawait this.runBeforeSearch(searchOptions);\n\n\t\tsearchLogger.debug({ msg: 'searchOptions', searchOptions, baseDN });\n\n\t\tthis.client.search(baseDN, searchOptions, (error: ldapjs.Error | null, res: ldapjs.SearchCallbackResponse): void => {\n\t\t\tif (error) {\n\t\t\t\tsearchLogger.error(error);\n\t\t\t\tcallback(error);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tres.on('error', (error) => {\n\t\t\t\tsearchLogger.error(error);\n\t\t\t\tcallback(error);\n\t\t\t});\n\n\t\t\tlet entries: T[] = [];\n\t\t\tconst internalPageSize = pageSize * 2;\n\n\t\t\tres.on('searchEntry', (entry) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = entryCallback ? entryCallback(entry) : entry;\n\t\t\t\t\tentries.push(result as T);\n\n\t\t\t\t\tif (entries.length >= internalPageSize) {\n\t\t\t\t\t\tthis.processSearchPage(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tentries,\n\t\t\t\t\t\t\t\ttitle: 'Internal Page',\n\t\t\t\t\t\t\t\tend: false,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tcallback,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tentries = [];\n\t\t\t\t\t}\n\t\t\t\t} catch (e) {\n\t\t\t\t\tsearchLogger.error(e);\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tres.on('page', (_result, next) => {\n\t\t\t\tif (!next) {\n\t\t\t\t\tthis._updateIdle(true);\n\t\t\t\t\tthis.processSearchPage(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tentries,\n\t\t\t\t\t\t\ttitle: 'Final Page',\n\t\t\t\t\t\t\tend: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tcallback,\n\t\t\t\t\t);\n\t\t\t\t\tentries = [];\n\t\t\t\t} else if (entries.length) {\n\t\t\t\t\tthis.processSearchPage(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tentries,\n\t\t\t\t\t\t\ttitle: 'Page',\n\t\t\t\t\t\t\tend: false,\n\t\t\t\t\t\t\tnext,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tcallback,\n\t\t\t\t\t);\n\t\t\t\t\tentries = [];\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tres.on('end', () => {\n\t\t\t\tif (entries.length) {\n\t\t\t\t\tthis.processSearchPage(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tentries,\n\t\t\t\t\t\t\ttitle: 'Final Page',\n\t\t\t\t\t\t\tend: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tcallback,\n\t\t\t\t\t);\n\t\t\t\t\tentries = [];\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _updateIdle(override?: boolean): void {\n\t\t// @ts-ignore calling a private method\n\t\tthis.client._updateIdle(override);\n\t}\n\n\tprotected async maybeBindDN(): Promise {\n\t\tif (this.usingAuthentication) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.options.authentication) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.options.authenticationUserDN) {\n\t\t\tlogger.error('Invalid UserDN for authentication');\n\t\t\treturn;\n\t\t}\n\n\t\tbindLogger.info({ msg: 'Binding UserDN', userDN: this.options.authenticationUserDN });\n\t\ttry {\n\t\t\tawait this.bindDN(this.options.authenticationUserDN, this.options.authenticationPassword);\n\t\t\tthis.usingAuthentication = true;\n\t\t} catch (error) {\n\t\t\tauthLogger.error({\n\t\t\t\tmsg: 'Base Authentication Issue',\n\t\t\t\terr: error,\n\t\t\t\tdn: this.options.authenticationUserDN,\n\t\t\t});\n\t\t\tthis.usingAuthentication = false;\n\t\t}\n\t}\n\n\tprotected async runBeforeSearch(_searchOptions: ldapjs.SearchOptions): Promise {\n\t\treturn this.maybeBindDN();\n\t}\n\n\t/*\n\t\tGet list of options to initialize a new ldapjs Client\n\t*/\n\tprivate getClientOptions(): {\n\t\tclientOptions: ldapjs.ClientOptions;\n\t\ttlsOptions: Record;\n\t} {\n\t\tconst clientOptions: ldapjs.ClientOptions = {\n\t\t\turl: `${this.options.host}:${this.options.port}`,\n\t\t\ttimeout: this.options.timeout,\n\t\t\tconnectTimeout: this.options.connectionTimeout,\n\t\t\tidleTimeout: this.options.idleTimeout,\n\t\t\treconnect: this.options.reconnect,\n\t\t\tlog: connLogger,\n\t\t};\n\n\t\tconst tlsOptions: Record = {\n\t\t\trejectUnauthorized: this.options.rejectUnauthorized,\n\t\t};\n\n\t\tif (this.options.caCert) {\n\t\t\t// Split CA cert into array of strings\n\t\t\tconst chainLines = this.options.caCert.split('\\n');\n\t\t\tlet cert: string[] = [];\n\t\t\tconst ca: string[] = [];\n\t\t\tchainLines.forEach((line) => {\n\t\t\t\tcert.push(line);\n\t\t\t\tif (line.match(/-END CERTIFICATE-/)) {\n\t\t\t\t\tca.push(cert.join('\\n'));\n\t\t\t\t\tcert = [];\n\t\t\t\t}\n\t\t\t});\n\t\t\ttlsOptions.ca = ca;\n\t\t}\n\n\t\tif (this.options.encryption === 'ssl') {\n\t\t\tclientOptions.url = `ldaps://${clientOptions.url}`;\n\t\t\tclientOptions.tlsOptions = tlsOptions;\n\t\t} else {\n\t\t\tclientOptions.url = `ldap://${clientOptions.url}`;\n\t\t}\n\n\t\treturn {\n\t\t\tclientOptions,\n\t\t\ttlsOptions,\n\t\t};\n\t}\n\n\tprivate handleConnectionResponse(error: any, response?: any): void {\n\t\tif (!this._receivedResponse) {\n\t\t\tthis._receivedResponse = true;\n\t\t\tthis._connectionCallback(error, response);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._connectionTimedOut && !error) {\n\t\t\tconnLogger.info('Received a response after the connection timedout.');\n\t\t} else {\n\t\t\tlogger.debug('Ignored error/response:');\n\t\t}\n\n\t\tif (error) {\n\t\t\tconnLogger.debug(error);\n\t\t} else {\n\t\t\tconnLogger.debug(response);\n\t\t}\n\t}\n\n\tprivate initializeConnection(callback: ILDAPCallback): void {\n\t\tconnLogger.info('Init Setup');\n\t\tthis._receivedResponse = false;\n\t\tthis._connectionTimedOut = false;\n\t\tthis._connectionCallback = callback;\n\n\t\tconst { clientOptions, tlsOptions } = this.getClientOptions();\n\t\tconnLogger.info({ msg: 'Connecting', url: clientOptions.url });\n\t\tconnLogger.debug({ msg: 'clientOptions', clientOptions });\n\n\t\tthis.client = ldapjs.createClient(clientOptions);\n\n\t\tthis.client.on('error', (error) => {\n\t\t\tconnLogger.error(error);\n\t\t\tthis.handleConnectionResponse(error, null);\n\t\t});\n\n\t\tthis.client.on('idle', () => {\n\t\t\tsearchLogger.info('Idle');\n\t\t\tthis.disconnect();\n\t\t});\n\n\t\tthis.client.on('close', () => {\n\t\t\tsearchLogger.info('Closed');\n\t\t});\n\n\t\tif (this.options.encryption === 'tls') {\n\t\t\t// Set host parameter for tls.connect which is used by ldapjs starttls. This may not be needed anymore\n\t\t\t// https://github.com/RocketChat/Rocket.Chat/issues/2035\n\t\t\t// https://github.com/mcavage/node-ldapjs/issues/349\n\t\t\ttlsOptions.host = this.options.host;\n\n\t\t\tconnLogger.info('Starting TLS');\n\t\t\tconnLogger.debug({ msg: 'tlsOptions', tlsOptions });\n\n\t\t\tthis.client.starttls(tlsOptions, null, (error, response) => {\n\t\t\t\tif (error) {\n\t\t\t\t\tconnLogger.error({ msg: 'TLS connection', error });\n\t\t\t\t\treturn this.handleConnectionResponse(error, null);\n\t\t\t\t}\n\n\t\t\t\tconnLogger.info('TLS connected');\n\t\t\t\tthis.connected = true;\n\t\t\t\tthis.handleConnectionResponse(null, response);\n\t\t\t});\n\t\t} else {\n\t\t\tthis.client.on('connect', (response) => {\n\t\t\t\tconnLogger.info('LDAP connected');\n\t\t\t\tthis.connected = true;\n\t\t\t\tthis.handleConnectionResponse(null, response);\n\t\t\t});\n\t\t}\n\n\t\tsetTimeout(() => {\n\t\t\tif (!this._receivedResponse) {\n\t\t\t\tconnLogger.error({ msg: 'connection time out', timeout: clientOptions.connectTimeout });\n\t\t\t\tthis.handleConnectionResponse(new Error('Timeout'));\n\t\t\t\tthis._connectionTimedOut = true;\n\t\t\t}\n\t\t}, clientOptions.connectTimeout);\n\t}\n\n\tprivate parseAttributeList(csv: string | undefined): Array {\n\t\tif (!csv) {\n\t\t\treturn ['*', '+'];\n\t\t}\n\n\t\tconst list = csv.split(',').map((item) => item.trim());\n\t\tif (!list?.length) {\n\t\t\treturn ['*', '+'];\n\t\t}\n\n\t\treturn list;\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/ldap/DataConverter.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/ldap/Logger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/ldap/Manager.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/ldap/getLDAPConditionalSetting.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/Logger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/getPino.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/logLevel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/logPayloads.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/logQueue.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/showBox.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/logger/system.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/messages/getMessageForUser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/migrations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/pushConfig.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/readMessages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/resetUserE2EKey.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/roles/addUserRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/roles/createOrUpdateProtectedRole.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/roles/getRoomRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/roles/removeUserFromRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/roles/validateRoleList.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomCoordinator.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/conversation.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/direct.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/favorite.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/livechat.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/private.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/public.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/unread.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/rooms/roomTypes/voip.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/sendDirectMessageToUsers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/sendMessagesToAdmins.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/settingsRegenerator.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/spotlight.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/statistics/getSettingsStatistics.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/videoConfProviders.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/lib/videoConfTypes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/main.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/OEmbedCacheCleanup.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/addAllUserToRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/addRoomLeader.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/addRoomModerator.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/addRoomOwner.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/afterVerifyEmail.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/browseChannels.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/canAccessRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/channelsList.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/createDirectMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/deleteFileMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/deleteUser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/eraseRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getAvatarSuggestion.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getPasswordPolicy.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getRoomById.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getRoomIdByNameOrId.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getRoomNameById.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getSetupWizardParameters.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getTotalChannels.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/getUsersOfRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/hideRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/ignoreUser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/loadHistory.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/loadLocale.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/loadMissedMessages.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/loadNextMessages.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/loadSurroundingMessages.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/logoutCleanUp.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/messageSearch.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/muteUserInRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/openRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/readMessages.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/readThreads.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/registerUser.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/removeRoomLeader.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/removeRoomModerator.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/removeRoomOwner.ts",["23198"],[],"import { Meteor } from 'meteor/meteor';\nimport { check } from 'meteor/check';\nimport { api, Team } from '@rocket.chat/core-services';\nimport { isRoomFederated } from '@rocket.chat/core-typings';\n\nimport { hasPermission, getUsersInRole } from '../../app/authorization/server';\nimport { Users, Subscriptions, Messages, Rooms } from '../../app/models/server';\nimport { settings } from '../../app/settings/server';\n\nMeteor.methods({\n\tasync removeRoomOwner(rid, userId) {\n\t\tcheck(rid, String);\n\t\tcheck(userId, String);\n\n\t\tconst uid = Meteor.userId();\n\n\t\tif (!uid) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tmethod: 'removeRoomOwner',\n\t\t\t});\n\t\t}\n\n\t\tconst room = Rooms.findOneById(rid, { fields: { t: 1, federated: 1 } });\n\t\tif (!hasPermission(uid, 'set-owner', rid) && !isRoomFederated(room)) {\n\t\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', {\n\t\t\t\tmethod: 'removeRoomOwner',\n\t\t\t});\n\t\t}\n\n\t\tconst user = Users.findOneById(userId);\n\t\tif (!user || !user.username) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\t\tmethod: 'removeRoomOwner',\n\t\t\t});\n\t\t}\n\n\t\tconst subscription = Subscriptions.findOneByRoomIdAndUserId(rid, user._id);\n\n\t\tif (!subscription) {\n\t\t\tthrow new Meteor.Error('error-invalid-room', 'Invalid room', {\n\t\t\t\tmethod: 'removeRoomOwner',\n\t\t\t});\n\t\t}\n\n\t\tif (Array.isArray(subscription.roles) === false || subscription.roles.includes('owner') === false) {\n\t\t\tthrow new Meteor.Error('error-user-not-owner', 'User is not an owner', {\n\t\t\t\tmethod: 'removeRoomOwner',\n\t\t\t});\n\t\t}\n\n\t\tconst numOwners = await (await getUsersInRole('owner', rid)).count();\n\n\t\tif (numOwners === 1) {\n\t\t\tthrow new Meteor.Error('error-remove-last-owner', 'This is the last owner. Please set a new owner before removing this one.', {\n\t\t\t\tmethod: 'removeRoomOwner',\n\t\t\t});\n\t\t}\n\n\t\tSubscriptions.removeRoleById(subscription._id, 'owner');\n\n\t\tconst fromUser = Users.findOneById(uid);\n\n\t\tMessages.createSubscriptionRoleRemovedWithRoomIdAndUser(rid, user, {\n\t\t\tu: {\n\t\t\t\t_id: fromUser._id,\n\t\t\t\tusername: fromUser.username,\n\t\t\t},\n\t\t\trole: 'owner',\n\t\t});\n\n\t\tconst team = await Team.getOneByMainRoomId(rid);\n\t\tif (team) {\n\t\t\tawait Team.removeRolesFromMember(team._id, userId, ['owner']);\n\t\t}\n\n\t\tconst event = {\n\t\t\ttype: 'removed',\n\t\t\t_id: 'owner',\n\t\t\tu: {\n\t\t\t\t_id: user._id,\n\t\t\t\tusername: user.username,\n\t\t\t\tname: user.name,\n\t\t\t},\n\t\t\tscope: rid,\n\t\t};\n\t\tif (settings.get('UI_DisplayRoles')) {\n\t\t\tapi.broadcast('user.roleUpdate', event);\n\t\t}\n\t\tapi.broadcast('federation.userRoleChanged', { ...event, givenByUserId: uid });\n\t\treturn true;\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/removeUserFromRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/reportMessage.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/requestDataDownload.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/resetAvatar.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/roomNameExists.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/saveUserPreferences.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/saveUserProfile.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/sendConfirmationEmail.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/sendForgotPasswordEmail.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/setAvatarFromService.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/setUserActiveStatus.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/setUserPassword.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/toogleFavorite.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/unmuteUserInRoom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/userPresence.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/methods/userSetUtcOffset.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Analytics.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Avatars.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Banners.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/BannersDismiss.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/CredentialTokens.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/CustomSounds.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/CustomUserStatus.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/EmailInbox.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/EmailMessageHistory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/EmojiCustom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/ExportOperations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/FederationKeys.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/FederationServers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/ImportData.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/InstanceStatus.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/IntegrationHistory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Integrations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Invites.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatAgentActivity.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatBusinessHours.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatCustomField.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatDepartment.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatDepartmentAgents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatInquiry.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatRooms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatTrigger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LivechatVisitors.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/LoginServiceConfiguration.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/MatrixBridgedRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/MatrixBridgedUser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/MessageReads.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Messages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/NotificationQueue.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Nps.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/NpsVote.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/OAuthApps.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/OEmbedCache.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/PbxEvents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Permissions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/PushToken.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Reports.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Roles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Rooms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/ServerEvents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Sessions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/SmarshHistory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Statistics.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Subscriptions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Team.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/TeamMember.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Uploads.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/UserDataFiles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/Users.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/UsersSessions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/VideoConference.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/VoipRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/WebdavAccounts.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Analytics.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Avatars.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Banners.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/BannersDismiss.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/BaseRaw.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/CredentialTokens.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/CustomSounds.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/CustomUserStatus.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/EmailInbox.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/EmailMessageHistory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/EmojiCustom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/ExportOperations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/FederationKeys.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/FederationServers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/ImportData.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/InstanceStatus.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/IntegrationHistory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Integrations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Invites.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatAgentActivity.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatBusinessHours.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatCustomField.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatDepartment.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatDepartmentAgents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatInquiry.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatRooms.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatTrigger.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LivechatVisitors.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/LoginServiceConfiguration.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/MatrixBridgedRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/MatrixBridgedUser.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/MessageReads.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Messages.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/NotificationQueue.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Nps.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/NpsVote.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/OAuthApps.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/OEmbedCache.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/PbxEvents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Permissions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/PushToken.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Reports.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Roles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Rooms.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/ServerEvents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Sessions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Settings.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/SmarshHistory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Statistics.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Subscriptions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Team.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/TeamMember.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Uploads.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/UserDataFiles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/Users.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/UsersSessions.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/VideoConference.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/VoipRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/raw/WebdavAccounts.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/models/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/core-apps/banner.module.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/core-apps/nps/createModal.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/core-apps/nps.module.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/core-apps/videoconf.module.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/listeners/listeners.module.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/notifications/notifications.module.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/streamer/streamer.module.ts",["23199"],[],"import { EventEmitter } from 'eventemitter3';\nimport type { IPublication, Rule, Connection, DDPSubscription, IStreamer, IRules, TransformMessage } from 'meteor/rocketchat:streamer';\nimport { MeteorError } from '@rocket.chat/core-services';\n\nimport { SystemLogger } from '../../lib/logger/system';\n\nclass StreamerCentralClass extends EventEmitter {\n\tpublic instances: Record = {};\n\n\tconstructor() {\n\t\tsuper();\n\t}\n}\n\nexport const StreamerCentral = new StreamerCentralClass();\n\nexport abstract class Streamer extends EventEmitter implements IStreamer {\n\tpublic subscriptions = new Set();\n\n\tprotected subscriptionsByEventName = new Map>();\n\n\tpublic retransmit = true;\n\n\tpublic retransmitToSelf = false;\n\n\tpublic serverOnly = false;\n\n\tprivate _allowRead: IRules = {};\n\n\tprivate _allowWrite: IRules = {};\n\n\tprivate _allowEmit: IRules = {};\n\n\tconstructor(\n\t\tpublic name: string,\n\t\t{ retransmit = true, retransmitToSelf = false }: { retransmit?: boolean; retransmitToSelf?: boolean } = {},\n\t) {\n\t\tsuper();\n\n\t\tif (StreamerCentral.instances[name]) {\n\t\t\tconsole.warn('Streamer instance already exists:', name);\n\t\t\treturn StreamerCentral.instances[name];\n\t\t}\n\n\t\tStreamerCentral.instances[name] = this;\n\n\t\tthis.retransmit = retransmit;\n\t\tthis.retransmitToSelf = retransmitToSelf;\n\n\t\tthis.iniPublication();\n\t\t// DDPStreamer doesn't have this\n\t\tthis.initMethod();\n\n\t\tthis.allowRead('none');\n\t\tthis.allowEmit('all');\n\t\tthis.allowWrite('none');\n\t}\n\n\tget subscriptionName(): string {\n\t\treturn `stream-${this.name}`;\n\t}\n\n\tprivate allow(rules: IRules, name: string) {\n\t\treturn (eventName: string | boolean | Rule, fn?: string | boolean | Rule): void => {\n\t\t\tif (fn === undefined) {\n\t\t\t\tfn = eventName;\n\t\t\t\teventName = '__all__';\n\t\t\t}\n\n\t\t\tif (typeof eventName !== 'string') {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (typeof fn === 'function') {\n\t\t\t\trules[eventName] = fn;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (typeof fn === 'string' && ['all', 'none', 'logged'].indexOf(fn) === -1) {\n\t\t\t\tSystemLogger.error(`${name} shortcut '${fn}' is invalid`);\n\t\t\t}\n\n\t\t\tif (fn === 'all' || fn === true) {\n\t\t\t\trules[eventName] = async function (): Promise {\n\t\t\t\t\treturn true;\n\t\t\t\t};\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (fn === 'none' || fn === false) {\n\t\t\t\trules[eventName] = async function (): Promise {\n\t\t\t\t\treturn false;\n\t\t\t\t};\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (fn === 'logged') {\n\t\t\t\trules[eventName] = async function (): Promise {\n\t\t\t\t\treturn Boolean(this.userId);\n\t\t\t\t};\n\t\t\t}\n\t\t};\n\t}\n\n\tallowRead(eventName: string | boolean | Rule, fn?: Rule | 'all' | 'none' | 'logged'): void {\n\t\tthis.allow(this._allowRead, 'allowRead')(eventName, fn);\n\t}\n\n\tallowWrite(eventName: string | boolean | Rule, fn?: Rule | 'all' | 'none' | 'logged'): void {\n\t\tthis.allow(this._allowWrite, 'allowWrite')(eventName, fn);\n\t}\n\n\tallowEmit(eventName: string | boolean | Rule, fn?: Rule | 'all' | 'none' | 'logged'): void {\n\t\tthis.allow(this._allowEmit, 'allowEmit')(eventName, fn);\n\t}\n\n\tprivate isAllowed(rules: IRules) {\n\t\treturn async (scope: IPublication, eventName: string, args: any): Promise => {\n\t\t\tif (rules[eventName]) {\n\t\t\t\treturn rules[eventName].call(scope, eventName, ...args);\n\t\t\t}\n\n\t\t\treturn rules.__all__.call(scope, eventName, ...args);\n\t\t};\n\t}\n\n\tasync isReadAllowed(scope: IPublication, eventName: string, args: any): Promise {\n\t\treturn this.isAllowed(this._allowRead)(scope, eventName, args);\n\t}\n\n\tasync isEmitAllowed(scope: IPublication, eventName: string, ...args: any[]): Promise {\n\t\treturn this.isAllowed(this._allowEmit)(scope, eventName, args);\n\t}\n\n\tasync isWriteAllowed(scope: IPublication, eventName: string, args: any): Promise {\n\t\treturn this.isAllowed(this._allowWrite)(scope, eventName, args);\n\t}\n\n\taddSubscription(subscription: DDPSubscription, eventName: string): void {\n\t\tthis.subscriptions.add(subscription);\n\n\t\tconst subByEventName = this.subscriptionsByEventName.get(eventName) || new Set();\n\t\tsubByEventName.add(subscription);\n\n\t\tthis.subscriptionsByEventName.set(eventName, subByEventName);\n\t}\n\n\tremoveSubscription(subscription: DDPSubscription, eventName: string): void {\n\t\tthis.subscriptions.delete(subscription);\n\n\t\tconst subByEventName = this.subscriptionsByEventName.get(eventName);\n\t\tif (subByEventName) {\n\t\t\tsubByEventName.delete(subscription);\n\t\t}\n\t}\n\n\tasync _publish(\n\t\tpublication: IPublication,\n\t\teventName: string,\n\t\toptions: boolean | { useCollection?: boolean; args?: any } = false,\n\t): Promise {\n\t\tlet useCollection;\n\t\tlet args = [];\n\n\t\tif (typeof options === 'boolean') {\n\t\t\tuseCollection = options;\n\t\t} else {\n\t\t\tif (options.useCollection) {\n\t\t\t\tuseCollection = options.useCollection;\n\t\t\t}\n\n\t\t\tif (options.args) {\n\t\t\t\targs = options.args;\n\t\t\t}\n\t\t}\n\n\t\tif (eventName.length === 0) {\n\t\t\tthrow new MeteorError('invalid-event-name');\n\t\t}\n\n\t\tif ((await this.isReadAllowed(publication, eventName, args)) !== true) {\n\t\t\tthrow new MeteorError('not-allowed');\n\t\t}\n\n\t\tconst subscription = {\n\t\t\tsubscription: publication,\n\t\t\teventName,\n\t\t};\n\n\t\tthis.addSubscription(subscription, eventName);\n\n\t\tpublication.onStop(() => {\n\t\t\tthis.removeSubscription(subscription, eventName);\n\t\t});\n\n\t\t// DDPStreamer doesn't have this\n\t\tif (useCollection === true) {\n\t\t\t// Collection compatibility\n\t\t\tpublication._session.sendAdded(this.subscriptionName, 'id', {\n\t\t\t\teventName,\n\t\t\t});\n\t\t}\n\n\t\tpublication.ready();\n\n\t\tsuper.emit('_afterPublish', this, publication, eventName, options);\n\t}\n\n\tabstract registerPublication(\n\t\tname: string,\n\t\tfn: (eventName: string, options: boolean | { useCollection?: boolean; args?: any }) => Promise,\n\t): void;\n\n\tiniPublication(): void {\n\t\tconst _publish = this._publish.bind(this);\n\t\tthis.registerPublication(\n\t\t\tthis.subscriptionName,\n\t\t\tasync function (this: IPublication, eventName: string, options: boolean | { useCollection?: boolean; args?: any }) {\n\t\t\t\treturn _publish(this, eventName, options);\n\t\t\t},\n\t\t);\n\t}\n\n\tabstract registerMethod(methods: Record any>): void;\n\n\tinitMethod(): void {\n\t\tconst isWriteAllowed = this.isWriteAllowed.bind(this);\n\t\tconst __emit = this.__emit.bind(this);\n\t\tconst _emit = this._emit.bind(this);\n\t\tconst { retransmit } = this;\n\n\t\tconst method: Record any> = {\n\t\t\tasync [this.subscriptionName](this: IPublication, eventName, ...args): Promise {\n\t\t\t\tif ((await isWriteAllowed(this, eventName, args)) !== true) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t__emit(eventName, ...args);\n\n\t\t\t\tif (retransmit === true) {\n\t\t\t\t\t_emit(eventName, args, this.connection, true);\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\n\t\ttry {\n\t\t\tthis.registerMethod(method);\n\t\t} catch (e) {\n\t\t\tSystemLogger.error(e);\n\t\t}\n\t}\n\n\tabstract changedPayload(collection: string, id: string, fields: Record): string | false;\n\n\t_emit(eventName: string, args: any[], origin: Connection | undefined, broadcast: boolean, transform?: TransformMessage): boolean {\n\t\tif (broadcast === true) {\n\t\t\tStreamerCentral.emit('broadcast', this.name, eventName, args);\n\t\t}\n\n\t\tconst subscriptions = this.subscriptionsByEventName.get(eventName);\n\t\tif (!subscriptions || !subscriptions.size) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (transform) {\n\t\t\tthis.sendToManySubscriptions(subscriptions, origin, eventName, args, transform);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tconst msg = this.changedPayload(this.subscriptionName, 'id', {\n\t\t\teventName,\n\t\t\targs,\n\t\t});\n\n\t\tif (!msg) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.sendToManySubscriptions(subscriptions, origin, eventName, args, msg);\n\n\t\treturn true;\n\t}\n\n\tasync sendToManySubscriptions(\n\t\tsubscriptions: Set,\n\t\torigin: Connection | undefined,\n\t\teventName: string,\n\t\targs: any[],\n\t\tgetMsg: string | TransformMessage,\n\t): Promise {\n\t\tsubscriptions.forEach(async (subscription) => {\n\t\t\tif (this.retransmitToSelf === false && origin && origin === subscription.subscription.connection) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst allowed = await this.isEmitAllowed(subscription.subscription, eventName, ...args);\n\t\t\tif (allowed) {\n\t\t\t\tconst msg = typeof getMsg === 'string' ? getMsg : getMsg(this, subscription, eventName, args, allowed);\n\t\t\t\tif (msg) {\n\t\t\t\t\tsubscription.subscription._session.socket?.send(msg);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\temit(eventName: string | symbol, ...args: any[]): boolean {\n\t\treturn this._emit(eventName as string, args, undefined, true);\n\t}\n\n\t__emit(eventName: string, ...args: any[]): boolean {\n\t\treturn super.emit(eventName, ...args);\n\t}\n\n\temitWithoutBroadcast(eventName: string, ...args: any[]): void {\n\t\tthis._emit(eventName, args, undefined, false);\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/watchers/publishFields.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/modules/watchers/watchers.module.ts",["23200"],[],"import mem from 'mem';\nimport type {\n\tISubscription,\n\tIUser,\n\tILoginServiceConfiguration,\n\tIIntegrationHistory,\n\tILivechatDepartmentAgents,\n\tIMessage,\n\tIPermission,\n\tISetting,\n\tIRoom,\n\tIInstanceStatus,\n\tIIntegration,\n\tIEmailInbox,\n\tIPbxEvent,\n\tSettingValue,\n\tILivechatInquiryRecord,\n\tIRole,\n\tILivechatPriority,\n} from '@rocket.chat/core-typings';\nimport {\n\tSubscriptions,\n\tMessages,\n\tUsers,\n\tSettings,\n\tRoles,\n\tLivechatInquiry,\n\tLivechatDepartmentAgents,\n\tRooms,\n\tLoginServiceConfiguration,\n\tInstanceStatus,\n\tIntegrationHistory,\n\tIntegrations,\n\tEmailInbox,\n\tPbxEvents,\n\tPermissions,\n\tLivechatPriority,\n} from '@rocket.chat/models';\nimport type { EventSignatures } from '@rocket.chat/core-services';\n\nimport { subscriptionFields, roomFields } from './publishFields';\nimport type { DatabaseWatcher } from '../../database/DatabaseWatcher';\n\ntype BroadcastCallback = (event: T, ...args: Parameters) => Promise;\n\nconst hasKeys =\n\t(requiredKeys: string[]): ((data?: Record) => boolean) =>\n\t(data?: Record): boolean => {\n\t\tif (!data) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn Object.keys(data)\n\t\t\t.filter((key) => key !== '_id')\n\t\t\t.map((key) => key.split('.')[0])\n\t\t\t.some((key) => requiredKeys.includes(key));\n\t};\n\nconst hasRoomFields = hasKeys(Object.keys(roomFields));\nconst hasSubscriptionFields = hasKeys(Object.keys(subscriptionFields));\n\nlet watcherStarted = false;\nexport function isWatcherRunning(): boolean {\n\treturn watcherStarted;\n}\n\nexport function initWatchers(watcher: DatabaseWatcher, broadcast: BroadcastCallback): void {\n\tconst getSettingCached = mem(async (setting: string): Promise => Settings.getValueById(setting), { maxAge: 10000 });\n\n\tconst getUserNameCached = mem(\n\t\tasync (userId: string): Promise => {\n\t\t\tconst user = await Users.findOne>(userId, { projection: { name: 1 } });\n\t\t\treturn user?.name;\n\t\t},\n\t\t{ maxAge: 10000 },\n\t);\n\n\twatcher.on(Messages.getCollectionName(), async ({ clientAction, id, data }) => {\n\t\tswitch (clientAction) {\n\t\t\tcase 'inserted':\n\t\t\tcase 'updated':\n\t\t\t\tconst message = data ?? (await Messages.findOneById(id));\n\t\t\t\tif (!message) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (message._hidden !== true && message.imported == null) {\n\t\t\t\t\tconst UseRealName = (await getSettingCached('UI_Use_Real_Name')) === true;\n\n\t\t\t\t\tif (UseRealName) {\n\t\t\t\t\t\tif (message.u?._id) {\n\t\t\t\t\t\t\tconst name = await getUserNameCached(message.u._id);\n\t\t\t\t\t\t\tif (name) {\n\t\t\t\t\t\t\t\tmessage.u.name = name;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (message.mentions?.length) {\n\t\t\t\t\t\t\tfor await (const mention of message.mentions) {\n\t\t\t\t\t\t\t\tconst name = await getUserNameCached(mention._id);\n\t\t\t\t\t\t\t\tif (name) {\n\t\t\t\t\t\t\t\t\tmention.name = name;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tbroadcast('watch.messages', { clientAction, message });\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t});\n\n\twatcher.on(Subscriptions.getCollectionName(), async ({ clientAction, id, data, diff }) => {\n\t\tswitch (clientAction) {\n\t\t\tcase 'inserted':\n\t\t\tcase 'updated': {\n\t\t\t\tif (!hasSubscriptionFields(data || diff)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Override data cuz we do not publish all fields\n\t\t\t\tconst subscription = await Subscriptions.findOneById>(id, {\n\t\t\t\t\tprojection: subscriptionFields,\n\t\t\t\t});\n\t\t\t\tif (!subscription) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tbroadcast('watch.subscriptions', { clientAction, subscription });\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase 'removed': {\n\t\t\t\tconst trash = await Subscriptions.trashFindOneById>(id, {\n\t\t\t\t\tprojection: { u: 1, rid: 1 },\n\t\t\t\t});\n\t\t\t\tconst subscription = trash || { _id: id };\n\t\t\t\tbroadcast('watch.subscriptions', { clientAction, subscription });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\twatcher.on(Roles.getCollectionName(), async ({ clientAction, id, data, diff }) => {\n\t\tif (diff && Object.keys(diff).length === 1 && diff._updatedAt) {\n\t\t\t// avoid useless changes\n\t\t\treturn;\n\t\t}\n\n\t\tconst role = clientAction === 'removed' ? { _id: id, name: id } : data || (await Roles.findOneById(id));\n\n\t\tif (!role) {\n\t\t\treturn;\n\t\t}\n\n\t\tbroadcast('watch.roles', {\n\t\t\tclientAction: clientAction !== 'removed' ? ('changed' as const) : clientAction,\n\t\t\trole,\n\t\t});\n\t});\n\n\twatcher.on(LivechatInquiry.getCollectionName(), async ({ clientAction, id, data, diff }) => {\n\t\tswitch (clientAction) {\n\t\t\tcase 'inserted':\n\t\t\tcase 'updated':\n\t\t\t\tdata = data ?? (await LivechatInquiry.findOneById(id)) ?? undefined;\n\t\t\t\tbreak;\n\n\t\t\tcase 'removed':\n\t\t\t\tdata = (await LivechatInquiry.trashFindOneById(id)) ?? undefined;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (!data) {\n\t\t\treturn;\n\t\t}\n\n\t\tbroadcast('watch.inquiries', { clientAction, inquiry: data, diff });\n\t});\n\n\twatcher.on(LivechatDepartmentAgents.getCollectionName(), async ({ clientAction, id, diff }) => {\n\t\tif (clientAction === 'removed') {\n\t\t\tconst data = await LivechatDepartmentAgents.trashFindOneById>(id, {\n\t\t\t\tprojection: { agentId: 1, departmentId: 1 },\n\t\t\t});\n\t\t\tif (!data) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbroadcast('watch.livechatDepartmentAgents', { clientAction, id, data, diff });\n\t\t\treturn;\n\t\t}\n\n\t\tconst data = await LivechatDepartmentAgents.findOneById>(id, {\n\t\t\tprojection: { agentId: 1, departmentId: 1 },\n\t\t});\n\t\tif (!data) {\n\t\t\treturn;\n\t\t}\n\t\tbroadcast('watch.livechatDepartmentAgents', { clientAction, id, data, diff });\n\t});\n\n\twatcher.on(Permissions.getCollectionName(), async ({ clientAction, id, data: eventData, diff }) => {\n\t\tif (diff && Object.keys(diff).length === 1 && diff._updatedAt) {\n\t\t\t// avoid useless changes\n\t\t\treturn;\n\t\t}\n\t\tlet data;\n\t\tswitch (clientAction) {\n\t\t\tcase 'updated':\n\t\t\tcase 'inserted':\n\t\t\t\tdata = eventData ?? (await Permissions.findOneById(id));\n\t\t\t\tbreak;\n\n\t\t\tcase 'removed':\n\t\t\t\tdata = { _id: id, roles: [] };\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (!data) {\n\t\t\treturn;\n\t\t}\n\n\t\tbroadcast('permission.changed', { clientAction, data });\n\n\t\tif (data.level === 'settings' && data.settingId) {\n\t\t\t// if the permission changes, the effect on the visible settings depends on the role affected.\n\t\t\t// The selected-settings-based consumers have to react accordingly and either add or remove the\n\t\t\t// setting from the user's collection\n\t\t\tconst setting = await Settings.findOneNotHiddenById(data.settingId);\n\t\t\tif (!setting) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tbroadcast('watch.settings', { clientAction: 'updated', setting });\n\t\t}\n\t});\n\n\twatcher.on(Settings.getCollectionName(), async ({ clientAction, id, data, diff }) => {\n\t\tif (diff && Object.keys(diff).length === 1 && diff._updatedAt) {\n\t\t\t// avoid useless changes\n\t\t\treturn;\n\t\t}\n\n\t\tlet setting;\n\t\tswitch (clientAction) {\n\t\t\tcase 'updated':\n\t\t\tcase 'inserted': {\n\t\t\t\tsetting = data ?? (await Settings.findOneById(id));\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase 'removed': {\n\t\t\t\tsetting = data ?? (await Settings.trashFindOneById(id));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!setting) {\n\t\t\treturn;\n\t\t}\n\n\t\tbroadcast('watch.settings', { clientAction, setting });\n\t});\n\n\twatcher.on(Rooms.getCollectionName(), async ({ clientAction, id, data, diff }) => {\n\t\tif (clientAction === 'removed') {\n\t\t\tbroadcast('watch.rooms', { clientAction, room: { _id: id } });\n\t\t\treturn;\n\t\t}\n\n\t\tif (!hasRoomFields(data || diff)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst room = data ?? (await Rooms.findOneById(id, { projection: roomFields }));\n\t\tif (!room) {\n\t\t\treturn;\n\t\t}\n\n\t\tbroadcast('watch.rooms', { clientAction, room });\n\t});\n\n\t// TODO: Prevent flood from database on username change, what causes changes on all past messages from that user\n\t// and most of those messages are not loaded by the clients.\n\twatcher.on(Users.getCollectionName(), ({ clientAction, id, data, diff, unset }) => {\n\t\t// LivechatCount is updated each time an agent is routed to a chat. This prop is not used on the UI so we don't need\n\t\t// to broadcast events originated by it when it's the only update on the user\n\t\tif (diff && Object.keys(diff).length === 1 && 'livechatCount' in diff) {\n\t\t\treturn;\n\t\t}\n\n\t\tbroadcast('watch.users', { clientAction, data, diff, unset, id });\n\t});\n\n\twatcher.on(LoginServiceConfiguration.getCollectionName(), async ({ clientAction, id }) => {\n\t\tconst data = await LoginServiceConfiguration.findOne>(id, { projection: { secret: 0 } });\n\t\tif (!data) {\n\t\t\treturn;\n\t\t}\n\n\t\tbroadcast('watch.loginServiceConfiguration', { clientAction, data, id });\n\t});\n\n\twatcher.on(InstanceStatus.getCollectionName(), ({ clientAction, id, data, diff }) => {\n\t\tbroadcast('watch.instanceStatus', { clientAction, data, diff, id });\n\t});\n\n\twatcher.on(IntegrationHistory.getCollectionName(), async ({ clientAction, id, data, diff }) => {\n\t\tswitch (clientAction) {\n\t\t\tcase 'updated': {\n\t\t\t\tconst history = await IntegrationHistory.findOneById>(id, {\n\t\t\t\t\tprojection: { 'integration._id': 1 },\n\t\t\t\t});\n\t\t\t\tif (!history || !history.integration) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tbroadcast('watch.integrationHistory', { clientAction, data: history, diff, id });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'inserted': {\n\t\t\t\tif (!data) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tbroadcast('watch.integrationHistory', { clientAction, data, diff, id });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t});\n\n\twatcher.on(Integrations.getCollectionName(), async ({ clientAction, id, data: eventData }) => {\n\t\tif (clientAction === 'removed') {\n\t\t\tbroadcast('watch.integrations', { clientAction, id, data: { _id: id } });\n\t\t\treturn;\n\t\t}\n\n\t\tconst data = eventData ?? (await Integrations.findOneById(id));\n\t\tif (!data) {\n\t\t\treturn;\n\t\t}\n\n\t\tbroadcast('watch.integrations', { clientAction, data, id });\n\t});\n\n\twatcher.on(EmailInbox.getCollectionName(), async ({ clientAction, id, data: eventData }) => {\n\t\tif (clientAction === 'removed') {\n\t\t\tbroadcast('watch.emailInbox', { clientAction, id, data: { _id: id } });\n\t\t\treturn;\n\t\t}\n\n\t\tconst data = eventData ?? (await EmailInbox.findOneById(id));\n\t\tif (!data) {\n\t\t\treturn;\n\t\t}\n\n\t\tbroadcast('watch.emailInbox', { clientAction, data, id });\n\t});\n\n\twatcher.on(PbxEvents.getCollectionName(), async ({ clientAction, id, data: eventData }) => {\n\t\t// For now, we just care about insertions here\n\t\tif (clientAction === 'inserted') {\n\t\t\tconst data = eventData ?? (await PbxEvents.findOneById(id));\n\t\t\tif (!data || !['ContactStatus', 'Hangup'].includes(data.event)) {\n\t\t\t\t// For now, we'll only care about agent connect/disconnect events\n\t\t\t\t// Other events are not handled by watchers but by service\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbroadcast('watch.pbxevents', { clientAction, data, id });\n\t\t}\n\t});\n\n\twatcher.on(LivechatPriority.getCollectionName(), async ({ clientAction, id, data: eventData, diff }) => {\n\t\tif (clientAction !== 'updated' || !diff || !('name' in diff)) {\n\t\t\t// For now, we don't support this actions from happening\n\t\t\treturn;\n\t\t}\n\n\t\tconst data = eventData ?? (await LivechatPriority.findOne({ _id: id }));\n\t\tif (!data) {\n\t\t\treturn;\n\t\t}\n\n\t\t// This solves the problem of broadcasting, since now, watcher is the one in charge of doing it.\n\t\t// What i don't like is the idea of giving more responsibilities to watcher, even when this works\n\t\tbroadcast('watch.priorities', { clientAction, data, id, diff });\n\t});\n\n\twatcherStarted = true;\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/overrides/http.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/publications/messages.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/publications/room/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/publications/settings/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/publications/spotlight.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/publications/subscription/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/middlewares/auth.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/middlewares/browserVersion.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/middlewares/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/room.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/user.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/avatar/utils.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/health.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/i18n.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/timesync.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/routes/userDataDownload.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/analytics/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/apps-engine/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/authorization/canAccessRoom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/authorization/canAccessRoomLivechat.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/authorization/canAccessRoomVoip.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/authorization/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/banner/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/device-management/events.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/device-management/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/federation/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/image/service.ts",[],["23201"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/ldap/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/messages/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/meteor/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/nps/getAndCreateNpsSurvey.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/nps/notification.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/nps/sendNpsResults.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/nps/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/omnichannel/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/omnichannel-voip/internalTypes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/omnichannel-voip/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/push/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/room/service.ts",["23202"],[],"import type { IRoom, IUser } from '@rocket.chat/core-typings';\nimport { Users } from '@rocket.chat/models';\nimport { ServiceClassInternal, Authorization } from '@rocket.chat/core-services';\nimport type { ICreateRoomParams, IRoomService } from '@rocket.chat/core-services';\n\nimport { createRoom } from '../../../app/lib/server/functions/createRoom'; // TODO remove this import\nimport { createDirectMessage } from '../../methods/createDirectMessage';\n\nexport class RoomService extends ServiceClassInternal implements IRoomService {\n\tprotected name = 'room';\n\n\tasync create(uid: string, params: ICreateRoomParams): Promise {\n\t\tconst { type, name, members = [], readOnly, extraData, options } = params;\n\n\t\tconst hasPermission = await Authorization.hasPermission(uid, `create-${type}`);\n\t\tif (!hasPermission) {\n\t\t\tthrow new Error('no-permission');\n\t\t}\n\n\t\tconst user = await Users.findOneById>(uid, {\n\t\t\tprojection: { username: 1 },\n\t\t});\n\t\tif (!user || !user.username) {\n\t\t\tthrow new Error('User not found');\n\t\t}\n\n\t\t// TODO convert `createRoom` function to \"raw\" and move to here\n\t\treturn createRoom(type, name, user.username, members, readOnly, extraData, options) as unknown as IRoom;\n\t}\n\n\tasync createDirectMessage({ to, from }: { to: string; from: string }): Promise<{ rid: string }> {\n\t\tconst [toUser, fromUser] = await Promise.all([\n\t\t\tUsers.findOneById(to, { projection: { username: 1 } }),\n\t\t\tUsers.findOneById(from, { projection: { _id: 1 } }),\n\t\t]);\n\n\t\tif (!toUser || !fromUser) {\n\t\t\tthrow new Error('error-invalid-user');\n\t\t}\n\t\treturn createDirectMessage([toUser.username], fromUser._id);\n\t}\n\n\tasync addMember(uid: string, rid: string): Promise {\n\t\tconst hasPermission = await Authorization.hasPermission(uid, 'add-user-to-joined-room', rid);\n\t\tif (!hasPermission) {\n\t\t\tthrow new Error('no-permission');\n\t\t}\n\n\t\treturn true;\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/sauMonitor/events.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/sauMonitor/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/settings/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/startup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/team/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/translation/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/uikit-core-app/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/upload/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/user/lib/getNewUserRoles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/video-conference/service.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/Command.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/CommandHandler.ts",["23203"],[],"/**\n * Class for executing command.\n * @remarks\n * This class abstracts lower details such as interface, connection and command objects\n * from the consumers of this class.\n * Connectors can be to different call-servers. For each call server, there will be\n * a multiple interfaces. e.g in case of asterisk, there are 3 types of interfaces.\n * Asterisk Gateway Interface (AGI) : Used for dialplan administration and manipulation\n * Asterisk Rest Interface (ARI) : Used for managing asterisk resources to build own application.\n * One of the use-case of ARI is for dynamically creating endpoints or listing existing recordings.\n * Asterisk Manager Interface (AMI) : Used for querying the information from asterisk.\n *\n * We shall be using only AMI interface in the for now. Other interfaces will be\n * added as and when required.\n */\nimport type { Db } from 'mongodb';\nimport type { IVoipConnectorResult, IManagementServerConnectionStatus, IManagementConfigData } from '@rocket.chat/core-typings';\n\nimport { Commands } from './Commands';\nimport type { IConnection } from './IConnection';\nimport { Logger } from '../../../../lib/logger/Logger';\nimport type { Command } from './Command';\nimport { CommandType } from './Command';\nimport { AMIConnection } from './ami/AMIConnection';\nimport { CommandFactory } from './ami/CommandFactory';\nimport { WebsocketConnection } from '../websocket/WebsocketConnection';\nimport { getManagementServerConfig } from '../../lib/Helper';\n\nconst version = 'Asterisk Connector 1.0';\n\nexport class CommandHandler {\n\tprivate connections: Map;\n\n\tprivate logger: Logger;\n\n\tprivate continuousMonitor: Command;\n\n\tprivate db: Db;\n\n\tconstructor(db: Db) {\n\t\tthis.logger = new Logger('CommandHandler');\n\t\tthis.connections = new Map();\n\t\tthis.db = db;\n\t}\n\n\tasync initConnection(commandType: CommandType): Promise {\n\t\t// Initialize available connections\n\t\tconst connection = new AMIConnection();\n\n\t\tconst config = commandType === CommandType.AMI ? getManagementServerConfig() : undefined;\n\t\tif (!config) {\n\t\t\tthis.logger.warn('Management server configuration not found');\n\t\t\treturn;\n\t\t}\n\t\t/**\n\t\t * If we have the same type of connection already established, close it\n\t\t * and remove it from the map.\n\t\t */\n\t\tif (this.connections.get(commandType)?.isConnected()) {\n\t\t\tthis.logger.error({ msg: 'connection exists. Closing the connection.' });\n\t\t\tthis.connections.get(commandType)?.closeConnection();\n\t\t\tthis.connections.delete(commandType);\n\t\t}\n\n\t\tif (!config.host) {\n\t\t\tthis.logger.error('Invalid host');\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tawait connection.connect(\n\t\t\t\tconfig.host,\n\t\t\t\t(config.configData as IManagementConfigData).port.toString(),\n\t\t\t\t(config.configData as IManagementConfigData).username,\n\t\t\t\t(config.configData as IManagementConfigData).password,\n\t\t\t);\n\t\t\tthis.connections.set(commandType, connection);\n\t\t\tthis.continuousMonitor = CommandFactory.getCommandObject(Commands.event_stream, this.db);\n\t\t\tconst continuousMonitor = this.connections.get(this.continuousMonitor.type);\n\t\t\tif (!continuousMonitor) {\n\t\t\t\tthrow new Error(`No connection for ${this.continuousMonitor.type}`);\n\t\t\t}\n\t\t\tthis.continuousMonitor.connection = continuousMonitor;\n\t\t\tthis.continuousMonitor.initMonitor({});\n\t\t} catch (err: unknown) {\n\t\t\tthis.logger.error({ msg: 'Management server connection error', err });\n\t\t}\n\t}\n\n\t/* Executes |commandToExecute| on a particular command object\n\t * @remarks\n\t * CommandFactory is responsible for creating a |Command| object necessary\n\t * for executing an AMI command. Every concrete command object inherits\n\t * from class |Command|. Which overrides a method called executeCommand.\n\t * This function returns a promise. Caller can wait for the promise to resolve\n\t * or rejected.\n\t */\n\texecuteCommand(commandToExecute: Commands, commandData?: any): Promise {\n\t\tthis.logger.debug({ msg: `executeCommand() executing ${Commands[commandToExecute]}` });\n\t\tconst command = CommandFactory.getCommandObject(commandToExecute, this.db);\n\t\tconst connection = this.connections.get(command.type) as IConnection;\n\t\tif (!connection || !connection.isConnected()) {\n\t\t\tthrow Error('Connection error');\n\t\t}\n\t\tcommand.connection = this.connections.get(command.type) as IConnection;\n\t\treturn command.executeCommand(commandData);\n\t}\n\n\t// Get the version string\n\tgetVersion(): string {\n\t\treturn version;\n\t}\n\n\tasync checkManagementConnection(\n\t\thost: string,\n\t\tport: string,\n\t\tuserName: string,\n\t\tpassword: string,\n\t): Promise {\n\t\tthis.logger.debug({ msg: 'checkManagementConnection()', host, port, userName });\n\t\tconst connection = new AMIConnection();\n\t\ttry {\n\t\t\tawait connection.connect(host, port, userName, password);\n\t\t\tif (connection.isConnected()) {\n\t\t\t\t// Just a second level of check to ensure that we are actually\n\t\t\t\t// connected and authenticated.\n\t\t\t\tconnection.closeConnection();\n\t\t\t}\n\t\t\tthis.logger.debug({ msg: 'checkManagementConnection() Connected ' });\n\t\t\treturn {\n\t\t\t\tstatus: 'connected',\n\t\t\t};\n\t\t} catch (err: unknown) {\n\t\t\tthis.logger.error({ msg: 'checkManagementConnection() Connection Error', err });\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\tasync checkCallserverConnection(websocketUrl: string, protocol?: string): Promise {\n\t\tthis.logger.debug({ msg: 'checkCallserverConnection()', websocketUrl });\n\t\tconst connection = new WebsocketConnection();\n\t\ttry {\n\t\t\tawait connection.connectWithUrl(websocketUrl, protocol);\n\t\t\tif (connection.isConnected()) {\n\t\t\t\t// Just a second level of check to ensure that we are actually\n\t\t\t\t// connected and authenticated.\n\t\t\t\tconnection.closeConnection();\n\t\t\t}\n\t\t\tthis.logger.debug({ msg: 'checkManagementConnection() Connected ' });\n\t\t\treturn {\n\t\t\t\tstatus: 'connected',\n\t\t\t};\n\t\t} catch (err: unknown) {\n\t\t\tthis.logger.error({ msg: 'checkManagementConnection() Connection Error', err });\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\tstop(): void {\n\t\tif (!this.continuousMonitor) {\n\t\t\t// service is already stopped or was never initialized\n\t\t\treturn;\n\t\t}\n\n\t\tthis.continuousMonitor.cleanMonitor();\n\t\tfor (const connection of this.connections.values()) {\n\t\t\tconnection.closeConnection();\n\t\t}\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/Commands.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ICallbackContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/IConnection.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ami/ACDQueue.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ami/AMIConnection.ts",[],["23204","23205","23206","23207","23208"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ami/CallbackContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ami/CommandFactory.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ami/ContinuousMonitor.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/asterisk/ami/PJSIPEndpoint.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/connector/websocket/WebsocketConnection.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/lib/Helper.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/services/voip/service.ts",["23209","23210"],[],"import type { Db } from 'mongodb';\nimport mem from 'mem';\nimport { ServerType, isICallServerConfigData, isIExtensionDetails } from '@rocket.chat/core-typings';\nimport type {\n\tIVoipConnectorResult,\n\tIQueueDetails,\n\tIQueueSummary,\n\tIManagementServerConnectionStatus,\n\tIVoipCallServerConfig,\n\tIVoipManagementServerConfig,\n\tIQueueMembershipDetails,\n\tIQueueMembershipSubscription,\n\tIRegistrationInfo,\n} from '@rocket.chat/core-typings';\nimport type { IVoipService } from '@rocket.chat/core-services';\nimport { api, ServiceClassInternal } from '@rocket.chat/core-services';\n\nimport { Logger } from '../../lib/logger/Logger';\nimport { CommandHandler } from './connector/asterisk/CommandHandler';\nimport { CommandType } from './connector/asterisk/Command';\nimport { Commands } from './connector/asterisk/Commands';\nimport { getServerConfigDataFromSettings, voipEnabled } from './lib/Helper';\n\nexport class VoipService extends ServiceClassInternal implements IVoipService {\n\tprotected name = 'voip';\n\n\tprivate logger: Logger;\n\n\tcommandHandler: CommandHandler;\n\n\tprivate active = false;\n\n\tconstructor(db: Db) {\n\t\tsuper();\n\n\t\tthis.logger = new Logger('VoIPService');\n\t\tthis.commandHandler = new CommandHandler(db);\n\t\tif (!voipEnabled()) {\n\t\t\tthis.logger.warn({ msg: 'Voip is not enabled. Cant start the service' });\n\t\t\treturn;\n\t\t}\n\t\t// Init from constructor if we already have\n\t\t// voip enabled by default while starting the server\n\t\tthis.init();\n\t}\n\n\tasync init(): Promise {\n\t\tthis.logger.info('Starting VoIP service');\n\t\tif (this.active) {\n\t\t\tthis.logger.warn({ msg: 'VoIP service already started' });\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.commandHandler.initConnection(CommandType.AMI);\n\t\t\tthis.active = true;\n\t\t\tapi.broadcast('connector.statuschanged', true);\n\t\t\tthis.logger.info('VoIP service started');\n\t\t} catch (err) {\n\t\t\tthis.logger.error({ msg: 'Error initializing VOIP service', err });\n\t\t}\n\t}\n\n\tasync stop(): Promise {\n\t\tthis.logger.info('Stopping VoIP service');\n\t\tif (!this.active) {\n\t\t\tthis.logger.warn({ msg: 'VoIP service already stopped' });\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tthis.commandHandler.stop();\n\t\t\tthis.active = false;\n\t\t\tapi.broadcast('connector.statuschanged', false);\n\t\t\tthis.logger.info('VoIP service stopped');\n\t\t} catch (err) {\n\t\t\tthis.logger.error({ msg: 'Error stopping VoIP service', err });\n\t\t}\n\t}\n\n\tasync refresh(): Promise {\n\t\tthis.logger.info('Restarting VoIP service due to settings changes');\n\t\ttry {\n\t\t\t// Disable voip service\n\t\t\tawait this.stop();\n\t\t\t// To then restart it\n\t\t\tawait this.init();\n\t\t} catch (err) {\n\t\t\tthis.logger.error({ msg: 'Error refreshing VoIP service', err });\n\t\t}\n\t}\n\n\tgetServerConfigData(type: ServerType): IVoipCallServerConfig | IVoipManagementServerConfig {\n\t\treturn getServerConfigDataFromSettings(type);\n\t}\n\n\tasync getQueueSummary(): Promise {\n\t\treturn this.commandHandler.executeCommand(Commands.queue_summary);\n\t}\n\n\tprivate cachedQueueSummary(): () => Promise {\n\t\t// arbitrary 5 secs cache to prevent fetching this from asterisk too often\n\t\treturn mem(this.getQueueSummary.bind(this), { maxAge: 5000 });\n\t}\n\n\tcachedQueueDetails(): () => Promise<{ name: string; members: string[] }[]> {\n\t\treturn mem(this.getQueueDetails.bind(this), { maxAge: 5000 });\n\t}\n\n\tprivate async getQueueDetails(): Promise<{ name: string; members: string[] }[]> {\n\t\tconst summary = await this.cachedQueueSummary()();\n\t\tconst queues = (summary.result as unknown as IQueueSummary[]).map((q) => q.name);\n\n\t\tconst queueInfo: { name: string; members: string[] }[] = [];\n\t\tfor await (const queue of queues) {\n\t\t\tconst queueDetails = (await this.commandHandler.executeCommand(Commands.queue_details, {\n\t\t\t\tqueueName: queue,\n\t\t\t})) as IVoipConnectorResult;\n\t\t\tconst details = queueDetails.result as IQueueDetails;\n\t\t\tif (!details.members || !details.members.length) {\n\t\t\t\t// Go to the next queue if queue does not have any\n\t\t\t\t// memmbers.\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tqueueInfo.push({\n\t\t\t\tname: queue,\n\t\t\t\tmembers: (queueDetails.result as IQueueDetails).members.map((member) => member.name.replace('PJSIP/', '')),\n\t\t\t});\n\t\t}\n\n\t\treturn queueInfo;\n\t}\n\n\tasync getQueuedCallsForThisExtension({ extension }: { extension: string }): Promise {\n\t\tconst membershipDetails: IQueueMembershipDetails = {\n\t\t\tqueueCount: 0,\n\t\t\tcallWaitingCount: 0,\n\t\t\textension,\n\t\t};\n\t\tconst queueSummary = (await this.commandHandler.executeCommand(Commands.queue_summary)) as IVoipConnectorResult;\n\n\t\tfor await (const queue of queueSummary.result as IQueueSummary[]) {\n\t\t\tconst queueDetails = (await this.commandHandler.executeCommand(Commands.queue_details, {\n\t\t\t\tqueueName: queue.name,\n\t\t\t})) as IVoipConnectorResult;\n\n\t\t\tconst details = queueDetails.result as IQueueDetails;\n\n\t\t\tif (!details.members.length) {\n\t\t\t\t// Go to the next queue if queue does not have any\n\t\t\t\t// memmbers.\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst isAMember = details.members.some((element) => element.name.endsWith(extension));\n\t\t\tif (!isAMember) {\n\t\t\t\t// Current extension is not a member of queue in question.\n\t\t\t\t// continue with next queue.\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tmembershipDetails.callWaitingCount += Number(details.calls);\n\t\t\tmembershipDetails.queueCount++;\n\t\t}\n\n\t\treturn { result: membershipDetails };\n\t}\n\n\tasync getQueueMembership({ extension }: { extension: string }): Promise {\n\t\tconst membershipDetails: IQueueMembershipSubscription = {\n\t\t\tqueues: [],\n\t\t\textension,\n\t\t};\n\t\tconst queueSummary = (await this.commandHandler.executeCommand(Commands.queue_summary)) as IVoipConnectorResult;\n\n\t\tfor await (const queue of queueSummary.result as IQueueSummary[]) {\n\t\t\tconst queueDetails = (await this.commandHandler.executeCommand(Commands.queue_details, {\n\t\t\t\tqueueName: queue.name,\n\t\t\t})) as IVoipConnectorResult;\n\n\t\t\tconst details = queueDetails.result as IQueueDetails;\n\n\t\t\tif (!details.members || !details.members.length) {\n\t\t\t\t// Go to the next queue if queue does not have any\n\t\t\t\t// memmbers.\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst isAMember = details.members.some((element) => element.name.endsWith(extension));\n\t\t\tif (!isAMember) {\n\t\t\t\t// Current extension is not a member of queue in question.\n\t\t\t\t// continue with next queue.\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmembershipDetails.queues.push(queue);\n\t\t}\n\t\treturn { result: membershipDetails };\n\t}\n\n\tgetConnectorVersion(): string {\n\t\treturn this.commandHandler.getVersion();\n\t}\n\n\tasync getExtensionList(): Promise {\n\t\treturn this.commandHandler.executeCommand(Commands.extension_list, undefined);\n\t}\n\n\tasync getExtensionDetails(requestParams: { extension: string }): Promise {\n\t\treturn this.commandHandler.executeCommand(Commands.extension_info, requestParams);\n\t}\n\n\tasync getRegistrationInfo(requestParams: { extension: string }): Promise<{ result: IRegistrationInfo }> {\n\t\tconst config = this.getServerConfigData(ServerType.CALL_SERVER);\n\t\tif (!config) {\n\t\t\tthis.logger.warn({ msg: 'API = connector.extension.getRegistrationInfo callserver settings not found' });\n\t\t\tthis.logger.warn('Check call server settings, without them you wont be be able to send/receive calls on RocketChat');\n\t\t\tthrow new Error('Not found');\n\t\t}\n\n\t\tconst endpointDetails = await this.commandHandler.executeCommand(Commands.extension_info, requestParams);\n\n\t\tif (!isIExtensionDetails(endpointDetails.result)) {\n\t\t\tthrow new Error('getRegistrationInfo Invalid endpointDetails response');\n\t\t}\n\t\tif (!isICallServerConfigData(config.configData)) {\n\t\t\tthrow new Error('getRegistrationInfo Invalid configData response');\n\t\t}\n\n\t\tconst result = {\n\t\t\tcallServerConfig: config.configData,\n\t\t\textensionDetails: endpointDetails.result,\n\t\t};\n\n\t\treturn {\n\t\t\tresult,\n\t\t};\n\t}\n\n\tasync checkManagementConnection(\n\t\thost: string,\n\t\tport: string,\n\t\tuserName: string,\n\t\tpassword: string,\n\t): Promise {\n\t\tthis.logger.debug('Checking management server connection');\n\t\treturn this.commandHandler.checkManagementConnection(host, port, userName, password);\n\t}\n\n\tasync checkCallserverConnection(websocketUrl: string, protocol?: string): Promise {\n\t\tthis.logger.debug('Checking call server connection');\n\t\treturn this.commandHandler.checkCallserverConnection(websocketUrl, protocol);\n\t}\n}\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/settings/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/settings/ldap.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/settings/userDataDownload.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/settings/video-conference.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/appcache.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/callbacks.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/coreApps.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/cron.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/initialData.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/localServices.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/minimumVersion.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v266.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v267.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v268.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v269.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v270.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v271.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v272.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v273.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v274.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v275.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v276.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v277.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v278.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v279.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v280.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v281.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v282.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v283.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v284.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v285.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v286.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v287.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v288.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v289.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v290.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v291.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/v292.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/migrations/xrun.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/presenceTroubleshoot.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/serverRunning.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/startup/watchDb.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/server/stream/stdout.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/administration-menu.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/administration.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/anonymous-user.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/apps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/channel-management.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/config/constants.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/config/global-setup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/config/global.d.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/create-channel.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/create-direct.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/create-discussion.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/e2e-encryption.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/email-inboxes.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/emojis.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/engagement-dashboard.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/config/constants.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/config/global-setup.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/account-profile.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/admin.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/channel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/account-sidenav.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/admin-flextab-users.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/admin-flextab.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-content.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-flextab-channels.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-flextab-dm-member.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-flextab-members.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-flextab-notificationPreferences.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-flextab-room.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-flextab.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/page-objects/fragments/home-sidenav.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/admin/rooms.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/admin/users.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/ce-version/ce.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/channel/dm.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/channel/private.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/channel/public.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/messaging/dm.spec.ts",["23211","23212","23213","23214"],[],"/* eslint no-await-in-loop: 0 */\nimport type { Page } from '@playwright/test';\n\nimport * as constants from '../../config/constants';\nimport { FederationChannel } from '../../page-objects/channel';\nimport { doLogin } from '../../utils/auth';\nimport { formatIntoFullMatrixUsername, formatUsernameAndDomainIntoMatrixFormat } from '../../utils/format';\nimport { registerUser } from '../../utils/register-user';\nimport { test, expect, setupTesting, tearDownTesting } from '../../utils/test';\n\ntest.describe.parallel('Federation - DM Messaging', () => {\n\tlet poFederationChannelServer1: FederationChannel;\n\tlet poFederationChannelServer2: FederationChannel;\n\tlet userFromServer2UsernameOnly: string;\n\tlet userFromServer1UsernameOnly: string;\n\tlet usernameWithDomainFromServer2: string;\n\tconst adminUsernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(\n\t\tconstants.RC_SERVER_1.username,\n\t\tconstants.RC_SERVER_1.matrixServerName,\n\t);\n\tlet pageForServer2: Page;\n\n\ttest.beforeAll(async ({ apiServer1, apiServer2, browser }) => {\n\t\tawait setupTesting(apiServer1);\n\t\tawait setupTesting(apiServer2);\n\t\tuserFromServer1UsernameOnly = await registerUser(apiServer1);\n\t\tuserFromServer2UsernameOnly = await registerUser(apiServer2);\n\t\tusernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\tuserFromServer2UsernameOnly,\n\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t);\n\t\tconst page = await browser.newPage();\n\t\tawait doLogin({\n\t\t\tpage,\n\t\t\tserver: {\n\t\t\t\turl: constants.RC_SERVER_1.url,\n\t\t\t\tusername: constants.RC_SERVER_1.username,\n\t\t\t\tpassword: constants.RC_SERVER_1.password,\n\t\t\t},\n\t\t});\n\t\tpoFederationChannelServer1 = new FederationChannel(page);\n\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(userFromServer2UsernameOnly, constants.RC_SERVER_2.matrixServerName);\n\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\t\tawait page.close();\n\t});\n\n\ttest.afterAll(async ({ apiServer1, apiServer2 }) => {\n\t\tawait tearDownTesting(apiServer1);\n\t\tawait tearDownTesting(apiServer2);\n\t});\n\n\ttest.beforeEach(async ({ page, browser }) => {\n\t\tpageForServer2 = await browser.newPage();\n\n\t\tpoFederationChannelServer1 = new FederationChannel(page);\n\t\tawait doLogin({\n\t\t\tpage,\n\t\t\tserver: {\n\t\t\t\turl: constants.RC_SERVER_1.url,\n\t\t\t\tusername: constants.RC_SERVER_1.username,\n\t\t\t\tpassword: constants.RC_SERVER_1.password,\n\t\t\t},\n\t\t});\n\n\t\tpoFederationChannelServer2 = new FederationChannel(pageForServer2);\n\t\tawait doLogin({\n\t\t\tpage: pageForServer2,\n\t\t\tserver: {\n\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\tusername: userFromServer2UsernameOnly,\n\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t},\n\t\t\tstoreState: false,\n\t\t});\n\n\t\tawait page.addInitScript(() => {\n\t\t\twindow.localStorage.setItem('fuselage-localStorage-members-list-type', JSON.stringify('online'));\n\t\t});\n\t});\n\n\ttest.afterEach(async ({ page }) => {\n\t\tawait page.close();\n\t\tawait pageForServer2.close();\n\t});\n\n\ttest.describe('Messaging - Direct Messages (DMs)', () => {\n\t\ttest.describe('Send message', () => {\n\t\t\ttest('expect to send a message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('hello world from server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('hello world from server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('hello world from server A');\n\t\t\t});\n\n\t\t\ttest('expect to send a message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\t\t\t\tawait poFederationChannelServer2.content.sendMessage('hello world from server B');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t});\n\n\t\t\ttest.describe('With multiple users', () => {\n\t\t\t\tlet createdUsernameFromServer2: string;\n\t\t\t\tlet usernameWithDomainFromServer2: string;\n\n\t\t\t\ttest('expect to send a message from Server A (creator) to Server B', async ({ browser, page, apiServer2 }) => {\n\t\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\t\tconst poFederationChannel1ForUser2 = new FederationChannel(page2);\n\t\t\t\t\tconst pageForServer2 = await browser.newPage();\n\t\t\t\t\tconst poFederationChannelServer2 = new FederationChannel(pageForServer2);\n\t\t\t\t\tcreatedUsernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\t\tawait doLogin({\n\t\t\t\t\t\tpage: pageForServer2,\n\t\t\t\t\t\tserver: {\n\t\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\t\tusername: createdUsernameFromServer2,\n\t\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstoreState: false,\n\t\t\t\t\t});\n\t\t\t\t\tawait doLogin({\n\t\t\t\t\t\tpage: page2,\n\t\t\t\t\t\tserver: {\n\t\t\t\t\t\t\turl: constants.RC_SERVER_1.url,\n\t\t\t\t\t\t\tusername: userFromServer1UsernameOnly,\n\t\t\t\t\t\t\tpassword: constants.RC_SERVER_1.password,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstoreState: false,\n\t\t\t\t\t});\n\t\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(createdUsernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\t\tusernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\t\tcreatedUsernameFromServer2,\n\t\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t\t);\n\n\t\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2, userFromServer1UsernameOnly]);\n\n\t\t\t\t\tawait poFederationChannelServer1.sidenav.openDMMultipleChat(usernameWithDomainFromServer2);\n\t\t\t\t\tawait poFederationChannel1ForUser2.sidenav.openDMMultipleChat(usernameWithDomainFromServer2);\n\t\t\t\t\tawait poFederationChannelServer1.content.sendMessage('hello world from server A (creator)');\n\n\t\t\t\t\tawait poFederationChannelServer2.sidenav.openDMMultipleChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('hello world from server A (creator)');\n\t\t\t\t\tawait expect(poFederationChannel1ForUser2.content.lastUserMessage.locator('p')).toHaveText('hello world from server A (creator)');\n\t\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('hello world from server A (creator)');\n\t\t\t\t\tawait pageForServer2.close();\n\t\t\t\t\tawait page2.close();\n\t\t\t\t});\n\n\t\t\t\ttest('expect to send a message from Server A (user 2) to Server B', async ({ browser }) => {\n\t\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\t\tconst poFederationChannel1ForUser2 = new FederationChannel(page2);\n\t\t\t\t\tconst pageForServer2 = await browser.newPage();\n\t\t\t\t\tconst poFederationChannelServer2 = new FederationChannel(pageForServer2);\n\n\t\t\t\t\tawait doLogin({\n\t\t\t\t\t\tpage: pageForServer2,\n\t\t\t\t\t\tserver: {\n\t\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\t\tusername: createdUsernameFromServer2,\n\t\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstoreState: false,\n\t\t\t\t\t});\n\t\t\t\t\tawait doLogin({\n\t\t\t\t\t\tpage: page2,\n\t\t\t\t\t\tserver: {\n\t\t\t\t\t\t\turl: constants.RC_SERVER_1.url,\n\t\t\t\t\t\t\tusername: userFromServer1UsernameOnly,\n\t\t\t\t\t\t\tpassword: constants.RC_SERVER_1.password,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstoreState: false,\n\t\t\t\t\t});\n\n\t\t\t\t\tawait page2.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\t\tawait poFederationChannel1ForUser2.sidenav.openDMMultipleChat(usernameWithDomainFromServer2);\n\t\t\t\t\tawait poFederationChannelServer1.sidenav.openDMMultipleChat(usernameWithDomainFromServer2);\n\t\t\t\t\tawait poFederationChannelServer2.sidenav.openDMMultipleChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\t\tawait poFederationChannel1ForUser2.content.sendMessage('hello world from server A (user 2)');\n\t\t\t\t\tawait poFederationChannel1ForUser2.content.sendMessage('hello world from server A (user 2) message 2');\n\n\t\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t\t'hello world from server A (user 2) message 2',\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(poFederationChannel1ForUser2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t\t'hello world from server A (user 2) message 2',\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t\t'hello world from server A (user 2) message 2',\n\t\t\t\t\t);\n\n\t\t\t\t\tawait page2.close();\n\t\t\t\t\tawait pageForServer2.close();\n\t\t\t\t});\n\n\t\t\t\ttest('expect to send a message from Server B to Server A', async ({ page, browser }) => {\n\t\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\t\tconst poFederationChannel1ForUser2 = new FederationChannel(page2);\n\t\t\t\t\tconst pageForServer2 = await browser.newPage();\n\t\t\t\t\tconst poFederationChannelServer2 = new FederationChannel(pageForServer2);\n\n\t\t\t\t\tawait doLogin({\n\t\t\t\t\t\tpage: pageForServer2,\n\t\t\t\t\t\tserver: {\n\t\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\t\tusername: createdUsernameFromServer2,\n\t\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstoreState: false,\n\t\t\t\t\t});\n\t\t\t\t\tawait doLogin({\n\t\t\t\t\t\tpage: page2,\n\t\t\t\t\t\tserver: {\n\t\t\t\t\t\t\turl: constants.RC_SERVER_1.url,\n\t\t\t\t\t\t\tusername: userFromServer1UsernameOnly,\n\t\t\t\t\t\t\tpassword: constants.RC_SERVER_1.password,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstoreState: false,\n\t\t\t\t\t});\n\t\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\t\tawait poFederationChannelServer1.sidenav.openDMMultipleChat(usernameWithDomainFromServer2);\n\t\t\t\t\tawait poFederationChannel1ForUser2.sidenav.openDMMultipleChat(usernameWithDomainFromServer2);\n\t\t\t\t\tawait poFederationChannelServer2.sidenav.openDMMultipleChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\t\tawait poFederationChannelServer2.content.sendMessage('hello world from server B');\n\n\t\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t\t\tawait expect(poFederationChannel1ForUser2.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t\t\tawait pageForServer2.close();\n\t\t\t\t\tawait page2.close();\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\ttest.describe('Send \"Special\" messages', () => {\n\t\t\ttest('expect to send a message with emojis from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('😀 😀 hello world 🌎 from server A with emojis 😀 😀');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t'😀 😀 hello world 🌎 from server A with emojis 😀 😀',\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t'😀 😀 hello world 🌎 from server A with emojis 😀 😀',\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('expect to send a message with emojis from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessage('😀 😀 hello world 🌎 from server B with emojis 😀 😀');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t'😀 😀 hello world 🌎 from server B with emojis 😀 😀',\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t'😀 😀 hello world 🌎 from server B with emojis 😀 😀',\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('expect to send an audio message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendAudioRecordedMessage();\n\n\t\t\t\tawait expect(await (await poFederationChannelServer1.content.getLastFileMessageByFileName('Audio record.mp3')).innerText()).toEqual(\n\t\t\t\t\t'Audio record.mp3',\n\t\t\t\t);\n\t\t\t\tawait expect(await (await poFederationChannelServer2.content.getLastFileMessageByFileName('Audio record.mp3')).innerText()).toEqual(\n\t\t\t\t\t'Audio record.mp3',\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('audio')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('audio')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send an audio message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendAudioRecordedMessage();\n\n\t\t\t\tawait expect(await (await poFederationChannelServer2.content.getLastFileMessageByFileName('Audio record.mp3')).innerText()).toEqual(\n\t\t\t\t\t'Audio record.mp3',\n\t\t\t\t);\n\t\t\t\tawait expect(await (await poFederationChannelServer1.content.getLastFileMessageByFileName('Audio record.mp3')).innerText()).toEqual(\n\t\t\t\t\t'Audio record.mp3',\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('audio')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('audio')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a video message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendVideoRecordedMessage();\n\n\t\t\t\tawait expect(\n\t\t\t\t\tawait (await poFederationChannelServer1.content.getLastFileMessageByFileName('Video record.webm')).innerText(),\n\t\t\t\t).toEqual('Video record.webm');\n\t\t\t\tawait expect(\n\t\t\t\t\tawait (await poFederationChannelServer2.content.getLastFileMessageByFileName('Video record.webm')).innerText(),\n\t\t\t\t).toEqual('Video record.webm');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a video message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendVideoRecordedMessage();\n\n\t\t\t\tawait expect(\n\t\t\t\t\tawait (await poFederationChannelServer2.content.getLastFileMessageByFileName('Video record.webm')).innerText(),\n\t\t\t\t).toEqual('Video record.webm');\n\t\t\t\tawait expect(\n\t\t\t\t\tawait (await poFederationChannelServer1.content.getLastFileMessageByFileName('Video record.webm')).innerText(),\n\t\t\t\t).toEqual('Video record.webm');\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (image) from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendFileMessage('test_image.jpeg');\n\t\t\t\tawait poFederationChannelServer1.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.getLastFileName).toContainText('test_image.jpeg');\n\t\t\t\tawait expect(poFederationChannelServer2.content.getLastFileName).toContainText('test_image.jpeg');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.getLastFileAttachmentContent.locator('img')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.getLastFileAttachmentContent.locator('img')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (image) from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendFileMessage('test_image.jpeg');\n\t\t\t\tawait poFederationChannelServer2.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.getLastFileName).toContainText('test_image.jpeg');\n\t\t\t\tawait expect(poFederationChannelServer1.content.getLastFileName).toContainText('test_image.jpeg');\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.getLastFileAttachmentContent.locator('img')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer1.content.getLastFileAttachmentContent.locator('img')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (video) from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendFileMessage('test_video.mp4');\n\t\t\t\tawait poFederationChannelServer1.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(await (await poFederationChannelServer1.content.getLastFileMessageByFileName('test_video.mp4')).innerText()).toEqual(\n\t\t\t\t\t'test_video.mp4',\n\t\t\t\t);\n\t\t\t\tawait expect(await (await poFederationChannelServer2.content.getLastFileMessageByFileName('test_video.mp4')).innerText()).toEqual(\n\t\t\t\t\t'test_video.mp4',\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (video) from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendFileMessage('test_video.mp4');\n\t\t\t\tawait poFederationChannelServer2.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(await (await poFederationChannelServer2.content.getLastFileMessageByFileName('test_video.mp4')).innerText()).toEqual(\n\t\t\t\t\t'test_video.mp4',\n\t\t\t\t);\n\t\t\t\tawait expect(await (await poFederationChannelServer1.content.getLastFileMessageByFileName('test_video.mp4')).innerText()).toEqual(\n\t\t\t\t\t'test_video.mp4',\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (pdf) from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendFileMessage('test_pdf_file.pdf');\n\t\t\t\tawait poFederationChannelServer1.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastMessageFileName).toContainText('test_pdf_file.pdf');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastMessageFileName).toContainText('test_pdf_file.pdf');\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (pdf) from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendFileMessage('test_pdf_file.pdf');\n\t\t\t\tawait poFederationChannelServer2.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastMessageFileName).toContainText('test_pdf_file.pdf');\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastMessageFileName).toContainText('test_pdf_file.pdf');\n\t\t\t});\n\n\t\t\ttest('expect to send a message mentioning an user from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer1.content.inputMessage.type(`@${userFromServer2UsernameOnly}`);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.messagePopUpItems.locator(`text=${usernameWithDomainFromServer2}`)).toBeVisible();\n\n\t\t\t\tawait poFederationChannelServer2.content.inputMessage.type(`@${constants.RC_SERVER_1.username}`);\n\n\t\t\t\tawait expect(\n\t\t\t\t\tpoFederationChannelServer2.content.messagePopUpItems.locator(`text=${adminUsernameWithDomainFromServer1}`),\n\t\t\t\t).toBeVisible();\n\n\t\t\t\tawait poFederationChannelServer1.content.inputMessage.fill('');\n\t\t\t\tawait poFederationChannelServer2.content.inputMessage.fill('');\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage(\n\t\t\t\t\t`hello @${usernameWithDomainFromServer2}, here's @${constants.RC_SERVER_1.username} from Server A`,\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${usernameWithDomainFromServer2}, here's ${constants.RC_SERVER_1.username} from Server A`,\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${userFromServer2UsernameOnly}, here's ${adminUsernameWithDomainFromServer1} from Server A`,\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('expect to send a message mentioning an user Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer2.content.inputMessage.type(`@${constants.RC_SERVER_1.username}`);\n\n\t\t\t\tawait expect(\n\t\t\t\t\tpoFederationChannelServer2.content.messagePopUpItems.locator(`text=${adminUsernameWithDomainFromServer1}`),\n\t\t\t\t).toBeVisible();\n\n\t\t\t\tawait poFederationChannelServer1.content.inputMessage.type(`@${userFromServer2UsernameOnly}`);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.messagePopUpItems.locator(`text=${usernameWithDomainFromServer2}`)).toBeVisible();\n\n\t\t\t\tawait poFederationChannelServer1.content.inputMessage.fill('');\n\t\t\t\tawait poFederationChannelServer2.content.inputMessage.fill('');\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessage(\n\t\t\t\t\t`hello @${adminUsernameWithDomainFromServer1}, here's @${userFromServer2UsernameOnly} from Server B`,\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${constants.RC_SERVER_1.username}, here's ${usernameWithDomainFromServer2} from Server B`,\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${adminUsernameWithDomainFromServer1}, here's ${userFromServer2UsernameOnly} from Server B`,\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('expect to send a message with multiple mentions, including @all from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage(\n\t\t\t\t\t`hello @${usernameWithDomainFromServer2}, here's @${constants.RC_SERVER_1.username} from Server A, @all, @${usernameWithDomainFromServer2}`,\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${usernameWithDomainFromServer2}, here's ${constants.RC_SERVER_1.username} from Server A, all, ${usernameWithDomainFromServer2}`,\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${userFromServer2UsernameOnly}, here's ${adminUsernameWithDomainFromServer1} from Server A, all, ${userFromServer2UsernameOnly}`,\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\ttest.describe('Message actions', () => {\n\t\t\ttest('expect to send a message quoting a message from Server A to Server B', async ({ browser, apiServer2, page }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tconst message = `Message for quote - ${Date.now()}`;\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter(message);\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\t\t\t\tawait poFederationChannelServer1.content.quoteMessage('this is a quote message');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to send a message quoting a message Server B to Server A', async ({ browser, apiServer2, page }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tconst message = `Message for quote - ${Date.now()}`;\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter(message);\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\t\t\t\tawait poFederationChannelServerUser2.content.quoteMessage('this is a quote message');\n\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServer1.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to react a message from Server A to Server B', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer1.content.reactToMessage('slight_smile');\n\n\t\t\t\tconst reactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\tconst reactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText('🙂');\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText('1');\n\t\t\t\t}\n\t\t\t\tconst reactionsServer2 = await poFederationChannelServerUser2.content.getAllReactions();\n\t\t\t\tconst reactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText('🙂');\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText('1');\n\t\t\t\t}\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to react a message from Server B to Server A', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServerUser2.content.reactToMessage('slight_smile');\n\n\t\t\t\tconst reactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\tconst reactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText('🙂');\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText('1');\n\t\t\t\t}\n\t\t\t\tconst reactionsServer2 = await poFederationChannelServerUser2.content.getAllReactions();\n\t\t\t\tconst reactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText('🙂');\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText('1');\n\t\t\t\t}\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to unreact a message from Server A to Server B', async ({ page, apiServer2 }) => {\n\t\t\t\tawait poFederationChannelServer2.sidenav.logout();\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: pageForServer2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer1.content.reactToMessage('slight_smile');\n\t\t\t\tawait poFederationChannelServer1.content.reactToMessage('grin');\n\n\t\t\t\tlet reactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\tlet reactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tconst reactionsMap: any = {\n\t\t\t\t\t0: {\n\t\t\t\t\t\temoji: '🙂',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t\t1: {\n\t\t\t\t\t\temoji: '😁',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(reactionsMap[i].emoji);\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(reactionsMap[i].count);\n\t\t\t\t}\n\t\t\t\tlet reactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\tlet reactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(reactionsMap[i].emoji);\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(reactionsMap[i].count);\n\t\t\t\t}\n\n\t\t\t\tawait poFederationChannelServer1.content.unreactLastMessage();\n\t\t\t\tawait pageForServer2.reload({ waitUntil: 'domcontentloaded' });\n\n\t\t\t\treactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\treactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\n\t\t\t\tconst reactionsMapAfterUnreaction: any = {\n\t\t\t\t\t0: {\n\t\t\t\t\t\temoji: '🙂',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].emoji,\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].count,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\treactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].emoji,\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].count,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\ttest('expect to unreact a message from Server B to Server A', async ({ page, apiServer2 }) => {\n\t\t\t\tawait poFederationChannelServer2.sidenav.logout();\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: pageForServer2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer2.content.reactToMessage('slight_smile');\n\t\t\t\tawait poFederationChannelServer2.content.reactToMessage('grin');\n\n\t\t\t\tlet reactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\tlet reactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tconst reactionsMap: any = {\n\t\t\t\t\t0: {\n\t\t\t\t\t\temoji: '🙂',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t\t1: {\n\t\t\t\t\t\temoji: '😁',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(reactionsMap[i].emoji);\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(reactionsMap[i].count);\n\t\t\t\t}\n\t\t\t\tlet reactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\tlet reactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(reactionsMap[i].emoji);\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(reactionsMap[i].count);\n\t\t\t\t}\n\n\t\t\t\tawait poFederationChannelServer2.content.unreactLastMessage();\n\t\t\t\tawait pageForServer2.reload({ waitUntil: 'domcontentloaded' });\n\n\t\t\t\treactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\treactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\n\t\t\t\tconst reactionsMapAfterUnreaction: any = {\n\t\t\t\t\t0: {\n\t\t\t\t\t\temoji: '🙂',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].emoji,\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].count,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\treactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].emoji,\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].count,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\ttest('expect to edit a message from Server A to Server B', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('message');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.editLastMessage('message from Server A - Edited');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A - Edited');\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server A - Edited');\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to edit a message from Server B to Server A', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('message');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServerUser2.content.sendMessageUsingEnter('message from Server B');\n\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server B');\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server B');\n\n\t\t\t\tawait poFederationChannelServerUser2.content.editLastMessage('message from Server B - Edited');\n\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server B - Edited');\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server B - Edited');\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to delete a message from Server A to Server B', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.deleteLastMessage();\n\t\t\t\tawait expect(poFederationChannelServer1.toastSuccess).toBeVisible();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage).not.toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage).not.toBeVisible();\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to delete a message from Server B to Server A', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.deleteLastMessage();\n\t\t\t\tawait page.waitForTimeout(2000);\n\t\t\t\tawait poFederationChannelServerUser2.content.sendMessageUsingEnter('message from Server B');\n\t\t\t\tawait poFederationChannelServerUser2.content.deleteLastMessage();\n\t\t\t\tawait expect(poFederationChannelServerUser2.toastSuccess).toBeVisible();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage).not.toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage).not.toBeVisible();\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to star a message on Server A', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('message');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.starLastMessage();\n\t\t\t\tawait expect(\n\t\t\t\t\tpoFederationChannelServer1.toastSuccess.locator('div.rcx-toastbar-content', { hasText: 'Message has been starred' }),\n\t\t\t\t).toBeVisible();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('.rcx-icon--name-star-filled')).toBeVisible();\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to star a message on Server B', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('message');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServerUser2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServerUser2.content.starLastMessage();\n\t\t\t\tawait expect(\n\t\t\t\t\tpoFederationChannelServerUser2.toastSuccess.locator('div.rcx-toastbar-content', { hasText: 'Message has been starred' }),\n\t\t\t\t).toBeVisible();\n\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('.rcx-icon--name-star-filled')).toBeVisible();\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to reply in thread in Server A', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('message');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer1.content.btnOptionReplyInThread).not.toBeVisible();\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to reply in thread in Server B', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('message');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServerUser2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServerUser2.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.btnOptionReplyInThread).not.toBeVisible();\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to start a discussion from a message in thread in Server A', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('message');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer1.content.btnOptionStartDiscussion).not.toBeVisible();\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to start a discussion from a message in thread in Server B', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('message');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServerUser2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServerUser2.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.btnOptionStartDiscussion).not.toBeVisible();\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to pin a message in Server A', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('message');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServerUser2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer1.content.btnOptionPinMessage).not.toBeVisible();\n\t\t\t\tawait page2.close();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to pin a message in Server B', async ({ browser, page, apiServer2 }) => {\n\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\tconst poFederationChannelServerUser2 = new FederationChannel(page2);\n\t\t\t\tconst usernameFromServer2 = await registerUser(apiServer2);\n\n\t\t\t\tawait doLogin({\n\t\t\t\t\tpage: page2,\n\t\t\t\t\tserver: {\n\t\t\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\t\t\tusername: usernameFromServer2,\n\t\t\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t\t\t},\n\t\t\t\t\tstoreState: false,\n\t\t\t\t});\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait page2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(usernameFromServer2, constants.RC_SERVER_2.matrixServerName);\n\t\t\t\tconst usernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\t\t\tusernameFromServer2,\n\t\t\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t\t\t);\n\t\t\t\tawait poFederationChannelServer1.createDirectMessagesUsingModal([fullUsernameFromServer2]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('message');\n\t\t\t\tawait poFederationChannelServerUser2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait poFederationChannelServerUser2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServerUser2.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServerUser2.content.btnOptionPinMessage).not.toBeVisible();\n\t\t\t\tawait page2.close();\n\t\t\t});\n\t\t});\n\n\t\ttest.describe('Visual Elements', () => {\n\t\t\ttest('expect to see the file list sent in the DM on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnFileList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to see the file list sent in the DM on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnFileList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to see all the starred messages sent in the DM on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnStarredMessagesList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to see all the starred messages sent in the DM on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\t\t\t\tawait poFederationChannelServer2.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnStarredMessagesList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not to see the pinned messages sent in the DM on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnPinnedMessagesList).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not to see the pinned messages sent in the DM on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\t\t\t\tawait poFederationChannelServer2.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnPinnedMessagesList).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to prune messages sent in the DM on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\t\t\t\tawait poFederationChannelServer1.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnPruneMessages).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to prune messages sent in the DM on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\t\t\t\tawait poFederationChannelServer2.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnPruneMessages).not.toBeVisible();\n\t\t\t});\n\t\t});\n\t});\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/messaging/private.spec.ts",["23215","23216","23217","23218"],[],"/* eslint no-await-in-loop: 0 */\nimport faker from '@faker-js/faker';\nimport type { Page } from '@playwright/test';\n\nimport * as constants from '../../config/constants';\nimport { FederationChannel } from '../../page-objects/channel';\nimport { doLogin } from '../../utils/auth';\nimport { createGroupAndInviteRemoteUserToCreateLocalUser } from '../../utils/channel';\nimport { formatIntoFullMatrixUsername, formatUsernameAndDomainIntoMatrixFormat } from '../../utils/format';\nimport { registerUser } from '../../utils/register-user';\nimport { test, expect, setupTesting, tearDownTesting } from '../../utils/test';\n\ntest.describe.parallel('Federation - Group Messaging', () => {\n\tlet poFederationChannelServer1: FederationChannel;\n\tlet poFederationChannelServer2: FederationChannel;\n\tlet userFromServer2UsernameOnly: string;\n\tlet userFromServer1UsernameOnly: string;\n\tlet createdGroupName: string;\n\tlet usernameWithDomainFromServer2: string;\n\tconst adminUsernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(\n\t\tconstants.RC_SERVER_1.username,\n\t\tconstants.RC_SERVER_1.matrixServerName,\n\t);\n\tlet pageForServer2: Page;\n\n\ttest.beforeAll(async ({ apiServer1, apiServer2, browser }) => {\n\t\tawait setupTesting(apiServer1);\n\t\tawait setupTesting(apiServer2);\n\t\tuserFromServer1UsernameOnly = await registerUser(apiServer1);\n\t\tuserFromServer2UsernameOnly = await registerUser(apiServer2);\n\t\tusernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\tuserFromServer2UsernameOnly,\n\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t);\n\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(userFromServer2UsernameOnly, constants.RC_SERVER_2.matrixServerName);\n\t\tconst page = await browser.newPage();\n\t\tpoFederationChannelServer1 = new FederationChannel(page);\n\t\tcreatedGroupName = await createGroupAndInviteRemoteUserToCreateLocalUser({\n\t\t\tpage,\n\t\t\tpoFederationChannelServer: poFederationChannelServer1,\n\t\t\tfullUsernameFromServer: fullUsernameFromServer2,\n\t\t\tserver: constants.RC_SERVER_1,\n\t\t});\n\t});\n\n\ttest.afterAll(async ({ apiServer1, apiServer2 }) => {\n\t\tawait tearDownTesting(apiServer1);\n\t\tawait tearDownTesting(apiServer2);\n\t});\n\n\ttest.beforeEach(async ({ page, browser }) => {\n\t\tpageForServer2 = await browser.newPage();\n\n\t\tpoFederationChannelServer1 = new FederationChannel(page);\n\t\tawait doLogin({\n\t\t\tpage,\n\t\t\tserver: {\n\t\t\t\turl: constants.RC_SERVER_1.url,\n\t\t\t\tusername: constants.RC_SERVER_1.username,\n\t\t\t\tpassword: constants.RC_SERVER_1.password,\n\t\t\t},\n\t\t});\n\n\t\tpoFederationChannelServer2 = new FederationChannel(pageForServer2);\n\t\tawait doLogin({\n\t\t\tpage: pageForServer2,\n\t\t\tserver: {\n\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\tusername: userFromServer2UsernameOnly,\n\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t},\n\t\t\tstoreState: false,\n\t\t});\n\n\t\tawait page.addInitScript(() => {\n\t\t\twindow.localStorage.setItem('fuselage-localStorage-members-list-type', JSON.stringify('online'));\n\t\t});\n\t});\n\n\ttest.afterEach(async ({ page }) => {\n\t\tawait page.close();\n\t\tawait pageForServer2.close();\n\t});\n\n\ttest.describe('Messaging - Group (Private)', () => {\n\t\ttest.describe('Send message', () => {\n\t\t\ttest('expect to send a message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('hello world from server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('hello world from server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('hello world from server A');\n\t\t\t});\n\n\t\t\ttest('expect to send a message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.content.sendMessage('hello world from server B');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t});\n\n\t\t\ttest.describe('With multiple users', () => {\n\t\t\t\tconst createdGroup = faker.datatype.uuid();\n\n\t\t\t\ttest('expect to send a message from Server A (creator) to Server B', async ({ browser, page }) => {\n\t\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\t\tconst poFederationChannel1ForUser2 = new FederationChannel(page2);\n\n\t\t\t\t\tawait doLogin({\n\t\t\t\t\t\tpage: page2,\n\t\t\t\t\t\tserver: {\n\t\t\t\t\t\t\turl: constants.RC_SERVER_1.url,\n\t\t\t\t\t\t\tusername: userFromServer1UsernameOnly,\n\t\t\t\t\t\t\tpassword: constants.RC_SERVER_1.password,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstoreState: false,\n\t\t\t\t\t});\n\t\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(createdGroup, [\n\t\t\t\t\t\tuserFromServer2UsernameOnly,\n\t\t\t\t\t\tuserFromServer1UsernameOnly,\n\t\t\t\t\t]);\n\n\t\t\t\t\tawait expect(page).toHaveURL(`${constants.RC_SERVER_1.url}/group/${createdGroup}`);\n\n\t\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroup);\n\t\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroup);\n\t\t\t\t\tawait poFederationChannel1ForUser2.sidenav.openChat(createdGroup);\n\n\t\t\t\t\tawait poFederationChannelServer1.content.sendMessage('hello world from server A (creator)');\n\n\t\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('hello world from server A (creator)');\n\t\t\t\t\tawait expect(poFederationChannel1ForUser2.content.lastUserMessage.locator('p')).toHaveText('hello world from server A (creator)');\n\t\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('hello world from server A (creator)');\n\t\t\t\t\tawait pageForServer2.close();\n\t\t\t\t\tawait page2.close();\n\t\t\t\t});\n\n\t\t\t\ttest('expect to send a message from Server A (user 2) to Server B', async ({ browser }) => {\n\t\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\t\tconst poFederationChannel1ForUser2 = new FederationChannel(page2);\n\t\t\t\t\tawait doLogin({\n\t\t\t\t\t\tpage: page2,\n\t\t\t\t\t\tserver: {\n\t\t\t\t\t\t\turl: constants.RC_SERVER_1.url,\n\t\t\t\t\t\t\tusername: userFromServer1UsernameOnly,\n\t\t\t\t\t\t\tpassword: constants.RC_SERVER_1.password,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstoreState: false,\n\t\t\t\t\t});\n\n\t\t\t\t\tawait page2.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\t\tawait poFederationChannel1ForUser2.sidenav.openChat(createdGroup);\n\t\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroup);\n\t\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroup);\n\n\t\t\t\t\tawait poFederationChannel1ForUser2.content.sendMessage('hello world from server A (user 2)');\n\t\t\t\t\tawait poFederationChannel1ForUser2.content.sendMessage('hello world from server A (user 2) message 2');\n\n\t\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t\t'hello world from server A (user 2) message 2',\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t\t'hello world from server A (user 2) message 2',\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(poFederationChannel1ForUser2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t\t'hello world from server A (user 2) message 2',\n\t\t\t\t\t);\n\n\t\t\t\t\tawait page2.close();\n\t\t\t\t\tawait pageForServer2.close();\n\t\t\t\t});\n\n\t\t\t\ttest('expect to send a message from Server B to Server A', async ({ browser, page }) => {\n\t\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\t\tconst poFederationChannel1ForUser2 = new FederationChannel(page2);\n\t\t\t\t\tawait doLogin({\n\t\t\t\t\t\tpage: page2,\n\t\t\t\t\t\tserver: {\n\t\t\t\t\t\t\turl: constants.RC_SERVER_1.url,\n\t\t\t\t\t\t\tusername: userFromServer1UsernameOnly,\n\t\t\t\t\t\t\tpassword: constants.RC_SERVER_1.password,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstoreState: false,\n\t\t\t\t\t});\n\t\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroup);\n\t\t\t\t\tawait poFederationChannel1ForUser2.sidenav.openChat(createdGroup);\n\t\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroup);\n\n\t\t\t\t\tawait expect(page).toHaveURL(`${constants.RC_SERVER_1.url}/group/${createdGroup}`);\n\n\t\t\t\t\tawait poFederationChannelServer2.content.sendMessage('hello world from server B');\n\n\t\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t\t\tawait expect(poFederationChannel1ForUser2.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t\t\tawait pageForServer2.close();\n\t\t\t\t\tawait page2.close();\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\ttest.describe('Send \"Special\" messages', () => {\n\t\t\ttest('expect to send a message with emojis from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('😀 😀 hello world 🌎 from server A with emojis 😀 😀');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t'😀 😀 hello world 🌎 from server A with emojis 😀 😀',\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t'😀 😀 hello world 🌎 from server A with emojis 😀 😀',\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('expect to send a message with emojis from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessage('😀 😀 hello world 🌎 from server B with emojis 😀 😀');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t'😀 😀 hello world 🌎 from server B with emojis 😀 😀',\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t'😀 😀 hello world 🌎 from server B with emojis 😀 😀',\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('expect to send an audio message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendAudioRecordedMessage();\n\n\t\t\t\tawait expect(await (await poFederationChannelServer1.content.getLastFileMessageByFileName('Audio record.mp3')).innerText()).toEqual(\n\t\t\t\t\t'Audio record.mp3',\n\t\t\t\t);\n\t\t\t\tawait expect(await (await poFederationChannelServer2.content.getLastFileMessageByFileName('Audio record.mp3')).innerText()).toEqual(\n\t\t\t\t\t'Audio record.mp3',\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('audio')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('audio')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send an audio message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendAudioRecordedMessage();\n\n\t\t\t\tawait expect(await (await poFederationChannelServer2.content.getLastFileMessageByFileName('Audio record.mp3')).innerText()).toEqual(\n\t\t\t\t\t'Audio record.mp3',\n\t\t\t\t);\n\t\t\t\tawait expect(await (await poFederationChannelServer1.content.getLastFileMessageByFileName('Audio record.mp3')).innerText()).toEqual(\n\t\t\t\t\t'Audio record.mp3',\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('audio')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('audio')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a video message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendVideoRecordedMessage();\n\n\t\t\t\tawait expect(\n\t\t\t\t\tawait (await poFederationChannelServer1.content.getLastFileMessageByFileName('Video record.webm')).innerText(),\n\t\t\t\t).toEqual('Video record.webm');\n\t\t\t\tawait expect(\n\t\t\t\t\tawait (await poFederationChannelServer2.content.getLastFileMessageByFileName('Video record.webm')).innerText(),\n\t\t\t\t).toEqual('Video record.webm');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a video message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendVideoRecordedMessage();\n\n\t\t\t\tawait expect(\n\t\t\t\t\tawait (await poFederationChannelServer2.content.getLastFileMessageByFileName('Video record.webm')).innerText(),\n\t\t\t\t).toEqual('Video record.webm');\n\t\t\t\tawait expect(\n\t\t\t\t\tawait (await poFederationChannelServer1.content.getLastFileMessageByFileName('Video record.webm')).innerText(),\n\t\t\t\t).toEqual('Video record.webm');\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (image) from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendFileMessage('test_image.jpeg');\n\t\t\t\tawait poFederationChannelServer1.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.getLastFileName).toContainText('test_image.jpeg');\n\t\t\t\tawait expect(poFederationChannelServer2.content.getLastFileName).toContainText('test_image.jpeg');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.getLastFileAttachmentContent.locator('img')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.getLastFileAttachmentContent.locator('img')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (image) from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendFileMessage('test_image.jpeg');\n\t\t\t\tawait poFederationChannelServer2.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.getLastFileName).toContainText('test_image.jpeg');\n\t\t\t\tawait expect(poFederationChannelServer1.content.getLastFileName).toContainText('test_image.jpeg');\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.getLastFileAttachmentContent.locator('img')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer1.content.getLastFileAttachmentContent.locator('img')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (video) from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendFileMessage('test_video.mp4');\n\t\t\t\tawait poFederationChannelServer1.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(await (await poFederationChannelServer1.content.getLastFileMessageByFileName('test_video.mp4')).innerText()).toEqual(\n\t\t\t\t\t'test_video.mp4',\n\t\t\t\t);\n\t\t\t\tawait expect(await (await poFederationChannelServer2.content.getLastFileMessageByFileName('test_video.mp4')).innerText()).toEqual(\n\t\t\t\t\t'test_video.mp4',\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (video) from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendFileMessage('test_video.mp4');\n\t\t\t\tawait poFederationChannelServer2.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(await (await poFederationChannelServer2.content.getLastFileMessageByFileName('test_video.mp4')).innerText()).toEqual(\n\t\t\t\t\t'test_video.mp4',\n\t\t\t\t);\n\t\t\t\tawait expect(await (await poFederationChannelServer1.content.getLastFileMessageByFileName('test_video.mp4')).innerText()).toEqual(\n\t\t\t\t\t'test_video.mp4',\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (pdf) from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendFileMessage('test_pdf_file.pdf');\n\t\t\t\tawait poFederationChannelServer1.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastMessageFileName).toContainText('test_pdf_file.pdf');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastMessageFileName).toContainText('test_pdf_file.pdf');\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (pdf) from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendFileMessage('test_pdf_file.pdf');\n\t\t\t\tawait poFederationChannelServer2.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastMessageFileName).toContainText('test_pdf_file.pdf');\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastMessageFileName).toContainText('test_pdf_file.pdf');\n\t\t\t});\n\n\t\t\ttest('expect to send a message mentioning an user from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.inputMessage.type(`@${userFromServer2UsernameOnly}`);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.messagePopUpItems.locator(`text=${usernameWithDomainFromServer2}`)).toBeVisible();\n\n\t\t\t\tawait poFederationChannelServer2.content.inputMessage.type(`@${constants.RC_SERVER_1.username}`);\n\n\t\t\t\tawait expect(\n\t\t\t\t\tpoFederationChannelServer2.content.messagePopUpItems.locator(`text=${adminUsernameWithDomainFromServer1}`),\n\t\t\t\t).toBeVisible();\n\n\t\t\t\tawait poFederationChannelServer1.content.inputMessage.fill('');\n\t\t\t\tawait poFederationChannelServer2.content.inputMessage.fill('');\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage(\n\t\t\t\t\t`hello @${usernameWithDomainFromServer2}, here's @${constants.RC_SERVER_1.username} from Server A`,\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${usernameWithDomainFromServer2}, here's ${constants.RC_SERVER_1.username} from Server A`,\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${userFromServer2UsernameOnly}, here's ${adminUsernameWithDomainFromServer1} from Server A`,\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('expect to send a message mentioning an user Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.inputMessage.type(`@${constants.RC_SERVER_1.username}`);\n\n\t\t\t\tawait expect(\n\t\t\t\t\tpoFederationChannelServer2.content.messagePopUpItems.locator(`text=${adminUsernameWithDomainFromServer1}`),\n\t\t\t\t).toBeVisible();\n\n\t\t\t\tawait poFederationChannelServer1.content.inputMessage.type(`@${userFromServer2UsernameOnly}`);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.messagePopUpItems.locator(`text=${usernameWithDomainFromServer2}`)).toBeVisible();\n\n\t\t\t\tawait poFederationChannelServer1.content.inputMessage.fill('');\n\t\t\t\tawait poFederationChannelServer2.content.inputMessage.fill('');\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessage(\n\t\t\t\t\t`hello @${adminUsernameWithDomainFromServer1}, here's @${userFromServer2UsernameOnly} from Server B`,\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${constants.RC_SERVER_1.username}, here's ${usernameWithDomainFromServer2} from Server B`,\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${adminUsernameWithDomainFromServer1}, here's ${userFromServer2UsernameOnly} from Server B`,\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('expect to send a message with multiple mentions, including @all from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage(\n\t\t\t\t\t`hello @${usernameWithDomainFromServer2}, here's @${constants.RC_SERVER_1.username} from Server A, @all, @${usernameWithDomainFromServer2}`,\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${usernameWithDomainFromServer2}, here's ${constants.RC_SERVER_1.username} from Server A, all, ${usernameWithDomainFromServer2}`,\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${userFromServer2UsernameOnly}, here's ${adminUsernameWithDomainFromServer1} from Server A, all, ${userFromServer2UsernameOnly}`,\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\ttest.describe('Message actions', () => {\n\t\t\ttest('expect to send a message quoting a message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tconst message = `Message for quote - ${Date.now()}`;\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessage(message);\n\t\t\t\tawait poFederationChannelServer1.content.quoteMessage('this is a quote message');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServer2.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t});\n\n\t\t\ttest('expect to send a message quoting a message Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tconst message = `Message for quote - ${Date.now()}`;\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage(message);\n\t\t\t\tawait poFederationChannelServer2.content.quoteMessage('this is a quote message');\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServer1.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t});\n\n\t\t\ttest('expect to react a message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServer1.content.reactToMessage('slight_smile');\n\n\t\t\t\tconst reactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\tconst reactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText('🙂');\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText('1');\n\t\t\t\t}\n\t\t\t\tconst reactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\tconst reactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText('🙂');\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText('1');\n\t\t\t\t}\n\t\t\t});\n\n\t\t\ttest('expect to react a message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServer2.content.reactToMessage('slight_smile');\n\n\t\t\t\tconst reactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\tconst reactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText('🙂');\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText('1');\n\t\t\t\t}\n\t\t\t\tconst reactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\tconst reactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText('🙂');\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText('1');\n\t\t\t\t}\n\t\t\t});\n\n\t\t\ttest('expect to unreact a message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServer1.content.reactToMessage('slight_smile');\n\t\t\t\tawait poFederationChannelServer1.content.reactToMessage('grin');\n\t\t\t\tawait page.reload();\n\n\t\t\t\tlet reactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\tlet reactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tconst reactionsMap: any = {\n\t\t\t\t\t0: {\n\t\t\t\t\t\temoji: '🙂',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t\t1: {\n\t\t\t\t\t\temoji: '😁',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(reactionsMap[i].emoji);\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(reactionsMap[i].count);\n\t\t\t\t}\n\t\t\t\tlet reactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\tlet reactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(reactionsMap[i].emoji);\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(reactionsMap[i].count);\n\t\t\t\t}\n\n\t\t\t\tawait poFederationChannelServer1.content.unreactLastMessage();\n\t\t\t\tawait pageForServer2.reload();\n\n\t\t\t\treactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\treactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\n\t\t\t\tconst reactionsMapAfterUnreaction: any = {\n\t\t\t\t\t0: {\n\t\t\t\t\t\temoji: '🙂',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].emoji,\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].count,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\treactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].emoji,\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].count,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\ttest('expect to unreact a message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServer2.content.reactToMessage('slight_smile');\n\t\t\t\tawait poFederationChannelServer2.content.reactToMessage('grin');\n\t\t\t\tawait page.reload();\n\n\t\t\t\tlet reactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\tlet reactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tconst reactionsMap: any = {\n\t\t\t\t\t0: {\n\t\t\t\t\t\temoji: '🙂',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t\t1: {\n\t\t\t\t\t\temoji: '😁',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(reactionsMap[i].emoji);\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(reactionsMap[i].count);\n\t\t\t\t}\n\t\t\t\tlet reactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\tlet reactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(reactionsMap[i].emoji);\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(reactionsMap[i].count);\n\t\t\t\t}\n\n\t\t\t\tawait poFederationChannelServer2.content.unreactLastMessage();\n\t\t\t\tawait pageForServer2.reload();\n\n\t\t\t\treactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\treactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\n\t\t\t\tconst reactionsMapAfterUnreaction: any = {\n\t\t\t\t\t0: {\n\t\t\t\t\t\temoji: '🙂',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].emoji,\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].count,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\treactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].emoji,\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].count,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\ttest('expect to edit a message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.editLastMessage('message from Server A - Edited');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A - Edited');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A - Edited');\n\t\t\t});\n\n\t\t\ttest('expect to edit a message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server B');\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server B');\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server B');\n\n\t\t\t\tawait poFederationChannelServer2.content.editLastMessage('message from Server B - Edited');\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server B - Edited');\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server B - Edited');\n\t\t\t});\n\n\t\t\ttest('expect to delete a message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.deleteLastMessage();\n\t\t\t\tawait expect(poFederationChannelServer1.toastSuccess).toBeVisible();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage).not.toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to delete a message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer2.content.deleteLastMessage();\n\t\t\t\tawait expect(poFederationChannelServer2.toastSuccess).toBeVisible();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage).not.toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to reply a message in DM from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tconst message = 'message from Server B';\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter(message);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(message);\n\n\t\t\t\tawait poFederationChannelServer1.content.replyInDm('reply directly in DM from server A');\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServer2.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t});\n\n\t\t\ttest('expect to reply a message in DM Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tconst message = 'message from Server A';\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter(message);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(message);\n\n\t\t\t\tawait poFederationChannelServer2.content.replyInDm('reply directly in DM from server B');\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServer2.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t});\n\n\t\t\ttest('expect to star a message on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.starLastMessage();\n\t\t\t\tawait expect(\n\t\t\t\t\tpoFederationChannelServer1.toastSuccess.locator('div.rcx-toastbar-content', { hasText: 'Message has been starred' }),\n\t\t\t\t).toBeVisible();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('.rcx-icon--name-star-filled')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to star a message on Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer2.content.starLastMessage();\n\t\t\t\tawait expect(\n\t\t\t\t\tpoFederationChannelServer2.toastSuccess.locator('div.rcx-toastbar-content', { hasText: 'Message has been starred' }),\n\t\t\t\t).toBeVisible();\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('.rcx-icon--name-star-filled')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to reply in thread in Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer1.content.btnOptionReplyInThread).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to reply in thread in Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer2.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer2.content.btnOptionReplyInThread).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to start a discussion from a message in thread in Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer1.content.btnOptionStartDiscussion).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to start a discussion from a message in thread in Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer2.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer2.content.btnOptionStartDiscussion).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to pin a message in Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer1.content.btnOptionPinMessage).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to pin a message in Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst groupName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPrivateGroupAndInviteUsersUsingCreationModal(groupName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(groupName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(groupName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer2.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer2.content.btnOptionPinMessage).not.toBeVisible();\n\t\t\t});\n\t\t});\n\n\t\ttest.describe('Visual Elements', () => {\n\t\t\ttest('expect to see the file list sent in the group on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnFileList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to see the file list sent in the group on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnFileList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to see all the mentions sent in the group on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer1.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnMentionedMessagesList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to see all the mentions sent in the group on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnMentionedMessagesList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to see all the starred messages sent in the group on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer1.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnStarredMessagesList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to see all the starred messages sent in the group on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnStarredMessagesList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not to see the pinned messages sent in the group on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer1.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnPinnedMessagesList).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not to see the pinned messages sent in the group on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnPinnedMessagesList).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to prune messages sent in the group on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer1.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnPruneMessages).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to prune messages sent in the group on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdGroupName);\n\t\t\t\tawait poFederationChannelServer2.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnPruneMessages).not.toBeVisible();\n\t\t\t});\n\t\t});\n\t});\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/messaging/public.spec.ts",["23219","23220","23221","23222"],[],"/* eslint no-await-in-loop: 0 */\nimport faker from '@faker-js/faker';\nimport type { Page } from '@playwright/test';\n\nimport * as constants from '../../config/constants';\nimport { FederationChannel } from '../../page-objects/channel';\nimport { doLogin } from '../../utils/auth';\nimport { createChannelAndInviteRemoteUserToCreateLocalUser } from '../../utils/channel';\nimport { formatIntoFullMatrixUsername, formatUsernameAndDomainIntoMatrixFormat } from '../../utils/format';\nimport { registerUser } from '../../utils/register-user';\nimport { test, expect, setupTesting, tearDownTesting } from '../../utils/test';\n\ntest.describe.parallel('Federation - Channel Messaging', () => {\n\tlet poFederationChannelServer1: FederationChannel;\n\tlet poFederationChannelServer2: FederationChannel;\n\tlet userFromServer2UsernameOnly: string;\n\tlet userFromServer1UsernameOnly: string;\n\tlet createdChannelName: string;\n\tlet usernameWithDomainFromServer2: string;\n\tconst adminUsernameWithDomainFromServer1 = formatUsernameAndDomainIntoMatrixFormat(\n\t\tconstants.RC_SERVER_1.username,\n\t\tconstants.RC_SERVER_1.matrixServerName,\n\t);\n\tlet pageForServer2: Page;\n\n\ttest.beforeAll(async ({ apiServer1, apiServer2, browser }) => {\n\t\tawait setupTesting(apiServer1);\n\t\tawait setupTesting(apiServer2);\n\t\tuserFromServer1UsernameOnly = await registerUser(apiServer1);\n\t\tuserFromServer2UsernameOnly = await registerUser(apiServer2);\n\t\tusernameWithDomainFromServer2 = formatUsernameAndDomainIntoMatrixFormat(\n\t\t\tuserFromServer2UsernameOnly,\n\t\t\tconstants.RC_SERVER_2.matrixServerName,\n\t\t);\n\t\tconst fullUsernameFromServer2 = formatIntoFullMatrixUsername(userFromServer2UsernameOnly, constants.RC_SERVER_2.matrixServerName);\n\t\tconst page = await browser.newPage();\n\t\tpoFederationChannelServer1 = new FederationChannel(page);\n\t\tcreatedChannelName = await createChannelAndInviteRemoteUserToCreateLocalUser({\n\t\t\tpage,\n\t\t\tpoFederationChannelServer: poFederationChannelServer1,\n\t\t\tfullUsernameFromServer: fullUsernameFromServer2,\n\t\t\tserver: constants.RC_SERVER_1,\n\t\t});\n\t});\n\n\ttest.afterAll(async ({ apiServer1, apiServer2 }) => {\n\t\tawait tearDownTesting(apiServer1);\n\t\tawait tearDownTesting(apiServer2);\n\t});\n\n\ttest.beforeEach(async ({ page, browser }) => {\n\t\tpageForServer2 = await browser.newPage();\n\n\t\tpoFederationChannelServer1 = new FederationChannel(page);\n\t\tawait doLogin({\n\t\t\tpage,\n\t\t\tserver: {\n\t\t\t\turl: constants.RC_SERVER_1.url,\n\t\t\t\tusername: constants.RC_SERVER_1.username,\n\t\t\t\tpassword: constants.RC_SERVER_1.password,\n\t\t\t},\n\t\t});\n\n\t\tpoFederationChannelServer2 = new FederationChannel(pageForServer2);\n\t\tawait doLogin({\n\t\t\tpage: pageForServer2,\n\t\t\tserver: {\n\t\t\t\turl: constants.RC_SERVER_2.url,\n\t\t\t\tusername: userFromServer2UsernameOnly,\n\t\t\t\tpassword: constants.RC_SERVER_2.password,\n\t\t\t},\n\t\t\tstoreState: false,\n\t\t});\n\n\t\tawait page.addInitScript(() => {\n\t\t\twindow.localStorage.setItem('fuselage-localStorage-members-list-type', JSON.stringify('online'));\n\t\t});\n\t});\n\n\ttest.afterEach(async ({ page }) => {\n\t\tawait page.close();\n\t\tawait pageForServer2.close();\n\t});\n\n\ttest.describe('Messaging - Channel (Public)', () => {\n\t\ttest.describe('Send message', () => {\n\t\t\ttest('expect to send a message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('hello world from server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('hello world from server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('hello world from server A');\n\t\t\t});\n\n\t\t\ttest('expect to send a message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.content.sendMessage('hello world from server B');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t});\n\n\t\t\ttest.describe('With multiple users', () => {\n\t\t\t\tconst createdChannel = faker.datatype.uuid();\n\n\t\t\t\ttest('expect to send a message from Server A (creator) to Server B', async ({ browser, page }) => {\n\t\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\t\tconst poFederationChannel1ForUser2 = new FederationChannel(page2);\n\n\t\t\t\t\tawait doLogin({\n\t\t\t\t\t\tpage: page2,\n\t\t\t\t\t\tserver: {\n\t\t\t\t\t\t\turl: constants.RC_SERVER_1.url,\n\t\t\t\t\t\t\tusername: userFromServer1UsernameOnly,\n\t\t\t\t\t\t\tpassword: constants.RC_SERVER_1.password,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstoreState: false,\n\t\t\t\t\t});\n\t\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(createdChannel, [\n\t\t\t\t\t\tuserFromServer2UsernameOnly,\n\t\t\t\t\t\tuserFromServer1UsernameOnly,\n\t\t\t\t\t]);\n\n\t\t\t\t\tawait expect(page).toHaveURL(`${constants.RC_SERVER_1.url}/channel/${createdChannel}`);\n\n\t\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannel);\n\t\t\t\t\tawait poFederationChannel1ForUser2.sidenav.openChat(createdChannel);\n\t\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannel);\n\n\t\t\t\t\tawait poFederationChannelServer1.content.sendMessage('hello world from server A (creator)');\n\n\t\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('hello world from server A (creator)');\n\t\t\t\t\tawait expect(poFederationChannel1ForUser2.content.lastUserMessage.locator('p')).toHaveText('hello world from server A (creator)');\n\t\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('hello world from server A (creator)');\n\t\t\t\t\tawait pageForServer2.close();\n\t\t\t\t\tawait page2.close();\n\t\t\t\t});\n\n\t\t\t\ttest('expect to send a message from Server A (user 2) to Server B', async ({ browser }) => {\n\t\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\t\tconst poFederationChannel1ForUser2 = new FederationChannel(page2);\n\n\t\t\t\t\tawait doLogin({\n\t\t\t\t\t\tpage: page2,\n\t\t\t\t\t\tserver: {\n\t\t\t\t\t\t\turl: constants.RC_SERVER_1.url,\n\t\t\t\t\t\t\tusername: userFromServer1UsernameOnly,\n\t\t\t\t\t\t\tpassword: constants.RC_SERVER_1.password,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstoreState: false,\n\t\t\t\t\t});\n\n\t\t\t\t\tawait page2.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannel);\n\t\t\t\t\tawait poFederationChannel1ForUser2.sidenav.openChat(createdChannel);\n\t\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannel);\n\n\t\t\t\t\tawait poFederationChannel1ForUser2.content.sendMessage('hello world from server A (user 2)');\n\t\t\t\t\tawait poFederationChannel1ForUser2.content.sendMessage('hello world from server A (user 2) message 2');\n\n\t\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t\t'hello world from server A (user 2) message 2',\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t\t'hello world from server A (user 2) message 2',\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(poFederationChannel1ForUser2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t\t'hello world from server A (user 2) message 2',\n\t\t\t\t\t);\n\n\t\t\t\t\tawait page2.close();\n\t\t\t\t\tawait pageForServer2.close();\n\t\t\t\t});\n\n\t\t\t\ttest('expect to send a message from Server B to Server A', async ({ browser, page }) => {\n\t\t\t\t\tconst page2 = await browser.newPage();\n\t\t\t\t\tconst poFederationChannel1ForUser2 = new FederationChannel(page2);\n\n\t\t\t\t\tawait doLogin({\n\t\t\t\t\t\tpage: page2,\n\t\t\t\t\t\tserver: {\n\t\t\t\t\t\t\turl: constants.RC_SERVER_1.url,\n\t\t\t\t\t\t\tusername: userFromServer1UsernameOnly,\n\t\t\t\t\t\t\tpassword: constants.RC_SERVER_1.password,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstoreState: false,\n\t\t\t\t\t});\n\t\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannel);\n\t\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannel);\n\t\t\t\t\tawait poFederationChannel1ForUser2.sidenav.openChat(createdChannel);\n\n\t\t\t\t\tawait expect(page).toHaveURL(`${constants.RC_SERVER_1.url}/channel/${createdChannel}`);\n\n\t\t\t\t\tawait poFederationChannelServer2.content.sendMessage('hello world from server B');\n\n\t\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t\t\tawait expect(poFederationChannel1ForUser2.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('hello world from server B');\n\t\t\t\t\tawait pageForServer2.close();\n\t\t\t\t\tawait page2.close();\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\ttest.describe('Send \"Special\" messages', () => {\n\t\t\ttest('expect to send a message with emojis from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage('😀 😀 hello world 🌎 from server A with emojis 😀 😀');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t'😀 😀 hello world 🌎 from server A with emojis 😀 😀',\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t'😀 😀 hello world 🌎 from server A with emojis 😀 😀',\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('expect to send a message with emojis from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessage('😀 😀 hello world 🌎 from server B with emojis 😀 😀');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t'😀 😀 hello world 🌎 from server B with emojis 😀 😀',\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t'😀 😀 hello world 🌎 from server B with emojis 😀 😀',\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('expect to send an audio message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendAudioRecordedMessage();\n\n\t\t\t\tawait expect(await (await poFederationChannelServer1.content.getLastFileMessageByFileName('Audio record.mp3')).innerText()).toEqual(\n\t\t\t\t\t'Audio record.mp3',\n\t\t\t\t);\n\t\t\t\tawait expect(await (await poFederationChannelServer2.content.getLastFileMessageByFileName('Audio record.mp3')).innerText()).toEqual(\n\t\t\t\t\t'Audio record.mp3',\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('audio')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('audio')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send an audio message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.content.sendAudioRecordedMessage();\n\n\t\t\t\tawait expect(await (await poFederationChannelServer2.content.getLastFileMessageByFileName('Audio record.mp3')).innerText()).toEqual(\n\t\t\t\t\t'Audio record.mp3',\n\t\t\t\t);\n\t\t\t\tawait expect(await (await poFederationChannelServer1.content.getLastFileMessageByFileName('Audio record.mp3')).innerText()).toEqual(\n\t\t\t\t\t'Audio record.mp3',\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('audio')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('audio')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a video message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendVideoRecordedMessage();\n\n\t\t\t\tawait expect(\n\t\t\t\t\tawait (await poFederationChannelServer1.content.getLastFileMessageByFileName('Video record.webm')).innerText(),\n\t\t\t\t).toEqual('Video record.webm');\n\t\t\t\tawait expect(\n\t\t\t\t\tawait (await poFederationChannelServer2.content.getLastFileMessageByFileName('Video record.webm')).innerText(),\n\t\t\t\t).toEqual('Video record.webm');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a video message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendVideoRecordedMessage();\n\n\t\t\t\tawait expect(\n\t\t\t\t\tawait (await poFederationChannelServer2.content.getLastFileMessageByFileName('Video record.webm')).innerText(),\n\t\t\t\t).toEqual('Video record.webm');\n\t\t\t\tawait expect(\n\t\t\t\t\tawait (await poFederationChannelServer1.content.getLastFileMessageByFileName('Video record.webm')).innerText(),\n\t\t\t\t).toEqual('Video record.webm');\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (image) from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendFileMessage('test_image.jpeg');\n\t\t\t\tawait poFederationChannelServer1.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.getLastFileName).toContainText('test_image.jpeg');\n\t\t\t\tawait expect(poFederationChannelServer2.content.getLastFileName).toContainText('test_image.jpeg');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.getLastFileAttachmentContent.locator('img')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.getLastFileAttachmentContent.locator('img')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (image) from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.content.sendFileMessage('test_image.jpeg');\n\t\t\t\tawait poFederationChannelServer2.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.getLastFileName).toContainText('test_image.jpeg');\n\t\t\t\tawait expect(poFederationChannelServer1.content.getLastFileName).toContainText('test_image.jpeg');\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.getLastFileAttachmentContent.locator('img')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer1.content.getLastFileAttachmentContent.locator('img')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (video) from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendFileMessage('test_video.mp4');\n\t\t\t\tawait poFederationChannelServer1.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(await (await poFederationChannelServer1.content.getLastFileMessageByFileName('test_video.mp4')).innerText()).toEqual(\n\t\t\t\t\t'test_video.mp4',\n\t\t\t\t);\n\t\t\t\tawait expect(await (await poFederationChannelServer2.content.getLastFileMessageByFileName('test_video.mp4')).innerText()).toEqual(\n\t\t\t\t\t'test_video.mp4',\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (video) from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendFileMessage('test_video.mp4');\n\t\t\t\tawait poFederationChannelServer2.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(await (await poFederationChannelServer2.content.getLastFileMessageByFileName('test_video.mp4')).innerText()).toEqual(\n\t\t\t\t\t'test_video.mp4',\n\t\t\t\t);\n\t\t\t\tawait expect(await (await poFederationChannelServer1.content.getLastFileMessageByFileName('test_video.mp4')).innerText()).toEqual(\n\t\t\t\t\t'test_video.mp4',\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastFileMessage.locator('video')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (pdf) from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendFileMessage('test_pdf_file.pdf');\n\t\t\t\tawait poFederationChannelServer1.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastMessageFileName).toContainText('test_pdf_file.pdf');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastMessageFileName).toContainText('test_pdf_file.pdf');\n\t\t\t});\n\n\t\t\ttest('expect to send a file message (pdf) from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendFileMessage('test_pdf_file.pdf');\n\t\t\t\tawait poFederationChannelServer2.content.btnModalConfirm.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastMessageFileName).toContainText('test_pdf_file.pdf');\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastMessageFileName).toContainText('test_pdf_file.pdf');\n\t\t\t});\n\n\t\t\ttest('expect to send a message mentioning an user from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.inputMessage.type(`@${userFromServer2UsernameOnly}`);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.messagePopUpItems.locator(`text=${usernameWithDomainFromServer2}`)).toBeVisible();\n\n\t\t\t\tawait poFederationChannelServer2.content.inputMessage.type(`@${constants.RC_SERVER_1.username}`);\n\n\t\t\t\tawait expect(\n\t\t\t\t\tpoFederationChannelServer2.content.messagePopUpItems.locator(`text=${adminUsernameWithDomainFromServer1}`),\n\t\t\t\t).toBeVisible();\n\n\t\t\t\tawait poFederationChannelServer1.content.inputMessage.fill('');\n\t\t\t\tawait poFederationChannelServer2.content.inputMessage.fill('');\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage(\n\t\t\t\t\t`hello @${usernameWithDomainFromServer2}, here's @${constants.RC_SERVER_1.username} from Server A`,\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${usernameWithDomainFromServer2}, here's ${constants.RC_SERVER_1.username} from Server A`,\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${userFromServer2UsernameOnly}, here's ${adminUsernameWithDomainFromServer1} from Server A`,\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('expect to send a message mentioning an user Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait poFederationChannelServer2.content.inputMessage.type(`@${constants.RC_SERVER_1.username}`);\n\n\t\t\t\tawait expect(\n\t\t\t\t\tpoFederationChannelServer2.content.messagePopUpItems.locator(`text=${adminUsernameWithDomainFromServer1}`),\n\t\t\t\t).toBeVisible();\n\n\t\t\t\tawait poFederationChannelServer1.content.inputMessage.type(`@${userFromServer2UsernameOnly}`);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.messagePopUpItems.locator(`text=${usernameWithDomainFromServer2}`)).toBeVisible();\n\n\t\t\t\tawait poFederationChannelServer1.content.inputMessage.fill('');\n\t\t\t\tawait poFederationChannelServer2.content.inputMessage.fill('');\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessage(\n\t\t\t\t\t`hello @${adminUsernameWithDomainFromServer1}, here's @${userFromServer2UsernameOnly} from Server B`,\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${constants.RC_SERVER_1.username}, here's ${usernameWithDomainFromServer2} from Server B`,\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${adminUsernameWithDomainFromServer1}, here's ${userFromServer2UsernameOnly} from Server B`,\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('expect to send a message with multiple mentions, including @all from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage(\n\t\t\t\t\t`hello @${usernameWithDomainFromServer2}, here's @${constants.RC_SERVER_1.username} from Server A, @all, @${usernameWithDomainFromServer2}`,\n\t\t\t\t);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${usernameWithDomainFromServer2}, here's ${constants.RC_SERVER_1.username} from Server A, all, ${usernameWithDomainFromServer2}`,\n\t\t\t\t);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(\n\t\t\t\t\t`hello ${userFromServer2UsernameOnly}, here's ${adminUsernameWithDomainFromServer1} from Server A, all, ${userFromServer2UsernameOnly}`,\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\ttest.describe('Message actions', () => {\n\t\t\ttest('expect to send a message quoting a message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tconst message = `Message for quote - ${Date.now()}`;\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessage(message);\n\t\t\t\tawait poFederationChannelServer1.content.quoteMessage('this is a quote message');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServer2.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t});\n\n\t\t\ttest('expect to send a message quoting a message Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tconst message = `Message for quote - ${Date.now()}`;\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessage(message);\n\t\t\t\tawait poFederationChannelServer2.content.quoteMessage('this is a quote message');\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServer1.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t});\n\n\t\t\ttest('expect to react a message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServer1.content.reactToMessage('slight_smile');\n\n\t\t\t\tconst reactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\tconst reactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText('🙂');\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText('1');\n\t\t\t\t}\n\t\t\t\tconst reactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\tconst reactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText('🙂');\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText('1');\n\t\t\t\t}\n\t\t\t});\n\n\t\t\ttest('expect to react a message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServer2.content.reactToMessage('slight_smile');\n\n\t\t\t\tconst reactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\tconst reactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText('🙂');\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText('1');\n\t\t\t\t}\n\t\t\t\tconst reactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\tconst reactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText('🙂');\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText('1');\n\t\t\t\t}\n\t\t\t});\n\n\t\t\ttest('expect to unreact a message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServer1.content.reactToMessage('slight_smile');\n\t\t\t\tawait poFederationChannelServer1.content.reactToMessage('grin');\n\n\t\t\t\tlet reactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\tlet reactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tconst reactionsMap: any = {\n\t\t\t\t\t0: {\n\t\t\t\t\t\temoji: '🙂',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t\t1: {\n\t\t\t\t\t\temoji: '😁',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(reactionsMap[i].emoji);\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(reactionsMap[i].count);\n\t\t\t\t}\n\t\t\t\tlet reactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\tlet reactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(reactionsMap[i].emoji);\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(reactionsMap[i].count);\n\t\t\t\t}\n\n\t\t\t\tawait poFederationChannelServer1.content.unreactLastMessage();\n\t\t\t\tawait pageForServer2.reload();\n\n\t\t\t\treactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\treactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\n\t\t\t\tconst reactionsMapAfterUnreaction: any = {\n\t\t\t\t\t0: {\n\t\t\t\t\t\temoji: '🙂',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].emoji,\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].count,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\treactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].emoji,\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].count,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\ttest('expect to unreact a message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\t\t\t\tawait poFederationChannelServer2.content.reactToMessage('slight_smile');\n\t\t\t\tawait poFederationChannelServer2.content.reactToMessage('grin');\n\n\t\t\t\tlet reactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\tlet reactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\t\t\t\tconst reactionsMap: any = {\n\t\t\t\t\t0: {\n\t\t\t\t\t\temoji: '🙂',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t\t1: {\n\t\t\t\t\t\temoji: '😁',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(reactionsMap[i].emoji);\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(reactionsMap[i].count);\n\t\t\t\t}\n\t\t\t\tlet reactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\tlet reactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(reactionsMap[i].emoji);\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(reactionsMap[i].count);\n\t\t\t\t}\n\n\t\t\t\tawait poFederationChannelServer2.content.unreactLastMessage();\n\t\t\t\tawait pageForServer2.reload();\n\n\t\t\t\treactionsServer2 = await poFederationChannelServer2.content.getAllReactions();\n\t\t\t\treactionListExcludingTheActionServer2 = (await reactionsServer2.count()) - 1;\n\n\t\t\t\tconst reactionsMapAfterUnreaction: any = {\n\t\t\t\t\t0: {\n\t\t\t\t\t\temoji: '🙂',\n\t\t\t\t\t\tcount: '1',\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer2; i++) {\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].emoji,\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(reactionsServer2.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].count,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treactionsServer1 = await poFederationChannelServer1.content.getAllReactions();\n\t\t\t\treactionListExcludingTheActionServer1 = (await reactionsServer1.count()) - 1;\n\t\t\t\tfor (let i = 0; i < reactionListExcludingTheActionServer1; i++) {\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('span.rcx-message-reactions__emoji.emojione')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].emoji,\n\t\t\t\t\t);\n\t\t\t\t\tawait expect(reactionsServer1.nth(i).locator('div.rcx-message-reactions__counter')).toContainText(\n\t\t\t\t\t\treactionsMapAfterUnreaction[i].count,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\ttest('expect to edit a message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.editLastMessage('message from Server A - Edited');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A - Edited');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A - Edited');\n\t\t\t});\n\n\t\t\ttest('expect to edit a message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server B');\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server B');\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server B');\n\n\t\t\t\tawait poFederationChannelServer2.content.editLastMessage('message from Server B - Edited');\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server B - Edited');\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server B - Edited');\n\t\t\t});\n\n\t\t\ttest('expect to delete a message from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.deleteLastMessage();\n\t\t\t\tawait expect(poFederationChannelServer1.toastSuccess).toBeVisible();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage).not.toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to delete a message from Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer2.content.deleteLastMessage();\n\t\t\t\tawait expect(poFederationChannelServer2.toastSuccess).toBeVisible();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage).not.toBeVisible();\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to reply a message in DM from Server A to Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tconst message = 'message from Server B';\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter(message);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(message);\n\n\t\t\t\tawait poFederationChannelServer1.content.replyInDm('reply directly in DM from server A');\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(adminUsernameWithDomainFromServer1);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServer2.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t});\n\n\t\t\ttest('expect to reply a message in DM Server B to Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tconst message = 'message from Server A';\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter(message);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText(message);\n\n\t\t\t\tawait poFederationChannelServer2.content.replyInDm('reply directly in DM from server B');\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(usernameWithDomainFromServer2);\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t\tawait expect(poFederationChannelServer2.content.waitForLastMessageTextAttachmentEqualsText).toHaveText(message);\n\t\t\t});\n\n\t\t\ttest('expect to star a message on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.starLastMessage();\n\t\t\t\tawait expect(\n\t\t\t\t\tpoFederationChannelServer1.toastSuccess.locator('div.rcx-toastbar-content', { hasText: 'Message has been starred' }),\n\t\t\t\t).toBeVisible();\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('.rcx-icon--name-star-filled')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to star a message on Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer2.content.starLastMessage();\n\t\t\t\tawait expect(\n\t\t\t\t\tpoFederationChannelServer2.toastSuccess.locator('div.rcx-toastbar-content', { hasText: 'Message has been starred' }),\n\t\t\t\t).toBeVisible();\n\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('.rcx-icon--name-star-filled')).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to reply in thread in Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer1.content.btnOptionReplyInThread).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to reply in thread in Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer2.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer2.content.btnOptionReplyInThread).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to start a discussion from a message in thread in Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer1.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer1.content.btnOptionStartDiscussion).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to start a discussion from a message in thread in Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer2.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer2.content.btnOptionStartDiscussion).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to pin a message in Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer1.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer1.content.btnOptionPinMessage).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to pin a message in Server B', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\t\t\t\tconst channelName = faker.datatype.uuid();\n\n\t\t\t\tawait poFederationChannelServer1.createPublicChannelAndInviteUsersUsingCreationModal(channelName, [userFromServer2UsernameOnly]);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(channelName);\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(channelName);\n\n\t\t\t\tawait poFederationChannelServer2.content.sendMessageUsingEnter('message from Server A');\n\n\t\t\t\tawait expect(poFederationChannelServer1.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\t\t\t\tawait expect(poFederationChannelServer2.content.lastUserMessage.locator('p')).toHaveText('message from Server A');\n\n\t\t\t\tawait poFederationChannelServer2.content.openLastMessageMenu();\n\t\t\t\tawait expect(poFederationChannelServer2.content.btnOptionPinMessage).not.toBeVisible();\n\t\t\t});\n\t\t});\n\n\t\ttest.describe('Visual Elements', () => {\n\t\t\ttest('expect to see the file list sent in the channel on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnFileList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to see the file list sent in the channel on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnFileList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to see all the mentions sent in the channel on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer1.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnMentionedMessagesList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to see all the mentions sent in the channel on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnMentionedMessagesList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to see all the starred messages sent in the channel on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer1.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnStarredMessagesList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to see all the starred messages sent in the channel on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnStarredMessagesList).toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not to see the pinned messages sent in the channel on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer1.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnPinnedMessagesList).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not to see the pinned messages sent in the channel on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnPinnedMessagesList).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to prune messages sent in the channel on Server A', async ({ page }) => {\n\t\t\t\tawait page.goto(`${constants.RC_SERVER_1.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer1.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer1.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer1.tabs.btnPruneMessages).not.toBeVisible();\n\t\t\t});\n\n\t\t\ttest('expect to not be able to prune messages sent in the channel on Server B', async () => {\n\t\t\t\tawait pageForServer2.goto(`${constants.RC_SERVER_2.url}/home`);\n\n\t\t\t\tawait poFederationChannelServer2.sidenav.openChat(createdChannelName);\n\t\t\t\tawait poFederationChannelServer2.tabs.kebab.click();\n\n\t\t\t\tawait expect(poFederationChannelServer2.tabs.btnPruneMessages).not.toBeVisible();\n\t\t\t});\n\t\t});\n\t});\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/tests/user-account/user.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/utils/auth.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/utils/channel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/utils/format.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/utils/register-user.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/federation/utils/test.ts",["23223","23224","23225"],[],"import type { APIResponse } from '@playwright/test';\nimport { test as baseTest } from '@playwright/test';\n\nimport { API_PREFIX } from '../../config/constants';\nimport * as constants from '../config/constants';\n\nexport type AnyObj = { [key: string]: any };\n\nexport type API = {\n\tget(uri: string, prefix?: string): Promise;\n\tpost(uri: string, data: AnyObj, prefix?: string): Promise;\n\tput(uri: string, data: AnyObj, prefix?: string): Promise;\n\tdelete(uri: string, prefix?: string): Promise;\n};\n\nexport type BaseTest = {\n\tapiServer1: API;\n\tapiServer2: API;\n};\n\nconst api = async (request: any, use: any, user: string, password: string, baseUrl: string) => {\n\tconst resp = await request.post(`${baseUrl + API_PREFIX}/login`, { data: { user, password } });\n\tconst json = await resp.json();\n\n\tconst headers = {\n\t\t'X-Auth-Token': json.data.authToken,\n\t\t'X-User-Id': json.data.userId,\n\t};\n\n\tawait use({\n\t\tget(uri: string, prefix = API_PREFIX) {\n\t\t\treturn request.get(baseUrl + prefix + uri, { headers });\n\t\t},\n\t\tpost(uri: string, data: AnyObj, prefix = API_PREFIX) {\n\t\t\treturn request.post(baseUrl + prefix + uri, { headers, data });\n\t\t},\n\t\tput(uri: string, data: AnyObj, prefix = API_PREFIX) {\n\t\t\treturn request.put(baseUrl + prefix + uri, { headers, data });\n\t\t},\n\t\tdelete(uri: string, prefix = API_PREFIX) {\n\t\t\treturn request.delete(baseUrl + prefix + uri, { headers });\n\t\t},\n\t});\n};\n\nexport const test = baseTest.extend({\n\tapiServer1: async ({ request }, use) =>\n\t\tapi(request, use, constants.RC_SERVER_1.username, constants.RC_SERVER_1.password, constants.RC_SERVER_1.url),\n\tapiServer2: async ({ request }, use) =>\n\t\tapi(request, use, constants.RC_SERVER_2.username, constants.RC_SERVER_2.password, constants.RC_SERVER_2.url),\n});\n\nexport const { expect } = test;\n\nexport const setupTesting = async (api: API) => {\n\tawait api.post('/settings/Message_AudioRecorderEnabled', { value: true });\n\tawait api.post('/settings/Message_AudioRecorderEnabled', { value: true });\n\tawait api.post('/settings/Accounts_ManuallyApproveNewUsers', { value: false });\n\tawait api.post('/settings/API_Enable_Rate_Limiter', { value: false });\n\tawait api.post('/settings/Rate_Limiter_Limit_RegisterUser', { value: 10 });\n\tawait api.post('/settings/Accounts_RegistrationForm', { value: 'Public' });\n\tawait api.post('/permissions.update', { permissions: [{ _id: 'force-delete-message', roles: ['admin', 'user'] }] });\n};\n\nexport const tearDownTesting = async (api: API) => {\n\tawait api.post('/settings/Accounts_ManuallyApproveNewUsers', { value: true });\n\tawait api.post('/settings/API_Enable_Rate_Limiter', { value: true });\n\tawait api.post('/settings/Rate_Limiter_Limit_RegisterUser', { value: 1 });\n\tawait api.post('/settings/Accounts_RegistrationForm', { value: 'Disabled' });\n};\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/file-upload.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/fixtures/collections/users.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/fixtures/createAuxContext.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/fixtures/inject-initial-data.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/fixtures/insert-apps.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/fixtures/userStates.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/forgot-password.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/homepage.spec.ts",[],["23226","23227","23228"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/imports.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/login.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/message-actions.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/message-mentions.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/messaging.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-agents.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-auto-onhold-chat-closing.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-auto-transfer-unanswered-chat.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-canned-responses-sidebar.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-changing-room-priority-and-sla.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-chat-history.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-close-chat.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-contact-center.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-contact-info.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-currentChats.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-custom-fields.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-departaments-ce.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-departaments.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-livechat.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-manager.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-priorities.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-send-transcript.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-sla-policies.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-takeChat.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-transfer-to-another-agents.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/omnichannel-triggers.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/account-profile.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/admin-email-inboxes.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/admin.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/auth.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/account-sidenav.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-users.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/admin-flextab.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-channels.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-members.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-notificationPreferences.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-room.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-omnichannel-content.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/home-sidenav.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/omnichannel-close-chat-modal.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/fragments/omnichannel-sidenav.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/home-channel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/home-discussion.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/home-omnichannel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/home-team.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-agents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-contacts-list.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-current-chats.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-custom-fields.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-departments.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-info.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-livechat.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-manage-contact.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-manager.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-priorities.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-section.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-sla-policies.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/omnichannel-triggers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/page-objects/utils.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/permissions.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/register.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/settings-account-profile.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/settings-assets.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/system-messages.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/team-management.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/thread-actions.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/user-invitations.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/utils/create-target-channel.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/utils/index.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/utils/omnichannel/priority.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/utils/omnichannel/sla.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/utils/setSettingValueById.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/utils/test.ts",["23229"],[],"import * as fs from 'fs';\nimport * as path from 'path';\n\nimport type { Locator, APIResponse, APIRequestContext } from '@playwright/test';\nimport { test as baseTest, request as baseRequest } from '@playwright/test';\nimport { v4 as uuid } from 'uuid';\n\nimport { BASE_API_URL, API_PREFIX, ADMIN_CREDENTIALS } from '../config/constants';\nimport { Users } from '../fixtures/userStates';\n\nconst PATH_NYC_OUTPUT = path.join(process.cwd(), '.nyc_output');\n\nexport type AnyObj = { [key: string]: any };\n\nexport type BaseTest = {\n\tapi: {\n\t\trecreateContext(): Promise;\n\t\tlogin(credentials: { username: string; password: string }): Promise;\n\t\tget(uri: string, params?: AnyObj, prefix?: string): Promise;\n\t\tpost(uri: string, data: AnyObj, prefix?: string): Promise;\n\t\tput(uri: string, data: AnyObj, prefix?: string): Promise;\n\t\tdelete(uri: string, params?: AnyObj, prefix?: string): Promise;\n\t};\n};\ndeclare global {\n\t// eslint-disable-next-line @typescript-eslint/naming-convention\n\tinterface Window {\n\t\tcollectIstanbulCoverage: (coverageJSON: string) => void;\n\t\t__coverage__: Record;\n\t}\n}\n\nlet apiContext: APIRequestContext;\n\nexport const test = baseTest.extend({\n\tcontext: async ({ context }, use) => {\n\t\tif (!process.env.E2E_COVERAGE) {\n\t\t\tawait use(context);\n\t\t\tawait context.close();\n\n\t\t\treturn;\n\t\t}\n\n\t\tawait context.addInitScript(() =>\n\t\t\twindow.addEventListener('beforeunload', () => window.collectIstanbulCoverage(JSON.stringify(window.__coverage__))),\n\t\t);\n\n\t\tawait fs.promises.mkdir(PATH_NYC_OUTPUT, { recursive: true });\n\n\t\tawait context.exposeFunction('collectIstanbulCoverage', (coverageJSON: string) => {\n\t\t\tif (coverageJSON) {\n\t\t\t\tfs.writeFileSync(path.join(PATH_NYC_OUTPUT, `playwright_coverage_${uuid()}.json`), coverageJSON);\n\t\t\t}\n\t\t});\n\n\t\tawait use(context);\n\n\t\tawait Promise.all(\n\t\t\tcontext.pages().map(async (page) => {\n\t\t\t\tawait page.evaluate(() => window.collectIstanbulCoverage(JSON.stringify(window.__coverage__)));\n\t\t\t\tawait page.close();\n\t\t\t}),\n\t\t);\n\t},\n\n\tapi: async ({ request }, use) => {\n\t\tconst login = async (credentials: { username: string; password: string }): Promise => {\n\t\t\tif (credentials.username === Users.admin.data.username) {\n\t\t\t\treturn baseRequest.newContext({\n\t\t\t\t\tbaseURL: BASE_API_URL,\n\t\t\t\t\textraHTTPHeaders: {\n\t\t\t\t\t\t'X-Auth-Token': Users.admin.data.loginToken,\n\t\t\t\t\t\t'X-User-Id': Users.admin.data.username,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst resp = await request.post(`${BASE_API_URL}/login`, { data: credentials });\n\t\t\tconst json = await resp.json();\n\n\t\t\treturn baseRequest.newContext({\n\t\t\t\tbaseURL: BASE_API_URL,\n\t\t\t\textraHTTPHeaders: {\n\t\t\t\t\t'X-Auth-Token': json.data.authToken,\n\t\t\t\t\t'X-User-Id': json.data.userId,\n\t\t\t\t},\n\t\t\t});\n\t\t};\n\n\t\tconst recreateContext = async () => {\n\t\t\tapiContext = await login(ADMIN_CREDENTIALS);\n\t\t};\n\n\t\tif (!apiContext) {\n\t\t\tawait recreateContext();\n\t\t}\n\n\t\tawait use({\n\t\t\trecreateContext,\n\t\t\tlogin,\n\t\t\tget(uri: string, params?: AnyObj, prefix = API_PREFIX) {\n\t\t\t\treturn apiContext.get(prefix + uri, { params });\n\t\t\t},\n\t\t\tpost(uri: string, data: AnyObj, prefix = API_PREFIX) {\n\t\t\t\treturn apiContext.post(prefix + uri, { data });\n\t\t\t},\n\t\t\tput(uri: string, data: AnyObj, prefix = API_PREFIX) {\n\t\t\t\treturn apiContext.put(prefix + uri, { data });\n\t\t\t},\n\t\t\tdelete(uri: string, params?: AnyObj, prefix = API_PREFIX) {\n\t\t\t\treturn apiContext.delete(prefix + uri, { params });\n\t\t\t},\n\t\t});\n\t},\n});\n\nexport const { expect } = test;\n\nexpect.extend({\n\tasync toBeInvalid(received: Locator) {\n\t\ttry {\n\t\t\tawait expect(received).toHaveAttribute('aria-invalid', 'true');\n\n\t\t\treturn {\n\t\t\t\tmessage: () => `expected ${received} to be invalid`,\n\t\t\t\tpass: true,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tmessage: () => `expected ${received} to be invalid`,\n\t\t\t\tpass: false,\n\t\t\t};\n\t\t}\n\t},\n\tasync toBeBusy(received: Locator) {\n\t\ttry {\n\t\t\tawait expect(received).toHaveAttribute('aria-busy', 'true');\n\n\t\t\treturn {\n\t\t\t\tmessage: () => `expected ${received} to be busy`,\n\t\t\t\tpass: true,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tmessage: () => `expected ${received} to be busy`,\n\t\t\t\tpass: false,\n\t\t\t};\n\t\t}\n\t},\n\tasync hasAttribute(received: Locator, attribute: string) {\n\t\tconst pass = await received.evaluate((node, attribute) => node.hasAttribute(attribute), attribute);\n\n\t\treturn {\n\t\t\tmessage: () => `expected ${received} to have attribute \\`${attribute}\\``,\n\t\t\tpass,\n\t\t};\n\t},\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/video-conference-ring.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/e2e/video-conference.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/00-autotranslate.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/00-miscellaneous.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/01-users.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/02-channels.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/03-groups.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/04-direct-message.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/05-chat.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/06-outgoing-integrations.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/07-incoming-integrations.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/08-settings.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/09-rooms.js",[],["23230"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/10-subscriptions.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/11-permissions.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/12-emoji-custom.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/14-assets.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/16-commands.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/17-custom-sounds.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/17-custom-user-status.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/17-webdav.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/18-oauthapps.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/19-statistics.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/20-licenses.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/21-banners.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/22-push-token.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/23-invites.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/24-methods.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/25-teams.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/26-LDAP.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/27-presence.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/27-roles.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/import.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/00-rooms.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/01-agents.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/02-appearance.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/03-custom-fields.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/04-dashboards.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/05-inquiries.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/06-integrations.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/07-queue.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/08-triggers.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/09-visitors.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/10-departments.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/11-email-inbox.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/11-livechat.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/12-mailer.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/12-priorites.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/13-tags.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/14-units.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/15-canned-responses.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/16-video-call.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/17-dashboards-ee.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/18-rooms-ee.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/19-business-hours.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/api/livechat/methods/changeLivechatStatus.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/00-installation.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/01-send-messages.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/02-send-messages-as-user.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/03-slash-command-test-simple.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/04-slash-command-test-with-arguments.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/05-video-conferences.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/apps/apps-uninstall.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/end-to-end/teardown.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/client/FakeChatProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/client/FakeRoomProvider.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/client/ModalContextMock.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/client/RouterContextMock.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/client/blobUrls.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/client/jsdom.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/data.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/mocks/server/mongodb.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/setup/chaiPlugins.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/setup/cleanupTestingLibrary.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/setup/hoistedReact.ts",[],["23231","23232"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/setup/registerWebApiMocks.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/api/server/v1/lib/checkPermissions.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/api/server/v1/lib/checkPermissionsForInvocation.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/api/server/v1/lib/isValidQuery.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/messages.tests.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/mocks/models/BaseModel.mock.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/mocks/models/Messages.mock.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/mocks/models/Rooms.mock.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/mocks/models/Users.mock.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/mocks/models/index.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/apps/server/mocks/orchestrator.mock.js",[],["23233"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/custom-oauth/server/transform_helpers.tests.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/Federation.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/MessageServiceListener.spec.ts",[],["23234"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/RoomServiceListener.spec.ts",[],["23235"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/UserServiceListener.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/sender/MessageSenders.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/sender/MessageServiceSender.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/sender/RoomInternalHooksValidator.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/sender/RoomServiceSender.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/application/sender/UserServiceSender.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/domain/FederatedRoom.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/domain/FederatedUser.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/Bridge.spec.ts",[],["23236","23237"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/converters/MatrixTextParser.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/converters/RoomReceiver.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/converters/UserReceiver.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/handlers/BaseEvent.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/handlers/MatrixEventsHandler.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/matrix/handlers/Room.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/queue/InMemoryQueue.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/rocket-chat/converters/RocketTextParser.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/rocket-chat/converters/RoomSender.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/rocket-chat/hooks/hooks.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/rocket-chat/slash-commands/actions.spec.ts",[],["23238","23239","23240","23241","23242","23243","23244","23245"],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/federation-v2/server/unit/infrastructure/rocket-chat/statistics.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/highlight-words/helper.tests.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/lib/server.tests.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/mailer/api.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/markdown/client.mocks.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/markdown/client.tests.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/mentions/client.tests.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/mentions/server.tests.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/meteor-accounts-saml/data.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/meteor-accounts-saml/server.tests.ts",["23246","23247"],[],"import { expect } from 'chai';\nimport proxyquire from 'proxyquire';\n\nimport { AuthorizeRequest } from '../../../../app/meteor-accounts-saml/server/lib/generators/AuthorizeRequest';\nimport { LogoutRequest } from '../../../../app/meteor-accounts-saml/server/lib/generators/LogoutRequest';\nimport { LogoutResponse } from '../../../../app/meteor-accounts-saml/server/lib/generators/LogoutResponse';\nimport { LogoutRequestParser } from '../../../../app/meteor-accounts-saml/server/lib/parsers/LogoutRequest';\nimport { LogoutResponseParser } from '../../../../app/meteor-accounts-saml/server/lib/parsers/LogoutResponse';\nimport { ResponseParser } from '../../../../app/meteor-accounts-saml/server/lib/parsers/Response';\nimport { SAMLUtils } from '../../../../app/meteor-accounts-saml/server/lib/Utils';\nimport {\n\tserviceProviderOptions,\n\tsimpleMetadata,\n\tmetadataWithCertificate,\n\tsimpleLogoutRequest,\n\tinvalidXml,\n\trandomXml,\n\tinvalidLogoutRequest,\n\tsimpleLogoutResponse,\n\tinvalidLogoutResponse,\n\tsimpleSamlResponse,\n\tsamlResponse,\n\tduplicatedSamlResponse,\n\tsamlResponseMissingStatus,\n\tsamlResponseFailedStatus,\n\tsamlResponseMultipleAssertions,\n\tsamlResponseMissingAssertion,\n\tsamlResponseMultipleIssuers,\n\tsamlResponseValidSignatures,\n\tsamlResponseValidAssertionSignature,\n\tencryptedResponse,\n\tprofile,\n\tcertificate,\n\tprivateKeyCert,\n\tprivateKey,\n} from './data';\nimport { isTruthy } from '../../../../lib/isTruthy';\n\nconst { ServiceProviderMetadata } = proxyquire\n\t.noCallThru()\n\t.load('../../../../app/meteor-accounts-saml/server/lib/generators/ServiceProviderMetadata', {\n\t\t'meteor/meteor': {\n\t\t\tMeteor: {\n\t\t\t\tabsoluteUrl() {\n\t\t\t\t\treturn 'http://localhost:3000/';\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t});\n\ndescribe('SAML', () => {\n\tdescribe('[AuthorizeRequest]', () => {\n\t\tdescribe('AuthorizeRequest.generate', () => {\n\t\t\tit('should use the custom templates to generate the request', () => {\n\t\t\t\tconst authorizeRequest = AuthorizeRequest.generate(serviceProviderOptions);\n\t\t\t\texpect(authorizeRequest.request).to.be.equal(\n\t\t\t\t\t' Password ',\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tit('should include the unique ID on the request', () => {\n\t\t\t\tconst customOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tauthRequestTemplate: '__newId__',\n\t\t\t\t};\n\n\t\t\t\tconst authorizeRequest = AuthorizeRequest.generate(customOptions);\n\t\t\t\texpect(authorizeRequest.request).to.be.equal(authorizeRequest.id);\n\t\t\t});\n\n\t\t\tit('should include the custom options on the request', () => {\n\t\t\t\tconst customOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tauthRequestTemplate: '__callbackUrl__ __entryPoint__ __issuer__',\n\t\t\t\t};\n\n\t\t\t\tconst authorizeRequest = AuthorizeRequest.generate(customOptions);\n\t\t\t\texpect(authorizeRequest.request).to.be.equal('[callback-url] [entry-point] [issuer]');\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('[LogoutRequest]', () => {\n\t\tdescribe('LogoutRequest.generate', () => {\n\t\t\tit('should use the custom template to generate the request', () => {\n\t\t\t\tconst logoutRequest = LogoutRequest.generate(serviceProviderOptions, 'NameID', 'sessionIndex');\n\t\t\t\texpect(logoutRequest.request).to.be.equal('[logout-request-template]');\n\t\t\t});\n\n\t\t\tit('should include the unique ID on the request', () => {\n\t\t\t\tconst customOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tlogoutRequestTemplate: '__newId__',\n\t\t\t\t};\n\n\t\t\t\tconst logoutRequest = LogoutRequest.generate(customOptions, 'NameID', 'sessionIndex');\n\t\t\t\texpect(logoutRequest.request).to.be.equal(logoutRequest.id);\n\t\t\t});\n\n\t\t\tit('should include the custom options on the request', () => {\n\t\t\t\tconst customOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tlogoutRequestTemplate: '__idpSLORedirectURL__ __issuer__ __identifierFormat__ __nameID__ __sessionIndex__',\n\t\t\t\t};\n\n\t\t\t\tconst logoutRequest = LogoutRequest.generate(customOptions, 'NameID', 'sessionIndex');\n\t\t\t\texpect(logoutRequest.request).to.be.equal('[idpSLORedirectURL] [issuer] email NameID sessionIndex');\n\t\t\t});\n\t\t});\n\n\t\tdescribe('LogoutRequest.validate', () => {\n\t\t\tit('should extract the idpSession and nameID from the request', () => {\n\t\t\t\tconst parser = new LogoutRequestParser(serviceProviderOptions);\n\n\t\t\t\tparser.validate(simpleLogoutRequest, (err, data) => {\n\t\t\t\t\texpect(err).to.be.null;\n\t\t\t\t\texpect(data).to.be.an('object');\n\t\t\t\t\texpect(data).to.have.property('idpSession');\n\t\t\t\t\texpect(data).to.have.property('nameID');\n\t\t\t\t\t// @ts-ignore -- chai already ensured the object exists\n\t\t\t\t\texpect(data.idpSession).to.be.equal('_d6ad0e25459aaddd0433a81e159aa79e55dc52c280');\n\t\t\t\t\t// @ts-ignore -- chai already ensured the object exists\n\t\t\t\t\texpect(data.nameID).to.be.equal('_ab7e1d9a603473e92148d569d50176bafa60bcb2e9');\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should fail to parse an invalid xml', () => {\n\t\t\t\tconst parser = new LogoutRequestParser(serviceProviderOptions);\n\t\t\t\tparser.validate(invalidXml, (err, data) => {\n\t\t\t\t\texpect(err).to.exist;\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should fail to parse a xml without any LogoutRequest tag', () => {\n\t\t\t\tconst parser = new LogoutRequestParser(serviceProviderOptions);\n\t\t\t\tparser.validate(randomXml, (err, data) => {\n\t\t\t\t\texpect(err).to.be.equal('No Request Found');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should fail to parse a request with no NameId', () => {\n\t\t\t\tconst parser = new LogoutRequestParser(serviceProviderOptions);\n\n\t\t\t\tparser.validate(invalidLogoutRequest, (err, data) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').equal('SAML Logout Request: No NameID node found');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('[LogoutResponse]', () => {\n\t\tdescribe('LogoutResponse.generate', () => {\n\t\t\tit('should use the custom template to generate the response', () => {\n\t\t\t\tconst logoutResponse = LogoutResponse.generate(serviceProviderOptions, 'NameID', 'sessionIndex', 'inResponseToId');\n\t\t\t\texpect(logoutResponse.response).to.be.equal('[logout-response-template]');\n\t\t\t});\n\n\t\t\tit('should include the unique ID on the response', () => {\n\t\t\t\tconst customOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tlogoutResponseTemplate: '__newId__',\n\t\t\t\t};\n\n\t\t\t\tconst logoutResponse = LogoutResponse.generate(customOptions, 'NameID', 'sessionIndex', 'inResponseToId');\n\t\t\t\texpect(logoutResponse.response).to.be.equal(logoutResponse.id);\n\t\t\t});\n\n\t\t\tit('should include the custom options on the response', () => {\n\t\t\t\tconst customOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tlogoutResponseTemplate: '__idpSLORedirectURL__ __issuer__',\n\t\t\t\t};\n\n\t\t\t\tconst logoutResponse = LogoutResponse.generate(customOptions, 'NameID', 'sessionIndex', 'inResponseToId');\n\t\t\t\texpect(logoutResponse.response).to.be.equal('[idpSLORedirectURL] [issuer]');\n\t\t\t});\n\t\t});\n\n\t\tdescribe('LogoutResponse.validate', () => {\n\t\t\tit('should extract the inResponseTo from the response', () => {\n\t\t\t\tconst logoutResponse = simpleLogoutResponse.replace('[STATUSCODE]', 'urn:oasis:names:tc:SAML:2.0:status:Success');\n\t\t\t\tconst parser = new LogoutResponseParser(serviceProviderOptions);\n\n\t\t\t\tparser.validate(logoutResponse, (err, inResponseTo) => {\n\t\t\t\t\texpect(err).to.be.null;\n\t\t\t\t\texpect(inResponseTo).to.be.equal('_id-6530db3fcd23dc42a31c');\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should reject a response with a non-success StatusCode', () => {\n\t\t\t\tconst logoutResponse = simpleLogoutResponse.replace('[STATUSCODE]', 'Anything');\n\t\t\t\tconst parser = new LogoutResponseParser(serviceProviderOptions);\n\n\t\t\t\tparser.validate(logoutResponse, (err, inResponseTo) => {\n\t\t\t\t\texpect(err).to.be.equal('Error. Logout not confirmed by IDP');\n\t\t\t\t\texpect(inResponseTo).to.be.null;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should fail to parse an invalid xml', () => {\n\t\t\t\tconst parser = new LogoutResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(invalidXml, (err, inResponseTo) => {\n\t\t\t\t\texpect(err).to.exist;\n\t\t\t\t\texpect(inResponseTo).to.not.exist;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should fail to parse a xml without any LogoutResponse tag', () => {\n\t\t\t\tconst parser = new LogoutResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(randomXml, (err, inResponseTo) => {\n\t\t\t\t\texpect(err).to.be.equal('No Response Found');\n\t\t\t\t\texpect(inResponseTo).to.not.exist;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should fail to parse a xml without an inResponseTo attribute', () => {\n\t\t\t\tconst instant = new Date().toISOString();\n\t\t\t\tconst logoutResponse = simpleLogoutResponse\n\t\t\t\t\t.replace('[INSTANT]', instant)\n\t\t\t\t\t.replace('[STATUSCODE]', 'urn:oasis:names:tc:SAML:2.0:status:Success')\n\t\t\t\t\t.replace('InResponseTo=', 'SomethingElse=');\n\n\t\t\t\tconst parser = new LogoutResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(logoutResponse, (err, inResponseTo) => {\n\t\t\t\t\texpect(err).to.be.equal('Unexpected Response from IDP');\n\t\t\t\t\texpect(inResponseTo).to.not.exist;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should reject a response with no status tag', () => {\n\t\t\t\tconst parser = new LogoutResponseParser(serviceProviderOptions);\n\n\t\t\t\tparser.validate(invalidLogoutResponse, (err, inResponseTo) => {\n\t\t\t\t\texpect(err).to.be.equal('Error. Logout not confirmed by IDP');\n\t\t\t\t\texpect(inResponseTo).to.be.null;\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('[Metadata]', () => {\n\t\tdescribe('[Metadata.generate]', () => {\n\t\t\tit('should generate a simple metadata file when no certificate info is included', () => {\n\t\t\t\tconst metadata = ServiceProviderMetadata.generate(serviceProviderOptions);\n\t\t\t\texpect(metadata).to.be.equal(simpleMetadata);\n\t\t\t});\n\n\t\t\tit('should include additional information when a certificate is provided', () => {\n\t\t\t\tconst customOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tprivateCert: '[CERTIFICATE_CONTENT]',\n\t\t\t\t\tprivateKey: '[PRIVATE_KEY]',\n\t\t\t\t};\n\n\t\t\t\tconst metadata = ServiceProviderMetadata.generate(customOptions);\n\t\t\t\texpect(metadata).to.be.equal(metadataWithCertificate);\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('[Response]', () => {\n\t\tdescribe('[Response.validate]', () => {\n\t\t\tit('should extract a profile from the response', () => {\n\t\t\t\tconst notBefore = new Date();\n\t\t\t\tnotBefore.setMinutes(notBefore.getMinutes() - 3);\n\n\t\t\t\tconst notOnOrAfter = new Date();\n\t\t\t\tnotOnOrAfter.setMinutes(notOnOrAfter.getMinutes() + 3);\n\n\t\t\t\tconst response = simpleSamlResponse\n\t\t\t\t\t.replace('[NOTBEFORE]', notBefore.toISOString())\n\t\t\t\t\t.replace('[NOTONORAFTER]', notOnOrAfter.toISOString());\n\n\t\t\t\tconst parser = new ResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(response, (err, profile, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.null;\n\t\t\t\t\texpect(profile).to.be.an('object');\n\t\t\t\t\texpect(profile).to.have.property('inResponseToId').equal('[INRESPONSETO]');\n\t\t\t\t\texpect(profile).to.have.property('issuer').equal('[ISSUER]');\n\t\t\t\t\texpect(profile).to.have.property('nameID').equal('[NAMEID]');\n\t\t\t\t\texpect(profile).to.have.property('sessionIndex').equal('[SESSIONINDEX]');\n\t\t\t\t\texpect(profile).to.have.property('uid').equal('1');\n\t\t\t\t\texpect(profile).to.have.property('eduPersonAffiliation').equal('group1');\n\t\t\t\t\texpect(profile).to.have.property('email').equal('user1@example.com');\n\t\t\t\t\texpect(profile).to.have.property('channels').that.is.an('array').that.is.deep.equal(['channel1', 'pets', 'random']);\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should respect NotOnOrAfter conditions', () => {\n\t\t\t\tconst notBefore = new Date();\n\t\t\t\tnotBefore.setMinutes(notBefore.getMinutes() - 3);\n\n\t\t\t\tconst response = samlResponse.replace('[NOTBEFORE]', notBefore.toISOString()).replace('[NOTONORAFTER]', new Date().toISOString());\n\n\t\t\t\tconst parser = new ResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(response, (err, profile, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('NotBefore / NotOnOrAfter assertion failed');\n\t\t\t\t\texpect(profile).to.be.null;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should respect NotBefore conditions', () => {\n\t\t\t\tconst notBefore = new Date();\n\t\t\t\tnotBefore.setMinutes(notBefore.getMinutes() + 3);\n\n\t\t\t\tconst notOnOrAfter = new Date();\n\t\t\t\tnotOnOrAfter.setMinutes(notOnOrAfter.getMinutes() + 3);\n\n\t\t\t\tconst response = samlResponse.replace('[NOTBEFORE]', notBefore.toISOString()).replace('[NOTONORAFTER]', notOnOrAfter.toISOString());\n\n\t\t\t\tconst parser = new ResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(response, (err, profile, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('NotBefore / NotOnOrAfter assertion failed');\n\t\t\t\t\texpect(profile).to.be.null;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should fail to parse an invalid xml', () => {\n\t\t\t\tconst parser = new ResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(invalidXml, (err, data, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('Unknown SAML response message');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should fail to parse a xml without any Response tag', () => {\n\t\t\t\tconst parser = new ResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(randomXml, (err, data, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('Unknown SAML response message');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should reject a xml with multiple responses', () => {\n\t\t\t\tconst parser = new ResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(duplicatedSamlResponse, (err, data, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('Too many SAML responses');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should fail to parse a reponse with no Status tag', () => {\n\t\t\t\tconst parser = new ResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(samlResponseMissingStatus, (err, data, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('Missing StatusCode');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should fail to parse a reponse with a failed status', () => {\n\t\t\t\tconst parser = new ResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(samlResponseFailedStatus, (err, data, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('Status is: Failed');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should reject a response with multiple assertions', () => {\n\t\t\t\tconst parser = new ResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(samlResponseMultipleAssertions, (err, data, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('Too many SAML assertions');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should reject a response with no assertions', () => {\n\t\t\t\tconst parser = new ResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(samlResponseMissingAssertion, (err, data, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('Missing SAML assertion');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should reject a document without signatures if the setting requires at least one', () => {\n\t\t\t\tconst providerOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tsignatureValidationType: 'Either',\n\t\t\t\t\tcert: 'invalidCert',\n\t\t\t\t};\n\n\t\t\t\tconst notBefore = new Date();\n\t\t\t\tnotBefore.setMinutes(notBefore.getMinutes() - 3);\n\n\t\t\t\tconst notOnOrAfter = new Date();\n\t\t\t\tnotOnOrAfter.setMinutes(notOnOrAfter.getMinutes() + 3);\n\n\t\t\t\tconst response = simpleSamlResponse\n\t\t\t\t\t.replace('[NOTBEFORE]', notBefore.toISOString())\n\t\t\t\t\t.replace('[NOTONORAFTER]', notOnOrAfter.toISOString());\n\n\t\t\t\tconst parser = new ResponseParser(providerOptions);\n\t\t\t\tparser.validate(response, (err, data, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('No valid SAML Signature found');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should reject a document with multiple issuers', () => {\n\t\t\t\tconst parser = new ResponseParser(serviceProviderOptions);\n\t\t\t\tparser.validate(samlResponseMultipleIssuers, (err, data, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('Too many Issuers');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should decrypt an encrypted response', () => {\n\t\t\t\tconst options = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tprivateCert: privateKeyCert,\n\t\t\t\t\tprivateKey,\n\t\t\t\t};\n\n\t\t\t\tconst parser = new ResponseParser(options);\n\t\t\t\tparser.validate(encryptedResponse, (err, profile, loggedOut) => {\n\t\t\t\t\t// No way to change the assertion conditions on an encrypted response ¯\\_(ツ)_/¯\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('NotBefore / NotOnOrAfter assertion failed');\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t\texpect(profile).to.be.null;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should validate signatures on an encrypted response', () => {\n\t\t\t\tconst options = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tprivateCert: privateKeyCert,\n\t\t\t\t\tsignatureValidationType: 'All',\n\t\t\t\t\tprivateKey,\n\t\t\t\t};\n\n\t\t\t\tconst parser = new ResponseParser(options);\n\t\t\t\tparser.validate(encryptedResponse, (err, profile, loggedOut) => {\n\t\t\t\t\t// No way to change the assertion conditions on an encrypted response ¯\\_(ツ)_/¯\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('NotBefore / NotOnOrAfter assertion failed');\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t\texpect(profile).to.be.null;\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\tdescribe('[Validate Signatures]', () => {\n\t\t\tit('should reject an unsigned assertion if the setting says so', () => {\n\t\t\t\tconst providerOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tsignatureValidationType: 'Assertion',\n\t\t\t\t\tcert: 'invalidCert',\n\t\t\t\t};\n\n\t\t\t\tconst notBefore = new Date();\n\t\t\t\tnotBefore.setMinutes(notBefore.getMinutes() - 3);\n\n\t\t\t\tconst notOnOrAfter = new Date();\n\t\t\t\tnotOnOrAfter.setMinutes(notOnOrAfter.getMinutes() + 3);\n\n\t\t\t\tconst response = simpleSamlResponse\n\t\t\t\t\t.replace('[NOTBEFORE]', notBefore.toISOString())\n\t\t\t\t\t.replace('[NOTONORAFTER]', notOnOrAfter.toISOString());\n\n\t\t\t\tconst parser = new ResponseParser(providerOptions);\n\t\t\t\tparser.validate(response, (err, data, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('Invalid Assertion signature');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should reject an unsigned response if the setting says so', () => {\n\t\t\t\tconst providerOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tsignatureValidationType: 'Response',\n\t\t\t\t\tcert: 'invalidCert',\n\t\t\t\t};\n\n\t\t\t\tconst notBefore = new Date();\n\t\t\t\tnotBefore.setMinutes(notBefore.getMinutes() - 3);\n\n\t\t\t\tconst notOnOrAfter = new Date();\n\t\t\t\tnotOnOrAfter.setMinutes(notOnOrAfter.getMinutes() + 3);\n\n\t\t\t\tconst response = simpleSamlResponse\n\t\t\t\t\t.replace('[NOTBEFORE]', notBefore.toISOString())\n\t\t\t\t\t.replace('[NOTONORAFTER]', notOnOrAfter.toISOString());\n\n\t\t\t\tconst parser = new ResponseParser(providerOptions);\n\t\t\t\tparser.validate(response, (err, data, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('Invalid Signature');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should reject an assertion signed with an invalid signature', () => {\n\t\t\t\tconst providerOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tsignatureValidationType: 'Assertion',\n\t\t\t\t\tcert: certificate,\n\t\t\t\t};\n\n\t\t\t\tconst notBefore = new Date();\n\t\t\t\tnotBefore.setMinutes(notBefore.getMinutes() - 3);\n\n\t\t\t\tconst notOnOrAfter = new Date();\n\t\t\t\tnotOnOrAfter.setMinutes(notOnOrAfter.getMinutes() + 3);\n\n\t\t\t\tconst response = samlResponse.replace('[NOTBEFORE]', notBefore.toISOString()).replace('[NOTONORAFTER]', notOnOrAfter.toISOString());\n\n\t\t\t\tconst parser = new ResponseParser(providerOptions);\n\t\t\t\tparser.validate(response, (err, data, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('Invalid Assertion signature');\n\t\t\t\t\texpect(data).to.not.exist;\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should accept an assertion with a valid signature', () => {\n\t\t\t\tconst providerOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tsignatureValidationType: 'Assertion',\n\t\t\t\t\tcert: certificate,\n\t\t\t\t};\n\n\t\t\t\tconst parser = new ResponseParser(providerOptions);\n\t\t\t\tparser.validate(samlResponseValidAssertionSignature, (err, profile, loggedOut) => {\n\t\t\t\t\t// To have a valid signature, we can't change the assertion conditions ¯\\_(ツ)_/¯\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('NotBefore / NotOnOrAfter assertion failed');\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t\texpect(profile).to.be.null;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should accept a document with a valid response signature', () => {\n\t\t\t\tconst providerOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tsignatureValidationType: 'Response',\n\t\t\t\t\tcert: certificate,\n\t\t\t\t};\n\n\t\t\t\tconst parser = new ResponseParser(providerOptions);\n\t\t\t\tparser.validate(samlResponseValidSignatures, (err, profile, loggedOut) => {\n\t\t\t\t\t// To have a valid signature, we can't change the assertion conditions ¯\\_(ツ)_/¯\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('NotBefore / NotOnOrAfter assertion failed');\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t\texpect(profile).to.be.null;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should reject a document with a valid signature of the wrong type', () => {\n\t\t\t\tconst providerOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tsignatureValidationType: 'Response',\n\t\t\t\t\tcert: certificate,\n\t\t\t\t};\n\n\t\t\t\tconst parser = new ResponseParser(providerOptions);\n\t\t\t\tparser.validate(samlResponseValidAssertionSignature, (err, profile, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('Invalid Signature');\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t\texpect(profile).to.be.null;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should accept a document with both valid signatures', () => {\n\t\t\t\tconst providerOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tsignatureValidationType: 'All',\n\t\t\t\t\tcert: certificate,\n\t\t\t\t};\n\n\t\t\t\tconst parser = new ResponseParser(providerOptions);\n\t\t\t\tparser.validate(samlResponseValidSignatures, (err, profile, loggedOut) => {\n\t\t\t\t\t// To have a valid signature, we can't change the assertion conditions ¯\\_(ツ)_/¯\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('NotBefore / NotOnOrAfter assertion failed');\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t\texpect(profile).to.be.null;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should reject a document with a single signature when both are expected', () => {\n\t\t\t\tconst providerOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tsignatureValidationType: 'All',\n\t\t\t\t\tcert: certificate,\n\t\t\t\t};\n\n\t\t\t\tconst parser = new ResponseParser(providerOptions);\n\t\t\t\tparser.validate(samlResponseValidAssertionSignature, (err, profile, loggedOut) => {\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('Invalid Signature');\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t\texpect(profile).to.be.null;\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tit('should accept a document with either valid signature', () => {\n\t\t\t\tconst providerOptions = {\n\t\t\t\t\t...serviceProviderOptions,\n\t\t\t\t\tsignatureValidationType: 'Either',\n\t\t\t\t\tcert: certificate,\n\t\t\t\t};\n\n\t\t\t\tconst parser = new ResponseParser(providerOptions);\n\t\t\t\tparser.validate(samlResponseValidAssertionSignature, (err, profile, loggedOut) => {\n\t\t\t\t\t// To have a valid signature, we can't change the assertion conditions ¯\\_(ツ)_/¯\n\t\t\t\t\texpect(err).to.be.an('error').that.has.property('message').that.is.equal('NotBefore / NotOnOrAfter assertion failed');\n\t\t\t\t\texpect(loggedOut).to.be.false;\n\t\t\t\t\texpect(profile).to.be.null;\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('[Login]', () => {\n\t\tdescribe('UserMapping', () => {\n\t\t\tit('should collect all appropriate data from the profile, respecting the fieldMap', () => {\n\t\t\t\tconst { globalSettings } = SAMLUtils;\n\n\t\t\t\tconst fieldMap = {\n\t\t\t\t\tusername: 'anotherUsername',\n\t\t\t\t\temail: 'singleEmail',\n\t\t\t\t\tname: 'anotherName',\n\t\t\t\t};\n\n\t\t\t\tglobalSettings.userDataFieldMap = JSON.stringify(fieldMap);\n\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\t\t\t\tSAMLUtils.relayState = '[RelayState]';\n\t\t\t\tconst userObject = SAMLUtils.mapProfileToUserObject(profile);\n\n\t\t\t\texpect(userObject).to.be.an('object');\n\t\t\t\texpect(userObject).to.have.property('samlLogin').that.is.an('object');\n\t\t\t\texpect(userObject).to.have.nested.property('samlLogin.provider').that.is.equal('[RelayState]');\n\t\t\t\texpect(userObject).to.have.nested.property('samlLogin.idp').that.is.equal('[IssuerName]');\n\t\t\t\texpect(userObject).to.have.nested.property('samlLogin.idpSession').that.is.equal('[SessionIndex]');\n\t\t\t\texpect(userObject).to.have.nested.property('samlLogin.nameID').that.is.equal('[nameID]');\n\t\t\t\texpect(userObject).to.have.property('emailList').that.is.an('array').that.includes('testing@server.com');\n\t\t\t\texpect(userObject).to.have.property('fullName').that.is.equal('[AnotherName]');\n\t\t\t\texpect(userObject).to.have.property('username').that.is.equal('[AnotherUserName]');\n\t\t\t\texpect(userObject).to.not.have.property('roles');\n\t\t\t\texpect(userObject).to.have.property('channels').that.is.an('array').with.members(['pets', 'pics', 'funny', 'random', 'babies']);\n\t\t\t});\n\n\t\t\tit('should join array values if username receives an array of values', () => {\n\t\t\t\tconst { globalSettings } = SAMLUtils;\n\n\t\t\t\tconst multipleUsernames = {\n\t\t\t\t\t...profile,\n\t\t\t\t\tanotherUsername: ['user1', 'user2'],\n\t\t\t\t};\n\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\t\t\t\tconst userObject = SAMLUtils.mapProfileToUserObject(multipleUsernames);\n\n\t\t\t\texpect(userObject).to.be.an('object');\n\t\t\t\texpect(userObject).to.have.property('samlLogin').that.is.an('object');\n\t\t\t\texpect(userObject).to.have.property('username').that.is.equal('user1 user2');\n\t\t\t});\n\n\t\t\t// Channels support both a comma separated single value and an array of values\n\t\t\tit('should support `channels` attribute with multiple values', () => {\n\t\t\t\tconst channelsProfile = {\n\t\t\t\t\t...profile,\n\t\t\t\t\tchannels: ['pets', 'pics', 'funny'],\n\t\t\t\t};\n\n\t\t\t\tconst userObject = SAMLUtils.mapProfileToUserObject(channelsProfile);\n\n\t\t\t\texpect(userObject).to.be.an('object');\n\t\t\t\texpect(userObject).to.have.property('channels').that.is.an('array').with.members(['pets', 'pics', 'funny']);\n\t\t\t});\n\n\t\t\tit('should reject an userDataFieldMap without an email field', () => {\n\t\t\t\tconst { globalSettings } = SAMLUtils;\n\t\t\t\tglobalSettings.userDataFieldMap = JSON.stringify({});\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\n\t\t\t\texpect(() => {\n\t\t\t\t\tSAMLUtils.mapProfileToUserObject(profile);\n\t\t\t\t}).to.throw('SAML Profile did not contain an email address');\n\t\t\t});\n\n\t\t\tit('should fail to map a profile that is missing the email field', () => {\n\t\t\t\tconst { globalSettings } = SAMLUtils;\n\t\t\t\tconst fieldMap = {\n\t\t\t\t\tinexistentField: 'email',\n\t\t\t\t};\n\n\t\t\t\tglobalSettings.userDataFieldMap = JSON.stringify(fieldMap);\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\n\t\t\t\texpect(() => {\n\t\t\t\t\tSAMLUtils.mapProfileToUserObject(profile);\n\t\t\t\t}).to.throw('SAML Profile did not contain an email address');\n\t\t\t});\n\n\t\t\tit('should load data from the default fields when the field map is lacking', () => {\n\t\t\t\tconst { globalSettings } = SAMLUtils;\n\n\t\t\t\tconst fieldMap = {\n\t\t\t\t\temail: 'singleEmail',\n\t\t\t\t};\n\n\t\t\t\tglobalSettings.userDataFieldMap = JSON.stringify(fieldMap);\n\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\t\t\t\tconst userObject = SAMLUtils.mapProfileToUserObject(profile);\n\n\t\t\t\texpect(userObject).to.be.an('object');\n\t\t\t\texpect(userObject).to.have.property('fullName').that.is.equal('[DisplayName]');\n\t\t\t\texpect(userObject).to.have.property('username').that.is.equal('[username]');\n\t\t\t});\n\n\t\t\tit('should run custom regexes when one is used', () => {\n\t\t\t\tconst { globalSettings } = SAMLUtils;\n\n\t\t\t\tconst fieldMap = {\n\t\t\t\t\tusername: {\n\t\t\t\t\t\tfieldName: 'singleEmail',\n\t\t\t\t\t\tregex: '(.*)@.+$',\n\t\t\t\t\t},\n\t\t\t\t\temail: 'singleEmail',\n\t\t\t\t\tname: 'anotherName',\n\t\t\t\t};\n\n\t\t\t\tglobalSettings.userDataFieldMap = JSON.stringify(fieldMap);\n\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\t\t\t\tSAMLUtils.relayState = '[RelayState]';\n\t\t\t\tconst userObject = SAMLUtils.mapProfileToUserObject(profile);\n\n\t\t\t\texpect(userObject).to.be.an('object');\n\t\t\t\texpect(userObject).to.have.property('username').that.is.equal('testing');\n\t\t\t});\n\n\t\t\tit('should run custom templates when one is used', () => {\n\t\t\t\tconst { globalSettings } = SAMLUtils;\n\n\t\t\t\tconst fieldMap = {\n\t\t\t\t\tusername: {\n\t\t\t\t\t\tfieldName: 'anotherName',\n\t\t\t\t\t\ttemplate: 'user-__anotherName__',\n\t\t\t\t\t},\n\t\t\t\t\temail: 'singleEmail',\n\t\t\t\t\tname: {\n\t\t\t\t\t\tfieldNames: ['anotherName', 'displayName'],\n\t\t\t\t\t\ttemplate: '__displayName__ (__anotherName__)',\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tglobalSettings.userDataFieldMap = JSON.stringify(fieldMap);\n\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\t\t\t\tSAMLUtils.relayState = '[RelayState]';\n\t\t\t\tconst userObject = SAMLUtils.mapProfileToUserObject(profile);\n\n\t\t\t\texpect(userObject).to.be.an('object');\n\t\t\t\texpect(userObject).to.have.property('username').that.is.equal('user-[AnotherName]');\n\t\t\t\texpect(userObject).to.have.property('fullName').that.is.equal('[DisplayName] ([AnotherName])');\n\t\t\t});\n\n\t\t\tit('should combine regexes and templates when both are used', () => {\n\t\t\t\tconst { globalSettings } = SAMLUtils;\n\n\t\t\t\tconst fieldMap = {\n\t\t\t\t\tusername: {\n\t\t\t\t\t\tfieldName: 'anotherName',\n\t\t\t\t\t\ttemplate: 'user-__anotherName__45@7',\n\t\t\t\t\t\tregex: 'user-(.*)@',\n\t\t\t\t\t},\n\t\t\t\t\temail: 'singleEmail',\n\t\t\t\t\tname: {\n\t\t\t\t\t\tfieldNames: ['anotherName', 'displayName'],\n\t\t\t\t\t\tregex: '\\\\[(.*)\\\\]',\n\t\t\t\t\t\ttemplate: '__displayName__ (__regex__)',\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tglobalSettings.userDataFieldMap = JSON.stringify(fieldMap);\n\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\t\t\t\tSAMLUtils.relayState = '[RelayState]';\n\t\t\t\tconst userObject = SAMLUtils.mapProfileToUserObject(profile);\n\n\t\t\t\texpect(userObject).to.be.an('object');\n\t\t\t\t// should run the template first, then the regex\n\t\t\t\texpect(userObject).to.have.property('username').that.is.equal('[AnotherName]45');\n\t\t\t\t// for this one, should run the regex first, then the template\n\t\t\t\texpect(userObject).to.have.property('fullName').that.is.equal('[DisplayName] (AnotherName)');\n\t\t\t});\n\n\t\t\tit('should support individual array values on templates', () => {\n\t\t\t\tconst { globalSettings } = SAMLUtils;\n\n\t\t\t\tconst multipleUsernames = {\n\t\t\t\t\t...profile,\n\t\t\t\t\tanotherUsername: ['1', '2'],\n\t\t\t\t};\n\n\t\t\t\tconst fieldMap = {\n\t\t\t\t\tusername: {\n\t\t\t\t\t\tfieldName: 'anotherUsername',\n\t\t\t\t\t\ttemplate: 'user-__anotherUsername[-1]__',\n\t\t\t\t\t},\n\t\t\t\t\temail: {\n\t\t\t\t\t\tfieldName: 'anotherUsername',\n\t\t\t\t\t\ttemplate: 'user-__anotherUsername[0]__',\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tglobalSettings.userDataFieldMap = JSON.stringify(fieldMap);\n\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\t\t\t\tconst userObject = SAMLUtils.mapProfileToUserObject(multipleUsernames);\n\n\t\t\t\texpect(userObject).to.be.an('object');\n\t\t\t\texpect(userObject).to.have.property('username').that.is.equal('user-2');\n\t\t\t\texpect(userObject).to.have.property('emailList').that.is.an('array').that.includes('user-1');\n\t\t\t});\n\n\t\t\tit('should collect the values of every attribute on the field map', () => {\n\t\t\t\tconst { globalSettings } = SAMLUtils;\n\n\t\t\t\tconst fieldMap = {\n\t\t\t\t\tusername: 'anotherUsername',\n\t\t\t\t\temail: 'singleEmail',\n\t\t\t\t\tname: 'anotherName',\n\t\t\t\t\tothers: {\n\t\t\t\t\t\tfieldNames: ['issuer', 'sessionIndex', 'nameID', 'displayName', 'username', 'roles', 'otherRoles', 'language', 'channels'],\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tglobalSettings.userDataFieldMap = JSON.stringify(fieldMap);\n\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\t\t\t\tconst userObject = SAMLUtils.mapProfileToUserObject(profile);\n\n\t\t\t\texpect(userObject).to.be.an('object');\n\t\t\t\texpect(userObject)\n\t\t\t\t\t.to.have.property('attributeList')\n\t\t\t\t\t.that.is.a('Map')\n\t\t\t\t\t.that.have.keys([\n\t\t\t\t\t\t'anotherUsername',\n\t\t\t\t\t\t'singleEmail',\n\t\t\t\t\t\t'anotherName',\n\t\t\t\t\t\t'issuer',\n\t\t\t\t\t\t'sessionIndex',\n\t\t\t\t\t\t'nameID',\n\t\t\t\t\t\t'displayName',\n\t\t\t\t\t\t'username',\n\t\t\t\t\t\t'roles',\n\t\t\t\t\t\t'otherRoles',\n\t\t\t\t\t\t'language',\n\t\t\t\t\t\t'channels',\n\t\t\t\t\t]);\n\n\t\t\t\t// Workaround because chai doesn't handle Maps very well\n\t\t\t\tfor (const [key, value] of userObject.attributeList) {\n\t\t\t\t\texpect(value).to.be.equal(profile[key as keyof typeof profile]);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tit('should use the immutable property as default identifier', () => {\n\t\t\t\tconst { globalSettings } = SAMLUtils;\n\n\t\t\t\tglobalSettings.immutableProperty = 'EMail';\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\n\t\t\t\tconst userObject = SAMLUtils.mapProfileToUserObject(profile);\n\t\t\t\texpect(userObject).to.be.an('object');\n\t\t\t\texpect(userObject).to.have.property('identifier').that.has.property('type').that.is.equal('email');\n\n\t\t\t\tglobalSettings.immutableProperty = 'Username';\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\n\t\t\t\tconst newUserObject = SAMLUtils.mapProfileToUserObject(profile);\n\t\t\t\texpect(newUserObject).to.be.an('object');\n\t\t\t\texpect(newUserObject).to.have.property('identifier').that.has.property('type').that.is.equal('username');\n\t\t\t});\n\n\t\t\tit('should collect the identifier from the fieldset', () => {\n\t\t\t\tconst { globalSettings } = SAMLUtils;\n\n\t\t\t\tconst fieldMap = {\n\t\t\t\t\tusername: 'anotherUsername',\n\t\t\t\t\temail: 'singleEmail',\n\t\t\t\t\tname: 'anotherName',\n\t\t\t\t\t__identifier__: 'customField3',\n\t\t\t\t};\n\n\t\t\t\tglobalSettings.userDataFieldMap = JSON.stringify(fieldMap);\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\n\t\t\t\tconst userObject = SAMLUtils.mapProfileToUserObject(profile);\n\n\t\t\t\texpect(userObject).to.be.an('object');\n\t\t\t\texpect(userObject).to.have.property('identifier').that.has.property('type').that.is.equal('custom');\n\t\t\t\texpect(userObject).to.have.property('identifier').that.has.property('attribute').that.is.equal('customField3');\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('Response Mapping', () => {\n\t\tit('should extract a mapped user from the response', () => {\n\t\t\tconst notBefore = new Date();\n\t\t\tnotBefore.setMinutes(notBefore.getMinutes() - 3);\n\n\t\t\tconst notOnOrAfter = new Date();\n\t\t\tnotOnOrAfter.setMinutes(notOnOrAfter.getMinutes() + 3);\n\n\t\t\tconst response = simpleSamlResponse\n\t\t\t\t.replace('[NOTBEFORE]', notBefore.toISOString())\n\t\t\t\t.replace('[NOTONORAFTER]', notOnOrAfter.toISOString());\n\n\t\t\tconst parser = new ResponseParser(serviceProviderOptions);\n\t\t\tparser.validate(response, (err, profile, loggedOut) => {\n\t\t\t\texpect(profile).to.be.an('object');\n\t\t\t\texpect(err).to.be.null;\n\t\t\t\texpect(loggedOut).to.be.false;\n\n\t\t\t\tconst { globalSettings } = SAMLUtils;\n\n\t\t\t\tconst fieldMap = {\n\t\t\t\t\tusername: {\n\t\t\t\t\t\tfieldName: 'uid',\n\t\t\t\t\t\ttemplate: 'user-__uid__',\n\t\t\t\t\t},\n\t\t\t\t\temail: 'email',\n\t\t\t\t};\n\n\t\t\t\tglobalSettings.userDataFieldMap = JSON.stringify(fieldMap);\n\n\t\t\t\tSAMLUtils.updateGlobalSettings(globalSettings);\n\t\t\t\tSAMLUtils.relayState = '[RelayState]';\n\n\t\t\t\tif (!isTruthy(profile)) {\n\t\t\t\t\tthrow new Error('Profile is null');\n\t\t\t\t}\n\n\t\t\t\tconst userObject = SAMLUtils.mapProfileToUserObject(profile);\n\n\t\t\t\texpect(userObject).to.be.an('object');\n\t\t\t\texpect(userObject).to.have.property('samlLogin').that.is.an('object');\n\t\t\t\texpect(userObject).to.have.nested.property('samlLogin.provider').that.is.equal('[RelayState]');\n\t\t\t\texpect(userObject).to.have.nested.property('samlLogin.idp').that.is.equal('[ISSUER]');\n\t\t\t\texpect(userObject).to.have.nested.property('samlLogin.idpSession').that.is.equal('[SESSIONINDEX]');\n\t\t\t\texpect(userObject).to.have.nested.property('samlLogin.nameID').that.is.equal('[NAMEID]');\n\t\t\t\texpect(userObject).to.have.property('emailList').that.is.an('array').that.includes('user1@example.com');\n\t\t\t\texpect(userObject).to.have.property('username').that.is.equal('user-1');\n\n\t\t\t\tconst map = new Map();\n\t\t\t\tmap.set('epa', 'group1');\n\t\t\t});\n\t\t});\n\t});\n});\n","/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/models/server/raw/Sessions.tests.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/settings/server/functions/getSettingDefaults.tests.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/settings/server/functions/overrideGenerator.tests.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/settings/server/functions/settings.tests.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/settings/server/functions/validateSettings.tests.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/statistics/server/lib/UAParserCustom.tests.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/ui-utils/client.tests.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/ui-utils/server.tests.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/app/utils/lib/getURL.tests.js",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/components/Omnichannel/modals/TranscriptModal.spec.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/lib/download.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/lib/federation/Federation.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/lib/minimongo/bson.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/lib/minimongo/comparisons.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/lib/minimongo/lookups.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/lib/utils/isRTLScriptLanguage.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/providers/CallProvider/lib/parseStringToIceServers.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/siderbar/header/actions/Administration.spec.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByCategories.test.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByFree.test.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByPaid.test.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/admin/apps/helpers/filterAppsByText.test.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/admin/apps/helpers/sortAppsByAlphabeticalOrInverseOrder.test.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/admin/apps/helpers/sortAppsByClosestOrFarthestModificationDate.test.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/notFound/NotFoundPage.spec.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/Message.spec.tsx",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/hooks/useKatex.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/autoTranslate.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/buildImageURL.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/isMessageFirstUnread.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/isMessageNewDay.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/isMessageSequential.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/isOwnUserMessage.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/isParsedMessage.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/isValidLink.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessage.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessageAttachments.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/client/views/room/MessageList/lib/parseMessageQuoteAttachment.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/federation/FederationAddServerProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/federation/FederationJoinExternalPublicRoomProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/federation/FederationPublicRoomsProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/federation/FederationRemoveServerProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsAddMembersProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsConvertToChannelProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsDeleteProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsLeaveProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsRemoveMemberProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsRemoveRoomProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsUpdateMemberProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/teams/TeamsUpdateProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/video-conference/VideoConfCancelProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/video-conference/VideoConfInfoProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/video-conference/VideoConfJoinProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/video-conference/VideoConfListProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/definition/rest/v1/video-conference/VideoConfStartProps.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/mimeTypes.tests.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/roles/getMostImportantRole.tests.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/upgradeTab.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/arrayUtils.tests.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/isRelativeURL.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/isURL.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/parseCSV.tests.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/parseParameters.tests.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/secondsToHHMMSS.spec.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/lib/utils/stringUtils.tests.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/server/lib/fileUtils.tests.ts",[],[],"/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/tests/unit/server/sdk/errors.tests.ts",[],[],{"ruleId":"23248","severity":2,"message":"23249","line":7,"column":12,"nodeType":"23250","endLine":7,"endColumn":66,"suppressions":"23251"},{"ruleId":"23252","severity":2,"message":"23253","line":25,"column":29,"nodeType":"23250","messageId":"23254","endLine":25,"endColumn":80,"suppressions":"23255"},{"ruleId":"23256","severity":2,"message":"23257","line":25,"column":37,"nodeType":"23258","endLine":25,"endColumn":79,"suppressions":"23259"},{"ruleId":"23260","severity":1,"message":"23261","line":18,"column":6,"nodeType":"23262","messageId":"23263","endLine":18,"endColumn":41,"suggestions":"23264"},{"ruleId":"23260","severity":1,"message":"23261","line":17,"column":7,"nodeType":"23262","messageId":"23263","endLine":17,"endColumn":75,"suggestions":"23265"},{"ruleId":"23260","severity":1,"message":"23261","line":15,"column":7,"nodeType":"23262","messageId":"23263","endLine":15,"endColumn":30,"suggestions":"23266"},{"ruleId":"23260","severity":1,"message":"23261","line":20,"column":7,"nodeType":"23262","messageId":"23263","endLine":20,"endColumn":75,"suggestions":"23267"},{"ruleId":"23260","severity":1,"message":"23261","line":20,"column":7,"nodeType":"23262","messageId":"23263","endLine":20,"endColumn":78,"suggestions":"23268"},{"ruleId":"23269","severity":2,"message":"23270","line":8,"column":12,"nodeType":"23271","messageId":"23272","endLine":8,"endColumn":18,"suppressions":"23273"},{"ruleId":"23274","severity":2,"message":"23275","line":36,"column":5,"nodeType":"23276","messageId":"23277","endLine":36,"endColumn":24,"fix":"23278","suppressions":"23279"},{"ruleId":"23280","severity":2,"message":"23281","line":38,"column":8,"nodeType":"23258","messageId":"23282","endLine":38,"endColumn":31,"fix":"23283","suppressions":"23284"},{"ruleId":"23285","severity":2,"message":"23286","line":42,"column":37,"nodeType":"23271","messageId":"23287","endLine":42,"endColumn":46,"suppressions":"23288"},{"ruleId":"23289","severity":2,"message":"23290","line":43,"column":9,"nodeType":"23291","messageId":"23292","endLine":43,"endColumn":10,"suppressions":"23293"},{"ruleId":"23289","severity":2,"message":"23290","line":45,"column":30,"nodeType":"23291","messageId":"23292","endLine":45,"endColumn":31,"suppressions":"23294"},{"ruleId":"23269","severity":2,"message":"23295","line":138,"column":12,"nodeType":"23271","messageId":"23296","endLine":138,"endColumn":22,"suppressions":"23297"},{"ruleId":"23269","severity":2,"message":"23298","line":138,"column":24,"nodeType":"23271","messageId":"23296","endLine":138,"endColumn":35,"suppressions":"23299"},{"ruleId":"23300","severity":2,"message":"23301","line":136,"column":37,"nodeType":"23302","messageId":"23303","endLine":136,"endColumn":45,"suppressions":"23304"},{"ruleId":"23300","severity":2,"message":"23301","line":160,"column":37,"nodeType":"23302","messageId":"23303","endLine":160,"endColumn":45,"suppressions":"23305"},{"ruleId":"23306","severity":2,"message":"23307","line":69,"column":32,"nodeType":"23271","endLine":69,"endColumn":46,"suppressions":"23308"},{"ruleId":"23260","severity":1,"message":"23261","line":231,"column":21,"nodeType":"23262","messageId":"23263","endLine":231,"endColumn":42,"suggestions":"23309"},{"ruleId":"23269","severity":2,"message":"23310","line":478,"column":12,"nodeType":"23271","messageId":"23272","endLine":478,"endColumn":21,"suppressions":"23311"},{"ruleId":"23260","severity":1,"message":"23261","line":105,"column":8,"nodeType":"23262","messageId":"23263","endLine":105,"endColumn":61,"suggestions":"23312"},{"ruleId":"23300","severity":2,"message":"23313","line":66,"column":21,"nodeType":"23250","messageId":"23314","endLine":66,"endColumn":27,"suppressions":"23315"},{"ruleId":"23316","severity":1,"message":"23317","line":11,"column":19,"nodeType":"23318","messageId":"23319","endLine":62,"endColumn":4,"suppressions":"23320"},{"ruleId":"23260","severity":1,"message":"23261","line":71,"column":7,"nodeType":"23262","messageId":"23263","endLine":71,"endColumn":24,"suggestions":"23321"},{"ruleId":"23260","severity":1,"message":"23261","line":76,"column":7,"nodeType":"23262","messageId":"23263","endLine":76,"endColumn":38,"suggestions":"23322"},{"ruleId":"23260","severity":1,"message":"23261","line":88,"column":7,"nodeType":"23262","messageId":"23263","endLine":88,"endColumn":38,"suggestions":"23323"},{"ruleId":"23324","severity":1,"message":"23325","line":192,"column":25,"nodeType":"23326","messageId":"23327","endLine":192,"endColumn":51,"suggestions":"23328"},{"ruleId":"23324","severity":1,"message":"23325","line":193,"column":41,"nodeType":"23326","messageId":"23327","endLine":193,"endColumn":55,"suggestions":"23329"},{"ruleId":"23260","severity":1,"message":"23261","line":292,"column":7,"nodeType":"23262","messageId":"23263","endLine":292,"endColumn":41,"suggestions":"23330"},{"ruleId":"23260","severity":1,"message":"23261","line":63,"column":6,"nodeType":"23262","messageId":"23263","endLine":63,"endColumn":38,"suggestions":"23331"},{"ruleId":"23260","severity":1,"message":"23261","line":34,"column":7,"nodeType":"23262","messageId":"23263","endLine":34,"endColumn":28,"suggestions":"23332"},{"ruleId":"23260","severity":1,"message":"23261","line":54,"column":7,"nodeType":"23262","messageId":"23263","endLine":54,"endColumn":25,"suggestions":"23333"},{"ruleId":"23260","severity":1,"message":"23261","line":49,"column":7,"nodeType":"23262","messageId":"23263","endLine":49,"endColumn":25,"suggestions":"23334"},{"ruleId":"23335","severity":2,"message":"23336","line":7,"column":60,"nodeType":"23258","endLine":7,"endColumn":77,"fix":"23337","suppressions":"23338"},{"ruleId":"23335","severity":2,"message":"23336","line":10,"column":8,"nodeType":"23258","endLine":10,"endColumn":25,"suppressions":"23339"},{"ruleId":"23340","severity":1,"message":"23341","line":150,"column":3,"nodeType":"23250","endLine":154,"endColumn":5},{"ruleId":"23340","severity":1,"message":"23341","line":163,"column":3,"nodeType":"23250","endLine":178,"endColumn":5},{"ruleId":"23340","severity":1,"message":"23341","line":167,"column":5,"nodeType":"23250","endLine":169,"endColumn":7},{"ruleId":"23340","severity":1,"message":"23341","line":261,"column":4,"nodeType":"23250","endLine":268,"endColumn":6},{"ruleId":"23260","severity":1,"message":"23261","line":47,"column":6,"nodeType":"23262","messageId":"23263","endLine":47,"endColumn":51,"suggestions":"23342"},{"ruleId":"23343","severity":1,"message":"23344","line":98,"column":39,"nodeType":"23250","endLine":98,"endColumn":102},{"ruleId":"23345","severity":2,"message":"23346","line":7,"column":32,"nodeType":"23347","messageId":"23348","endLine":7,"endColumn":59,"suppressions":"23349"},{"ruleId":"23300","severity":2,"message":"23301","line":13,"column":24,"nodeType":"23302","messageId":"23303","endLine":13,"endColumn":28,"suppressions":"23350"},{"ruleId":"23345","severity":2,"message":"23346","line":21,"column":7,"nodeType":"23347","messageId":"23348","endLine":21,"endColumn":22,"suppressions":"23351"},{"ruleId":"23300","severity":2,"message":"23301","line":29,"column":24,"nodeType":"23302","messageId":"23303","endLine":29,"endColumn":28,"suppressions":"23352"},{"ruleId":"23269","severity":2,"message":"23353","line":122,"column":22,"nodeType":"23271","messageId":"23296","endLine":122,"endColumn":32,"suppressions":"23354"},{"ruleId":"23269","severity":2,"message":"23355","line":122,"column":34,"nodeType":"23271","messageId":"23296","endLine":122,"endColumn":45,"suppressions":"23356"},{"ruleId":"23269","severity":2,"message":"23295","line":167,"column":9,"nodeType":"23271","messageId":"23296","endLine":167,"endColumn":19,"suppressions":"23357"},{"ruleId":"23269","severity":2,"message":"23298","line":167,"column":21,"nodeType":"23271","messageId":"23296","endLine":167,"endColumn":32,"suppressions":"23358"},{"ruleId":"23269","severity":2,"message":"23295","line":265,"column":12,"nodeType":"23271","messageId":"23296","endLine":265,"endColumn":22,"suppressions":"23359"},{"ruleId":"23269","severity":2,"message":"23298","line":265,"column":24,"nodeType":"23271","messageId":"23296","endLine":265,"endColumn":35,"suppressions":"23360"},{"ruleId":"23269","severity":2,"message":"23353","line":274,"column":19,"nodeType":"23271","messageId":"23296","endLine":274,"endColumn":29,"suppressions":"23361"},{"ruleId":"23269","severity":2,"message":"23355","line":274,"column":31,"nodeType":"23271","messageId":"23296","endLine":274,"endColumn":42,"suppressions":"23362"},{"ruleId":"23269","severity":2,"message":"23355","line":325,"column":25,"nodeType":"23271","messageId":"23296","endLine":325,"endColumn":44,"suppressions":"23363"},{"ruleId":"23269","severity":2,"message":"23355","line":401,"column":25,"nodeType":"23271","messageId":"23296","endLine":401,"endColumn":44,"suppressions":"23364"},{"ruleId":"23365","severity":2,"message":"23366","line":27,"column":24,"nodeType":"23367","messageId":"23368","endLine":32,"endColumn":4,"suppressions":"23369"},{"ruleId":"23260","severity":1,"message":"23261","line":76,"column":7,"nodeType":"23262","messageId":"23263","endLine":76,"endColumn":47,"suggestions":"23370"},{"ruleId":"23316","severity":1,"message":"23371","line":58,"column":37,"nodeType":"23372","messageId":"23319","endLine":211,"endColumn":3},{"ruleId":"23260","severity":1,"message":"23261","line":53,"column":7,"nodeType":"23262","messageId":"23263","endLine":53,"endColumn":26,"suggestions":"23373"},{"ruleId":"23260","severity":1,"message":"23261","line":81,"column":7,"nodeType":"23262","messageId":"23263","endLine":81,"endColumn":26,"suggestions":"23374"},{"ruleId":"23375","severity":2,"message":"23376","line":30,"column":18,"nodeType":"23271","messageId":"23377","endLine":30,"endColumn":35,"suppressions":"23378"},{"ruleId":"23260","severity":1,"message":"23261","line":89,"column":7,"nodeType":"23262","messageId":"23263","endLine":89,"endColumn":30,"suggestions":"23379"},{"ruleId":"23300","severity":2,"message":"23301","line":42,"column":35,"nodeType":"23302","messageId":"23303","endLine":42,"endColumn":43,"suppressions":"23380"},{"ruleId":"23300","severity":2,"message":"23301","line":26,"column":35,"nodeType":"23302","messageId":"23303","endLine":26,"endColumn":43,"suppressions":"23381"},{"ruleId":"23300","severity":2,"message":"23301","line":20,"column":35,"nodeType":"23302","messageId":"23303","endLine":20,"endColumn":43,"suppressions":"23382"},{"ruleId":"23300","severity":2,"message":"23301","line":20,"column":35,"nodeType":"23302","messageId":"23303","endLine":20,"endColumn":43,"suppressions":"23383"},{"ruleId":"23300","severity":2,"message":"23301","line":22,"column":35,"nodeType":"23302","messageId":"23303","endLine":22,"endColumn":43,"suppressions":"23384"},{"ruleId":"23260","severity":1,"message":"23261","line":109,"column":3,"nodeType":"23262","messageId":"23263","endLine":109,"endColumn":60,"suggestions":"23385"},{"ruleId":"23386","severity":2,"message":"23387","line":72,"column":9,"nodeType":"23388","messageId":"23389","endLine":74,"endColumn":3,"suppressions":"23390"},{"ruleId":"23391","severity":2,"message":"23392","line":135,"column":53,"nodeType":"23258","messageId":"23393","endLine":135,"endColumn":72,"suppressions":"23394"},{"ruleId":"23391","severity":2,"message":"23392","line":85,"column":41,"nodeType":"23258","messageId":"23393","endLine":85,"endColumn":60,"suppressions":"23395"},{"ruleId":"23324","severity":1,"message":"23325","line":62,"column":54,"nodeType":"23326","messageId":"23327","endLine":62,"endColumn":62,"suppressions":"23396"},{"ruleId":"23324","severity":1,"message":"23325","line":62,"column":66,"nodeType":"23326","messageId":"23327","endLine":62,"endColumn":78,"suppressions":"23397"},{"ruleId":"23324","severity":1,"message":"23325","line":62,"column":94,"nodeType":"23326","messageId":"23327","endLine":62,"endColumn":102,"suppressions":"23398"},{"ruleId":"23324","severity":1,"message":"23325","line":62,"column":106,"nodeType":"23326","messageId":"23327","endLine":62,"endColumn":118,"suppressions":"23399"},{"ruleId":"23324","severity":1,"message":"23325","line":125,"column":40,"nodeType":"23326","messageId":"23327","endLine":125,"endColumn":60,"suppressions":"23400"},{"ruleId":"23324","severity":1,"message":"23325","line":125,"column":64,"nodeType":"23326","messageId":"23327","endLine":125,"endColumn":88,"suppressions":"23401"},{"ruleId":"23324","severity":1,"message":"23325","line":125,"column":90,"nodeType":"23326","messageId":"23327","endLine":125,"endColumn":114,"suppressions":"23402"},{"ruleId":"23403","severity":1,"message":"23404","line":49,"column":7,"nodeType":"23250","endLine":49,"endColumn":33},{"ruleId":"23324","severity":1,"message":"23325","line":160,"column":29,"nodeType":"23326","messageId":"23327","endLine":160,"endColumn":66,"suppressions":"23405"},{"ruleId":"23324","severity":1,"message":"23325","line":24,"column":32,"nodeType":"23326","messageId":"23327","endLine":24,"endColumn":37,"suppressions":"23406"},{"ruleId":"23324","severity":1,"message":"23325","line":27,"column":34,"nodeType":"23326","messageId":"23327","endLine":27,"endColumn":39,"suppressions":"23407"},{"ruleId":"23408","severity":1,"message":"23409","line":57,"column":80,"nodeType":"23410","messageId":"23411","endLine":57,"endColumn":82,"suppressions":"23412"},{"ruleId":"23280","severity":2,"message":"23413","line":63,"column":36,"nodeType":"23258","messageId":"23282","endLine":63,"endColumn":42,"fix":"23414","suppressions":"23415"},{"ruleId":"23280","severity":2,"message":"23416","line":63,"column":56,"nodeType":"23258","messageId":"23282","endLine":63,"endColumn":69,"fix":"23417","suppressions":"23418"},{"ruleId":"23280","severity":2,"message":"23413","line":72,"column":33,"nodeType":"23258","messageId":"23282","endLine":72,"endColumn":39,"fix":"23419","suppressions":"23420"},{"ruleId":"23280","severity":2,"message":"23416","line":72,"column":51,"nodeType":"23258","messageId":"23282","endLine":72,"endColumn":64,"fix":"23421","suppressions":"23422"},{"ruleId":"23324","severity":1,"message":"23325","line":27,"column":10,"nodeType":"23326","messageId":"23327","endLine":27,"endColumn":18,"suppressions":"23423"},{"ruleId":"23324","severity":1,"message":"23325","line":27,"column":22,"nodeType":"23326","messageId":"23327","endLine":27,"endColumn":34,"suppressions":"23424"},{"ruleId":"23324","severity":1,"message":"23325","line":27,"column":50,"nodeType":"23326","messageId":"23327","endLine":27,"endColumn":58,"suppressions":"23425"},{"ruleId":"23324","severity":1,"message":"23325","line":27,"column":62,"nodeType":"23326","messageId":"23327","endLine":27,"endColumn":74,"suppressions":"23426"},{"ruleId":"23340","severity":1,"message":"23341","line":15,"column":4,"nodeType":"23250","endLine":17,"endColumn":6},{"ruleId":"23340","severity":1,"message":"23341","line":44,"column":3,"nodeType":"23250","endLine":46,"endColumn":5},{"ruleId":"23340","severity":1,"message":"23341","line":83,"column":2,"nodeType":"23250","endLine":85,"endColumn":4},{"ruleId":"23260","severity":1,"message":"23261","line":24,"column":7,"nodeType":"23262","messageId":"23263","endLine":24,"endColumn":31,"suggestions":"23427"},{"ruleId":"23269","severity":2,"message":"23428","line":8,"column":19,"nodeType":"23271","messageId":"23272","endLine":8,"endColumn":32,"suppressions":"23429"},{"ruleId":"23430","severity":2,"message":"23431","line":58,"column":6,"nodeType":"23432","messageId":"23433","endLine":58,"endColumn":21,"suppressions":"23434"},{"ruleId":"23260","severity":1,"message":"23261","line":19,"column":7,"nodeType":"23262","messageId":"23263","endLine":19,"endColumn":23,"suggestions":"23435"},{"ruleId":"23260","severity":1,"message":"23261","line":21,"column":7,"nodeType":"23262","messageId":"23263","endLine":21,"endColumn":31,"suggestions":"23436"},{"ruleId":"23269","severity":2,"message":"23428","line":8,"column":19,"nodeType":"23271","messageId":"23272","endLine":8,"endColumn":32,"suppressions":"23437"},{"ruleId":"23403","severity":1,"message":"23404","line":42,"column":7,"nodeType":"23250","endLine":42,"endColumn":69},{"ruleId":"23300","severity":2,"message":"23313","line":142,"column":9,"nodeType":"23250","messageId":"23314","endLine":142,"endColumn":28,"suppressions":"23438"},{"ruleId":"23300","severity":2,"message":"23313","line":147,"column":10,"nodeType":"23250","messageId":"23314","endLine":147,"endColumn":29,"suppressions":"23439"},{"ruleId":"23340","severity":1,"message":"23341","line":64,"column":2,"nodeType":"23250","endLine":116,"endColumn":4},{"ruleId":"23260","severity":1,"message":"23261","line":293,"column":8,"nodeType":"23262","messageId":"23263","endLine":293,"endColumn":46,"suggestions":"23440"},{"ruleId":"23260","severity":1,"message":"23261","line":36,"column":8,"nodeType":"23262","messageId":"23263","endLine":36,"endColumn":86,"suggestions":"23441"},{"ruleId":"23442","severity":1,"message":"23443","line":24,"column":22,"nodeType":"23250","endLine":26,"endColumn":6},{"ruleId":"23403","severity":1,"message":"23404","line":29,"column":9,"nodeType":"23250","endLine":29,"endColumn":50},{"ruleId":"23260","severity":1,"message":"23261","line":20,"column":7,"nodeType":"23262","messageId":"23263","endLine":20,"endColumn":26,"suggestions":"23444"},{"ruleId":"23403","severity":1,"message":"23404","line":23,"column":6,"nodeType":"23250","endLine":23,"endColumn":106},{"ruleId":"23403","severity":1,"message":"23404","line":24,"column":6,"nodeType":"23250","endLine":24,"endColumn":55},{"ruleId":"23316","severity":1,"message":"23445","line":10,"column":25,"nodeType":"23318","messageId":"23319","endLine":359,"endColumn":2,"suppressions":"23446"},{"ruleId":"23447","severity":1,"message":"23448","line":57,"column":10,"nodeType":"23250","endLine":57,"endColumn":94},{"ruleId":"23260","severity":1,"message":"23261","line":47,"column":7,"nodeType":"23262","messageId":"23263","endLine":47,"endColumn":45,"suggestions":"23449"},{"ruleId":"23260","severity":1,"message":"23261","line":38,"column":7,"nodeType":"23262","messageId":"23263","endLine":38,"endColumn":53,"suggestions":"23450"},{"ruleId":"23300","severity":2,"message":"23313","line":42,"column":16,"nodeType":"23250","messageId":"23314","endLine":42,"endColumn":20,"suppressions":"23451"},{"ruleId":"23274","severity":2,"message":"23452","line":43,"column":4,"nodeType":"23453","messageId":"23277","endLine":43,"endColumn":25,"fix":"23454","suppressions":"23455"},{"ruleId":"23442","severity":1,"message":"23443","line":369,"column":4,"nodeType":"23250","endLine":373,"endColumn":6},{"ruleId":"23269","severity":2,"message":"23456","line":73,"column":21,"nodeType":"23271","messageId":"23296","endLine":73,"endColumn":51,"suppressions":"23457"},{"ruleId":"23260","severity":1,"message":"23261","line":17,"column":6,"nodeType":"23262","messageId":"23263","endLine":17,"endColumn":29,"suggestions":"23458"},{"ruleId":"23269","severity":2,"message":"23428","line":10,"column":12,"nodeType":"23271","messageId":"23272","endLine":10,"endColumn":25,"suppressions":"23459"},{"ruleId":"23269","severity":2,"message":"23428","line":9,"column":12,"nodeType":"23271","messageId":"23272","endLine":9,"endColumn":25,"suppressions":"23460"},{"ruleId":"23269","severity":2,"message":"23428","line":11,"column":12,"nodeType":"23271","messageId":"23272","endLine":11,"endColumn":25,"suppressions":"23461"},{"ruleId":"23260","severity":1,"message":"23261","line":27,"column":6,"nodeType":"23262","messageId":"23263","endLine":27,"endColumn":38,"suggestions":"23462"},{"ruleId":"23260","severity":1,"message":"23261","line":40,"column":7,"nodeType":"23262","messageId":"23263","endLine":40,"endColumn":44,"suggestions":"23463"},{"ruleId":"23260","severity":1,"message":"23261","line":154,"column":7,"nodeType":"23262","messageId":"23263","endLine":154,"endColumn":25,"suggestions":"23464"},{"ruleId":"23340","severity":1,"message":"23341","line":175,"column":4,"nodeType":"23250","endLine":179,"endColumn":6},{"ruleId":"23340","severity":1,"message":"23341","line":92,"column":6,"nodeType":"23250","endLine":100,"endColumn":8},{"ruleId":"23465","severity":1,"message":"23466","line":263,"column":37,"nodeType":"23250","endLine":269,"endColumn":4},{"ruleId":"23465","severity":1,"message":"23466","line":270,"column":42,"nodeType":"23250","endLine":276,"endColumn":4},{"ruleId":"23465","severity":1,"message":"23466","line":277,"column":36,"nodeType":"23250","endLine":283,"endColumn":4},{"ruleId":"23465","severity":1,"message":"23466","line":284,"column":38,"nodeType":"23250","endLine":290,"endColumn":4},{"ruleId":"23467","severity":2,"message":"23468","line":16,"column":2,"nodeType":"23469","messageId":"23470","endLine":30,"endColumn":4,"suppressions":"23471"},{"ruleId":"23467","severity":2,"message":"23468","line":34,"column":2,"nodeType":"23469","messageId":"23470","endLine":34,"endColumn":82,"suppressions":"23472"},{"ruleId":"23467","severity":2,"message":"23468","line":13,"column":2,"nodeType":"23469","messageId":"23470","endLine":32,"endColumn":3,"suppressions":"23473"},{"ruleId":"23260","severity":1,"message":"23261","line":70,"column":8,"nodeType":"23262","messageId":"23263","endLine":70,"endColumn":81,"suggestions":"23474"},{"ruleId":"23260","severity":1,"message":"23261","line":238,"column":9,"nodeType":"23262","messageId":"23263","endLine":238,"endColumn":90,"suggestions":"23475"},{"ruleId":"23260","severity":1,"message":"23261","line":252,"column":7,"nodeType":"23262","messageId":"23263","endLine":252,"endColumn":117,"suggestions":"23476"},{"ruleId":"23260","severity":1,"message":"23261","line":276,"column":7,"nodeType":"23262","messageId":"23263","endLine":276,"endColumn":80,"suggestions":"23477"},{"ruleId":"23260","severity":1,"message":"23261","line":93,"column":8,"nodeType":"23262","messageId":"23263","endLine":93,"endColumn":89,"suggestions":"23478"},{"ruleId":"23260","severity":1,"message":"23261","line":104,"column":6,"nodeType":"23262","messageId":"23263","endLine":104,"endColumn":116,"suggestions":"23479"},{"ruleId":"23260","severity":1,"message":"23261","line":104,"column":7,"nodeType":"23262","messageId":"23263","endLine":104,"endColumn":28,"suggestions":"23480"},{"ruleId":"23269","severity":2,"message":"23481","line":60,"column":2,"nodeType":"23271","messageId":"23296","endLine":60,"endColumn":18,"suppressions":"23482"},{"ruleId":"23269","severity":2,"message":"23483","line":62,"column":2,"nodeType":"23271","messageId":"23296","endLine":62,"endColumn":18,"suppressions":"23484"},{"ruleId":"23269","severity":2,"message":"23485","line":64,"column":2,"nodeType":"23271","messageId":"23296","endLine":64,"endColumn":23,"suppressions":"23486"},{"ruleId":"23269","severity":2,"message":"23487","line":66,"column":2,"nodeType":"23271","messageId":"23296","endLine":66,"endColumn":22,"suppressions":"23488"},{"ruleId":"23269","severity":2,"message":"23489","line":68,"column":2,"nodeType":"23271","messageId":"23296","endLine":68,"endColumn":41,"suppressions":"23490"},{"ruleId":"23269","severity":2,"message":"23491","line":70,"column":2,"nodeType":"23271","messageId":"23296","endLine":70,"endColumn":11,"suppressions":"23492"},{"ruleId":"23269","severity":2,"message":"23493","line":72,"column":2,"nodeType":"23271","messageId":"23296","endLine":72,"endColumn":24,"suppressions":"23494"},{"ruleId":"23442","severity":1,"message":"23443","line":17,"column":9,"nodeType":"23250","endLine":19,"endColumn":4},{"ruleId":"23442","severity":1,"message":"23443","line":28,"column":9,"nodeType":"23250","endLine":28,"endColumn":59},{"ruleId":"23403","severity":1,"message":"23404","line":32,"column":6,"nodeType":"23250","endLine":32,"endColumn":28},{"ruleId":"23495","severity":1,"message":"23496","line":36,"column":20,"nodeType":"23250","endLine":38,"endColumn":4},{"ruleId":"23403","severity":1,"message":"23404","line":39,"column":6,"nodeType":"23250","endLine":39,"endColumn":66},{"ruleId":"23260","severity":1,"message":"23261","line":56,"column":7,"nodeType":"23262","messageId":"23263","endLine":56,"endColumn":31,"suggestions":"23497"},{"ruleId":"23260","severity":1,"message":"23261","line":68,"column":7,"nodeType":"23262","messageId":"23263","endLine":68,"endColumn":31,"suggestions":"23498"},{"ruleId":"23260","severity":1,"message":"23261","line":91,"column":7,"nodeType":"23262","messageId":"23263","endLine":91,"endColumn":31,"suggestions":"23499"},{"ruleId":"23260","severity":1,"message":"23261","line":112,"column":7,"nodeType":"23262","messageId":"23263","endLine":112,"endColumn":31,"suggestions":"23500"},{"ruleId":"23260","severity":1,"message":"23261","line":31,"column":7,"nodeType":"23262","messageId":"23263","endLine":31,"endColumn":40,"suggestions":"23501"},{"ruleId":"23502","severity":2,"message":"23503","line":19,"column":57,"nodeType":"23318","messageId":"23393","endLine":19,"endColumn":59,"suppressions":"23504"},{"ruleId":"23260","severity":1,"message":"23261","line":25,"column":6,"nodeType":"23262","messageId":"23263","endLine":25,"endColumn":27,"suggestions":"23505"},{"ruleId":"23506","severity":2,"message":"23507","line":72,"column":33,"nodeType":"23318","messageId":"23508","endLine":78,"endColumn":2,"suppressions":"23509"},{"ruleId":"23269","severity":2,"message":"23510","line":31,"column":9,"nodeType":"23271","messageId":"23296","endLine":31,"endColumn":14,"suppressions":"23511"},{"ruleId":"23512","severity":1,"message":"23513","line":31,"column":63,"nodeType":"23514","endLine":31,"endColumn":71,"suggestions":"23515","suppressions":"23516"},{"ruleId":"23512","severity":1,"message":"23517","line":12,"column":5,"nodeType":"23271","endLine":12,"endColumn":17,"suppressions":"23518"},{"ruleId":"23512","severity":1,"message":"23519","line":12,"column":5,"nodeType":"23271","endLine":12,"endColumn":17,"suggestions":"23520","suppressions":"23521"},{"ruleId":"23260","severity":1,"message":"23261","line":77,"column":7,"nodeType":"23262","messageId":"23263","endLine":77,"endColumn":26,"suggestions":"23522"},{"ruleId":"23260","severity":1,"message":"23261","line":41,"column":6,"nodeType":"23262","messageId":"23263","endLine":41,"endColumn":31,"suggestions":"23523"},{"ruleId":"23260","severity":1,"message":"23261","line":9,"column":6,"nodeType":"23262","messageId":"23263","endLine":9,"endColumn":25,"suggestions":"23524"},{"ruleId":"23260","severity":1,"message":"23261","line":42,"column":7,"nodeType":"23262","messageId":"23263","endLine":42,"endColumn":85,"suggestions":"23525"},{"ruleId":"23526","severity":2,"message":"23527","line":39,"column":22,"nodeType":"23528","messageId":"23529","endLine":39,"endColumn":106,"suppressions":"23530"},{"ruleId":"23526","severity":2,"message":"23527","line":43,"column":29,"nodeType":"23528","messageId":"23529","endLine":43,"endColumn":122,"suppressions":"23531"},{"ruleId":"23506","severity":2,"message":"23507","line":41,"column":35,"nodeType":"23318","messageId":"23508","endLine":45,"endColumn":2,"suppressions":"23532"},{"ruleId":"23506","severity":2,"message":"23507","line":76,"column":20,"nodeType":"23318","messageId":"23508","endLine":113,"endColumn":5,"suppressions":"23533"},{"ruleId":"23260","severity":1,"message":"23261","line":112,"column":8,"nodeType":"23262","messageId":"23263","endLine":112,"endColumn":60,"suggestions":"23534"},{"ruleId":"23260","severity":1,"message":"23261","line":29,"column":4,"nodeType":"23262","messageId":"23263","endLine":29,"endColumn":38,"suggestions":"23535"},{"ruleId":"23260","severity":1,"message":"23261","line":40,"column":11,"nodeType":"23262","messageId":"23263","endLine":40,"endColumn":45,"suggestions":"23536"},{"ruleId":"23512","severity":1,"message":"23537","line":37,"column":5,"nodeType":"23514","endLine":37,"endColumn":19,"suggestions":"23538"},{"ruleId":"23512","severity":1,"message":"23539","line":52,"column":5,"nodeType":"23514","endLine":52,"endColumn":77,"suggestions":"23540"},{"ruleId":"23260","severity":1,"message":"23261","line":54,"column":11,"nodeType":"23262","messageId":"23263","endLine":54,"endColumn":45,"suggestions":"23541"},{"ruleId":"23260","severity":1,"message":"23261","line":43,"column":11,"nodeType":"23262","messageId":"23263","endLine":43,"endColumn":45,"suggestions":"23542"},{"ruleId":"23512","severity":1,"message":"23543","line":70,"column":5,"nodeType":"23514","endLine":70,"endColumn":40,"suggestions":"23544","suppressions":"23545"},{"ruleId":"23512","severity":1,"message":"23546","line":70,"column":6,"nodeType":"23347","endLine":70,"endColumn":39,"suppressions":"23547"},{"ruleId":"23512","severity":1,"message":"23548","line":96,"column":5,"nodeType":"23514","endLine":96,"endColumn":81,"suggestions":"23549","suppressions":"23550"},{"ruleId":"23512","severity":1,"message":"23551","line":96,"column":21,"nodeType":"23347","endLine":96,"endColumn":54,"suppressions":"23552"},{"ruleId":"23512","severity":1,"message":"23553","line":49,"column":5,"nodeType":"23514","endLine":49,"endColumn":69,"suggestions":"23554","suppressions":"23555"},{"ruleId":"23430","severity":2,"message":"23431","line":520,"column":4,"nodeType":"23432","messageId":"23433","endLine":520,"endColumn":31,"suppressions":"23556"},{"ruleId":"23260","severity":1,"message":"23261","line":85,"column":6,"nodeType":"23262","messageId":"23263","endLine":85,"endColumn":49,"suggestions":"23557"},{"ruleId":"23269","severity":2,"message":"23558","line":13,"column":11,"nodeType":"23271","messageId":"23272","endLine":13,"endColumn":19,"suppressions":"23559"},{"ruleId":"23269","severity":2,"message":"23560","line":6,"column":18,"nodeType":"23271","messageId":"23272","endLine":6,"endColumn":29,"suppressions":"23561"},{"ruleId":"23375","severity":2,"message":"23376","line":6,"column":18,"nodeType":"23271","messageId":"23377","endLine":6,"endColumn":29,"suppressions":"23562"},{"ruleId":"23260","severity":1,"message":"23261","line":28,"column":6,"nodeType":"23262","messageId":"23263","endLine":28,"endColumn":31,"suggestions":"23563"},{"ruleId":"23512","severity":1,"message":"23564","line":27,"column":5,"nodeType":"23271","endLine":27,"endColumn":9,"suppressions":"23565"},{"ruleId":"23512","severity":1,"message":"23566","line":27,"column":5,"nodeType":"23271","endLine":27,"endColumn":9,"suggestions":"23567","suppressions":"23568"},{"ruleId":"23316","severity":1,"message":"23317","line":98,"column":20,"nodeType":"23318","messageId":"23319","endLine":444,"endColumn":2,"suppressions":"23569"},{"ruleId":"23408","severity":1,"message":"23409","line":3,"column":28,"nodeType":"23410","messageId":"23411","endLine":3,"endColumn":30},{"ruleId":"23365","severity":2,"message":"23366","line":23,"column":37,"nodeType":"23367","messageId":"23368","endLine":23,"endColumn":93,"suppressions":"23570"},{"ruleId":"23365","severity":2,"message":"23366","line":23,"column":37,"nodeType":"23367","messageId":"23368","endLine":23,"endColumn":90,"suppressions":"23571"},{"ruleId":"23512","severity":1,"message":"23572","line":50,"column":9,"nodeType":"23271","endLine":50,"endColumn":20,"suggestions":"23573","suppressions":"23574"},{"ruleId":"23260","severity":1,"message":"23261","line":18,"column":6,"nodeType":"23262","messageId":"23263","endLine":18,"endColumn":24,"suggestions":"23575"},{"ruleId":"23365","severity":2,"message":"23366","line":23,"column":37,"nodeType":"23367","messageId":"23368","endLine":23,"endColumn":91,"suppressions":"23576"},{"ruleId":"23260","severity":1,"message":"23261","line":26,"column":7,"nodeType":"23262","messageId":"23263","endLine":26,"endColumn":46,"suggestions":"23577"},{"ruleId":"23502","severity":2,"message":"23578","line":20,"column":28,"nodeType":"23372","messageId":"23393","endLine":20,"endColumn":30,"suppressions":"23579"},{"ruleId":"23260","severity":1,"message":"23261","line":21,"column":6,"nodeType":"23262","messageId":"23263","endLine":21,"endColumn":33,"suggestions":"23580"},{"ruleId":"23581","severity":2,"message":"23582","line":2,"column":1,"nodeType":"23583","messageId":"23584","endLine":2,"endColumn":30,"fix":"23585","suppressions":"23586"},{"ruleId":"23587","severity":2,"message":"23588","line":5,"column":34,"nodeType":"23271","messageId":"23589","endLine":5,"endColumn":35,"suppressions":"23590"},{"ruleId":"23269","severity":2,"message":"23428","line":6,"column":12,"nodeType":"23271","messageId":"23272","endLine":6,"endColumn":25,"suppressions":"23591"},{"ruleId":"23269","severity":2,"message":"23428","line":6,"column":12,"nodeType":"23271","messageId":"23272","endLine":6,"endColumn":25,"suppressions":"23592"},{"ruleId":"23593","severity":1,"message":"23594","line":1,"column":1,"nodeType":"23583","endLine":1,"endColumn":30},{"ruleId":"23260","severity":1,"message":"23261","line":186,"column":7,"nodeType":"23262","messageId":"23263","endLine":186,"endColumn":42,"suggestions":"23595"},{"ruleId":"23260","severity":1,"message":"23261","line":107,"column":9,"nodeType":"23262","messageId":"23263","endLine":107,"endColumn":31,"suggestions":"23596"},{"ruleId":"23260","severity":1,"message":"23261","line":121,"column":9,"nodeType":"23262","messageId":"23263","endLine":121,"endColumn":31,"suggestions":"23597"},{"ruleId":"23260","severity":1,"message":"23261","line":17,"column":6,"nodeType":"23262","messageId":"23263","endLine":17,"endColumn":29,"suggestions":"23598"},{"ruleId":"23260","severity":1,"message":"23261","line":6,"column":6,"nodeType":"23262","messageId":"23263","endLine":6,"endColumn":24,"suggestions":"23599"},{"ruleId":"23260","severity":1,"message":"23261","line":9,"column":6,"nodeType":"23262","messageId":"23263","endLine":9,"endColumn":37,"suggestions":"23600"},{"ruleId":"23260","severity":1,"message":"23261","line":19,"column":6,"nodeType":"23262","messageId":"23263","endLine":19,"endColumn":25,"suggestions":"23601"},{"ruleId":"23602","severity":2,"message":"23603","line":44,"column":24,"nodeType":"23250","messageId":"23604","endLine":46,"endColumn":4,"suppressions":"23605"},{"ruleId":"23506","severity":2,"message":"23507","line":44,"column":24,"nodeType":"23250","messageId":"23508","endLine":46,"endColumn":4,"suppressions":"23606"},{"ruleId":"23269","severity":2,"message":"23560","line":24,"column":12,"nodeType":"23271","messageId":"23272","endLine":24,"endColumn":23,"suppressions":"23607"},{"ruleId":"23608","severity":1,"message":"23609","line":105,"column":18,"nodeType":"23453","messageId":"23610","endLine":105,"endColumn":31},{"ruleId":"23608","severity":1,"message":"23609","line":113,"column":11,"nodeType":"23453","messageId":"23610","endLine":113,"endColumn":24},{"ruleId":"23608","severity":1,"message":"23609","line":98,"column":11,"nodeType":"23453","messageId":"23610","endLine":98,"endColumn":24},{"ruleId":"23608","severity":1,"message":"23609","line":111,"column":11,"nodeType":"23453","messageId":"23610","endLine":111,"endColumn":24},{"ruleId":"23608","severity":1,"message":"23609","line":172,"column":13,"nodeType":"23453","messageId":"23610","endLine":172,"endColumn":26},{"ruleId":"23269","severity":2,"message":"23428","line":8,"column":19,"nodeType":"23271","messageId":"23272","endLine":8,"endColumn":32,"suppressions":"23611"},{"ruleId":"23269","severity":2,"message":"23428","line":6,"column":19,"nodeType":"23271","messageId":"23272","endLine":6,"endColumn":32,"suppressions":"23612"},{"ruleId":"23269","severity":2,"message":"23310","line":27,"column":12,"nodeType":"23271","messageId":"23272","endLine":27,"endColumn":21,"suppressions":"23613"},{"ruleId":"23269","severity":2,"message":"23310","line":5,"column":12,"nodeType":"23271","messageId":"23272","endLine":5,"endColumn":21,"suppressions":"23614"},{"ruleId":"23269","severity":2,"message":"23310","line":5,"column":12,"nodeType":"23271","messageId":"23272","endLine":5,"endColumn":21,"suppressions":"23615"},{"ruleId":"23269","severity":2,"message":"23310","line":6,"column":12,"nodeType":"23271","messageId":"23272","endLine":6,"endColumn":21,"suppressions":"23616"},{"ruleId":"23269","severity":2,"message":"23310","line":6,"column":12,"nodeType":"23271","messageId":"23272","endLine":6,"endColumn":21,"suppressions":"23617"},{"ruleId":"23269","severity":2,"message":"23310","line":72,"column":12,"nodeType":"23271","messageId":"23272","endLine":72,"endColumn":21,"suppressions":"23618"},{"ruleId":"23269","severity":2,"message":"23310","line":9,"column":12,"nodeType":"23271","messageId":"23272","endLine":9,"endColumn":21,"suppressions":"23619"},{"ruleId":"23300","severity":2,"message":"23313","line":39,"column":24,"nodeType":"23250","messageId":"23314","endLine":39,"endColumn":30,"suppressions":"23620"},{"ruleId":"23621","severity":2,"message":"23622","line":163,"column":8,"nodeType":"23623","messageId":"23624","endLine":163,"endColumn":58,"fix":"23625","suppressions":"23626"},{"ruleId":"23324","severity":1,"message":"23325","line":43,"column":10,"nodeType":"23326","messageId":"23327","endLine":43,"endColumn":33,"suppressions":"23627"},{"ruleId":"23324","severity":1,"message":"23325","line":75,"column":9,"nodeType":"23326","messageId":"23327","endLine":76,"endColumn":18,"suggestions":"23628","suppressions":"23629"},{"ruleId":"23324","severity":1,"message":"23325","line":85,"column":29,"nodeType":"23326","messageId":"23327","endLine":85,"endColumn":52,"suggestions":"23630","suppressions":"23631"},{"ruleId":"23324","severity":1,"message":"23325","line":87,"column":28,"nodeType":"23326","messageId":"23327","endLine":87,"endColumn":60,"suggestions":"23632","suppressions":"23633"},{"ruleId":"23324","severity":1,"message":"23325","line":89,"column":9,"nodeType":"23326","messageId":"23327","endLine":89,"endColumn":32,"suggestions":"23634","suppressions":"23635"},{"ruleId":"23324","severity":1,"message":"23325","line":95,"column":15,"nodeType":"23326","messageId":"23327","endLine":95,"endColumn":38,"suggestions":"23636","suppressions":"23637"},{"ruleId":"23324","severity":1,"message":"23325","line":101,"column":9,"nodeType":"23326","messageId":"23327","endLine":101,"endColumn":32,"suggestions":"23638","suppressions":"23639"},{"ruleId":"23640","severity":2,"message":"23641","line":17,"column":10,"nodeType":"23642","messageId":"23393","endLine":17,"endColumn":12,"suggestions":"23643","suppressions":"23644"},{"ruleId":"23640","severity":2,"message":"23641","line":24,"column":10,"nodeType":"23642","messageId":"23393","endLine":24,"endColumn":12,"suggestions":"23645","suppressions":"23646"},{"ruleId":"23640","severity":2,"message":"23641","line":45,"column":10,"nodeType":"23642","messageId":"23393","endLine":45,"endColumn":12,"suggestions":"23647","suppressions":"23648"},{"ruleId":"23502","severity":2,"message":"23503","line":51,"column":36,"nodeType":"23318","messageId":"23393","endLine":51,"endColumn":38,"suppressions":"23649"},{"ruleId":"23260","severity":1,"message":"23261","line":32,"column":12,"nodeType":"23262","messageId":"23263","endLine":32,"endColumn":30,"suggestions":"23650"},{"ruleId":"23260","severity":1,"message":"23261","line":17,"column":7,"nodeType":"23262","messageId":"23263","endLine":17,"endColumn":43,"suggestions":"23651"},{"ruleId":"23652","severity":2,"message":"23653","line":26,"column":10,"nodeType":"23318","messageId":"23654","endLine":26,"endColumn":120,"suppressions":"23655"},{"ruleId":"23656","severity":2,"message":"23657","line":7,"column":43,"nodeType":null,"messageId":"23658","endLine":7,"endColumn":56,"fix":"23659","suppressions":"23660"},{"ruleId":"23656","severity":2,"message":"23661","line":8,"column":2,"nodeType":null,"messageId":"23662","endLine":8,"endColumn":2,"fix":"23663","suppressions":"23664"},{"ruleId":"23656","severity":2,"message":"23661","line":9,"column":3,"nodeType":null,"messageId":"23662","endLine":9,"endColumn":3,"fix":"23665","suppressions":"23666"},{"ruleId":"23656","severity":2,"message":"23661","line":10,"column":1,"nodeType":null,"messageId":"23662","endLine":10,"endColumn":1,"fix":"23667","suppressions":"23668"},{"ruleId":"23656","severity":2,"message":"23661","line":11,"column":1,"nodeType":null,"messageId":"23662","endLine":11,"endColumn":1,"fix":"23669","suppressions":"23670"},{"ruleId":"23656","severity":2,"message":"23661","line":12,"column":6,"nodeType":null,"messageId":"23662","endLine":12,"endColumn":6,"fix":"23671","suppressions":"23672"},{"ruleId":"23656","severity":2,"message":"23673","line":13,"column":5,"nodeType":null,"messageId":"23658","endLine":13,"endColumn":6,"fix":"23674","suppressions":"23675"},{"ruleId":"23656","severity":2,"message":"23676","line":16,"column":2,"nodeType":null,"messageId":"23677","endLine":17,"endColumn":1,"fix":"23678","suppressions":"23679"},{"ruleId":"23252","severity":2,"message":"23253","line":9,"column":28,"nodeType":"23250","messageId":"23254","endLine":9,"endColumn":66,"suppressions":"23680"},{"ruleId":"23681","severity":2,"message":"23682","line":48,"column":1,"nodeType":"23271","messageId":"23683","endLine":48,"endColumn":4,"suppressions":"23684"},{"ruleId":"23685","severity":2,"message":"23686","line":197,"column":10,"nodeType":"23271","messageId":"23589","endLine":197,"endColumn":14,"suppressions":"23687"},{"ruleId":"23681","severity":2,"message":"23682","line":34,"column":12,"nodeType":"23271","messageId":"23683","endLine":34,"endColumn":15,"suppressions":"23688"},{"ruleId":"23681","severity":2,"message":"23682","line":35,"column":14,"nodeType":"23271","messageId":"23683","endLine":35,"endColumn":17,"suppressions":"23689"},{"ruleId":"23681","severity":2,"message":"23682","line":36,"column":15,"nodeType":"23271","messageId":"23683","endLine":36,"endColumn":18,"suppressions":"23690"},{"ruleId":"23681","severity":2,"message":"23682","line":37,"column":16,"nodeType":"23271","messageId":"23683","endLine":37,"endColumn":19,"suppressions":"23691"},{"ruleId":"23256","severity":2,"message":"23692","line":29,"column":22,"nodeType":"23258","endLine":29,"endColumn":33,"suppressions":"23693"},{"ruleId":"23681","severity":2,"message":"23682","line":34,"column":17,"nodeType":"23271","messageId":"23683","endLine":34,"endColumn":20,"suppressions":"23694"},{"ruleId":"23681","severity":2,"message":"23682","line":35,"column":13,"nodeType":"23271","messageId":"23683","endLine":35,"endColumn":16,"suppressions":"23695"},{"ruleId":"23685","severity":2,"message":"23696","line":37,"column":8,"nodeType":"23271","messageId":"23589","endLine":37,"endColumn":12,"suppressions":"23697"},{"ruleId":"23681","severity":2,"message":"23682","line":37,"column":15,"nodeType":"23271","messageId":"23683","endLine":37,"endColumn":18,"suppressions":"23698"},{"ruleId":"23685","severity":2,"message":"23699","line":39,"column":8,"nodeType":"23271","messageId":"23589","endLine":39,"endColumn":13,"suppressions":"23700"},{"ruleId":"23681","severity":2,"message":"23682","line":39,"column":16,"nodeType":"23271","messageId":"23683","endLine":39,"endColumn":19,"suppressions":"23701"},{"ruleId":"23681","severity":2,"message":"23682","line":40,"column":17,"nodeType":"23271","messageId":"23683","endLine":40,"endColumn":20,"suppressions":"23702"},{"ruleId":"23681","severity":2,"message":"23682","line":41,"column":17,"nodeType":"23271","messageId":"23683","endLine":41,"endColumn":20,"suppressions":"23703"},{"ruleId":"23681","severity":2,"message":"23682","line":42,"column":14,"nodeType":"23271","messageId":"23683","endLine":42,"endColumn":17,"suppressions":"23704"},{"ruleId":"23681","severity":2,"message":"23682","line":43,"column":15,"nodeType":"23271","messageId":"23683","endLine":43,"endColumn":18,"suppressions":"23705"},{"ruleId":"23685","severity":2,"message":"23706","line":176,"column":21,"nodeType":"23271","messageId":"23589","endLine":176,"endColumn":24,"suppressions":"23707"},{"ruleId":"23681","severity":2,"message":"23682","line":341,"column":15,"nodeType":"23271","messageId":"23683","endLine":341,"endColumn":18,"suppressions":"23708"},{"ruleId":"23685","severity":2,"message":"23709","line":399,"column":9,"nodeType":"23271","messageId":"23589","endLine":399,"endColumn":15,"suppressions":"23710"},{"ruleId":"23685","severity":2,"message":"23711","line":399,"column":17,"nodeType":"23271","messageId":"23589","endLine":399,"endColumn":25,"suppressions":"23712"},{"ruleId":"23685","severity":2,"message":"23709","line":468,"column":16,"nodeType":"23271","messageId":"23589","endLine":468,"endColumn":22,"suppressions":"23713"},{"ruleId":"23685","severity":2,"message":"23686","line":468,"column":24,"nodeType":"23271","messageId":"23589","endLine":468,"endColumn":28,"suppressions":"23714"},{"ruleId":"23685","severity":2,"message":"23709","line":503,"column":17,"nodeType":"23271","messageId":"23589","endLine":503,"endColumn":23,"suppressions":"23715"},{"ruleId":"23685","severity":2,"message":"23686","line":503,"column":25,"nodeType":"23271","messageId":"23589","endLine":503,"endColumn":29,"suppressions":"23716"},{"ruleId":"23685","severity":2,"message":"23686","line":524,"column":27,"nodeType":"23271","messageId":"23589","endLine":524,"endColumn":31,"suppressions":"23717"},{"ruleId":"23685","severity":2,"message":"23686","line":533,"column":17,"nodeType":"23271","messageId":"23589","endLine":533,"endColumn":21,"suppressions":"23718"},{"ruleId":"23685","severity":2,"message":"23709","line":544,"column":9,"nodeType":"23271","messageId":"23589","endLine":544,"endColumn":15,"suppressions":"23719"},{"ruleId":"23685","severity":2,"message":"23686","line":544,"column":17,"nodeType":"23271","messageId":"23589","endLine":544,"endColumn":21,"suppressions":"23720"},{"ruleId":"23685","severity":2,"message":"23721","line":544,"column":23,"nodeType":"23271","messageId":"23589","endLine":544,"endColumn":30,"suppressions":"23722"},{"ruleId":"23685","severity":2,"message":"23723","line":544,"column":32,"nodeType":"23271","messageId":"23589","endLine":544,"endColumn":40,"suppressions":"23724"},{"ruleId":"23685","severity":2,"message":"23686","line":556,"column":27,"nodeType":"23271","messageId":"23589","endLine":556,"endColumn":31,"suppressions":"23725"},{"ruleId":"23685","severity":2,"message":"23686","line":565,"column":13,"nodeType":"23271","messageId":"23589","endLine":565,"endColumn":17,"suppressions":"23726"},{"ruleId":"23685","severity":2,"message":"23686","line":575,"column":28,"nodeType":"23271","messageId":"23589","endLine":575,"endColumn":32,"suppressions":"23727"},{"ruleId":"23685","severity":2,"message":"23728","line":184,"column":66,"nodeType":"23271","messageId":"23589","endLine":184,"endColumn":72,"suppressions":"23729"},{"ruleId":"23685","severity":2,"message":"23728","line":460,"column":65,"nodeType":"23271","messageId":"23589","endLine":460,"endColumn":71,"suppressions":"23730"},{"ruleId":"23685","severity":2,"message":"23686","line":474,"column":10,"nodeType":"23271","messageId":"23589","endLine":474,"endColumn":14,"suppressions":"23731"},{"ruleId":"23685","severity":2,"message":"23686","line":481,"column":13,"nodeType":"23271","messageId":"23589","endLine":481,"endColumn":17,"suppressions":"23732"},{"ruleId":"23685","severity":2,"message":"23686","line":488,"column":11,"nodeType":"23271","messageId":"23589","endLine":488,"endColumn":15,"suppressions":"23733"},{"ruleId":"23685","severity":2,"message":"23686","line":496,"column":15,"nodeType":"23271","messageId":"23589","endLine":496,"endColumn":19,"suppressions":"23734"},{"ruleId":"23685","severity":2,"message":"23686","line":506,"column":13,"nodeType":"23271","messageId":"23589","endLine":506,"endColumn":17,"suppressions":"23735"},{"ruleId":"23685","severity":2,"message":"23736","line":506,"column":19,"nodeType":"23271","messageId":"23589","endLine":506,"endColumn":27,"suppressions":"23737"},{"ruleId":"23685","severity":2,"message":"23686","line":513,"column":10,"nodeType":"23271","messageId":"23589","endLine":513,"endColumn":14,"suppressions":"23738"},{"ruleId":"23685","severity":2,"message":"23686","line":520,"column":9,"nodeType":"23271","messageId":"23589","endLine":520,"endColumn":13,"suppressions":"23739"},{"ruleId":"23269","severity":2,"message":"23740","line":79,"column":32,"nodeType":"23271","messageId":"23296","endLine":79,"endColumn":47,"suppressions":"23741"},{"ruleId":"23260","severity":1,"message":"23261","line":83,"column":7,"nodeType":"23262","messageId":"23263","endLine":83,"endColumn":43,"suggestions":"23742"},{"ruleId":"23269","severity":2,"message":"23743","line":46,"column":51,"nodeType":"23271","messageId":"23296","endLine":46,"endColumn":62,"suppressions":"23744"},{"ruleId":"23260","severity":1,"message":"23261","line":92,"column":7,"nodeType":"23262","messageId":"23263","endLine":92,"endColumn":32,"suggestions":"23745"},{"ruleId":"23608","severity":1,"message":"23609","line":208,"column":2,"nodeType":"23453","messageId":"23610","endLine":208,"endColumn":57},{"ruleId":"23608","severity":1,"message":"23609","line":615,"column":3,"nodeType":"23453","messageId":"23610","endLine":615,"endColumn":41},{"ruleId":"23391","severity":2,"message":"23746","line":310,"column":61,"nodeType":"23258","messageId":"23393","endLine":310,"endColumn":74,"suppressions":"23747"},{"ruleId":"23260","severity":1,"message":"23261","line":31,"column":7,"nodeType":"23262","messageId":"23263","endLine":31,"endColumn":30,"suggestions":"23748"},{"ruleId":"23260","severity":1,"message":"23261","line":261,"column":7,"nodeType":"23262","messageId":"23263","endLine":261,"endColumn":44,"suggestions":"23749"},{"ruleId":"23260","severity":1,"message":"23261","line":313,"column":9,"nodeType":"23262","messageId":"23263","endLine":313,"endColumn":41,"suggestions":"23750"},{"ruleId":"23252","severity":2,"message":"23253","line":11,"column":25,"nodeType":"23250","messageId":"23254","endLine":11,"endColumn":48,"suppressions":"23751"},{"ruleId":"23260","severity":1,"message":"23261","line":23,"column":7,"nodeType":"23262","messageId":"23263","endLine":23,"endColumn":30,"suggestions":"23752"},{"ruleId":"23260","severity":1,"message":"23261","line":102,"column":7,"nodeType":"23262","messageId":"23263","endLine":102,"endColumn":47,"suggestions":"23753"},{"ruleId":"23252","severity":2,"message":"23253","line":23,"column":17,"nodeType":"23250","messageId":"23254","endLine":23,"endColumn":44,"suppressions":"23754"},{"ruleId":"23502","severity":2,"message":"23755","line":26,"column":51,"nodeType":"23372","messageId":"23393","endLine":26,"endColumn":53,"suppressions":"23756"},{"ruleId":"23502","severity":2,"message":"23757","line":27,"column":55,"nodeType":"23372","messageId":"23393","endLine":27,"endColumn":57,"suppressions":"23758"},{"ruleId":"23502","severity":2,"message":"23759","line":28,"column":53,"nodeType":"23372","messageId":"23393","endLine":28,"endColumn":55,"suppressions":"23760"},{"ruleId":"23502","severity":2,"message":"23761","line":29,"column":55,"nodeType":"23372","messageId":"23393","endLine":29,"endColumn":57,"suppressions":"23762"},{"ruleId":"23260","severity":1,"message":"23261","line":120,"column":8,"nodeType":"23262","messageId":"23263","endLine":120,"endColumn":51,"suggestions":"23763"},{"ruleId":"23260","severity":1,"message":"23261","line":183,"column":8,"nodeType":"23262","messageId":"23263","endLine":183,"endColumn":51,"suggestions":"23764"},{"ruleId":"23765","severity":1,"message":"23766","line":753,"column":25,"nodeType":"23767","messageId":"23768","endLine":753,"endColumn":28,"suggestions":"23769"},{"ruleId":"23765","severity":1,"message":"23766","line":780,"column":40,"nodeType":"23767","messageId":"23768","endLine":780,"endColumn":43,"suggestions":"23770"},{"ruleId":"23765","severity":1,"message":"23766","line":839,"column":25,"nodeType":"23767","messageId":"23768","endLine":839,"endColumn":28,"suggestions":"23771"},{"ruleId":"23765","severity":1,"message":"23766","line":866,"column":40,"nodeType":"23767","messageId":"23768","endLine":866,"endColumn":43,"suggestions":"23772"},{"ruleId":"23765","severity":1,"message":"23766","line":631,"column":25,"nodeType":"23767","messageId":"23768","endLine":631,"endColumn":28,"suggestions":"23773"},{"ruleId":"23765","severity":1,"message":"23766","line":658,"column":40,"nodeType":"23767","messageId":"23768","endLine":658,"endColumn":43,"suggestions":"23774"},{"ruleId":"23765","severity":1,"message":"23766","line":701,"column":25,"nodeType":"23767","messageId":"23768","endLine":701,"endColumn":28,"suggestions":"23775"},{"ruleId":"23765","severity":1,"message":"23766","line":728,"column":40,"nodeType":"23767","messageId":"23768","endLine":728,"endColumn":43,"suggestions":"23776"},{"ruleId":"23765","severity":1,"message":"23766","line":630,"column":25,"nodeType":"23767","messageId":"23768","endLine":630,"endColumn":28,"suggestions":"23777"},{"ruleId":"23765","severity":1,"message":"23766","line":657,"column":40,"nodeType":"23767","messageId":"23768","endLine":657,"endColumn":43,"suggestions":"23778"},{"ruleId":"23765","severity":1,"message":"23766","line":699,"column":25,"nodeType":"23767","messageId":"23768","endLine":699,"endColumn":28,"suggestions":"23779"},{"ruleId":"23765","severity":1,"message":"23766","line":726,"column":40,"nodeType":"23767","messageId":"23768","endLine":726,"endColumn":43,"suggestions":"23780"},{"ruleId":"23765","severity":1,"message":"23766","line":7,"column":39,"nodeType":"23767","messageId":"23768","endLine":7,"endColumn":42,"suggestions":"23781"},{"ruleId":"23765","severity":1,"message":"23766","line":21,"column":29,"nodeType":"23767","messageId":"23768","endLine":21,"endColumn":32,"suggestions":"23782"},{"ruleId":"23765","severity":1,"message":"23766","line":21,"column":39,"nodeType":"23767","messageId":"23768","endLine":21,"endColumn":42,"suggestions":"23783"},{"ruleId":"23784","severity":2,"message":"23785","line":35,"column":45,"nodeType":"23318","messageId":"23786","endLine":37,"endColumn":6,"suppressions":"23787"},{"ruleId":"23784","severity":2,"message":"23788","line":128,"column":50,"nodeType":"23318","messageId":"23786","endLine":130,"endColumn":7,"suppressions":"23789"},{"ruleId":"23784","severity":2,"message":"23788","line":133,"column":46,"nodeType":"23318","messageId":"23786","endLine":135,"endColumn":7,"suppressions":"23790"},{"ruleId":"23765","severity":1,"message":"23766","line":13,"column":39,"nodeType":"23767","messageId":"23768","endLine":13,"endColumn":42,"suggestions":"23791"},{"ruleId":"23685","severity":2,"message":"23792","line":290,"column":7,"nodeType":"23271","messageId":"23589","endLine":290,"endColumn":18,"suppressions":"23793"},{"ruleId":"23252","severity":2,"message":"23253","line":15,"column":15,"nodeType":"23250","messageId":"23254","endLine":15,"endColumn":50,"suppressions":"23794"},{"ruleId":"23252","severity":2,"message":"23253","line":15,"column":52,"nodeType":"23250","messageId":"23254","endLine":15,"endColumn":93,"suppressions":"23795"},{"ruleId":"23285","severity":2,"message":"23286","line":76,"column":19,"nodeType":"23271","messageId":"23287","endLine":76,"endColumn":28,"suppressions":"23796"},{"ruleId":"23797","severity":2,"message":"23798","line":29,"column":1,"nodeType":"23583","endLine":29,"endColumn":142,"fix":"23799","suppressions":"23800"},{"ruleId":"23797","severity":2,"message":"23798","line":44,"column":1,"nodeType":"23583","endLine":44,"endColumn":103,"fix":"23801","suppressions":"23802"},{"ruleId":"23502","severity":2,"message":"23503","line":13,"column":89,"nodeType":"23318","messageId":"23393","endLine":13,"endColumn":92,"suppressions":"23803"},{"ruleId":"23656","severity":2,"message":"23804","line":13,"column":90,"nodeType":null,"messageId":"23677","endLine":13,"endColumn":91,"fix":"23805","suppressions":"23806"},{"ruleId":"23656","severity":2,"message":"23807","line":7,"column":8,"nodeType":null,"messageId":"23658","endLine":10,"endColumn":28,"fix":"23808","suppressions":"23809"},{"ruleId":"23656","severity":2,"message":"23661","line":11,"column":2,"nodeType":null,"messageId":"23662","endLine":11,"endColumn":2,"fix":"23810","suppressions":"23811"},{"ruleId":"23656","severity":2,"message":"23661","line":12,"column":1,"nodeType":null,"messageId":"23662","endLine":12,"endColumn":1,"fix":"23812","suppressions":"23813"},{"ruleId":"23656","severity":2,"message":"23661","line":13,"column":4,"nodeType":null,"messageId":"23662","endLine":13,"endColumn":4,"fix":"23814","suppressions":"23815"},{"ruleId":"23656","severity":2,"message":"23661","line":14,"column":5,"nodeType":null,"messageId":"23662","endLine":14,"endColumn":5,"fix":"23816","suppressions":"23817"},{"ruleId":"23656","severity":2,"message":"23661","line":15,"column":1,"nodeType":null,"messageId":"23662","endLine":15,"endColumn":1,"fix":"23818","suppressions":"23819"},{"ruleId":"23656","severity":2,"message":"23673","line":16,"column":5,"nodeType":null,"messageId":"23658","endLine":16,"endColumn":6,"fix":"23820","suppressions":"23821"},{"ruleId":"23656","severity":2,"message":"23676","line":19,"column":2,"nodeType":null,"messageId":"23677","endLine":20,"endColumn":1,"fix":"23822","suppressions":"23823"},{"ruleId":"23608","severity":1,"message":"23609","line":120,"column":6,"nodeType":"23453","messageId":"23610","endLine":120,"endColumn":61},{"ruleId":"23608","severity":1,"message":"23609","line":122,"column":6,"nodeType":"23453","messageId":"23610","endLine":122,"endColumn":61},"import/no-dynamic-require","Calls to require() should use string literals","CallExpression",["23824"],"@typescript-eslint/no-var-requires","Require statement not part of import statement.","noVarReqs",["23825","23826"],"import/no-unresolved","Unable to resolve path to module '!!raw-loader!../private/public/icons.svg'.","Literal",["23827"],"@typescript-eslint/prefer-optional-chain","Prefer using an optional chain expression instead, as it's more concise and easier to read.","LogicalExpression","preferOptionalChain",["23828"],["23829"],["23830"],["23831"],["23832"],"@typescript-eslint/naming-convention","Interface name `Window` must match the RegExp: /^I[A-Z]/u","Identifier","satisfyCustom",["23833"],"spaced-comment","Expected space or tab after '/*' in comment.","Block","expectedSpaceAfter",{"range":"23834","text":"23835"},["23836"],"dot-notation","[\"GoogleAnalyticsObject\"] is better written in dot notation.","useDot",{"range":"23837","text":"23838"},["23839"],"prefer-rest-params","Use the rest parameters instead of 'arguments'.","preferRestParams",["23840"],"no-sequences","Unexpected use of comma operator.","SequenceExpression","unexpectedCommaExpression",["23841"],["23842"],"Variable name `public_key` must match one of the following formats: camelCase, UPPER_CASE, PascalCase","doesNotMatchFormat",["23843"],"Variable name `private_key` must match one of the following formats: camelCase, UPPER_CASE, PascalCase",["23844"],"new-cap","A constructor name should not start with a lowercase letter.","NewExpression","lower",["23845"],["23846"],"react-hooks/rules-of-hooks","React Hook \"useInviteToken\" is called in function \"post\" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word \"use\".",["23847"],["23848"],"Interface name `Endpoints` must match the RegExp: /^I[A-Z]/u",["23849"],["23850"],"A function with a name starting with an uppercase letter should only be used as a constructor.","upper",["23851"],"complexity","Arrow function has a complexity of 40. Maximum allowed is 31.","ArrowFunctionExpression","complex",["23852"],["23853"],["23854"],["23855"],"@typescript-eslint/no-non-null-assertion","Forbidden non-null assertion.","TSNonNullExpression","noNonNull",["23856"],["23857"],["23858"],["23859"],["23860"],["23861"],["23862"],"import/no-duplicates","'/Users/diegosampaio/dev/Rocket.Chat/apps/meteor/app/autotranslate/server/autotranslate.ts' imported multiple times.",{"range":"23863","text":"23864"},["23865"],["23866"],"you-dont-need-lodash-underscore/each","Consider using the native Array.prototype.forEach() or Object.entries().forEach()",["23867"],"you-dont-need-lodash-underscore/all","Consider using the native Array.prototype.every()","no-proto","The '__proto__' property is deprecated.","MemberExpression","unexpectedProto",["23868"],["23869"],["23870"],["23871"],"Parameter name `public_key` must match one of the following formats: camelCase",["23872"],"Parameter name `private_key` must match one of the following formats: camelCase",["23873"],["23874"],["23875"],["23876"],["23877"],["23878"],["23879"],["23880"],["23881"],"no-await-in-loop","Unexpected `await` inside a loop.","AwaitExpression","unexpectedAwait",["23882"],["23883"],"Async method 'onChangeRoomMembership' has a complexity of 35. Maximum allowed is 31.","FunctionExpression",["23884"],["23885"],"@typescript-eslint/no-empty-interface","An empty interface is equivalent to `{}`.","noEmpty",["23886"],["23887"],["23888"],["23889"],["23890"],["23891"],["23892"],["23893"],"@typescript-eslint/no-namespace","ES2015 module syntax is preferred over namespaces.","TSModuleDeclaration","moduleSyntaxIsPreferred",["23894"],"no-control-regex","Unexpected control character(s) in regular expression: \\x07.","unexpected",["23895"],["23896"],["23897"],["23898"],["23899"],["23900"],["23901"],["23902"],["23903"],"you-dont-need-lodash-underscore/contains","Consider using the native Array.prototype.includes()",["23904"],["23905"],["23906"],"@typescript-eslint/ban-types","Don't use `{}` as a type. `{}` actually means \"any non-nullish value\".\n- If you want a type meaning \"any object\", you probably want `object` instead.\n- If you want a type meaning \"any value\", you probably want `unknown` instead.\n- If you want a type meaning \"empty object\", you probably want `Record` instead.","TSTypeLiteral","bannedTypeMessage",["23907"],"[\"blob\"] is better written in dot notation.",{"range":"23908","text":"23909"},["23910"],"[\"contentType\"] is better written in dot notation.",{"range":"23911","text":"23912"},["23913"],{"range":"23914","text":"23909"},["23915"],{"range":"23916","text":"23912"},["23917"],["23918"],["23919"],["23920"],["23921"],["23922"],"Interface name `ServerMethods` must match the RegExp: /^I[A-Z]/u",["23923"],"no-unsafe-finally","Unsafe usage of ReturnStatement.","ReturnStatement","unsafeUsage",["23924"],["23925"],["23926"],["23927"],["23928"],["23929"],["23930"],["23931"],"you-dont-need-lodash-underscore/map","Consider using the native Array.prototype.map()",["23932"],"Async arrow function has a complexity of 173. Maximum allowed is 31.",["23933"],"you-dont-need-lodash-underscore/find","Consider using the native Array.prototype.find()",["23934"],["23935"],["23936"],"Expected space or tab after '//' in comment.","Line",{"range":"23937","text":"23835"},["23938"],"Parameter name `Streamer` must match one of the following formats: camelCase",["23939"],["23940"],["23941"],["23942"],["23943"],["23944"],["23945"],["23946"],"you-dont-need-lodash-underscore/reduce","Consider using the native Array.prototype.reduce()","no-void","Expected 'undefined' and instead saw 'void'.","UnaryExpression","noVoid",["23947"],["23948"],["23949"],["23950"],["23951"],["23952"],["23953"],["23954"],["23955"],["23956"],"Parameter name `UI_Use_Real_Name` must match one of the following formats: camelCase",["23957"],"Parameter name `Chatops_Username` must match one of the following formats: camelCase",["23958"],"Parameter name `AutoTranslate_Enabled` must match one of the following formats: camelCase",["23959"],"Parameter name `Message_AllowEditing` must match one of the following formats: camelCase",["23960"],"Parameter name `Message_AllowEditing_BlockEditInMinutes` must match one of the following formats: camelCase",["23961"],"Parameter name `API_Embed` must match one of the following formats: camelCase",["23962"],"Parameter name `Message_GroupingPeriod` must match one of the following formats: camelCase",["23963"],"you-dont-need-lodash-underscore/filter","Consider using the native Array.prototype.filter()",["23964"],["23965"],["23966"],["23967"],["23968"],"@typescript-eslint/no-empty-function","Unexpected empty arrow function.",["23969"],["23970"],"react/no-multi-comp","Declare only one React component per file","onlyOneComponent",["23971"],"Parameter name `Badge` must match one of the following formats: camelCase",["23972"],"react-hooks/exhaustive-deps","React Hook useMemo has missing dependencies: 'conditions' and 'debouncedFilter'. Either include them or remove the dependency array.","ArrayExpression",["23973"],["23974"],"React Hook useEffect was passed a dependency list that is not an array literal. This means we can't statically verify whether you've passed the correct dependencies.",["23975"],"React Hook useEffect has a missing dependency: 'effect'. Either include it or remove the dependency array. If 'effect' changes too often, find the parent component that defines it and wrap that definition in useCallback.",["23976"],["23977"],["23978"],["23979"],["23980"],["23981"],"no-nested-ternary","Do not nest ternary expressions.","ConditionalExpression","noNestedTernary",["23982"],["23983"],["23984"],["23985"],["23986"],["23987"],["23988"],"React Hook useEffect has a missing dependency: 'step'. Either include it or remove the dependency array.",["23989"],"React Hook useCallback has a missing dependency: 'onSuccess'. Either include it or remove the dependency array. If 'onSuccess' changes too often, find the parent component that defines it and wrap that definition in useCallback.",["23990"],["23991"],["23992"],"React Hook useEffect has a missing dependency: 'setting'. Either include it or remove the dependency array.",["23993"],["23994"],"React Hook useEffect has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked.",["23995"],"React Hook useCallback has a missing dependency: 'setting'. Either include it or remove the dependency array.",["23996"],["23997"],"React Hook useCallback has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked.",["23998"],"React Hook useEffect has a missing dependency: 'markAppRequestsAsSeen'. Either include it or remove the dependency array.",["23999"],["24000"],["24001"],["24002"],"Interface name `ApiError` must match the RegExp: /^I[A-Z]/u",["24003"],"Interface name `EEFormHooks` must match the RegExp: /^I[A-Z]/u",["24004"],["24005"],["24006"],"React Hook useCallback was passed a dependency list that is not an array literal. This means we can't statically verify whether you've passed the correct dependencies.",["24007"],"React Hook useCallback has a missing dependency: 'refs'. Either include it or remove the dependency array.",["24008"],["24009"],["24010"],["24011"],["24012"],"React Hook useCallback has a missing dependency: 'isDeletionAllowed'. Either include it or remove the dependency array.",["24013"],["24014"],["24015"],["24016"],["24017"],"Unexpected empty method 'componentDidCatch'.",["24018"],["24019"],"@typescript-eslint/consistent-type-imports","All imports in the declaration are only used as types. Use `import type`.","ImportDeclaration","typeOverValue",{"range":"24020","text":"24021"},["24022"],"@typescript-eslint/no-unused-vars","'T' is defined but never used.","unusedVar",["24023"],["24024"],["24025"],"you-dont-need-lodash-underscore/get","Import from 'lodash.get' detected. Consider using the native optional chaining to get nested values and nullish coalescing operator for fallback values",["24026"],["24027"],["24028"],["24029"],["24030"],["24031"],["24032"],"react/display-name","Component definition is missing display name","noDisplayName",["24033"],["24034"],["24035"],"@typescript-eslint/ban-ts-comment","Do not use \"@ts-ignore\" because it alters compilation errors.","tsDirectiveComment",["24036"],["24037"],["24038"],["24039"],["24040"],["24041"],["24042"],["24043"],["24044"],["24045"],"prefer-destructuring","Use object destructuring.","VariableDeclarator","preferDestructuring",{"range":"24046","text":"24047"},["24048"],["24049"],["24050"],["24051"],["24052"],["24053"],["24054"],["24055"],["24056"],["24057"],["24058"],["24059"],["24060"],["24061"],"no-empty","Empty block statement.","BlockStatement",["24062"],["24063"],["24064"],["24065"],["24066"],["24067"],["24068"],["24069"],["24070"],"no-return-assign","Arrow function should not return assignment.","arrowAssignment",["24071"],"prettier/prettier","Replace `.noCallThru()` with `⏎↹.noCallThru()⏎↹`","replace",{"range":"24072","text":"24073"},["24074"],"Insert `↹`","insert",{"range":"24075","text":"24076"},["24077"],{"range":"24078","text":"24076"},["24079"],{"range":"24080","text":"24076"},["24081"],{"range":"24082","text":"24076"},["24083"],{"range":"24084","text":"24076"},["24085"],"Replace `}` with `↹}⏎↹↹↹↹},`",{"range":"24086","text":"24087"},["24088"],"Delete `}⏎`","delete",{"range":"24089","text":"24090"},["24091"],["24092"],"no-undef","'Npm' is not defined.","undef",["24093"],"no-unused-vars","'file' is defined but never used.",["24094"],["24095"],["24096"],["24097"],["24098"],"Unable to resolve path to module 'spark-md5'.",["24099"],["24100"],["24101"],"'http' is assigned a value but never used.",["24102"],["24103"],"'https' is assigned a value but never used.",["24104"],["24105"],["24106"],["24107"],["24108"],["24109"],"'err' is defined but never used.",["24110"],["24111"],"'fileId' is defined but never used.",["24112"],"'callback' is defined but never used.",["24113"],["24114"],["24115"],["24116"],["24117"],["24118"],["24119"],["24120"],["24121"],"'request' is defined but never used.",["24122"],"'response' is defined but never used.",["24123"],["24124"],["24125"],["24126"],"'result' is defined but never used.",["24127"],["24128"],["24129"],["24130"],["24131"],["24132"],["24133"],"'progress' is defined but never used.",["24134"],["24135"],["24136"],"Parameter name `SyncedCron` must match one of the following formats: camelCase",["24137"],["24138"],"Parameter name `LoggerClass` must match one of the following formats: camelCase",["24139"],["24140"],"Unexpected control character(s) in regular expression: \\x00, \\x1f.",["24141"],["24142"],["24143"],["24144"],["24145"],["24146"],["24147"],["24148"],"Unexpected empty function 'log'.",["24149"],"Unexpected empty function 'debug'.",["24150"],"Unexpected empty function 'info'.",["24151"],"Unexpected empty function 'error'.",["24152"],["24153"],["24154"],"@typescript-eslint/no-explicit-any","Unexpected any. Specify a different type.","TSAnyKeyword","unexpectedAny",["24155","24156"],["24157","24158"],["24159","24160"],["24161","24162"],["24163","24164"],["24165","24166"],["24167","24168"],["24169","24170"],["24171","24172"],["24173","24174"],["24175","24176"],["24177","24178"],["24179","24180"],["24181","24182"],["24183","24184"],"no-loop-func","Function declared in a loop contains unsafe references to variable(s) 'adminPage'.","unsafeRefs",["24185"],"Function declared in a loop contains unsafe references to variable(s) 'regularUserPage'.",["24186"],["24187"],["24188","24189"],"'testChannel' is assigned a value but never used.",["24190"],["24191"],["24192"],["24193"],"import/first","Import in body of module; reorder to top.",{"range":"24194","text":"24195"},["24196"],{"range":"24197","text":"24198"},["24199"],["24200"],"Delete `·`",{"range":"24201","text":"24090"},["24202"],"Replace `⏎↹normalizeExternalInviteeId,⏎↹executeSlashCommand,⏎}·=·proxyquire.noCallThru()` with `·normalizeExternalInviteeId,·executeSlashCommand·}·=·proxyquire⏎↹.noCallThru()⏎↹`",{"range":"24203","text":"24204"},["24205"],{"range":"24206","text":"24076"},["24207"],{"range":"24208","text":"24076"},["24209"],{"range":"24210","text":"24076"},["24211"],{"range":"24212","text":"24076"},["24213"],{"range":"24214","text":"24076"},["24215"],{"range":"24216","text":"24087"},["24217"],{"range":"24218","text":"24090"},["24219"],{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24222","desc":"24223"},{"messageId":"24221","fix":"24224","desc":"24223"},{"messageId":"24221","fix":"24225","desc":"24223"},{"messageId":"24221","fix":"24226","desc":"24223"},{"messageId":"24221","fix":"24227","desc":"24223"},{"kind":"24220","justification":"24090"},[772,772]," ",{"kind":"24220","justification":"24090"},[852,877],".GoogleAnalyticsObject",{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24228","desc":"24223"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24229","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24230","desc":"24223"},{"messageId":"24221","fix":"24231","desc":"24223"},{"messageId":"24221","fix":"24232","desc":"24223"},{"messageId":"24233","fix":"24234","desc":"24235"},{"messageId":"24233","fix":"24236","desc":"24235"},{"messageId":"24221","fix":"24237","desc":"24223"},{"messageId":"24221","fix":"24238","desc":"24223"},{"messageId":"24221","fix":"24239","desc":"24223"},{"messageId":"24221","fix":"24240","desc":"24223"},{"messageId":"24221","fix":"24241","desc":"24223"},[233,330],"} from './autotranslate';\nimport './settings';\nimport './permissions';\n",{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24242","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24243","desc":"24223"},{"messageId":"24221","fix":"24244","desc":"24223"},{"messageId":"24221","fix":"24245","desc":"24223"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24246","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24247","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},[2438,2446],".blob",{"kind":"24220","justification":"24090"},[2458,2473],".contentType",{"kind":"24220","justification":"24090"},[2678,2686],{"kind":"24220","justification":"24090"},[2696,2711],{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24248","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24249","desc":"24223"},{"messageId":"24221","fix":"24250","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24251","desc":"24223"},{"messageId":"24221","fix":"24252","desc":"24223"},{"messageId":"24221","fix":"24253","desc":"24223"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24254","desc":"24223"},{"messageId":"24221","fix":"24255","desc":"24223"},{"kind":"24220","justification":"24090"},[1118,1118],{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24256","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24257","desc":"24223"},{"messageId":"24221","fix":"24258","desc":"24223"},{"messageId":"24221","fix":"24259","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24260","desc":"24223"},{"messageId":"24221","fix":"24261","desc":"24223"},{"messageId":"24221","fix":"24262","desc":"24223"},{"messageId":"24221","fix":"24263","desc":"24223"},{"messageId":"24221","fix":"24264","desc":"24223"},{"messageId":"24221","fix":"24265","desc":"24223"},{"messageId":"24221","fix":"24266","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24267","desc":"24223"},{"messageId":"24221","fix":"24268","desc":"24223"},{"messageId":"24221","fix":"24269","desc":"24223"},{"messageId":"24221","fix":"24270","desc":"24223"},{"messageId":"24221","fix":"24271","desc":"24223"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24272","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"desc":"24273","fix":"24274"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"desc":"24275","fix":"24276"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24277","desc":"24223"},{"messageId":"24221","fix":"24278","desc":"24223"},{"messageId":"24221","fix":"24279","desc":"24223"},{"messageId":"24221","fix":"24280","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24281","desc":"24223"},{"messageId":"24221","fix":"24282","desc":"24223"},{"messageId":"24221","fix":"24283","desc":"24223"},{"desc":"24284","fix":"24285"},{"desc":"24286","fix":"24287"},{"messageId":"24221","fix":"24288","desc":"24223"},{"messageId":"24221","fix":"24289","desc":"24223"},{"desc":"24290","fix":"24291"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"desc":"24292","fix":"24293"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"desc":"24294","fix":"24295"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24296","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24297","desc":"24223"},{"kind":"24220","justification":"24090"},{"desc":"24298","fix":"24299"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"desc":"24300","fix":"24301"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24302","desc":"24223"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24303","desc":"24223"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24304","desc":"24223"},[77,77]," type",{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24305","desc":"24223"},{"messageId":"24221","fix":"24306","desc":"24223"},{"messageId":"24221","fix":"24307","desc":"24223"},{"messageId":"24221","fix":"24308","desc":"24223"},{"messageId":"24221","fix":"24309","desc":"24223"},{"messageId":"24221","fix":"24310","desc":"24223"},{"messageId":"24221","fix":"24311","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},[3992,4042],"{type} = req.body",{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24233","fix":"24312","desc":"24235"},{"kind":"24220","justification":"24090"},{"messageId":"24233","fix":"24313","desc":"24235"},{"kind":"24220","justification":"24090"},{"messageId":"24233","fix":"24314","desc":"24235"},{"kind":"24220","justification":"24090"},{"messageId":"24233","fix":"24315","desc":"24235"},{"kind":"24220","justification":"24090"},{"messageId":"24233","fix":"24316","desc":"24235"},{"kind":"24220","justification":"24090"},{"messageId":"24233","fix":"24317","desc":"24235"},{"kind":"24220","justification":"24090"},{"messageId":"24318","data":"24319","fix":"24320","desc":"24321"},{"kind":"24220","justification":"24090"},{"messageId":"24318","data":"24322","fix":"24323","desc":"24321"},{"kind":"24220","justification":"24090"},{"messageId":"24318","data":"24324","fix":"24325","desc":"24321"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24326","desc":"24223"},{"messageId":"24221","fix":"24327","desc":"24223"},{"kind":"24220","justification":"24090"},[215,228],"\n\t.noCallThru()\n\t",{"kind":"24220","justification":"24090"},[338,338],"\t",{"kind":"24220","justification":"24090"},[365,365],{"kind":"24220","justification":"24090"},[374,374],{"kind":"24220","justification":"24090"},[447,447],{"kind":"24220","justification":"24090"},[494,494],{"kind":"24220","justification":"24090"},[538,539],"\t}\n\t\t\t\t},",{"kind":"24220","justification":"24090"},[552,554],"",{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24328","desc":"24223"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24329","desc":"24223"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24330","desc":"24223"},{"messageId":"24221","fix":"24331","desc":"24223"},{"messageId":"24221","fix":"24332","desc":"24223"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24333","desc":"24223"},{"messageId":"24221","fix":"24334","desc":"24223"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24221","fix":"24335","desc":"24223"},{"messageId":"24221","fix":"24336","desc":"24223"},{"messageId":"24337","fix":"24338","desc":"24339"},{"messageId":"24340","fix":"24341","desc":"24342"},{"messageId":"24337","fix":"24343","desc":"24339"},{"messageId":"24340","fix":"24344","desc":"24342"},{"messageId":"24337","fix":"24345","desc":"24339"},{"messageId":"24340","fix":"24346","desc":"24342"},{"messageId":"24337","fix":"24347","desc":"24339"},{"messageId":"24340","fix":"24348","desc":"24342"},{"messageId":"24337","fix":"24349","desc":"24339"},{"messageId":"24340","fix":"24350","desc":"24342"},{"messageId":"24337","fix":"24351","desc":"24339"},{"messageId":"24340","fix":"24352","desc":"24342"},{"messageId":"24337","fix":"24353","desc":"24339"},{"messageId":"24340","fix":"24354","desc":"24342"},{"messageId":"24337","fix":"24355","desc":"24339"},{"messageId":"24340","fix":"24356","desc":"24342"},{"messageId":"24337","fix":"24357","desc":"24339"},{"messageId":"24340","fix":"24358","desc":"24342"},{"messageId":"24337","fix":"24359","desc":"24339"},{"messageId":"24340","fix":"24360","desc":"24342"},{"messageId":"24337","fix":"24361","desc":"24339"},{"messageId":"24340","fix":"24362","desc":"24342"},{"messageId":"24337","fix":"24363","desc":"24339"},{"messageId":"24340","fix":"24364","desc":"24342"},{"messageId":"24337","fix":"24365","desc":"24339"},{"messageId":"24340","fix":"24366","desc":"24342"},{"messageId":"24337","fix":"24367","desc":"24339"},{"messageId":"24340","fix":"24368","desc":"24342"},{"messageId":"24337","fix":"24369","desc":"24339"},{"messageId":"24340","fix":"24370","desc":"24342"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"messageId":"24337","fix":"24371","desc":"24339"},{"messageId":"24340","fix":"24372","desc":"24342"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},[0,859],"/* eslint-disable import/first */\nimport { expect } from 'chai';\nimport sinon from 'sinon';\nimport { RoomType } from '@rocket.chat/apps-engine/definition/rooms';\nimport proxyquire from 'proxyquire';\n\nimport { FederationMessageServiceListener } from '../../../../../../../app/federation-v2/server/application/listener/MessageServiceListener';\n\nconst { FederatedUser } = proxyquire.noCallThru().load('../../../../../../../app/federation-v2/server/domain/FederatedUser', {\n\tmongodb: {\n\t\t'ObjectId': class ObjectId {\n\t\t\ttoHexString(): string {\n\t\t\t\treturn 'hexString';\n\t\t\t}\n\t\t},\n\t\t'@global': true,\n\t},\n});\n\nconst { FederatedRoom } = proxyquire.noCallThru().load('../../../../../../../app/federation-v2/server/domain/FederatedRoom', {\n\tmongodb: {\n\t\t'ObjectId': class ObjectId {\n\t\t\ttoHexString(): string {\n\t\t\t\treturn 'hexString';\n\t\t\t}\n\t\t},\n\t\t'@global': true,\n\t},\n});",{"kind":"24220","justification":"24090"},[0,1169],"/* eslint-disable import/first */\nimport { expect } from 'chai';\nimport sinon from 'sinon';\nimport { RoomType } from '@rocket.chat/apps-engine/definition/rooms';\nimport proxyquire from 'proxyquire';\n\nimport { EVENT_ORIGIN } from '../../../../../../../app/federation-v2/server/domain/IFederationBridge';\n\nconst { FederationRoomServiceListener } = proxyquire\n\t.noCallThru()\n\t.load('../../../../../../../app/federation-v2/server/application/listener/RoomServiceListener', {\n\t\tmongodb: {\n\t\t\t'ObjectId': class ObjectId {\n\t\t\t\ttoHexString(): string {\n\t\t\t\t\treturn 'hexString';\n\t\t\t\t}\n\t\t\t},\n\t\t\t'@global': true,\n\t\t},\n\t});\n\nconst { FederatedUser } = proxyquire.noCallThru().load('../../../../../../../app/federation-v2/server/domain/FederatedUser', {\n\tmongodb: {\n\t\t'ObjectId': class ObjectId {\n\t\t\ttoHexString(): string {\n\t\t\t\treturn 'hexString';\n\t\t\t}\n\t\t},\n\t\t'@global': true,\n\t},\n});\n\nconst { DirectMessageFederatedRoom, FederatedRoom } = proxyquire\n\t.noCallThru()\n\t.load('../../../../../../../app/federation-v2/server/domain/FederatedRoom', {\n\t\tmongodb: {\n\t\t\t'ObjectId': class ObjectId {\n\t\t\t\ttoHexString(): string {\n\t\t\t\t\treturn 'hexString';\n\t\t\t\t}\n\t\t\t},\n\t\t\t'@global': true,\n\t\t},\n\t});",{"kind":"24220","justification":"24090"},{"kind":"24220","justification":"24090"},[484,485],{"kind":"24220","justification":"24090"},[180,259]," normalizeExternalInviteeId, executeSlashCommand } = proxyquire\n\t.noCallThru()\n\t",{"kind":"24220","justification":"24090"},[372,372],{"kind":"24220","justification":"24090"},[397,397],{"kind":"24220","justification":"24090"},[411,411],{"kind":"24220","justification":"24090"},[485,485],{"kind":"24220","justification":"24090"},[523,523],{"kind":"24220","justification":"24090"},[572,573],{"kind":"24220","justification":"24090"},[586,588],{"kind":"24220","justification":"24090"},"directive","optionalChainSuggest",{"range":"24373","text":"24374"},"Change to an optional chain.",{"range":"24375","text":"24376"},{"range":"24377","text":"24378"},{"range":"24379","text":"24376"},{"range":"24380","text":"24381"},{"range":"24382","text":"24383"},{"range":"24384","text":"24385"},{"range":"24386","text":"24387"},{"range":"24388","text":"24389"},{"range":"24390","text":"24389"},"suggestOptionalChain",{"range":"24391","text":"24392"},"Consider using the optional chain operator `?.` instead. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator.",{"range":"24393","text":"24392"},{"range":"24394","text":"24395"},{"range":"24396","text":"24397"},{"range":"24398","text":"24399"},{"range":"24400","text":"24401"},{"range":"24402","text":"24401"},{"range":"24403","text":"24404"},{"range":"24405","text":"24406"},{"range":"24407","text":"24408"},{"range":"24409","text":"24408"},{"range":"24410","text":"24378"},{"range":"24411","text":"24412"},{"range":"24413","text":"24414"},{"range":"24415","text":"24416"},{"range":"24417","text":"24414"},{"range":"24418","text":"24419"},{"range":"24420","text":"24421"},{"range":"24422","text":"24423"},{"range":"24424","text":"24425"},{"range":"24426","text":"24427"},{"range":"24428","text":"24378"},{"range":"24429","text":"24430"},{"range":"24431","text":"24432"},{"range":"24433","text":"24434"},{"range":"24435","text":"24436"},{"range":"24437","text":"24438"},{"range":"24439","text":"24440"},{"range":"24441","text":"24436"},{"range":"24442","text":"24438"},{"range":"24443","text":"24440"},{"range":"24444","text":"24445"},{"range":"24446","text":"24447"},{"range":"24448","text":"24447"},{"range":"24449","text":"24447"},{"range":"24450","text":"24414"},{"range":"24451","text":"24452"},{"range":"24453","text":"24454"},"Update the dependencies array to be: [conditions, debouncedFilter]",{"range":"24455","text":"24456"},"Update the dependencies array to be: [effect]",{"range":"24457","text":"24458"},{"range":"24459","text":"24423"},{"range":"24460","text":"24461"},{"range":"24462","text":"24463"},{"range":"24464","text":"24465"},{"range":"24466","text":"24467"},{"range":"24468","text":"24469"},{"range":"24470","text":"24469"},"Update the dependencies array to be: [email, step, terms]",{"range":"24471","text":"24472"},"Update the dependencies array to be: [cloudConfirmationPoll, intentData.device_code, dispatchToastMessage, t, onSuccess]",{"range":"24473","text":"24474"},{"range":"24475","text":"24469"},{"range":"24476","text":"24469"},"Update the dependencies array to be: [setting]",{"range":"24477","text":"24478"},"Update the dependencies array to be: [setting, update, persistedSetting]",{"range":"24479","text":"24480"},"Update the dependencies array to be: [isAdminUser, isSuccess, markAppRequestsAsSeen, paginatedAppRequests.data, reloadApps]",{"range":"24481","text":"24482"},{"range":"24483","text":"24484"},{"range":"24485","text":"24486"},"Update the dependencies array to be: [refs]",{"range":"24487","text":"24488"},"Update the dependencies array to be: [isDeletionAllowed]",{"range":"24489","text":"24490"},{"range":"24491","text":"24401"},{"range":"24492","text":"24493"},{"range":"24494","text":"24495"},{"range":"24496","text":"24497"},{"range":"24498","text":"24499"},{"range":"24500","text":"24499"},{"range":"24501","text":"24378"},{"range":"24502","text":"24503"},{"range":"24504","text":"24505"},{"range":"24506","text":"24507"},{"range":"24508","text":"24392"},{"range":"24509","text":"24392"},{"range":"24510","text":"24392"},{"range":"24511","text":"24392"},{"range":"24512","text":"24392"},{"range":"24513","text":"24392"},"suggestComment",{"type":"24514"},{"range":"24515","text":"24516"},"Add comment inside empty block statement.",{"type":"24514"},{"range":"24517","text":"24516"},{"type":"24514"},{"range":"24518","text":"24516"},{"range":"24519","text":"24520"},{"range":"24521","text":"24522"},{"range":"24523","text":"24524"},{"range":"24525","text":"24526"},{"range":"24527","text":"24378"},{"range":"24528","text":"24529"},{"range":"24530","text":"24531"},{"range":"24532","text":"24378"},{"range":"24533","text":"24534"},{"range":"24535","text":"24536"},{"range":"24537","text":"24536"},"suggestUnknown",{"range":"24538","text":"24539"},"Use `unknown` instead, this will force you to explicitly, and safely assert the type is correct.","suggestNever",{"range":"24538","text":"24540"},"Use `never` instead, this is useful when instantiating generic type parameters that you don't need to know the type of.",{"range":"24541","text":"24539"},{"range":"24541","text":"24540"},{"range":"24542","text":"24539"},{"range":"24542","text":"24540"},{"range":"24543","text":"24539"},{"range":"24543","text":"24540"},{"range":"24544","text":"24539"},{"range":"24544","text":"24540"},{"range":"24545","text":"24539"},{"range":"24545","text":"24540"},{"range":"24546","text":"24539"},{"range":"24546","text":"24540"},{"range":"24547","text":"24539"},{"range":"24547","text":"24540"},{"range":"24548","text":"24539"},{"range":"24548","text":"24540"},{"range":"24549","text":"24539"},{"range":"24549","text":"24540"},{"range":"24550","text":"24539"},{"range":"24550","text":"24540"},{"range":"24551","text":"24539"},{"range":"24551","text":"24540"},{"range":"24552","text":"24539"},{"range":"24552","text":"24540"},{"range":"24553","text":"24539"},{"range":"24553","text":"24540"},{"range":"24554","text":"24539"},{"range":"24554","text":"24540"},{"range":"24555","text":"24539"},{"range":"24555","text":"24540"},[571,606],"!options.totp?.code",[334,402],"!user.services?.totp?.enabled",[299,322],"!user?.username",[444,512],[448,519],"!user.services?.totp?.tempSecret",[7871,7892],"!name?.trim()",[2995,3048],"!this.bodyParams.name?.trim()",[2760,2777],"!room?.id",[2779,2810],"!room?.u?._id",[3168,3199],[6874,6875],"?",[6943,6944],[7304,7338],"!settingValue?.url",[2153,2185],"!lastLogin?.loginAt",[808,829],"!rules?.size",[1972,1990],"!user?._id",[1733,1751],[1360,1405],"!currentLicense?._updatedAt",[3152,3192],"!internalUser?.username",[2367,2386],"!file?.size",[3246,3265],[3339,3362],[3757,3814],"!integration.retryDelay?.trim()",[713,737],"!command?.cmd",[463,479],"!msg?.rid",[666,690],[8946,8984],"!config.survey?.items",[1172,1250],"!config.theme?.actionLinks?.webrtc",[614,633],"!room?.open",[1368,1406],"!samlObject?.serviceName",[1291,1337],"!user?.services?.saml",[702,725],[1037,1069],"!message?.attachments",[1339,1376],"!msg?.urls?.length",[3976,3994],"!data?.url",[1979,2052],"!document.execCommand?.('insertText', false, text)",[6306,6387],"!document.execCommand?.('insertText', false, selectedText)",[6772,6882],"!document.execCommand?.('insertText', false, pattern.replace('{{text}}', selectedText))",[7726,7799],[2444,2525],[2841,2951],[3133,3154],"!config?.id",[1402,1426],"!message?.rid",[1825,1849],[2517,2541],[3121,3145],[1025,1058],"!message.u?.username",[792,813],"!value?.room",[1211,1219],"[conditions, debouncedFilter]",[345,357],"[effect]",[2303,2322],[969,994],"!user?._updatedAt",[358,377],"!room?.uids",[1364,1442],"!patchedElement?.classList.contains('patched-css-variables')",[3215,3267],"!e2eRoom?.shouldConvertReceivedMessages()",[1000,1034],"onStatusChange?.()",[1325,1359],[1182,1196],"[email, step, terms]",[1690,1762],"[cloudConfirmationPoll, intentData.device_code, dispatchToastMessage, t, onSuccess]",[1795,1829],[1516,1550],[2412,2447],"[setting]",[3036,3112],"[setting, update, persistedSetting]",[2026,2090],"[isAdminUser, isSuccess, markAppRequestsAsSeen, paginatedAppRequests.data, reloadApps]",[2210,2253],"!apiError.xhr?.responseJSON",[916,941],"!data?.appearance",[871,875],"[refs]",[1505,1634],"[isDeletionAllowed]",[548,566],[663,702],"!ref.current?.parentNode",[702,729],"!setting?.values",[7554,7589],"!internalRoom?.name",[3704,3726],"!params?.rid",[4164,4186],[711,734],[245,263],"!room?._id",[523,554],"!options?.department",[730,749],"!rid?.trim()",[3169,3170],[3553,3554],[3634,3635],[3687,3688],[3894,3895],[3976,3977],"block",[657,657]," /* empty */ ",[782,782],[1186,1186],[1103,1121],"!room?.rid",[873,909],"!threadMessage?.tlm",[2472,2508],"!isMasterDoc?.setName",[2734,2759],"!message?.file",[973,996],[7127,7164],"!subscriptions?.size",[9044,9076],"!history?.integration",[970,993],[4121,4161],"!connection?.isConnected()",[3805,3848],"!details.members?.length",[5844,5887],[36483,36486],"unknown","never",[37799,37802],[40406,40409],[41722,41725],[31038,31041],[32321,32324],[34342,34345],[35625,35628],[31168,31171],[32451,32454],[34456,34459],[35739,35742],[249,252],[638,641],[648,651],[487,490]] \ No newline at end of file diff --git a/apps/meteor/.eslintrc.json b/apps/meteor/.eslintrc.json index e41eb46338e03..344588417273d 100644 --- a/apps/meteor/.eslintrc.json +++ b/apps/meteor/.eslintrc.json @@ -1,5 +1,5 @@ { - "extends": ["@rocket.chat/eslint-config"], + "extends": ["@rocket.chat/eslint-config", "plugin:you-dont-need-lodash-underscore/compatible"], "globals": { "__meteor_bootstrap__": false, "__meteor_runtime_config__": false, diff --git a/apps/meteor/.gitignore b/apps/meteor/.gitignore index 31e6bfee5c60d..3a7ccfde42536 100644 --- a/apps/meteor/.gitignore +++ b/apps/meteor/.gitignore @@ -85,4 +85,5 @@ coverage tests/e2e/test-failures/ out.txt dist -*-session.json \ No newline at end of file +*-session.json +matrix-federation-config/* \ No newline at end of file diff --git a/apps/meteor/.meteor/packages b/apps/meteor/.meteor/packages index 292ef0526ba7f..853b8e4ac4980 100644 --- a/apps/meteor/.meteor/packages +++ b/apps/meteor/.meteor/packages @@ -13,39 +13,38 @@ accounts-facebook@1.3.3 accounts-github@1.5.0 accounts-google@1.4.0 accounts-meteor-developer@1.5.0 -accounts-password@2.3.1 +accounts-password@2.3.3 accounts-twitter@1.5.0 blaze-html-templates -check@1.3.1 -ddp-rate-limiter@1.1.0 +check@1.3.2 +ddp-rate-limiter@1.1.1 ddp-common@1.4.0 dynamic-import@0.7.2 -ecmascript@0.16.2 -typescript@4.5.4 -ejson@1.1.2 -email@2.2.1 +ecmascript@0.16.4 +typescript@4.6.4 +ejson@1.1.3 +email@2.2.3 http@2.0.0 logging@1.3.1 meteor-base@1.5.1 mobile-experience@1.1.0 -mongo@1.15.0 -random@1.2.0 +mongo@1.16.3 +random@1.2.1 rate-limit@1.0.9 -reactive-dict@1.3.0 -reactive-var@1.0.11 +reactive-dict@1.3.1 +reactive-var@1.0.12 reload@1.3.1 -service-configuration@1.3.0 -session@1.2.0 +service-configuration@1.3.1 +session@1.2.1 shell-server@0.5.0 spacebars -standard-minifier-js@2.8.0 -tracker@1.2.0 +standard-minifier-js@2.8.1 +tracker@1.2.1 rocketchat:livechat rocketchat:streamer rocketchat:version -konecty:multiple-instances-status konecty:user-presence dispatch:run-as-user @@ -66,28 +65,27 @@ raix:handlebar-helpers raix:ui-dropped-event rocketchat:tap-i18n@3.0.0 -underscore@1.0.10 +underscore@1.0.11 littledata:synced-cron -accounts-base@2.2.3 -accounts-oauth@1.4.1 +accounts-base@2.2.6 +accounts-oauth@1.4.2 autoupdate@1.8.0 -babel-compiler@7.9.0 -google-oauth@1.4.2 +babel-compiler@7.10.1 +google-oauth@1.4.3 htmljs -less matb33:collection-hooks meteorhacks:inject-initial -oauth@2.1.2 -oauth2@1.3.1 +oauth@2.1.3 +oauth2@1.3.2 routepolicy@1.1.1 sha@1.0.9 templating -webapp@1.13.1 -webapp-hashing@1.1.0 +webapp@1.13.2 +webapp-hashing@1.1.1 rocketchat:oauth2-server rocketchat:i18n dandv:caret-position facts-base@1.0.1 url@1.3.2 -standard-minifier-css +standard-minifier-css@1.8.3 diff --git a/apps/meteor/.meteor/release b/apps/meteor/.meteor/release index 66dd7b6647248..eff99d911ecbf 100644 --- a/apps/meteor/.meteor/release +++ b/apps/meteor/.meteor/release @@ -1 +1 @@ -METEOR@2.7.3 +METEOR@2.9.1 diff --git a/apps/meteor/.meteor/versions b/apps/meteor/.meteor/versions index 2cb41ac914aa2..e88a81075a4eb 100644 --- a/apps/meteor/.meteor/versions +++ b/apps/meteor/.meteor/versions @@ -1,51 +1,51 @@ -accounts-base@2.2.3 +accounts-base@2.2.6 accounts-facebook@1.3.3 accounts-github@1.5.0 accounts-google@1.4.0 accounts-meteor-developer@1.5.0 -accounts-oauth@1.4.1 -accounts-password@2.3.1 +accounts-oauth@1.4.2 +accounts-password@2.3.3 accounts-twitter@1.5.0 aldeed:simple-schema@1.5.4 allow-deny@1.1.1 autoupdate@1.8.0 -babel-compiler@7.9.0 +babel-compiler@7.10.1 babel-runtime@1.5.1 base64@1.0.12 binary-heap@1.0.11 -blaze@2.6.0 -blaze-html-templates@1.2.1 +blaze@2.6.1 +blaze-html-templates@2.0.0 blaze-tools@1.1.3 boilerplate-generator@1.7.1 caching-compiler@1.2.2 caching-html-compiler@1.2.1 callback-hook@1.4.0 -check@1.3.1 +check@1.3.2 coffeescript@2.4.1 coffeescript-compiler@2.4.1 dandv:caret-position@2.1.1 -ddp@1.4.0 -ddp-client@2.5.0 +ddp@1.4.1 +ddp-client@2.6.1 ddp-common@1.4.0 -ddp-rate-limiter@1.1.0 -ddp-server@2.5.0 +ddp-rate-limiter@1.1.1 +ddp-server@2.6.0 deps@1.0.12 -diff-sequence@1.1.1 +diff-sequence@1.1.2 dispatch:run-as-user@1.1.1 dynamic-import@0.7.2 -ecmascript@0.16.2 +ecmascript@0.16.4 ecmascript-runtime@0.8.0 ecmascript-runtime-client@0.12.1 ecmascript-runtime-server@0.11.0 -ejson@1.1.2 -email@2.2.1 +ejson@1.1.3 +email@2.2.3 es5-shim@4.8.0 -facebook-oauth@1.11.0 +facebook-oauth@1.11.2 facts-base@1.0.1 -fetch@0.1.1 -geojson-utils@1.0.10 -github-oauth@1.4.0 -google-oauth@1.4.2 +fetch@0.1.3 +geojson-utils@1.0.11 +github-oauth@1.4.1 +google-oauth@1.4.3 hot-code-push@1.0.4 html-tools@1.1.3 htmljs@1.1.1 @@ -60,52 +60,50 @@ jparker:crypto-md5@0.1.1 jparker:gravatar@0.5.1 jquery@3.0.0 kadira:flow-router@2.12.1 -konecty:multiple-instances-status@1.1.0 konecty:user-presence@2.6.3 launch-screen@1.3.0 -less@3.0.2 littledata:synced-cron@1.5.1 localstorage@1.2.0 logging@1.3.1 -matb33:collection-hooks@1.1.2 +matb33:collection-hooks@1.2.0 mdg:validation-error@0.5.1 -meteor@1.10.0 +meteor@1.10.4 meteor-base@1.5.1 -meteor-developer-oauth@1.3.1 +meteor-developer-oauth@1.3.2 meteorhacks:inject-initial@1.0.5 -minifier-css@1.6.0 -minifier-js@2.7.4 -minimongo@1.8.0 +minifier-css@1.6.2 +minifier-js@2.7.5 +minimongo@1.9.1 mobile-experience@1.1.0 mobile-status-bar@1.1.0 -modern-browsers@0.1.8 -modules@0.18.0 -modules-runtime@0.13.0 -mongo@1.15.0 +modern-browsers@0.1.9 +modules@0.19.0 +modules-runtime@0.13.1 +mongo@1.16.3 mongo-decimal@0.1.3 mongo-dev-server@1.1.0 mongo-id@1.0.8 mrt:reactive-store@0.0.1 mystor:device-detection@0.2.0 nooitaf:colors@1.2.0 -npm-mongo@4.3.1 -oauth@2.1.2 -oauth1@1.5.0 -oauth2@1.3.1 +npm-mongo@4.12.1 +oauth@2.1.3 +oauth1@1.5.1 +oauth2@1.3.2 observe-sequence@1.0.20 ordered-dict@1.1.0 ostrio:cookies@2.7.2 pauli:accounts-linkedin@6.0.0 pauli:linkedin-oauth@6.0.0 -promise@0.12.0 +promise@0.12.2 raix:eventemitter@1.0.0 raix:handlebar-helpers@0.2.5 raix:ui-dropped-event@0.0.7 -random@1.2.0 +random@1.2.1 rate-limit@1.0.9 react-fast-refresh@0.2.3 -reactive-dict@1.3.0 -reactive-var@1.0.11 +reactive-dict@1.3.1 +reactive-var@1.0.12 reload@1.3.1 retry@1.1.0 rocketchat:ddp@0.0.1 @@ -118,25 +116,26 @@ rocketchat:streamer@1.1.0 rocketchat:tap-i18n@3.0.0 rocketchat:version@1.0.0 routepolicy@1.1.1 -service-configuration@1.3.0 -session@1.2.0 +service-configuration@1.3.1 +session@1.2.1 sha@1.0.9 shell-server@0.5.0 simple:json-routes@2.3.1 socket-stream-client@0.5.0 spacebars@1.3.0 spacebars-compiler@1.3.1 -standard-minifier-css@1.8.1 -standard-minifier-js@2.8.0 +standard-minifier-css@1.8.3 +standard-minifier-js@2.8.1 templating@1.4.2 templating-compiler@1.4.1 -templating-runtime@1.6.0 +templating-runtime@1.6.1 templating-tools@1.2.2 -tracker@1.2.0 -twitter-oauth@1.3.0 -typescript@4.5.4 +tracker@1.2.1 +twitter-oauth@1.3.2 +typescript@4.6.4 ui@1.0.13 -underscore@1.0.10 +underscore@1.0.11 url@1.3.2 -webapp@1.13.1 -webapp-hashing@1.1.0 +webapp@1.13.2 +webapp-hashing@1.1.1 +zodern:types@1.0.9 diff --git a/apps/meteor/.mocharc.api.js b/apps/meteor/.mocharc.api.js index f6c09a541e002..92168e92cc9a4 100644 --- a/apps/meteor/.mocharc.api.js +++ b/apps/meteor/.mocharc.api.js @@ -9,11 +9,5 @@ module.exports = { timeout: 10000, bail: true, file: 'tests/end-to-end/teardown.js', - spec: [ - 'tests/unit/app/api/server/v1/**/*.spec.ts', - 'tests/end-to-end/api/**/*.js', - 'tests/end-to-end/api/**/*.ts', - 'tests/end-to-end/apps/*.js', - 'tests/end-to-end/apps/*.ts', - ], + spec: ['tests/unit/app/api/server/v1/**/*.spec.*', 'tests/end-to-end/api/**/*', 'tests/end-to-end/apps/*'], }; diff --git a/apps/meteor/.mocharc.base.json b/apps/meteor/.mocharc.base.json index ac8a2bcce8b7f..e81bd7ee4f7c5 100644 --- a/apps/meteor/.mocharc.base.json +++ b/apps/meteor/.mocharc.base.json @@ -3,8 +3,6 @@ "reporter": "spec", "extension": ["js", "ts", "tsx"], "require": [ - "@babel/register", - "regenerator-runtime/runtime", "ts-node/register", "./tests/setup/chaiPlugins.ts" ], diff --git a/apps/meteor/.mocharc.client.js b/apps/meteor/.mocharc.client.js index 071914fe61c59..50ef8e2139337 100644 --- a/apps/meteor/.mocharc.client.js +++ b/apps/meteor/.mocharc.client.js @@ -28,12 +28,14 @@ module.exports = { './tests/setup/hoistedReact.ts', './tests/setup/cleanupTestingLibrary.ts', ], + reporter: 'dot', + timeout: 5000, exit: false, slow: 200, spec: [ - 'tests/unit/client/**/*.spec.ts', + 'client/**/*.spec.{ts,tsx}', + 'tests/unit/client/**/*.spec.{ts,tsx}', 'tests/unit/lib/**/*.tests.ts', 'tests/unit/client/**/*.test.ts', - 'tests/unit/client/**/*.spec.tsx', ], }; diff --git a/apps/meteor/.mocharc.js b/apps/meteor/.mocharc.js index f8118d74f7c93..3a7c511d8a245 100644 --- a/apps/meteor/.mocharc.js +++ b/apps/meteor/.mocharc.js @@ -24,6 +24,7 @@ module.exports = { ...base, // see https://github.com/mochajs/mocha/issues/3916 exit: true, spec: [ + 'ee/server/lib/ldap/*.spec.ts', 'ee/tests/**/*.tests.ts', 'ee/tests/**/*.spec.ts', 'tests/unit/app/**/*.spec.ts', diff --git a/apps/meteor/.storybook/babel.config.js b/apps/meteor/.storybook/babel.config.js index 666946b95d787..66538f004bd59 100644 --- a/apps/meteor/.storybook/babel.config.js +++ b/apps/meteor/.storybook/babel.config.js @@ -7,15 +7,15 @@ module.exports = { useBuiltIns: 'usage', corejs: '3', modules: 'commonjs', + include: [ + '@babel/plugin-proposal-class-properties', + '@babel/plugin-proposal-optional-chaining', + '@babel/plugin-proposal-nullish-coalescing-operator', + ], }, ], '@babel/preset-react', '@babel/preset-flow', - '@babel/preset-typescript', - ], - plugins: [ - '@babel/plugin-proposal-class-properties', - '@babel/plugin-proposal-optional-chaining', - '@babel/plugin-proposal-nullish-coalescing-operator', + ['@babel/preset-typescript', { allowDeclareFields: true }], ], }; diff --git a/apps/meteor/.storybook/decorators.tsx b/apps/meteor/.storybook/decorators.tsx index 3da8357a1230a..a295c4ab60b89 100644 --- a/apps/meteor/.storybook/decorators.tsx +++ b/apps/meteor/.storybook/decorators.tsx @@ -1,5 +1,6 @@ -import { DecoratorFunction } from '@storybook/addons'; -import React, { ReactElement } from 'react'; +import type { DecoratorFunction } from '@storybook/addons'; +import type { ReactElement } from 'react'; +import React from 'react'; import ModalContextMock from '../client/stories/contexts/ModalContextMock'; import QueryClientProviderMock from '../client/stories/contexts/QueryClientProviderMock'; diff --git a/apps/meteor/app/2fa/client/TOTPGoogle.js b/apps/meteor/app/2fa/client/TOTPGoogle.js index ac2ceac92bbe6..e43132684dd72 100644 --- a/apps/meteor/app/2fa/client/TOTPGoogle.js +++ b/apps/meteor/app/2fa/client/TOTPGoogle.js @@ -1,7 +1,6 @@ import { Meteor } from 'meteor/meteor'; import { Accounts } from 'meteor/accounts-base'; import { Google } from 'meteor/google-oauth'; -import _ from 'underscore'; import { overrideLoginMethod } from '../../../client/lib/2fa/overrideLoginMethod'; @@ -25,8 +24,8 @@ const loginWithGoogleAndTOTP = function (options, code, callback) { // has the proper email address after the OAuth conversation. if (typeof Accounts._options.restrictCreationByEmailDomain === 'string') { - options = _.extend({}, options || {}); - options.loginUrlParameters = _.extend({}, options.loginUrlParameters || {}); + options = Object.assign({}, options || {}); + options.loginUrlParameters = Object.assign({}, options.loginUrlParameters || {}); options.loginUrlParameters.hd = Accounts._options.restrictCreationByEmailDomain; } diff --git a/apps/meteor/app/2fa/client/overrideMeteorCall.ts b/apps/meteor/app/2fa/client/overrideMeteorCall.ts index ac19a24219fc2..382499e2aedcc 100644 --- a/apps/meteor/app/2fa/client/overrideMeteorCall.ts +++ b/apps/meteor/app/2fa/client/overrideMeteorCall.ts @@ -1,10 +1,10 @@ import { Meteor } from 'meteor/meteor'; import { t } from '../../utils/client'; -import { process2faReturn } from '../../../client/lib/2fa/process2faReturn'; +import { process2faReturn, process2faAsyncReturn } from '../../../client/lib/2fa/process2faReturn'; import { isTotpInvalidError } from '../../../client/lib/2fa/utils'; -const { call } = Meteor; +const { call, callAsync } = Meteor; type Callback = { (error: unknown): void; @@ -34,8 +34,34 @@ const callWithoutTotp = (methodName: string, args: unknown[], callback: Callback }); }); +const callAsyncWithTotp = + (methodName: string, args: unknown[]) => + async (twoFactorCode: string, twoFactorMethod: string): Promise => { + try { + const result = await callAsync(methodName, ...args, { twoFactorCode, twoFactorMethod }); + + return result; + } catch (error: unknown) { + if (isTotpInvalidError(error)) { + throw new Error(twoFactorMethod === 'password' ? t('Invalid_password') : t('Invalid_two_factor_code')); + } + + throw error; + } + }; + Meteor.call = function (methodName: string, ...args: unknown[]): unknown { const callback = args.length > 0 && typeof args[args.length - 1] === 'function' ? (args.pop() as Callback) : (): void => undefined; return callWithoutTotp(methodName, args, callback)(); }; + +Meteor.callAsync = async function _callAsyncWithTotp(methodName: string, ...args: unknown[]): Promise { + const promise = callAsync(methodName, ...args); + + return process2faAsyncReturn({ + promise, + onCode: callAsyncWithTotp(methodName, args), + emailOrUsername: undefined, + }); +}; diff --git a/apps/meteor/app/2fa/server/code/index.ts b/apps/meteor/app/2fa/server/code/index.ts index 878f817fb4094..00a59bce1d8a1 100644 --- a/apps/meteor/app/2fa/server/code/index.ts +++ b/apps/meteor/app/2fa/server/code/index.ts @@ -92,7 +92,7 @@ export function isAuthorizedForToken(connection: IMethodConnection, user: IUser, return false; } - if (tokenObject.bypassTwoFactor === true) { + if ('bypassTwoFactor' in tokenObject && tokenObject.bypassTwoFactor === true) { return true; } diff --git a/apps/meteor/app/2fa/server/functions/resetTOTP.ts b/apps/meteor/app/2fa/server/functions/resetTOTP.ts index decce3432be5f..7059cdd472f03 100644 --- a/apps/meteor/app/2fa/server/functions/resetTOTP.ts +++ b/apps/meteor/app/2fa/server/functions/resetTOTP.ts @@ -5,6 +5,7 @@ import { Users } from '@rocket.chat/models'; import { settings } from '../../../settings/server'; import * as Mailer from '../../../mailer'; +import { isUserIdFederated } from '../../../../server/lib/isUserIdFederated'; const sendResetNotification = async function (uid: string): Promise { const user = await Users.findOneById>(uid, { @@ -60,6 +61,11 @@ export async function resetTOTP(userId: string, notifyUser = false): Promise { - if (login.type === 'resume' || login.type === 'proxy' || login.methodName === 'verifyEmail') { + if (login.methodName === 'verifyEmail') { + throw new Meteor.Error('verify-email', 'E-mail verified'); + } + + if (login.type === 'resume' || login.type === 'proxy') { return login; } // CAS login doesn't yet support 2FA. diff --git a/apps/meteor/app/2fa/server/methods/enable.ts b/apps/meteor/app/2fa/server/methods/enable.ts index 3c26effb38050..ba0cbfc2080bf 100644 --- a/apps/meteor/app/2fa/server/methods/enable.ts +++ b/apps/meteor/app/2fa/server/methods/enable.ts @@ -18,6 +18,14 @@ Meteor.methods({ }); } + const hasUnverifiedEmail = user.emails?.some((email) => !email.verified); + + if (hasUnverifiedEmail) { + throw new Meteor.Error('error-invalid-user', 'You need to verify your emails before setting up 2FA', { + method: '2fa:enable', + }); + } + const secret = TOTP.generateSecret(); Users.disable2FAAndSetTempSecretByUserId(userId, secret.base32); diff --git a/apps/meteor/app/action-links/README.md b/apps/meteor/app/action-links/README.md deleted file mode 100644 index 6967588117ae0..0000000000000 --- a/apps/meteor/app/action-links/README.md +++ /dev/null @@ -1,26 +0,0 @@ -RocketChat Action Links -============ - -Action Links are a way to add custom javascript functions to RocketChat messages. The links appear as a horizontal list below the message they correspond to, and by clicking the link will run a function you define server-side. - -Usage ------------- - -Add 'actionLinks' to any message object as in the example below. It should be an array of object, each containing a 'label' (this will be the text printed to click on), a method_id (this is the name of the method that will be run), and params (this is the parameters passed to the method_id function). - -~~~ -message.actionLinks = [{ label: "Another Option", method_id: "anotherFunction", params: "stuff"}, { label: "An Option", method_id: "functOne", params: ""}]; -~~~ - - - - - -The functions to be run need to be added to the actionLinkFuncts namespace. This is done by calling the RocketChat.actionLinks.register method. Your custom functions should take two parameters: the original message from the database, and the 'params' object given for that function. -~~~ -RocketChat.actionLinks.register('functOne', function (origDbMsg, params) { - - console.log("I did some stuff!"); - -}); -~~~ diff --git a/apps/meteor/app/action-links/client/lib/actionLinks.ts b/apps/meteor/app/action-links/client/lib/actionLinks.ts index 057592a2f7892..a69acc06ca85c 100644 --- a/apps/meteor/app/action-links/client/lib/actionLinks.ts +++ b/apps/meteor/app/action-links/client/lib/actionLinks.ts @@ -1,55 +1,28 @@ import { Meteor } from 'meteor/meteor'; import type { IMessage } from '@rocket.chat/core-typings'; -import { dispatchToastMessage } from '../../../../client/lib/toast'; +import { isLayoutEmbedded } from '../../../../client/lib/utils/isLayoutEmbedded'; +import { fireGlobalEvent } from '../../../../client/lib/utils/fireGlobalEvent'; // Action Links namespace creation. export const actionLinks = { - actions: new Map< - string, - (message: IMessage, params: string, instance?: Blaze.TemplateInstance | ((actionId: string, context: string) => void)) => void - >(), - register( - name: string, - fn: (message: IMessage, params: string, instance?: Blaze.TemplateInstance | ((actionId: string, context: string) => void)) => void, - ): void { + actions: new Map void>(), + register(name: string, fn: (message: IMessage, params: string) => void): void { actionLinks.actions.set(name, fn); }, - // getMessage(name, messageId) { - // const userId = Meteor.userId(); - // if (!userId) { - // throw new Meteor.Error('error-invalid-user', 'Invalid user', { - // function: 'actionLinks.getMessage', - // }); - // } - - // const message = Messages.findOne({ _id: messageId }); - // if (!message) { - // throw new Meteor.Error('error-invalid-message', 'Invalid message', { - // function: 'actionLinks.getMessage', - // }); - // } - - // const subscription = Subscriptions.findOne({ - // 'rid': message.rid, - // 'u._id': userId, - // }); - // if (!subscription) { - // throw new Meteor.Error('error-not-allowed', 'Not allowed', { - // function: 'actionLinks.getMessage', - // }); - // } - - // if (!message.actionLinks || !message.actionLinks[name]) { - // throw new Meteor.Error('error-invalid-actionlink', 'Invalid action link', { - // function: 'actionLinks.getMessage', - // }); - // } + run(actionMethodId: string, message: IMessage): void { + const embedded = isLayoutEmbedded(); + + if (embedded) { + fireGlobalEvent('click-action-link', { + actionlink: actionMethodId, + value: message._id, + message, + }); + return; + } - // return message; - // }, - run(method: string, message: IMessage, instance?: Blaze.TemplateInstance | ((actionId: string, context: string) => void)): void { - const actionLink = message.actionLinks?.find((action) => action.method_id === method); + const actionLink = message.actionLinks?.find((action) => action.method_id === actionMethodId); if (!actionLink) { throw new Meteor.Error('error-invalid-actionlink', 'Invalid action link'); @@ -60,21 +33,6 @@ export const actionLinks = { } const fn = actionLinks.actions.get(actionLink.method_id); - - let ranClient = false; - - if (fn) { - // run just on client side - fn(message, actionLink.params, instance); - - ranClient = true; - } - - // and run on server side - Meteor.call('actionLinkHandler', name, message._id, (error: unknown) => { - if (error && !ranClient) { - dispatchToastMessage({ type: 'error', message: error }); - } - }); + fn?.(message, actionLink.params); }, }; diff --git a/apps/meteor/app/action-links/server/actionLinkHandler.ts b/apps/meteor/app/action-links/server/actionLinkHandler.ts deleted file mode 100644 index 51c196ffb3b75..0000000000000 --- a/apps/meteor/app/action-links/server/actionLinkHandler.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { check } from 'meteor/check'; - -import { actionLinks } from './lib/actionLinks'; -// Action Links Handler. This method will be called off the client. - -Meteor.methods({ - actionLinkHandler(name, messageId) { - check(messageId, String); - check(name, String); - - if (!Meteor.userId()) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'actionLinkHandler' }); - } - - const message = actionLinks.getMessage(name, messageId); - - if (!message) { - throw new Meteor.Error('error-invalid-message', 'Invalid message', { method: 'actionLinkHandler' }); - } - - // NOTE: based on types (and how FE uses it) this should be the way of doing it - const actionLink = message.actionLinks?.find((action) => action.method_id === name); - - if (!actionLink) { - throw new Meteor.Error('error-invalid-actionlink', 'Invalid action link', { method: 'actionLinkHandler' }); - } - - actionLinks.actions[actionLink.method_id](message, actionLink.params); - }, -}); diff --git a/apps/meteor/app/action-links/server/index.ts b/apps/meteor/app/action-links/server/index.ts deleted file mode 100644 index 1b59ca164a314..0000000000000 --- a/apps/meteor/app/action-links/server/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { actionLinks } from './lib/actionLinks'; -import './actionLinkHandler'; - -export { actionLinks }; diff --git a/apps/meteor/app/action-links/server/lib/actionLinks.ts b/apps/meteor/app/action-links/server/lib/actionLinks.ts deleted file mode 100644 index 58b8fa950b03e..0000000000000 --- a/apps/meteor/app/action-links/server/lib/actionLinks.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { IMessage } from '@rocket.chat/core-typings'; -import { Meteor } from 'meteor/meteor'; - -import { getMessageForUser } from '../../../../server/lib/messages/getMessageForUser'; - -function getMessageById(messageId: IMessage['_id']): IMessage | undefined { - try { - const user = Meteor.userId(); - if (!user) { - return; - } - return Promise.await(getMessageForUser(messageId, user)); - } catch (e) { - throw new Meteor.Error(e instanceof Error ? e.message : String(e), 'Invalid message', { - function: 'actionLinks.getMessage', - }); - } -} - -type ActionLinkHandler = (message: IMessage, params?: string, instance?: undefined) => void; - -// Action Links namespace creation. -export const actionLinks = { - actions: {} as { [key: string]: ActionLinkHandler }, - register(name: string, funct: ActionLinkHandler): void { - actionLinks.actions[name] = funct; - }, - getMessage(name: string, messageId: IMessage['_id']): IMessage | undefined { - const message = getMessageById(messageId); - - if (!message) { - throw new Meteor.Error('error-invalid-message', 'Invalid message', { - function: 'actionLinks.getMessage', - }); - } - - if (!message.actionLinks?.some((action) => action.method_id === name)) { - throw new Meteor.Error('error-invalid-actionlink', 'Invalid action link', { - function: 'actionLinks.getMessage', - }); - } - - return message; - }, -}; diff --git a/apps/meteor/app/analytics/client/index.js b/apps/meteor/app/analytics/client/index.ts similarity index 100% rename from apps/meteor/app/analytics/client/index.js rename to apps/meteor/app/analytics/client/index.ts diff --git a/apps/meteor/app/analytics/client/loadScript.js b/apps/meteor/app/analytics/client/loadScript.js deleted file mode 100644 index 747fefe076a31..0000000000000 --- a/apps/meteor/app/analytics/client/loadScript.js +++ /dev/null @@ -1,98 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Template } from 'meteor/templating'; - -import { settings } from '../../settings'; -import { hex_sha1 } from '../../utils'; - -Template.body.onRendered(function () { - this.autorun((c) => { - const piwikUrl = settings.get('PiwikAnalytics_enabled') && settings.get('PiwikAnalytics_url'); - const piwikSiteId = piwikUrl && settings.get('PiwikAnalytics_siteId'); - const piwikPrependDomain = piwikUrl && settings.get('PiwikAnalytics_prependDomain'); - const piwikCookieDomain = piwikUrl && settings.get('PiwikAnalytics_cookieDomain'); - const piwikDomains = piwikUrl && settings.get('PiwikAnalytics_domains'); - const piwikAdditionalTracker = piwikUrl && settings.get('PiwikAdditionalTrackers'); - const googleId = settings.get('GoogleAnalytics_enabled') && settings.get('GoogleAnalytics_ID'); - if (piwikSiteId || googleId) { - c.stop(); - - if (piwikSiteId) { - window._paq = window._paq || []; - if (Meteor.userId()) { - window._paq.push(['setUserId', Meteor.userId()]); - } - - window._paq.push(['trackPageView']); - window._paq.push(['enableLinkTracking']); - if (piwikPrependDomain) { - window._paq.push(['setDocumentTitle', `${window.location.hostname}/${document.title}`]); - } - const upperLevelDomain = `*.${window.location.hostname.split('.').slice(1).join('.')}`; - if (piwikCookieDomain) { - window._paq.push(['setCookieDomain', upperLevelDomain]); - } - if (piwikDomains) { - // array - const domainsArray = piwikDomains.split(/\n/); - const domains = []; - for (let i = 0; i < domainsArray.length; i++) { - // only push domain if it contains a non whitespace character. - if (/\S/.test(domainsArray[i])) { - domains.push(`*.${domainsArray[i].trim()}`); - } - } - window._paq.push(['setDomains', domains]); - } - (() => { - try { - if (/\S/.test(piwikAdditionalTracker)) { - // piwikAdditionalTracker is not empty or whitespace only - const addTrackers = JSON.parse(piwikAdditionalTracker); - for (let i = 0; i < addTrackers.length; i++) { - const tracker = addTrackers[i]; - window._paq.push(['addTracker', `${tracker.trackerURL}js/`, tracker.siteId]); - } - } - } catch (e) { - // parsing JSON faild - console.log('Error while parsing JSON value of "piwikAdditionalTracker": ', e); - } - window._paq.push(['setTrackerUrl', `${piwikUrl}js/`]); - window._paq.push(['setSiteId', Number.parseInt(piwikSiteId)]); - const d = document; - const g = d.createElement('script'); - const s = d.getElementsByTagName('script')[0]; - g.type = 'text/javascript'; - g.async = true; - g.defer = true; - g.src = `${piwikUrl}js/`; - s.parentNode.insertBefore(g, s); - })(); - } - - if (googleId) { - /*eslint-disable */ - (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); - - ga('create', googleId, 'auto'); - - // WIDECHAT - obfuscate username in GA - const pathArray = document.location.pathname.split('/'); - if (pathArray[1] === 'direct') { - const hashedUsername = hex_sha1(pathArray[2]); - const page = document.location.pathname.replace(pathArray[2], hashedUsername); - - ga('set', 'location', page); - ga('send', 'pageview', page); - - } else { - ga('send', 'pageview'); - } - /* eslint-enable */ - } - } - }); -}); diff --git a/apps/meteor/app/analytics/client/loadScript.ts b/apps/meteor/app/analytics/client/loadScript.ts new file mode 100644 index 0000000000000..7ddce14102c68 --- /dev/null +++ b/apps/meteor/app/analytics/client/loadScript.ts @@ -0,0 +1,122 @@ +import { Meteor } from 'meteor/meteor'; +import { Template } from 'meteor/templating'; + +import { settings } from '../../settings/client'; + +declare global { + // eslint-disable-next-line @typescript-eslint/naming-convention + interface Window { + _paq: [string, ...unknown[]][]; + GoogleAnalyticsObject: unknown; + ga: qa; + } + + type qa = { + (...args: unknown[]): void; + l: number; + q: unknown[]; + }; +} + +Template.body.onRendered(function () { + this.autorun(() => { + const uid = Meteor.userId(); + if (uid) { + window._paq = window._paq || []; + window._paq.push(['setUserId', uid]); + } + }); + + this.autorun((c) => { + const googleId = settings.get('GoogleAnalytics_enabled') && settings.get('GoogleAnalytics_ID'); + if (googleId) { + c.stop(); + + if (googleId) { + /*eslint-disable */ + (function (i, s, o, g, r: 'ga', a?: any, m?: any) { + i['GoogleAnalyticsObject'] = r; + (i[r] = + i[r] || + function () { + (i[r].q = i[r].q || []).push(arguments); + }), + (i[r].l = new Date().getTime()); + (a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]); + a.async = 1; + a.src = g; + m.parentNode.insertBefore(a, m); + })(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga'); + + window.ga('create', googleId, 'auto'); + window.ga('send', 'pageview'); + /* eslint-enable */ + } + } + }); + + this.autorun(() => { + const piwikUrl = settings.get('PiwikAnalytics_enabled') && settings.get('PiwikAnalytics_url'); + + if (!piwikUrl) { + document.getElementById('piwik-analytics')?.remove(); + window._paq = []; + return; + } + + const piwikSiteId = piwikUrl && settings.get('PiwikAnalytics_siteId'); + const piwikPrependDomain = piwikUrl && settings.get('PiwikAnalytics_prependDomain'); + const piwikCookieDomain = piwikUrl && settings.get('PiwikAnalytics_cookieDomain'); + const piwikDomains = piwikUrl && settings.get('PiwikAnalytics_domains'); + const piwikAdditionalTracker = piwikUrl && settings.get('PiwikAdditionalTrackers'); + window._paq = window._paq || []; + + window._paq.push(['trackPageView']); + window._paq.push(['enableLinkTracking']); + if (piwikPrependDomain) { + window._paq.push(['setDocumentTitle', `${window.location.hostname}/${document.title}`]); + } + const upperLevelDomain = `*.${window.location.hostname.split('.').slice(1).join('.')}`; + if (piwikCookieDomain) { + window._paq.push(['setCookieDomain', upperLevelDomain]); + } + if (piwikDomains) { + // array + const domainsArray = piwikDomains.split(/\n/); + const domains = []; + for (let i = 0; i < domainsArray.length; i++) { + // only push domain if it contains a non whitespace character. + if (/\S/.test(domainsArray[i])) { + domains.push(`*.${domainsArray[i].trim()}`); + } + } + window._paq.push(['setDomains', domains]); + } + (() => { + try { + if (/\S/.test(piwikAdditionalTracker)) { + // piwikAdditionalTracker is not empty or whitespace only + const addTrackers = JSON.parse(piwikAdditionalTracker); + for (let i = 0; i < addTrackers.length; i++) { + const tracker = addTrackers[i]; + window._paq.push(['addTracker', `${tracker.trackerURL}js/`, tracker.siteId]); + } + } + } catch (e) { + // parsing JSON faild + console.log('Error while parsing JSON value of "piwikAdditionalTracker": ', e); + } + window._paq.push(['setTrackerUrl', `${piwikUrl}js/`]); + window._paq.push(['setSiteId', Number.parseInt(piwikSiteId)]); + const d = document; + const g = d.createElement('script'); + g.setAttribute('id', 'piwik-analytics'); + const s = d.getElementsByTagName('script')[0]; + g.type = 'text/javascript'; + g.async = true; + g.defer = true; + g.src = `${piwikUrl}js/`; + s.parentNode?.insertBefore(g, s); + })(); + }); +}); diff --git a/apps/meteor/app/analytics/server/index.js b/apps/meteor/app/analytics/server/index.ts similarity index 100% rename from apps/meteor/app/analytics/server/index.js rename to apps/meteor/app/analytics/server/index.ts diff --git a/apps/meteor/app/api/server/api.d.ts b/apps/meteor/app/api/server/api.d.ts index 8ddc27f0457cb..20630f1acf8e1 100644 --- a/apps/meteor/app/api/server/api.d.ts +++ b/apps/meteor/app/api/server/api.d.ts @@ -139,6 +139,7 @@ type ActionThis { return remoteAddress; } - if (!_.isString(forwardedFor)) { + if (!forwardedFor || typeof forwardedFor.valueOf() !== 'string') { return remoteAddress; } @@ -322,7 +322,7 @@ export class APIClass extends Restivus { const shouldVerifyPermissions = checkPermissions(options); // Allow for more than one route using the same option and endpoints - if (!_.isArray(routes)) { + if (!Array.isArray(routes)) { routes = [routes]; } const { version } = this._config; diff --git a/apps/meteor/app/api/server/helpers/deprecationWarning.ts b/apps/meteor/app/api/server/helpers/deprecationWarning.ts index 5487d97d54d29..a7f148219b0e1 100644 --- a/apps/meteor/app/api/server/helpers/deprecationWarning.ts +++ b/apps/meteor/app/api/server/helpers/deprecationWarning.ts @@ -1,20 +1,24 @@ import { API } from '../api'; import { apiDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; -export function deprecationWarning({ - endpoint, - versionWillBeRemoved = '5.0', - response, -}: { +type DeprecationWarningParams = { endpoint: string; versionWillBeRemoved?: string; response: T; -}): T { - const warningMessage = `The endpoint "${endpoint}" is deprecated and will be removed after version ${versionWillBeRemoved}`; - apiDeprecationLogger.warn(warningMessage); + warningMessage?: string | ((props: Omit, 'warningMessage'>) => string); +}; +export function deprecationWarning({ + endpoint, + versionWillBeRemoved = '6.0', + response, + warningMessage = `The endpoint "${endpoint}" is deprecated and will be removed on version ${versionWillBeRemoved}`, +}: DeprecationWarningParams): T { + const warning = typeof warningMessage === 'function' ? warningMessage({ endpoint, versionWillBeRemoved, response }) : warningMessage; + + apiDeprecationLogger.warn(warning); if (process.env.NODE_ENV === 'development') { return { - warning: warningMessage, + warning, ...response, }; } diff --git a/apps/meteor/app/api/server/helpers/requestParams.ts b/apps/meteor/app/api/server/helpers/requestParams.ts index a68205ab09ede..a7f11d5ffecf5 100644 --- a/apps/meteor/app/api/server/helpers/requestParams.ts +++ b/apps/meteor/app/api/server/helpers/requestParams.ts @@ -1,5 +1,5 @@ import { API } from '../api'; API.helperMethods.set('requestParams', function _requestParams(this: any) { - return ['POST', 'PUT'].includes(this.request.method) ? this.bodyParams : this.queryParams; + return ['POST', 'PUT', 'DELETE'].includes(this.request.method) ? this.bodyParams : this.queryParams; }); diff --git a/apps/meteor/app/api/server/index.ts b/apps/meteor/app/api/server/index.ts index 921e554492522..0849c4c98241d 100644 --- a/apps/meteor/app/api/server/index.ts +++ b/apps/meteor/app/api/server/index.ts @@ -27,6 +27,7 @@ import './v1/import'; import './v1/ldap'; import './v1/misc'; import './v1/permissions'; +import './v1/presence'; import './v1/push'; import './v1/roles'; import './v1/rooms.js'; @@ -44,6 +45,7 @@ import './v1/custom-user-status'; import './v1/instances'; import './v1/banners'; import './v1/email-inbox'; +import './v1/mailer'; import './v1/teams'; import './v1/voip/extensions'; import './v1/voip/queues'; diff --git a/apps/meteor/app/api/server/lib/emailInbox.ts b/apps/meteor/app/api/server/lib/emailInbox.ts index 1e6e1db361963..dcfd147b6a1f6 100644 --- a/apps/meteor/app/api/server/lib/emailInbox.ts +++ b/apps/meteor/app/api/server/lib/emailInbox.ts @@ -2,15 +2,12 @@ import type { IEmailInbox } from '@rocket.chat/core-typings'; import type { Filter, InsertOneResult, Sort, UpdateResult, WithId } from 'mongodb'; import { EmailInbox } from '@rocket.chat/models'; -import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { Users } from '../../../models/server'; export const findEmailInboxes = async ({ - userId, query = {}, pagination: { offset, count, sort }, }: { - userId: string; query?: Filter; pagination: { offset: number; @@ -23,9 +20,6 @@ export const findEmailInboxes = async ({ count: number; offset: number; }> => { - if (!(await hasPermissionAsync(userId, 'manage-email-inbox'))) { - throw new Error('error-not-allowed'); - } const { cursor, totalCount } = EmailInbox.findPaginated(query, { sort: sort || { name: 1 }, skip: offset, @@ -42,10 +36,7 @@ export const findEmailInboxes = async ({ }; }; -export const findOneEmailInbox = async ({ userId, _id }: { userId: string; _id: string }): Promise => { - if (!(await hasPermissionAsync(userId, 'manage-email-inbox'))) { - throw new Error('error-not-allowed'); - } +export const findOneEmailInbox = async ({ _id }: { _id: string }): Promise => { return EmailInbox.findOneById(_id); }; export const insertOneEmailInbox = async ( @@ -62,12 +53,11 @@ export const insertOneEmailInbox = async ( }; export const updateEmailInbox = async ( - userId: string, emailInboxParams: Pick, ): Promise> | UpdateResult> => { const { _id, active, name, email, description, senderInfo, department, smtp, imap } = emailInboxParams; - const emailInbox = await findOneEmailInbox({ userId, _id }); + const emailInbox = await findOneEmailInbox({ _id }); if (!emailInbox) { throw new Error('error-invalid-email-inbox'); @@ -90,10 +80,3 @@ export const updateEmailInbox = async ( return EmailInbox.updateOne({ _id }, updateEmailInbox); }; - -export const findOneEmailInboxByEmail = async ({ userId, email }: { userId: string; email: string }): Promise => { - if (!(await hasPermissionAsync(userId, 'manage-email-inbox'))) { - throw new Error('error-not-allowed'); - } - return EmailInbox.findOne({ email }); -}; diff --git a/apps/meteor/app/api/server/lib/getUploadFormData.ts b/apps/meteor/app/api/server/lib/getUploadFormData.ts index 15a433a214133..5df41638b90a1 100644 --- a/apps/meteor/app/api/server/lib/getUploadFormData.ts +++ b/apps/meteor/app/api/server/lib/getUploadFormData.ts @@ -1,19 +1,21 @@ import type { Readable } from 'stream'; -import { Meteor } from 'meteor/meteor'; import type { Request } from 'express'; import busboy from 'busboy'; import type { ValidateFunction } from 'ajv'; +import { MeteorError } from '@rocket.chat/core-services'; -type UploadResult = { - file: Readable; +type UploadResult = { + file: Readable & { truncated: boolean }; + fieldname: string; filename: string; encoding: string; mimetype: string; fileBuffer: Buffer; + fields: K; }; -export const getUploadFormData = async < +export async function getUploadFormData< T extends string, K extends Record = Record, V extends ValidateFunction = ValidateFunction, @@ -22,63 +24,103 @@ export const getUploadFormData = async < options: { field?: T; validate?: V; + sizeLimit?: number; } = {}, -): Promise<[UploadResult, K, T]> => - new Promise((resolve, reject) => { - const bb = busboy({ headers: request.headers, defParamCharset: 'utf8' }); - const fields = Object.create(null) as K; - - let uploadedFile: UploadResult | undefined; - - let assetName: T | undefined; - - bb.on( - 'file', - ( - fieldname: string, - file: Readable, - { filename, encoding, mimeType: mimetype }: { filename: string; encoding: string; mimeType: string }, - ) => { - const fileData: Uint8Array[] = []; - - file.on('data', (data: any) => fileData.push(data)); - - file.on('end', () => { - if (uploadedFile) { - return reject('Just 1 file is allowed'); - } - if (options.field && fieldname !== options.field) { - return reject(new Meteor.Error('invalid-field')); - } - uploadedFile = { - file, - filename, - encoding, - mimetype, - fileBuffer: Buffer.concat(fileData), - }; - - assetName = fieldname as T; - }); - }, - ); - - bb.on('field', (fieldname: keyof K, value: K[keyof K]) => { - fields[fieldname] = value; +): Promise> { + const limits = { + files: 1, + ...(options.sizeLimit && options.sizeLimit > -1 && { fileSize: options.sizeLimit }), + }; + + const bb = busboy({ headers: request.headers, defParamCharset: 'utf8', limits }); + const fields = Object.create(null) as K; + + let uploadedFile: UploadResult | undefined; + + let returnResult = (_value: UploadResult) => { + // noop + }; + let returnError = (_error?: Error | string | null | undefined) => { + // noop + }; + + function onField(fieldname: keyof K, value: K[keyof K]) { + fields[fieldname] = value; + } + + function onEnd() { + if (!uploadedFile) { + return returnError(new MeteorError('No file uploaded')); + } + if (options.validate !== undefined && !options.validate(fields)) { + return returnError(new MeteorError(`Invalid fields ${options.validate.errors?.join(', ')}`)); + } + return returnResult(uploadedFile); + } + + function onFile( + fieldname: string, + file: Readable & { truncated: boolean }, + { filename, encoding, mimeType: mimetype }: { filename: string; encoding: string; mimeType: string }, + ) { + if (options.field && fieldname !== options.field) { + file.resume(); + return returnError(new MeteorError('invalid-field')); + } + + const fileChunks: Uint8Array[] = []; + file.on('data', function (chunk) { + fileChunks.push(chunk); }); - bb.on('finish', () => { - if (!uploadedFile || !assetName) { - return reject('No file uploaded'); - } - if (options.validate === undefined) { - return resolve([uploadedFile, fields, assetName]); + file.on('end', function () { + if (file.truncated) { + fileChunks.length = 0; + return returnError(new MeteorError('error-file-too-large')); } - if (!options.validate(fields)) { - return reject(`Invalid fields${options.validate.errors?.join(', ')}`); - } - return resolve([uploadedFile, fields, assetName]); + + uploadedFile = { + file, + filename, + encoding, + mimetype, + fieldname, + fields, + fileBuffer: Buffer.concat(fileChunks), + }; }); + } + + function cleanup() { + request.unpipe(bb); + request.on('readable', request.read.bind(request)); + bb.removeAllListeners(); + } + + bb.on('field', onField); + bb.on('file', onFile); + bb.on('close', cleanup); + bb.on('end', onEnd); + bb.on('finish', onEnd); + + bb.on('error', function (err: Error) { + returnError(err); + }); + + bb.on('partsLimit', function () { + returnError(); + }); + bb.on('filesLimit', function () { + returnError('Just 1 file is allowed'); + }); + bb.on('fieldsLimit', function () { + returnError(); + }); + + request.pipe(bb); - request.pipe(bb); + return new Promise((resolve, reject) => { + returnResult = resolve; + returnError = reject; }); +} diff --git a/apps/meteor/app/api/server/lib/messages.ts b/apps/meteor/app/api/server/lib/messages.ts index d6955ce7b9331..a4f28f9680f7e 100644 --- a/apps/meteor/app/api/server/lib/messages.ts +++ b/apps/meteor/app/api/server/lib/messages.ts @@ -3,7 +3,6 @@ import type { IMessage, IUser } from '@rocket.chat/core-typings'; import { Rooms, Messages, Users } from '@rocket.chat/models'; import { canAccessRoomAsync } from '../../../authorization/server/functions/canAccessRoom'; -import { getValue } from '../../../settings/server/raw'; export async function findMentionedMessages({ uid, @@ -55,7 +54,7 @@ export async function findStarredMessages({ }): Promise<{ messages: IMessage[]; count: number; - offset: any; + offset: number; total: number; }> { const room = await Rooms.findOneById(roomId); @@ -83,73 +82,6 @@ export async function findStarredMessages({ }; } -export async function findSnippetedMessageById({ uid, messageId }: { uid: string; messageId: string }): Promise { - if (!(await getValue('Message_AllowSnippeting'))) { - throw new Error('error-not-allowed'); - } - - if (!uid) { - throw new Error('invalid-user'); - } - - const snippet = await Messages.findOne({ _id: messageId, snippeted: true }); - - if (!snippet) { - throw new Error('invalid-message'); - } - - const room = await Rooms.findOneById(snippet.rid); - - if (!room) { - throw new Error('invalid-message'); - } - - if (!(await canAccessRoomAsync(room, { _id: uid }))) { - throw new Error('error-not-allowed'); - } - - return snippet; -} - -export async function findSnippetedMessages({ - uid, - roomId, - pagination: { offset, count, sort }, -}: { - uid: string; - roomId: string; - pagination: { offset: number; count: number; sort: FindOptions['sort'] }; -}): Promise<{ - messages: IMessage[]; - count: number; - offset: number; - total: number; -}> { - if (!(await getValue('Message_AllowSnippeting'))) { - throw new Error('error-not-allowed'); - } - const room = await Rooms.findOneById(roomId); - - if (!room || !(await canAccessRoomAsync(room, { _id: uid }))) { - throw new Error('error-not-allowed'); - } - - const { cursor, totalCount } = Messages.findSnippetedByRoom(roomId, { - sort: sort || { ts: -1 }, - skip: offset, - limit: count, - }); - - const [messages, total] = await Promise.all([cursor.toArray(), totalCount]); - - return { - messages, - count: messages.length, - offset, - total, - }; -} - export async function findDiscussionsFromRoom({ uid, roomId, diff --git a/apps/meteor/app/api/server/lib/rooms.ts b/apps/meteor/app/api/server/lib/rooms.ts index 32908c1854416..c2738f35e9950 100644 --- a/apps/meteor/app/api/server/lib/rooms.ts +++ b/apps/meteor/app/api/server/lib/rooms.ts @@ -32,23 +32,22 @@ export async function findAdminRooms({ const showTypes = Array.isArray(types) ? types.filter((type) => !typesToRemove.includes(type)) : []; const options = { projection: adminFields, - sort: sort || { default: -1, name: 1 }, skip: offset, limit: count, }; let result; if (name && showTypes.length) { - result = Rooms.findByNameContainingAndTypes(name, showTypes, discussion, includeTeams, showOnlyTeams, options); + result = Rooms.findByNameOrFnameContainingAndTypes(name, showTypes, discussion, includeTeams, showOnlyTeams, options); } else if (showTypes.length) { result = Rooms.findByTypes(showTypes, discussion, includeTeams, showOnlyTeams, options); } else { - result = Rooms.findByNameContaining(name, discussion, includeTeams, showOnlyTeams, options); + result = Rooms.findByNameOrFnameContaining(name, discussion, includeTeams, showOnlyTeams, options); } const { cursor, totalCount } = result; - const [rooms, total] = await Promise.all([cursor.toArray(), totalCount]); + const [rooms, total] = await Promise.all([cursor.sort(sort || { default: -1, name: 1 }).toArray(), totalCount]); return { rooms, diff --git a/apps/meteor/app/api/server/lib/users.ts b/apps/meteor/app/api/server/lib/users.ts index 38edb4fa5cd41..8fed9e4e21555 100644 --- a/apps/meteor/app/api/server/lib/users.ts +++ b/apps/meteor/app/api/server/lib/users.ts @@ -1,28 +1,24 @@ import { escapeRegExp } from '@rocket.chat/string-helpers'; import type { IUser } from '@rocket.chat/core-typings'; import type { Filter } from 'mongodb'; -import { Users } from '@rocket.chat/models'; +import { Users, Subscriptions } from '@rocket.chat/models'; import type { Mongo } from 'meteor/mongo'; import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; +import { settings } from '../../../settings/server'; type UserAutoComplete = Required>; + export async function findUsersToAutocomplete({ uid, selector, }: { uid: string; - selector: { - exceptions: string[]; - conditions: Filter; - term: string; - }; + selector: { exceptions: Required['username'][]; conditions: Filter; term: string }; }): Promise<{ items: UserAutoComplete[]; }> { - if (!(await hasPermissionAsync(uid, 'view-outside-room'))) { - return { items: [] }; - } + const searchFields = settings.get('Accounts_SearchFields').trim().split(','); const exceptions = selector.exceptions || []; const conditions = selector.conditions || {}; const options = { @@ -39,6 +35,20 @@ export async function findUsersToAutocomplete({ limit: 10, }; + // Search on DMs first, to list known users before others. + const contacts = await Subscriptions.findConnectedUsersExcept(uid, selector.term, exceptions, searchFields, conditions, 10, 'd'); + if (contacts.length >= options.limit) { + return { items: contacts as UserAutoComplete[] }; + } + + options.limit -= contacts.length; + contacts.forEach(({ username }) => exceptions.push(username)); + + if (!(await hasPermissionAsync(uid, 'view-outside-room'))) { + const users = await Subscriptions.findConnectedUsersExcept(uid, selector.term, exceptions, searchFields, conditions, 10); + return { items: contacts.concat(users) as UserAutoComplete[] }; + } + const users = await Users.findActiveByUsernameOrNameRegexWithExceptionsAndConditions( new RegExp(escapeRegExp(selector.term), 'i'), exceptions, @@ -47,7 +57,7 @@ export async function findUsersToAutocomplete({ ).toArray(); return { - items: users, + items: (contacts as UserAutoComplete[]).concat(users), }; } diff --git a/apps/meteor/app/api/server/settings.ts b/apps/meteor/app/api/server/settings.ts index 692a856280b92..dce44913422ce 100644 --- a/apps/meteor/app/api/server/settings.ts +++ b/apps/meteor/app/api/server/settings.ts @@ -31,5 +31,12 @@ settingsRegistry.addGroup('General', function () { type: 'boolean', public: true, }); + + // Should enforce the permission on next Major and remove this setting + this.add('API_Apply_permission_view-outside-room_on_users-list', false, { + type: 'boolean', + public: true, + alert: 'This_is_a_deprecated_feature_alert', + }); }); }); diff --git a/apps/meteor/app/api/server/v1/assets.ts b/apps/meteor/app/api/server/v1/assets.ts index db3d63827535b..2c4bf90b68aa9 100644 --- a/apps/meteor/app/api/server/v1/assets.ts +++ b/apps/meteor/app/api/server/v1/assets.ts @@ -4,20 +4,25 @@ import { isAssetsUnsetAssetProps } from '@rocket.chat/rest-typings'; import { RocketChatAssets } from '../../../assets/server'; import { API } from '../api'; import { getUploadFormData } from '../lib/getUploadFormData'; +import { settings } from '../../../settings/server'; API.v1.addRoute( 'assets.setAsset', { authRequired: true }, { async post() { - const [asset, { refreshAllClients, assetName: customName }, fileName] = await getUploadFormData( + const asset = await getUploadFormData( { request: this.request, }, - { field: 'asset' }, + { field: 'asset', sizeLimit: settings.get('FileUpload_MaxFileSize') }, ); - const assetName = customName || fileName; + const { fileBuffer, fields, filename, mimetype } = asset; + + const { refreshAllClients, assetName: customName } = fields; + + const assetName = customName || filename; const assetsKeys = Object.keys(RocketChatAssets.assets); const isValidAsset = assetsKeys.includes(assetName); @@ -25,7 +30,7 @@ API.v1.addRoute( throw new Meteor.Error('error-invalid-asset', 'Invalid asset'); } - Meteor.call('setAsset', asset.fileBuffer, asset.mimetype, assetName); + Meteor.call('setAsset', fileBuffer, mimetype, assetName); if (refreshAllClients) { Meteor.call('refreshClients'); } diff --git a/apps/meteor/app/api/server/v1/banners.ts b/apps/meteor/app/api/server/v1/banners.ts index 4b979b376d94c..deea03bccca2b 100644 --- a/apps/meteor/app/api/server/v1/banners.ts +++ b/apps/meteor/app/api/server/v1/banners.ts @@ -1,8 +1,8 @@ import { Match, check } from 'meteor/check'; import { BannerPlatform } from '@rocket.chat/core-typings'; +import { Banner } from '@rocket.chat/core-services'; import { API } from '../api'; -import { Banner } from '../../../../server/sdk'; /** * @deprecated diff --git a/apps/meteor/app/api/server/v1/channels.js b/apps/meteor/app/api/server/v1/channels.js index 2b02a1f860790..735b27a2ad84b 100644 --- a/apps/meteor/app/api/server/v1/channels.js +++ b/apps/meteor/app/api/server/v1/channels.js @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; import { Match, check } from 'meteor/check'; -import _ from 'underscore'; import { Integrations, Uploads, Messages as MessagesRaw, Rooms as RoomsRaw, Subscriptions as SubscriptionsRaw } from '@rocket.chat/models'; +import { Team } from '@rocket.chat/core-services'; import { Rooms, Subscriptions, Messages, Users } from '../../../models/server'; import { canAccessRoom, hasPermission, hasAtLeastOnePermission } from '../../../authorization/server'; @@ -9,7 +9,6 @@ import { mountIntegrationQueryBasedOnPermissions } from '../../../integrations/s import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser'; import { API } from '../api'; import { settings } from '../../../settings/server'; -import { Team } from '../../../../server/sdk'; import { findUsersOfRoom } from '../../../../server/lib/findUsersOfRoom'; import { addUserToFileObj } from '../helpers/addUserToFileObj'; @@ -174,7 +173,7 @@ function createChannelValidator(params) { throw new Error(`Param "${params.name.key}" is required`); } - if (params.members && params.members.value && !_.isArray(params.members.value)) { + if (params.members && params.members.value && !Array.isArray(params.members.value)) { throw new Error(`Param "${params.members.key}" must be an array if provided`); } @@ -287,7 +286,7 @@ API.v1.addRoute( const ourQuery = Object.assign({}, query, { rid: findResult._id }); - const { cursor, totalCount } = Uploads.findPaginated(ourQuery, { + const { cursor, totalCount } = Uploads.findPaginatedWithoutThumbs(ourQuery, { sort: sort || { name: 1 }, skip: offset, limit: count, diff --git a/apps/meteor/app/api/server/v1/channels.ts b/apps/meteor/app/api/server/v1/channels.ts index 9816a262d10e2..f727b7b501ddf 100644 --- a/apps/meteor/app/api/server/v1/channels.ts +++ b/apps/meteor/app/api/server/v1/channels.ts @@ -19,12 +19,12 @@ import { isChannelsDeleteProps, } from '@rocket.chat/rest-typings'; import { Messages } from '@rocket.chat/models'; +import { Team } from '@rocket.chat/core-services'; import { Rooms, Subscriptions } from '../../../models/server'; import { hasPermission } from '../../../authorization/server'; import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser'; import { API } from '../api'; -import { Team } from '../../../../server/sdk'; // Returns the channel IF found otherwise it will return the failure of why it didn't. Check the `statusCode` property function findChannelByIdOrName({ @@ -270,7 +270,6 @@ API.v1.addRoute( return API.v1.unauthorized(); } - // @ts-expect-error recursive types are causing issues here const { cursor, totalCount } = Messages.findPaginated(ourQuery, { sort: sort || { ts: -1 }, skip: offset, @@ -471,8 +470,7 @@ API.v1.addRoute( const room = findChannelByIdOrName({ params: { - roomId: channelId, - roomName: channelName, + ...(channelId ? { roomId: channelId } : { roomName: channelName }), }, userId: this.userId, }); diff --git a/apps/meteor/app/api/server/v1/chat.js b/apps/meteor/app/api/server/v1/chat.js index 73f4b6931ddc4..76f042c8cbc0d 100644 --- a/apps/meteor/app/api/server/v1/chat.js +++ b/apps/meteor/app/api/server/v1/chat.js @@ -14,13 +14,7 @@ import Rooms from '../../../models/server/models/Rooms'; import Users from '../../../models/server/models/Users'; import Subscriptions from '../../../models/server/models/Subscriptions'; import { settings } from '../../../settings/server'; -import { - findMentionedMessages, - findStarredMessages, - findSnippetedMessageById, - findSnippetedMessages, - findDiscussionsFromRoom, -} from '../lib/messages'; +import { findMentionedMessages, findStarredMessages, findDiscussionsFromRoom } from '../lib/messages'; API.v1.addRoute( 'chat.delete', @@ -372,31 +366,6 @@ API.v1.addRoute( }, ); -API.v1.addRoute( - 'chat.getMessageReadReceipts', - { authRequired: true }, - { - async get() { - const { messageId } = this.queryParams; - if (!messageId) { - return API.v1.failure({ - error: "The required 'messageId' param is missing.", - }); - } - - try { - return API.v1.success({ - receipts: await Meteor.call('getReadReceipts', { messageId }), - }); - } catch (error) { - return API.v1.failure({ - error: error.message, - }); - } - }, - }, -); - API.v1.addRoute( 'chat.reportMessage', { authRequired: true }, @@ -786,55 +755,6 @@ API.v1.addRoute( }, ); -API.v1.addRoute( - 'chat.getSnippetedMessageById', - { authRequired: true }, - { - get() { - const { messageId } = this.queryParams; - - if (!messageId) { - throw new Meteor.Error('error-invalid-params', 'The required "messageId" query param is missing.'); - } - const message = Promise.await( - findSnippetedMessageById({ - uid: this.userId, - messageId, - }), - ); - return API.v1.success(message); - }, - }, -); - -API.v1.addRoute( - 'chat.getSnippetedMessages', - { authRequired: true }, - { - get() { - const { roomId } = this.queryParams; - const { sort } = this.parseJsonQuery(); - const { offset, count } = this.getPaginationItems(); - - if (!roomId) { - throw new Meteor.Error('error-invalid-params', 'The required "roomId" query param is missing.'); - } - const messages = Promise.await( - findSnippetedMessages({ - uid: this.userId, - roomId, - pagination: { - offset, - count, - sort, - }, - }), - ); - return API.v1.success(messages); - }, - }, -); - API.v1.addRoute( 'chat.getDiscussions', { authRequired: true }, diff --git a/apps/meteor/app/api/server/v1/cloud.ts b/apps/meteor/app/api/server/v1/cloud.ts index d7e108a7b0348..38b6a7221871d 100644 --- a/apps/meteor/app/api/server/v1/cloud.ts +++ b/apps/meteor/app/api/server/v1/cloud.ts @@ -5,6 +5,7 @@ import { hasPermission, hasRole } from '../../../authorization/server'; import { saveRegistrationData } from '../../../cloud/server/functions/saveRegistrationData'; import { retrieveRegistrationStatus } from '../../../cloud/server/functions/retrieveRegistrationStatus'; import { startRegisterWorkspaceSetupWizard } from '../../../cloud/server/functions/startRegisterWorkspaceSetupWizard'; +import { registerPreIntentWorkspaceWizard } from '../../../cloud/server/functions/registerPreIntentWorkspaceWizard'; import { getConfirmationPoll } from '../../../cloud/server/functions/getConfirmationPoll'; API.v1.addRoute( @@ -60,6 +61,20 @@ API.v1.addRoute( }, ); +API.v1.addRoute( + 'cloud.registerPreIntent', + { authRequired: true }, + { + async post() { + if (!hasPermission(this.userId, 'manage-cloud')) { + return API.v1.unauthorized(); + } + + return API.v1.success({ offline: !(await registerPreIntentWorkspaceWizard()) }); + }, + }, +); + API.v1.addRoute( 'cloud.confirmationPoll', { authRequired: true }, diff --git a/apps/meteor/app/api/server/v1/e2e.ts b/apps/meteor/app/api/server/v1/e2e.ts index 47420ab2f62d4..70f1066e09f47 100644 --- a/apps/meteor/app/api/server/v1/e2e.ts +++ b/apps/meteor/app/api/server/v1/e2e.ts @@ -8,6 +8,7 @@ import { import type { IUser } from '@rocket.chat/core-typings'; import { API } from '../api'; +import { handleSuggestedGroupKey } from '../../../e2e/server/functions/handleSuggestedGroupKey'; API.v1.addRoute( 'e2e.fetchMyKeys', @@ -195,3 +196,37 @@ API.v1.addRoute( }, }, ); + +API.v1.addRoute( + 'e2e.acceptSuggestedGroupKey', + { + authRequired: true, + validateParams: ise2eGetUsersOfRoomWithoutKeyParamsGET, + }, + { + async post() { + const { rid } = this.bodyParams; + + await handleSuggestedGroupKey('accept', rid, this.userId, 'e2e.acceptSuggestedGroupKey'); + + return API.v1.success(); + }, + }, +); + +API.v1.addRoute( + 'e2e.rejectSuggestedGroupKey', + { + authRequired: true, + validateParams: ise2eGetUsersOfRoomWithoutKeyParamsGET, + }, + { + async post() { + const { rid } = this.bodyParams; + + await handleSuggestedGroupKey('reject', rid, this.userId, 'e2e.rejectSuggestedGroupKey'); + + return API.v1.success(); + }, + }, +); diff --git a/apps/meteor/app/api/server/v1/email-inbox.ts b/apps/meteor/app/api/server/v1/email-inbox.ts index 293ae2e6b8aaa..36248c7bdfe4f 100644 --- a/apps/meteor/app/api/server/v1/email-inbox.ts +++ b/apps/meteor/app/api/server/v1/email-inbox.ts @@ -3,18 +3,17 @@ import { EmailInbox } from '@rocket.chat/models'; import { API } from '../api'; import { insertOneEmailInbox, findEmailInboxes, findOneEmailInbox, updateEmailInbox } from '../lib/emailInbox'; -import { hasPermission } from '../../../authorization/server/functions/hasPermission'; import Users from '../../../models/server/models/Users'; import { sendTestEmailToInbox } from '../../../../server/features/EmailInbox/EmailInbox_Outgoing'; API.v1.addRoute( 'email-inbox.list', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['manage-email-inbox'] }, { async get() { const { offset, count } = this.getPaginationItems(); const { sort, query } = this.parseJsonQuery(); - const emailInboxes = await findEmailInboxes({ userId: this.userId, query, pagination: { offset, count, sort } }); + const emailInboxes = await findEmailInboxes({ query, pagination: { offset, count, sort } }); return API.v1.success(emailInboxes); }, @@ -23,21 +22,17 @@ API.v1.addRoute( API.v1.addRoute( 'email-inbox', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['manage-email-inbox'] }, { async post() { - if (!hasPermission(this.userId, 'manage-email-inbox')) { - throw new Error('error-not-allowed'); - } - check(this.bodyParams, { _id: Match.Maybe(String), active: Boolean, name: String, email: String, - description: String, - senderInfo: String, - department: String, + description: Match.Maybe(String), + senderInfo: Match.Maybe(String), + department: Match.Maybe(String), smtp: Match.ObjectIncluding({ server: String, port: Number, @@ -64,7 +59,7 @@ API.v1.addRoute( _id = emailInbox.insertedId.toString(); } else { _id = emailInboxParams._id; - await updateEmailInbox(this.userId, { ...emailInboxParams, _id }); + await updateEmailInbox({ ...emailInboxParams, _id }); } return API.v1.success({ _id }); }, @@ -73,7 +68,7 @@ API.v1.addRoute( API.v1.addRoute( 'email-inbox/:_id', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['manage-email-inbox'] }, { async get() { check(this.urlParams, { @@ -84,15 +79,15 @@ API.v1.addRoute( if (!_id) { throw new Error('error-invalid-param'); } - // TODO: Chapter day backend - check if user has permission to view this email inbox instead of null values - const emailInboxes = await findOneEmailInbox({ userId: this.userId, _id }); + const emailInbox = await findOneEmailInbox({ _id }); - return API.v1.success(emailInboxes); + if (!emailInbox) { + return API.v1.notFound(); + } + + return API.v1.success(emailInbox); }, async delete() { - if (!hasPermission(this.userId, 'manage-email-inbox')) { - throw new Error('error-not-allowed'); - } check(this.urlParams, { _id: String, }); @@ -103,7 +98,6 @@ API.v1.addRoute( } const emailInboxes = await EmailInbox.findOneById(_id); - if (!emailInboxes) { return API.v1.notFound(); } @@ -115,12 +109,9 @@ API.v1.addRoute( API.v1.addRoute( 'email-inbox.search', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['manage-email-inbox'] }, { async get() { - if (!hasPermission(this.userId, 'manage-email-inbox')) { - throw new Error('error-not-allowed'); - } check(this.queryParams, { email: String, }); @@ -138,12 +129,9 @@ API.v1.addRoute( API.v1.addRoute( 'email-inbox.send-test/:_id', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['manage-email-inbox'] }, { async post() { - if (!hasPermission(this.userId, 'manage-email-inbox')) { - throw new Error('error-not-allowed'); - } check(this.urlParams, { _id: String, }); @@ -152,7 +140,7 @@ API.v1.addRoute( if (!_id) { throw new Error('error-invalid-param'); } - const emailInbox = await findOneEmailInbox({ userId: this.userId, _id }); + const emailInbox = await findOneEmailInbox({ _id }); if (!emailInbox) { return API.v1.notFound(); diff --git a/apps/meteor/app/api/server/v1/emoji-custom.ts b/apps/meteor/app/api/server/v1/emoji-custom.ts index e0027765352e0..c56ccb6169cce 100644 --- a/apps/meteor/app/api/server/v1/emoji-custom.ts +++ b/apps/meteor/app/api/server/v1/emoji-custom.ts @@ -1,11 +1,12 @@ import { Meteor } from 'meteor/meteor'; import { EmojiCustom } from '@rocket.chat/models'; +import { Media } from '@rocket.chat/core-services'; import { API } from '../api'; import { getUploadFormData } from '../lib/getUploadFormData'; import { findEmojisCustom } from '../lib/emoji-custom'; -import { Media } from '../../../../server/sdk'; import { SystemLogger } from '../../../../server/lib/logger/system'; +import { settings } from '../../../settings/server'; API.v1.addRoute( 'emoji-custom.list', @@ -68,19 +69,21 @@ API.v1.addRoute( { authRequired: true }, { async post() { - const [emoji, fields] = await getUploadFormData( + const emoji = await getUploadFormData( { request: this.request, }, - { field: 'emoji' }, + { field: 'emoji', sizeLimit: settings.get('FileUpload_MaxFileSize') }, ); - const isUploadable = await Media.isImage(emoji.fileBuffer); + const { fields, fileBuffer, mimetype } = emoji; + + const isUploadable = await Media.isImage(fileBuffer); if (!isUploadable) { throw new Meteor.Error('emoji-is-not-image', "Emoji file provided cannot be uploaded since it's not an image"); } - const [, extension] = emoji.mimetype.split('/'); + const [, extension] = mimetype.split('/'); fields.extension = extension; try { @@ -89,7 +92,7 @@ API.v1.addRoute( newFile: true, aliases: fields.aliases || '', }); - Meteor.call('uploadEmojiCustom', emoji.fileBuffer, emoji.mimetype, { + Meteor.call('uploadEmojiCustom', fileBuffer, mimetype, { ...fields, newFile: true, aliases: fields.aliases || '', @@ -109,13 +112,15 @@ API.v1.addRoute( { authRequired: true }, { async post() { - const [emoji, fields] = await getUploadFormData( + const emoji = await getUploadFormData( { request: this.request, }, - { field: 'emoji' }, + { field: 'emoji', sizeLimit: settings.get('FileUpload_MaxFileSize') }, ); + const { fields, fileBuffer, mimetype } = emoji; + if (!fields._id) { throw new Meteor.Error('The required "_id" query param is missing.'); } @@ -128,15 +133,15 @@ API.v1.addRoute( fields.previousName = emojiToUpdate.name; fields.previousExtension = emojiToUpdate.extension; fields.aliases = fields.aliases || ''; - const newFile = Boolean(emoji?.fileBuffer.length); + const newFile = Boolean(emoji && fileBuffer.length); if (fields.newFile) { - const isUploadable = await Media.isImage(emoji.fileBuffer); + const isUploadable = await Media.isImage(fileBuffer); if (!isUploadable) { throw new Meteor.Error('emoji-is-not-image', "Emoji file provided cannot be uploaded since it's not an image"); } - const [, extension] = emoji.mimetype.split('/'); + const [, extension] = mimetype.split('/'); fields.extension = extension; } else { fields.extension = emojiToUpdate.extension; @@ -144,7 +149,7 @@ API.v1.addRoute( Meteor.call('insertOrUpdateEmoji', { ...fields, newFile }); if (fields.newFile) { - Meteor.call('uploadEmojiCustom', emoji.fileBuffer, emoji.mimetype, { ...fields, newFile }); + Meteor.call('uploadEmojiCustom', fileBuffer, mimetype, { ...fields, newFile }); } return API.v1.success(); }, diff --git a/apps/meteor/app/api/server/v1/groups.js b/apps/meteor/app/api/server/v1/groups.js index 6593effe5b722..c435c2a9a7a37 100644 --- a/apps/meteor/app/api/server/v1/groups.js +++ b/apps/meteor/app/api/server/v1/groups.js @@ -1,7 +1,7 @@ -import _ from 'underscore'; import { Meteor } from 'meteor/meteor'; import { Match, check } from 'meteor/check'; import { Integrations, Messages as MessagesRaw, Uploads, Rooms as RoomsRaw, Subscriptions as SubscriptionsRaw } from '@rocket.chat/models'; +import { Team } from '@rocket.chat/core-services'; import { mountIntegrationQueryBasedOnPermissions } from '../../../integrations/server/lib/mountQueriesBasedOnPermission'; import { Subscriptions, Rooms, Messages, Users } from '../../../models/server'; @@ -14,7 +14,6 @@ import { } from '../../../authorization/server'; import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser'; import { API } from '../api'; -import { Team } from '../../../../server/sdk'; import { findUsersOfRoom } from '../../../../server/lib/findUsersOfRoom'; import { addUserToFileObj } from '../helpers/addUserToFileObj'; @@ -277,7 +276,7 @@ API.v1.addRoute( return API.v1.failure('Body param "name" is required'); } - if (this.bodyParams.members && !_.isArray(this.bodyParams.members)) { + if (this.bodyParams.members && !Array.isArray(this.bodyParams.members)) { return API.v1.failure('Body param "members" must be an array if provided'); } @@ -346,7 +345,7 @@ API.v1.addRoute( const ourQuery = Object.assign({}, query, { rid: findResult.rid }); - const { cursor, totalCount } = Uploads.findPaginated(ourQuery, { + const { cursor, totalCount } = Uploads.findPaginatedWithoutThumbs(ourQuery, { sort: sort || { name: 1 }, skip: offset, limit: count, diff --git a/apps/meteor/app/api/server/v1/im.ts b/apps/meteor/app/api/server/v1/im.ts index eb66fefd67237..53683c0dbe867 100644 --- a/apps/meteor/app/api/server/v1/im.ts +++ b/apps/meteor/app/api/server/v1/im.ts @@ -1,7 +1,7 @@ /** * Docs: https://github.com/RocketChat/developer-docs/blob/master/reference/api/rest-api/endpoints/team-collaboration-endpoints/im-endpoints */ -import type { IMessage, IRoom, ISubscription, IUpload } from '@rocket.chat/core-typings'; +import type { IMessage, IRoom, ISubscription } from '@rocket.chat/core-typings'; import { isDmDeleteProps, isDmFileProps, @@ -23,9 +23,6 @@ import { createDirectMessage } from '../../../../server/methods/createDirectMess import { addUserToFileObj } from '../helpers/addUserToFileObj'; import { settings } from '../../../settings/server'; -interface IImFilesObject extends IUpload { - userId: string; -} // TODO: Refact or remove type findDirectMessageRoomProps = @@ -218,7 +215,7 @@ API.v1.addRoute( const ourQuery = query ? { rid: room._id, ...query } : { rid: room._id }; - const { cursor, totalCount } = Uploads.findPaginated(ourQuery, { + const { cursor, totalCount } = Uploads.findPaginatedWithoutThumbs(ourQuery, { sort: sort || { name: 1 }, skip: offset, limit: count, diff --git a/apps/meteor/app/api/server/v1/instances.ts b/apps/meteor/app/api/server/v1/instances.ts index 204f1ceb9440e..e2b3b352580c0 100644 --- a/apps/meteor/app/api/server/v1/instances.ts +++ b/apps/meteor/app/api/server/v1/instances.ts @@ -1,9 +1,17 @@ -import type { IInstanceStatus } from '@rocket.chat/core-typings'; import { InstanceStatus } from '@rocket.chat/models'; -import { getInstanceConnection } from '../../../../server/stream/streamBroadcast'; +import { Instance as InstanceService } from '../../../../ee/server/sdk'; import { hasPermission } from '../../../authorization/server'; import { API } from '../api'; +import { isRunningMs } from '../../../../server/lib/isRunningMs'; + +const getMatrixInstances = (() => { + if (isRunningMs()) { + return () => []; + } + + return () => InstanceService.getInstances(); +})(); API.v1.addRoute( 'instances.get', @@ -14,20 +22,27 @@ API.v1.addRoute( return API.v1.unauthorized(); } - const instances = await InstanceStatus.find().toArray(); + const instanceRecords = await InstanceStatus.find().toArray(); + + const connections = await getMatrixInstances(); + + const result = instanceRecords.map((instanceRecord) => { + const connection = connections.find((c) => c.id === instanceRecord._id); + + return { + address: connection?.ipList[0], + currentStatus: { + connected: connection?.available || false, + lastHeartbeatTime: connection?.lastHeartbeatTime, + local: connection?.local, + }, + instanceRecord, + broadcastAuth: true, + }; + }); return API.v1.success({ - instances: instances.map((instance: IInstanceStatus) => { - const connection = getInstanceConnection(instance); - - if (connection) { - delete connection.instanceRecord; - } - return { - ...instance, - connection, - }; - }), + instances: result, }); }, }, diff --git a/apps/meteor/app/api/server/v1/invites.ts b/apps/meteor/app/api/server/v1/invites.ts index bf4f64be32b7b..5f4f484075cda 100644 --- a/apps/meteor/app/api/server/v1/invites.ts +++ b/apps/meteor/app/api/server/v1/invites.ts @@ -1,6 +1,11 @@ /* eslint-disable react-hooks/rules-of-hooks */ import type { IInvite } from '@rocket.chat/core-typings'; -import { isFindOrCreateInviteParams, isUseInviteTokenProps, isValidateInviteTokenProps } from '@rocket.chat/rest-typings'; +import { + isFindOrCreateInviteParams, + isUseInviteTokenProps, + isValidateInviteTokenProps, + isSendInvitationEmailParams, +} from '@rocket.chat/rest-typings'; import { API } from '../api'; import { findOrCreateInvite } from '../../../invites/server/functions/findOrCreateInvite'; @@ -8,6 +13,7 @@ import { removeInvite } from '../../../invites/server/functions/removeInvite'; import { listInvites } from '../../../invites/server/functions/listInvites'; import { useInviteToken } from '../../../invites/server/functions/useInviteToken'; import { validateInviteToken } from '../../../invites/server/functions/validateInviteToken'; +import { sendInvitationEmail } from '../../../invites/server/functions/sendInvitationEmail'; API.v1.addRoute( 'listInvites', @@ -82,3 +88,21 @@ API.v1.addRoute( }, }, ); + +API.v1.addRoute( + 'sendInvitationEmail', + { + authRequired: true, + validateParams: isSendInvitationEmailParams, + }, + { + async post() { + const { emails } = this.bodyParams; + try { + return API.v1.success({ success: Boolean(await sendInvitationEmail(this.userId, emails)) }); + } catch (e: any) { + return API.v1.failure({ error: e.message }); + } + }, + }, +); diff --git a/apps/meteor/app/api/server/v1/ldap.ts b/apps/meteor/app/api/server/v1/ldap.ts index aa4db389d848a..8d8bd3a2f3ec2 100644 --- a/apps/meteor/app/api/server/v1/ldap.ts +++ b/apps/meteor/app/api/server/v1/ldap.ts @@ -1,10 +1,10 @@ import { Match, check } from 'meteor/check'; +import { LDAP } from '@rocket.chat/core-services'; import { hasPermission } from '../../../authorization/server'; import { settings } from '../../../settings/server'; import { API } from '../api'; import { SystemLogger } from '../../../../server/lib/logger/system'; -import { LDAP } from '../../../../server/sdk'; API.v1.addRoute( 'ldap.testConnection', diff --git a/apps/meteor/app/api/server/v1/mailer.ts b/apps/meteor/app/api/server/v1/mailer.ts new file mode 100644 index 0000000000000..999fedc5e12b5 --- /dev/null +++ b/apps/meteor/app/api/server/v1/mailer.ts @@ -0,0 +1,42 @@ +import { isMailerProps, isMailerUnsubscribeProps } from '@rocket.chat/rest-typings'; + +import { API } from '../api'; +import { hasPermission } from '../../../authorization/server/functions/hasPermission'; + +API.v1.addRoute( + 'mailer', + { + authRequired: true, + validateParams: isMailerProps, + }, + { + async post() { + if (!hasPermission(this.userId, 'send-mail')) { + throw new Error('error-not-allowed'); + } + + const { from, subject, body, dryrun, query } = this.bodyParams; + + const result = Meteor.call('Mailer.sendMail', from, subject, body, Boolean(dryrun), query); + + return API.v1.success(result); + }, + }, +); + +API.v1.addRoute( + 'mailer.unsubscribe', + { + authRequired: true, + validateParams: isMailerUnsubscribeProps, + }, + { + async post() { + const { _id, createdAt } = this.bodyParams; + + const result = Meteor.call('Mailer:unsubscribe', _id, createdAt); + + return API.v1.success(result); + }, + }, +); diff --git a/apps/meteor/app/api/server/v1/misc.ts b/apps/meteor/app/api/server/v1/misc.ts index 5c7cf193f3a86..3efcdc58098d3 100644 --- a/apps/meteor/app/api/server/v1/misc.ts +++ b/apps/meteor/app/api/server/v1/misc.ts @@ -553,14 +553,13 @@ API.v1.addRoute( const result = Meteor.call(method, ...params); return API.v1.success(mountResult({ id, result })); - } catch (error) { - if (error instanceof Error) SystemLogger.error(`Exception while invoking method ${method}`, error.message); - else SystemLogger.error(`Exception while invoking method ${method}`, error); + } catch (err) { + SystemLogger.error({ msg: `Exception while invoking method ${method}`, err }); if (settings.get('Log_Level') === '2') { - Meteor._debug(`Exception while invoking method ${method}`, error); + Meteor._debug(`Exception while invoking method ${method}`, err); } - return API.v1.success(mountResult({ id, error })); + return API.v1.success(mountResult({ id, error: err })); } }, }, @@ -612,14 +611,13 @@ API.v1.addRoute( const result = Meteor.call(method, ...params); return API.v1.success(mountResult({ id, result })); - } catch (error) { - if (error instanceof Error) SystemLogger.error(`Exception while invoking method ${method}`, error.message); - else SystemLogger.error(`Exception while invoking method ${method}`, error); + } catch (err) { + SystemLogger.error({ msg: `Exception while invoking method ${method}`, err }); if (settings.get('Log_Level') === '2') { - Meteor._debug(`Exception while invoking method ${method}`, error); + Meteor._debug(`Exception while invoking method ${method}`, err); } - return API.v1.success(mountResult({ id, error })); + return API.v1.success(mountResult({ id, error: err })); } }, }, diff --git a/apps/meteor/app/api/server/v1/oauthapps.ts b/apps/meteor/app/api/server/v1/oauthapps.ts index a9d48884595d0..8c9809392e823 100644 --- a/apps/meteor/app/api/server/v1/oauthapps.ts +++ b/apps/meteor/app/api/server/v1/oauthapps.ts @@ -1,8 +1,10 @@ -import { isOauthAppsGetParams } from '@rocket.chat/rest-typings'; +import { isOauthAppsGetParams, isOauthAppsAddParams } from '@rocket.chat/rest-typings'; import { OAuthApps } from '@rocket.chat/models'; import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { API } from '../api'; +import { addOAuthApp } from '../../../oauth2-server-config/server/admin/functions/addOAuthApp'; +import { deprecationWarning } from '../helpers/deprecationWarning'; API.v1.addRoute( 'oauth-apps.list', @@ -22,22 +24,42 @@ API.v1.addRoute( API.v1.addRoute( 'oauth-apps.get', - { authRequired: true }, + { authRequired: true, validateParams: isOauthAppsGetParams }, { async get() { - if (!isOauthAppsGetParams(this.queryParams)) { - return API.v1.failure('At least one of the query parameters "clientId" or "appId" is required.'); - } - const oauthApp = await OAuthApps.findOneAuthAppByIdOrClientId(this.queryParams); if (!oauthApp) { return API.v1.failure('OAuth app not found.'); } - + if ('appId' in this.queryParams) { + return API.v1.success( + deprecationWarning({ + endpoint: 'oauth-apps.get', + warningMessage: ({ versionWillBeRemoved, endpoint }) => + `appId get parameter from "${endpoint}" is deprecated and will be removed after version ${versionWillBeRemoved}. Use _id instead.`, + response: { oauthApp }, + }), + ); + } return API.v1.success({ oauthApp, }); }, }, ); + +API.v1.addRoute( + 'oauth-apps.create', + { + authRequired: true, + validateParams: isOauthAppsAddParams, + }, + { + async post() { + const application = await addOAuthApp(this.bodyParams, this.userId); + + return API.v1.success({ application }); + }, + }, +); diff --git a/apps/meteor/app/api/server/v1/presence.ts b/apps/meteor/app/api/server/v1/presence.ts new file mode 100644 index 0000000000000..019137569f610 --- /dev/null +++ b/apps/meteor/app/api/server/v1/presence.ts @@ -0,0 +1,27 @@ +import { Presence } from '@rocket.chat/core-services'; + +import { API } from '../api'; + +API.v1.addRoute( + 'presence.getConnections', + { authRequired: true, permissionsRequired: ['manage-user-status'] }, + { + async get() { + const result = await Presence.getConnectionCount(); + + return API.v1.success(result); + }, + }, +); + +API.v1.addRoute( + 'presence.enableBroadcast', + { authRequired: true, permissionsRequired: ['manage-user-status'], twoFactorRequired: true }, + { + async post() { + await Presence.toggleBroadcast(true); + + return API.v1.success(); + }, + }, +); diff --git a/apps/meteor/app/api/server/v1/roles.ts b/apps/meteor/app/api/server/v1/roles.ts index 252421d1a9b61..b8fd4479a7056 100644 --- a/apps/meteor/app/api/server/v1/roles.ts +++ b/apps/meteor/app/api/server/v1/roles.ts @@ -1,26 +1,18 @@ import { Meteor } from 'meteor/meteor'; import { check, Match } from 'meteor/check'; -import { - isRoleAddUserToRoleProps, - isRoleCreateProps, - isRoleDeleteProps, - isRoleRemoveUserFromRoleProps, - isRoleUpdateProps, -} from '@rocket.chat/rest-typings'; +import { isRoleAddUserToRoleProps, isRoleDeleteProps, isRoleRemoveUserFromRoleProps } from '@rocket.chat/rest-typings'; import type { IRole } from '@rocket.chat/core-typings'; import { Roles } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; import { Users } from '../../../models/server'; import { API } from '../api'; import { hasRole } from '../../../authorization/server'; import { getUsersInRolePaginated } from '../../../authorization/server/functions/getUsersInRole'; import { settings } from '../../../settings/server/index'; -import { api } from '../../../../server/sdk/api'; import { apiDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; import { hasAnyRoleAsync } from '../../../authorization/server/functions/hasRole'; import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; -import { updateRole } from '../../../../server/lib/roles/updateRole'; -import { insertRole } from '../../../../server/lib/roles/insertRole'; API.v1.addRoute( 'roles.list', @@ -58,48 +50,6 @@ API.v1.addRoute( }, ); -API.v1.addRoute( - 'roles.create', - { authRequired: true }, - { - async post() { - if (!isRoleCreateProps(this.bodyParams)) { - throw new Meteor.Error('error-invalid-role-properties', 'The role properties are invalid.'); - } - - const userId = Meteor.userId(); - - if (!userId || !(await hasPermissionAsync(userId, 'access-permissions'))) { - throw new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed'); - } - - const { name, scope, description, mandatory2fa } = this.bodyParams; - - if (await Roles.findOneByIdOrName(name)) { - throw new Meteor.Error('error-duplicate-role-names-not-allowed', 'Role name already exists'); - } - - const roleData = { - description: description || '', - ...(mandatory2fa !== undefined && { mandatory2fa }), - name, - scope: scope || 'Users', - protected: false, - }; - - const options = { - broadcastUpdate: settings.get('UI_DisplayRoles'), - }; - - const role = insertRole(roleData, options); - - return API.v1.success({ - role, - }); - }, - }, -); - API.v1.addRoute( 'roles.addUserToRole', { authRequired: true }, @@ -190,42 +140,6 @@ API.v1.addRoute( }, ); -API.v1.addRoute( - 'roles.update', - { authRequired: true }, - { - async post() { - if (!isRoleUpdateProps(this.bodyParams)) { - throw new Meteor.Error('error-invalid-role-properties', 'The role properties are invalid.'); - } - - if (!(await hasPermissionAsync(this.userId, 'access-permissions'))) { - throw new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed'); - } - - const { roleId, name, scope, description, mandatory2fa } = this.bodyParams; - - const roleData = { - description: description || '', - ...(mandatory2fa !== undefined && { mandatory2fa }), - name, - scope: scope || 'Users', - protected: false, - }; - - const options = { - broadcastUpdate: settings.get('UI_DisplayRoles'), - }; - - const role = updateRole(roleId, roleData, options); - - return API.v1.success({ - role, - }); - }, - }, -); - API.v1.addRoute( 'roles.delete', { authRequired: true }, diff --git a/apps/meteor/app/api/server/v1/rooms.js b/apps/meteor/app/api/server/v1/rooms.js index ee059908eda04..fe4ccd088ca84 100644 --- a/apps/meteor/app/api/server/v1/rooms.js +++ b/apps/meteor/app/api/server/v1/rooms.js @@ -1,5 +1,6 @@ import { Meteor } from 'meteor/meteor'; import { Rooms as RoomsRaw } from '@rocket.chat/models'; +import { Media } from '@rocket.chat/core-services'; import { FileUpload } from '../../../file-upload'; import { Rooms, Messages } from '../../../models/server'; @@ -12,9 +13,8 @@ import { findRoomsAvailableForTeams, findChannelAndPrivateAutocompleteWithPagination, } from '../lib/rooms'; -import { sendFile, sendViaEmail } from '../../../../server/lib/channelExport'; +import * as dataExport from '../../../../server/lib/dataExport'; import { canAccessRoom, canAccessRoomId, hasPermission } from '../../../authorization/server'; -import { Media } from '../../../../server/sdk'; import { settings } from '../../../settings/server/index'; import { getUploadFormData } from '../lib/getUploadFormData'; @@ -81,39 +81,41 @@ API.v1.addRoute( 'rooms.upload/:rid', { authRequired: true }, { - post() { + async post() { if (!canAccessRoomId(this.urlParams.rid, this.userId)) { return API.v1.unauthorized(); } - const [file, fields] = Promise.await( - getUploadFormData( - { - request: this.request, - }, - { field: 'file' }, - ), + const file = await getUploadFormData( + { + request: this.request, + }, + { field: 'file', sizeLimit: settings.get('FileUpload_MaxFileSize') }, ); if (!file) { throw new Meteor.Error('invalid-field'); } + const { fields } = file; + let { fileBuffer } = file; + const details = { name: file.filename, - size: file.fileBuffer.length, + size: fileBuffer.length, type: file.mimetype, rid: this.urlParams.rid, userId: this.userId, }; const stripExif = settings.get('Message_Attachments_Strip_Exif'); - const fileStore = FileUpload.getStore('Uploads'); if (stripExif) { // No need to check mime. Library will ignore any files without exif/xmp tags (like BMP, ico, PDF, etc) - file.fileBuffer = Promise.await(Media.stripExifFromBuffer(file.fileBuffer)); + fileBuffer = await Media.stripExifFromBuffer(fileBuffer); } - const uploadedFile = fileStore.insertSync(details, file.fileBuffer); + + const fileStore = FileUpload.getStore('Uploads'); + const uploadedFile = await fileStore.insert(details, fileBuffer); uploadedFile.description = fields.description; @@ -540,7 +542,11 @@ API.v1.addRoute( dateTo = new Date(dateTo); dateTo.setDate(dateTo.getDate() + 1); - sendFile( + if (dateFrom > dateTo) { + throw new Meteor.Error('error-invalid-dates', 'From date cannot be after To date'); + } + + dataExport.sendFile( { rid, format, @@ -563,7 +569,7 @@ API.v1.addRoute( throw new Meteor.Error('error-invalid-messages'); } - const result = sendViaEmail( + const result = dataExport.sendViaEmail( { rid, toUsers, diff --git a/apps/meteor/app/api/server/v1/rooms.ts b/apps/meteor/app/api/server/v1/rooms.ts index 586a139dc36cd..5b920c8a77063 100644 --- a/apps/meteor/app/api/server/v1/rooms.ts +++ b/apps/meteor/app/api/server/v1/rooms.ts @@ -2,6 +2,7 @@ import { Meteor } from 'meteor/meteor'; import Ajv from 'ajv'; import { API } from '../api'; +import { eraseRoom } from '../../../../server/methods/eraseRoom'; // TO-DO: Replace this instance by only one Ajv import const ajv = new Ajv({ coerceTypes: true }); @@ -37,3 +38,23 @@ API.v1.addRoute( }, }, ); + +API.v1.addRoute( + 'rooms.delete', + { + authRequired: true, + }, + { + async post() { + const { roomId } = this.bodyParams; + + if (!roomId) { + return API.v1.failure("The 'roomId' param is required"); + } + + await eraseRoom(roomId, this.userId); + + return API.v1.success(); + }, + }, +); diff --git a/apps/meteor/app/api/server/v1/subscriptions.ts b/apps/meteor/app/api/server/v1/subscriptions.ts index b86c97f95ddd3..192476ccd6ce8 100644 --- a/apps/meteor/app/api/server/v1/subscriptions.ts +++ b/apps/meteor/app/api/server/v1/subscriptions.ts @@ -8,6 +8,7 @@ import { import { Subscriptions } from '@rocket.chat/models'; import { API } from '../api'; +import { readMessages } from '../../../../server/lib/readMessages'; API.v1.addRoute( 'subscriptions.get', @@ -63,12 +64,13 @@ API.v1.addRoute( ); /** - This API is suppose to mark any room as read. + This API is suppose to mark any room as read. Method: POST Route: api/v1/subscriptions.read Params: - rid: The rid of the room to be marked as read. + - roomId: Alternative for rid. */ API.v1.addRoute( 'subscriptions.read', @@ -77,8 +79,10 @@ API.v1.addRoute( validateParams: isSubscriptionsReadProps, }, { - post() { - Meteor.call('readMessages', this.bodyParams.rid); + async post() { + const { readThreads = false } = this.bodyParams; + const roomId = 'rid' in this.bodyParams ? this.bodyParams.rid : this.bodyParams.roomId; + await readMessages(roomId, this.userId, readThreads); return API.v1.success(); }, diff --git a/apps/meteor/app/api/server/v1/teams.ts b/apps/meteor/app/api/server/v1/teams.ts index 6d570ae49b0f2..0c1689c630e3a 100644 --- a/apps/meteor/app/api/server/v1/teams.ts +++ b/apps/meteor/app/api/server/v1/teams.ts @@ -13,11 +13,11 @@ import { } from '@rocket.chat/rest-typings'; import type { ITeam } from '@rocket.chat/core-typings'; import { TEAM_TYPE } from '@rocket.chat/core-typings'; +import { Team } from '@rocket.chat/core-services'; import { removeUserFromRoom } from '../../../lib/server/functions/removeUserFromRoom'; import { Rooms, Users } from '../../../models/server'; import { canAccessRoom, hasAtLeastOnePermission, hasPermission } from '../../../authorization/server'; -import { Team } from '../../../../server/sdk'; import { API } from '../api'; API.v1.addRoute( diff --git a/apps/meteor/app/api/server/v1/users.ts b/apps/meteor/app/api/server/v1/users.ts index 695fc204e0f9b..92a203b6943c3 100644 --- a/apps/meteor/app/api/server/v1/users.ts +++ b/apps/meteor/app/api/server/v1/users.ts @@ -11,13 +11,17 @@ import { isUsersUpdateParamsPOST, isUsersUpdateOwnBasicInfoParamsPOST, isUsersSetPreferencesParamsPOST, + isUsersCheckUsernameAvailabilityParamsGET, + isUsersSendConfirmationEmailParamsPOST, } from '@rocket.chat/rest-typings'; import { Meteor } from 'meteor/meteor'; import { Accounts } from 'meteor/accounts-base'; import { Match, check } from 'meteor/check'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import type { IExportOperation, IPersonalAccessToken, IUser } from '@rocket.chat/core-typings'; +import type { IExportOperation, ILoginToken, IPersonalAccessToken, IUser } from '@rocket.chat/core-typings'; import { Users as UsersRaw } from '@rocket.chat/models'; +import type { Filter } from 'mongodb'; +import { Team, api } from '@rocket.chat/core-services'; import { Users, Subscriptions } from '../../../models/server'; import { hasPermission } from '../../../authorization/server'; @@ -37,9 +41,7 @@ import { findUsersToAutocomplete, getInclusiveFields, getNonEmptyFields, getNonE import { getUserForCheck, emailCheck } from '../../../2fa/server/code'; import { resetUserE2EEncriptionKey } from '../../../../server/lib/resetUserE2EKey'; import { resetTOTP } from '../../../2fa/server/functions/resetTOTP'; -import { Team } from '../../../../server/sdk'; import { isValidQuery } from '../lib/isValidQuery'; -import { setUserStatus } from '../../../../imports/users-presence/server/activeUsers'; import { getURL } from '../../../utils/server'; import { getUploadFormData } from '../lib/getUploadFormData'; @@ -334,6 +336,20 @@ API.v1.addRoute( }, ); +API.v1.addRoute( + 'users.getAvatarSuggestion', + { + authRequired: true, + }, + { + async get() { + const suggestions = Meteor.call('getAvatarSuggestion'); + + return API.v1.success({ suggestions }); + }, + }, +); + API.v1.addRoute( 'users.update', { authRequired: true, twoFactorRequired: true, validateParams: isUsersUpdateParamsPOST }, @@ -424,7 +440,7 @@ API.v1.addRoute( language: user.language, }, }, - }, + } as Required>, }); }, }, @@ -461,19 +477,19 @@ API.v1.addRoute( return API.v1.success(); } - const [image, fields] = await getUploadFormData( + const image = await getUploadFormData( { request: this.request, }, - { - field: 'image', - }, + { field: 'image', sizeLimit: settings.get('FileUpload_MaxFileSize') }, ); if (!image) { return API.v1.failure("The 'image' param is required"); } + const { fields, fileBuffer, mimetype } = image; + const sentTheUserByFormData = fields.userId || fields.username; if (sentTheUserByFormData) { if (fields.userId) { @@ -492,7 +508,7 @@ API.v1.addRoute( } } - setUserAvatar(user, image.fileBuffer, image.mimetype, 'rest'); + setUserAvatar(user, fileBuffer, mimetype, 'rest'); return API.v1.success(); }, @@ -695,6 +711,10 @@ API.v1.addRoute( return API.v1.unauthorized(); } + if (settings.get('API_Apply_permission_view-outside-room_on_users-list') && !hasPermission(this.userId, 'view-outside-room')) { + return API.v1.unauthorized(); + } + const { offset, count } = this.getPaginationItems(); const { sort, fields, query } = this.parseJsonQuery(); @@ -714,6 +734,7 @@ API.v1.addRoute( inclusiveFieldsKeys.includes('username') && 'username.*', inclusiveFieldsKeys.includes('name') && 'name.*', inclusiveFieldsKeys.includes('type') && 'type.*', + inclusiveFieldsKeys.includes('customFields') && 'customFields.*', ].filter(Boolean) as string[], this.queryOperations, ) @@ -721,7 +742,15 @@ API.v1.addRoute( throw new Meteor.Error('error-invalid-query', isValidQuery.errors.join('\n')); } - const actualSort = sort?.name ? { nameInsensitive: sort.name, ...sort } : sort || { username: 1 }; + const actualSort = sort || { username: 1 }; + + if (sort?.status) { + actualSort.active = sort.status; + } + + if (sort?.name) { + actualSort.nameInsensitive = sort.name; + } const limit = count !== 0 @@ -799,8 +828,12 @@ API.v1.addRoute( return API.v1.failure('Username is already in use'); } + const { secret: secretURL, ...params } = this.bodyParams; // Register the user - const userId = Meteor.call('registerUser', this.bodyParams); + const userId = Meteor.call('registerUser', { + ...params, + ...(secretURL && { secretURL }), + }); // Now set their username Meteor.runAsUser(userId, () => Meteor.call('setUsername', this.bodyParams.username)); @@ -892,6 +925,22 @@ API.v1.addRoute( }, ); +API.v1.addRoute( + 'users.checkUsernameAvailability', + { + authRequired: true, + validateParams: isUsersCheckUsernameAvailabilityParamsGET, + }, + { + get() { + const { username } = this.queryParams; + const result = Meteor.call('checkUsernameAvailability', username); + + return API.v1.success({ result }); + }, + }, +); + API.v1.addRoute( 'users.generatePersonalAccessToken', { authRequired: true, twoFactorRequired: true }, @@ -935,16 +984,17 @@ API.v1.addRoute( const user = Users.getLoginTokensByUserId(this.userId).fetch()[0] as IUser | undefined; + const isPersonalAccessToken = (loginToken: ILoginToken | IPersonalAccessToken): loginToken is IPersonalAccessToken => + 'type' in loginToken && loginToken.type === 'personalAccessToken'; + return API.v1.success({ tokens: - user?.services?.resume?.loginTokens - ?.filter((loginToken: any) => loginToken.type === 'personalAccessToken') - .map((loginToken: IPersonalAccessToken) => ({ - name: loginToken.name, - createdAt: loginToken.createdAt.toISOString(), - lastTokenPart: loginToken.lastTokenPart, - bypassTwoFactor: Boolean(loginToken.bypassTwoFactor), - })) || [], + user?.services?.resume?.loginTokens?.filter(isPersonalAccessToken).map((loginToken) => ({ + name: loginToken.name, + createdAt: loginToken.createdAt.toISOString(), + lastTokenPart: loginToken.lastTokenPart, + bypassTwoFactor: Boolean(loginToken.bypassTwoFactor), + })) || [], }); }, }, @@ -1014,11 +1064,37 @@ API.v1.addRoute('users.2fa.sendEmailCode', { }, }); +API.v1.addRoute( + 'users.sendConfirmationEmail', + { + authRequired: true, + validateParams: isUsersSendConfirmationEmailParamsPOST, + }, + { + post() { + const { email } = this.bodyParams; + + if (Meteor.call('sendConfirmationEmail', email)) { + return API.v1.success(); + } + return API.v1.failure(); + }, + }, +); + API.v1.addRoute( 'users.presence', { authRequired: true }, { get() { + // if presence broadcast is disabled, return an empty array (all users are "offline") + if (settings.get('Presence_broadcast_disabled')) { + return API.v1.success({ + users: [], + full: true, + }); + } + const { from, ids } = this.queryParams; const options = { @@ -1098,12 +1174,12 @@ API.v1.addRoute( const token = me.services?.resume?.loginTokens?.find((token) => token.hashedToken === hashedToken); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const tokenExpires = new Date(token!.when.getTime() + settings.get('Accounts_LoginExpiration') * 1000); + const tokenExpires = + (token && 'when' in token && new Date(token.when.getTime() + settings.get('Accounts_LoginExpiration') * 1000)) || undefined; return API.v1.success({ token: xAuthToken, - tokenExpires: tokenExpires.toISOString() || '', + tokenExpires: tokenExpires?.toISOString() || '', }); }, }, @@ -1114,11 +1190,22 @@ API.v1.addRoute( { authRequired: true, validateParams: isUsersAutocompleteProps }, { async get() { - const { selector } = this.queryParams; + const { selector: selectorRaw } = this.queryParams; + + const selector: { exceptions: Required['username'][]; conditions: Filter; term: string } = JSON.parse(selectorRaw); + + try { + if (selector?.conditions && !isValidQuery(selector.conditions, ['*'], ['$or', '$and'])) { + throw new Error('error-invalid-query'); + } + } catch (e) { + return API.v1.failure(e); + } + return API.v1.success( await findUsersToAutocomplete({ uid: this.userId, - selector: JSON.parse(selector), + selector, }), ); }, @@ -1330,7 +1417,11 @@ API.v1.addRoute( }, }); - setUserStatus(user, status); + const { _id, username, statusText, roles, name } = user; + api.broadcast('presence.status', { + user: { status, _id, username, statusText, roles, name }, + previousStatus: user.status, + }); } else { throw new Meteor.Error('error-invalid-status', 'Valid status types include online, away, offline, and busy.', { method: 'users.setStatus', diff --git a/apps/meteor/app/api/server/v1/videoConference.ts b/apps/meteor/app/api/server/v1/videoConference.ts index f471fcaebe404..f945a49b497dc 100644 --- a/apps/meteor/app/api/server/v1/videoConference.ts +++ b/apps/meteor/app/api/server/v1/videoConference.ts @@ -6,11 +6,11 @@ import { isVideoConfInfoProps, isVideoConfListProps, } from '@rocket.chat/rest-typings'; +import { VideoConf } from '@rocket.chat/core-services'; import { API } from '../api'; import { canAccessRoomIdAsync } from '../../../authorization/server/functions/canAccessRoom'; import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; -import { VideoConf } from '../../../../server/sdk'; import { videoConfProviders } from '../../../../server/lib/videoConfProviders'; import { availabilityErrors } from '../../../../lib/videoConference/constants'; @@ -114,7 +114,7 @@ API.v1.addRoute( API.v1.addRoute( 'video-conference.info', - { authRequired: true, validateParams: isVideoConfInfoProps, rateLimiterOptions: { numRequestsAllowed: 3, intervalTimeInMS: 1000 } }, + { authRequired: true, validateParams: isVideoConfInfoProps, rateLimiterOptions: { numRequestsAllowed: 15, intervalTimeInMS: 3000 } }, { async get() { const { callId } = this.queryParams; diff --git a/apps/meteor/app/api/server/v1/voip/events.ts b/apps/meteor/app/api/server/v1/voip/events.ts index 5b3d61a46f6d7..5482d62041b1e 100644 --- a/apps/meteor/app/api/server/v1/voip/events.ts +++ b/apps/meteor/app/api/server/v1/voip/events.ts @@ -1,14 +1,14 @@ import { Match, check } from 'meteor/check'; import { VoipClientEvents } from '@rocket.chat/core-typings'; import { VoipRoom } from '@rocket.chat/models'; +import { LivechatVoip } from '@rocket.chat/core-services'; import { API } from '../../api'; -import { LivechatVoip } from '../../../../../server/sdk'; import { canAccessRoom } from '../../../../authorization/server'; API.v1.addRoute( 'voip/events', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['view-l-room'] }, { async post() { check(this.requestParams(), { diff --git a/apps/meteor/app/api/server/v1/voip/extensions.ts b/apps/meteor/app/api/server/v1/voip/extensions.ts index 598a8bce662eb..a3c29e99d1f5c 100644 --- a/apps/meteor/app/api/server/v1/voip/extensions.ts +++ b/apps/meteor/app/api/server/v1/voip/extensions.ts @@ -1,9 +1,9 @@ import { Match, check } from 'meteor/check'; import type { IVoipExtensionBase } from '@rocket.chat/core-typings'; import { Users } from '@rocket.chat/models'; +import { Voip } from '@rocket.chat/core-services'; import { API } from '../../api'; -import { Voip } from '../../../../../server/sdk'; import { generateJWT } from '../../../../utils/server/lib/JWTHelper'; import { settings } from '../../../../settings/server'; import { logger } from './logger'; diff --git a/apps/meteor/app/api/server/v1/voip/omnichannel.ts b/apps/meteor/app/api/server/v1/voip/omnichannel.ts index 9e7fe2e006638..16e90f7be616f 100644 --- a/apps/meteor/app/api/server/v1/voip/omnichannel.ts +++ b/apps/meteor/app/api/server/v1/voip/omnichannel.ts @@ -1,10 +1,9 @@ import { Match, check } from 'meteor/check'; import type { IUser, IVoipExtensionWithAgentInfo } from '@rocket.chat/core-typings'; import { Users } from '@rocket.chat/models'; +import { LivechatVoip } from '@rocket.chat/core-services'; import { API } from '../../api'; -import { hasPermission } from '../../../../authorization/server/index'; -import { LivechatVoip } from '../../../../../server/sdk'; import { logger } from './logger'; function filter( @@ -31,12 +30,9 @@ const isUserIdndTypeParams = (p: any): p is { userId: string; type: 'free' | 'al API.v1.addRoute( 'omnichannel/agent/extension', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['manage-agent-extension-association'] }, { async post() { - if (!hasPermission(this.userId, 'manage-agent-extension-association')) { - return API.v1.unauthorized(); - } check( this.bodyParams, Match.OneOf( @@ -94,13 +90,16 @@ API.v1.addRoute( API.v1.addRoute( 'omnichannel/agent/extension/:username', - { authRequired: true }, + { + authRequired: true, + permissionsRequired: { + GET: ['view-agent-extension-association'], + DELETE: ['manage-agent-extension-association'], + }, + }, { // Get the extensions associated with the agent passed as request params. async get() { - if (!hasPermission(this.userId, 'view-agent-extension-association')) { - return API.v1.unauthorized(); - } check( this.urlParams, Match.ObjectIncluding({ @@ -128,9 +127,6 @@ API.v1.addRoute( }, async delete() { - if (!hasPermission(this.userId, 'manage-agent-extension-association')) { - return API.v1.unauthorized(); - } check( this.urlParams, Match.ObjectIncluding({ diff --git a/apps/meteor/app/api/server/v1/voip/queues.ts b/apps/meteor/app/api/server/v1/voip/queues.ts index 803418f06c095..ce82150228f87 100644 --- a/apps/meteor/app/api/server/v1/voip/queues.ts +++ b/apps/meteor/app/api/server/v1/voip/queues.ts @@ -1,12 +1,12 @@ import { Match, check } from 'meteor/check'; import type { IVoipConnectorResult, IQueueSummary, IQueueMembershipDetails, IQueueMembershipSubscription } from '@rocket.chat/core-typings'; +import { Voip } from '@rocket.chat/core-services'; -import { Voip } from '../../../../../server/sdk'; import { API } from '../../api'; API.v1.addRoute( 'voip/queues.getSummary', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['inbound-voip-calls'] }, { async get() { const queueSummary = await Voip.getQueueSummary(); @@ -17,7 +17,7 @@ API.v1.addRoute( API.v1.addRoute( 'voip/queues.getQueuedCallsForThisExtension', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['inbound-voip-calls'] }, { async get() { check( @@ -34,7 +34,7 @@ API.v1.addRoute( API.v1.addRoute( 'voip/queues.getMembershipSubscription', - { authRequired: true }, + { authRequired: true, permissionsRequired: ['inbound-voip-calls'] }, { async get() { check( diff --git a/apps/meteor/app/api/server/v1/voip/rooms.ts b/apps/meteor/app/api/server/v1/voip/rooms.ts index 1798591f57dbf..9feb74ead33cd 100644 --- a/apps/meteor/app/api/server/v1/voip/rooms.ts +++ b/apps/meteor/app/api/server/v1/voip/rooms.ts @@ -2,9 +2,9 @@ import { Random } from 'meteor/random'; import type { ILivechatAgent, IVoipRoom } from '@rocket.chat/core-typings'; import { isVoipRoomProps, isVoipRoomsProps, isVoipRoomCloseProps } from '@rocket.chat/rest-typings'; import { VoipRoom, LivechatVisitors, Users } from '@rocket.chat/models'; +import { LivechatVoip } from '@rocket.chat/core-services'; import { API } from '../../api'; -import { LivechatVoip } from '../../../../../server/sdk'; import { hasPermission } from '../../../../authorization/server'; import { typedJsonParse } from '../../../../../lib/typedJSONParse'; diff --git a/apps/meteor/app/api/server/v1/voip/server-connection.ts b/apps/meteor/app/api/server/v1/voip/server-connection.ts index d784a87e95f18..e19e897b4918e 100644 --- a/apps/meteor/app/api/server/v1/voip/server-connection.ts +++ b/apps/meteor/app/api/server/v1/voip/server-connection.ts @@ -1,7 +1,7 @@ import { Match, check } from 'meteor/check'; +import { Voip } from '@rocket.chat/core-services'; import { API } from '../../api'; -import { Voip } from '../../../../../server/sdk'; API.v1.addRoute( 'voip/managementServer/checkConnection', diff --git a/apps/meteor/app/apple/lib/handleIdentityToken.ts b/apps/meteor/app/apple/lib/handleIdentityToken.ts new file mode 100644 index 0000000000000..528c8f4168314 --- /dev/null +++ b/apps/meteor/app/apple/lib/handleIdentityToken.ts @@ -0,0 +1,45 @@ +import { KJUR } from 'jsrsasign'; +import { HTTP } from 'meteor/http'; +import NodeRSA from 'node-rsa'; + +function isValidAppleJWT(identityToken: string, header: any): boolean { + const applePublicKeys = HTTP.get('https://appleid.apple.com/auth/keys').data.keys as any; + const { kid } = header; + + const key = applePublicKeys.find((k: any) => k.kid === kid); + + const pubKey = new NodeRSA(); + pubKey.importKey({ n: Buffer.from(key.n, 'base64'), e: Buffer.from(key.e, 'base64') }, 'components-public'); + const userKey = pubKey.exportKey('public'); + + try { + return KJUR.jws.JWS.verify(identityToken, userKey, ['RS256']); + } catch { + return false; + } +} + +export function handleIdentityToken(identityToken: string): { id: string; email: string; name: string } { + const decodedToken = KJUR.jws.JWS.parse(identityToken); + + if (!isValidAppleJWT(identityToken, decodedToken.headerObj)) { + throw new Error('identityToken is not a valid JWT'); + } + + if (!decodedToken.payloadObj) { + throw new Error('identityToken does not have a payload'); + } + + const { iss, sub, email } = decodedToken.payloadObj as any; + if (!iss) { + throw new Error('Insufficient data in auth response token'); + } + + const serviceData = { + id: sub, + email, + name: '', + }; + + return serviceData; +} diff --git a/apps/meteor/app/apple/server/AppleCustomOAuth.ts b/apps/meteor/app/apple/server/AppleCustomOAuth.ts index 01c5027a44fbe..706322368815f 100644 --- a/apps/meteor/app/apple/server/AppleCustomOAuth.ts +++ b/apps/meteor/app/apple/server/AppleCustomOAuth.ts @@ -1,72 +1,35 @@ import { Accounts } from 'meteor/accounts-base'; -import { HTTP } from 'meteor/http'; -import NodeRSA from 'node-rsa'; -import { KJUR } from 'jsrsasign'; +import { MeteorError } from '@rocket.chat/core-services'; import { CustomOAuth } from '../../custom-oauth/server/custom_oauth_server'; -import { MeteorError } from '../../../server/sdk/errors'; - -const isValidAppleJWT = (identityToken: string, header: any): any => { - const applePublicKeys = HTTP.get('https://appleid.apple.com/auth/keys').data.keys as any; - const { kid } = header; - - const key = applePublicKeys.find((k: any) => k.kid === kid); - - const pubKey = new NodeRSA(); - pubKey.importKey({ n: Buffer.from(key.n, 'base64'), e: Buffer.from(key.e, 'base64') }, 'components-public'); - const userKey = pubKey.exportKey('public'); - - try { - return KJUR.jws.JWS.verify(identityToken, userKey, ['RS256']); - } catch { - return false; - } -}; +import { handleIdentityToken } from '../lib/handleIdentityToken'; export class AppleCustomOAuth extends CustomOAuth { getIdentity(_accessToken: string, query: Record): any { const { id_token: identityToken, user: userStr = '' } = query; - let user = {} as any; + let usrObj = {} as any; try { - user = JSON.parse(userStr); + usrObj = JSON.parse(userStr); } catch (e) { // ignore } - const decodedToken = KJUR.jws.JWS.parse(identityToken); + try { + const serviceData = handleIdentityToken(identityToken); - if (!isValidAppleJWT(identityToken, decodedToken.headerObj)) { - return { - type: 'apple', - error: new MeteorError(Accounts.LoginCancelledError.numericError, 'identityToken is a invalid JWT'), - }; - } + if (usrObj?.name) { + serviceData.name = `${usrObj.name.firstName}${usrObj.name.middleName ? ` ${usrObj.name.middleName}` : ''}${ + usrObj.name.lastName ? ` ${usrObj.name.lastName}` : '' + }`; + } - const { iss, sub, email } = decodedToken.payloadObj as any; - if (!iss) { + return serviceData; + } catch (error: any) { return { type: 'apple', - error: new MeteorError(Accounts.LoginCancelledError.numericError, 'Insufficient data in auth response token'), + error: new MeteorError(Accounts.LoginCancelledError.numericError, error.message), }; } - - const serviceData = { - id: sub, - email, - name: '', - }; - - if (email) { - serviceData.email = email; - } - - if (user?.name) { - serviceData.name = `${user.name.firstName}${user.name.middleName ? ` ${user.name.middleName}` : ''}${ - user.name.lastName ? ` ${user.name.lastName}` : '' - }`; - } - - return serviceData; } } diff --git a/apps/meteor/app/apple/server/appleOauthRegisterService.ts b/apps/meteor/app/apple/server/appleOauthRegisterService.ts index c7f01a6809171..728daf40105e1 100644 --- a/apps/meteor/app/apple/server/appleOauthRegisterService.ts +++ b/apps/meteor/app/apple/server/appleOauthRegisterService.ts @@ -34,6 +34,22 @@ settings.watchMultiple( }); } + // if everything is empty but Apple login is enabled, don't show the login button + if (!clientId && !serverSecret && !iss && !kid) { + ServiceConfiguration.configurations.upsert( + { + service: 'apple', + }, + { + $set: { + showButton: false, + enabled: settings.get('Accounts_OAuth_Apple'), + }, + }, + ); + return; + } + const HEADER = { kid, alg: 'ES256', @@ -67,7 +83,6 @@ settings.watchMultiple( enabled: settings.get('Accounts_OAuth_Apple'), loginStyle: 'popup', clientId, - buttonLabelText: 'Sign in with Apple', buttonColor: '#000', buttonLabelColor: '#FFF', }, diff --git a/apps/meteor/app/apple/server/index.ts b/apps/meteor/app/apple/server/index.ts index d4b3d92958ad6..5643ad67a54e2 100644 --- a/apps/meteor/app/apple/server/index.ts +++ b/apps/meteor/app/apple/server/index.ts @@ -1 +1,2 @@ import './appleOauthRegisterService'; +import './loginHandler'; diff --git a/apps/meteor/app/apple/server/loginHandler.ts b/apps/meteor/app/apple/server/loginHandler.ts new file mode 100644 index 0000000000000..e69ea39b34c02 --- /dev/null +++ b/apps/meteor/app/apple/server/loginHandler.ts @@ -0,0 +1,49 @@ +import { Meteor } from 'meteor/meteor'; +import { Accounts } from 'meteor/accounts-base'; + +import { handleIdentityToken } from '../lib/handleIdentityToken'; +import { settings } from '../../settings/server'; + +Accounts.registerLoginHandler('apple', (loginRequest) => { + if (!loginRequest.identityToken) { + return; + } + + if (!settings.get('Accounts_OAuth_Apple')) { + return; + } + + const { identityToken, fullName, email } = loginRequest; + + try { + const serviceData = handleIdentityToken(identityToken); + + if (!serviceData.email && email) { + serviceData.email = email; + } + + const profile: { name?: string } = {}; + + const { givenName, familyName } = fullName; + if (givenName && familyName) { + profile.name = `${givenName} ${familyName}`; + } + + const result = Accounts.updateOrCreateUserFromExternalService('apple', serviceData, { profile }); + + // Ensure processing succeeded + if (result === undefined || result.userId === undefined) { + return { + type: 'apple', + error: new Meteor.Error(Accounts.LoginCancelledError.numericError, 'User creation failed from Apple response token'), + }; + } + + return result; + } catch (error: any) { + return { + type: 'apple', + error: new Meteor.Error(Accounts.LoginCancelledError.numericError, error.message), + }; + } +}); diff --git a/apps/meteor/app/apps/client/communication/websockets.js b/apps/meteor/app/apps/client/communication/websockets.js deleted file mode 100644 index 67f03e0df1eed..0000000000000 --- a/apps/meteor/app/apps/client/communication/websockets.js +++ /dev/null @@ -1,63 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Emitter } from '@rocket.chat/emitter'; - -import { slashCommands, APIClient } from '../../../utils'; -import { CachedCollectionManager } from '../../../ui-cached-collection'; -import { loadButtons } from '../../../ui-message/client/ActionButtonSyncer'; - -export const AppEvents = Object.freeze({ - APP_ADDED: 'app/added', - APP_REMOVED: 'app/removed', - APP_UPDATED: 'app/updated', - APP_STATUS_CHANGE: 'app/statusUpdate', - APP_SETTING_UPDATED: 'app/settingUpdated', - COMMAND_ADDED: 'command/added', - COMMAND_DISABLED: 'command/disabled', - COMMAND_UPDATED: 'command/updated', - COMMAND_REMOVED: 'command/removed', - ACTIONS_CHANGED: 'actions/changed', -}); - -export class AppWebsocketReceiver extends Emitter { - constructor() { - super(); - - this.streamer = new Meteor.Streamer('apps'); - - CachedCollectionManager.onLogin(() => { - this.listenStreamerEvents(); - }); - } - - listenStreamerEvents() { - Object.values(AppEvents).forEach((eventName) => { - this.streamer.on(eventName, this.emit.bind(this, eventName)); - }); - - this.streamer.on(AppEvents.COMMAND_ADDED, this.onCommandAddedOrUpdated); - this.streamer.on(AppEvents.COMMAND_UPDATED, this.onCommandAddedOrUpdated); - this.streamer.on(AppEvents.COMMAND_REMOVED, this.onCommandRemovedOrDisabled); - this.streamer.on(AppEvents.COMMAND_DISABLED, this.onCommandRemovedOrDisabled); - this.streamer.on(AppEvents.ACTIONS_CHANGED, this.onActionsChanged); - } - - registerListener(event, listener) { - this.on(event, listener); - } - - unregisterListener(event, listener) { - this.off(event, listener); - } - - onCommandAddedOrUpdated = (command) => { - APIClient.get('/v1/commands.get', { command }).then((result) => { - slashCommands.add(result.command); - }); - }; - - onCommandRemovedOrDisabled = (command) => { - delete slashCommands.commands[command]; - }; - - onActionsChanged = () => loadButtons(); -} diff --git a/apps/meteor/app/apps/client/gameCenter/gameCenter.html b/apps/meteor/app/apps/client/gameCenter/gameCenter.html deleted file mode 100644 index 6e6f0e9809595..0000000000000 --- a/apps/meteor/app/apps/client/gameCenter/gameCenter.html +++ /dev/null @@ -1,69 +0,0 @@ - diff --git a/apps/meteor/app/apps/client/gameCenter/gameCenter.js b/apps/meteor/app/apps/client/gameCenter/gameCenter.js deleted file mode 100644 index 787f315de39ee..0000000000000 --- a/apps/meteor/app/apps/client/gameCenter/gameCenter.js +++ /dev/null @@ -1,111 +0,0 @@ -import { Template } from 'meteor/templating'; -import { ReactiveVar } from 'meteor/reactive-var'; - -import { modal } from '../../../ui-utils/client'; -import { APIClient, t } from '../../../utils/client'; -import { dispatchToastMessage } from '../../../../client/lib/toast'; -import './gameCenter.html'; - -const getExternalComponents = async (instance) => { - try { - const { externalComponents } = await APIClient.get('/apps/externalComponents'); - instance.games.set(externalComponents); - } catch (error) { - dispatchToastMessage({ type: 'error', message: error }); - } - - instance.isLoading.set(false); - instance.ready.set(true); -}; - -const openGame = (gameManifestInfo) => { - const instance = Template.instance(); - const { location = 'MODAL' } = gameManifestInfo; - - if (location === 'CONTEXTUAL_BAR') { - instance.gameManifestInfo.set(gameManifestInfo); - } else if (location === 'MODAL') { - modal.open({ - allowOutsideClick: false, - data: { - game: gameManifestInfo, - }, - template: 'GameContainer', - type: 'rc-game', - }); - } -}; - -Template.GameCenter.helpers({ - isReady() { - if (Template.instance().ready != null) { - return Template.instance().ready.get(); - } - return false; - }, - games() { - return Template.instance().games.get(); - }, - isLoading() { - return Template.instance().isLoading.get(); - }, - onTableScroll() { - const instance = Template.instance(); - if (instance.loading || instance.end.get()) { - return; - } - return function (currentTarget) { - if (currentTarget.offsetHeight + currentTarget.scrollTop >= currentTarget.scrollHeight - 100) { - return instance.page.set(instance.page.get() + 1); - } - }; - }, - showGame() { - return Template.instance().gameManifestInfo.get(); - }, - gameContainerOptions() { - const { gameManifestInfo, clearGameManifestInfo } = Template.instance(); - - return { - game: gameManifestInfo.get(), - showBackButton: true, - clearGameManifestInfo, - }; - }, -}); - -Template.GameCenter.onCreated(function () { - this.ready = new ReactiveVar(false); - this.games = new ReactiveVar([]); - this.isLoading = new ReactiveVar(true); - this.page = new ReactiveVar(0); - this.end = new ReactiveVar(false); - - this.gameManifestInfo = new ReactiveVar(null); - - this.clearGameManifestInfo = () => { - this.gameManifestInfo.set(null); - }; - - getExternalComponents(this); -}); - -Template.GameCenter.events({ - 'click .rc-game-center__game'() { - const gameManifestInfo = this; - - openGame(gameManifestInfo); - }, - 'click .js-invite'(event) { - event.stopPropagation(); - modal.open({ - title: t('Apps_Game_Center_Invite_Friends'), - content: 'InvitePlayers', - data: this, - confirmOnEnter: false, - showCancelButton: false, - showConfirmButton: false, - html: false, - }); - }, -}); diff --git a/apps/meteor/app/apps/client/gameCenter/gameContainer.html b/apps/meteor/app/apps/client/gameCenter/gameContainer.html deleted file mode 100644 index 26ccc33a7060f..0000000000000 --- a/apps/meteor/app/apps/client/gameCenter/gameContainer.html +++ /dev/null @@ -1,33 +0,0 @@ - diff --git a/apps/meteor/app/apps/client/gameCenter/gameContainer.js b/apps/meteor/app/apps/client/gameCenter/gameContainer.js deleted file mode 100644 index d954c06d1c25a..0000000000000 --- a/apps/meteor/app/apps/client/gameCenter/gameContainer.js +++ /dev/null @@ -1,78 +0,0 @@ -import { Template } from 'meteor/templating'; - -import { modal } from '../../../ui-utils/client'; -import { Apps } from '../orchestrator'; -import { APIClient } from '../../../utils/client'; - -import './gameContainer.html'; - -const getExternalComponent = async () => { - const { - data: { game: externalComponent }, - } = Template.instance(); - const realAppClientUIHost = Apps.getUIHost(); - const currentUser = await realAppClientUIHost.getClientUserInfo(); - const currentRoom = await realAppClientUIHost.getClientRoomInfo(); - - externalComponent.state = { - currentUser, - currentRoom, - }; - - return externalComponent; -}; - -Template.GameContainer.helpers({ - isContextualBar() { - const { - data: { game }, - } = Template.instance(); - const { location } = game; - - return location === 'CONTEXTUAL_BAR'; - }, - isModal() { - const { - data: { game }, - } = Template.instance(); - const { location } = game; - - return location === 'MODAL'; - }, -}); - -Template.GameContainer.events({ - 'click .rc-game__close'() { - const { - data: { clearGameManifestInfo }, - } = Template.instance(); - - clearGameManifestInfo(); - modal.cancel(); - }, - 'click .js-back'() { - const { - data: { clearGameManifestInfo }, - } = Template.instance(); - - clearGameManifestInfo(); - }, -}); - -Template.GameContainer.onCreated(async () => { - const externalComponent = await getExternalComponent(); - - APIClient.post('/apps/externalComponentEvent', { - event: 'IPostExternalComponentOpened', - externalComponent, - }); -}); - -Template.GameContainer.onDestroyed(async () => { - const externalComponent = await getExternalComponent(); - - APIClient.post('/apps/externalComponentEvent', { - event: 'IPostExternalComponentClosed', - externalComponent, - }); -}); diff --git a/apps/meteor/app/apps/client/gameCenter/invitePlayers.html b/apps/meteor/app/apps/client/gameCenter/invitePlayers.html deleted file mode 100644 index a74e14ce30bfe..0000000000000 --- a/apps/meteor/app/apps/client/gameCenter/invitePlayers.html +++ /dev/null @@ -1,54 +0,0 @@ - - - diff --git a/apps/meteor/app/apps/client/gameCenter/invitePlayers.js b/apps/meteor/app/apps/client/gameCenter/invitePlayers.js deleted file mode 100644 index a6e0e1ac61105..0000000000000 --- a/apps/meteor/app/apps/client/gameCenter/invitePlayers.js +++ /dev/null @@ -1,233 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Random } from 'meteor/random'; -import { Template } from 'meteor/templating'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { Blaze } from 'meteor/blaze'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { Tracker } from 'meteor/tracker'; -import { Session } from 'meteor/session'; - -import { AutoComplete } from '../../../meteor-autocomplete/client'; -import { roomCoordinator } from '../../../../client/lib/rooms/roomCoordinator'; -import { ChatRoom } from '../../../models/client'; -import { modal } from '../../../ui-utils/client'; -import { callWithErrorHandling } from '../../../../client/lib/utils/callWithErrorHandling'; - -import './invitePlayers.html'; - -Template.InvitePlayers.helpers({ - onSelectUser() { - return Template.instance().onSelectUser; - }, - selectedUsers() { - const myUsername = Meteor.user().username; - const { message } = this; - const users = Template.instance() - .selectedUsers.get() - .map((e) => e); - if (message) { - users.unshift(message.u); - } - return users.filter(({ username }) => myUsername !== username); - }, - onClickTagUser() { - return Template.instance().onClickTagUser; - }, - deleteLastItemUser() { - return Template.instance().deleteLastItemUser; - }, - onClickTagRoom() { - return Template.instance().onClickTagRoom; - }, - deleteLastItemRoom() { - return Template.instance().deleteLastItemRoom; - }, - selectedRoom() { - return Template.instance().selectedRoom.get(); - }, - onSelectRoom() { - return Template.instance().onSelectRoom; - }, - roomCollection() { - return ChatRoom; - }, - roomSelector() { - return (expression) => ({ name: { $regex: `.*${expression}.*` } }); - }, - roomModifier() { - return (filter, text = '') => { - const f = filter.get(); - return `#${f.length === 0 ? text : text.replace(new RegExp(filter.get(), 'i'), (part) => `${part}`)}`; - }; - }, - userModifier() { - return (filter, text = '') => { - const f = filter.get(); - return `@${f.length === 0 ? text : text.replace(new RegExp(filter.get(), 'i'), (part) => `${part}`)}`; - }; - }, - nameSuggestion() { - return Template.instance().discussionName.get(); - }, -}); - -Template.InvitePlayers.events({ - async 'submit #invite-players, click .js-invite-players'(e, instance) { - e.preventDefault(); - - const { - data: { name }, - } = instance; - const users = instance.selectedUsers.get().map(({ username }) => username); - const privateGroupName = `${name.replace(/\s/g, '-')}-${Random.id(10)}`; - - try { - const result = await callWithErrorHandling('createPrivateGroup', privateGroupName, users); - - roomCoordinator.openRouteLink(result.t, result); - - // This ensures the message is only sent after the - // user has been redirected to the new room, preventing a - // weird bug that made the message appear as unsent until - // the screen gets refreshed - Tracker.autorun((c) => { - if (Session.get('openedRoom') !== result.rid) { - return; - } - - callWithErrorHandling('sendMessage', { - _id: Random.id(), - rid: result.rid, - msg: TAPi18n.__('Apps_Game_Center_Play_Game_Together', { name }), - }); - - c.stop(); - }); - - modal.close(); - } catch (err) { - console.warn(err); - } - }, -}); - -Template.InvitePlayers.onCreated(function () { - this.selectedUsers = new ReactiveVar([]); - this.onSelectUser = ({ item: user }) => { - if (user.username === Meteor.user().username) { - return; - } - const users = this.selectedUsers.get(); - if (!users.find((u) => user.username === u.username)) { - this.selectedUsers.set([...users, user]); - } - }; - this.onClickTagUser = ({ username }) => { - this.selectedUsers.set(this.selectedUsers.get().filter((user) => user.username !== username)); - }; - this.deleteLastItemUser = () => { - const arr = this.selectedUsers.get(); - arr.pop(); - this.selectedUsers.set(arr); - }; -}); - -Template.SearchInvitePlayers.helpers({ - list() { - return this.list; - }, - items() { - return Template.instance().ac.filteredList(); - }, - config() { - const { filter } = Template.instance(); - const { noMatchTemplate, templateItem, modifier } = Template.instance().data; - return { - filter: filter.get(), - template_item: templateItem, - noMatchTemplate, - modifier(text) { - return modifier(filter, text); - }, - }; - }, - autocomplete(key) { - const instance = Template.instance(); - const param = instance.ac[key]; - return typeof param === 'function' ? param.apply(instance.ac) : param; - }, -}); - -Template.SearchInvitePlayers.events({ - 'input input'(e, t) { - const input = e.target; - const position = input.selectionEnd || input.selectionStart; - const { length } = input.value; - document.activeElement === input && e && /input/i.test(e.type) && (input.selectionEnd = position + input.value.length - length); - t.filter.set(input.value); - }, - 'click .rc-popup-list__item'(e, t) { - t.ac.onItemClick(this, e); - }, - 'keydown input'(e, t) { - const KEYCODE_BACKSPACE = 8; - const KEYCODE_DELETE = 46; - - t.ac.onKeyDown(e); - if ([KEYCODE_BACKSPACE, KEYCODE_DELETE].includes(e.keyCode) && e.target.value === '') { - const { deleteLastItem } = t; - return deleteLastItem && deleteLastItem(); - } - }, - 'keyup input'(e, t) { - t.ac.onKeyUp(e); - }, - 'focus input'(e, t) { - t.ac.onFocus(e); - }, - 'blur input'(e, t) { - t.ac.onBlur(e); - }, - 'click .rc-tags__tag'({ target }, t) { - const { onClickTag } = t; - return onClickTag & onClickTag(Blaze.getData(target)); - }, -}); -Template.SearchInvitePlayers.onRendered(function () { - const { name } = this.data; - - this.ac.element = this.firstNode.querySelector(`[name=${name}]`); - this.ac.$element = $(this.ac.element); -}); - -Template.SearchInvitePlayers.onCreated(function () { - this.filter = new ReactiveVar(''); - this.selected = new ReactiveVar([]); - this.onClickTag = this.data.onClickTag; - this.deleteLastItem = this.data.deleteLastItem; - - const { collection, endpoint, field, sort, onSelect, selector = (match) => ({ term: match }) } = this.data; - this.ac = new AutoComplete({ - selector: { - anchor: '.rc-input__label', - item: '.rc-popup-list__item', - container: '.rc-popup-list__list', - }, - onSelect, - position: 'fixed', - limit: 10, - inputDelay: 300, - rules: [ - { - collection, - endpoint, - field, - matchAll: true, - doNotChangeWidth: false, - selector, - sort, - }, - ], - }); - this.ac.tmplInst = this; -}); diff --git a/apps/meteor/app/apps/client/gameCenter/tabBar.ts b/apps/meteor/app/apps/client/gameCenter/tabBar.ts deleted file mode 100644 index 6ca358e43b571..0000000000000 --- a/apps/meteor/app/apps/client/gameCenter/tabBar.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { useMemo } from 'react'; -import { useEndpoint } from '@rocket.chat/ui-contexts'; -import { useQuery } from '@tanstack/react-query'; - -import { addAction } from '../../../../client/views/room/lib/Toolbox'; - -addAction('game-center', () => { - const getExternalComponents = useEndpoint('GET', '/apps/externalComponents'); - const result = useQuery(['apps/external-components'], () => getExternalComponents(), { - staleTime: 10_000, - }); - - return useMemo( - () => - result.isSuccess && result.data.externalComponents.length > 0 - ? { - groups: ['channel', 'group', 'direct', 'direct_multiple', 'team'], - id: 'game-center', - title: 'Apps_Game_Center', - icon: 'game', - template: 'GameCenter', - order: -1, - } - : null, - [result.data?.externalComponents.length, result.isSuccess], - ); -}); diff --git a/apps/meteor/app/apps/client/index.js b/apps/meteor/app/apps/client/index.js deleted file mode 100644 index 51c7d3a3dee25..0000000000000 --- a/apps/meteor/app/apps/client/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import './gameCenter/tabBar'; -import './gameCenter/gameContainer'; -import './gameCenter/gameCenter'; -import './gameCenter/invitePlayers'; - -export { Apps } from './orchestrator'; diff --git a/apps/meteor/app/apps/client/orchestrator.ts b/apps/meteor/app/apps/client/orchestrator.ts deleted file mode 100644 index 3bc2cf8bc028d..0000000000000 --- a/apps/meteor/app/apps/client/orchestrator.ts +++ /dev/null @@ -1,256 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ -import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; -import { AppClientManager } from '@rocket.chat/apps-engine/client/AppClientManager'; -import type { IApiEndpointMetadata } from '@rocket.chat/apps-engine/definition/api'; -import { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus'; -import type { IPermission } from '@rocket.chat/apps-engine/definition/permissions/IPermission'; -import type { IAppStorageItem } from '@rocket.chat/apps-engine/server/storage/IAppStorageItem'; -import { Meteor } from 'meteor/meteor'; -import { Tracker } from 'meteor/tracker'; -import type { AppScreenshot, Serialized } from '@rocket.chat/core-typings'; - -import type { App } from '../../../client/views/admin/apps/types'; -import { dispatchToastMessage } from '../../../client/lib/toast'; -import { settings } from '../../settings/client'; -import { CachedCollectionManager } from '../../ui-cached-collection'; -import { createDeferredValue } from '../lib/misc/DeferredValue'; -import type { - // IAppFromMarketplace, - IAppLanguage, - IAppExternalURL, - ICategory, - // IAppSynced, - // IAppScreenshots, - // IScreenshot, -} from './@types/IOrchestrator'; -import { AppWebsocketReceiver } from './communication'; -import { handleI18nResources } from './i18n'; -import { RealAppsEngineUIHost } from './RealAppsEngineUIHost'; -import { APIClient } from '../../utils/client'; -import { hasAtLeastOnePermission } from '../../authorization/client'; - -class AppClientOrchestrator { - private _appClientUIHost: RealAppsEngineUIHost; - - private _manager: AppClientManager; - - private isLoaded: boolean; - - private ws: AppWebsocketReceiver; - - private setEnabled: (value: boolean | PromiseLike) => void; - - private deferredIsEnabled: Promise | undefined; - - constructor() { - this._appClientUIHost = new RealAppsEngineUIHost(); - this._manager = new AppClientManager(this._appClientUIHost); - this.isLoaded = false; - const { promise, resolve } = createDeferredValue(); - this.deferredIsEnabled = promise; - this.setEnabled = resolve; - } - - public async load(isEnabled: boolean): Promise { - if (!this.isLoaded) { - this.ws = new AppWebsocketReceiver(); - this.isLoaded = true; - } - - await handleI18nResources(); - - this.setEnabled(isEnabled); - } - - public getWsListener(): AppWebsocketReceiver { - return this.ws; - } - - public getAppClientManager(): AppClientManager { - return this._manager; - } - - public handleError(error: unknown): void { - if (hasAtLeastOnePermission(['manage-apps'])) { - dispatchToastMessage({ - type: 'error', - message: error, - }); - } - } - - public async screenshots(appId: string): Promise { - const { screenshots } = await APIClient.get(`/apps/${appId}/screenshots`); - return screenshots; - } - - public isEnabled(): Promise | undefined { - return this.deferredIsEnabled; - } - - public async getApps(): Promise { - const result = await APIClient.get<'/apps'>('/apps'); - - if ('apps' in result) { - // TODO: chapter day: multiple results are returned, but we only need one - return result.apps as App[]; - } - throw new Error('Invalid response from API'); - } - - public async getAppsFromMarketplace(): Promise { - const result = await APIClient.get('/apps', { marketplace: 'true' }); - - if (!Array.isArray(result)) { - // TODO: chapter day: multiple results are returned, but we only need one - throw new Error('Invalid response from API'); - } - - return (result as App[]).map((app: App) => { - const { latest, price, pricingPlans, purchaseType, isEnterpriseOnly, modifiedAt, bundledIn } = app; - return { - ...latest, - price, - pricingPlans, - purchaseType, - isEnterpriseOnly, - modifiedAt, - bundledIn, - }; - }); - } - - public async getAppsOnBundle(bundleId: string): Promise { - const { apps } = await APIClient.get(`/apps/bundles/${bundleId}/apps`); - return apps; - } - - public async getAppsLanguages(): Promise { - const { apps } = await APIClient.get('/apps/languages'); - return apps; - } - - public async getApp(appId: string): Promise { - const { app } = await APIClient.get(`/apps/${appId}` as any); - return app; - } - - public async getAppFromMarketplace(appId: string, version: string): Promise<{ app: App; success: boolean }> { - const result = await APIClient.get( - `/apps/${appId}` as any, - { - marketplace: 'true', - version, - } as any, - ); - return result; - } - - public async getLatestAppFromMarketplace(appId: string, version: string): Promise { - const { app } = await APIClient.get( - `/apps/${appId}` as any, - { - marketplace: 'true', - update: 'true', - appVersion: version, - } as any, - ); - return app; - } - - public async setAppSettings(appId: string, settings: ISetting[]): Promise { - await APIClient.post(`/apps/${appId}/settings`, { settings }); - } - - public async getAppApis(appId: string): Promise { - const { apis } = await APIClient.get(`/apps/${appId}/apis`); - return apis; - } - - public async getAppLanguages(appId: string): Promise { - const { languages } = await APIClient.get(`/apps/${appId}/languages`); - return languages; - } - - public async installApp(appId: string, version: string, permissionsGranted: IPermission[]): Promise { - const { app } = await APIClient.post('/apps', { - appId, - marketplace: true, - version, - permissionsGranted, - }); - return app; - } - - public async updateApp(appId: string, version: string, permissionsGranted: IPermission[]): Promise { - const result = (await (APIClient.post as any)(`/apps/${appId}` as any, { - appId, - marketplace: true, - version, - permissionsGranted, - })) as any; - - if ('app' in result) { - return result; - } - throw new Error('App not found'); - } - - public async setAppStatus(appId: string, status: AppStatus): Promise { - const { status: effectiveStatus } = await APIClient.post(`/apps/${appId}/status`, { status }); - return effectiveStatus; - } - - public disableApp(appId: string): Promise { - return this.setAppStatus(appId, AppStatus.MANUALLY_ENABLED); - } - - public async buildExternalUrl(appId: string, purchaseType: 'buy' | 'subscription' = 'buy', details = false): Promise { - const result = await APIClient.get('/apps', { - buildExternalUrl: 'true', - appId, - purchaseType, - details: `${details}`, - }); - - if ('url' in result) { - return result; - } - throw new Error('Failed to build external url'); - } - - public async getCategories(): Promise> { - const result = await APIClient.get('/apps', { categories: 'true' }); - - if (Array.isArray(result)) { - // TODO: chapter day: multiple results are returned, but we only need one - return result as Serialized[]; - } - throw new Error('Failed to get categories'); - } - - public getUIHost(): RealAppsEngineUIHost { - return this._appClientUIHost; - } -} - -export const Apps = new AppClientOrchestrator(); - -Meteor.startup(() => { - CachedCollectionManager.onLogin(() => { - Meteor.call('apps/is-enabled', (error: Error, isEnabled: boolean) => { - if (error) { - Apps.handleError(error); - return; - } - - Apps.getAppClientManager().initialize(); - Apps.load(isEnabled); - }); - }); - - Tracker.autorun(() => { - const isEnabled = settings.get('/Apps_Framework_enabled'); - Apps.load(isEnabled); - }); -}); diff --git a/apps/meteor/app/apps/server/bridges/activation.ts b/apps/meteor/app/apps/server/bridges/activation.ts index 511d3136dcebc..dce9d0011ec2a 100644 --- a/apps/meteor/app/apps/server/bridges/activation.ts +++ b/apps/meteor/app/apps/server/bridges/activation.ts @@ -3,7 +3,7 @@ import type { ProxiedApp } from '@rocket.chat/apps-engine/server/ProxiedApp'; import type { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus'; import { Users } from '@rocket.chat/models'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; export class AppActivationBridge extends ActivationBridge { // eslint-disable-next-line no-empty-function diff --git a/apps/meteor/app/apps/server/bridges/api.ts b/apps/meteor/app/apps/server/bridges/api.ts index c0dd3cc23d23f..7a391fc15807c 100644 --- a/apps/meteor/app/apps/server/bridges/api.ts +++ b/apps/meteor/app/apps/server/bridges/api.ts @@ -7,7 +7,7 @@ import type { IApiRequest, IApiEndpoint, IApi } from '@rocket.chat/apps-engine/d import type { AppApi } from '@rocket.chat/apps-engine/server/managers/AppApi'; import type { RequestMethod } from '@rocket.chat/apps-engine/definition/accessors'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { authenticationMiddleware } from '../../../api/server/middlewares/authentication'; const apiServer = express(); @@ -55,7 +55,7 @@ export class AppApisBridge extends ApiBridge { }); } - public registerApi({ api, computedPath, endpoint }: AppApi, appId: string): void { + public async registerApi({ api, computedPath, endpoint }: AppApi, appId: string): Promise { this.orch.debugLog(`The App ${appId} is registering the api: "${endpoint.path}" (${computedPath})`); this._verifyApi(api, endpoint); @@ -79,7 +79,7 @@ export class AppApisBridge extends ApiBridge { } } - public unregisterApis(appId: string): void { + public async unregisterApis(appId: string): Promise { this.orch.debugLog(`The App ${appId} is unregistering all apis`); if (this.appRouters.get(appId)) { diff --git a/apps/meteor/app/apps/server/bridges/bridges.js b/apps/meteor/app/apps/server/bridges/bridges.js index d6b948c6d06ee..04162f9742894 100644 --- a/apps/meteor/app/apps/server/bridges/bridges.js +++ b/apps/meteor/app/apps/server/bridges/bridges.js @@ -21,6 +21,7 @@ import { AppSchedulerBridge } from './scheduler'; import { AppAnalyticsBridge } from './analytics'; import { AppVideoConferenceBridge } from './videoConferences'; import { AppOAuthAppsBridge } from './oauthApps'; +import { AppInternalFederationBridge } from './internalFederation'; export class RealAppBridges extends AppBridges { constructor(orch) { @@ -47,6 +48,7 @@ export class RealAppBridges extends AppBridges { this._cloudWorkspaceBridge = new AppCloudBridge(orch); this._videoConfBridge = new AppVideoConferenceBridge(orch); this._oAuthBridge = new AppOAuthAppsBridge(orch); + this._internalFedBridge = new AppInternalFederationBridge(orch); } getCommandBridge() { @@ -132,4 +134,8 @@ export class RealAppBridges extends AppBridges { getOAuthAppsBridge() { return this._oAuthBridge; } + + getInternalFederationBridge() { + return this._internalFedBridge; + } } diff --git a/apps/meteor/app/apps/server/bridges/cloud.ts b/apps/meteor/app/apps/server/bridges/cloud.ts index 6f3569af0579f..87b94de7ad7fa 100644 --- a/apps/meteor/app/apps/server/bridges/cloud.ts +++ b/apps/meteor/app/apps/server/bridges/cloud.ts @@ -3,7 +3,7 @@ import { CloudWorkspaceBridge } from '@rocket.chat/apps-engine/server/bridges/Cl import type { IWorkspaceToken } from '@rocket.chat/apps-engine/definition/cloud/IWorkspaceToken'; import { getWorkspaceAccessTokenWithScope } from '../../../cloud/server'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; const boundGetWorkspaceAccessToken = Meteor.bindEnvironment(getWorkspaceAccessTokenWithScope); diff --git a/apps/meteor/app/apps/server/bridges/commands.ts b/apps/meteor/app/apps/server/bridges/commands.ts index 42735ec762ae4..b4908fafe986d 100644 --- a/apps/meteor/app/apps/server/bridges/commands.ts +++ b/apps/meteor/app/apps/server/bridges/commands.ts @@ -5,8 +5,8 @@ import { CommandBridge } from '@rocket.chat/apps-engine/server/bridges/CommandBr import type { IMessage, RequiredField, SlashCommand } from '@rocket.chat/core-typings'; import { slashCommands } from '../../../utils/server'; -import { Utilities } from '../../lib/misc/Utilities'; -import type { AppServerOrchestrator } from '../orchestrator'; +import { Utilities } from '../../../../ee/lib/misc/Utilities'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { parseParameters } from '../../../../lib/utils/parseParameters'; export class AppCommandsBridge extends CommandBridge { @@ -18,7 +18,7 @@ export class AppCommandsBridge extends CommandBridge { this.disabledCommands = new Map(); } - protected doesCommandExist(command: string, appId: string): boolean { + protected async doesCommandExist(command: string, appId: string): Promise { this.orch.debugLog(`The App ${appId} is checking if "${command}" command exists.`); if (typeof command !== 'string' || command.length === 0) { @@ -30,7 +30,7 @@ export class AppCommandsBridge extends CommandBridge { return typeof slashCommands.commands[cmd] === 'object' || this.disabledCommands.has(cmd); } - protected enableCommand(command: string, appId: string): void { + protected async enableCommand(command: string, appId: string): Promise { this.orch.debugLog(`The App ${appId} is attempting to enable the command: "${command}"`); if (typeof command !== 'string' || command.trim().length === 0) { @@ -48,7 +48,7 @@ export class AppCommandsBridge extends CommandBridge { this.orch.getNotifier().commandUpdated(cmd); } - protected disableCommand(command: string, appId: string): void { + protected async disableCommand(command: string, appId: string): Promise { this.orch.debugLog(`The App ${appId} is attempting to disable the command: "${command}"`); if (typeof command !== 'string' || command.trim().length === 0) { @@ -74,7 +74,7 @@ export class AppCommandsBridge extends CommandBridge { } // command: { command, paramsExample, i18nDescription, executor: function } - protected modifyCommand(command: ISlashCommand, appId: string): void { + protected async modifyCommand(command: ISlashCommand, appId: string): Promise { this.orch.debugLog(`The App ${appId} is attempting to modify the command: "${command}"`); this._verifyCommand(command); @@ -99,7 +99,7 @@ export class AppCommandsBridge extends CommandBridge { this.orch.getNotifier().commandUpdated(cmd); } - protected registerCommand(command: ISlashCommand, appId: string): void { + protected async registerCommand(command: ISlashCommand, appId: string): Promise { this.orch.debugLog(`The App ${appId} is registering the command: "${command.command}"`); this._verifyCommand(command); @@ -122,7 +122,7 @@ export class AppCommandsBridge extends CommandBridge { this.orch.getNotifier().commandAdded(command.command.toLowerCase()); } - protected unregisterCommand(command: string, appId: string): void { + protected async unregisterCommand(command: string, appId: string): Promise { this.orch.debugLog(`The App ${appId} is unregistering the command: "${command}"`); if (typeof command !== 'string' || command.trim().length === 0) { diff --git a/apps/meteor/app/apps/server/bridges/details.ts b/apps/meteor/app/apps/server/bridges/details.ts index 1cea999fd3c8b..cb60cc56f3aab 100644 --- a/apps/meteor/app/apps/server/bridges/details.ts +++ b/apps/meteor/app/apps/server/bridges/details.ts @@ -1,7 +1,7 @@ import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; import { AppDetailChangesBridge as DetailChangesBridge } from '@rocket.chat/apps-engine/server/bridges/AppDetailChangesBridge'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; export class AppDetailChangesBridge extends DetailChangesBridge { // eslint-disable-next-line no-empty-function diff --git a/apps/meteor/app/apps/server/bridges/environmental.ts b/apps/meteor/app/apps/server/bridges/environmental.ts index 2f7a46ae7934a..e159ad2779983 100644 --- a/apps/meteor/app/apps/server/bridges/environmental.ts +++ b/apps/meteor/app/apps/server/bridges/environmental.ts @@ -1,6 +1,6 @@ import { EnvironmentalVariableBridge } from '@rocket.chat/apps-engine/server/bridges/EnvironmentalVariableBridge'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; export class AppEnvironmentalVariableBridge extends EnvironmentalVariableBridge { allowed: Array; diff --git a/apps/meteor/app/apps/server/bridges/http.ts b/apps/meteor/app/apps/server/bridges/http.ts index c67a1b48470c0..264c6923281d6 100644 --- a/apps/meteor/app/apps/server/bridges/http.ts +++ b/apps/meteor/app/apps/server/bridges/http.ts @@ -2,7 +2,7 @@ import { HttpBridge } from '@rocket.chat/apps-engine/server/bridges/HttpBridge'; import type { IHttpResponse } from '@rocket.chat/apps-engine/definition/accessors'; import type { IHttpBridgeRequestInfo } from '@rocket.chat/apps-engine/server/bridges'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { fetch } from '../../../../server/lib/http/fetch'; const isGetOrHead = (method: string): boolean => ['GET', 'HEAD'].includes(method.toUpperCase()); diff --git a/apps/meteor/app/apps/server/bridges/index.js b/apps/meteor/app/apps/server/bridges/index.ts similarity index 100% rename from apps/meteor/app/apps/server/bridges/index.js rename to apps/meteor/app/apps/server/bridges/index.ts diff --git a/apps/meteor/app/apps/server/bridges/internal.ts b/apps/meteor/app/apps/server/bridges/internal.ts index 8355ec817d648..6584a7ac5e8bb 100644 --- a/apps/meteor/app/apps/server/bridges/internal.ts +++ b/apps/meteor/app/apps/server/bridges/internal.ts @@ -3,7 +3,7 @@ import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; import type { ISubscription } from '@rocket.chat/core-typings'; import { Settings } from '@rocket.chat/models'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { Subscriptions } from '../../../models/server'; export class AppInternalBridge extends InternalBridge { diff --git a/apps/meteor/app/apps/server/bridges/internalFederation.ts b/apps/meteor/app/apps/server/bridges/internalFederation.ts new file mode 100644 index 0000000000000..9bf3b34439ce5 --- /dev/null +++ b/apps/meteor/app/apps/server/bridges/internalFederation.ts @@ -0,0 +1,12 @@ +import type { IInternalFederationBridge } from '@rocket.chat/apps-engine/server/bridges/IInternalFederationBridge'; +import { FederationKeys } from '@rocket.chat/models'; + +export class AppInternalFederationBridge implements IInternalFederationBridge { + async getPrivateKey(): Promise { + return FederationKeys.getKey('private'); + } + + async getPublicKey(): Promise { + return FederationKeys.getKey('public'); + } +} diff --git a/apps/meteor/app/apps/server/bridges/listeners.js b/apps/meteor/app/apps/server/bridges/listeners.js index 9f8dd436df123..30fa305b7085c 100644 --- a/apps/meteor/app/apps/server/bridges/listeners.js +++ b/apps/meteor/app/apps/server/bridges/listeners.js @@ -82,12 +82,12 @@ export class AppListenerBridge { user: this.orch.getConverters().get('users').convertToApp(userDeleted), }; case AppInterface.IPostMessageReacted: - const [userReacted, reaction, isRemoved] = payload; + const [userReacted, reaction, isReacted] = payload; return { message: msg, user: this.orch.getConverters().get('users').convertToApp(userReacted), reaction, - isRemoved, + isReacted, }; case AppInterface.IPostMessageFollowed: const [userFollowed, isUnfollow] = payload; diff --git a/apps/meteor/app/apps/server/bridges/livechat.ts b/apps/meteor/app/apps/server/bridges/livechat.ts index 73a391c7126fc..9b514097c9ada 100644 --- a/apps/meteor/app/apps/server/bridges/livechat.ts +++ b/apps/meteor/app/apps/server/bridges/livechat.ts @@ -16,7 +16,8 @@ import { LivechatVisitors } from '@rocket.chat/models'; import { getRoom } from '../../../livechat/server/api/lib/livechat'; import { Livechat } from '../../../livechat/server/lib/Livechat'; import { Users, LivechatDepartment, LivechatRooms } from '../../../models/server'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; +import { Livechat as LivechatTyped } from '../../../livechat/server/lib/LivechatTyped'; export class AppLivechatBridge extends LivechatBridge { // eslint-disable-next-line no-empty-function @@ -122,7 +123,9 @@ export class AppLivechatBridge extends LivechatBridge { ...(visitor && { visitor }), }; - return Livechat.closeRoom(closeData); + await LivechatTyped.closeRoom(closeData); + + return true; } protected async findRooms(visitor: IVisitor, departmentId: string | null, appId: string): Promise> { diff --git a/apps/meteor/app/apps/server/bridges/messages.ts b/apps/meteor/app/apps/server/bridges/messages.ts index 935a10efbc117..b90e590bfca86 100644 --- a/apps/meteor/app/apps/server/bridges/messages.ts +++ b/apps/meteor/app/apps/server/bridges/messages.ts @@ -4,13 +4,13 @@ import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; import type { IUser } from '@rocket.chat/apps-engine/definition/users'; import type { IRoom } from '@rocket.chat/apps-engine/definition/rooms'; import type { ISubscription } from '@rocket.chat/core-typings'; +import { api } from '@rocket.chat/core-services'; import { Messages, Users, Subscriptions } from '../../../models/server'; import { updateMessage } from '../../../lib/server/functions/updateMessage'; import { executeSendMessage } from '../../../lib/server/methods/sendMessage'; -import { api } from '../../../../server/sdk/api'; import notifications from '../../../notifications/server/lib/Notifications'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; export class AppMessageBridge extends MessageBridge { // eslint-disable-next-line no-empty-function diff --git a/apps/meteor/app/apps/server/bridges/oauthApps.ts b/apps/meteor/app/apps/server/bridges/oauthApps.ts index e29443d8cc495..6d2c25ba2e256 100644 --- a/apps/meteor/app/apps/server/bridges/oauthApps.ts +++ b/apps/meteor/app/apps/server/bridges/oauthApps.ts @@ -5,7 +5,7 @@ import { OAuthApps, Users } from '@rocket.chat/models'; import { Random } from 'meteor/random'; import { v4 as uuidv4 } from 'uuid'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; export class AppOAuthAppsBridge extends OAuthAppsBridge { constructor(private readonly orch: AppServerOrchestrator) { diff --git a/apps/meteor/app/apps/server/bridges/persistence.ts b/apps/meteor/app/apps/server/bridges/persistence.ts index b14aef68eb3f9..b1b8f0b5a642f 100644 --- a/apps/meteor/app/apps/server/bridges/persistence.ts +++ b/apps/meteor/app/apps/server/bridges/persistence.ts @@ -1,7 +1,7 @@ import { PersistenceBridge } from '@rocket.chat/apps-engine/server/bridges/PersistenceBridge'; import type { RocketChatAssociationRecord } from '@rocket.chat/apps-engine/definition/metadata'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; export class AppPersistenceBridge extends PersistenceBridge { // eslint-disable-next-line no-empty-function diff --git a/apps/meteor/app/apps/server/bridges/rooms.ts b/apps/meteor/app/apps/server/bridges/rooms.ts index 401b045997097..f0c699e68c482 100644 --- a/apps/meteor/app/apps/server/bridges/rooms.ts +++ b/apps/meteor/app/apps/server/bridges/rooms.ts @@ -4,11 +4,12 @@ import { RoomBridge } from '@rocket.chat/apps-engine/server/bridges/RoomBridge'; import type { IUser } from '@rocket.chat/apps-engine/definition/users'; import type { IMessage } from '@rocket.chat/apps-engine/definition/messages'; import { Meteor } from 'meteor/meteor'; -import type { ISubscription } from '@rocket.chat/core-typings'; +import type { ISubscription, IUser as ICoreUser } from '@rocket.chat/core-typings'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { Rooms, Subscriptions, Users } from '../../../models/server'; import { addUserToRoom } from '../../../lib/server/functions/addUserToRoom'; +import { deleteRoom } from '../../../lib/server/functions/deleteRoom'; export class AppRoomBridge extends RoomBridge { // eslint-disable-next-line no-empty-function @@ -130,7 +131,7 @@ export class AppRoomBridge extends RoomBridge { protected async delete(roomId: string, appId: string): Promise { this.orch.debugLog(`The App ${appId} is deleting a room.`); - Rooms.removeById(roomId); + deleteRoom(roomId); } protected async createDiscussion( @@ -169,4 +170,26 @@ export class AppRoomBridge extends RoomBridge { return rid; } + + protected getModerators(roomId: string, appId: string): Promise { + this.orch.debugLog(`The App ${appId} is getting room moderators for room id: ${roomId}`); + return this.getUsersByRoomIdAndSubscriptionRole(roomId, 'moderator'); + } + + protected getOwners(roomId: string, appId: string): Promise { + this.orch.debugLog(`The App ${appId} is getting room owners for room id: ${roomId}`); + return this.getUsersByRoomIdAndSubscriptionRole(roomId, 'owner'); + } + + protected getLeaders(roomId: string, appId: string): Promise { + this.orch.debugLog(`The App ${appId} is getting room leaders for room id: ${roomId}`); + return this.getUsersByRoomIdAndSubscriptionRole(roomId, 'leader'); + } + + private async getUsersByRoomIdAndSubscriptionRole(roomId: string, role: string): Promise { + const subs = await Subscriptions.findByRoomIdAndRoles(roomId, [role], { projection: { uid: '$u._id', _id: 0 } }); + const users = await Users.findByIds(subs.map((user: { uid: string }) => user.uid)); + const userConverter = this.orch.getConverters()!.get('users'); + return users.map((user: ICoreUser) => userConverter!.convertToApp(user)); + } } diff --git a/apps/meteor/app/apps/server/bridges/scheduler.ts b/apps/meteor/app/apps/server/bridges/scheduler.ts index c64ffd1d9f874..42f4b383132dc 100644 --- a/apps/meteor/app/apps/server/bridges/scheduler.ts +++ b/apps/meteor/app/apps/server/bridges/scheduler.ts @@ -6,7 +6,7 @@ import type { IProcessor, IOnetimeSchedule, IRecurringSchedule, IJobContext, IRu import { StartupType } from '@rocket.chat/apps-engine/definition/scheduler'; import { SchedulerBridge } from '@rocket.chat/apps-engine/server/bridges/SchedulerBridge'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; const { MONGO_URL = 'mongodb://localhost:27017/rocketchat' } = process.env; @@ -19,7 +19,13 @@ function _callProcessor(processor: IProcessor['processor']): (job: Job) => Promi data.jobId = job.attrs._id?.toString(); - return (processor as (jobContext: IJobContext) => Promise)(data); + return (processor as (jobContext: IJobContext) => Promise)(data).then(() => { + // ensure the 'normal' ('onetime' in our vocab) type job is removed after it is run + // as Agenda does not remove it from the DB + if (job.attrs.type === 'normal') { + job.agenda.cancel({ _id: job.attrs._id }); + } + }); }; } @@ -111,7 +117,7 @@ export class AppSchedulerBridge extends SchedulerBridge { } private async scheduleOnceAfterRegister(job: IOnetimeSchedule, appId: string): Promise { - const scheduledJobs = await this.scheduler.jobs({ name: job.id, type: 'normal' }); + const scheduledJobs = await this.scheduler.jobs({ name: job.id, type: 'normal' }, {}, 1); if (!scheduledJobs.length) { return this.scheduleOnce(job, appId); } diff --git a/apps/meteor/app/apps/server/bridges/settings.ts b/apps/meteor/app/apps/server/bridges/settings.ts index 7be7a888043d9..14e4834c36328 100644 --- a/apps/meteor/app/apps/server/bridges/settings.ts +++ b/apps/meteor/app/apps/server/bridges/settings.ts @@ -2,7 +2,7 @@ import type { ISetting } from '@rocket.chat/apps-engine/definition/settings'; import { ServerSettingBridge } from '@rocket.chat/apps-engine/server/bridges/ServerSettingBridge'; import { Settings } from '@rocket.chat/models'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; export class AppSettingBridge extends ServerSettingBridge { // eslint-disable-next-line no-empty-function diff --git a/apps/meteor/app/apps/server/bridges/uiInteraction.ts b/apps/meteor/app/apps/server/bridges/uiInteraction.ts index 15788ce4684d5..6db79eacd984c 100644 --- a/apps/meteor/app/apps/server/bridges/uiInteraction.ts +++ b/apps/meteor/app/apps/server/bridges/uiInteraction.ts @@ -1,9 +1,9 @@ import { UiInteractionBridge as UiIntBridge } from '@rocket.chat/apps-engine/server/bridges/UiInteractionBridge'; import type { IUIKitInteraction } from '@rocket.chat/apps-engine/definition/uikit'; import type { IUser } from '@rocket.chat/apps-engine/definition/users'; +import { api } from '@rocket.chat/core-services'; -import { api } from '../../../../server/sdk/api'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; export class UiInteractionBridge extends UiIntBridge { // eslint-disable-next-line no-empty-function diff --git a/apps/meteor/app/apps/server/bridges/uploads.ts b/apps/meteor/app/apps/server/bridges/uploads.ts index 21de997be2f66..94655eadef02a 100644 --- a/apps/meteor/app/apps/server/bridges/uploads.ts +++ b/apps/meteor/app/apps/server/bridges/uploads.ts @@ -4,8 +4,8 @@ import type { IUpload } from '@rocket.chat/apps-engine/definition/uploads'; import type { IUploadDetails } from '@rocket.chat/apps-engine/definition/uploads/IUploadDetails'; import { FileUpload } from '../../../file-upload/server'; -import { determineFileType } from '../../lib/misc/determineFileType'; -import type { AppServerOrchestrator } from '../orchestrator'; +import { determineFileType } from '../../../../ee/lib/misc/determineFileType'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; const getUploadDetails = (details: IUploadDetails): Partial => { if (details.visitorToken) { diff --git a/apps/meteor/app/apps/server/bridges/users.ts b/apps/meteor/app/apps/server/bridges/users.ts index af00a8be2cd40..1b95601146b96 100644 --- a/apps/meteor/app/apps/server/bridges/users.ts +++ b/apps/meteor/app/apps/server/bridges/users.ts @@ -1,12 +1,11 @@ import { Random } from 'meteor/random'; -import { UserPresence } from 'meteor/konecty:user-presence'; import { UserBridge } from '@rocket.chat/apps-engine/server/bridges/UserBridge'; -import type { IUserCreationOptions, IUser } from '@rocket.chat/apps-engine/definition/users'; +import type { IUserCreationOptions, IUser, UserType } from '@rocket.chat/apps-engine/definition/users'; import { Subscriptions, Users as UsersRaw } from '@rocket.chat/models'; -import { setUserAvatar, checkUsernameAvailability, deleteUser } from '../../../lib/server/functions'; +import { setUserAvatar, checkUsernameAvailability, deleteUser, getUserCreatedByApp } from '../../../lib/server/functions'; import { Users } from '../../../models/server'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; export class AppUserBridge extends UserBridge { // eslint-disable-next-line no-empty-function @@ -34,6 +33,24 @@ export class AppUserBridge extends UserBridge { return this.orch.getConverters()?.get('users').convertToApp(user); } + /** + * Deletes all bot or app users created by the App. + * @param appId the App's ID. + * @param type the type of the user to be deleted. + * @returns true if any user was deleted, false otherwise. + */ + protected async deleteUsersCreatedByApp(appId: string, type: UserType.APP | UserType.BOT): Promise { + this.orch.debugLog(`The App ${appId} is deleting all bot users`); + + const appUsers = await getUserCreatedByApp(appId, type); + if (appUsers.length) { + this.orch.debugLog(`The App ${appId} is deleting ${appUsers.length} users`); + await Promise.all(appUsers.map((appUser) => deleteUser(appUser._id))); + return true; + } + return false; + } + protected async create(userDescriptor: Partial, appId: string, options?: IUserCreationOptions): Promise { this.orch.debugLog(`The App ${appId} is requesting to create a new user.`); const user = this.orch.getConverters()?.get('users').convertToRocketChat(userDescriptor); @@ -47,6 +64,7 @@ export class AppUserBridge extends UserBridge { } switch (user.type) { + case 'bot': case 'app': if (!checkUsernameAvailability(user.username)) { throw new Error(`The username "${user.username}" is already being used. Rename or remove the user using it to install this App`); @@ -84,7 +102,11 @@ export class AppUserBridge extends UserBridge { return true; } - protected async update(user: IUser & { id: string }, fields: Partial, appId: string): Promise { + protected async update( + user: IUser & { id: string }, + fields: Partial & { statusDefault: string }, + appId: string, + ): Promise { this.orch.debugLog(`The App ${appId} is updating a user`); if (!user) { @@ -98,12 +120,12 @@ export class AppUserBridge extends UserBridge { const { status } = fields; delete fields.status; - await UsersRaw.update({ _id: user.id }, { $set: fields as any }); - if (status) { - UserPresence.setDefaultStatus(user.id, status); + fields.statusDefault = status; } + await UsersRaw.updateOne({ _id: user.id }, { $set: fields as any }); + return true; } diff --git a/apps/meteor/app/apps/server/bridges/videoConferences.ts b/apps/meteor/app/apps/server/bridges/videoConferences.ts index d6ac7b62fb2a2..b8362622b3952 100644 --- a/apps/meteor/app/apps/server/bridges/videoConferences.ts +++ b/apps/meteor/app/apps/server/bridges/videoConferences.ts @@ -1,9 +1,9 @@ import { VideoConferenceBridge } from '@rocket.chat/apps-engine/server/bridges/VideoConferenceBridge'; import type { AppVideoConference, VideoConference } from '@rocket.chat/apps-engine/definition/videoConferences'; import type { IVideoConfProvider } from '@rocket.chat/apps-engine/definition/videoConfProviders'; +import { VideoConf } from '@rocket.chat/core-services'; -import { VideoConf } from '../../../../server/sdk'; -import type { AppServerOrchestrator } from '../orchestrator'; +import type { AppServerOrchestrator } from '../../../../ee/server/apps/orchestrator'; import { videoConfProviders } from '../../../../server/lib/videoConfProviders'; import type { AppVideoConferencesConverter } from '../converters/videoConferences'; diff --git a/apps/meteor/app/apps/server/communication/index.ts b/apps/meteor/app/apps/server/communication/index.ts deleted file mode 100644 index 251fec9e06e00..0000000000000 --- a/apps/meteor/app/apps/server/communication/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { AppMethods } from './methods'; -import { AppsRestApi } from './rest'; -import { AppUIKitInteractionApi } from './uikit'; -import { AppEvents, AppServerListener, AppServerNotifier } from './websockets'; - -export { AppUIKitInteractionApi, AppMethods, AppsRestApi, AppEvents, AppServerNotifier, AppServerListener }; diff --git a/apps/meteor/app/apps/server/communication/methods.ts b/apps/meteor/app/apps/server/communication/methods.ts deleted file mode 100644 index 3757314cf387a..0000000000000 --- a/apps/meteor/app/apps/server/communication/methods.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import type { SettingValue } from '@rocket.chat/core-typings'; -import { Settings } from '@rocket.chat/models'; - -import { hasPermission } from '../../../authorization/server'; -import { twoFactorRequired } from '../../../2fa/server/twoFactorRequired'; -import type { AppServerOrchestrator } from '../orchestrator'; - -const waitToLoad = function (orch: AppServerOrchestrator): unknown { - return new Promise((resolve) => { - const id = setInterval(() => { - if (orch.isEnabled() && orch.isLoaded()) { - clearInterval(id); - resolve(); - } - }, 100); - }); -}; - -const waitToUnload = function (orch: AppServerOrchestrator): unknown { - return new Promise((resolve) => { - const id = setInterval(() => { - if (!orch.isEnabled() && !orch.isLoaded()) { - clearInterval(id); - resolve(); - } - }, 100); - }); -}; - -export class AppMethods { - private orch: AppServerOrchestrator; - - constructor(orch: AppServerOrchestrator) { - this.orch = orch; - - this.addMethods(); - } - - isEnabled(): SettingValue { - return typeof this.orch !== 'undefined' && this.orch.isEnabled(); - } - - isLoaded(): boolean { - return Boolean(typeof this.orch !== 'undefined' && this.orch.isEnabled() && this.orch.isLoaded()); - } - - private addMethods(): void { - // eslint-disable-next-line @typescript-eslint/no-this-alias - const instance = this; - - Meteor.methods({ - 'apps/is-enabled'() { - return instance.isEnabled(); - }, - - 'apps/is-loaded'() { - return instance.isLoaded(); - }, - - 'apps/go-enable': twoFactorRequired(function _appsGoEnable() { - const uid = Meteor.userId(); - if (!uid) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'apps/go-enable', - }); - } - - if (!hasPermission(uid, 'manage-apps')) { - throw new Meteor.Error('error-action-not-allowed', 'Not allowed', { - method: 'apps/go-enable', - }); - } - - Settings.updateValueById('Apps_Framework_enabled', true); - - Promise.await(waitToLoad(instance.orch)); - }), - - 'apps/go-disable': twoFactorRequired(function _appsGoDisable() { - const uid = Meteor.userId(); - if (!uid) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'apps/go-enable', - }); - } - - if (!hasPermission(uid, 'manage-apps')) { - throw new Meteor.Error('error-action-not-allowed', 'Not allowed', { - method: 'apps/go-enable', - }); - } - - Settings.updateValueById('Apps_Framework_enabled', false); - - Promise.await(waitToUnload(instance.orch)); - }), - }); - } -} diff --git a/apps/meteor/app/apps/server/communication/rest.js b/apps/meteor/app/apps/server/communication/rest.js deleted file mode 100644 index d80da1178d5d9..0000000000000 --- a/apps/meteor/app/apps/server/communication/rest.js +++ /dev/null @@ -1,977 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { HTTP } from 'meteor/http'; -import { Settings } from '@rocket.chat/models'; - -import { API } from '../../../api/server'; -import { getUploadFormData } from '../../../api/server/lib/getUploadFormData'; -import { getWorkspaceAccessToken, getUserCloudAccessToken } from '../../../cloud/server'; -import { settings } from '../../../settings/server'; -import { Info } from '../../../utils'; -import { Users } from '../../../models/server'; -import { Apps } from '../orchestrator'; -import { formatAppInstanceForRest } from '../../lib/misc/formatAppInstanceForRest'; -import { actionButtonsHandler } from './endpoints/actionButtonsHandler'; -import { fetch } from '../../../../server/lib/http/fetch'; -import { updateAppSettingById, updateAgentConfig, addAgentConfig, deleteAgentConfig, getAgentConfig } from './appConfig'; - -const appsEngineVersionForMarketplace = Info.marketplaceApiVersion.replace(/-.*/g, ''); -const getDefaultHeaders = () => ({ - 'X-Apps-Engine-Version': appsEngineVersionForMarketplace, -}); - -const purchaseTypes = new Set(['buy', 'subscription']); - -export class AppsRestApi { - constructor(orch, manager) { - this._orch = orch; - this._manager = manager; - this.loadAPI(); - } - - async loadAPI() { - this.api = new API.ApiClass({ - version: 'apps', - useDefaultAuth: true, - prettyJson: false, - enableCors: false, - auth: API.getUserAuth(), - }); - this.addManagementRoutes(); - } - - addManagementRoutes() { - const orchestrator = this._orch; - const manager = this._manager; - - const handleError = (message, e) => { - // when there is no `response` field in the error, it means the request - // couldn't even make it to the server - if (!e.hasOwnProperty('response')) { - orchestrator.getRocketChatLogger().warn(message, e.message); - return API.v1.internalError('Could not reach the Marketplace'); - } - - orchestrator.getRocketChatLogger().error(message, e.response.data); - - if (e.response.statusCode >= 500 && e.response.statusCode <= 599) { - return API.v1.internalError(); - } - - if (e.response.statusCode === 404) { - return API.v1.notFound(); - } - - return API.v1.failure(); - }; - - this.api.addRoute('actionButtons', ...actionButtonsHandler(this)); - - // WE NEED TO MOVE EACH ENDPOINT HANDLER TO IT'S OWN FILE - this.api.addRoute( - '', - { authRequired: true, permissionsRequired: ['manage-apps'] }, - { - async get() { - const baseUrl = orchestrator.getMarketplaceUrl(); - - // Gets the Apps from the marketplace - if (this.queryParams.marketplace) { - const headers = getDefaultHeaders(); - const token = await getWorkspaceAccessToken(); - if (token) { - headers.Authorization = `Bearer ${token}`; - } - - let result; - try { - result = HTTP.get(`${baseUrl}/v1/apps`, { - headers, - }); - } catch (e) { - return handleError('Unable to access Marketplace. Does the server has access to the internet?', e); - } - - if (!result || result.statusCode !== 200) { - orchestrator.getRocketChatLogger().error('Error getting the Apps:', result.data); - return API.v1.failure(); - } - - return API.v1.success(result.data); - } - - if (this.queryParams.categories) { - const headers = getDefaultHeaders(); - const token = await getWorkspaceAccessToken(); - if (token) { - headers.Authorization = `Bearer ${token}`; - } - - let result; - try { - result = HTTP.get(`${baseUrl}/v1/categories`, { - headers, - }); - } catch (e) { - orchestrator.getRocketChatLogger().error('Error getting the categories from the Marketplace:', e.response.data); - return API.v1.internalError(); - } - - if (!result || result.statusCode !== 200) { - orchestrator.getRocketChatLogger().error('Error getting the categories from the Marketplace:', result.data); - return API.v1.failure(); - } - - return API.v1.success(result.data); - } - - if (this.queryParams.buildExternalUrl && this.queryParams.appId) { - const workspaceId = settings.get('Cloud_Workspace_Id'); - - if (!this.queryParams.purchaseType || !purchaseTypes.has(this.queryParams.purchaseType)) { - return API.v1.failure({ error: 'Invalid purchase type' }); - } - - const token = getUserCloudAccessToken(this.getLoggedInUser()._id, true, 'marketplace:purchase', false); - if (!token) { - return API.v1.failure({ error: 'Unauthorized' }); - } - - const subscribeRoute = this.queryParams.details === 'true' ? 'subscribe/details' : 'subscribe'; - - const seats = Users.getActiveLocalUserCount(); - - return API.v1.success({ - url: `${baseUrl}/apps/${this.queryParams.appId}/${ - this.queryParams.purchaseType === 'buy' ? this.queryParams.purchaseType : subscribeRoute - }?workspaceId=${workspaceId}&token=${token}&seats=${seats}`, - }); - } - - const apps = manager.get().map(formatAppInstanceForRest); - - if (this.queryParams.appName || this.queryParams.appName === '') { - const headers = getDefaultHeaders(); - const token = getWorkspaceAccessToken(); - if (token) { - headers.Authorization = `Bearer ${token}`; - } - - let result; - try { - result = HTTP.get(`${baseUrl}/v1/apps`, { - headers, - }); - } catch (e) { - return handleError('Unable to access Marketplace. Does the server has access to the internet?', e); - } - - if (!result || result.statusCode !== 200) { - orchestrator.getRocketChatLogger().error('Error getting the Apps:', result.data); - return API.v1.failure(); - } - - if (apps) { - const appNames = {}; - for (const app of apps) { - if (this.queryParams.appName === '' || this.queryParams.appName === app.name) { - appNames[app.name] = app.id; - } - } - return API.v1.success(appNames); - } - - return API.v1.success(result.data); - } - - return API.v1.success({ apps }); - }, - async post() { - let buff; - let marketplaceInfo; - let permissionsGranted; - - if (this.bodyParams.url) { - if (settings.get('Apps_Framework_Development_Mode') !== true) { - return API.v1.failure({ error: 'Installation from url is disabled.' }); - } - - try { - const response = await fetch(this.bodyParams.url); - - if (response.status !== 200 || response.headers.get('content-type') !== 'application/zip') { - return API.v1.failure({ - error: 'Invalid url. It doesn\'t exist or is not "application/zip".', - }); - } - - buff = Buffer.from(await response.arrayBuffer()); - } catch (e) { - orchestrator.getRocketChatLogger().error('Error getting the app from url:', e.response.data); - return API.v1.internalError(); - } - - if (this.bodyParams.downloadOnly) { - return API.v1.success({ buff }); - } - } else if (this.bodyParams.appId && this.bodyParams.marketplace && this.bodyParams.version) { - const baseUrl = orchestrator.getMarketplaceUrl(); - - const headers = getDefaultHeaders(); - try { - const downloadToken = await getWorkspaceAccessToken(true, 'marketplace:download', false); - const marketplaceToken = await getWorkspaceAccessToken(); - - const [downloadResponse, marketplaceResponse] = await Promise.all([ - fetch(`${baseUrl}/v2/apps/${this.bodyParams.appId}/download/${this.bodyParams.version}?token=${downloadToken}`, { - headers, - }), - fetch(`${baseUrl}/v1/apps/${this.bodyParams.appId}?appVersion=${this.bodyParams.version}`, { - headers: { - Authorization: `Bearer ${marketplaceToken}`, - ...headers, - }, - }), - ]); - - if (downloadResponse.headers.get('content-type') !== 'application/zip') { - throw new Error('Invalid url. It doesn\'t exist or is not "application/zip".'); - } - - buff = Buffer.from(await downloadResponse.arrayBuffer()); - marketplaceInfo = await marketplaceResponse.json(); - permissionsGranted = this.bodyParams.permissionsGranted; - } catch (err) { - return API.v1.failure(err.message); - } - } else { - if (settings.get('Apps_Framework_Development_Mode') !== true) { - return API.v1.failure({ error: 'Direct installation of an App is disabled.' }); - } - - const [app, formData] = await getUploadFormData( - { - request: this.request, - }, - { field: 'app' }, - ); - buff = app?.fileBuffer; - permissionsGranted = (() => { - try { - const permissions = JSON.parse(formData?.permissions || ''); - return permissions.length ? permissions : undefined; - } catch { - return undefined; - } - })(); - } - - if (!buff) { - return API.v1.failure({ error: 'Failed to get a file to install for the App. ' }); - } - - const user = orchestrator.getConverters().get('users').convertToApp(Meteor.user()); - - const aff = await manager.add(buff, { marketplaceInfo, permissionsGranted, enable: true, user }); - const info = aff.getAppInfo(); - - if (aff.hasStorageError()) { - return API.v1.failure({ status: 'storage_error', messages: [aff.getStorageError()] }); - } - - if (aff.hasAppUserError()) { - return API.v1.failure({ - status: 'app_user_error', - messages: [aff.getAppUserError().message], - payload: { username: aff.getAppUserError().username }, - }); - } - - info.status = aff.getApp().getStatus(); - - return API.v1.success({ - app: info, - implemented: aff.getImplementedInferfaces(), - licenseValidation: aff.getLicenseValidationResult(), - }); - }, - }, - ); - - this.api.addRoute( - 'externalComponents', - { authRequired: false }, - { - get() { - const externalComponents = orchestrator.getProvidedComponents(); - - return API.v1.success({ externalComponents }); - }, - }, - ); - - this.api.addRoute( - 'languages', - { authRequired: false }, - { - get() { - const apps = manager.get().map((prl) => ({ - id: prl.getID(), - languages: prl.getStorageItem().languageContent, - })); - - return API.v1.success({ apps }); - }, - }, - ); - - this.api.addRoute( - 'externalComponentEvent', - { authRequired: true }, - { - post() { - if ( - !this.bodyParams.externalComponent || - !['IPostExternalComponentOpened', 'IPostExternalComponentClosed'].includes(this.bodyParams.event) - ) { - return API.v1.failure({ error: 'Event and externalComponent must be provided.' }); - } - - try { - const { event, externalComponent } = this.bodyParams; - const result = Apps.getBridges().getListenerBridge().externalComponentEvent(event, externalComponent); - - return API.v1.success({ result }); - } catch (e) { - orchestrator.getRocketChatLogger().error(`Error triggering external components' events ${e.response.data}`); - return API.v1.internalError(); - } - }, - }, - ); - - this.api.addRoute( - 'bundles/:id/apps', - { authRequired: true, permissionsRequired: ['manage-apps'] }, - { - async get() { - const baseUrl = orchestrator.getMarketplaceUrl(); - - const headers = {}; - const token = await getWorkspaceAccessToken(); - if (token) { - headers.Authorization = `Bearer ${token}`; - } - - let result; - try { - result = HTTP.get(`${baseUrl}/v1/bundles/${this.urlParams.id}/apps`, { - headers, - }); - } catch (e) { - orchestrator.getRocketChatLogger().error("Error getting the Bundle's Apps from the Marketplace:", e.response.data); - return API.v1.internalError(); - } - - if (!result || result.statusCode !== 200 || result.data.length === 0) { - orchestrator.getRocketChatLogger().error("Error getting the Bundle's Apps from the Marketplace:", result.data); - return API.v1.failure(); - } - - return API.v1.success({ apps: result.data }); - }, - }, - ); - - this.api.addRoute( - 'featured', - { authRequired: true }, - { - async get() { - const baseUrl = orchestrator.getMarketplaceUrl(); - - const headers = getDefaultHeaders(); - const token = await getWorkspaceAccessToken(); - if (token) { - headers.Authorization = `Bearer ${token}`; - } - - let result; - try { - result = HTTP.get(`${baseUrl}/v1/apps/featured`, { - headers, - }); - } catch (e) { - return handleError('Unable to access Marketplace. Does the server has access to the internet?', e); - } - - if (!result || result.statusCode !== 200) { - orchestrator.getRocketChatLogger().error('Error getting the Featured Apps from the Marketplace:', result.data); - return API.v1.failure(); - } - - return API.v1.success(result.data); - }, - }, - ); - - this.api.addRoute( - ':id', - { authRequired: true, permissionsRequired: ['manage-apps'] }, - { - async get() { - if (this.queryParams.marketplace && this.queryParams.version) { - const baseUrl = orchestrator.getMarketplaceUrl(); - - const headers = {}; // DO NOT ATTACH THE FRAMEWORK/ENGINE VERSION HERE. - const token = await getWorkspaceAccessToken(); - if (token) { - headers.Authorization = `Bearer ${token}`; - } - - let result; - try { - result = HTTP.get(`${baseUrl}/v1/apps/${this.urlParams.id}?appVersion=${this.queryParams.version}`, { - headers, - }); - } catch (e) { - return handleError('Unable to access Marketplace. Does the server has access to the internet?', e); - } - - if (!result || result.statusCode !== 200 || result.data.length === 0) { - orchestrator.getRocketChatLogger().error('Error getting the App information from the Marketplace:', result.data); - return API.v1.failure(); - } - - return API.v1.success({ app: result.data[0] }); - } - - if (this.queryParams.marketplace && this.queryParams.update && this.queryParams.appVersion) { - const baseUrl = orchestrator.getMarketplaceUrl(); - - const headers = getDefaultHeaders(); - const token = await getWorkspaceAccessToken(); - if (token) { - headers.Authorization = `Bearer ${token}`; - } - - let result; - try { - result = HTTP.get(`${baseUrl}/v1/apps/${this.urlParams.id}/latest?frameworkVersion=${appsEngineVersionForMarketplace}`, { - headers, - }); - } catch (e) { - return handleError('Unable to access Marketplace. Does the server has access to the internet?', e); - } - - if (result.statusCode !== 200 || result.data.length === 0) { - orchestrator.getRocketChatLogger().error('Error getting the App update info from the Marketplace:', result.data); - return API.v1.failure(); - } - - return API.v1.success({ app: result.data }); - } - const app = manager.getOneById(this.urlParams.id); - if (!app) { - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - } - - return API.v1.success({ - app: formatAppInstanceForRest(app), - }); - }, - async post() { - let buff; - let permissionsGranted; - - if (this.bodyParams.url) { - if (settings.get('Apps_Framework_Development_Mode') !== true) { - return API.v1.failure({ error: 'Updating an App from a url is disabled.' }); - } - - const response = await fetch(this.bodyParams.url); - - if (response.status !== 200 || response.headers.get('content-type') !== 'application/zip') { - return API.v1.failure({ - error: 'Invalid url. It doesn\'t exist or is not "application/zip".', - }); - } - - buff = Buffer.from(await response.arrayBuffer()); - } else if (this.bodyParams.appId && this.bodyParams.marketplace && this.bodyParams.version) { - const baseUrl = orchestrator.getMarketplaceUrl(); - - const headers = getDefaultHeaders(); - const token = await getWorkspaceAccessToken(true, 'marketplace:download', false); - - try { - const response = await fetch( - `${baseUrl}/v2/apps/${this.bodyParams.appId}/download/${this.bodyParams.version}?token=${token}`, - { - headers, - }, - ); - - if (response.status !== 200) { - orchestrator.getRocketChatLogger().error('Error getting the App from the Marketplace:', await response.text()); - return API.v1.failure(); - } - - if (response.headers.get('content-type') !== 'application/zip') { - return API.v1.failure({ - error: 'Invalid url. It doesn\'t exist or is not "application/zip".', - }); - } - - buff = Buffer.from(await response.arrayBuffer()); - } catch (e) { - orchestrator.getRocketChatLogger().error('Error getting the App from the Marketplace:', e.response.data); - return API.v1.internalError(); - } - } else { - if (settings.get('Apps_Framework_Development_Mode') !== true) { - return API.v1.failure({ error: 'Direct updating of an App is disabled.' }); - } - - const [app, formData] = await getUploadFormData( - { - request: this.request, - }, - { field: 'app' }, - ); - buff = app?.fileBuffer; - permissionsGranted = (() => { - try { - const permissions = JSON.parse(formData?.permissions || ''); - return permissions.length ? permissions : undefined; - } catch { - return undefined; - } - })(); - } - - if (!buff) { - return API.v1.failure({ error: 'Failed to get a file to install for the App. ' }); - } - - const aff = await manager.update(buff, permissionsGranted); - const info = aff.getAppInfo(); - - if (aff.hasStorageError()) { - return API.v1.failure({ status: 'storage_error', messages: [aff.getStorageError()] }); - } - - if (aff.hasAppUserError()) { - return API.v1.failure({ - status: 'app_user_error', - messages: [aff.getAppUserError().message], - payload: { username: aff.getAppUserError().username }, - }); - } - - info.status = aff.getApp().getStatus(); - - return API.v1.success({ - app: info, - implemented: aff.getImplementedInferfaces(), - licenseValidation: aff.getLicenseValidationResult(), - }); - }, - delete() { - const prl = manager.getOneById(this.urlParams.id); - - if (!prl) { - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - } - - const user = orchestrator.getConverters().get('users').convertToApp(Meteor.user()); - - Promise.await(manager.remove(prl.getID(), { user })); - - const info = prl.getInfo(); - info.status = prl.getStatus(); - - return API.v1.success({ app: info }); - }, - }, - ); - - this.api.addRoute( - ':id/versions', - { authRequired: true, permissionsRequired: ['manage-apps'] }, - { - async get() { - const baseUrl = orchestrator.getMarketplaceUrl(); - - const headers = {}; // DO NOT ATTACH THE FRAMEWORK/ENGINE VERSION HERE. - const token = await getWorkspaceAccessToken(); - if (token) { - headers.Authorization = `Bearer ${token}`; - } - - let result; - try { - result = HTTP.get(`${baseUrl}/v1/apps/${this.urlParams.id}`, { - headers, - }); - } catch (e) { - return handleError('Unable to access Marketplace. Does the server has access to the internet?', e); - } - - if (!result || result.statusCode !== 200) { - orchestrator.getRocketChatLogger().error('Error getting the App versions from the Marketplace:', result.data); - return API.v1.failure(); - } - - return API.v1.success({ apps: result.data }); - }, - }, - ); - - this.api.addRoute( - ':id/sync', - { authRequired: true, permissionsRequired: ['manage-apps'] }, - { - async post() { - const baseUrl = orchestrator.getMarketplaceUrl(); - - const headers = getDefaultHeaders(); - const token = await getWorkspaceAccessToken(); - if (token) { - headers.Authorization = `Bearer ${token}`; - } - - const workspaceIdSetting = await Settings.findOneById('Cloud_Workspace_Id'); - - let result; - try { - result = HTTP.get(`${baseUrl}/v1/workspaces/${workspaceIdSetting.value}/apps/${this.urlParams.id}`, { - headers, - }); - } catch (e) { - orchestrator.getRocketChatLogger().error('Error syncing the App from the Marketplace:', e.response.data); - return API.v1.internalError(); - } - - if (result.statusCode !== 200) { - orchestrator.getRocketChatLogger().error('Error syncing the App from the Marketplace:', result.data); - return API.v1.failure(); - } - - await Apps.updateAppsMarketplaceInfo([result.data]); - - return API.v1.success({ app: result.data }); - }, - }, - ); - - this.api.addRoute( - ':id/icon', - { authRequired: false }, - { - get() { - const prl = manager.getOneById(this.urlParams.id); - if (!prl) { - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - } - - const info = prl.getInfo(); - if (!info || !info.iconFileContent) { - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - } - - const imageData = info.iconFileContent.split(';base64,'); - - const buf = Buffer.from(imageData[1], 'base64'); - - return { - statusCode: 200, - headers: { - 'Content-Length': buf.length, - 'Content-Type': imageData[0].replace('data:', ''), - }, - body: buf, - }; - }, - }, - ); - - this.api.addRoute( - ':id/screenshots', - { authRequired: false }, - { - get() { - const baseUrl = orchestrator.getMarketplaceUrl(); - const appId = this.urlParams.id; - const headers = getDefaultHeaders(); - - try { - const { data } = HTTP.get(`${baseUrl}/v1/apps/${appId}/screenshots`, { headers }); - - return API.v1.success({ - screenshots: data, - }); - } catch (e) { - orchestrator.getRocketChatLogger().error('Error getting the screenshots from the Marketplace:', e.message); - return API.v1.failure(e.message); - } - }, - }, - ); - - this.api.addRoute( - ':id/languages', - { authRequired: false }, - { - get() { - const prl = manager.getOneById(this.urlParams.id); - - if (prl) { - const languages = prl.getStorageItem().languageContent || {}; - - return API.v1.success({ languages }); - } - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - }, - }, - ); - - this.api.addRoute( - ':id/logs', - { authRequired: true, permissionsRequired: ['manage-apps'] }, - { - get() { - const prl = manager.getOneById(this.urlParams.id); - - if (prl) { - const { offset, count } = this.getPaginationItems(); - const { sort, fields, query } = this.parseJsonQuery(); - - const ourQuery = Object.assign({}, query, { appId: prl.getID() }); - const options = { - sort: sort || { _updatedAt: -1 }, - skip: offset, - limit: count, - fields, - }; - - const logs = Promise.await(orchestrator.getLogStorage().find(ourQuery, options)); - - return API.v1.success({ logs }); - } - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - }, - }, - ); - - this.api.addRoute( - ':id/settings', - { authRequired: true, permissionsRequired: ['manage-apps'] }, - { - get() { - const prl = manager.getOneById(this.urlParams.id); - - if (prl) { - const settings = Object.assign({}, prl.getStorageItem().settings); - - Object.keys(settings).forEach((k) => { - if (settings[k].hidden) { - delete settings[k]; - } - }); - - return API.v1.success({ settings }); - } - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - }, - post() { - if (!this.bodyParams || !this.bodyParams.settings) { - return API.v1.failure('The settings to update must be present.'); - } - - const prl = manager.getOneById(this.urlParams.id); - - if (!prl) { - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - } - - const { settings } = prl.getStorageItem(); - - const updated = []; - this.bodyParams.settings.forEach((s) => { - if (settings[s.id]) { - Promise.await(manager.getSettingsManager().updateAppSetting(this.urlParams.id, s)); - // Updating? - updated.push(s); - } - }); - - return API.v1.success({ updated }); - }, - }, - ); - - this.api.addRoute( - ':id/settings/:settingId', - { authRequired: true, permissionsRequired: ['manage-apps'] }, - { - get() { - try { - const setting = manager.getSettingsManager().getAppSetting(this.urlParams.id, this.urlParams.settingId); - - return API.v1.success({ setting }); - } catch (e) { - if (e.message.includes('No setting found')) { - return API.v1.notFound(`No Setting found on the App by the id of: "${this.urlParams.settingId}"`); - } - if (e.message.includes('No App found')) { - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - } - return API.v1.failure(e.message); - } - }, - post() { - try { - Promise.await(updateAppSettingById(manager, this.urlParams.id, this.urlParams.settingId, this.bodyParams)); - - return API.v1.success(); - } catch (e) { - if (e.message.includes('No setting found')) { - return API.v1.notFound(`No Setting found on the App by the id of: "${this.urlParams.settingId}"`); - } - if (e.message.includes('No App found')) { - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - } - return API.v1.failure(e.message); - } - }, - }, - ); - - this.api.addRoute( - ':id/apis', - { authRequired: true, permissionsRequired: ['manage-apps'] }, - { - get() { - const prl = manager.getOneById(this.urlParams.id); - - if (prl) { - return API.v1.success({ - apis: manager.apiManager.listApis(this.urlParams.id), - }); - } - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - }, - }, - ); - - this.api.addRoute( - ':id/settings/:settingId/:agentName', - { authRequired: true, permissionsRequired: ['manage-apps'] }, - { - get() { - try { - const agentConfig = Promise.await( - getAgentConfig(manager, this.urlParams.id, this.urlParams.settingId, this.urlParams.agentName), - ); - - return API.v1.success({ agentConfig }); - } catch (e) { - if (e.message.includes('No setting found')) { - return API.v1.notFound(`No Setting found on the App by the id of: "${this.urlParams.settingId}"`); - } - if (e.message.includes('No App found')) { - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - } - if (e.message.includes('No agent found')) { - return API.v1.notFound(e.message); - } - return API.v1.failure(e.message); - } - }, - post() { - try { - Promise.await( - addAgentConfig(manager, this.urlParams.id, this.urlParams.settingId, this.urlParams.agentName, this.bodyParams.value), - ); - return API.v1.success(); - } catch (e) { - if (e.message.includes('No setting found')) { - return API.v1.notFound(`No Setting found on the App by the id of: "${this.urlParams.settingId}"`); - } - if (e.message.includes('No App found')) { - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - } - return API.v1.failure(e.message); - } - }, - put() { - try { - Promise.await( - updateAgentConfig(manager, this.urlParams.id, this.urlParams.settingId, this.urlParams.agentName, this.bodyParams.value), - ); - return API.v1.success(); - } catch (e) { - if (e.message.includes('No setting found')) { - return API.v1.notFound(`No Setting found on the App by the id of: "${this.urlParams.settingId}"`); - } - if (e.message.includes('No App found')) { - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - } - if (e.message.includes('No agent found')) { - return API.v1.notFound(e.message); - } - return API.v1.failure(e.message); - } - }, - delete() { - try { - Promise.await(deleteAgentConfig(manager, this.urlParams.id, this.urlParams.settingId, this.urlParams.agentName)); - - return API.v1.success(); - } catch (e) { - if (e.message.includes('No setting found')) { - return API.v1.notFound(`No Setting found on the App by the id of: "${this.urlParams.settingId}"`); - } - if (e.message.includes('No App found')) { - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - } - if (e.message.includes('No agent found')) { - return API.v1.notFound(e.message); - } - return API.v1.failure(e.message); - } - }, - }, - ); - - this.api.addRoute( - ':id/status', - { authRequired: true, permissionsRequired: ['manage-apps'] }, - { - get() { - const prl = manager.getOneById(this.urlParams.id); - - if (prl) { - return API.v1.success({ status: prl.getStatus() }); - } - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - }, - post() { - if (!this.bodyParams.status || typeof this.bodyParams.status !== 'string') { - return API.v1.failure('Invalid status provided, it must be "status" field and a string.'); - } - - const prl = manager.getOneById(this.urlParams.id); - - if (!prl) { - return API.v1.notFound(`No App found by the id of: ${this.urlParams.id}`); - } - - const result = Promise.await(manager.changeStatus(prl.getID(), this.bodyParams.status)); - - return API.v1.success({ status: result.getStatus() }); - }, - }, - ); - } -} diff --git a/apps/meteor/app/apps/server/converters/departments.js b/apps/meteor/app/apps/server/converters/departments.js index 3d5a76a0e1e19..0954250eb021b 100644 --- a/apps/meteor/app/apps/server/converters/departments.js +++ b/apps/meteor/app/apps/server/converters/departments.js @@ -1,5 +1,5 @@ import LivechatDepartment from '../../../models/server/models/LivechatDepartment'; -import { transformMappedData } from '../../lib/misc/transformMappedData'; +import { transformMappedData } from '../../../../ee/lib/misc/transformMappedData'; export class AppDepartmentsConverter { constructor(orch) { diff --git a/apps/meteor/app/apps/server/converters/index.js b/apps/meteor/app/apps/server/converters/index.js deleted file mode 100644 index d5fe67636dc01..0000000000000 --- a/apps/meteor/app/apps/server/converters/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import { AppMessagesConverter } from './messages'; -import { AppRoomsConverter } from './rooms'; -import { AppSettingsConverter } from './settings'; -import { AppUsersConverter } from './users'; -import { AppVideoConferencesConverter } from './videoConferences'; - -export { AppMessagesConverter, AppRoomsConverter, AppSettingsConverter, AppUsersConverter, AppVideoConferencesConverter }; diff --git a/apps/meteor/app/apps/server/converters/index.ts b/apps/meteor/app/apps/server/converters/index.ts new file mode 100644 index 0000000000000..c1f60ff181629 --- /dev/null +++ b/apps/meteor/app/apps/server/converters/index.ts @@ -0,0 +1,19 @@ +import { AppMessagesConverter } from './messages'; +import { AppRoomsConverter } from './rooms'; +import { AppSettingsConverter } from './settings'; +import { AppUsersConverter } from './users'; +import { AppVideoConferencesConverter } from './videoConferences'; +import { AppDepartmentsConverter } from './departments'; +import { AppUploadsConverter } from './uploads'; +import { AppVisitorsConverter } from './visitors'; + +export { + AppMessagesConverter, + AppRoomsConverter, + AppSettingsConverter, + AppUsersConverter, + AppVideoConferencesConverter, + AppDepartmentsConverter, + AppUploadsConverter, + AppVisitorsConverter, +}; diff --git a/apps/meteor/app/apps/server/converters/messages.js b/apps/meteor/app/apps/server/converters/messages.js index 18690597f8217..d67b5c5f75466 100644 --- a/apps/meteor/app/apps/server/converters/messages.js +++ b/apps/meteor/app/apps/server/converters/messages.js @@ -1,7 +1,7 @@ import { Random } from 'meteor/random'; import { Messages, Rooms, Users } from '../../../models/server'; -import { transformMappedData } from '../../lib/misc/transformMappedData'; +import { transformMappedData } from '../../../../ee/lib/misc/transformMappedData'; export class AppMessagesConverter { constructor(orch) { diff --git a/apps/meteor/app/apps/server/converters/rooms.js b/apps/meteor/app/apps/server/converters/rooms.js index 4a9f6225af15a..ee60db4fc29da 100644 --- a/apps/meteor/app/apps/server/converters/rooms.js +++ b/apps/meteor/app/apps/server/converters/rooms.js @@ -2,7 +2,7 @@ import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; import { LivechatVisitors } from '@rocket.chat/models'; import { Rooms, Users, LivechatDepartment } from '../../../models/server'; -import { transformMappedData } from '../../lib/misc/transformMappedData'; +import { transformMappedData } from '../../../../ee/lib/misc/transformMappedData'; export class AppRoomsConverter { constructor(orch) { diff --git a/apps/meteor/app/apps/server/converters/uploads.js b/apps/meteor/app/apps/server/converters/uploads.js index d386e52fdcac1..0d8362c03ef2f 100644 --- a/apps/meteor/app/apps/server/converters/uploads.js +++ b/apps/meteor/app/apps/server/converters/uploads.js @@ -1,6 +1,6 @@ import { Uploads } from '@rocket.chat/models'; -import { transformMappedData } from '../../lib/misc/transformMappedData'; +import { transformMappedData } from '../../../../ee/lib/misc/transformMappedData'; export class AppUploadsConverter { constructor(orch) { diff --git a/apps/meteor/app/apps/server/converters/videoConferences.ts b/apps/meteor/app/apps/server/converters/videoConferences.ts index 77bc25e4cbe7b..0b0c0a573b76c 100644 --- a/apps/meteor/app/apps/server/converters/videoConferences.ts +++ b/apps/meteor/app/apps/server/converters/videoConferences.ts @@ -1,7 +1,6 @@ import type { VideoConference } from '@rocket.chat/apps-engine/definition/videoConferences'; import type { IVideoConference } from '@rocket.chat/core-typings'; - -import { VideoConf } from '../../../../server/sdk'; +import { VideoConf } from '@rocket.chat/core-services'; export class AppVideoConferencesConverter { async convertById(callId: string): Promise { diff --git a/apps/meteor/app/apps/server/converters/visitors.js b/apps/meteor/app/apps/server/converters/visitors.js index 361aa3758c6ae..e54b7db257e54 100644 --- a/apps/meteor/app/apps/server/converters/visitors.js +++ b/apps/meteor/app/apps/server/converters/visitors.js @@ -1,6 +1,6 @@ import { LivechatVisitors } from '@rocket.chat/models'; -import { transformMappedData } from '../../lib/misc/transformMappedData'; +import { transformMappedData } from '../../../../ee/lib/misc/transformMappedData'; // TODO: check if functions from this converter can be async export class AppVisitorsConverter { diff --git a/apps/meteor/app/apps/server/index.js b/apps/meteor/app/apps/server/index.js deleted file mode 100644 index 7b2e9d4101cff..0000000000000 --- a/apps/meteor/app/apps/server/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import './cron'; -import './status.ts'; - -export { Apps, AppEvents } from './orchestrator'; -export { LivechatNotifications } from './communication'; diff --git a/apps/meteor/app/apps/server/status.ts b/apps/meteor/app/apps/server/status.ts deleted file mode 100644 index 3dd020df92efc..0000000000000 --- a/apps/meteor/app/apps/server/status.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { UserPresenceMonitor } from 'meteor/konecty:user-presence'; - -import { AppEvents, Apps } from './orchestrator'; - -UserPresenceMonitor.onSetUserStatus((...args: any) => { - const [user, status] = args; - - // App IPostUserStatusChanged event hook - Promise.await( - Apps.triggerEvent(AppEvents.IPostUserStatusChanged, { - user, - currentStatus: status, - previousStatus: user.status, - }), - ); -}); diff --git a/apps/meteor/app/assets/server/assets.ts b/apps/meteor/app/assets/server/assets.ts index d3b618e14ca90..cd6a3736c7267 100644 --- a/apps/meteor/app/assets/server/assets.ts +++ b/apps/meteor/app/assets/server/assets.ts @@ -16,6 +16,7 @@ import { getURL } from '../../utils/lib/getURL'; import { getExtension } from '../../utils/lib/mimeTypes'; import { hasPermission } from '../../authorization/server'; import { RocketChatFile } from '../../file'; +import { methodDeprecationLogger } from '../../lib/server/lib/deprecationWarningLogger'; const RocketChatAssetsInstance = new RocketChatFile.GridFS({ name: 'assets', @@ -33,6 +34,14 @@ const assets: IRocketChatAssets = { order: 2, }, }, + logo_dark: { + label: 'logo - dark theme (svg, png, jpg)', + defaultUrl: 'images/logo/logo_dark.svg', + constraints: { + type: 'image', + extensions: ['svg', 'png', 'jpg', 'jpeg'], + }, + }, background: { label: 'login background (svg, png, jpg)', constraints: { @@ -40,6 +49,13 @@ const assets: IRocketChatAssets = { extensions: ['svg', 'png', 'jpg', 'jpeg'], }, }, + background_dark: { + label: 'login background - dark theme (svg, png, jpg)', + constraints: { + type: 'image', + extensions: ['svg', 'png', 'jpg', 'jpeg'], + }, + }, favicon_ico: { label: 'favicon (ico)', defaultUrl: 'favicon.ico', @@ -429,6 +445,8 @@ WebAppHashing.calculateClientHash = function (manifest, includeFilter, runtimeCo Meteor.methods({ refreshClients() { + methodDeprecationLogger.warn('refreshClients will be deprecated in future versions of Rocket.Chat'); + if (!Meteor.userId()) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'refreshClients', diff --git a/apps/meteor/app/authentication/server/startup/index.js b/apps/meteor/app/authentication/server/startup/index.js index 536117e232d09..5fd8b84025fa1 100644 --- a/apps/meteor/app/authentication/server/startup/index.js +++ b/apps/meteor/app/authentication/server/startup/index.js @@ -17,8 +17,9 @@ import { isValidAttemptByUser, isValidLoginAttemptByIp } from '../lib/restrictLo import './settings'; import { getClientAddress } from '../../../../server/lib/getClientAddress'; import { getNewUserRoles } from '../../../../server/services/user/lib/getNewUserRoles'; -import { AppEvents, Apps } from '../../../apps/server/orchestrator'; +import { AppEvents, Apps } from '../../../../ee/server/apps/orchestrator'; import { safeGetMeteorUser } from '../../../utils/server/functions/safeGetMeteorUser'; +import { safeHtmlDots } from '../../../../lib/utils/safeHtmlDots'; Accounts.config({ forbidClientAccountCreation: true, @@ -91,7 +92,9 @@ Meteor.startup(() => { }); Accounts.emailTemplates.verifyEmail.html = function (userModel, url) { - return Mailer.replace(verifyEmailTemplate, { Verification_Url: url, name: userModel.name }); + const name = safeHtmlDots(userModel.name); + + return Mailer.replace(verifyEmailTemplate, { Verification_Url: url, name }); }; Accounts.emailTemplates.verifyEmail.subject = function () { @@ -205,7 +208,11 @@ Accounts.onCreateUser(function (options, user = {}) { to: destinations, from: settings.get('From_Email'), subject: Accounts.emailTemplates.userToActivate.subject(), - html: Accounts.emailTemplates.userToActivate.html(options), + html: Accounts.emailTemplates.userToActivate.html({ + ...options, + name: options.name || options.profile?.name, + email: options.email || user.emails[0].address, + }), }; Mailer.send(email); @@ -414,12 +421,14 @@ Accounts.validateNewUser(function (user) { export const MAX_RESUME_LOGIN_TOKENS = parseInt(process.env.MAX_RESUME_LOGIN_TOKENS) || 50; Accounts.onLogin(async ({ user }) => { - if (!user || !user.services || !user.services.resume || !user.services.resume.loginTokens) { + if (!user || !user.services || !user.services.resume || !user.services.resume.loginTokens || !user._id) { return; } + if (user.services.resume.loginTokens.length < MAX_RESUME_LOGIN_TOKENS) { return; } + const { tokens } = (await UsersRaw.findAllResumeTokensByUserId(user._id))[0]; if (tokens.length >= MAX_RESUME_LOGIN_TOKENS) { const oldestDate = tokens.reverse()[MAX_RESUME_LOGIN_TOKENS - 1]; diff --git a/apps/meteor/app/authorization/client/hasPermission.ts b/apps/meteor/app/authorization/client/hasPermission.ts index a0d6a2fe63b49..cac0c20f3f1f4 100644 --- a/apps/meteor/app/authorization/client/hasPermission.ts +++ b/apps/meteor/app/authorization/client/hasPermission.ts @@ -5,7 +5,13 @@ import { ChatPermissions } from './lib/ChatPermissions'; import * as Models from '../../models/client'; import { AuthorizationUtils } from '../lib/AuthorizationUtils'; -const isValidScope = (scope: IRole['scope']): boolean => typeof scope === 'string' && scope in Models; +const isValidScope = (scope: unknown): scope is keyof typeof Models => typeof scope === 'string' && scope in Models; + +const hasIsUserInRole = ( + model: unknown, +): model is { + isUserInRole: (this: any, uid: IUser['_id'], roleId: IRole['_id'], scope: string | undefined) => boolean; +} => typeof model === 'object' && model !== null && typeof (model as { isUserInRole?: unknown }).isUserInRole === 'function'; const createPermissionValidator = (quantifier: (predicate: (permissionId: IPermission['_id']) => boolean) => boolean) => @@ -21,7 +27,7 @@ const createPermissionValidator = } } - const permission: IPermission | null = ChatPermissions.findOne(permissionId, { + const permission = ChatPermissions.findOne(permissionId, { fields: { roles: 1 }, }); const roles = permission?.roles ?? []; @@ -34,8 +40,13 @@ const createPermissionValidator = return false; } - const model = Models[roleScope as keyof typeof Models]; - return model.isUserInRole?.(userId, roleId, scope); + const model = Models[roleScope]; + + if (hasIsUserInRole(model)) { + return model.isUserInRole(userId, roleId, scope); + } + + return undefined; }); }); }; diff --git a/apps/meteor/app/authorization/client/index.ts b/apps/meteor/app/authorization/client/index.ts index ea320d1601f28..f3e227202a89c 100644 --- a/apps/meteor/app/authorization/client/index.ts +++ b/apps/meteor/app/authorization/client/index.ts @@ -1,7 +1,6 @@ import { hasAllPermission, hasAtLeastOnePermission, hasPermission, userHasAllPermission } from './hasPermission'; import { hasRole, hasAnyRole } from './hasRole'; import { AuthorizationUtils } from '../lib/AuthorizationUtils'; -import './requiresPermission.html'; import './startup'; export { hasAllPermission, hasAtLeastOnePermission, hasRole, hasAnyRole, hasPermission, userHasAllPermission, AuthorizationUtils }; diff --git a/apps/meteor/app/authorization/client/requiresPermission.html b/apps/meteor/app/authorization/client/requiresPermission.html deleted file mode 100644 index db71b5643888d..0000000000000 --- a/apps/meteor/app/authorization/client/requiresPermission.html +++ /dev/null @@ -1,11 +0,0 @@ - diff --git a/apps/meteor/app/authorization/client/startup.js b/apps/meteor/app/authorization/client/startup.js index 6a7d79cb79cc5..d004e69205182 100644 --- a/apps/meteor/app/authorization/client/startup.js +++ b/apps/meteor/app/authorization/client/startup.js @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; import { Tracker } from 'meteor/tracker'; -import { CachedCollectionManager } from '../../ui-cached-collection'; +import { CachedCollectionManager } from '../../ui-cached-collection/client'; import { APIClient } from '../../utils/client/lib/RestApiClient'; import { Roles } from '../../models/client'; import { rolesStreamer } from './lib/streamer'; diff --git a/apps/meteor/app/authorization/lib/index.js b/apps/meteor/app/authorization/lib/index.js deleted file mode 100644 index 043e5a4beda2f..0000000000000 --- a/apps/meteor/app/authorization/lib/index.js +++ /dev/null @@ -1,10 +0,0 @@ -export const getSettingPermissionId = function (settingId) { - // setting-based permissions - return `change-setting-${settingId}`; -}; - -export const CONSTANTS = { - SETTINGS_LEVEL: 'settings', -}; - -export { AuthorizationUtils } from './AuthorizationUtils'; diff --git a/apps/meteor/app/authorization/lib/index.ts b/apps/meteor/app/authorization/lib/index.ts new file mode 100644 index 0000000000000..8e2a37a64138a --- /dev/null +++ b/apps/meteor/app/authorization/lib/index.ts @@ -0,0 +1,12 @@ +import type { ISetting } from '@rocket.chat/core-typings'; + +export const getSettingPermissionId = function (settingId: ISetting['_id']) { + // setting-based permissions + return `change-setting-${settingId}`; +}; + +export const CONSTANTS = { + SETTINGS_LEVEL: 'settings', +} as const; + +export { AuthorizationUtils } from './AuthorizationUtils'; diff --git a/apps/meteor/app/authorization/server/functions/canAccessRoom.ts b/apps/meteor/app/authorization/server/functions/canAccessRoom.ts index d82bed560d145..cd264e0ec7b52 100644 --- a/apps/meteor/app/authorization/server/functions/canAccessRoom.ts +++ b/apps/meteor/app/authorization/server/functions/canAccessRoom.ts @@ -1,5 +1,5 @@ -import { Authorization } from '../../../../server/sdk'; -import type { IAuthorization } from '../../../../server/sdk/types/IAuthorization'; +import { Authorization } from '@rocket.chat/core-services'; +import type { IAuthorization } from '@rocket.chat/core-services'; export const canAccessRoomAsync = Authorization.canAccessRoom; export const canAccessRoomIdAsync = Authorization.canAccessRoomId; diff --git a/apps/meteor/app/authorization/server/functions/canDeleteMessage.ts b/apps/meteor/app/authorization/server/functions/canDeleteMessage.ts index 8ffb33958c26b..8c1786853dee4 100644 --- a/apps/meteor/app/authorization/server/functions/canDeleteMessage.ts +++ b/apps/meteor/app/authorization/server/functions/canDeleteMessage.ts @@ -31,11 +31,15 @@ export const canDeleteMessageAsync = async (uid: string, { u, rid, ts }: { u: IU if (!allowed) { return false; } - const blockDeleteInMinutes = await getValue('Message_AllowDeleting_BlockDeleteInMinutes'); + const bypassBlockTimeLimit = await hasPermissionAsync(uid, 'bypass-time-limit-edit-and-delete'); - if (blockDeleteInMinutes) { - const timeElapsedForMessage = elapsedTime(ts); - return timeElapsedForMessage <= blockDeleteInMinutes; + if (!bypassBlockTimeLimit) { + const blockDeleteInMinutes = await getValue('Message_AllowDeleting_BlockDeleteInMinutes'); + + if (blockDeleteInMinutes) { + const timeElapsedForMessage = elapsedTime(ts); + return timeElapsedForMessage <= blockDeleteInMinutes; + } } const room = await Rooms.findOneById(rid, { fields: { ro: 1, unmuted: 1 } }); diff --git a/apps/meteor/app/authorization/server/functions/canSendMessage.ts b/apps/meteor/app/authorization/server/functions/canSendMessage.ts index 6b962fbda47c5..d96ed3c56d963 100644 --- a/apps/meteor/app/authorization/server/functions/canSendMessage.ts +++ b/apps/meteor/app/authorization/server/functions/canSendMessage.ts @@ -16,7 +16,7 @@ const subscriptionOptions = { async function validateRoomMessagePermissionsAsync( room: IRoom | null, { uid, username, type }: { uid: IUser['_id']; username: IUser['username']; type: IUser['type'] }, - extraData: Record, + extraData?: Record, ): Promise { if (!room) { throw new Error('error-invalid-room'); @@ -26,7 +26,7 @@ async function validateRoomMessagePermissionsAsync( throw new Error('error-not-allowed'); } - if (roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.BLOCK)) { + if (roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.BLOCK, uid)) { const subscription = await Subscriptions.findOneByRoomIdAndUserId(room._id, uid, subscriptionOptions); if (subscription && (subscription.blocked || subscription.blocker)) { throw new Error('room_is_blocked'); @@ -48,7 +48,7 @@ async function validateRoomMessagePermissionsAsync( export async function canSendMessageAsync( rid: IRoom['_id'], { uid, username, type }: { uid: IUser['_id']; username: IUser['username']; type: IUser['type'] }, - extraData: Record, + extraData?: Record, ): Promise { const room = await Rooms.findOneById(rid); if (!room) { @@ -62,14 +62,14 @@ export async function canSendMessageAsync( export function canSendMessage( rid: IRoom['_id'], { uid, username, type }: { uid: IUser['_id']; username: IUser['username']; type: IUser['type'] }, - extraData: Record, + extraData?: Record, ): IRoom { return Promise.await(canSendMessageAsync(rid, { uid, username, type }, extraData)); } export function validateRoomMessagePermissions( room: IRoom, { uid, username, type }: { uid: IUser['_id']; username: IUser['username']; type: IUser['type'] }, - extraData: Record, + extraData?: Record, ): void { return Promise.await(validateRoomMessagePermissionsAsync(room, { uid, username, type }, extraData)); } diff --git a/apps/meteor/app/authorization/server/functions/hasPermission.ts b/apps/meteor/app/authorization/server/functions/hasPermission.ts index ae7edd333e9fc..41b5fb051ca28 100644 --- a/apps/meteor/app/authorization/server/functions/hasPermission.ts +++ b/apps/meteor/app/authorization/server/functions/hasPermission.ts @@ -1,6 +1,5 @@ import type { IUser, IPermission, IRoom } from '@rocket.chat/core-typings'; - -import { Authorization } from '../../../../server/sdk'; +import { Authorization } from '@rocket.chat/core-services'; export const hasAllPermissionAsync = async ( userId: IUser['_id'], diff --git a/apps/meteor/app/authorization/server/functions/upsertPermissions.ts b/apps/meteor/app/authorization/server/functions/upsertPermissions.ts index 3be452c5ca58e..d335b0de8ef63 100644 --- a/apps/meteor/app/authorization/server/functions/upsertPermissions.ts +++ b/apps/meteor/app/authorization/server/functions/upsertPermissions.ts @@ -117,7 +117,7 @@ export const upsertPermissions = async (): Promise => { _id: 'on-hold-others-livechat-room', roles: ['livechat-manager', 'livechat-monitor', 'admin'], }, - { _id: 'save-others-livechat-room-info', roles: ['livechat-manager', 'livechat-monitor'] }, + { _id: 'save-others-livechat-room-info', roles: ['livechat-manager', 'livechat-monitor', 'admin'] }, { _id: 'remove-closed-livechat-rooms', roles: ['livechat-manager', 'livechat-monitor', 'admin'], @@ -152,7 +152,6 @@ export const upsertPermissions = async (): Promise => { { _id: 'view-livechat-installation', roles: ['livechat-manager', 'admin'] }, { _id: 'view-livechat-appearance', roles: ['livechat-manager', 'admin'] }, { _id: 'view-livechat-webhooks', roles: ['livechat-manager', 'admin'] }, - { _id: 'view-livechat-facebook', roles: ['livechat-manager', 'admin'] }, { _id: 'view-livechat-business-hours', roles: ['livechat-manager', 'livechat-monitor', 'admin'], @@ -210,7 +209,6 @@ export const upsertPermissions = async (): Promise => { { _id: 'manage-sounds', roles: ['admin'] }, { _id: 'access-mailer', roles: ['admin'] }, { _id: 'pin-message', roles: ['owner', 'moderator', 'admin'] }, - { _id: 'snippet-message', roles: ['owner', 'moderator', 'admin'] }, { _id: 'mobile-upload-file', roles: ['user', 'admin'] }, { _id: 'send-mail', roles: ['admin'] }, { _id: 'view-federation-data', roles: ['admin'] }, @@ -219,12 +217,12 @@ export const upsertPermissions = async (): Promise => { { _id: 'register-on-cloud', roles: ['admin'] }, { _id: 'test-admin-options', roles: ['admin'] }, { _id: 'sync-auth-services-users', roles: ['admin'] }, - { _id: 'manage-chatpal', roles: ['admin'] }, { _id: 'restart-server', roles: ['admin'] }, { _id: 'remove-slackbridge-links', roles: ['admin'] }, { _id: 'view-import-operations', roles: ['admin'] }, { _id: 'clear-oembed-cache', roles: ['admin'] }, { _id: 'videoconf-ring-users', roles: ['admin', 'owner', 'moderator', 'user'] }, + { _id: 'bypass-time-limit-edit-and-delete', roles: ['bot', 'app'] }, ]; for await (const permission of permissions) { @@ -269,12 +267,12 @@ export const upsertPermissions = async (): Promise => { }, ): Promise { const permissionId = getSettingPermissionId(setting._id); - const permission: Omit = { + const permission: Omit = { level: CONSTANTS.SETTINGS_LEVEL as 'settings' | undefined, // copy those setting-properties which are needed to properly publish the setting-based permissions settingId: setting._id, group: setting.group, - section: setting.section, + section: setting.section ?? undefined, sorter: setting.sorter, roles: [], }; diff --git a/apps/meteor/app/authorization/server/index.js b/apps/meteor/app/authorization/server/index.js index b43cbeabc51df..d334474f86b76 100644 --- a/apps/meteor/app/authorization/server/index.js +++ b/apps/meteor/app/authorization/server/index.js @@ -10,7 +10,6 @@ import './methods/addUserToRole'; import './methods/deleteRole'; import './methods/removeRoleFromPermission'; import './methods/removeUserFromRole'; -import './methods/saveRole'; import './streamer/permissions'; export { diff --git a/apps/meteor/app/authorization/server/methods/addUserToRole.ts b/apps/meteor/app/authorization/server/methods/addUserToRole.ts index c33f950e0dbcf..4e6c4e3535f13 100644 --- a/apps/meteor/app/authorization/server/methods/addUserToRole.ts +++ b/apps/meteor/app/authorization/server/methods/addUserToRole.ts @@ -1,12 +1,11 @@ import { Meteor } from 'meteor/meteor'; -import _ from 'underscore'; import type { IRole, IUser, IRoom } from '@rocket.chat/core-typings'; import { Roles } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; import { Users } from '../../../models/server'; import { settings } from '../../../settings/server'; import { hasPermission } from '../functions/hasPermission'; -import { api } from '../../../../server/sdk/api'; import { apiDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ @@ -20,7 +19,7 @@ Meteor.methods({ }); } - if (!roleId || !_.isString(roleId) || !username || !_.isString(username)) { + if (!roleId || typeof roleId.valueOf() !== 'string' || !username || typeof username.valueOf() !== 'string') { throw new Meteor.Error('error-invalid-arguments', 'Invalid arguments', { method: 'authorization:addUserToRole', }); diff --git a/apps/meteor/app/authorization/server/methods/removeUserFromRole.ts b/apps/meteor/app/authorization/server/methods/removeUserFromRole.ts index 3eeda9c2c84ee..fea457dff7e07 100644 --- a/apps/meteor/app/authorization/server/methods/removeUserFromRole.ts +++ b/apps/meteor/app/authorization/server/methods/removeUserFromRole.ts @@ -1,12 +1,11 @@ import { Meteor } from 'meteor/meteor'; -import _ from 'underscore'; import type { IRole, IUser } from '@rocket.chat/core-typings'; import { Roles } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; import { Users } from '../../../models/server'; import { settings } from '../../../settings/server'; import { hasPermission } from '../functions/hasPermission'; -import { api } from '../../../../server/sdk/api'; import { apiDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ @@ -20,7 +19,7 @@ Meteor.methods({ }); } - if (!roleId || !_.isString(roleId) || !username || !_.isString(username)) { + if (!roleId || typeof roleId.valueOf() !== 'string' || !username || typeof username.valueOf() !== 'string') { throw new Meteor.Error('error-invalid-arguments', 'Invalid arguments', { method: 'authorization:removeUserFromRole', }); @@ -73,17 +72,19 @@ Meteor.methods({ } const remove = await Roles.removeUserRoles(user._id, [role._id], scope); + const event = { + type: 'removed', + _id: role._id, + u: { + _id: user._id, + username, + }, + scope, + }; if (settings.get('UI_DisplayRoles')) { - api.broadcast('user.roleUpdate', { - type: 'removed', - _id: role._id, - u: { - _id: user._id, - username, - }, - scope, - }); + api.broadcast('user.roleUpdate', event); } + api.broadcast('federation.userRoleChanged', { ...event, givenByUserId: userId }); return remove; }, diff --git a/apps/meteor/app/authorization/server/methods/saveRole.ts b/apps/meteor/app/authorization/server/methods/saveRole.ts deleted file mode 100644 index 9eb19298f7f79..0000000000000 --- a/apps/meteor/app/authorization/server/methods/saveRole.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { isRoleCreateProps } from '@rocket.chat/rest-typings'; -import { Roles } from '@rocket.chat/models'; - -import { settings } from '../../../settings/server'; -import { hasPermission } from '../functions/hasPermission'; -import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; -import { updateRoleAsync } from '../../../../server/lib/roles/updateRole'; -import { insertRoleAsync } from '../../../../server/lib/roles/insertRole'; - -Meteor.methods({ - async 'authorization:saveRole'(roleData: Record) { - methodDeprecationLogger.warn('authorization:saveRole will be deprecated in future versions of Rocket.Chat'); - const userId = Meteor.userId(); - - if (!isRoleCreateProps(roleData)) { - throw new Meteor.Error('error-invalid-role-properties', 'The role properties are invalid.', { - method: 'authorization:saveRole', - }); - } - - if (!userId || !hasPermission(userId, 'access-permissions')) { - throw new Meteor.Error('error-action-not-allowed', 'Accessing permissions is not allowed', { - method: 'authorization:saveRole', - action: 'Accessing_permissions', - }); - } - - const role = { - description: roleData.description || '', - ...(roleData.mandatory2fa !== undefined && { mandatory2fa: roleData.mandatory2fa }), - name: roleData.name, - scope: roleData.scope || 'Users', - protected: false, - }; - - const existingRole = await Roles.findOneByName(roleData.name, { projection: { _id: 1 } }); - const options = { - broadcastUpdate: settings.get('UI_DisplayRoles'), - }; - - if (existingRole) { - return updateRoleAsync(existingRole._id, role, options); - } - - return insertRoleAsync(role); - }, -}); diff --git a/apps/meteor/app/autolinker/client/client.js b/apps/meteor/app/autolinker/client/client.js deleted file mode 100644 index a3e6d77d3e218..0000000000000 --- a/apps/meteor/app/autolinker/client/client.js +++ /dev/null @@ -1,58 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Random } from 'meteor/random'; -import Autolinker from 'autolinker'; -import { escapeRegExp } from '@rocket.chat/string-helpers'; - -export const createAutolinkerMessageRenderer = - ({ phone, ...config }) => - (message) => { - if (!message.html?.trim()) { - return message; - } - - let msgParts; - let regexTokens; - if (message.tokens && message.tokens.length) { - regexTokens = new RegExp(`(${(message.tokens || []).map(({ token }) => escapeRegExp(token))})`, 'g'); - msgParts = message.html.split(regexTokens); - } else { - msgParts = [message.html]; - } - - message.html = msgParts - .map((msgPart) => { - if (regexTokens && regexTokens.test(msgPart)) { - return msgPart; - } - - const muttableConfig = { - ...config, - phone: false, - stripTrailingSlash: false, - replaceFn: (match) => { - const token = `=!=${Random.id()}=!=`; - const tag = match.buildTag(); - - if (~match.matchedText.indexOf(Meteor.absoluteUrl())) { - tag.setAttr('target', ''); - } - - message.tokens = message.tokens ?? []; - message.tokens.push({ - token, - text: tag.toAnchorString(), - }); - return token; - }, - }; - - const autolinkerMsg = Autolinker.link(msgPart, muttableConfig); - - muttableConfig.phone = phone; - - return phone ? Autolinker.link(autolinkerMsg, muttableConfig) : autolinkerMsg; - }) - .join(''); - - return message; - }; diff --git a/apps/meteor/app/autolinker/client/index.js b/apps/meteor/app/autolinker/client/index.js deleted file mode 100644 index 4dbc401112536..0000000000000 --- a/apps/meteor/app/autolinker/client/index.js +++ /dev/null @@ -1 +0,0 @@ -export { createAutolinkerMessageRenderer } from './client'; diff --git a/apps/meteor/app/autolinker/server/settings.ts b/apps/meteor/app/autolinker/server/settings.ts deleted file mode 100644 index f655c669a5101..0000000000000 --- a/apps/meteor/app/autolinker/server/settings.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { settingsRegistry } from '../../settings/server'; - -Meteor.startup(function () { - const enableQuery = { - _id: 'AutoLinker', - value: true, - }; - - settingsRegistry.add('AutoLinker', true, { - type: 'boolean', - group: 'Message', - section: 'AutoLinker', - public: true, - i18nLabel: 'Enabled', - }); - - settingsRegistry.add('AutoLinker_StripPrefix', false, { - type: 'boolean', - group: 'Message', - section: 'AutoLinker', - public: true, - i18nDescription: 'AutoLinker_StripPrefix_Description', - enableQuery, - }); - settingsRegistry.add('AutoLinker_Urls_Scheme', true, { - type: 'boolean', - group: 'Message', - section: 'AutoLinker', - public: true, - enableQuery, - }); - settingsRegistry.add('AutoLinker_Urls_www', true, { - type: 'boolean', - group: 'Message', - section: 'AutoLinker', - public: true, - enableQuery, - }); - settingsRegistry.add('AutoLinker_Urls_TLD', true, { - type: 'boolean', - group: 'Message', - section: 'AutoLinker', - public: true, - enableQuery, - }); - settingsRegistry.add('AutoLinker_UrlsRegExp', '(://|www\\.).+', { - type: 'string', - group: 'Message', - section: 'AutoLinker', - public: true, - enableQuery, - }); - settingsRegistry.add('AutoLinker_Email', true, { - type: 'boolean', - group: 'Message', - section: 'AutoLinker', - public: true, - enableQuery, - }); - settingsRegistry.add('AutoLinker_Phone', true, { - type: 'boolean', - group: 'Message', - section: 'AutoLinker', - public: true, - i18nDescription: 'AutoLinker_Phone_Description', - enableQuery, - }); -}); diff --git a/apps/meteor/app/autotranslate/client/lib/actionButton.ts b/apps/meteor/app/autotranslate/client/lib/actionButton.ts index 0d742d68f9ab1..e30b8a05909da 100644 --- a/apps/meteor/app/autotranslate/client/lib/actionButton.ts +++ b/apps/meteor/app/autotranslate/client/lib/actionButton.ts @@ -1,6 +1,5 @@ import { Meteor } from 'meteor/meteor'; import { Tracker } from 'meteor/tracker'; -import { isTranslatedMessage } from '@rocket.chat/core-typings'; import { AutoTranslate } from './autotranslate'; import { settings } from '../../../settings/client'; @@ -8,6 +7,11 @@ import { hasAtLeastOnePermission } from '../../../authorization/client'; import { MessageAction } from '../../../ui-utils/client/lib/MessageAction'; import { messageArgs } from '../../../../client/lib/utils/messageArgs'; import { Messages } from '../../../models/client'; +import { + hasTranslationLanguageInAttachments, + hasTranslationLanguageInMessage, +} from '../../../../client/views/room/MessageList/lib/autoTranslate'; +import { roomCoordinator } from '../../../../client/lib/rooms/roomCoordinator'; Meteor.startup(() => { AutoTranslate.init(); @@ -22,8 +26,7 @@ Meteor.startup(() => { action(_, props) { const { message = messageArgs(this).msg } = props; const language = AutoTranslate.getLanguage(message.rid); - if (!isTranslatedMessage(message) || !message.translations[language]) { - // } && !_.find(message.attachments, attachment => { return attachment.translations && attachment.translations[language]; })) { + if (!hasTranslationLanguageInMessage(message, language) && !hasTranslationLanguageInAttachments(message.attachments, language)) { (AutoTranslate.messageIdsToWait as any)[message._id] = true; Messages.update({ _id: message._id }, { $set: { autoTranslateFetching: true } }); Meteor.call('autoTranslate.translateMessage', message, language); @@ -31,8 +34,21 @@ Meteor.startup(() => { const action = 'autoTranslateShowInverse' in message ? '$unset' : '$set'; Messages.update({ _id: message._id }, { [action]: { autoTranslateShowInverse: true } }); }, - condition({ message, user }) { - return Boolean(message?.u && message.u._id !== user._id && isTranslatedMessage(message) && message.autoTranslateShowInverse); + condition({ message, subscription, user, room }) { + if (!user) { + return false; + } + const language = subscription?.autoTranslateLanguage || AutoTranslate.getLanguage(message.rid) || ''; + const isLivechatRoom = roomCoordinator.isLivechatRoom(room?.t); + const isDifferentUser = message?.u && message.u._id !== user._id; + const autoTranslateEnabled = subscription?.autoTranslate || isLivechatRoom; + const hasLanguage = + hasTranslationLanguageInMessage(message, language) || hasTranslationLanguageInAttachments(message.attachments, language); + + return Boolean( + (message as { autoTranslateShowInverse?: boolean }).autoTranslateShowInverse || + (isDifferentUser && autoTranslateEnabled && !hasLanguage), + ); }, order: 90, }); @@ -44,8 +60,7 @@ Meteor.startup(() => { action(_, props) { const { message = messageArgs(this).msg } = props; const language = AutoTranslate.getLanguage(message.rid); - if (!isTranslatedMessage(message) || !message.translations[language]) { - // } && !_.find(message.attachments, attachment => { return attachment.translations && attachment.translations[language]; })) { + if (!hasTranslationLanguageInMessage(message, language) && !hasTranslationLanguageInAttachments(message.attachments, language)) { (AutoTranslate.messageIdsToWait as any)[message._id] = true; Messages.update({ _id: message._id }, { $set: { autoTranslateFetching: true } }); Meteor.call('autoTranslate.translateMessage', message, language); @@ -53,8 +68,23 @@ Meteor.startup(() => { const action = 'autoTranslateShowInverse' in message ? '$unset' : '$set'; Messages.update({ _id: message._id }, { [action]: { autoTranslateShowInverse: true } }); }, - condition({ message, user }) { - return Boolean(message?.u && message.u._id !== user._id && isTranslatedMessage(message) && !message.autoTranslateShowInverse); + condition({ message, subscription, user, room }) { + const language = subscription?.autoTranslateLanguage || AutoTranslate.getLanguage(message.rid) || ''; + const isLivechatRoom = roomCoordinator.isLivechatRoom(room?.t); + if (!user) { + return false; + } + const isDifferentUser = message?.u && message.u._id !== user._id; + const autoTranslateEnabled = subscription?.autoTranslate || isLivechatRoom; + const hasLanguage = + hasTranslationLanguageInMessage(message, language) || hasTranslationLanguageInAttachments(message.attachments, language); + + return Boolean( + !(message as { autoTranslateShowInverse?: boolean }).autoTranslateShowInverse && + isDifferentUser && + autoTranslateEnabled && + hasLanguage, + ); }, order: 90, }); diff --git a/apps/meteor/app/autotranslate/client/lib/autotranslate.ts b/apps/meteor/app/autotranslate/client/lib/autotranslate.ts index 71ff7cc92c5a9..199df2e5db71f 100644 --- a/apps/meteor/app/autotranslate/client/lib/autotranslate.ts +++ b/apps/meteor/app/autotranslate/client/lib/autotranslate.ts @@ -9,10 +9,15 @@ import type { IUser, MessageAttachmentDefault, } from '@rocket.chat/core-typings'; +import { isTranslatedMessageAttachment } from '@rocket.chat/core-typings'; import { Subscriptions, Messages } from '../../../models/client'; import { hasPermission } from '../../../authorization/client'; import { call } from '../../../../client/lib/utils/call'; +import { + hasTranslationLanguageInAttachments, + hasTranslationLanguageInMessage, +} from '../../../../client/views/room/MessageList/lib/autoTranslate'; let userLanguage = 'en'; let username = ''; @@ -55,6 +60,9 @@ export const AutoTranslate = { language: string, autoTranslateShowInverse: boolean, ): MessageAttachmentDefault[] { + if (!isTranslatedMessageAttachment(attachments)) { + return attachments; + } for (const attachment of attachments) { if (attachment.author_name !== username) { if (attachment.text && attachment.translations && attachment.translations[language]) { @@ -134,16 +142,11 @@ export const createAutoTranslateMessageRenderer = (): ((message: ITranslatedMess message.translations = {}; } if (!!subscription?.autoTranslate !== !!message.autoTranslateShowInverse) { - const hasAttachmentsTranslate = - message.attachments?.some( - (attachment) => - 'translations' in attachment && - typeof attachment.translations === 'object' && - autoTranslateLanguage in attachment.translations, - ) ?? false; - message.translations.original = message.html; - if (message.translations[autoTranslateLanguage] && !hasAttachmentsTranslate) { + if ( + message.translations[autoTranslateLanguage] && + !hasTranslationLanguageInAttachments(message.attachments, autoTranslateLanguage) + ) { message.html = message.translations[autoTranslateLanguage]; } @@ -155,12 +158,6 @@ export const createAutoTranslateMessageRenderer = (): ((message: ITranslatedMess ); } } - } else if (message.attachments && message.attachments.length > 0) { - message.attachments = AutoTranslate.translateAttachments( - message.attachments, - autoTranslateLanguage, - !!message.autoTranslateShowInverse, - ); } return message; }; @@ -177,7 +174,8 @@ export const createAutoTranslateMessageStreamHandler = (): ((message: ITranslate subscription && subscription.autoTranslate === true && message.msg && - (!message.translations || !message.translations[language]) + (!message.translations || + (!hasTranslationLanguageInMessage(message, language) && !hasTranslationLanguageInAttachments(message.attachments, language))) ) { // || (message.attachments && !_.find(message.attachments, attachment => { return attachment.translations && attachment.translations[language]; })) Messages.update({ _id: message._id }, { $set: { autoTranslateFetching: true } }); diff --git a/apps/meteor/app/autotranslate/server/autotranslate.ts b/apps/meteor/app/autotranslate/server/autotranslate.ts index 8566cdd18e4a6..9ade9beaa0ef6 100644 --- a/apps/meteor/app/autotranslate/server/autotranslate.ts +++ b/apps/meteor/app/autotranslate/server/autotranslate.ts @@ -67,7 +67,7 @@ export class TranslationProviderRegistry { return TranslationProviderRegistry.enabled ? TranslationProviderRegistry.getActiveProvider()?.getSupportedLanguages(target) : undefined; } - static translateMessage(message: IMessage, room: IRoom, targetLanguage: string): IMessage | undefined { + static translateMessage(message: IMessage, room: IRoom, targetLanguage?: string): IMessage | undefined { return TranslationProviderRegistry.enabled ? TranslationProviderRegistry.getActiveProvider()?.translateMessage(message, room, targetLanguage) : undefined; @@ -165,7 +165,7 @@ export abstract class AutoTranslate { tokenizeURLs(message: IMessage): IMessage { let count = message.tokens?.length || 0; - const schemes = settings.get('Markdown_SupportSchemesForLink')?.split(',').join('|'); + const schemes = 'http,https'; // Support ![alt text](http://image url) and [text](http://link) message.msg = message.msg.replace( @@ -281,7 +281,7 @@ export abstract class AutoTranslate { * @param {object} targetLanguage * @returns {object} unmodified message object. */ - translateMessage(message: IMessage, room: IRoom, targetLanguage: string): IMessage { + translateMessage(message: IMessage, room: IRoom, targetLanguage?: string): IMessage { let targetLanguages: string[]; if (targetLanguage) { targetLanguages = [targetLanguage]; @@ -305,10 +305,13 @@ export abstract class AutoTranslate { Meteor.defer(() => { for (const [index, attachment] of message.attachments?.entries() ?? []) { if (attachment.description || attachment.text) { - const translations = this._translateAttachmentDescriptions(attachment, targetLanguages); + // Removes the initial link `[ ](quoterl)` from quote message before translation + const translatedText = attachment?.text?.replace(/\[(.*?)\]\(.*?\)/g, '$1') || attachment?.text; + const attachmentMessage = { ...attachment, text: translatedText }; + const translations = this._translateAttachmentDescriptions(attachmentMessage, targetLanguages); + if (!_.isEmpty(translations)) { Messages.addAttachmentTranslations(message._id, index, translations); - Messages.addTranslations(message._id, translations, TranslationProviderRegistry[Provider]); } } } diff --git a/apps/meteor/app/autotranslate/server/deeplTranslate.ts b/apps/meteor/app/autotranslate/server/deeplTranslate.ts index 28793811505eb..2ee72877c73a0 100644 --- a/apps/meteor/app/autotranslate/server/deeplTranslate.ts +++ b/apps/meteor/app/autotranslate/server/deeplTranslate.ts @@ -231,8 +231,8 @@ class DeeplAutoTranslate extends AutoTranslate { .join('\n'); translations[language] = this.deTokenize(Object.assign({}, message, { msg: translatedText })); } - } catch (e) { - SystemLogger.error('Error translating message', e); + } catch (err) { + SystemLogger.error({ msg: 'Error translating message', err }); } }); return translations; @@ -272,8 +272,8 @@ class DeeplAutoTranslate extends AutoTranslate { translations[language] = result.data.translations.map((translation: IDeepLTranslation) => translation.text); } } - } catch (e) { - SystemLogger.error('Error translating message attachment', e); + } catch (err) { + SystemLogger.error({ msg: 'Error translating message attachment', err }); } }); return translations; diff --git a/apps/meteor/app/autotranslate/server/googleTranslate.ts b/apps/meteor/app/autotranslate/server/googleTranslate.ts index 5ce253f80af97..135601d48efcf 100644 --- a/apps/meteor/app/autotranslate/server/googleTranslate.ts +++ b/apps/meteor/app/autotranslate/server/googleTranslate.ts @@ -146,6 +146,7 @@ class GoogleAutoTranslate extends AutoTranslate { params: { key: this.apiKey, target: language, + format: 'text', }, query, }); @@ -161,8 +162,8 @@ class GoogleAutoTranslate extends AutoTranslate { const txt = result.data.data.translations.map((translation: IGoogleTranslation) => translation.translatedText).join('\n'); translations[language] = this.deTokenize(Object.assign({}, message, { msg: txt })); } - } catch (e) { - SystemLogger.error('Error translating message', e); + } catch (err) { + SystemLogger.error({ msg: 'Error translating message', err }); } }); return translations; @@ -190,6 +191,7 @@ class GoogleAutoTranslate extends AutoTranslate { params: { key: this.apiKey, target: language, + format: 'text', }, query, }); @@ -206,8 +208,8 @@ class GoogleAutoTranslate extends AutoTranslate { .map((translation: IGoogleTranslation) => translation.translatedText) .join('\n'); } - } catch (e) { - SystemLogger.error('Error translating message', e); + } catch (err) { + SystemLogger.error({ msg: 'Error translating message', err }); } }); return translations; diff --git a/apps/meteor/app/cas/client/index.js b/apps/meteor/app/cas/client/index.ts similarity index 100% rename from apps/meteor/app/cas/client/index.js rename to apps/meteor/app/cas/client/index.ts diff --git a/apps/meteor/app/cas/server/cas_server.js b/apps/meteor/app/cas/server/cas_server.js index cf0a273c4fcc0..6c3c139006ae3 100644 --- a/apps/meteor/app/cas/server/cas_server.js +++ b/apps/meteor/app/cas/server/cas_server.js @@ -93,7 +93,7 @@ const middleware = function (req, res, next) { closePopup(res); }); } catch (err) { - logger.error(`Unexpected error : ${err.message}`); + logger.error({ msg: 'Unexpected error', err }); closePopup(res); } }; @@ -162,7 +162,7 @@ Accounts.registerLoginHandler('cas', function (options) { _.each(attr_map, function (source, int_name) { // Source is our String to interpolate - if (_.isString(source)) { + if (source && typeof source.valueOf() === 'string') { let replacedValue = source; _.each(ext_attrs, function (value, ext_name) { replacedValue = replacedValue.replace(`%${ext_name}%`, ext_attrs[ext_name]); diff --git a/apps/meteor/app/cas/server/index.js b/apps/meteor/app/cas/server/index.ts similarity index 100% rename from apps/meteor/app/cas/server/index.js rename to apps/meteor/app/cas/server/index.ts diff --git a/apps/meteor/app/channel-settings/client/index.js b/apps/meteor/app/channel-settings/client/index.ts similarity index 100% rename from apps/meteor/app/channel-settings/client/index.js rename to apps/meteor/app/channel-settings/client/index.ts diff --git a/apps/meteor/app/channel-settings/client/lib/ChannelSettings.js b/apps/meteor/app/channel-settings/client/lib/ChannelSettings.js index c28423a726337..93d83e5d80faa 100644 --- a/apps/meteor/app/channel-settings/client/lib/ChannelSettings.js +++ b/apps/meteor/app/channel-settings/client/lib/ChannelSettings.js @@ -1,6 +1,7 @@ import { ReactiveVar } from 'meteor/reactive-var'; import { Tracker } from 'meteor/tracker'; -import _ from 'underscore'; + +import { isTruthy } from '../../../../lib/isTruthy'; export const ChannelSettings = new (class { constructor() { @@ -26,18 +27,20 @@ export const ChannelSettings = new (class { } getOptions(currentData = {}, group) { - const allOptions = _.toArray(this.options.get()); - const allowedOptions = _.compact( - _.map(allOptions, function (option) { + return Object.entries(this.options.get()) + .map((option) => { const ret = { ...option }; if (option.validation == null || option.validation(currentData)) { ret.data = Object.assign({}, typeof option.data === 'function' ? option.data() : option.data, currentData); return ret; } - }), - ).filter(function (option) { - return !group || !option.group || option.group.includes(group); - }); - return _.sortBy(allowedOptions, 'order'); + + return null; + }) + .filter(isTruthy) + .filter(function (option) { + return !group || !option.group || option.group.includes(group); + }) + .sort((a, b) => a.order - b.order); } })(); diff --git a/apps/meteor/app/channel-settings/index.js b/apps/meteor/app/channel-settings/index.js index a67eca871efbb..1f3257e45429a 100644 --- a/apps/meteor/app/channel-settings/index.js +++ b/apps/meteor/app/channel-settings/index.js @@ -1,8 +1,8 @@ import { Meteor } from 'meteor/meteor'; if (Meteor.isClient) { - module.exports = require('./client/index.js'); + module.exports = require('./client/index.ts'); } if (Meteor.isServer) { - module.exports = require('./server/index.js'); + module.exports = require('./server/index.ts'); } diff --git a/apps/meteor/app/channel-settings/server/functions/saveRoomName.js b/apps/meteor/app/channel-settings/server/functions/saveRoomName.js index 941f8e86fcfcb..8bfbb57ced98a 100644 --- a/apps/meteor/app/channel-settings/server/functions/saveRoomName.js +++ b/apps/meteor/app/channel-settings/server/functions/saveRoomName.js @@ -1,5 +1,6 @@ import { Meteor } from 'meteor/meteor'; import { Integrations } from '@rocket.chat/models'; +import { isRoomFederated } from '@rocket.chat/core-typings'; import { Rooms, Messages, Subscriptions } from '../../../models/server'; import { getValidRoomName } from '../../../utils/server'; @@ -7,10 +8,11 @@ import { callbacks } from '../../../../lib/callbacks'; import { checkUsernameAvailability } from '../../../lib/server/functions'; import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator'; -const updateRoomName = (rid, displayName, isDiscussion) => { - if (isDiscussion) { - return Rooms.setFnameById(rid, displayName) && Subscriptions.updateFnameByRoomId(rid, displayName); - } +const updateFName = (rid, displayName) => { + return Rooms.setFnameById(rid, displayName) && Subscriptions.updateFnameByRoomId(rid, displayName); +}; + +const updateRoomName = (rid, displayName) => { const slugifiedRoomName = getValidRoomName(displayName, rid); // Check if the username is available @@ -37,7 +39,14 @@ export async function saveRoomName(rid, displayName, user, sendMessage = true) { return; } const isDiscussion = Boolean(room && room.prid); - const update = updateRoomName(rid, displayName, isDiscussion); + let update; + + if (isDiscussion || isRoomFederated(room)) { + update = updateFName(rid, displayName); + } else { + update = updateRoomName(rid, displayName); + } + if (!update) { return; } diff --git a/apps/meteor/app/channel-settings/server/functions/saveRoomType.js b/apps/meteor/app/channel-settings/server/functions/saveRoomType.js index 206520b01b23a..cf76ca651930e 100644 --- a/apps/meteor/app/channel-settings/server/functions/saveRoomType.js +++ b/apps/meteor/app/channel-settings/server/functions/saveRoomType.js @@ -41,11 +41,11 @@ export const saveRoomType = function (rid, roomType, user, sendMessage = true) { if (sendMessage) { let message; if (roomType === 'c') { - message = TAPi18n.__('Channel', { + message = TAPi18n.__('public', { lng: (user && user.language) || settings.get('Language') || 'en', }); } else { - message = TAPi18n.__('Private_Group', { + message = TAPi18n.__('private', { lng: (user && user.language) || settings.get('Language') || 'en', }); } diff --git a/apps/meteor/app/channel-settings/server/index.js b/apps/meteor/app/channel-settings/server/index.ts similarity index 100% rename from apps/meteor/app/channel-settings/server/index.js rename to apps/meteor/app/channel-settings/server/index.ts diff --git a/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.js b/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.js index 89dcd43fb8b81..ed324d7b64cc8 100644 --- a/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.js +++ b/apps/meteor/app/channel-settings/server/methods/saveRoomSettings.js @@ -1,6 +1,7 @@ import { Meteor } from 'meteor/meteor'; import { Match } from 'meteor/check'; import { TEAM_TYPE } from '@rocket.chat/core-typings'; +import { Team } from '@rocket.chat/core-services'; import { setRoomAvatar } from '../../../lib/server/functions/setRoomAvatar'; import { hasPermission } from '../../../authorization'; @@ -17,7 +18,6 @@ import { saveReactWhenReadOnly } from '../functions/saveReactWhenReadOnly'; import { saveRoomSystemMessages } from '../functions/saveRoomSystemMessages'; import { saveRoomEncrypted } from '../functions/saveRoomEncrypted'; import { saveStreamingOptions } from '../functions/saveStreamingOptions'; -import { Team } from '../../../../server/sdk'; import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator'; import { RoomSettingsEnum } from '../../../../definition/IRoomTypeConfig'; @@ -160,11 +160,17 @@ const settingSavers = { } }, roomTopic({ value, room, rid, user }) { + if (!value && !room.topic) { + return; + } if (value !== room.topic) { saveRoomTopic(rid, value, user); } }, roomAnnouncement({ value, room, rid, user }) { + if (!value && !room.announcement) { + return; + } if (value !== room.announcement) { saveRoomAnnouncement(rid, value, user); } @@ -175,6 +181,9 @@ const settingSavers = { } }, roomDescription({ value, room, rid, user }) { + if (!value && !room.description) { + return; + } if (value !== room.description) { saveRoomDescription(rid, value, user); } diff --git a/apps/meteor/app/chatpal-search/client/index.js b/apps/meteor/app/chatpal-search/client/index.js deleted file mode 100644 index 6bf6d22ad237f..0000000000000 --- a/apps/meteor/app/chatpal-search/client/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import './template/admin.html'; -import './template/result.html'; -import './template/suggestion.html'; -import './template/admin'; -import './template/result'; -import './template/suggestion'; -import './style.css'; diff --git a/apps/meteor/app/chatpal-search/client/style.css b/apps/meteor/app/chatpal-search/client/style.css deleted file mode 100644 index cc704ea30b0d9..0000000000000 --- a/apps/meteor/app/chatpal-search/client/style.css +++ /dev/null @@ -1,371 +0,0 @@ -.chatpal-admin-link { - text-decoration: underline !important; - - color: red !important; -} - -.chatpalProvider .search-form { - padding: 0 24px; -} - -.chatpal_search-loader { - position: relative; - - margin-top: 50px; -} - -.chatpal-search-container { - display: flex; - flex-direction: column; - flex: 1; -} - -.chatpal-search-result { - position: relative; - - overflow: auto; - overflow-x: hidden; - - flex: 1; - - padding: 0 24px 24px; - - background-color: #f1f1f1; -} - -.chatpal-search-typefilter { - display: flex; -} - -.chatpal-search-typefilter li { - display: flex; - flex: 0 0 33%; - - height: 35px; - padding-top: 10px; - - cursor: pointer; - - border-bottom: 4px solid white; - justify-content: center; -} - -.chatpal-search-typefilter li.selected { - border-bottom: 4px solid #125074; -} - -.chatpal-admin-header { - margin-bottom: 20px; - - font-size: 18px; -} - -.chatpal-search-result-header { - margin: 20px 0; - - font-weight: bold; -} - -.chatpal-search-result-single { - position: relative; - - min-height: 92px; - - margin-bottom: 10px; - - padding: 10px; - - border: 1px solid #e6e6e6; - background-color: white; -} - -.chatpal-search-result-user { - position: relative; - - min-height: 40px; - - margin-bottom: 10px; - - padding: 10px; - - border: 1px solid #e6e6e6; - background-color: white; -} - -.chatpal-search-result-user .chatpal-avatar { - position: absolute; - - width: 36px; - height: 36px; -} - -.chatpal-search-result-user .chatpal-avatar .chatpal-avatar-image { - width: 100%; - height: 100%; - - background-repeat: no-repeat; - background-size: contain; -} - -.chatpal-search-result-user h2 { - margin-bottom: 5px; - padding-left: 45px; -} - -.chatpal-search-result-user .direct-message { - padding-left: 45px; - - font-size: 14px; - font-weight: bold; -} - -.chatpal-channel { - flex: 1 1 auto; -} - -.chatpal-search-result-user .chatpal-channel { - font-weight: bold; -} - -.chatpal-show-more-messages { - margin-bottom: 20px; - - cursor: pointer; - - text-align: center; - - color: #125074; - - font-size: 14px; - font-weight: bold; -} - -.chatpal-show-more-messages:hover { - text-decoration: underline; -} - -.chatpal-search-result-user .direct-message a { - color: #125074; -} - -.chatpal-search-result-user .direct-message a:hover { - text-decoration: underline; -} - -.chatpal-search-result-single h2 { - display: flex; - - margin-bottom: 20px; - align-items: center; -} - -.chatpal-search-result-single .chatpal-avatar { - position: absolute; - - width: 36px; - height: 36px; -} - -.chatpal-search-result-single .chatpal-avatar .chatpal-avatar-image { - width: 100%; - height: 100%; - - background-repeat: no-repeat; - background-size: contain; -} - -.chatpal-search-result-single .chatpal-name { - padding: 0 0 0 46px; - - color: #444444; - - font-size: 14px; - - font-weight: bold; -} - -.chatpal-search-result-single .chatpal-date { - color: #a0a0a0; - - font-size: 12px; - - font-weight: normal; -} - -.chatpal-search-result-single .chatpal-time { - margin-left: 3px; - - color: #a0a0a0; - - font-size: 12px; -} - -.chatpal-search-result-single .chatpal-message { - overflow-x: hidden; - - margin-top: 5px; - padding: 0 0 0 46px; - - line-height: 20px; -} - -.chatpal-search-result-single .chatpal-message em { - background-color: #faf9c8; - - font-style: normal; -} - -.chatpal-search-result-single .chatpal-link { - display: none; - flex: 20; - - color: #125074; -} - -.chatpal-search-result-single .chatpal-link:hover { - text-decoration: underline; -} - -.chatpal-search-result-single:hover .chatpal-link { - display: inline-block; -} - -.chatpal-paging { - margin: 30px 0 50px; - - text-align: center; -} - -.chatpal-paging-text { - position: relative; - top: -2px; - - display: inline-block; -} - -.chatpal-paging .chatpal-paging-button { - display: inline-block; - - cursor: pointer; - - color: #125074; - - font-size: 20px; -} - -.chatpal-paging .chatpal-paging-prev { - padding-right: 10px; -} - -.chatpal-paging .chatpal-paging-next { - padding-left: 10px; -} - -.chatpal-search-info { - margin-top: 40px; - padding: 10px; -} - -.chatpal-search-welcome { - padding-top: 40px; - - text-align: center; -} - -.chatpal-search-result-room h2 { - padding-left: 0 !important; -} - -.chatpal-search-result-list em { - background-color: #faf9c8; - - font-style: normal; -} - -.chatpal-search-result-room .chatpal-link { - display: none; - - margin-left: 3px; - - color: #125074; -} - -.chatpal-search-result-room:hover .chatpal-link { - display: inline-block; -} - -.chatpal-search-result-room .chatpal-link:hover { - text-decoration: underline; -} - -.chatpal-search-pills div { - display: inline-block; - - margin-top: 5px; - - margin-right: 5px; - - padding: 2px 5px; - - border-radius: 3px; - background-color: #f1f1f1; -} - -.apikey h2 { - margin-top: 20px; -} - -.apikey .key { - position: relative; - - margin: 20px 0; - - padding: 10px; - - text-align: center; - - background-color: #f1f1f1; - - font-size: 20px; -} - -.apikey a { - text-decoration: underline; -} - -.chatpal-suggestion { - display: flex; - - padding: 10px; - justify-items: center; -} - -.chatpal-suggestion-text { - flex: 1 1 auto; -} - -.chatpal-suggestion-hint { - display: none; -} - -.rocket-search-suggestion-item.active .chatpal-suggestion-hint { - display: block; -} - -.chatpalProvider .rc-input__icon { - top: 3px; - - left: 10px; - - width: 26px; -} - -.chatpalProvider .rc-input__icon-svg { - font-size: 26px !important; -} - -.chatpalProvider .rocket-search-suggestion-item.active, -.chatpalProvider .rocket-search-suggestion-item:hover { - color: white; - background-color: #125074; -} diff --git a/apps/meteor/app/chatpal-search/client/template/admin.html b/apps/meteor/app/chatpal-search/client/template/admin.html deleted file mode 100644 index 91c31cf49d211..0000000000000 --- a/apps/meteor/app/chatpal-search/client/template/admin.html +++ /dev/null @@ -1,56 +0,0 @@ - diff --git a/apps/meteor/app/chatpal-search/client/template/admin.js b/apps/meteor/app/chatpal-search/client/template/admin.js deleted file mode 100644 index dd878d3e91e98..0000000000000 --- a/apps/meteor/app/chatpal-search/client/template/admin.js +++ /dev/null @@ -1,91 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { Template } from 'meteor/templating'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; - -import { settings } from '../../../settings'; -import { hasPermission } from '../../../authorization'; -import { dispatchToastMessage } from '../../../../client/lib/toast'; -import { validateEmail } from '../../../../lib/emailValidator'; - -Template.ChatpalAdmin.onCreated(function () { - this.validateEmail = validateEmail; - - this.apiKey = new ReactiveVar(); - - const lang = settings.get('Language'); - - this.lang = lang === 'de' || lang === 'en' ? lang : 'en'; - - this.tac = new ReactiveVar(); - - Meteor.call('chatpalUtilsGetTaC', this.lang, (err, data) => { - this.tac.set(data); - }); -}); - -Template.ChatpalAdmin.events({ - 'submit form'(e, t) { - e.preventDefault(); - - const email = e.target.email.value; - const tac = e.target.readtac.checked; - - if (!tac) { - return dispatchToastMessage({ - type: 'error', - message: TAPi18n.__('Chatpal_ERROR_TAC_must_be_checked'), - }); - } - if (!email || email === '') { - return dispatchToastMessage({ - type: 'error', - message: TAPi18n.__('Chatpal_ERROR_Email_must_be_set'), - }); - } - if (!t.validateEmail(email)) { - return dispatchToastMessage({ - type: 'error', - message: TAPi18n.__('Chatpal_ERROR_Email_must_be_valid'), - }); - } - - // TODO register - try { - Meteor.call('chatpalUtilsCreateKey', email, (err, key) => { - if (!key) { - return dispatchToastMessage({ - type: 'error', - message: TAPi18n.__('Chatpal_ERROR_username_already_exists'), - }); - } - - dispatchToastMessage({ - type: 'info', - message: TAPi18n.__('Chatpal_created_key_successfully'), - }); - - t.apiKey.set(key); - }); - } catch (e) { - console.log(e); - dispatchToastMessage({ - type: 'error', - message: TAPi18n.__('Chatpal_ERROR_username_already_exists'), - }); // TODO error messages - } - }, -}); - -// template -Template.ChatpalAdmin.helpers({ - apiKey() { - return Template.instance().apiKey.get(); - }, - isAdmin() { - return hasPermission('manage-chatpal'); - }, - tac() { - return Template.instance().tac.get(); - }, -}); diff --git a/apps/meteor/app/chatpal-search/client/template/result.html b/apps/meteor/app/chatpal-search/client/template/result.html deleted file mode 100644 index 7b05a7b18272b..0000000000000 --- a/apps/meteor/app/chatpal-search/client/template/result.html +++ /dev/null @@ -1,160 +0,0 @@ - - - - - - - diff --git a/apps/meteor/app/chatpal-search/client/template/result.js b/apps/meteor/app/chatpal-search/client/template/result.js deleted file mode 100644 index 17a91ae4f6b19..0000000000000 --- a/apps/meteor/app/chatpal-search/client/template/result.js +++ /dev/null @@ -1,153 +0,0 @@ -import { ReactiveVar } from 'meteor/reactive-var'; -import { Template } from 'meteor/templating'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; - -import { getURL } from '../../../utils'; -import { Subscriptions } from '../../../models/client'; -import { getUserAvatarURL as getAvatarUrl } from '../../../utils/lib/getUserAvatarURL'; -import { formatTime } from '../../../../client/lib/utils/formatTime'; -import { formatDate } from '../../../../client/lib/utils/formatDate'; -import { roomCoordinator } from '../../../../client/lib/rooms/roomCoordinator'; - -const getDMUrl = (username) => getURL(`/direct/${username}`); - -Template.ChatpalSearchResultTemplate.onCreated(function () { - this.badRequest = new ReactiveVar(false); - this.resultType = new ReactiveVar(this.data.settings.DefaultResultType); - this.data.parentPayload.resultType = this.resultType.get(); -}); - -Template.ChatpalSearchResultTemplate.events = { - 'click .chatpal-search-typefilter li'(evt, t) { - t.data.parentPayload.resultType = evt.currentTarget.getAttribute('value'); - t.data.payload.start = 0; - t.resultType.set(t.data.parentPayload.resultType); - t.data.search(); - }, - 'click .chatpal-paging-prev'(env, t) { - t.data.payload.start -= t.data.settings.PageSize; - t.data.search(); - }, - 'click .chatpal-paging-next'(env, t) { - t.data.payload.start = (t.data.payload.start || 0) + t.data.settings.PageSize; - t.data.search(); - }, - 'click .chatpal-show-more-messages'(evt, t) { - t.data.parentPayload.resultType = 'Messages'; - t.data.payload.start = 0; - t.data.payload.rows = t.data.settings.PageSize; - t.resultType.set(t.data.parentPayload.resultType); - t.data.search(); - }, -}; - -Template.ChatpalSearchResultTemplate.helpers({ - result() { - return Template.instance().data.result.get(); - }, - searching() { - return Template.instance().data.searching.get(); - }, - resultType() { - return Template.instance().resultType.get(); - }, - navSelected(type) { - return Template.instance().resultType.get() === type ? 'selected' : ''; - }, - resultsFoundForAllSearch() { - const result = Template.instance().data.result.get(); - - if (!result) { - return true; - } - - return result.message.numFound > 0 || result.user.numFound > 0 || result.room.numFound > 0; - }, - moreMessagesThanDisplayed() { - const result = Template.instance().data.result.get(); - - return result.message.docs.length < result.message.numFound; - }, - resultNumFound() { - const result = Template.instance().data.result.get(); - if (result) { - switch (result.message.numFound) { - case 0: - return TAPi18n.__('Chatpal_no_search_results'); - case 1: - return TAPi18n.__('Chatpal_one_search_result'); - default: - return TAPi18n.__('Chatpal_search_results', result.message.numFound); - } - } - }, - resultMessagesOnly() { - return Template.instance().resultType.get() === 'Messages' || Template.instance().resultType.get() === 'Room'; - }, - resultPaging() { - const result = Template.instance().data.result.get(); - const pageSize = Template.instance().data.settings.PageSize; - if (result) { - return { - currentPage: 1 + result.message.start / pageSize, - numOfPages: Math.ceil(result.message.numFound / pageSize), - }; - } - }, -}); - -Template.ChatpalSearchSingleMessage.helpers({ - roomIcon() { - const room = this.r; - if (room && room.t === 'd') { - return 'at'; - } - return roomCoordinator.getIcon(room); - }, - - roomLink() { - return roomCoordinator.getRouteLink(this.r.t, this.r); - }, - - roomName() { - return roomCoordinator.getRoomName(this.r.t, this.r); - }, - - roomNotSubscribed() { - const subscription = Subscriptions.findOne({ rid: this.rid }); - return typeof subscription === 'undefined'; - }, - - time() { - return formatTime(this.created); - }, - date() { - return formatDate(this.created); - }, - getAvatarUrl, -}); - -Template.ChatpalSearchSingleRoom.helpers({ - roomIcon() { - if (this.t === 'd') { - return 'at'; - } - return roomCoordinator.getIcon(this); - }, - roomLink() { - return roomCoordinator.getRouteLink(this.t, this); - }, - roomNotSubscribed() { - const subscription = Subscriptions.findOne({ rid: this.rid }); - return typeof subscription === 'undefined'; - }, -}); - -Template.ChatpalSearchSingleUser.helpers({ - cleanUsername() { - const username = this.user_username || this.username; // varies whether users or messages of users are displayed - return username.replace(/<\/?em>/gi, ''); - }, - getAvatarUrl, - getDMUrl, -}); diff --git a/apps/meteor/app/chatpal-search/client/template/suggestion.html b/apps/meteor/app/chatpal-search/client/template/suggestion.html deleted file mode 100644 index b003193c8af37..0000000000000 --- a/apps/meteor/app/chatpal-search/client/template/suggestion.html +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/apps/meteor/app/chatpal-search/client/template/suggestion.js b/apps/meteor/app/chatpal-search/client/template/suggestion.js deleted file mode 100644 index 8f6e64c8775f1..0000000000000 --- a/apps/meteor/app/chatpal-search/client/template/suggestion.js +++ /dev/null @@ -1,9 +0,0 @@ -import { Template } from 'meteor/templating'; - -Template.ChatpalSuggestionItemTemplate.onCreated(function () { - if (this.data.type === 'link') { - this.data.action = () => { - console.log('an example for an external link'); - }; - } -}); diff --git a/apps/meteor/app/chatpal-search/server/asset/config.js b/apps/meteor/app/chatpal-search/server/asset/config.js deleted file mode 100644 index fa93ed60def7e..0000000000000 --- a/apps/meteor/app/chatpal-search/server/asset/config.js +++ /dev/null @@ -1,4 +0,0 @@ -import { injectIntoBody } from '../../../ui-master/server'; - -injectIntoBody('chatpal-enter', Assets.getText('server/asset/chatpal-enter.svg')); -injectIntoBody('chatpal-logo-icon-darkblue', Assets.getText('server/asset/chatpal-logo-icon-darkblue.svg')); diff --git a/apps/meteor/app/chatpal-search/server/index.js b/apps/meteor/app/chatpal-search/server/index.js deleted file mode 100644 index 2a7f1094d0904..0000000000000 --- a/apps/meteor/app/chatpal-search/server/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import './asset/config'; -import './provider/provider'; -import './utils/utils'; diff --git a/apps/meteor/app/chatpal-search/server/provider/index.js b/apps/meteor/app/chatpal-search/server/provider/index.js deleted file mode 100644 index 77eaa27255963..0000000000000 --- a/apps/meteor/app/chatpal-search/server/provider/index.js +++ /dev/null @@ -1,444 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { HTTP } from 'meteor/http'; -import { Random } from 'meteor/random'; - -import ChatpalLogger from '../utils/logger'; -import { Rooms, Messages } from '../../../models/server'; - -/** - * Enables HTTP functions on Chatpal Backend - */ -class Backend { - constructor(options) { - this._options = options; - } - - /** - * index a set of Sorl documents - * @param docs - * @returns {boolean} - */ - index(docs) { - const options = { - data: docs, - params: { language: this._options.language }, - ...this._options.httpOptions, - }; - - try { - const response = HTTP.call('POST', `${this._options.baseurl}${this._options.updatepath}`, options); - - if (response.statusCode >= 200 && response.statusCode < 300) { - ChatpalLogger.debug({ msg: `indexed ${docs.length} documents`, data: response.data }); - } else { - throw new Error(response); - } - } catch (e) { - // TODO how to deal with this - ChatpalLogger.error({ msg: 'indexing failed', err: e }); - return false; - } - } - - /** - * remove an entry by type and id - * @param type - * @param id - * @returns {boolean} - */ - remove(type, id) { - ChatpalLogger.debug(`Remove ${type}(${id}) from Index`); - - const options = { - data: { - delete: { - query: `id:${id} AND type:${type}`, - }, - commit: {}, - }, - ...this._options.httpOptions, - }; - - try { - const response = HTTP.call('POST', this._options.baseurl + this._options.clearpath, options); - - return response.statusCode >= 200 && response.statusCode < 300; - } catch (e) { - return false; - } - } - - count(type) { - return this.query({ type, rows: 0, text: '*' })[type].numFound; - } - - /** - * query with params - * @param params - * @param callback - */ - query(params, callback) { - const options = { - params, - ...this._options.httpOptions, - }; - - ChatpalLogger.debug({ query: options }); - - try { - if (callback) { - HTTP.call('POST', this._options.baseurl + this._options.searchpath, options, (err, result) => { - if (err) { - return callback(err); - } - - callback(undefined, result.data); - }); - } else { - const response = HTTP.call('POST', this._options.baseurl + this._options.searchpath, options); - - if (response.statusCode >= 200 && response.statusCode < 300) { - return response.data; - } - throw new Error(response); - } - } catch (e) { - ChatpalLogger.error({ msg: 'query failed', err: e }); - throw e; - } - } - - suggest(params, callback) { - const options = { - params, - ...this._options.httpOptions, - }; - - HTTP.call('POST', this._options.baseurl + this._options.suggestionpath, options, (err, result) => { - if (err) { - return callback(err); - } - - try { - callback(undefined, result.data.suggestion); - } catch (e) { - callback(e); - } - }); - } - - clear() { - ChatpalLogger.debug('Clear Index'); - - const options = { - data: { - delete: { - query: '*:*', - }, - commit: {}, - }, - ...this._options.httpOptions, - }; - - try { - const response = HTTP.call('POST', this._options.baseurl + this._options.clearpath, options); - - return response.statusCode >= 200 && response.statusCode < 300; - } catch (e) { - return false; - } - } - - /** - * statically ping with configuration - * @param options - * @returns {boolean} - */ - static ping(config) { - const options = { - params: { - stats: true, - }, - ...config.httpOptions, - }; - - try { - const response = HTTP.call('GET', config.baseurl + config.pingpath, options); - - if (response.statusCode >= 200 && response.statusCode < 300) { - return response.data.stats; - } - return false; - } catch (e) { - return false; - } - } -} - -/** - * Enabled batch indexing - */ -class BatchIndexer { - constructor(size, func, ...rest) { - this._size = size; - this._func = func; - this._rest = rest; - this._values = []; - } - - add(value) { - this._values.push(value); - if (this._values.length === this._size) { - this.flush(); - } - } - - flush() { - this._func(this._values, this._rest); // TODO if flush does not work - this._values = []; - } -} - -/** - * Provides index functions to chatpal provider - */ -export default class Index { - /** - * Creates Index Stub - * @param options - * @param clear if a complete reindex should be done - */ - constructor(options, clear, date) { - this._id = Random.id(); - - this._backend = new Backend(options); - - this._options = options; - - this._batchIndexer = new BatchIndexer(this._options.batchSize || 100, (values) => this._backend.index(values)); - - this._bootstrap(clear, date); - } - - /** - * prepare solr documents - * @param type - * @param doc - * @returns {*} - * @private - */ - _getIndexDocument(type, doc) { - switch (type) { - case 'message': - return { - id: doc._id, - rid: doc.rid, - user: doc.u._id, - created: doc.ts, - updated: doc._updatedAt, - text: doc.msg, - type, - }; - case 'room': - return { - id: doc._id, - rid: doc._id, - created: doc.createdAt, - updated: doc.lm ? doc.lm : doc._updatedAt, - type, - room_name: doc.name, - room_announcement: doc.announcement, - room_description: doc.description, - room_topic: doc.topic, - }; - case 'user': - return { - id: doc._id, - created: doc.createdAt, - updated: doc._updatedAt, - type, - user_username: doc.username, - user_name: doc.name, - user_email: doc.emails && doc.emails.map((e) => e.address), - }; - default: - throw new Error(`Cannot index type '${type}'`); - } - } - - /** - * return true if there are messages in the databases which has been created before *date* - * @param date - * @returns {boolean} - * @private - */ - _existsDataOlderThan(date) { - return Messages.model.find({ ts: { $lt: new Date(date) }, t: { $exists: false } }, { limit: 1 }).fetch().length > 0; - } - - _doesRoomCountDiffer() { - return Rooms.find({ t: { $ne: 'd' } }).count() !== this._backend.count('room'); - } - - _doesUserCountDiffer() { - return Meteor.users.find({ active: true }).count() !== this._backend.count('user'); - } - - /** - * Index users by using a database cursor - */ - _indexUsers() { - const cursor = Meteor.users.find({ active: true }); - - ChatpalLogger.debug(`Start indexing ${cursor.count()} users`); - - cursor.forEach((user) => { - this.indexDoc('user', user, false); - }); - - ChatpalLogger.info(`Users indexed successfully (index-id: ${this._id})`); - } - - /** - * Index rooms by database cursor - * @private - */ - _indexRooms() { - const cursor = Rooms.find({ t: { $ne: 'd' } }); - - ChatpalLogger.debug(`Start indexing ${cursor.count()} rooms`); - - cursor.forEach((room) => { - this.indexDoc('room', room, false); - }); - - ChatpalLogger.info(`Rooms indexed successfully (index-id: ${this._id})`); - } - - _indexMessages(date, gap) { - const start = new Date(date - gap); - const end = new Date(date); - - const cursor = Messages.model.find({ ts: { $gt: start, $lt: end }, t: { $exists: false } }); - - ChatpalLogger.debug(`Start indexing ${cursor.count()} messages between ${start.toString()} and ${end.toString()}`); - - cursor.forEach((message) => { - this.indexDoc('message', message, false); - }); - - ChatpalLogger.info(`Messages between ${start.toString()} and ${end.toString()} indexed successfully (index-id: ${this._id})`); - - return start.getTime(); - } - - _run(date, resolve, reject) { - this._running = true; - - if (this._existsDataOlderThan(date) && !this._break) { - Meteor.setTimeout(() => { - date = this._indexMessages(date, (this._options.windowSize || 24) * 3600000); - - this._run(date, resolve, reject); - }, this._options.timeout || 1000); - } else if (this._break) { - ChatpalLogger.info(`stopped bootstrap (index-id: ${this._id})`); - - this._batchIndexer.flush(); - - this._running = false; - - resolve(); - } else { - ChatpalLogger.info(`No messages older than already indexed date ${new Date(date).toString()}`); - - if (this._doesUserCountDiffer() && !this._break) { - this._indexUsers(); - } else { - ChatpalLogger.info('Users already indexed'); - } - - if (this._doesRoomCountDiffer() && !this._break) { - this._indexRooms(); - } else { - ChatpalLogger.info('Rooms already indexed'); - } - - this._batchIndexer.flush(); - - ChatpalLogger.info(`finished bootstrap (index-id: ${this._id})`); - - this._running = false; - - resolve(); - } - } - - _bootstrap(clear, date) { - ChatpalLogger.info('Start bootstrapping'); - - return new Promise((resolve, reject) => { - if (clear) { - this._backend.clear(); - date = new Date().getTime(); - } - - this._run(date, resolve, reject); - }); - } - - static ping(options) { - return Backend.ping(options); - } - - stop() { - this._break = true; - } - - reindex() { - if (!this._running) { - this._bootstrap(true); - } - } - - indexDoc(type, doc, flush = true) { - this._batchIndexer.add(this._getIndexDocument(type, doc)); - - if (flush) { - this._batchIndexer.flush(); - } - - return true; - } - - removeDoc(type, id) { - return this._backend.remove(type, id); - } - - query(text, language, acl, type, start, rows, callback, params = {}) { - this._backend.query( - { - text, - language, - acl, - type, - start, - rows, - ...params, - }, - callback, - ); - } - - suggest(text, language, acl, type, callback) { - this._backend.suggest( - { - text, - language, - acl, - type, - }, - callback, - ); - } -} diff --git a/apps/meteor/app/chatpal-search/server/provider/provider.js b/apps/meteor/app/chatpal-search/server/provider/provider.js deleted file mode 100644 index b8705cf29be3a..0000000000000 --- a/apps/meteor/app/chatpal-search/server/provider/provider.js +++ /dev/null @@ -1,380 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { searchProviderService, SearchProvider } from '../../../search/server'; -import ChatpalLogger from '../utils/logger'; -import { Subscriptions, Rooms } from '../../../models/server'; -import { baseUrl } from '../utils/settings'; -import Index from './index'; - -/** - * The chatpal search provider enables chatpal search. An appropriate backedn has to be specified by settings. - */ -class ChatpalProvider extends SearchProvider { - /** - * Create chatpal provider with some settings for backend and ui - */ - constructor() { - super('chatpalProvider'); - - this.chatpalBaseUrl = `${baseUrl}`; - - ChatpalLogger.debug(`Using ${this.chatpalBaseUrl} as chatpal base url`); - - this._settings.add('Backend', 'select', 'cloud', { - values: [ - { key: 'cloud', i18nLabel: 'Cloud Service' }, - { key: 'onsite', i18nLabel: 'On-Site' }, - ], - i18nLabel: 'Chatpal_Backend', - i18nDescription: 'Chatpal_Backend_Description', - }); - this._settings.add('API_Key', 'string', '', { - enableQuery: [ - { - _id: 'Search.chatpalProvider.Backend', - value: 'cloud', - }, - ], - i18nLabel: 'Chatpal_API_Key', - i18nDescription: 'Chatpal_API_Key_Description', - }); - this._settings.add('Base_URL', 'string', '', { - enableQuery: [ - { - _id: 'Search.chatpalProvider.Backend', - value: 'onsite', - }, - ], - i18nLabel: 'Chatpal_Base_URL', - i18nDescription: 'Chatpal_Base_URL_Description', - }); - this._settings.add('HTTP_Headers', 'string', '', { - enableQuery: [ - { - _id: 'Search.chatpalProvider.Backend', - value: 'onsite', - }, - ], - multiline: true, - i18nLabel: 'Chatpal_HTTP_Headers', - i18nDescription: 'Chatpal_HTTP_Headers_Description', - }); - this._settings.add('Main_Language', 'select', 'en', { - values: [ - { key: 'en', i18nLabel: 'English' }, - { key: 'none', i18nLabel: 'Language_Not_set' }, - { key: 'cs', i18nLabel: 'Czech' }, - { key: 'de', i18nLabel: 'Deutsch' }, - { key: 'el', i18nLabel: 'Greek' }, - { key: 'es', i18nLabel: 'Spanish' }, - { key: 'fi', i18nLabel: 'Finish' }, - { key: 'fr', i18nLabel: 'French' }, - { key: 'hu', i18nLabel: 'Hungarian' }, - { key: 'it', i18nLabel: 'Italian' }, - { key: 'nl', i18nLabel: 'Dutsch' }, - { key: 'pl', i18nLabel: 'Polish' }, - { key: 'pt', i18nLabel: 'Portuguese' }, - { key: 'pt_BR', i18nLabel: 'Brasilian' }, - { key: 'ro', i18nLabel: 'Romanian' }, - { key: 'ru', i18nLabel: 'Russian' }, - { key: 'sv', i18nLabel: 'Swedisch' }, - { key: 'tr', i18nLabel: 'Turkish' }, - { key: 'uk', i18nLabel: 'Ukrainian' }, - ], - i18nLabel: 'Chatpal_Main_Language', - i18nDescription: 'Chatpal_Main_Language_Description', - }); - this._settings.add('DefaultResultType', 'select', 'All', { - values: [ - { key: 'All', i18nLabel: 'Chatpal_All_Results' }, - { key: 'Room', i18nLabel: 'Chatpal_Current_Room_Only' }, - { key: 'Messages', i18nLabel: 'Chatpal_Messages_Only' }, - ], - i18nLabel: 'Chatpal_Default_Result_Type', - i18nDescription: 'Chatpal_Default_Result_Type_Description', - }); - this._settings.add('PageSize', 'int', 15, { - i18nLabel: 'Search_Page_Size', - }); - this._settings.add('SuggestionEnabled', 'boolean', true, { - i18nLabel: 'Chatpal_Suggestion_Enabled', - alert: 'This feature is currently in beta and will be extended in the future', - }); - this._settings.add('IncludeAllPublicChannels', 'boolean', false, { - i18nLabel: 'Chatpal_Include_All_Public_Channels', - i18nDescription: 'Chatpal_Include_All_Public_Channels_Description', - }); - this._settings.add('BatchSize', 'int', 100, { - i18nLabel: 'Chatpal_Batch_Size', - i18nDescription: 'Chatpal_Batch_Size_Description', - }); - this._settings.add('TimeoutSize', 'int', 5000, { - i18nLabel: 'Chatpal_Timeout_Size', - i18nDescription: 'Chatpal_Timeout_Size_Description', - }); - this._settings.add('WindowSize', 'int', 48, { - i18nLabel: 'Chatpal_Window_Size', - i18nDescription: 'Chatpal_Window_Size_Description', - }); - } - - get i18nLabel() { - return 'Chatpal Provider'; - } - - get iconName() { - return 'chatpal-logo-icon-darkblue'; - } - - get resultTemplate() { - return 'ChatpalSearchResultTemplate'; - } - - get suggestionItemTemplate() { - return 'ChatpalSuggestionItemTemplate'; - } - - get supportsSuggestions() { - return this._settings.get('SuggestionEnabled'); - } - - /** - * indexing for messages, rooms and users - * @inheritDoc - */ - on(name, value, payload) { - if (!this.index) { - this.indexFail = true; - return false; - } - - switch (name) { - case 'message.save': - return this.index.indexDoc('message', payload); - case 'user.save': - return this.index.indexDoc('user', payload); - case 'room.save': - return this.index.indexDoc('room', payload); - case 'message.delete': - return this.index.removeDoc('message', value); - case 'user.delete': - return this.index.removeDoc('user', value); - case 'room.delete': - return this.index.removeDoc('room', value); - } - - return true; - } - - /** - * Check if the index has to be deleted and completely new reindexed - * @param reason the reason for the provider start - * @returns {boolean} - * @private - */ - _checkForClear(reason) { - if (reason === 'startup') { - return false; - } - - if (reason === 'switch') { - return true; - } - - return ( - this._indexConfig.backendtype !== this._settings.get('Backend') || - (this._indexConfig.backendtype === 'onsite' && - this._indexConfig.baseurl !== - (this._settings.get('Base_URL').endsWith('/') ? this._settings.get('Base_URL').slice(0, -1) : this._settings.get('Base_URL'))) || - (this._indexConfig.backendtype === 'cloud' && this._indexConfig.httpOptions.headers['X-Api-Key'] !== this._settings.get('API_Key')) || - this._indexConfig.language !== this._settings.get('Main_Language') - ); - } - - /** - * parse string to object that can be used as header for HTTP calls - * @returns {{}} - * @private - */ - _parseHeaders() { - const headers = {}; - const sh = this._settings.get('HTTP_Headers').split('\n'); - sh.forEach(function (d) { - const ds = d.split(':'); - if (ds.length === 2 && ds[0].trim() !== '') { - headers[ds[0]] = ds[1]; - } - }); - return headers; - } - - /** - * ping if configuration has been set correctly - * @param config - * @param resolve if ping was successfull - * @param reject if some error occurs - * @param timeout until ping is repeated - * @private - */ - _ping(config, resolve, reject, timeout = 5000) { - const maxTimeout = 200000; - - const stats = Index.ping(config); - - if (stats) { - ChatpalLogger.debug('ping was successfull'); - resolve({ config, stats }); - } else { - ChatpalLogger.warn(`ping failed, retry in ${timeout} ms`); - - this._pingTimeout = Meteor.setTimeout(() => { - this._ping(config, resolve, reject, Math.min(maxTimeout, 2 * timeout)); - }, timeout); - } - } - - /** - * Get index config based on settings - * @param callback - * @private - */ - _getIndexConfig() { - return new Promise((resolve, reject) => { - const config = { - backendtype: this._settings.get('Backend'), - }; - - if (this._settings.get('Backend') === 'cloud') { - config.baseurl = this.chatpalBaseUrl; - config.language = this._settings.get('Main_Language'); - config.searchpath = 'search/search'; - config.updatepath = 'search/update'; - config.pingpath = 'search/ping'; - config.clearpath = 'search/clear'; - config.suggestionpath = 'search/suggest'; - config.httpOptions = { - headers: { - 'X-Api-Key': this._settings.get('API_Key'), - }, - }; - } else { - config.baseurl = this._settings.get('Base_URL').replace(/\/?$/, '/'); - config.language = this._settings.get('Main_Language'); - config.searchpath = 'chatpal/search'; - config.updatepath = 'chatpal/update'; - config.pingpath = 'chatpal/ping'; - config.clearpath = 'chatpal/clear'; - config.suggestionpath = 'chatpal/suggest'; - config.httpOptions = { - headers: this._parseHeaders(), - }; - } - - config.batchSize = this._settings.get('BatchSize'); - config.timeout = this._settings.get('TimeoutSize'); - config.windowSize = this._settings.get('WindowSize'); - - this._ping(config, resolve, reject); - }); - } - - /** - * @inheritDoc - * @param callback - */ - stop(resolve) { - ChatpalLogger.info('Provider stopped'); - Meteor.clearTimeout(this._pingTimeout); - this.indexFail = false; - this.index && this.index.stop(); - resolve(); - } - - /** - * @inheritDoc - * @param reason - * @param resolve - * @param reject - */ - start(reason, resolve, reject) { - const clear = this._checkForClear(reason); - - ChatpalLogger.debug(`clear = ${clear} with reason '${reason}'`); - - this._getIndexConfig().then((server) => { - this._indexConfig = server.config; - - this._stats = server.stats; - - ChatpalLogger.debug({ config: this._indexConfig }); - ChatpalLogger.debug({ stats: this._stats }); - - this.index = new Index(this._indexConfig, this.indexFail || clear, this._stats.message.oldest || new Date().valueOf()); - - resolve(); - }, reject); - } - - /** - * returns a list of rooms that are allowed to be seen by current user - * @param context - * @private - */ - _getAcl(context) { - let aclRoomsIds = []; - - const subscribedRooms = Subscriptions.find({ 'u._id': context.uid }) - .fetch() - .map((room) => room.rid); - aclRoomsIds = aclRoomsIds.concat(subscribedRooms); - - if (this._settings.get('IncludeAllPublicChannels')) { - const publicRooms = Rooms.findByType('c') - .fetch() - .map((room) => room._id); - aclRoomsIds = aclRoomsIds.concat(publicRooms); - } - - // return unique room ids - return [...new Set(aclRoomsIds)]; - } - - /** - * @inheritDoc - * @returns {*} - */ - search(text, context, payload, callback) { - if (!this.index) { - return callback({ msg: 'Chatpal_currently_not_active' }); - } - - const type = payload.resultType === 'All' ? ['message', 'user', 'room'] : ['message']; - const params = Object.assign({}, payload.custom); - - this.index.query( - text, - this._settings.get('Main_Language'), - payload.resultType === 'Room' ? [context.rid] : this._getAcl(context), - type, - payload.start || 0, - payload.rows || this._settings.get('PageSize'), - callback, - params, - ); - } - - /** - * @inheritDoc - */ - suggest(text, context, payload, callback) { - if (!this.index) { - return callback({ msg: 'Chatpal_currently_not_active' }); - } - - const type = payload.resultType === 'All' ? ['message', 'user', 'room'] : ['message']; - - this.index.suggest(text, this._settings.get('Main_Language'), this._getAcl(context), type, callback); - } -} - -searchProviderService.register(new ChatpalProvider()); diff --git a/apps/meteor/app/chatpal-search/server/utils/logger.js b/apps/meteor/app/chatpal-search/server/utils/logger.js deleted file mode 100644 index bfc73d4ecbc7f..0000000000000 --- a/apps/meteor/app/chatpal-search/server/utils/logger.js +++ /dev/null @@ -1,4 +0,0 @@ -import { Logger } from '../../../logger'; - -const ChatpalLogger = new Logger('Chatpal Logger'); -export default ChatpalLogger; diff --git a/apps/meteor/app/chatpal-search/server/utils/settings.js b/apps/meteor/app/chatpal-search/server/utils/settings.js deleted file mode 100644 index a1450bc16b6d7..0000000000000 --- a/apps/meteor/app/chatpal-search/server/utils/settings.js +++ /dev/null @@ -1 +0,0 @@ -export const baseUrl = (process.env.CHATPAL_URL || 'https://api.chatpal.io/v1').replace(/\/?$/, '/'); diff --git a/apps/meteor/app/chatpal-search/server/utils/utils.js b/apps/meteor/app/chatpal-search/server/utils/utils.js deleted file mode 100644 index 2e74b55705db6..0000000000000 --- a/apps/meteor/app/chatpal-search/server/utils/utils.js +++ /dev/null @@ -1,29 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { HTTP } from 'meteor/http'; - -import { baseUrl } from './settings'; - -Meteor.methods({ - chatpalUtilsCreateKey(email) { - try { - const response = HTTP.call('POST', `${baseUrl}account`, { data: { email, tier: 'free' } }); - if (response.statusCode === 201) { - return response.data.key; - } - return false; - } catch (e) { - return false; - } - }, - chatpalUtilsGetTaC(lang) { - try { - const response = HTTP.call('GET', `${baseUrl}terms/${lang}.html`); - if (response.statusCode === 200) { - return response.content; - } - return undefined; - } catch (e) { - return false; - } - }, -}); diff --git a/apps/meteor/app/cloud/server/functions/buildRegistrationData.ts b/apps/meteor/app/cloud/server/functions/buildRegistrationData.ts index a30fc190546b4..79db197033dcc 100644 --- a/apps/meteor/app/cloud/server/functions/buildRegistrationData.ts +++ b/apps/meteor/app/cloud/server/functions/buildRegistrationData.ts @@ -30,6 +30,7 @@ type WorkspaceRegistrationData = { licenseVersion: number; enterpriseReady: boolean; setupComplete: boolean; + connectionDisable: boolean; npsEnabled: SettingValue; }; @@ -49,7 +50,7 @@ export async function buildWorkspaceRegistrationData>(userId, { projection: { 'services.cloud': 1 } }); + if (!user?.services?.cloud?.accessToken || !user?.services?.cloud?.refreshToken) { + return ''; + } + + const { accessToken, refreshToken, expiresAt } = user.services.cloud; + + const clientId = settings.get('Cloud_Workspace_Client_Id'); + if (!clientId) { + return ''; + } + + const clientSecret = settings.get('Cloud_Workspace_Client_Secret'); + if (!clientSecret) { + return ''; + } + + const now = new Date(); + + if (now < expiresAt && !forceNew) { + return accessToken; + } + + const cloudUrl = settings.get('Cloud_Url'); + const redirectUri = getRedirectUri(); + + if (scope === '') { + scope = userScopes.join(' '); + } + + let authTokenResult; + try { + authTokenResult = HTTP.post(`${cloudUrl}/api/oauth/token`, { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + params: { + client_id: clientId, + client_secret: clientSecret, + refresh_token: refreshToken, + scope, + grant_type: 'refresh_token', + redirect_uri: redirectUri, + }, + }); + } catch (err: any) { + SystemLogger.error({ + msg: 'Failed to get User AccessToken from Rocket.Chat Cloud', + url: '/api/oauth/token', + ...(err.response?.data && { cloudError: err.response.data }), + err, + }); + + if (err.response?.data?.error) { + if (err.response.data.error === 'oauth_invalid_client_credentials') { + SystemLogger.error('Server has been unregistered from cloud'); + removeWorkspaceRegistrationInfo(); + } + + if (err.response.data.error === 'unauthorized') { + userLoggedOut(userId); + } + } + + return ''; + } + + if (save) { + const willExpireAt = new Date(); + willExpireAt.setSeconds(willExpireAt.getSeconds() + authTokenResult.data.expires_in); + + await Users.updateOne( + { _id: user._id }, + { + $set: { + 'services.cloud': { + accessToken: authTokenResult.data.access_token, + expiresAt: willExpireAt, + }, + }, + }, + ); + } + + return authTokenResult.data.access_token; +} diff --git a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessTokenWithScope.js b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessTokenWithScope.js index 7bcdb01c92d9d..319cf094d3d31 100644 --- a/apps/meteor/app/cloud/server/functions/getWorkspaceAccessTokenWithScope.js +++ b/apps/meteor/app/cloud/server/functions/getWorkspaceAccessTokenWithScope.js @@ -2,7 +2,7 @@ import { HTTP } from 'meteor/http'; import { getRedirectUri } from './getRedirectUri'; import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; -import { unregisterWorkspace } from './unregisterWorkspace'; +import { removeWorkspaceRegistrationInfo } from './removeWorkspaceRegistrationInfo'; import { settings } from '../../../settings/server'; import { workspaceScopes } from '../oauthScopes'; import { SystemLogger } from '../../../../server/lib/logger/system'; @@ -41,16 +41,18 @@ export function getWorkspaceAccessTokenWithScope(scope = '') { redirect_uri: redirectUri, }, }); - } catch (e) { - if (e.response && e.response.data && e.response.data.error) { - SystemLogger.error(`Failed to get AccessToken from Rocket.Chat Cloud. Error: ${e.response.data.error}`); + } catch (err) { + SystemLogger.error({ + msg: 'Failed to get Workspace AccessToken from Rocket.Chat Cloud', + url: '/api/oauth/token', + scope, + ...(err.response?.data && { cloudError: err.response.data }), + err, + }); - if (e.response.data.error === 'oauth_invalid_client_credentials') { - SystemLogger.error('Server has been unregistered from cloud'); - unregisterWorkspace(); - } - } else { - SystemLogger.error(e); + if (err.response?.data?.error === 'oauth_invalid_client_credentials') { + SystemLogger.error('Server has been unregistered from cloud'); + removeWorkspaceRegistrationInfo(); } return tokenResponse; diff --git a/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts b/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts index ac556eb33cfce..77630ad936f49 100644 --- a/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts +++ b/apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts @@ -7,11 +7,21 @@ import { callbacks } from '../../../../lib/callbacks'; import { LICENSE_VERSION } from '../license'; import { SystemLogger } from '../../../../server/lib/logger/system'; -export async function getWorkspaceLicense() { - const token = await getWorkspaceAccessToken(); +export async function getWorkspaceLicense(): Promise<{ updated: boolean; license: string }> { + const currentLicense = await Settings.findOne('Cloud_Workspace_License'); + + const cachedLicenseReturn = () => { + const license = currentLicense?.value as string; + if (license) { + callbacks.run('workspaceLicenseChanged', license); + } + + return { updated: false, license }; + }; + const token = await getWorkspaceAccessToken(); if (!token) { - return { updated: false, license: '' }; + return cachedLicenseReturn(); } let licenseResult; @@ -21,25 +31,25 @@ export async function getWorkspaceLicense() { Authorization: `Bearer ${token}`, }, }); - } catch (e: any) { - if (e.response?.data?.error) { - SystemLogger.error(`Failed to update license from Rocket.Chat Cloud. Error: ${e.response.data.error}`); - } else { - SystemLogger.error(e); - } + } catch (err: any) { + SystemLogger.error({ + msg: 'Failed to update license from Rocket.Chat Cloud', + url: '/license', + ...(err.response?.data && { cloudError: err.response.data }), + err, + }); - return { updated: false, license: '' }; + return cachedLicenseReturn(); } const remoteLicense = licenseResult.data; - const currentLicense = await Settings.findOne('Cloud_Workspace_License'); if (!currentLicense || !currentLicense._updatedAt) { throw new Error('Failed to retrieve current license'); } if (remoteLicense.updatedAt <= currentLicense._updatedAt) { - return { updated: false, license: '' }; + return cachedLicenseReturn(); } await Settings.updateValueById('Cloud_Workspace_License', remoteLicense.license); diff --git a/apps/meteor/app/cloud/server/functions/reconnectWorkspace.ts b/apps/meteor/app/cloud/server/functions/reconnectWorkspace.ts new file mode 100644 index 0000000000000..90dd1fac96a32 --- /dev/null +++ b/apps/meteor/app/cloud/server/functions/reconnectWorkspace.ts @@ -0,0 +1,17 @@ +import { Settings } from '@rocket.chat/models'; + +import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; +import { syncWorkspace } from './syncWorkspace'; + +export async function reconnectWorkspace() { + const { workspaceRegistered } = retrieveRegistrationStatus(); + if (!workspaceRegistered || process.env.TEST_MODE) { + return false; + } + + await Settings.updateValueById('Register_Server', true); + + await syncWorkspace(true); + + return true; +} diff --git a/apps/meteor/app/cloud/server/functions/registerPreIntentWorkspaceWizard.ts b/apps/meteor/app/cloud/server/functions/registerPreIntentWorkspaceWizard.ts new file mode 100644 index 0000000000000..c4f12aeaa9fe8 --- /dev/null +++ b/apps/meteor/app/cloud/server/functions/registerPreIntentWorkspaceWizard.ts @@ -0,0 +1,33 @@ +import { HTTP } from 'meteor/http'; +import type { IUser } from '@rocket.chat/core-typings'; + +import { settings } from '../../../settings/server'; +import { buildWorkspaceRegistrationData } from './buildRegistrationData'; +import { SystemLogger } from '../../../../server/lib/logger/system'; +import { Users } from '../../../models/server'; + +export async function registerPreIntentWorkspaceWizard(): Promise { + const firstUser = Users.getOldest({ name: 1, emails: 1 }) as IUser | undefined; + const email = firstUser?.emails?.find((address) => address)?.address || ''; + + const regInfo = await buildWorkspaceRegistrationData(email); + const cloudUrl = settings.get('Cloud_Url'); + + try { + HTTP.post(`${cloudUrl}/api/v2/register/workspace/pre-intent`, { + data: regInfo, + timeout: 10 * 1000, + }); + + return true; + } catch (err: any) { + SystemLogger.error({ + msg: 'Failed to register workspace pre-intent with Rocket.Chat Cloud', + url: '/api/v2/register/workspace/pre-intent', + ...(err.response?.data && { cloudError: err.response.data }), + err, + }); + + return false; + } +} diff --git a/apps/meteor/app/cloud/server/functions/removeWorkspaceRegistrationInfo.ts b/apps/meteor/app/cloud/server/functions/removeWorkspaceRegistrationInfo.ts new file mode 100644 index 0000000000000..a8e21257560fb --- /dev/null +++ b/apps/meteor/app/cloud/server/functions/removeWorkspaceRegistrationInfo.ts @@ -0,0 +1,22 @@ +import { Settings } from '@rocket.chat/models'; + +import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; + +export async function removeWorkspaceRegistrationInfo() { + const { workspaceRegistered } = retrieveRegistrationStatus(); + if (!workspaceRegistered) { + return true; + } + + await Promise.all([ + Settings.updateValueById('Cloud_Workspace_Id', null), + Settings.updateValueById('Cloud_Workspace_Name', null), + Settings.updateValueById('Cloud_Workspace_Client_Id', null), + Settings.updateValueById('Cloud_Workspace_Client_Secret', null), + Settings.updateValueById('Cloud_Workspace_Client_Secret_Expires_At', null), + Settings.updateValueById('Cloud_Workspace_PublicKey', null), + Settings.updateValueById('Cloud_Workspace_Registration_Client_Uri', null), + ]); + + return true; +} diff --git a/apps/meteor/app/cloud/server/functions/retrieveRegistrationStatus.ts b/apps/meteor/app/cloud/server/functions/retrieveRegistrationStatus.ts index d7761b0f067ef..66b8e66b60a38 100644 --- a/apps/meteor/app/cloud/server/functions/retrieveRegistrationStatus.ts +++ b/apps/meteor/app/cloud/server/functions/retrieveRegistrationStatus.ts @@ -11,7 +11,7 @@ export function retrieveRegistrationStatus(): { } { const info = { connectToCloud: settings.get('Register_Server'), - workspaceRegistered: !!settings.get('Cloud_Workspace_Client_Id'), + workspaceRegistered: !!settings.get('Cloud_Workspace_Client_Id') && !!settings.get('Cloud_Workspace_Client_Secret'), workspaceId: settings.get('Cloud_Workspace_Id'), uniqueId: settings.get('uniqueID'), token: '', diff --git a/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts b/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts index a3a19810cafcb..4d73fd3d7c73a 100644 --- a/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts +++ b/apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts @@ -26,12 +26,14 @@ export async function startRegisterWorkspace(resend = false) { result = HTTP.post(`${cloudUrl}/api/v2/register/workspace?resend=${resend}`, { data: regInfo, }); - } catch (e: any) { - if (e.response?.data?.error) { - SystemLogger.error(`Failed to register with Rocket.Chat Cloud. ErrorCode: ${e.response.data.error}`); - } else { - SystemLogger.error(e); - } + } catch (err: any) { + SystemLogger.error({ + msg: 'Failed to register with Rocket.Chat Cloud', + url: '/api/v2/register/workspace', + ...(err.response?.data && { cloudError: err.response.data }), + err, + }); + return false; } const { data } = result; diff --git a/apps/meteor/app/cloud/server/functions/startRegisterWorkspaceSetupWizard.ts b/apps/meteor/app/cloud/server/functions/startRegisterWorkspaceSetupWizard.ts index d0aa9e77045e8..bb17647772e59 100644 --- a/apps/meteor/app/cloud/server/functions/startRegisterWorkspaceSetupWizard.ts +++ b/apps/meteor/app/cloud/server/functions/startRegisterWorkspaceSetupWizard.ts @@ -14,14 +14,15 @@ export async function startRegisterWorkspaceSetupWizard(resend = false, email: s result = HTTP.post(`${cloudUrl}/api/v2/register/workspace/intent?resent=${resend}`, { data: regInfo, }); - } catch (e: any) { - if (e.response?.data?.error) { - SystemLogger.error(`Failed to register with Rocket.Chat Cloud. ErrorCode: ${e.response.data.error}`); - } else { - SystemLogger.error(e); - } + } catch (err: any) { + SystemLogger.error({ + msg: 'Failed to register workspace intent with Rocket.Chat Cloud', + url: '/api/v2/register/workspace', + ...(err.response?.data && { cloudError: err.response.data }), + err, + }); - throw e; + throw err; } const { data } = result; diff --git a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts index 72f0a2eb33519..01462542ebf90 100644 --- a/apps/meteor/app/cloud/server/functions/syncWorkspace.ts +++ b/apps/meteor/app/cloud/server/functions/syncWorkspace.ts @@ -1,5 +1,6 @@ import { HTTP } from 'meteor/http'; import { Settings } from '@rocket.chat/models'; +import { NPS, Banner } from '@rocket.chat/core-services'; import { buildWorkspaceRegistrationData } from './buildRegistrationData'; import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; @@ -7,7 +8,6 @@ import { getWorkspaceAccessToken } from './getWorkspaceAccessToken'; import { getWorkspaceLicense } from './getWorkspaceLicense'; import { settings } from '../../../settings/server'; import { getAndCreateNpsSurvey } from '../../../../server/services/nps/getAndCreateNpsSurvey'; -import { NPS, Banner } from '../../../../server/sdk'; import { SystemLogger } from '../../../../server/lib/logger/system'; export async function syncWorkspace(reconnectCheck = false) { @@ -35,16 +35,18 @@ export async function syncWorkspace(reconnectCheck = false) { data: info, headers, }); - - await getWorkspaceLicense(); - } catch (e: any) { - if (e.response?.data?.error) { - SystemLogger.error(`Failed to sync with Rocket.Chat Cloud. Error: ${e.response.data.error}`); - } else { - SystemLogger.error(e); - } + } catch (err: any) { + SystemLogger.error({ + msg: 'Failed to sync with Rocket.Chat Cloud', + url: '/client', + ...(err.response?.data && { cloudError: err.response.data }), + err, + }); return false; + } finally { + // aways fetch the license + await getWorkspaceLicense(); } const { data } = result; diff --git a/apps/meteor/app/cloud/server/functions/unregisterWorkspace.ts b/apps/meteor/app/cloud/server/functions/unregisterWorkspace.ts deleted file mode 100644 index e4023b6f66f7b..0000000000000 --- a/apps/meteor/app/cloud/server/functions/unregisterWorkspace.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Settings } from '@rocket.chat/models'; - -import { retrieveRegistrationStatus } from './retrieveRegistrationStatus'; - -export async function unregisterWorkspace() { - const { workspaceRegistered } = retrieveRegistrationStatus(); - if (!workspaceRegistered) { - return true; - } - - await Promise.all([ - Settings.updateValueById('Cloud_Workspace_Id', null), - Settings.updateValueById('Cloud_Workspace_Name', null), - Settings.updateValueById('Cloud_Workspace_Client_Id', null), - Settings.updateValueById('Cloud_Workspace_Client_Secret', null), - Settings.updateValueById('Cloud_Workspace_Client_Secret_Expires_At', null), - Settings.updateValueById('Cloud_Workspace_PublicKey', null), - Settings.updateValueById('Cloud_Workspace_Registration_Client_Uri', null), - ]); - - return true; -} diff --git a/apps/meteor/app/cloud/server/functions/userLogout.js b/apps/meteor/app/cloud/server/functions/userLogout.js index 6d2e917f347d3..5e133ac3e3240 100644 --- a/apps/meteor/app/cloud/server/functions/userLogout.js +++ b/apps/meteor/app/cloud/server/functions/userLogout.js @@ -40,12 +40,13 @@ export function userLogout(userId) { token_type_hint: 'refresh_token', }, }); - } catch (e) { - if (e.response && e.response.data && e.response.data.error) { - SystemLogger.error(`Failed to get Revoke refresh token to logout of Rocket.Chat Cloud. Error: ${e.response.data.error}`); - } else { - SystemLogger.error(e); - } + } catch (err) { + SystemLogger.error({ + msg: 'Failed to get Revoke refresh token to logout of Rocket.Chat Cloud', + url: '/api/oauth/revoke', + ...(err.response?.data && { cloudError: err.response.data }), + err, + }); } } diff --git a/apps/meteor/app/cloud/server/methods.js b/apps/meteor/app/cloud/server/methods.js index cb642a41dc1c3..bb34babf5be59 100644 --- a/apps/meteor/app/cloud/server/methods.js +++ b/apps/meteor/app/cloud/server/methods.js @@ -3,6 +3,7 @@ import { check } from 'meteor/check'; import { retrieveRegistrationStatus } from './functions/retrieveRegistrationStatus'; import { connectWorkspace } from './functions/connectWorkspace'; +import { reconnectWorkspace } from './functions/reconnectWorkspace'; import { getOAuthAuthorizationUrl } from './functions/getOAuthAuthorizationUrl'; import { finishOAuthAuthorization } from './functions/finishOAuthAuthorization'; import { startRegisterWorkspace } from './functions/startRegisterWorkspace'; @@ -47,13 +48,13 @@ Meteor.methods({ async 'cloud:registerWorkspace'() { if (!Meteor.userId()) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'cloud:startRegister', + method: 'cloud:registerWorkspace', }); } if (!hasPermission(Meteor.userId(), 'manage-cloud')) { throw new Meteor.Error('error-not-authorized', 'Not authorized', { - method: 'cloud:startRegister', + method: 'cloud:registerWorkspace', }); } @@ -79,19 +80,19 @@ Meteor.methods({ if (!Meteor.userId()) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'cloud:connectServer', + method: 'cloud:connectWorkspace', }); } if (!hasPermission(Meteor.userId(), 'manage-cloud')) { throw new Meteor.Error('error-not-authorized', 'Not authorized', { - method: 'cloud:connectServer', + method: 'cloud:connectWorkspace', }); } if (!token) { throw new Meteor.Error('error-invalid-payload', 'Token is required.', { - method: 'cloud:connectServer', + method: 'cloud:connectWorkspace', }); } @@ -112,17 +113,32 @@ Meteor.methods({ return disconnectWorkspace(); }, + 'cloud:reconnectWorkspace'() { + if (!Meteor.userId()) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'cloud:reconnectWorkspace', + }); + } + + if (!hasPermission(Meteor.userId(), 'manage-cloud')) { + throw new Meteor.Error('error-not-authorized', 'Not authorized', { + method: 'cloud:reconnectWorkspace', + }); + } + + return reconnectWorkspace(); + }, // Currently unused but will link local account to Rocket.Chat Cloud account. 'cloud:getOAuthAuthorizationUrl'() { if (!Meteor.userId()) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'cloud:connectServer', + method: 'cloud:getOAuthAuthorizationUrl', }); } if (!hasPermission(Meteor.userId(), 'manage-cloud')) { throw new Meteor.Error('error-not-authorized', 'Not authorized', { - method: 'cloud:connectServer', + method: 'cloud:getOAuthAuthorizationUrl', }); } @@ -140,7 +156,7 @@ Meteor.methods({ if (!hasPermission(Meteor.userId(), 'manage-cloud')) { throw new Meteor.Error('error-not-authorized', 'Not authorized', { - method: 'cloud:connectServer', + method: 'cloud:finishOAuthAuthorization', }); } @@ -149,13 +165,13 @@ Meteor.methods({ 'cloud:checkUserLoggedIn'() { if (!Meteor.userId()) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'cloud:connectServer', + method: 'cloud:checkUserLoggedIn', }); } if (!hasPermission(Meteor.userId(), 'manage-cloud')) { throw new Meteor.Error('error-not-authorized', 'Not authorized', { - method: 'cloud:connectServer', + method: 'cloud:checkUserLoggedIn', }); } @@ -164,13 +180,13 @@ Meteor.methods({ 'cloud:logout'() { if (!Meteor.userId()) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'cloud:connectServer', + method: 'cloud:logout', }); } if (!hasPermission(Meteor.userId(), 'manage-cloud')) { throw new Meteor.Error('error-not-authorized', 'Not authorized', { - method: 'cloud:connectServer', + method: 'cloud:logout', }); } diff --git a/apps/meteor/app/colors/client/index.js b/apps/meteor/app/colors/client/index.ts similarity index 100% rename from apps/meteor/app/colors/client/index.js rename to apps/meteor/app/colors/client/index.ts diff --git a/apps/meteor/app/colors/server/index.js b/apps/meteor/app/colors/server/index.js deleted file mode 100644 index 97097791afdc4..0000000000000 --- a/apps/meteor/app/colors/server/index.js +++ /dev/null @@ -1 +0,0 @@ -import './settings'; diff --git a/apps/meteor/app/autolinker/server/index.js b/apps/meteor/app/colors/server/index.ts similarity index 100% rename from apps/meteor/app/autolinker/server/index.js rename to apps/meteor/app/colors/server/index.ts diff --git a/apps/meteor/app/cors/server/cors.js b/apps/meteor/app/cors/server/cors.js index c4f3c9e7693c6..cc6bcefb93216 100644 --- a/apps/meteor/app/cors/server/cors.js +++ b/apps/meteor/app/cors/server/cors.js @@ -35,7 +35,17 @@ WebApp.rawConnectHandlers.use(function (req, res, next) { ] .filter(Boolean) .join(' '); - const external = [settings.get('Accounts_OAuth_Apple') && 'https://appleid.cdn-apple.com'].filter(Boolean).join(' '); + const external = [ + settings.get('Accounts_OAuth_Apple') && 'https://appleid.cdn-apple.com', + settings.get('PiwikAnalytics_enabled') && settings.get('PiwikAnalytics_url'), + settings.get('GoogleAnalytics_enabled' && 'https://www.google-analytics.com'), + ...settings + .get('Extra_CSP_Domains') + .split(/[ \n\,]/gim) + .filter((e) => Boolean(e.trim())), + ] + .filter(Boolean) + .join(' '); res.setHeader( 'Content-Security-Policy', [ diff --git a/apps/meteor/app/crowd/client/index.js b/apps/meteor/app/crowd/client/index.ts similarity index 100% rename from apps/meteor/app/crowd/client/index.js rename to apps/meteor/app/crowd/client/index.ts diff --git a/apps/meteor/app/crowd/server/crowd.js b/apps/meteor/app/crowd/server/crowd.js index 535e4e130b74e..60211545cc5a1 100644 --- a/apps/meteor/app/crowd/server/crowd.js +++ b/apps/meteor/app/crowd/server/crowd.js @@ -197,9 +197,9 @@ export class CROWD { try { crowdUser = self.fetchCrowdUser(crowd_username); - } catch (error) { - logger.debug(error); - logger.error('Could not sync user with username', crowd_username); + } catch (err) { + logger.debug({ err }); + logger.error({ msg: 'Could not sync user with username', crowd_username }); const email = user.emails[0].address; logger.info('Attempting to find for user by email', email); @@ -272,8 +272,8 @@ export class CROWD { return { userId: crowdUser._id, }; - } catch (error) { - logger.error('Error creating new crowd user.', error.message); + } catch (err) { + logger.error({ msg: 'Error creating new crowd user.', err }); } } } @@ -304,8 +304,8 @@ Accounts.registerLoginHandler('crowd', function (loginRequest) { } return crowd.updateUserCollection(user); - } catch (error) { - logger.debug(error); + } catch (err) { + logger.debug({ err }); logger.error('Crowd user not authenticated due to an error'); } }); @@ -362,10 +362,11 @@ Meteor.methods({ message: 'Connection success', params: [], }; - } catch (error) { - logger.error( - 'Invalid crowd connection details, check the url and application username/password and make sure this server is allowed to speak to crowd', - ); + } catch (err) { + logger.error({ + msg: 'Invalid crowd connection details, check the url and application username/password and make sure this server is allowed to speak to crowd', + err, + }); throw new Meteor.Error('Invalid connection details', '', { method: 'crowd_test_connection' }); } }, @@ -392,8 +393,8 @@ Meteor.methods({ message: `User data synced in ${actual} seconds`, params: [], }; - } catch (error) { - logger.error('Error syncing user data. ', error.message); + } catch (err) { + logger.error({ msg: 'Error syncing user data. ', err }); throw new Meteor.Error('Error syncing user data', '', { method: 'crowd_sync_users' }); } }, diff --git a/apps/meteor/app/crowd/server/index.js b/apps/meteor/app/crowd/server/index.ts similarity index 100% rename from apps/meteor/app/crowd/server/index.js rename to apps/meteor/app/crowd/server/index.ts diff --git a/apps/meteor/app/custom-oauth/server/custom_oauth_server.js b/apps/meteor/app/custom-oauth/server/custom_oauth_server.js index c87a54999a9d6..18f1321118ecb 100644 --- a/apps/meteor/app/custom-oauth/server/custom_oauth_server.js +++ b/apps/meteor/app/custom-oauth/server/custom_oauth_server.js @@ -354,7 +354,8 @@ export class CustomOAuth { user.services && user.services[serviceName] && user.services[serviceName].id === serviceData.id && - user.name === serviceData.name + user.name === serviceData.name && + (this.keyField === 'email' || user.emails?.find(({ address }) => address === serviceData.email)) ) { return; } @@ -367,6 +368,7 @@ export class CustomOAuth { const update = { $set: { name: serviceData.name, + ...(this.keyField === 'username' && serviceData.email && { emails: [{ address: serviceData.email, verified: true }] }), [serviceIdKey]: serviceData.id, }, }; @@ -392,12 +394,6 @@ export class CustomOAuth { user.name = user.services[this.name].name; } - callbacks.run('afterValidateNewOAuthUser', { - identity: user.services[this.name], - serviceName: this.name, - user, - }); - return true; }); } @@ -443,5 +439,15 @@ Accounts.updateOrCreateUserFromExternalService = function (...args /* serviceNam hook.apply(this, args); } - return updateOrCreateUserFromExternalService.apply(this, args); + const [serviceName, serviceData] = args; + + const user = updateOrCreateUserFromExternalService.apply(this, args); + + callbacks.run('afterValidateNewOAuthUser', { + identity: serviceData, + serviceName, + user: Users.findOneById(user.userId), + }); + + return user; }; diff --git a/apps/meteor/app/custom-sounds/client/index.js b/apps/meteor/app/custom-sounds/client/index.ts similarity index 100% rename from apps/meteor/app/custom-sounds/client/index.js rename to apps/meteor/app/custom-sounds/client/index.ts diff --git a/apps/meteor/app/custom-sounds/client/lib/CustomSounds.js b/apps/meteor/app/custom-sounds/client/lib/CustomSounds.js index 5ab7049466194..28d5bfc19b4cd 100644 --- a/apps/meteor/app/custom-sounds/client/lib/CustomSounds.js +++ b/apps/meteor/app/custom-sounds/client/lib/CustomSounds.js @@ -1,8 +1,7 @@ import { Meteor } from 'meteor/meteor'; import { ReactiveVar } from 'meteor/reactive-var'; -import _ from 'underscore'; -import { CachedCollectionManager } from '../../../ui-cached-collection'; +import { CachedCollectionManager } from '../../../ui-cached-collection/client'; import { getURL } from '../../../utils/client'; const getCustomSoundId = (sound) => `custom-sound-${sound}`; @@ -95,7 +94,7 @@ class CustomSoundsClass { getList() { const list = Object.values(this.list.get()); - return _.sortBy(list, 'name'); + return list.sort((a, b) => (a.name ?? '').localeCompare(b.name ?? '')); } play = (sound, { volume = 1, loop = false } = {}) => { @@ -118,9 +117,6 @@ class CustomSoundsClass { } audio.pause(); - if (audio.currentTime !== 0) { - audio.currentTime = 0; - } }; isPlaying = (sound) => { diff --git a/apps/meteor/app/custom-sounds/client/notifications/deleteCustomSound.js b/apps/meteor/app/custom-sounds/client/notifications/deleteCustomSound.js index 7472fd1f834d7..51aafda75c489 100644 --- a/apps/meteor/app/custom-sounds/client/notifications/deleteCustomSound.js +++ b/apps/meteor/app/custom-sounds/client/notifications/deleteCustomSound.js @@ -1,6 +1,6 @@ import { Meteor } from 'meteor/meteor'; -import { CachedCollectionManager } from '../../../ui-cached-collection'; +import { CachedCollectionManager } from '../../../ui-cached-collection/client'; import { Notifications } from '../../../notifications'; import { CustomSounds } from '../lib/CustomSounds'; diff --git a/apps/meteor/app/custom-sounds/client/notifications/updateCustomSound.js b/apps/meteor/app/custom-sounds/client/notifications/updateCustomSound.js index 4005efb3aaf0a..68c75204ef622 100644 --- a/apps/meteor/app/custom-sounds/client/notifications/updateCustomSound.js +++ b/apps/meteor/app/custom-sounds/client/notifications/updateCustomSound.js @@ -1,6 +1,6 @@ import { Meteor } from 'meteor/meteor'; -import { CachedCollectionManager } from '../../../ui-cached-collection'; +import { CachedCollectionManager } from '../../../ui-cached-collection/client'; import { Notifications } from '../../../notifications'; import { CustomSounds } from '../lib/CustomSounds'; diff --git a/apps/meteor/app/custom-sounds/server/index.js b/apps/meteor/app/custom-sounds/server/index.ts similarity index 100% rename from apps/meteor/app/custom-sounds/server/index.js rename to apps/meteor/app/custom-sounds/server/index.ts diff --git a/apps/meteor/app/custom-sounds/server/methods/deleteCustomSound.js b/apps/meteor/app/custom-sounds/server/methods/deleteCustomSound.js index 1a51820ec6e86..3c21c4d89b964 100644 --- a/apps/meteor/app/custom-sounds/server/methods/deleteCustomSound.js +++ b/apps/meteor/app/custom-sounds/server/methods/deleteCustomSound.js @@ -1,8 +1,8 @@ import { Meteor } from 'meteor/meteor'; import { CustomSounds } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; import { hasPermission } from '../../../authorization/server'; -import { api } from '../../../../server/sdk/api'; import { RocketChatFileCustomSoundsInstance } from '../startup/custom-sounds'; Meteor.methods({ diff --git a/apps/meteor/app/custom-sounds/server/methods/insertOrUpdateSound.js b/apps/meteor/app/custom-sounds/server/methods/insertOrUpdateSound.js index d5cf8ae377bc0..4f687dbbcb927 100644 --- a/apps/meteor/app/custom-sounds/server/methods/insertOrUpdateSound.js +++ b/apps/meteor/app/custom-sounds/server/methods/insertOrUpdateSound.js @@ -1,11 +1,11 @@ import { Meteor } from 'meteor/meteor'; -import s from 'underscore.string'; import { check } from 'meteor/check'; import { CustomSounds } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; import { hasPermission } from '../../../authorization/server'; -import { api } from '../../../../server/sdk/api'; import { RocketChatFileCustomSoundsInstance } from '../startup/custom-sounds'; +import { trim } from '../../../../lib/utils/stringUtils'; Meteor.methods({ async insertOrUpdateSound(soundData) { @@ -13,7 +13,7 @@ Meteor.methods({ throw new Meteor.Error('not_authorized'); } - if (!s.trim(soundData.name)) { + if (!trim(soundData.name)) { throw new Meteor.Error('error-the-field-is-required', 'The field Name is required', { method: 'insertOrUpdateSound', field: 'Name', diff --git a/apps/meteor/app/custom-sounds/server/methods/uploadCustomSound.js b/apps/meteor/app/custom-sounds/server/methods/uploadCustomSound.js index 6339033487026..2d9dff22cdf2b 100644 --- a/apps/meteor/app/custom-sounds/server/methods/uploadCustomSound.js +++ b/apps/meteor/app/custom-sounds/server/methods/uploadCustomSound.js @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; +import { api } from '@rocket.chat/core-services'; import { hasPermission } from '../../../authorization/server'; -import { api } from '../../../../server/sdk/api'; import { RocketChatFile } from '../../../file/server'; import { RocketChatFileCustomSoundsInstance } from '../startup/custom-sounds'; @@ -16,10 +16,7 @@ Meteor.methods({ const rs = RocketChatFile.bufferToStream(file); RocketChatFileCustomSoundsInstance.deleteFile(`${soundData._id}.${soundData.extension}`); const ws = RocketChatFileCustomSoundsInstance.createWriteStream(`${soundData._id}.${soundData.extension}`, contentType); - ws.on( - 'end', - setTimeout(() => api.broadcast('notify.updateCustomSound', { soundData }), 500), - ); + ws.on('end', () => setTimeout(() => api.broadcast('notify.updateCustomSound', { soundData }), 500)); rs.pipe(ws); }, diff --git a/apps/meteor/app/custom/client/index.js b/apps/meteor/app/custom/client/index.js deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/apps/meteor/app/custom/server/index.js b/apps/meteor/app/custom/server/index.js deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/apps/meteor/app/discussion/client/createDiscussionMessageAction.ts b/apps/meteor/app/discussion/client/createDiscussionMessageAction.ts index 2b99ff50a022b..785a2114b0478 100644 --- a/apps/meteor/app/discussion/client/createDiscussionMessageAction.ts +++ b/apps/meteor/app/discussion/client/createDiscussionMessageAction.ts @@ -54,6 +54,10 @@ Meteor.startup(function () { return false; } + if (!user) { + return false; + } + return uid !== user._id ? hasPermission('start-discussion-other-user') : hasPermission('start-discussion'); }, order: 1, diff --git a/apps/meteor/app/discussion/client/discussionFromMessageBox.js b/apps/meteor/app/discussion/client/discussionFromMessageBox.js deleted file mode 100644 index eb2d67e53dc1d..0000000000000 --- a/apps/meteor/app/discussion/client/discussionFromMessageBox.js +++ /dev/null @@ -1,30 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Tracker } from 'meteor/tracker'; - -import { messageBox } from '../../ui-utils/client'; -import { settings } from '../../settings/client'; -import { hasPermission } from '../../authorization/client'; -import { imperativeModal } from '../../../client/lib/imperativeModal'; -import CreateDiscussion from '../../../client/components/CreateDiscussion/CreateDiscussion'; - -Meteor.startup(function () { - Tracker.autorun(() => { - if (!settings.get('Discussion_enabled')) { - return messageBox.actions.remove('Create_new', /start-discussion/); - } - messageBox.actions.add('Create_new', 'Discussion', { - id: 'start-discussion', - icon: 'discussion', - condition: () => hasPermission('start-discussion') || hasPermission('start-discussion-other-user'), - action(data) { - imperativeModal.open({ - component: CreateDiscussion, - props: { - defaultParentRoom: data.prid || data.rid, - onClose: imperativeModal.close, - }, - }); - }, - }); - }); -}); diff --git a/apps/meteor/app/discussion/client/index.js b/apps/meteor/app/discussion/client/index.js deleted file mode 100644 index 25f06f1a7bb4d..0000000000000 --- a/apps/meteor/app/discussion/client/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Other UI extensions -import './lib/messageTypes/discussionMessage'; -import './createDiscussionMessageAction'; -import './discussionFromMessageBox'; -import './tabBar'; diff --git a/apps/meteor/app/discussion/client/index.ts b/apps/meteor/app/discussion/client/index.ts new file mode 100644 index 0000000000000..f45e6458ae7a4 --- /dev/null +++ b/apps/meteor/app/discussion/client/index.ts @@ -0,0 +1,4 @@ +// Other UI extensions +import './lib/messageTypes/discussionMessage'; +import './createDiscussionMessageAction'; +import './tabBar'; diff --git a/apps/meteor/app/discussion/client/views/DiscussionTabbar.html b/apps/meteor/app/discussion/client/views/DiscussionTabbar.html deleted file mode 100644 index 80f65ec9d16c1..0000000000000 --- a/apps/meteor/app/discussion/client/views/DiscussionTabbar.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/apps/meteor/app/discussion/server/index.js b/apps/meteor/app/discussion/server/index.ts similarity index 100% rename from apps/meteor/app/discussion/server/index.js rename to apps/meteor/app/discussion/server/index.ts diff --git a/apps/meteor/app/discussion/server/methods/createDiscussion.js b/apps/meteor/app/discussion/server/methods/createDiscussion.js deleted file mode 100644 index 212201f2b2937..0000000000000 --- a/apps/meteor/app/discussion/server/methods/createDiscussion.js +++ /dev/null @@ -1,186 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Random } from 'meteor/random'; -import { Match } from 'meteor/check'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; - -import { hasAtLeastOnePermission, canSendMessage } from '../../../authorization/server'; -import { Messages, Rooms } from '../../../models/server'; -import { createRoom, addUserToRoom, sendMessage, attachMessage } from '../../../lib/server'; -import { settings } from '../../../settings/server'; -import { callbacks } from '../../../../lib/callbacks'; -import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator'; - -const getParentRoom = (rid) => { - const room = Rooms.findOne(rid); - return room && (room.prid ? Rooms.findOne(room.prid, { fields: { _id: 1 } }) : room); -}; - -const createDiscussionMessage = (rid, user, drid, msg, message_embedded) => { - const welcomeMessage = { - msg, - rid, - drid, - attachments: [message_embedded].filter((e) => e), - }; - return Messages.createWithTypeRoomIdMessageAndUser('discussion-created', rid, '', user, welcomeMessage); -}; - -const mentionMessage = (rid, { _id, username, name }, message_embedded) => { - const welcomeMessage = { - rid, - u: { _id, username, name }, - ts: new Date(), - _updatedAt: new Date(), - attachments: [message_embedded].filter((e) => e), - }; - - return Messages.insert(welcomeMessage); -}; - -const create = ({ prid, pmid, t_name, reply, users, user, encrypted }) => { - // if you set both, prid and pmid, and the rooms dont match... should throw an error) - let message = false; - if (pmid) { - message = Messages.findOne({ _id: pmid }); - if (!message) { - throw new Meteor.Error('error-invalid-message', 'Invalid message', { - method: 'DiscussionCreation', - }); - } - if (prid) { - if (prid !== getParentRoom(message.rid)._id) { - throw new Meteor.Error('error-invalid-arguments', { method: 'DiscussionCreation' }); - } - } else { - prid = message.rid; - } - } - - if (!prid) { - throw new Meteor.Error('error-invalid-arguments', { method: 'DiscussionCreation' }); - } - - let p_room; - try { - p_room = canSendMessage(prid, { uid: user._id, username: user.username, type: user.type }); - } catch (error) { - throw new Meteor.Error(error.message); - } - - if (p_room.prid) { - throw new Meteor.Error('error-nested-discussion', 'Cannot create nested discussions', { - method: 'DiscussionCreation', - }); - } - - if (!Match.Maybe(encrypted, Boolean)) { - throw new Meteor.Error('error-invalid-arguments', 'Invalid encryption state', { - method: 'DiscussionCreation', - }); - } - - if (typeof encrypted !== 'boolean') { - encrypted = p_room.encrypted; - } - - if (encrypted && reply) { - throw new Meteor.Error('error-invalid-arguments', 'Encrypted discussions must not receive an initial reply.', { - method: 'DiscussionCreation', - }); - } - - if (pmid) { - const discussionAlreadyExists = Rooms.findOne( - { - prid, - pmid, - }, - { - fields: { _id: 1 }, - }, - ); - if (discussionAlreadyExists) { - // do not allow multiple discussions to the same message'\ - addUserToRoom(discussionAlreadyExists._id, user); - return discussionAlreadyExists; - } - } - - const name = Random.id(); - - // auto invite the replied message owner - const invitedUsers = message ? [message.u.username, ...users] : users; - - const type = roomCoordinator.getRoomDirectives(p_room.t)?.getDiscussionType(); - const description = p_room.encrypted ? '' : message.msg; - const topic = p_room.name; - - const discussion = createRoom( - type, - name, - user.username, - [...new Set(invitedUsers)], - false, - { - fname: t_name, - description, // TODO discussions remove - topic, // TODO discussions remove - prid, - encrypted, - }, - { - // overrides name validation to allow anything, because discussion's name is randomly generated - nameValidationRegex: /.*/, - }, - ); - - let discussionMsg; - if (pmid) { - if (p_room.encrypted) { - message.msg = TAPi18n.__('Encrypted_message'); - } - mentionMessage(discussion._id, user, attachMessage(message, p_room)); - - discussionMsg = createDiscussionMessage(message.rid, user, discussion._id, t_name, attachMessage(message, p_room)); - } else { - discussionMsg = createDiscussionMessage(prid, user, discussion._id, t_name); - } - - callbacks.runAsync('afterSaveMessage', discussionMsg, p_room); - - if (reply) { - sendMessage(user, { msg: reply }, discussion); - } - return discussion; -}; - -Meteor.methods({ - /** - * Create discussion by room or message - * @constructor - * @param {string} prid - Parent Room Id - The room id, optional if you send pmid. - * @param {string} pmid - Parent Message Id - Create the discussion by a message, optional. - * @param {string} reply - The reply, optional - * @param {string} t_name - discussion name - * @param {string[]} users - users to be added - * @param {boolean} encrypted - if the discussion's e2e encryption should be enabled. - */ - createDiscussion({ prid, pmid, t_name, reply, users, encrypted }) { - if (!settings.get('Discussion_enabled')) { - throw new Meteor.Error('error-action-not-allowed', 'You are not allowed to create a discussion', { method: 'createDiscussion' }); - } - - const uid = Meteor.userId(); - if (!uid) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'DiscussionCreation', - }); - } - - if (!hasAtLeastOnePermission(uid, ['start-discussion', 'start-discussion-other-user'])) { - throw new Meteor.Error('error-action-not-allowed', 'You are not allowed to create a discussion', { method: 'createDiscussion' }); - } - - return create({ uid, prid, pmid, t_name, reply, users, user: Meteor.user(), encrypted }); - }, -}); diff --git a/apps/meteor/app/discussion/server/methods/createDiscussion.ts b/apps/meteor/app/discussion/server/methods/createDiscussion.ts new file mode 100644 index 0000000000000..e400940991389 --- /dev/null +++ b/apps/meteor/app/discussion/server/methods/createDiscussion.ts @@ -0,0 +1,209 @@ +import { Meteor } from 'meteor/meteor'; +import { Random } from 'meteor/random'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import type { IMessage, IRoom, IUser, MessageAttachmentDefault } from '@rocket.chat/core-typings'; + +import { hasAtLeastOnePermission, canSendMessage } from '../../../authorization/server'; +import { Messages, Rooms } from '../../../models/server'; +import { createRoom, addUserToRoom, sendMessage, attachMessage } from '../../../lib/server'; +import { settings } from '../../../settings/server'; +import { callbacks } from '../../../../lib/callbacks'; +import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator'; + +const getParentRoom = (rid: IRoom['_id']) => { + const room = Rooms.findOne(rid); + return room && (room.prid ? Rooms.findOne(room.prid, { fields: { _id: 1 } }) : room); +}; + +const createDiscussionMessage = ( + rid: IRoom['_id'], + user: IUser, + drid: IRoom['_id'], + msg: IMessage['msg'], + messageEmbedded?: MessageAttachmentDefault, +): IMessage => { + const welcomeMessage = { + msg, + rid, + drid, + attachments: [messageEmbedded].filter((e) => e), + }; + return Messages.createWithTypeRoomIdMessageAndUser('discussion-created', rid, '', user, welcomeMessage) as IMessage; +}; + +const mentionMessage = ( + rid: IRoom['_id'], + { _id, username, name }: Pick, + messageEmbedded?: MessageAttachmentDefault, +) => { + const welcomeMessage = { + rid, + u: { _id, username, name }, + ts: new Date(), + _updatedAt: new Date(), + attachments: [messageEmbedded].filter((e) => e), + }; + + return Messages.insert(welcomeMessage); +}; + +type CreateDiscussionProperties = { + prid: IRoom['_id']; + pmid?: IMessage['_id']; + t_name: string; + reply?: string; + users: Array>; + user: IUser; + encrypted?: boolean; +}; + +const create = ({ prid, pmid, t_name: discussionName, reply, users, user, encrypted }: CreateDiscussionProperties) => { + // if you set both, prid and pmid, and the rooms dont match... should throw an error) + let message: undefined | IMessage; + if (pmid) { + message = Messages.findOne({ _id: pmid }) as IMessage | undefined; + if (!message) { + throw new Meteor.Error('error-invalid-message', 'Invalid message', { + method: 'DiscussionCreation', + }); + } + if (prid) { + if (prid !== getParentRoom(message.rid)._id) { + throw new Meteor.Error('error-invalid-arguments', 'Root message room ID does not match parent room ID ', { + method: 'DiscussionCreation', + }); + } + } else { + prid = message.rid; + } + } + + if (!prid) { + throw new Meteor.Error('error-invalid-arguments', 'Missing parent room ID', { method: 'DiscussionCreation' }); + } + + let parentRoom; + try { + parentRoom = canSendMessage(prid, { uid: user._id, username: user.username, type: user.type }); + } catch (error) { + throw new Meteor.Error((error as Error).message); + } + + if (parentRoom.prid) { + throw new Meteor.Error('error-nested-discussion', 'Cannot create nested discussions', { + method: 'DiscussionCreation', + }); + } + + if (typeof encrypted !== 'boolean') { + encrypted = Boolean(parentRoom.encrypted); + } + + if (encrypted && reply) { + throw new Meteor.Error('error-invalid-arguments', 'Encrypted discussions must not receive an initial reply.', { + method: 'DiscussionCreation', + }); + } + + if (pmid) { + const discussionAlreadyExists = Rooms.findOne( + { + prid, + pmid, + }, + { + fields: { _id: 1 }, + }, + ); + if (discussionAlreadyExists) { + // do not allow multiple discussions to the same message'\ + addUserToRoom(discussionAlreadyExists._id, user); + return discussionAlreadyExists; + } + } + + const name = Random.id(); + + // auto invite the replied message owner + const invitedUsers = message ? [message.u.username, ...users] : users; + + const type = roomCoordinator.getRoomDirectives(parentRoom.t)?.getDiscussionType(parentRoom); + const description = parentRoom.encrypted ? '' : message?.msg; + const topic = parentRoom.name; + + if (!type) { + throw new Meteor.Error('error-invalid-type', 'Cannot define discussion room type', { + method: 'DiscussionCreation', + }); + } + + const discussion = createRoom( + type, + name, + user.username as string, + [...new Set(invitedUsers)].filter(Boolean), + false, + { + fname: discussionName, + description, // TODO discussions remove + topic, // TODO discussions remove + prid, + encrypted, + }, + { + // overrides name validation to allow anything, because discussion's name is randomly generated + nameValidationRegex: '.*', + creator: user._id, + }, + ); + + let discussionMsg; + if (message) { + if (parentRoom.encrypted) { + message.msg = TAPi18n.__('Encrypted_message'); + } + mentionMessage(discussion._id, user, attachMessage(message, parentRoom)); + + discussionMsg = createDiscussionMessage(message.rid, user, discussion._id, discussionName, attachMessage(message, parentRoom)); + } else { + discussionMsg = createDiscussionMessage(prid, user, discussion._id, discussionName); + } + + callbacks.runAsync('afterSaveMessage', discussionMsg, parentRoom); + + if (reply) { + sendMessage(user, { msg: reply }, discussion); + } + return discussion; +}; + +Meteor.methods({ + /** + * Create discussion by room or message + * @constructor + * @param {string} prid - Parent Room Id - The room id, optional if you send pmid. + * @param {string} pmid - Parent Message Id - Create the discussion by a message, optional. + * @param {string} reply - The reply, optional + * @param {string} t_name - discussion name + * @param {string[]} users - users to be added + * @param {boolean} encrypted - if the discussion's e2e encryption should be enabled. + */ + createDiscussion({ prid, pmid, t_name: discussionName, reply, users, encrypted }: CreateDiscussionProperties) { + if (!settings.get('Discussion_enabled')) { + throw new Meteor.Error('error-action-not-allowed', 'You are not allowed to create a discussion', { method: 'createDiscussion' }); + } + + const uid = Meteor.userId(); + if (!uid) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'DiscussionCreation', + }); + } + + if (!hasAtLeastOnePermission(uid, ['start-discussion', 'start-discussion-other-user'])) { + throw new Meteor.Error('error-action-not-allowed', 'You are not allowed to create a discussion', { method: 'createDiscussion' }); + } + + return create({ prid, pmid, t_name: discussionName, reply, users, user: Meteor.user() as IUser, encrypted }); + }, +}); diff --git a/apps/meteor/app/dolphin/client/index.js b/apps/meteor/app/dolphin/client/index.ts similarity index 100% rename from apps/meteor/app/dolphin/client/index.js rename to apps/meteor/app/dolphin/client/index.ts diff --git a/apps/meteor/app/dolphin/server/index.js b/apps/meteor/app/dolphin/server/index.ts similarity index 100% rename from apps/meteor/app/dolphin/server/index.js rename to apps/meteor/app/dolphin/server/index.ts diff --git a/apps/meteor/app/drupal/client/index.js b/apps/meteor/app/drupal/client/index.ts similarity index 100% rename from apps/meteor/app/drupal/client/index.js rename to apps/meteor/app/drupal/client/index.ts diff --git a/apps/meteor/app/drupal/server/index.js b/apps/meteor/app/drupal/server/index.ts similarity index 100% rename from apps/meteor/app/drupal/server/index.js rename to apps/meteor/app/drupal/server/index.ts diff --git a/apps/meteor/app/e2e/client/index.js b/apps/meteor/app/e2e/client/index.js deleted file mode 100644 index 0564e11fa6b61..0000000000000 --- a/apps/meteor/app/e2e/client/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import './stylesheets/e2e.css'; - -export * from './rocketchat.e2e'; diff --git a/apps/meteor/app/e2e/client/index.ts b/apps/meteor/app/e2e/client/index.ts new file mode 100644 index 0000000000000..f4e81a3237ebc --- /dev/null +++ b/apps/meteor/app/e2e/client/index.ts @@ -0,0 +1 @@ +export * from './rocketchat.e2e'; diff --git a/apps/meteor/app/e2e/client/rocketchat.e2e.js b/apps/meteor/app/e2e/client/rocketchat.e2e.js deleted file mode 100644 index 88935931b8326..0000000000000 --- a/apps/meteor/app/e2e/client/rocketchat.e2e.js +++ /dev/null @@ -1,407 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { EJSON } from 'meteor/ejson'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { Emitter } from '@rocket.chat/emitter'; - -import { E2ERoom } from './rocketchat.e2e.room'; -import { - toString, - toArrayBuffer, - joinVectorAndEcryptedData, - splitVectorAndEcryptedData, - encryptAES, - decryptAES, - generateRSAKey, - exportJWKKey, - importRSAKey, - importRawKey, - deriveKey, - generateMnemonicPhrase, -} from './helper'; -import * as banners from '../../../client/lib/banners'; -import { Rooms, Subscriptions, Messages } from '../../models/client'; -import './events.js'; -import './tabbar'; -import { log, logError } from './logger'; -import { waitUntilFind } from '../../../client/lib/utils/waitUntilFind'; -import { imperativeModal } from '../../../client/lib/imperativeModal'; -import SaveE2EPasswordModal from '../../../client/views/e2e/SaveE2EPasswordModal'; -import EnterE2EPasswordModal from '../../../client/views/e2e/EnterE2EPasswordModal'; -import { call } from '../../../client/lib/utils/call'; - -let failedToDecodeKey = false; - -class E2E extends Emitter { - constructor() { - super(); - this.started = false; - this.enabled = new ReactiveVar(false); - this._ready = new ReactiveVar(false); - this.instancesByRoomId = {}; - - this.on('ready', () => { - this._ready.set(true); - this.log('startClient -> Done'); - this.log('decryptSubscriptions'); - - this.decryptSubscriptions(); - this.log('decryptSubscriptions -> Done'); - }); - } - - log(...msg) { - log('E2E', ...msg); - } - - error(...msg) { - logError('E2E', ...msg); - } - - isEnabled() { - return this.enabled.get(); - } - - isReady() { - return this.enabled.get() && this._ready.get(); - } - - async getInstanceByRoomId(rid) { - const room = await waitUntilFind(() => Rooms.findOne({ _id: rid })); - - if (room.t !== 'd' && room.t !== 'p') { - return null; - } - - if (room.encrypted !== true && !room.e2eKeyId) { - return null; - } - - if (!this.instancesByRoomId[rid]) { - this.instancesByRoomId[rid] = new E2ERoom(Meteor.userId(), rid, room.t); - } - - return this.instancesByRoomId[rid]; - } - - removeInstanceByRoomId(rid) { - delete this.instancesByRoomId[rid]; - } - - async startClient() { - if (this.started) { - return; - } - - this.log('startClient -> STARTED'); - - this.started = true; - let public_key = Meteor._localStorage.getItem('public_key'); - let private_key = Meteor._localStorage.getItem('private_key'); - - await this.loadKeysFromDB(); - - if (!public_key && this.db_public_key) { - public_key = this.db_public_key; - } - - if (!private_key && this.db_private_key) { - try { - private_key = await this.decodePrivateKey(this.db_private_key); - } catch (error) { - this.started = false; - failedToDecodeKey = true; - this.openAlert({ - title: TAPi18n.__("Wasn't possible to decode your encryption key to be imported."), - html: '
Your encryption password seems wrong. Click here to try again.
', - modifiers: ['large', 'danger'], - closable: true, - icon: 'key', - action: () => { - this.startClient(); - this.closeAlert(); - }, - }); - return; - } - } - - if (public_key && private_key) { - await this.loadKeys({ public_key, private_key }); - } else { - await this.createAndLoadKeys(); - } - - // TODO: Split in 2 methods to persist keys - if (!this.db_public_key || !this.db_private_key) { - await call('e2e.setUserPublicAndPrivateKeys', { - public_key: Meteor._localStorage.getItem('public_key'), - private_key: await this.encodePrivateKey(Meteor._localStorage.getItem('private_key'), await this.createRandomPassword()), - }); - } - - const randomPassword = Meteor._localStorage.getItem('e2e.randomPassword'); - if (randomPassword) { - const passwordRevealText = TAPi18n.__('E2E_password_reveal_text', { - postProcess: 'sprintf', - sprintf: [randomPassword], - }); - - this.openAlert({ - title: TAPi18n.__('Save_Your_Encryption_Password'), - html: TAPi18n.__('Click_here_to_view_and_copy_your_password'), - modifiers: ['large'], - closable: false, - icon: 'key', - action: () => { - imperativeModal.open({ - component: SaveE2EPasswordModal, - props: { - passwordRevealText, - onClose: imperativeModal.close, - onCancel: () => { - this.closeAlert(); - imperativeModal.close(); - }, - onConfirm: () => { - Meteor._localStorage.removeItem('e2e.randomPassword'); - this.closeAlert(); - imperativeModal.close(); - }, - }, - }); - }, - }); - } - this.emit('ready'); - } - - async stopClient() { - this.log('-> Stop Client'); - this.closeAlert(); - - Meteor._localStorage.removeItem('public_key'); - Meteor._localStorage.removeItem('private_key'); - this.instancesByRoomId = {}; - this.privateKey = null; - this.enabled.set(false); - this._ready.set(false); - this.started = false; - } - - async changePassword(newPassword) { - await call('e2e.setUserPublicAndPrivateKeys', { - public_key: Meteor._localStorage.getItem('public_key'), - private_key: await this.encodePrivateKey(Meteor._localStorage.getItem('private_key'), newPassword), - }); - - if (Meteor._localStorage.getItem('e2e.randomPassword')) { - Meteor._localStorage.setItem('e2e.randomPassword', newPassword); - } - } - - async loadKeysFromDB() { - try { - const { public_key, private_key } = await call('e2e.fetchMyKeys'); - - this.db_public_key = public_key; - this.db_private_key = private_key; - } catch (error) { - return this.error('Error fetching RSA keys: ', error); - } - } - - async loadKeys({ public_key, private_key }) { - Meteor._localStorage.setItem('public_key', public_key); - - try { - this.privateKey = await importRSAKey(EJSON.parse(private_key), ['decrypt']); - - Meteor._localStorage.setItem('private_key', private_key); - } catch (error) { - return this.error('Error importing private key: ', error); - } - } - - async createAndLoadKeys() { - // Could not obtain public-private keypair from server. - let key; - try { - key = await generateRSAKey(); - this.privateKey = key.privateKey; - } catch (error) { - return this.error('Error generating key: ', error); - } - - try { - const publicKey = await exportJWKKey(key.publicKey); - - Meteor._localStorage.setItem('public_key', JSON.stringify(publicKey)); - } catch (error) { - return this.error('Error exporting public key: ', error); - } - - try { - const privateKey = await exportJWKKey(key.privateKey); - - Meteor._localStorage.setItem('private_key', JSON.stringify(privateKey)); - } catch (error) { - return this.error('Error exporting private key: ', error); - } - - this.requestSubscriptionKeys(); - } - - async requestSubscriptionKeys() { - call('e2e.requestSubscriptionKeys'); - } - - async createRandomPassword() { - const randomPassword = await generateMnemonicPhrase(5); - Meteor._localStorage.setItem('e2e.randomPassword', randomPassword); - return randomPassword; - } - - async encodePrivateKey(private_key, password) { - const masterKey = await this.getMasterKey(password); - - const vector = crypto.getRandomValues(new Uint8Array(16)); - try { - const encodedPrivateKey = await encryptAES(vector, masterKey, toArrayBuffer(private_key)); - - return EJSON.stringify(joinVectorAndEcryptedData(vector, encodedPrivateKey)); - } catch (error) { - return this.error('Error encrypting encodedPrivateKey: ', error); - } - } - - async getMasterKey(password) { - if (password == null) { - alert('You should provide a password'); - } - - // First, create a PBKDF2 "key" containing the password - let baseKey; - try { - baseKey = await importRawKey(toArrayBuffer(password)); - } catch (error) { - return this.error('Error creating a key based on user password: ', error); - } - - // Derive a key from the password - try { - return await deriveKey(toArrayBuffer(Meteor.userId()), baseKey); - } catch (error) { - return this.error('Error deriving baseKey: ', error); - } - } - - async requestPassword() { - return new Promise((resolve) => { - const showModal = () => { - imperativeModal.open({ - component: EnterE2EPasswordModal, - props: { - onClose: imperativeModal.close, - onCancel: () => { - failedToDecodeKey = false; - this.closeAlert(); - imperativeModal.close(); - }, - onConfirm: (password) => { - resolve(password); - this.closeAlert(); - imperativeModal.close(); - }, - }, - }); - }; - - const showAlert = () => { - this.openAlert({ - title: TAPi18n.__('Enter_your_E2E_password'), - html: TAPi18n.__('Click_here_to_enter_your_encryption_password'), - modifiers: ['large'], - closable: false, - icon: 'key', - action() { - showModal(); - }, - }); - }; - - if (failedToDecodeKey) { - showModal(); - } else { - showAlert(); - } - }); - } - - async decodePrivateKey(private_key) { - const password = await this.requestPassword(); - - const masterKey = await this.getMasterKey(password); - - const [vector, cipherText] = splitVectorAndEcryptedData(EJSON.parse(private_key)); - - try { - const privKey = await decryptAES(vector, masterKey, cipherText); - return toString(privKey); - } catch (error) { - throw new Error('E2E -> Error decrypting private key'); - } - } - - async decryptMessage(message) { - if (message.t !== 'e2e' || message.e2e === 'done') { - return message; - } - - const e2eRoom = await this.getInstanceByRoomId(message.rid); - - if (!e2eRoom) { - return message; - } - - const data = await e2eRoom.decrypt(message.msg); - - if (!data) { - return message; - } - - return { - ...message, - msg: data.text, - e2e: 'done', - }; - } - - async decryptPendingMessages() { - return Messages.find({ t: 'e2e', e2e: 'pending' }).forEach(async ({ _id, ...msg }) => { - Messages.direct.update({ _id }, await this.decryptMessage(msg)); - }); - } - - async decryptSubscription(rid) { - const e2eRoom = await this.getInstanceByRoomId(rid); - this.log('decryptSubscription ->', rid); - e2eRoom?.decryptSubscription(); - } - - async decryptSubscriptions() { - Subscriptions.find({ - encrypted: true, - }).forEach((room) => this.decryptSubscription(room._id)); - } - - openAlert(config) { - banners.open({ id: 'e2e', ...config }); - } - - closeAlert() { - banners.closeById('e2e'); - } -} - -export const e2e = new E2E(); diff --git a/apps/meteor/app/e2e/client/rocketchat.e2e.room.js b/apps/meteor/app/e2e/client/rocketchat.e2e.room.js index fea71e3811821..b0a5dbe86fc92 100644 --- a/apps/meteor/app/e2e/client/rocketchat.e2e.room.js +++ b/apps/meteor/app/e2e/client/rocketchat.e2e.room.js @@ -1,4 +1,3 @@ -import _ from 'underscore'; import { Base64 } from 'meteor/base64'; import { EJSON } from 'meteor/ejson'; import { Random } from 'meteor/random'; @@ -264,7 +263,8 @@ export class E2ERoom extends Emitter { const decryptedKey = await decryptRSA(e2e.privateKey, groupKey); this.sessionKeyExportedString = toString(decryptedKey); } catch (error) { - return this.error('Error decrypting group key: ', error); + this.error('Error decrypting group key: ', error); + return false; } this.keyID = Base64.encode(this.sessionKeyExportedString).slice(0, 12); @@ -275,8 +275,11 @@ export class E2ERoom extends Emitter { // Key has been obtained. E2E is now in session. this.groupSessionKey = key; } catch (error) { - return this.error('Error importing group key: ', error); + this.error('Error importing group key: ', error); + return false; } + + return true; } async createGroupKey() { @@ -373,7 +376,7 @@ export class E2ERoom extends Emitter { // Encrypts messages async encryptText(data) { - if (!_.isObject(data)) { + if (!(typeof data === 'function' || (typeof data === 'object' && !!data))) { data = new TextEncoder('UTF-8').encode(EJSON.stringify({ text: data, ack: Random.id((Random.fraction() + 1) * 20) })); } diff --git a/apps/meteor/app/e2e/client/rocketchat.e2e.ts b/apps/meteor/app/e2e/client/rocketchat.e2e.ts new file mode 100644 index 0000000000000..fcc36ee071209 --- /dev/null +++ b/apps/meteor/app/e2e/client/rocketchat.e2e.ts @@ -0,0 +1,512 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import URL from 'url'; +import QueryString from 'querystring'; + +import { Meteor } from 'meteor/meteor'; +import { ReactiveVar } from 'meteor/reactive-var'; +import type { ReactiveVar as ReactiveVarType } from 'meteor/reactive-var'; +import { EJSON } from 'meteor/ejson'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import { Emitter } from '@rocket.chat/emitter'; +import type { IE2EEMessage, IMessage, IRoom, ISubscription } from '@rocket.chat/core-typings'; +import { isE2EEMessage } from '@rocket.chat/core-typings'; + +import { getMessageUrlRegex } from '../../../lib/getMessageUrlRegex'; +import { E2ERoom } from './rocketchat.e2e.room'; +import { + toString, + toArrayBuffer, + joinVectorAndEcryptedData, + splitVectorAndEcryptedData, + encryptAES, + decryptAES, + generateRSAKey, + exportJWKKey, + importRSAKey, + importRawKey, + deriveKey, + generateMnemonicPhrase, +} from './helper'; +import * as banners from '../../../client/lib/banners'; +import type { LegacyBannerPayload } from '../../../client/lib/banners'; +import { Rooms, Subscriptions, Messages } from '../../models/client'; +import './events.js'; +import './tabbar'; +import { log, logError } from './logger'; +import { waitUntilFind } from '../../../client/lib/utils/waitUntilFind'; +import { imperativeModal } from '../../../client/lib/imperativeModal'; +import SaveE2EPasswordModal from '../../../client/views/e2e/SaveE2EPasswordModal'; +import EnterE2EPasswordModal from '../../../client/views/e2e/EnterE2EPasswordModal'; +import { call } from '../../../client/lib/utils/call'; +import { APIClient } from '../../utils/client'; +import { createQuoteAttachment } from '../../../lib/createQuoteAttachment'; +import { mapMessageFromApi } from '../../../client/lib/utils/mapMessageFromApi'; + +let failedToDecodeKey = false; + +type KeyPair = { + public_key: string | null; + private_key: string | null; +}; + +class E2E extends Emitter { + private started: boolean; + + public enabled: ReactiveVarType; + + private _ready: ReactiveVarType; + + private instancesByRoomId: Record; + + private db_public_key: string | null; + + private db_private_key: string | null; + + private privateKey: CryptoKey | undefined; + + constructor() { + super(); + this.started = false; + this.enabled = new ReactiveVar(false); + this._ready = new ReactiveVar(false); + this.instancesByRoomId = {}; + + this.on('ready', () => { + this._ready.set(true); + this.log('startClient -> Done'); + this.log('decryptSubscriptions'); + + this.decryptSubscriptions(); + this.log('decryptSubscriptions -> Done'); + }); + } + + log(...msg: unknown[]) { + log('E2E', ...msg); + } + + error(...msg: unknown[]) { + logError('E2E', ...msg); + } + + isEnabled(): boolean { + return this.enabled.get(); + } + + isReady(): boolean { + return this.enabled.get() && this._ready.get(); + } + + async getInstanceByRoomId(rid: IRoom['_id']): Promise { + const room = await waitUntilFind(() => Rooms.findOne({ _id: rid })); + + if (room.t !== 'd' && room.t !== 'p') { + return null; + } + + if (room.encrypted !== true && !room.e2eKeyId) { + return null; + } + + if (!this.instancesByRoomId[rid]) { + this.instancesByRoomId[rid] = new E2ERoom(Meteor.userId(), rid, room.t); + } + + return this.instancesByRoomId[rid]; + } + + removeInstanceByRoomId(rid: IRoom['_id']): void { + delete this.instancesByRoomId[rid]; + } + + async persistKeys({ public_key, private_key }: KeyPair, password: string): Promise { + if (typeof public_key !== 'string' || typeof private_key !== 'string') { + throw new Error('Failed to persist keys as they are not strings.'); + } + + const encodedPrivateKey = await this.encodePrivateKey(private_key, password); + + if (!encodedPrivateKey) { + throw new Error('Failed to encode private key with provided password.'); + } + + await APIClient.post('/v1/e2e.setUserPublicAndPrivateKeys', { + public_key, + private_key: encodedPrivateKey, + }); + } + + async acceptSuggestedKey(rid: string): Promise { + await APIClient.post('/v1/e2e.acceptSuggestedGroupKey', { + rid, + }); + } + + async rejectSuggestedKey(rid: string): Promise { + await APIClient.post('/v1/e2e.rejectSuggestedGroupKey', { + rid, + }); + } + + getKeysFromLocalStorage(): KeyPair { + return { + public_key: Meteor._localStorage.getItem('public_key'), + private_key: Meteor._localStorage.getItem('private_key'), + }; + } + + async startClient(): Promise { + if (this.started) { + return; + } + + this.log('startClient -> STARTED'); + + this.started = true; + + let { public_key, private_key } = this.getKeysFromLocalStorage(); + + await this.loadKeysFromDB(); + + if (!public_key && this.db_public_key) { + public_key = this.db_public_key; + } + + if (!private_key && this.db_private_key) { + try { + private_key = await this.decodePrivateKey(this.db_private_key); + } catch (error) { + this.started = false; + failedToDecodeKey = true; + this.openAlert({ + title: TAPi18n.__("Wasn't possible to decode your encryption key to be imported."), + html: '
Your encryption password seems wrong. Click here to try again.
', + modifiers: ['large', 'danger'], + closable: true, + icon: 'key', + action: () => { + this.startClient(); + this.closeAlert(); + }, + }); + return; + } + } + + if (public_key && private_key) { + await this.loadKeys({ public_key, private_key }); + } else { + await this.createAndLoadKeys(); + } + + if (!this.db_public_key || !this.db_private_key) { + this.persistKeys(this.getKeysFromLocalStorage(), await this.createRandomPassword()); + } + + const randomPassword = Meteor._localStorage.getItem('e2e.randomPassword'); + if (randomPassword) { + const passwordRevealText = TAPi18n.__('E2E_password_reveal_text', { + postProcess: 'sprintf', + sprintf: [randomPassword], + }); + + this.openAlert({ + title: TAPi18n.__('Save_Your_Encryption_Password'), + html: TAPi18n.__('Click_here_to_view_and_copy_your_password'), + modifiers: ['large'], + closable: false, + icon: 'key', + action: () => { + imperativeModal.open({ + component: SaveE2EPasswordModal, + props: { + passwordRevealText, + onClose: imperativeModal.close, + onCancel: () => { + this.closeAlert(); + imperativeModal.close(); + }, + onConfirm: () => { + Meteor._localStorage.removeItem('e2e.randomPassword'); + this.closeAlert(); + imperativeModal.close(); + }, + }, + }); + }, + }); + } + this.emit('ready'); + } + + async stopClient(): Promise { + this.log('-> Stop Client'); + this.closeAlert(); + + Meteor._localStorage.removeItem('public_key'); + Meteor._localStorage.removeItem('private_key'); + this.instancesByRoomId = {}; + this.privateKey = undefined; + this.enabled.set(false); + this._ready.set(false); + this.started = false; + } + + async changePassword(newPassword: string): Promise { + await this.persistKeys(this.getKeysFromLocalStorage(), newPassword); + + if (Meteor._localStorage.getItem('e2e.randomPassword')) { + Meteor._localStorage.setItem('e2e.randomPassword', newPassword); + } + } + + async loadKeysFromDB(): Promise { + try { + const { public_key, private_key } = await APIClient.get('/v1/e2e.fetchMyKeys'); + + this.db_public_key = public_key; + this.db_private_key = private_key; + } catch (error) { + return this.error('Error fetching RSA keys: ', error); + } + } + + async loadKeys({ public_key, private_key }: { public_key: string; private_key: string }): Promise { + Meteor._localStorage.setItem('public_key', public_key); + + try { + this.privateKey = await importRSAKey(EJSON.parse(private_key), ['decrypt']); + + Meteor._localStorage.setItem('private_key', private_key); + } catch (error) { + return this.error('Error importing private key: ', error); + } + } + + async createAndLoadKeys(): Promise { + // Could not obtain public-private keypair from server. + let key; + try { + key = await generateRSAKey(); + this.privateKey = key.privateKey; + } catch (error) { + return this.error('Error generating key: ', error); + } + + try { + const publicKey = await exportJWKKey(key.publicKey); + + Meteor._localStorage.setItem('public_key', JSON.stringify(publicKey)); + } catch (error) { + return this.error('Error exporting public key: ', error); + } + + try { + const privateKey = await exportJWKKey(key.privateKey); + + Meteor._localStorage.setItem('private_key', JSON.stringify(privateKey)); + } catch (error) { + return this.error('Error exporting private key: ', error); + } + + this.requestSubscriptionKeys(); + } + + async requestSubscriptionKeys(): Promise { + call('e2e.requestSubscriptionKeys'); + } + + async createRandomPassword(): Promise { + const randomPassword = await generateMnemonicPhrase(5); + Meteor._localStorage.setItem('e2e.randomPassword', randomPassword); + return randomPassword; + } + + async encodePrivateKey(private_key: string, password: string): Promise { + const masterKey = await this.getMasterKey(password); + + const vector = crypto.getRandomValues(new Uint8Array(16)); + try { + const encodedPrivateKey = await encryptAES(vector, masterKey, toArrayBuffer(private_key)); + + return EJSON.stringify(joinVectorAndEcryptedData(vector, encodedPrivateKey)); + } catch (error) { + return this.error('Error encrypting encodedPrivateKey: ', error); + } + } + + async getMasterKey(password: string): Promise { + if (password == null) { + alert('You should provide a password'); + } + + // First, create a PBKDF2 "key" containing the password + let baseKey; + try { + baseKey = await importRawKey(toArrayBuffer(password)); + } catch (error) { + return this.error('Error creating a key based on user password: ', error); + } + + // Derive a key from the password + try { + return await deriveKey(toArrayBuffer(Meteor.userId()), baseKey); + } catch (error) { + return this.error('Error deriving baseKey: ', error); + } + } + + async requestPassword(): Promise { + return new Promise((resolve) => { + const showModal = () => { + imperativeModal.open({ + component: EnterE2EPasswordModal, + props: { + onClose: imperativeModal.close, + onCancel: () => { + failedToDecodeKey = false; + this.closeAlert(); + imperativeModal.close(); + }, + onConfirm: (password) => { + resolve(password); + this.closeAlert(); + imperativeModal.close(); + }, + }, + }); + }; + + const showAlert = () => { + this.openAlert({ + title: TAPi18n.__('Enter_your_E2E_password'), + html: TAPi18n.__('Click_here_to_enter_your_encryption_password'), + modifiers: ['large'], + closable: false, + icon: 'key', + action() { + showModal(); + }, + }); + }; + + if (failedToDecodeKey) { + showModal(); + } else { + showAlert(); + } + }); + } + + async decodePrivateKey(private_key: string): Promise { + const password = await this.requestPassword(); + + const masterKey = await this.getMasterKey(password); + + const [vector, cipherText] = splitVectorAndEcryptedData(EJSON.parse(private_key)); + + try { + const privKey = await decryptAES(vector, masterKey, cipherText); + return toString(privKey); + } catch (error) { + throw new Error('E2E -> Error decrypting private key'); + } + } + + async decryptMessage(message: IMessage | IE2EEMessage): Promise { + if (!isE2EEMessage(message) || message.e2e === 'done') { + return message; + } + + const e2eRoom = await this.getInstanceByRoomId(message.rid); + + if (!e2eRoom) { + return message; + } + + const data = await e2eRoom.decrypt(message.msg); + + if (!data) { + return message; + } + + const decryptedMessage: IE2EEMessage = { + ...message, + msg: data.text, + e2e: 'done', + }; + + const decryptedMessageWithQuote = await this.parseQuoteAttachment(decryptedMessage); + + return decryptedMessageWithQuote; + } + + async decryptPendingMessages(): Promise { + return Messages.find({ t: 'e2e', e2e: 'pending' }).forEach(async ({ _id, ...msg }: IMessage) => { + Messages.direct.update({ _id }, await this.decryptMessage(msg as IE2EEMessage)); + }); + } + + async decryptSubscription(subscriptionId: ISubscription['_id']): Promise { + const e2eRoom = await this.getInstanceByRoomId(subscriptionId); + this.log('decryptSubscription ->', subscriptionId); + e2eRoom?.decryptSubscription(); + } + + async decryptSubscriptions(): Promise { + Subscriptions.find({ + encrypted: true, + }).forEach((subscription) => this.decryptSubscription(subscription._id)); + } + + openAlert(config: Omit): void { + banners.open({ id: 'e2e', ...config }); + } + + closeAlert(): void { + banners.closeById('e2e'); + } + + async parseQuoteAttachment(message: IE2EEMessage): Promise { + const urls = message.msg.match(getMessageUrlRegex()) || []; + + await Promise.all( + urls.map(async (url) => { + if (!url.includes(Meteor.absoluteUrl())) { + return; + } + + const urlObj = URL.parse(url); + // if the URL doesn't have query params (doesn't reference message) skip + if (!urlObj.query) { + return; + } + + const { msg: msgId } = QueryString.parse(urlObj.query); + + if (!msgId || Array.isArray(msgId)) { + return; + } + + const getQuotedMessage = await APIClient.get('/v1/chat.getMessage', { msgId }); + const quotedMessage = getQuotedMessage?.message; + + if (!quotedMessage) { + return; + } + + const decryptedQuoteMessage = await this.decryptMessage(mapMessageFromApi(quotedMessage)); + + message.attachments = message.attachments || []; + + const quoteAttachment = createQuoteAttachment(decryptedQuoteMessage, url); + + message.attachments.push(quoteAttachment); + }), + ); + + return message; + } +} + +export const e2e = new E2E(); diff --git a/apps/meteor/app/e2e/client/stylesheets/e2e.css b/apps/meteor/app/e2e/client/stylesheets/e2e.css deleted file mode 100644 index b026287a731f8..0000000000000 --- a/apps/meteor/app/e2e/client/stylesheets/e2e.css +++ /dev/null @@ -1,13 +0,0 @@ -.message { - &.e2e { - .info::before { - display: inline-block; - - visibility: visible; - - content: "\e952"; - - font-family: 'fontello'; - } - } -} diff --git a/apps/meteor/app/e2e/client/tabbar.ts b/apps/meteor/app/e2e/client/tabbar.ts index 22eff563ae980..78b2b9a92543e 100644 --- a/apps/meteor/app/e2e/client/tabbar.ts +++ b/apps/meteor/app/e2e/client/tabbar.ts @@ -1,6 +1,7 @@ import { useMemo, useCallback } from 'react'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { useSetting, usePermission, useEndpoint } from '@rocket.chat/ui-contexts'; +import { isRoomFederated } from '@rocket.chat/core-typings'; import { addAction } from '../../../client/views/room/lib/Toolbox'; import { useReactiveValue } from '../../../client/hooks/useReactiveValue'; @@ -12,6 +13,7 @@ addAction('e2e', ({ room }) => { const canToggleE2e = usePermission('toggle-room-e2e-encryption', room._id); const canEditRoom = usePermission('edit-room', room._id); const hasPermission = (room.t === 'd' || (canEditRoom && canToggleE2e)) && e2eReady; + const federated = isRoomFederated(room); const toggleE2E = useEndpoint('POST', '/v1/rooms.saveRoomSettings'); @@ -31,8 +33,12 @@ addAction('e2e', ({ room }) => { icon: 'key', order: 13, action, + ...(federated && { + 'data-tooltip': 'E2E_unavailable_for_federation', + 'disabled': true, + }), } : null, - [action, e2eEnabled, enabledOnRoom, hasPermission], + [action, e2eEnabled, enabledOnRoom, hasPermission, federated], ); }); diff --git a/apps/meteor/app/e2e/server/functions/handleSuggestedGroupKey.ts b/apps/meteor/app/e2e/server/functions/handleSuggestedGroupKey.ts new file mode 100644 index 0000000000000..8b6d313e57e25 --- /dev/null +++ b/apps/meteor/app/e2e/server/functions/handleSuggestedGroupKey.ts @@ -0,0 +1,29 @@ +import { Meteor } from 'meteor/meteor'; +import { Subscriptions } from '@rocket.chat/models'; + +export async function handleSuggestedGroupKey( + handle: 'accept' | 'reject', + rid: string, + userId: string | null, + method: string, +): Promise { + if (!userId) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { method }); + } + + const sub = await Subscriptions.findOneByRoomIdAndUserId(rid, userId); + if (!sub) { + throw new Meteor.Error('error-subscription-not-found', 'Subscription not found', { method }); + } + + const suggestedKey = String(sub.E2ESuggestedKey ?? '').trim(); + if (!suggestedKey) { + throw new Meteor.Error('error-no-suggested-key-available', 'No suggested key available', { method }); + } + + if (handle === 'accept') { + await Subscriptions.setGroupE2EKey(sub._id, suggestedKey); + } + + await Subscriptions.unsetGroupE2ESuggestedKey(sub._id); +} diff --git a/apps/meteor/app/e2e/server/index.js b/apps/meteor/app/e2e/server/index.js index ad982fd196a9d..080a32d811940 100644 --- a/apps/meteor/app/e2e/server/index.js +++ b/apps/meteor/app/e2e/server/index.js @@ -1,5 +1,6 @@ +import { api } from '@rocket.chat/core-services'; + import { callbacks } from '../../../lib/callbacks'; -import { api } from '../../../server/sdk/api'; import './settings'; import './beforeCreateRoom'; diff --git a/apps/meteor/app/e2e/server/methods/requestSubscriptionKeys.js b/apps/meteor/app/e2e/server/methods/requestSubscriptionKeys.js index 76d28b27c599b..2dea12b1e0c47 100644 --- a/apps/meteor/app/e2e/server/methods/requestSubscriptionKeys.js +++ b/apps/meteor/app/e2e/server/methods/requestSubscriptionKeys.js @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; +import { api } from '@rocket.chat/core-services'; import { Subscriptions, Rooms } from '../../../models/server'; -import { api } from '../../../../server/sdk/api'; Meteor.methods({ 'e2e.requestSubscriptionKeys'() { diff --git a/apps/meteor/app/e2e/server/methods/updateGroupKey.js b/apps/meteor/app/e2e/server/methods/updateGroupKey.js deleted file mode 100644 index 9aae29003ddff..0000000000000 --- a/apps/meteor/app/e2e/server/methods/updateGroupKey.js +++ /dev/null @@ -1,17 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { Subscriptions } from '../../../models/server'; - -Meteor.methods({ - 'e2e.updateGroupKey'(rid, uid, key) { - const mySub = Subscriptions.findOneByRoomIdAndUserId(rid, Meteor.userId()); - if (mySub) { - // I have a subscription to this room - const userSub = Subscriptions.findOneByRoomIdAndUserId(rid, uid); - if (userSub) { - // uid also has subscription to this room - return Subscriptions.updateGroupE2EKey(userSub._id, key); - } - } - }, -}); diff --git a/apps/meteor/app/e2e/server/methods/updateGroupKey.ts b/apps/meteor/app/e2e/server/methods/updateGroupKey.ts new file mode 100644 index 0000000000000..fd5c0b055adad --- /dev/null +++ b/apps/meteor/app/e2e/server/methods/updateGroupKey.ts @@ -0,0 +1,27 @@ +import { Meteor } from 'meteor/meteor'; +import { Subscriptions } from '@rocket.chat/models'; + +Meteor.methods({ + async 'e2e.updateGroupKey'(rid, uid, key) { + const userId = Meteor.userId(); + if (!userId) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'e2e.acceptSuggestedGroupKey' }); + } + + // I have a subscription to this room + const mySub = await Subscriptions.findOneByRoomIdAndUserId(rid, userId); + + if (mySub) { + // Setting the key to myself, can set directly to the final field + if (userId === uid) { + return Subscriptions.setGroupE2EKey(mySub._id, key); + } + + // uid also has subscription to this room + const userSub = await Subscriptions.findOneByRoomIdAndUserId(rid, uid); + if (userSub) { + return Subscriptions.setGroupE2ESuggestedKey(userSub._id, key); + } + } + }, +}); diff --git a/apps/meteor/app/emoji-custom/client/index.js b/apps/meteor/app/emoji-custom/client/index.ts similarity index 100% rename from apps/meteor/app/emoji-custom/client/index.js rename to apps/meteor/app/emoji-custom/client/index.ts diff --git a/apps/meteor/app/emoji-custom/client/lib/emojiCustom.js b/apps/meteor/app/emoji-custom/client/lib/emojiCustom.js index a3df7135cc5ff..8ae032cede8cc 100644 --- a/apps/meteor/app/emoji-custom/client/lib/emojiCustom.js +++ b/apps/meteor/app/emoji-custom/client/lib/emojiCustom.js @@ -6,23 +6,18 @@ import { isSetNotNull } from './function-isSet'; import { RoomManager } from '../../../ui-utils/client'; import { emoji, EmojiPicker } from '../../../emoji/client'; import { CachedCollectionManager } from '../../../ui-cached-collection/client'; -import { APIClient } from '../../../utils/client'; +import { APIClient, getURL } from '../../../utils/client'; export const getEmojiUrlFromName = function (name, extension) { - Session.get; + if (name == null) { + return; + } const key = `emoji_random_${name}`; - let random = 0; - if (isSetNotNull(() => Session.keys[key])) { - random = Session.keys[key]; - } + const random = isSetNotNull(() => Session.keys[key]) ? Session.keys[key] : 0; - if (name == null) { - return; - } - const path = __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || ''; - return `${path}/emoji-custom/${encodeURIComponent(name)}.${extension}?_dc=${random}`; + return getURL(`/emoji-custom/${encodeURIComponent(name)}.${extension}?_dc=${random}`); }; export const deleteEmojiCustom = function (emojiData) { @@ -200,8 +195,6 @@ Meteor.startup(() => }; } } - - EmojiPicker.updateRecent('rocket'); } catch (e) { console.error('Error getting custom emoji', e); } diff --git a/apps/meteor/app/emoji-custom/server/index.js b/apps/meteor/app/emoji-custom/server/index.ts similarity index 100% rename from apps/meteor/app/emoji-custom/server/index.js rename to apps/meteor/app/emoji-custom/server/index.ts diff --git a/apps/meteor/app/emoji-custom/server/methods/deleteEmojiCustom.js b/apps/meteor/app/emoji-custom/server/methods/deleteEmojiCustom.js index 4d26d9ca065ab..49732eed2b0d2 100644 --- a/apps/meteor/app/emoji-custom/server/methods/deleteEmojiCustom.js +++ b/apps/meteor/app/emoji-custom/server/methods/deleteEmojiCustom.js @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; import { EmojiCustom } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; -import { api } from '../../../../server/sdk/api'; import { hasPermission } from '../../../authorization'; import { RocketChatFileEmojiCustomInstance } from '../startup/emoji-custom'; diff --git a/apps/meteor/app/emoji-custom/server/methods/insertOrUpdateEmoji.js b/apps/meteor/app/emoji-custom/server/methods/insertOrUpdateEmoji.js index 96b95f3fbc6fd..8c0e526851f9a 100644 --- a/apps/meteor/app/emoji-custom/server/methods/insertOrUpdateEmoji.js +++ b/apps/meteor/app/emoji-custom/server/methods/insertOrUpdateEmoji.js @@ -1,12 +1,12 @@ import { Meteor } from 'meteor/meteor'; import _ from 'underscore'; -import s from 'underscore.string'; import limax from 'limax'; import { EmojiCustom } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; import { hasPermission } from '../../../authorization'; import { RocketChatFileEmojiCustomInstance } from '../startup/emoji-custom'; -import { api } from '../../../../server/sdk/api'; +import { trim } from '../../../../lib/utils/stringUtils'; Meteor.methods({ async insertOrUpdateEmoji(emojiData) { @@ -14,7 +14,7 @@ Meteor.methods({ throw new Meteor.Error('not_authorized'); } - if (!s.trim(emojiData.name)) { + if (!trim(emojiData.name)) { throw new Meteor.Error('error-the-field-is-required', 'The field Name is required', { method: 'insertOrUpdateEmoji', field: 'Name', diff --git a/apps/meteor/app/emoji-custom/server/methods/listEmojiCustom.js b/apps/meteor/app/emoji-custom/server/methods/listEmojiCustom.js index a4fd124abe911..b553e5b398e43 100644 --- a/apps/meteor/app/emoji-custom/server/methods/listEmojiCustom.js +++ b/apps/meteor/app/emoji-custom/server/methods/listEmojiCustom.js @@ -1,8 +1,30 @@ import { Meteor } from 'meteor/meteor'; import { EmojiCustom } from '@rocket.chat/models'; +import { check, Match } from 'meteor/check'; + +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; + +/** + * @deprecated Will be removed in future versions. + */ Meteor.methods({ async listEmojiCustom(options = {}) { + methodDeprecationLogger.warn('listEmojiCustom will be removed in future versions of Rocket.Chat'); + + const user = Meteor.user(); + + if (!user) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'listEmojiCustom', + }); + } + + check(options, { + name: Match.Optional(String), + aliases: Match.Optional([String]), + }); + return EmojiCustom.find(options).toArray(); }, }); diff --git a/apps/meteor/app/emoji-custom/server/methods/uploadEmojiCustom.js b/apps/meteor/app/emoji-custom/server/methods/uploadEmojiCustom.js index 7269a36330f3a..51a2ef3c84df7 100644 --- a/apps/meteor/app/emoji-custom/server/methods/uploadEmojiCustom.js +++ b/apps/meteor/app/emoji-custom/server/methods/uploadEmojiCustom.js @@ -1,12 +1,11 @@ import { Meteor } from 'meteor/meteor'; import limax from 'limax'; import sharp from 'sharp'; +import { api, Media } from '@rocket.chat/core-services'; import { hasPermission } from '../../../authorization'; import { RocketChatFile } from '../../../file'; import { RocketChatFileEmojiCustomInstance } from '../startup/emoji-custom'; -import { api } from '../../../../server/sdk/api'; -import { Media } from '../../../../server/sdk'; const getFile = async (file, extension) => { if (extension !== 'svg+xml') { diff --git a/apps/meteor/app/emoji-custom/server/startup/emoji-custom.js b/apps/meteor/app/emoji-custom/server/startup/emoji-custom.js index 8551d201410c0..f408d594c0a5a 100644 --- a/apps/meteor/app/emoji-custom/server/startup/emoji-custom.js +++ b/apps/meteor/app/emoji-custom/server/startup/emoji-custom.js @@ -82,28 +82,20 @@ Meteor.startup(function () { return; } - let fileUploadDate = undefined; - if (file.uploadDate != null) { - fileUploadDate = file.uploadDate.toUTCString(); - } + const fileUploadDate = file.uploadDate != null ? file.uploadDate.toUTCString() : undefined; const reqModifiedHeader = req.headers['if-modified-since']; - if (reqModifiedHeader != null) { - if (reqModifiedHeader === fileUploadDate) { - res.setHeader('Last-Modified', reqModifiedHeader); - res.writeHead(304); - res.end(); - return; - } + if (reqModifiedHeader != null && reqModifiedHeader === fileUploadDate) { + res.setHeader('Last-Modified', reqModifiedHeader); + res.writeHead(304); + res.end(); + return; } - res.setHeader('Cache-Control', 'public, max-age=0'); - res.setHeader('Expires', '-1'); - if (fileUploadDate != null) { - res.setHeader('Last-Modified', fileUploadDate); - } else { - res.setHeader('Last-Modified', new Date().toUTCString()); - } + res.setHeader('Cache-Control', 'public, max-age=31536000'); + res.setHeader('Last-Modified', fileUploadDate || new Date().toUTCString()); + res.setHeader('Content-Length', file.length); + if (/^svg$/i.test(params.emoji.split('.').pop())) { res.setHeader('Content-Type', 'image/svg+xml'); } else if (/^png$/i.test(params.emoji.split('.').pop())) { @@ -111,7 +103,6 @@ Meteor.startup(function () { } else { res.setHeader('Content-Type', 'image/jpeg'); } - res.setHeader('Content-Length', file.length); file.readStream.pipe(res); }), diff --git a/apps/meteor/app/emoji-emojione/client/emojione-sprites.css b/apps/meteor/app/emoji-emojione/client/emojione-sprites.css index a483d9a168b35..2a480d6294b1b 100644 --- a/apps/meteor/app/emoji-emojione/client/emojione-sprites.css +++ b/apps/meteor/app/emoji-emojione/client/emojione-sprites.css @@ -29,10 +29,6 @@ image-rendering: optimizeQuality; } -.message .emojione.big { - width: 44px; - height: 44px; -} .big > .emojione { width: 44px; height: 44px; diff --git a/apps/meteor/app/emoji-emojione/client/index.js b/apps/meteor/app/emoji-emojione/client/index.ts similarity index 100% rename from apps/meteor/app/emoji-emojione/client/index.js rename to apps/meteor/app/emoji-emojione/client/index.ts diff --git a/apps/meteor/app/emoji-emojione/server/index.js b/apps/meteor/app/emoji-emojione/server/index.ts similarity index 100% rename from apps/meteor/app/emoji-emojione/server/index.js rename to apps/meteor/app/emoji-emojione/server/index.ts diff --git a/apps/meteor/app/emoji/client/emojiPicker.html b/apps/meteor/app/emoji/client/emojiPicker.html index 498f4ec1e4875..419ee59a4d42f 100644 --- a/apps/meteor/app/emoji/client/emojiPicker.html +++ b/apps/meteor/app/emoji/client/emojiPicker.html @@ -1,52 +1,4 @@ diff --git a/apps/meteor/app/emoji/client/emojiPicker.js b/apps/meteor/app/emoji/client/emojiPicker.js index 671698280cc16..6032e029c2269 100644 --- a/apps/meteor/app/emoji/client/emojiPicker.js +++ b/apps/meteor/app/emoji/client/emojiPicker.js @@ -1,4 +1,3 @@ -import _ from 'underscore'; import { ReactiveVar } from 'meteor/reactive-var'; import { ReactiveDict } from 'meteor/reactive-dict'; import { FlowRouter } from 'meteor/kadira:flow-router'; @@ -8,6 +7,8 @@ import { escapeRegExp } from '@rocket.chat/string-helpers'; import { t } from '../../utils/client'; import { EmojiPicker } from './lib/EmojiPicker'; import { emoji } from '../lib/rocketchat'; +import { withThrottling } from '../../../lib/utils/highOrderFunctions'; +import { baseURI } from '../../../client/lib/baseURI'; import './emojiPicker.html'; const ESCAPE = 27; @@ -17,7 +18,26 @@ const emojiListByCategory = new ReactiveDict('emojiList'); const getEmojiElement = (emoji, image) => image && `
  • ${image}
  • `; -const createEmojiList = (category, actualTone) => { +// used as a function so `t` can use the user's language correctly when called +const loadMoreLink = () => `
  • ${t('Load_more')}
  • `; + +let customItems = 90; + +const baseUrlFix = () => `${baseURI}${FlowRouter.current().path.substring(1)}`; + +const isMozillaFirefoxBelowVersion = (upperVersion) => { + const [, version] = navigator.userAgent.match(/Firefox\/(\d+)\.\d/) || []; + return parseInt(version, 10) < upperVersion; +}; + +const isGoogleChromeBelowVersion = (upperVersion) => { + const [, version] = navigator.userAgent.match(/Chrome\/(\d+)\.\d/) || []; + return parseInt(version, 10) < upperVersion; +}; + +const isBaseUrlFixNeeded = () => isMozillaFirefoxBelowVersion(55) || isGoogleChromeBelowVersion(55); + +const createEmojiList = (category, actualTone, limit = null) => { const html = Object.values(emoji.packages) .map((emojiPackage) => { @@ -25,12 +45,24 @@ const createEmojiList = (category, actualTone) => { return; } - return emojiPackage.emojisByCategory[category] - .map((current) => { - const tone = actualTone > 0 && emojiPackage.toneList.hasOwnProperty(current) ? `_tone${actualTone}` : ''; - return getEmojiElement(current, emojiPackage.renderPicker(`:${current}${tone}:`)); - }) - .join(''); + const result = []; + + const total = emojiPackage.emojisByCategory[category].length; + + const listTotal = limit ? Math.min(limit, total) : total; + + for (let i = 0; i < listTotal; i++) { + const current = emojiPackage.emojisByCategory[category][i]; + + const tone = actualTone > 0 && emojiPackage.toneList.hasOwnProperty(current) ? `_tone${actualTone}` : ''; + result.push(getEmojiElement(current, emojiPackage.renderPicker(`:${current}${tone}:`))); + } + + if (limit > 0 && total > limit) { + result.push(loadMoreLink()); + } + + return result.join(''); }) .join('') || `
  • ${t('No_emojis_found')}
  • `; @@ -38,25 +70,28 @@ const createEmojiList = (category, actualTone) => { }; export function updateRecentEmoji(category) { - emojiListByCategory.set(category, createEmojiList(category)); + emojiListByCategory.set(category, createEmojiList(category, null, category === 'rocket' ? customItems : null)); } const createPickerEmojis = (instance) => { const categories = instance.categoriesList; const actualTone = instance.tone; - categories.forEach((category) => emojiListByCategory.set(category.key, createEmojiList(category.key, actualTone))); + categories.forEach((category) => + emojiListByCategory.set(category.key, createEmojiList(category.key, actualTone, category.key === 'rocket' ? customItems : null)), + ); }; -function getEmojisBySearchTerm(searchTerm) { +function getEmojisBySearchTerm(searchTerm, limit) { let html = '
      '; - const t = Template.instance(); - const actualTone = t.tone; + const actualTone = Template.instance().tone; EmojiPicker.currentCategory.set(''); const searchRegExp = new RegExp(escapeRegExp(searchTerm.replace(/:/g, '')), 'i'); + let totalFound = 0; + for (let current in emoji.list) { if (!emoji.list.hasOwnProperty(current)) { continue; @@ -89,8 +124,14 @@ function getEmojisBySearchTerm(searchTerm) { if (emojiFound) { const image = emoji.packages[emojiPackage].renderPicker(`:${current}${tone}:`); html += getEmojiElement(current, image); + totalFound++; } } + + if (totalFound >= limit) { + html += loadMoreLink(); + break; + } } html += '
    '; @@ -116,10 +157,14 @@ Template.emojiPicker.helpers({ return Template.instance().currentSearchTerm.get().length > 0; }, searchResults() { - return getEmojisBySearchTerm(Template.instance().currentSearchTerm.get()); + return getEmojisBySearchTerm(Template.instance().currentSearchTerm.get(), Template.instance().searchTermItems.get()); }, - emojiList(category) { - return emojiListByCategory.get(category); + emojiList() { + emojiListByCategory.all(); + + return (category) => { + return emojiListByCategory.get(category); + }; }, currentTone() { return `tone-${Template.instance().tone}`; @@ -141,6 +186,7 @@ Template.emojiPicker.helpers({ currentCategory() { return EmojiPicker.currentCategory.get(); }, + baseUrl: isBaseUrlFixNeeded() ? baseUrlFix : undefined, }); Template.emojiPicker.events({ @@ -162,7 +208,7 @@ Template.emojiPicker.events({ return false; }, - 'scroll .emojis': _.throttle((event, instance) => { + 'scroll .emojis': withThrottling({ wait: 300 })((event, instance) => { if (EmojiPicker.scrollingToCategory) { return; } @@ -183,13 +229,25 @@ Template.emojiPicker.events({ const category = el.id.replace('emoji-list-category-', ''); EmojiPicker.currentCategory.set(category); - }, 300), + }), 'click .change-tone > a'(event, instance) { event.stopPropagation(); event.preventDefault(); instance.$('.tone-selector').toggleClass('show'); }, + 'click .emoji-picker-load-more > a'(event, instance) { + event.stopPropagation(); + event.preventDefault(); + + if (instance.currentSearchTerm.get().length > 0) { + instance.searchTermItems.set(instance.searchTermItems.get() + 90); + return; + } + + customItems += 90; + emojiListByCategory.set('rocket', createEmojiList('rocket', null, customItems)); + }, 'click .tone-selector .tone'(event, instance) { event.stopPropagation(); event.preventDefault(); @@ -241,6 +299,7 @@ Template.emojiPicker.events({ input.val(''); } instance.currentSearchTerm.set(''); + instance.searchTermItems.set(90); EmojiPicker.pickEmoji(_emoji + tone); }, @@ -266,6 +325,7 @@ Template.emojiPicker.onCreated(function () { const recent = EmojiPicker.getRecent(); this.currentSearchTerm = new ReactiveVar(''); + this.searchTermItems = new ReactiveVar(90); this.categoriesList = []; for (const emojiPackage in emoji.packages) { diff --git a/apps/meteor/app/emoji/client/index.js b/apps/meteor/app/emoji/client/index.ts similarity index 100% rename from apps/meteor/app/emoji/client/index.js rename to apps/meteor/app/emoji/client/index.ts diff --git a/apps/meteor/app/emoji/client/lib/EmojiPicker.js b/apps/meteor/app/emoji/client/lib/EmojiPicker.js index 8c5f883dfacf6..cbda2193a5c7a 100644 --- a/apps/meteor/app/emoji/client/lib/EmojiPicker.js +++ b/apps/meteor/app/emoji/client/lib/EmojiPicker.js @@ -1,4 +1,3 @@ -import _ from 'underscore'; import { Blaze } from 'meteor/blaze'; import { Meteor } from 'meteor/meteor'; import { Template } from 'meteor/templating'; @@ -6,6 +5,8 @@ import { ReactiveVar } from 'meteor/reactive-var'; import { Tracker } from 'meteor/tracker'; import { emoji } from '../../lib/rocketchat'; +import { updateRecentEmoji } from '../emojiPicker'; +import { withDebouncing } from '../../../../lib/utils/highOrderFunctions'; let updatePositions = true; @@ -45,12 +46,12 @@ export const EmojiPicker = { }); $(window).resize( - _.debounce(() => { + withDebouncing({ wait: 300 })(() => { if (!this.opened) { return; } this.setPosition(); - }, 300), + }), ); }, isOpened() { @@ -93,6 +94,10 @@ export const EmojiPicker = { return $('.emoji-picker').css(cssProperties); }, + /** + * @param {Element} source + * @param {(emoji: string) => void} callback + */ async open(source, callback) { if (!this.initiated) { await this.init(); @@ -122,10 +127,9 @@ export const EmojiPicker = { this.source.focus(); }, pickEmoji(emoji) { - this.pickCallback(emoji); - this.close(); this.addRecent(emoji); + this.pickCallback(emoji); }, addRecent(_emoji) { const pos = this.recent.indexOf(_emoji); @@ -153,9 +157,7 @@ export const EmojiPicker = { this.recent.splice(pos, 1); Meteor._localStorage.setItem('emoji.recent', this.recent); }, - async updateRecent(category) { - const emojiPickerImport = await import('../emojiPicker'); - const { updateRecentEmoji } = emojiPickerImport; + updateRecent(category) { updateRecentEmoji(category); }, calculateCategoryPositions() { diff --git a/apps/meteor/app/emoji/index.js b/apps/meteor/app/emoji/index.js index a67eca871efbb..1f3257e45429a 100644 --- a/apps/meteor/app/emoji/index.js +++ b/apps/meteor/app/emoji/index.js @@ -1,8 +1,8 @@ import { Meteor } from 'meteor/meteor'; if (Meteor.isClient) { - module.exports = require('./client/index.js'); + module.exports = require('./client/index.ts'); } if (Meteor.isServer) { - module.exports = require('./server/index.js'); + module.exports = require('./server/index.ts'); } diff --git a/apps/meteor/app/emoji/server/index.js b/apps/meteor/app/emoji/server/index.ts similarity index 100% rename from apps/meteor/app/emoji/server/index.js rename to apps/meteor/app/emoji/server/index.ts diff --git a/apps/meteor/app/error-handler/index.js b/apps/meteor/app/error-handler/index.ts similarity index 100% rename from apps/meteor/app/error-handler/index.js rename to apps/meteor/app/error-handler/index.ts diff --git a/apps/meteor/app/error-handler/server/index.js b/apps/meteor/app/error-handler/server/index.ts similarity index 100% rename from apps/meteor/app/error-handler/server/index.js rename to apps/meteor/app/error-handler/server/index.ts diff --git a/apps/meteor/app/federation-v2/server/Federation.ts b/apps/meteor/app/federation-v2/server/Federation.ts index 25080150b6878..f45bacc2bbe3a 100644 --- a/apps/meteor/app/federation-v2/server/Federation.ts +++ b/apps/meteor/app/federation-v2/server/Federation.ts @@ -1,21 +1,75 @@ -import type { IRoom, ValueOf } from '@rocket.chat/core-typings'; -import { isDirectMessageRoom } from '@rocket.chat/core-typings'; +import type { IRoom, IUser, ValueOf } from '@rocket.chat/core-typings'; +import { isRoomFederated, isDirectMessageRoom } from '@rocket.chat/core-typings'; +import { Subscriptions } from '@rocket.chat/models'; -import { RoomMemberActions } from '../../../definition/IRoomTypeConfig'; +import { RoomMemberActions, RoomSettingsEnum } from '../../../definition/IRoomTypeConfig'; +import { escapeExternalFederationEventId, unescapeExternalFederationEventId } from './infrastructure/rocket-chat/adapters/MessageConverter'; const allowedActionsInFederatedRooms: ValueOf[] = [ RoomMemberActions.REMOVE_USER, + RoomMemberActions.SET_AS_OWNER, + RoomMemberActions.SET_AS_MODERATOR, RoomMemberActions.INVITE, RoomMemberActions.JOIN, RoomMemberActions.LEAVE, ]; +const allowedActionsForModerators = allowedActionsInFederatedRooms.filter((action) => action !== RoomMemberActions.SET_AS_OWNER); + +const allowedRoomSettingsChangesInFederatedRooms: ValueOf[] = [RoomSettingsEnum.NAME, RoomSettingsEnum.TOPIC]; + export class Federation { - public static actionAllowed(room: IRoom, action: ValueOf): boolean { - return isDirectMessageRoom(room) && action === RoomMemberActions.REMOVE_USER ? false : allowedActionsInFederatedRooms.includes(action); + public static actionAllowed(room: IRoom, action: ValueOf, userId?: IUser['_id']): boolean { + if (!isRoomFederated(room)) { + return false; + } + if (isDirectMessageRoom(room)) { + return false; + } + if (!userId) { + return true; + } + + const userSubscription = Promise.await(Subscriptions.findOneByRoomIdAndUserId(room._id, userId)); + if (!userSubscription) { + return true; + } + + if (action === RoomMemberActions.LEAVE) { + return true; + } + + if (userSubscription.roles?.includes('owner')) { + return allowedActionsInFederatedRooms.includes(action); + } + + if (userSubscription.roles?.includes('moderator')) { + return allowedActionsForModerators.includes(action); + } + + return false; } public static isAFederatedUsername(username: string): boolean { return username.includes('@') && username.includes(':'); } + + public static escapeExternalFederationEventId(externalEventId: string): string { + return escapeExternalFederationEventId(externalEventId); + } + + public static unescapeExternalFederationEventId(externalEventId: string): string { + return unescapeExternalFederationEventId(externalEventId); + } + + public static isRoomSettingAllowed(room: Partial, setting: ValueOf): boolean { + if (!isRoomFederated(room)) { + return false; + } + + if (isDirectMessageRoom(room)) { + return false; + } + return allowedRoomSettingsChangesInFederatedRooms.includes(setting); + } } diff --git a/apps/meteor/app/federation-v2/server/application/AbstractFederationService.ts b/apps/meteor/app/federation-v2/server/application/AbstractFederationService.ts index 773eb480afc24..61647b5126b4a 100644 --- a/apps/meteor/app/federation-v2/server/application/AbstractFederationService.ts +++ b/apps/meteor/app/federation-v2/server/application/AbstractFederationService.ts @@ -1,5 +1,8 @@ +import type { IUser } from '@rocket.chat/core-typings'; + import { FederatedUser } from '../domain/FederatedUser'; import type { IFederationBridge } from '../domain/IFederationBridge'; +import type { RocketChatFileAdapter } from '../infrastructure/rocket-chat/adapters/File'; import type { RocketChatSettingsAdapter } from '../infrastructure/rocket-chat/adapters/Settings'; import type { RocketChatUserAdapter } from '../infrastructure/rocket-chat/adapters/User'; @@ -9,29 +12,66 @@ export abstract class FederationService { constructor( protected bridge: IFederationBridge, protected internalUserAdapter: RocketChatUserAdapter, + protected internalFileAdapter: RocketChatFileAdapter, protected internalSettingsAdapter: RocketChatSettingsAdapter, ) { this.internalHomeServerDomain = this.internalSettingsAdapter.getHomeServerDomain(); } - protected async createFederatedUser( + protected async createFederatedUserInternallyOnly( externalUserId: string, username: string, existsOnlyOnProxyServer = false, providedName?: string, ): Promise { + const internalUser = await this.internalUserAdapter.getInternalUserByUsername(username); const externalUserProfileInformation = await this.bridge.getUserProfileInformation(externalUserId); - const name = externalUserProfileInformation?.displayName || providedName || username; - const federatedUser = FederatedUser.createInstance(externalUserId, { - name, - username, - existsOnlyOnProxyServer, - }); - + let federatedUser; + if (internalUser) { + federatedUser = FederatedUser.createWithInternalReference(externalUserId, existsOnlyOnProxyServer, internalUser); + } else { + const name = externalUserProfileInformation?.displayName || providedName || username; + federatedUser = FederatedUser.createInstance(externalUserId, { + name, + username, + existsOnlyOnProxyServer, + }); + } await this.internalUserAdapter.createFederatedUser(federatedUser); + const insertedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalUserId); + if (!insertedUser) { + return; + } + await this.updateUserAvatarInternally(insertedUser, externalUserProfileInformation?.avatarUrl); + await this.updateUserDisplayNameInternally(insertedUser, externalUserProfileInformation?.displayName); + } + + protected async updateUserAvatarInternally(federatedUser: FederatedUser, avatarUrl?: string): Promise { + if (!avatarUrl) { + return; + } + if (!federatedUser.isRemote()) { + return; + } + if (federatedUser.shouldUpdateFederationAvatar(avatarUrl)) { + await this.internalUserAdapter.setAvatar(federatedUser, this.bridge.convertMatrixUrlToHttp(federatedUser.getExternalId(), avatarUrl)); + await this.internalUserAdapter.updateFederationAvatar(federatedUser.getInternalId(), avatarUrl); + } + } + + protected async updateUserDisplayNameInternally(federatedUser: FederatedUser, displayName?: string): Promise { + if (!displayName) { + return; + } + if (!federatedUser.isRemote()) { + return; + } + if (federatedUser.shouldUpdateDisplayName(displayName)) { + await this.internalUserAdapter.updateRealName(federatedUser.getInternalReference(), displayName); + } } - protected async createFederatedUserForInviterUsingLocalInformation(internalInviterId: string): Promise { + protected async createFederatedUserIncludingHomeserverUsingLocalInformation(internalInviterId: string): Promise { const internalUser = await this.internalUserAdapter.getInternalUserById(internalInviterId); if (!internalUser || !internalUser?.username) { throw new Error(`Could not find user id for ${internalInviterId}`); @@ -39,8 +79,35 @@ export abstract class FederationService { const name = internalUser.name || internalUser.username; const externalInviterId = await this.bridge.createUser(internalUser.username, name, this.internalHomeServerDomain); const existsOnlyOnProxyServer = true; - await this.createFederatedUser(externalInviterId, internalUser.username, existsOnlyOnProxyServer, name); + await this.createFederatedUserInternallyOnly(externalInviterId, internalUser.username, existsOnlyOnProxyServer, name); + await this.updateUserAvatarExternally( + internalUser, + (await this.internalUserAdapter.getFederatedUserByExternalId(externalInviterId)) as FederatedUser, + ); return externalInviterId; } + + protected async updateUserAvatarExternally(internalUser: IUser, externalInviter: FederatedUser): Promise { + if (!internalUser.username) { + return; + } + const buffer = await this.internalFileAdapter.getBufferForAvatarFile(internalUser.username); + if (!buffer) { + return; + } + const avatarFileRecord = await this.internalFileAdapter.getFileMetadataForAvatarFile(internalUser.username); + if (!avatarFileRecord?.type || !avatarFileRecord?.name) { + return; + } + const externalFileUri = await this.bridge.uploadContent(externalInviter.getExternalId(), buffer, { + type: avatarFileRecord.type, + name: avatarFileRecord.name, + }); + if (!externalFileUri) { + return; + } + await this.internalUserAdapter.updateFederationAvatar(internalUser._id, externalFileUri); + await this.bridge.setUserAvatar(externalInviter.getExternalId(), externalFileUri); + } } diff --git a/apps/meteor/app/federation-v2/server/application/RoomServiceListener.ts b/apps/meteor/app/federation-v2/server/application/RoomServiceListener.ts deleted file mode 100644 index afdd395e56573..0000000000000 --- a/apps/meteor/app/federation-v2/server/application/RoomServiceListener.ts +++ /dev/null @@ -1,258 +0,0 @@ -import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; -import { isDirectMessageRoom } from '@rocket.chat/core-typings'; - -import { DirectMessageFederatedRoom, FederatedRoom } from '../domain/FederatedRoom'; -import { FederatedUser } from '../domain/FederatedUser'; -import { EVENT_ORIGIN } from '../domain/IFederationBridge'; -import type { IFederationBridge } from '../domain/IFederationBridge'; -import type { RocketChatMessageAdapter } from '../infrastructure/rocket-chat/adapters/Message'; -import type { RocketChatRoomAdapter } from '../infrastructure/rocket-chat/adapters/Room'; -import type { RocketChatSettingsAdapter } from '../infrastructure/rocket-chat/adapters/Settings'; -import type { RocketChatUserAdapter } from '../infrastructure/rocket-chat/adapters/User'; -import type { - FederationRoomCreateInputDto, - FederationRoomChangeMembershipDto, - FederationRoomReceiveExternalMessageDto, - FederationRoomChangeJoinRulesDto, - FederationRoomChangeNameDto, - FederationRoomChangeTopicDto, -} from './input/RoomReceiverDto'; -import { FederationService } from './AbstractFederationService'; - -export class FederationRoomServiceListener extends FederationService { - constructor( - protected internalRoomAdapter: RocketChatRoomAdapter, - protected internalUserAdapter: RocketChatUserAdapter, - protected internalMessageAdapter: RocketChatMessageAdapter, - protected internalSettingsAdapter: RocketChatSettingsAdapter, - protected bridge: IFederationBridge, - ) { - super(bridge, internalUserAdapter, internalSettingsAdapter); - } - - public async onCreateRoom(roomCreateInput: FederationRoomCreateInputDto): Promise { - const { - externalRoomId, - externalInviterId, - normalizedInviterId, - externalRoomName, - normalizedRoomId, - roomType, - wasInternallyProgramaticallyCreated = false, - internalRoomId = '', - } = roomCreateInput; - - if (await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId)) { - return; - } - if (wasInternallyProgramaticallyCreated) { - const room = await this.internalRoomAdapter.getInternalRoomById(internalRoomId); - if (!room || !isDirectMessageRoom(room)) { - return; - } - await this.internalRoomAdapter.updateFederatedRoomByInternalRoomId(internalRoomId, externalRoomId); - return; - } - - const creatorUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalInviterId); - if (!creatorUser) { - await this.createFederatedUser(externalInviterId, normalizedInviterId); - } - const creator = creatorUser || (await this.internalUserAdapter.getFederatedUserByExternalId(externalInviterId)); - if (!creator) { - throw new Error('Creator user not found'); - } - const newFederatedRoom = FederatedRoom.createInstance( - externalRoomId, - normalizedRoomId, - creator, - roomType || RoomType.CHANNEL, - externalRoomName, - ); - await this.internalRoomAdapter.createFederatedRoom(newFederatedRoom); - } - - public async onChangeRoomMembership(roomChangeMembershipInput: FederationRoomChangeMembershipDto): Promise { - const { - externalRoomId, - normalizedInviteeId, - normalizedRoomId, - normalizedInviterId, - externalRoomName, - externalInviteeId, - externalInviterId, - inviteeUsernameOnly, - inviterUsernameOnly, - eventOrigin, - roomType, - leave, - } = roomChangeMembershipInput; - const wasGeneratedOnTheProxyServer = eventOrigin === EVENT_ORIGIN.LOCAL; - const affectedFederatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); - - if (wasGeneratedOnTheProxyServer && !affectedFederatedRoom) { - throw new Error(`Could not find room with external room id: ${externalRoomId}`); - } - - const isInviterFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( - this.bridge.extractHomeserverOrigin(externalInviterId), - this.internalHomeServerDomain, - ); - const isInviteeFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( - this.bridge.extractHomeserverOrigin(externalInviteeId), - this.internalHomeServerDomain, - ); - const inviterUsername = isInviterFromTheSameHomeServer ? inviterUsernameOnly : normalizedInviterId; - const inviteeUsername = isInviteeFromTheSameHomeServer ? inviteeUsernameOnly : normalizedInviteeId; - - const inviterUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalInviterId); - if (!inviterUser) { - await this.createFederatedUser(externalInviterId, inviterUsername, isInviterFromTheSameHomeServer); - } - - const inviteeUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalInviteeId); - if (!inviteeUser) { - await this.createFederatedUser(externalInviteeId, inviteeUsername, isInviteeFromTheSameHomeServer); - } - const federatedInviteeUser = inviteeUser || (await this.internalUserAdapter.getFederatedUserByExternalId(externalInviteeId)); - const federatedInviterUser = inviterUser || (await this.internalUserAdapter.getFederatedUserByExternalId(externalInviterId)); - - if (!federatedInviteeUser || !federatedInviterUser) { - throw new Error('Invitee or inviter user not found'); - } - - if (!wasGeneratedOnTheProxyServer && !affectedFederatedRoom) { - if (!roomType) { - return; - } - if (isDirectMessageRoom({ t: roomType })) { - const members = [federatedInviterUser, federatedInviteeUser]; - const newFederatedRoom = DirectMessageFederatedRoom.createInstance(externalRoomId, federatedInviterUser, members); - await this.internalRoomAdapter.createFederatedRoomForDirectMessage(newFederatedRoom); - await this.bridge.joinRoom(externalRoomId, externalInviteeId); - return; - } - const newFederatedRoom = FederatedRoom.createInstance( - externalRoomId, - normalizedRoomId, - federatedInviterUser, - roomType, - externalRoomName, - ); - - await this.internalRoomAdapter.createFederatedRoom(newFederatedRoom); - await this.bridge.joinRoom(externalRoomId, externalInviteeId); - } - - const federatedRoom = affectedFederatedRoom || (await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId)); - if (!federatedRoom) { - throw new Error(`Could not find room with external room id: ${externalRoomId}`); - } - - if (leave) { - const inviteeAlreadyJoinedTheInternalRoom = await this.internalRoomAdapter.isUserAlreadyJoined( - federatedRoom.getInternalId(), - federatedInviteeUser.getInternalId(), - ); - if (!inviteeAlreadyJoinedTheInternalRoom) { - return; - } - await this.internalRoomAdapter.removeUserFromRoom(federatedRoom, federatedInviteeUser, federatedInviterUser); - return; - } - if (!wasGeneratedOnTheProxyServer && federatedRoom.isDirectMessage()) { - const directMessageRoom = federatedRoom as DirectMessageFederatedRoom; - if (directMessageRoom.isUserPartOfTheRoom(federatedInviteeUser)) { - return; - } - directMessageRoom.addMember(federatedInviteeUser); - const newFederatedRoom = DirectMessageFederatedRoom.createInstance( - externalRoomId, - federatedInviterUser, - directMessageRoom.getMembers(), - ); - await this.internalRoomAdapter.removeDirectMessageRoom(federatedRoom); - await this.internalRoomAdapter.createFederatedRoomForDirectMessage(newFederatedRoom); - return; - } - - await this.internalRoomAdapter.addUserToRoom(federatedRoom, federatedInviteeUser, federatedInviterUser); - } - - public async onExternalMessageReceived(roomReceiveExternalMessageInput: FederationRoomReceiveExternalMessageDto): Promise { - const { externalRoomId, externalSenderId, messageText } = roomReceiveExternalMessageInput; - - const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); - if (!federatedRoom) { - return; - } - - const senderUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId); - if (!senderUser) { - return; - } - - await this.internalMessageAdapter.sendMessage(senderUser, federatedRoom, messageText); - } - - public async onChangeJoinRules(roomJoinRulesChangeInput: FederationRoomChangeJoinRulesDto): Promise { - const { externalRoomId, roomType } = roomJoinRulesChangeInput; - - const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); - if (!federatedRoom) { - return; - } - - const notAllowedChangeJoinRules = federatedRoom.isDirectMessage(); - if (notAllowedChangeJoinRules) { - return; - } - - federatedRoom.changeRoomType(roomType); - await this.internalRoomAdapter.updateRoomType(federatedRoom); - } - - public async onChangeRoomName(roomChangeNameInput: FederationRoomChangeNameDto): Promise { - const { externalRoomId, normalizedRoomName, externalSenderId } = roomChangeNameInput; - - const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); - if (!federatedRoom) { - return; - } - - if (!federatedRoom.shouldUpdateRoomName(normalizedRoomName)) { - return; - } - - const federatedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId); - if (!federatedUser) { - return; - } - - federatedRoom.changeRoomName(normalizedRoomName); - - await this.internalRoomAdapter.updateRoomName(federatedRoom, federatedUser); - } - - public async onChangeRoomTopic(roomChangeTopicInput: FederationRoomChangeTopicDto): Promise { - const { externalRoomId, roomTopic, externalSenderId } = roomChangeTopicInput; - - const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); - if (!federatedRoom) { - return; - } - - if (!federatedRoom.shouldUpdateRoomTopic(roomTopic)) { - return; - } - - const federatedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId); - if (!federatedUser) { - return; - } - - federatedRoom.changeRoomTopic(roomTopic); - - await this.internalRoomAdapter.updateRoomTopic(federatedRoom, federatedUser); - } -} diff --git a/apps/meteor/app/federation-v2/server/application/input/RoomReceiverDto.ts b/apps/meteor/app/federation-v2/server/application/input/RoomReceiverDto.ts deleted file mode 100644 index 8e20bbe0c9881..0000000000000 --- a/apps/meteor/app/federation-v2/server/application/input/RoomReceiverDto.ts +++ /dev/null @@ -1,199 +0,0 @@ -import type { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; - -import type { EVENT_ORIGIN } from '../../domain/IFederationBridge'; - -export interface IFederationReceiverBaseRoomInputDto { - externalRoomId: string; - normalizedRoomId: string; -} - -export interface IFederationCreateInputDto extends IFederationReceiverBaseRoomInputDto { - externalInviterId: string; - normalizedInviterId: string; - externalRoomName?: string; - roomType?: RoomType; - wasInternallyProgramaticallyCreated?: boolean; - internalRoomId?: string; -} - -export interface IFederationChangeMembershipInputDto extends IFederationReceiverBaseRoomInputDto { - externalInviterId: string; - normalizedInviterId: string; - externalInviteeId: string; - normalizedInviteeId: string; - inviteeUsernameOnly: string; - inviterUsernameOnly: string; - eventOrigin: EVENT_ORIGIN; - leave?: boolean; - roomType?: RoomType; - externalRoomName?: string; -} - -export interface IFederationSendInternalMessageInputDto extends IFederationReceiverBaseRoomInputDto { - externalSenderId: string; - normalizedSenderId: string; - messageText: string; -} - -export interface IFederationRoomChangeJoinRulesDtoInputDto extends IFederationReceiverBaseRoomInputDto { - roomType: RoomType; -} - -export interface IFederationRoomNameChangeInputDto extends IFederationReceiverBaseRoomInputDto { - normalizedRoomName: string; - - externalSenderId: string; -} - -export interface IFederationRoomTopicChangeInputDto extends IFederationReceiverBaseRoomInputDto { - roomTopic: string; - - externalSenderId: string; -} - -export class FederationBaseRoomInputDto { - constructor({ externalRoomId, normalizedRoomId }: IFederationReceiverBaseRoomInputDto) { - this.externalRoomId = externalRoomId; - this.normalizedRoomId = normalizedRoomId; - } - - externalRoomId: string; - - normalizedRoomId: string; -} - -export class FederationRoomCreateInputDto extends FederationBaseRoomInputDto { - constructor({ - externalRoomId, - normalizedRoomId, - externalInviterId, - normalizedInviterId, - wasInternallyProgramaticallyCreated, - roomType, - externalRoomName, - internalRoomId, - }: IFederationCreateInputDto) { - super({ externalRoomId, normalizedRoomId }); - this.externalInviterId = externalInviterId; - this.normalizedInviterId = normalizedInviterId; - this.wasInternallyProgramaticallyCreated = wasInternallyProgramaticallyCreated; - this.roomType = roomType; - this.externalRoomName = externalRoomName; - this.internalRoomId = internalRoomId; - } - - externalInviterId: string; - - normalizedInviterId: string; - - wasInternallyProgramaticallyCreated?: boolean; - - internalRoomId?: string; - - externalRoomName?: string; - - roomType?: RoomType; -} - -export class FederationRoomChangeMembershipDto extends FederationBaseRoomInputDto { - constructor({ - externalRoomId, - normalizedRoomId, - externalInviterId, - normalizedInviterId, - externalInviteeId, - normalizedInviteeId, - inviteeUsernameOnly, - inviterUsernameOnly, - eventOrigin, - leave, - roomType, - externalRoomName, - }: IFederationChangeMembershipInputDto) { - super({ externalRoomId, normalizedRoomId }); - this.externalInviterId = externalInviterId; - this.normalizedInviterId = normalizedInviterId; - this.externalInviteeId = externalInviteeId; - this.normalizedInviteeId = normalizedInviteeId; - this.inviteeUsernameOnly = inviteeUsernameOnly; - this.inviterUsernameOnly = inviterUsernameOnly; - this.eventOrigin = eventOrigin; - this.leave = leave; - this.roomType = roomType; - this.externalRoomName = externalRoomName; - } - - externalInviterId: string; - - normalizedInviterId: string; - - inviterUsernameOnly: string; - - externalInviteeId: string; - - normalizedInviteeId: string; - - inviteeUsernameOnly: string; - - eventOrigin: EVENT_ORIGIN; - - roomType?: RoomType; - - leave?: boolean; - - externalRoomName?: string; -} - -export class FederationRoomReceiveExternalMessageDto extends FederationBaseRoomInputDto { - constructor({ - externalRoomId, - normalizedRoomId, - externalSenderId, - normalizedSenderId, - messageText, - }: IFederationSendInternalMessageInputDto) { - super({ externalRoomId, normalizedRoomId }); - this.externalSenderId = externalSenderId; - this.normalizedSenderId = normalizedSenderId; - this.messageText = messageText; - } - - externalSenderId: string; - - normalizedSenderId: string; - - messageText: string; -} - -export class FederationRoomChangeJoinRulesDto extends FederationBaseRoomInputDto { - constructor({ externalRoomId, normalizedRoomId, roomType }: IFederationRoomChangeJoinRulesDtoInputDto) { - super({ externalRoomId, normalizedRoomId }); - this.roomType = roomType; - } - - roomType: RoomType; -} - -export class FederationRoomChangeNameDto extends FederationBaseRoomInputDto { - constructor({ externalRoomId, normalizedRoomId, normalizedRoomName, externalSenderId }: IFederationRoomNameChangeInputDto) { - super({ externalRoomId, normalizedRoomId }); - this.normalizedRoomName = normalizedRoomName; - this.externalSenderId = externalSenderId; - } - - normalizedRoomName: string; - - externalSenderId: string; -} - -export class FederationRoomChangeTopicDto extends FederationBaseRoomInputDto { - constructor({ externalRoomId, normalizedRoomId, roomTopic, externalSenderId }: IFederationRoomTopicChangeInputDto) { - super({ externalRoomId, normalizedRoomId }); - this.roomTopic = roomTopic; - this.externalSenderId = externalSenderId; - } - - roomTopic: string; - - externalSenderId: string; -} diff --git a/apps/meteor/app/federation-v2/server/application/listener/MessageServiceListener.ts b/apps/meteor/app/federation-v2/server/application/listener/MessageServiceListener.ts new file mode 100644 index 0000000000000..6ebe9d8b3df1b --- /dev/null +++ b/apps/meteor/app/federation-v2/server/application/listener/MessageServiceListener.ts @@ -0,0 +1,59 @@ +import { isMessageFromMatrixFederation } from '@rocket.chat/core-typings'; + +import type { IFederationBridge } from '../../domain/IFederationBridge'; +import type { RocketChatFileAdapter } from '../../infrastructure/rocket-chat/adapters/File'; +import type { RocketChatMessageAdapter } from '../../infrastructure/rocket-chat/adapters/Message'; +import type { RocketChatRoomAdapter } from '../../infrastructure/rocket-chat/adapters/Room'; +import type { RocketChatSettingsAdapter } from '../../infrastructure/rocket-chat/adapters/Settings'; +import type { RocketChatUserAdapter } from '../../infrastructure/rocket-chat/adapters/User'; +import { FederationService } from '../AbstractFederationService'; +import type { FederationMessageReactionEventDto } from './input/MessageReceiverDto'; + +export class FederationMessageServiceListener extends FederationService { + constructor( + protected internalRoomAdapter: RocketChatRoomAdapter, + protected internalUserAdapter: RocketChatUserAdapter, + protected internalMessageAdapter: RocketChatMessageAdapter, + protected internalFileAdapter: RocketChatFileAdapter, + protected internalSettingsAdapter: RocketChatSettingsAdapter, + protected bridge: IFederationBridge, + ) { + super(bridge, internalUserAdapter, internalFileAdapter, internalSettingsAdapter); + } + + public async onMessageReaction(messageReactionEventInput: FederationMessageReactionEventDto): Promise { + const { + externalRoomId, + emoji, + externalSenderId, + externalEventId: externalReactionEventId, + externalReactedEventId: externalMessageId, + } = messageReactionEventInput; + + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); + if (!federatedRoom) { + return; + } + + const federatedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId); + if (!federatedUser) { + return; + } + const message = await this.internalMessageAdapter.getMessageByFederationId(externalMessageId); + if (!message) { + return; + } + if (!isMessageFromMatrixFederation(message)) { + return; + } + // TODO: move this to a Message entity in the domain layer + const userAlreadyReacted = Boolean( + federatedUser.getUsername() && message.reactions?.[emoji]?.usernames?.includes(federatedUser.getUsername() as string), + ); + if (userAlreadyReacted) { + return; + } + + await this.internalMessageAdapter.reactToMessage(federatedUser, message, emoji, externalReactionEventId); + } +} diff --git a/apps/meteor/app/federation-v2/server/application/listener/RoomRedactionHandlers.ts b/apps/meteor/app/federation-v2/server/application/listener/RoomRedactionHandlers.ts new file mode 100644 index 0000000000000..e966a2ebc1c44 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/application/listener/RoomRedactionHandlers.ts @@ -0,0 +1,61 @@ +import type { IMessage } from '@rocket.chat/core-typings'; + +import type { FederatedUser } from '../../domain/FederatedUser'; +import { Federation } from '../../Federation'; +import type { RocketChatMessageAdapter } from '../../infrastructure/rocket-chat/adapters/Message'; + +export interface IRoomRedactionHandlers { + handle(): Promise; +} + +class DeleteMessageHandler implements IRoomRedactionHandlers { + constructor( + private readonly internalMessageAdapter: RocketChatMessageAdapter, + private readonly message: IMessage, + private readonly federatedUser: FederatedUser, + ) {} + + public async handle(): Promise { + await this.internalMessageAdapter.deleteMessage(this.message, this.federatedUser); + } +} + +class UnreactToMessageHandler implements IRoomRedactionHandlers { + constructor( + private readonly internalMessageAdapter: RocketChatMessageAdapter, + private readonly message: IMessage, + private readonly federatedUser: FederatedUser, + private readonly redactsEvents: string, + ) {} + + public async handle(): Promise { + const normalizedEventId = Federation.escapeExternalFederationEventId(this.redactsEvents); + const reaction = Object.keys(this.message.reactions || {}).find( + (key) => + this.message.reactions?.[key]?.federationReactionEventIds?.[normalizedEventId] === this.federatedUser.getUsername() && + this.message.reactions?.[key]?.usernames?.includes(this.federatedUser.getUsername() || ''), + ); + if (!reaction) { + return; + } + await this.internalMessageAdapter.unreactToMessage(this.federatedUser, this.message, reaction, this.redactsEvents); + } +} + +export const getRedactMessageHandler = async ( + internalMessageAdapter: RocketChatMessageAdapter, + redactsEvent: string, + federatedUser: FederatedUser, +): Promise => { + const message = await internalMessageAdapter.getMessageByFederationId(redactsEvent); + const messageWithReaction = await internalMessageAdapter.findOneByFederationIdOnReactions(redactsEvent, federatedUser); + if (!message && !messageWithReaction) { + return; + } + if (messageWithReaction) { + return new UnreactToMessageHandler(internalMessageAdapter, messageWithReaction, federatedUser, redactsEvent); + } + if (message) { + return new DeleteMessageHandler(internalMessageAdapter, message, federatedUser); + } +}; diff --git a/apps/meteor/app/federation-v2/server/application/listener/RoomServiceListener.ts b/apps/meteor/app/federation-v2/server/application/listener/RoomServiceListener.ts new file mode 100644 index 0000000000000..35ea70e258096 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/application/listener/RoomServiceListener.ts @@ -0,0 +1,561 @@ +import { isDirectMessageRoom, isQuoteAttachment } from '@rocket.chat/core-typings'; + +import { DirectMessageFederatedRoom, FederatedRoom } from '../../domain/FederatedRoom'; +import { FederatedUser } from '../../domain/FederatedUser'; +import { EVENT_ORIGIN } from '../../domain/IFederationBridge'; +import type { IFederationBridge } from '../../domain/IFederationBridge'; +import type { RocketChatMessageAdapter } from '../../infrastructure/rocket-chat/adapters/Message'; +import type { RocketChatRoomAdapter } from '../../infrastructure/rocket-chat/adapters/Room'; +import type { RocketChatSettingsAdapter } from '../../infrastructure/rocket-chat/adapters/Settings'; +import type { RocketChatUserAdapter } from '../../infrastructure/rocket-chat/adapters/User'; +import type { + FederationRoomCreateInputDto, + FederationRoomChangeMembershipDto, + FederationRoomReceiveExternalMessageDto, + FederationRoomChangeJoinRulesDto, + FederationRoomChangeNameDto, + FederationRoomChangeTopicDto, + FederationRoomReceiveExternalFileMessageDto, + FederationRoomRedactEventDto, + FederationRoomEditExternalMessageDto, + FederationRoomRoomChangePowerLevelsEventDto, +} from './input/RoomReceiverDto'; +import { FederationService } from '../AbstractFederationService'; +import type { RocketChatFileAdapter } from '../../infrastructure/rocket-chat/adapters/File'; +import { getRedactMessageHandler } from './RoomRedactionHandlers'; +import type { RocketChatNotificationAdapter } from '../../infrastructure/rocket-chat/adapters/Notification'; +import type { InMemoryQueue } from '../../infrastructure/queue/InMemoryQueue'; + +export class FederationRoomServiceListener extends FederationService { + constructor( + protected internalRoomAdapter: RocketChatRoomAdapter, + protected internalUserAdapter: RocketChatUserAdapter, + protected internalMessageAdapter: RocketChatMessageAdapter, + protected internalFileAdapter: RocketChatFileAdapter, + protected internalSettingsAdapter: RocketChatSettingsAdapter, + protected internalNotificationAdapter: RocketChatNotificationAdapter, + protected federationQueueInstance: InMemoryQueue, + protected bridge: IFederationBridge, + ) { + super(bridge, internalUserAdapter, internalFileAdapter, internalSettingsAdapter); + } + + public async onCreateRoom(roomCreateInput: FederationRoomCreateInputDto): Promise { + const { externalRoomId, wasInternallyProgramaticallyCreated = false, internalRoomId = '' } = roomCreateInput; + if (await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId)) { + return; + } + if (!wasInternallyProgramaticallyCreated) { + return; + } + const room = await this.internalRoomAdapter.getInternalRoomById(internalRoomId); + if (!room || !isDirectMessageRoom(room)) { + return; + } + await this.internalRoomAdapter.updateFederatedRoomByInternalRoomId(internalRoomId, externalRoomId); + } + + public async onChangeRoomMembership(roomChangeMembershipInput: FederationRoomChangeMembershipDto): Promise { + const { + externalRoomId, + normalizedInviteeId, + normalizedRoomId, + normalizedInviterId, + externalInviteeId, + externalInviterId, + inviteeUsernameOnly, + inviterUsernameOnly, + eventOrigin, + roomType, + leave, + userProfile, + allInviteesExternalIdsWhenDM, + externalRoomName, + externalEventId, + } = roomChangeMembershipInput; + const wasGeneratedOnTheProxyServer = eventOrigin === EVENT_ORIGIN.LOCAL; + const affectedFederatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); + const isUserJoiningByHimself = externalInviterId === externalInviteeId && !leave; + + if (userProfile?.avatarUrl) { + const federatedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalInviteeId); + federatedUser && (await this.updateUserAvatarInternally(federatedUser, userProfile?.avatarUrl)); + } + if (userProfile?.displayName) { + const federatedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalInviteeId); + federatedUser && (await this.updateUserDisplayNameInternally(federatedUser, userProfile?.displayName)); + } + + if (wasGeneratedOnTheProxyServer && (isUserJoiningByHimself || !affectedFederatedRoom)) { + return; + } + + const isInviterFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(externalInviterId), + this.internalHomeServerDomain, + ); + const isInviteeFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(externalInviteeId), + this.internalHomeServerDomain, + ); + const inviterUsername = isInviterFromTheSameHomeServer ? inviterUsernameOnly : normalizedInviterId; + const inviteeUsername = isInviteeFromTheSameHomeServer ? inviteeUsernameOnly : normalizedInviteeId; + + const inviterUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalInviterId); + if (!inviterUser) { + await this.createFederatedUserInternallyOnly(externalInviterId, inviterUsername, isInviterFromTheSameHomeServer); + } + + const inviteeUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalInviteeId); + if (!inviteeUser) { + await this.createFederatedUserInternallyOnly(externalInviteeId, inviteeUsername, isInviteeFromTheSameHomeServer); + } + const federatedInviteeUser = inviteeUser || (await this.internalUserAdapter.getFederatedUserByExternalId(externalInviteeId)); + const federatedInviterUser = inviterUser || (await this.internalUserAdapter.getFederatedUserByExternalId(externalInviterId)); + + if (!federatedInviteeUser || !federatedInviterUser) { + throw new Error('Invitee or inviter user not found'); + } + + if (!wasGeneratedOnTheProxyServer && !affectedFederatedRoom) { + if (!roomType) { + return; + } + if (isDirectMessageRoom({ t: roomType })) { + const wereAllInviteesProvidedByCreationalEventAtOnce = allInviteesExternalIdsWhenDM && allInviteesExternalIdsWhenDM.length > 0; + if (wereAllInviteesProvidedByCreationalEventAtOnce) { + return this.handleDMRoomInviteWhenAllUsersWereBeingProvidedInTheCreationalEvent( + allInviteesExternalIdsWhenDM, + externalRoomId, + federatedInviterUser, + ); + } + return this.handleDMRoomInviteWhenNotifiedByRegularEventsOnly(federatedInviteeUser, federatedInviterUser, externalRoomId); + } + + const newFederatedRoom = FederatedRoom.createInstance(externalRoomId, normalizedRoomId, federatedInviterUser, roomType); + const createdInternalRoomId = await this.internalRoomAdapter.createFederatedRoom(newFederatedRoom); + + await this.bridge.joinRoom(externalRoomId, externalInviteeId); + if (externalRoomName) { + await this.onChangeRoomName({ + externalRoomId, + normalizedRoomName: externalRoomName, + externalEventId, + externalSenderId: externalInviterId, + normalizedRoomId, + }); + } + await this.internalNotificationAdapter.subscribeToUserTypingEventsOnFederatedRoomId( + createdInternalRoomId, + this.internalNotificationAdapter.broadcastUserTypingOnRoom.bind(this.internalNotificationAdapter), + ); + const roomHistoricalJoinEvents = await this.bridge.getRoomHistoricalJoinEvents(externalRoomId, externalInviteeId, [ + externalInviterId, + externalInviteeId, + ]); + roomHistoricalJoinEvents.forEach((event) => this.federationQueueInstance.addToQueue(event)); + } + + const federatedRoom = affectedFederatedRoom || (await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId)); + if (!federatedRoom) { + return; + } + + const inviteeAlreadyJoinedTheInternalRoom = await this.internalRoomAdapter.isUserAlreadyJoined( + federatedRoom.getInternalId(), + federatedInviteeUser.getInternalId(), + ); + if (!leave && inviteeAlreadyJoinedTheInternalRoom) { + return; + } + + if (leave) { + const inviteeAlreadyJoinedTheInternalRoom = await this.internalRoomAdapter.isUserAlreadyJoined( + federatedRoom.getInternalId(), + federatedInviteeUser.getInternalId(), + ); + if (!inviteeAlreadyJoinedTheInternalRoom) { + return; + } + await this.internalRoomAdapter.removeUserFromRoom(federatedRoom, federatedInviteeUser, federatedInviterUser); + return; + } + if (!wasGeneratedOnTheProxyServer && federatedRoom.isDirectMessage()) { + const directMessageRoom = federatedRoom as DirectMessageFederatedRoom; + if (directMessageRoom.isUserPartOfTheRoom(federatedInviteeUser)) { + return; + } + directMessageRoom.addMember(federatedInviteeUser); + const newFederatedRoom = DirectMessageFederatedRoom.createInstance( + externalRoomId, + federatedInviterUser, + directMessageRoom.getMembers(), + ); + await this.internalRoomAdapter.removeDirectMessageRoom(federatedRoom); + const createdInternalRoomId = await this.internalRoomAdapter.createFederatedRoomForDirectMessage(newFederatedRoom); + await this.internalNotificationAdapter.subscribeToUserTypingEventsOnFederatedRoomId( + createdInternalRoomId, + this.internalNotificationAdapter.broadcastUserTypingOnRoom.bind(this.internalNotificationAdapter), + ); + return; + } + if (isUserJoiningByHimself) { + await this.internalRoomAdapter.addUserToRoom(federatedRoom, federatedInviteeUser); + return; + } + await this.internalRoomAdapter.addUserToRoom(federatedRoom, federatedInviteeUser, federatedInviterUser); + if (isInviteeFromTheSameHomeServer) { + await this.bridge.joinRoom(externalRoomId, externalInviteeId); + } + } + + private async handleDMRoomInviteWhenAllUsersWereBeingProvidedInTheCreationalEvent( + allInviteesExternalIds: { + externalInviteeId: string; + normalizedInviteeId: string; + inviteeUsernameOnly: string; + }[], + externalRoomId: string, + federatedInviterUser: FederatedUser, + ): Promise { + const allInvitees = await Promise.all( + allInviteesExternalIds.map(async (dmExternalInviteeId) => { + const invitee = await this.internalUserAdapter.getFederatedUserByExternalId(dmExternalInviteeId.externalInviteeId); + if (!invitee) { + const isDMInviteeFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(dmExternalInviteeId.externalInviteeId), + this.internalHomeServerDomain, + ); + const dmInviteeUsername = isDMInviteeFromTheSameHomeServer + ? dmExternalInviteeId.inviteeUsernameOnly + : dmExternalInviteeId.normalizedInviteeId; + await this.createFederatedUserInternallyOnly( + dmExternalInviteeId.externalInviteeId, + dmInviteeUsername, + isDMInviteeFromTheSameHomeServer, + ); + } + return (invitee || + (await this.internalUserAdapter.getFederatedUserByExternalId(dmExternalInviteeId.externalInviteeId))) as FederatedUser; + }), + ); + const newFederatedRoom = DirectMessageFederatedRoom.createInstance(externalRoomId, federatedInviterUser, [ + federatedInviterUser, + ...allInvitees, + ]); + const createdInternalRoomId = await this.internalRoomAdapter.createFederatedRoomForDirectMessage(newFederatedRoom); + await this.internalNotificationAdapter.subscribeToUserTypingEventsOnFederatedRoomId( + createdInternalRoomId, + this.internalNotificationAdapter.broadcastUserTypingOnRoom.bind(this.internalNotificationAdapter), + ); + await Promise.all( + allInvitees + .filter((invitee) => + FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(invitee.getExternalId()), + this.internalHomeServerDomain, + ), + ) + .map((invitee) => this.bridge.joinRoom(externalRoomId, invitee.getExternalId())), + ); + } + + private async handleDMRoomInviteWhenNotifiedByRegularEventsOnly( + federatedInviteeUser: FederatedUser, + federatedInviterUser: FederatedUser, + externalRoomId: string, + ): Promise { + const members = [federatedInviterUser, federatedInviteeUser]; + const newFederatedRoom = DirectMessageFederatedRoom.createInstance(externalRoomId, federatedInviterUser, members); + const createdInternalRoomId = await this.internalRoomAdapter.createFederatedRoomForDirectMessage(newFederatedRoom); + const isInviteeFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(federatedInviteeUser.getExternalId()), + this.internalHomeServerDomain, + ); + await this.internalNotificationAdapter.subscribeToUserTypingEventsOnFederatedRoomId( + createdInternalRoomId, + this.internalNotificationAdapter.broadcastUserTypingOnRoom.bind(this.internalNotificationAdapter), + ); + if (isInviteeFromTheSameHomeServer) { + await this.bridge.joinRoom(externalRoomId, federatedInviteeUser.getExternalId()); + } + } + + public async onExternalMessageReceived(roomReceiveExternalMessageInput: FederationRoomReceiveExternalMessageDto): Promise { + const { externalRoomId, externalSenderId, rawMessage, externalFormattedText, externalEventId, replyToEventId } = + roomReceiveExternalMessageInput; + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); + if (!federatedRoom) { + return; + } + + const senderUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId); + if (!senderUser) { + return; + } + const message = await this.internalMessageAdapter.getMessageByFederationId(externalEventId); + if (message) { + return; + } + + if (replyToEventId) { + const messageToReplyTo = await this.internalMessageAdapter.getMessageByFederationId(replyToEventId); + if (!messageToReplyTo) { + return; + } + await this.internalMessageAdapter.sendQuoteMessage( + senderUser, + federatedRoom, + externalFormattedText, + rawMessage, + externalEventId, + messageToReplyTo, + this.internalHomeServerDomain, + ); + return; + } + + await this.internalMessageAdapter.sendMessage( + senderUser, + federatedRoom, + rawMessage, + externalFormattedText, + externalEventId, + this.internalHomeServerDomain, + ); + } + + public async onExternalMessageEditedReceived(roomEditExternalMessageInput: FederationRoomEditExternalMessageDto): Promise { + const { externalRoomId, externalSenderId, editsEvent, newExternalFormattedText, newRawMessage } = roomEditExternalMessageInput; + + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); + if (!federatedRoom) { + return; + } + + const senderUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId); + if (!senderUser) { + return; + } + + const message = await this.internalMessageAdapter.getMessageByFederationId(editsEvent); + if (!message) { + return; + } + + // TODO: leaked business logic, move this to its proper place + const isAQuotedMessage = message.attachments?.some((attachment) => isQuoteAttachment(attachment) && Boolean(attachment.message_link)); + if (isAQuotedMessage) { + const wasGeneratedLocally = FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(externalSenderId), + this.internalHomeServerDomain, + ); + if (wasGeneratedLocally) { + return; + } + const internalFormattedMessageToBeEdited = await this.internalMessageAdapter.getMessageToEditWhenReplyAndQuote( + message, + newExternalFormattedText, + newRawMessage, + this.internalHomeServerDomain, + senderUser, + ); + // TODO: create an entity to abstract all the message logic + if (!FederatedRoom.shouldUpdateMessage(internalFormattedMessageToBeEdited, message)) { + return; + } + await this.internalMessageAdapter.editQuotedMessage( + senderUser, + newRawMessage, + newExternalFormattedText, + message, + this.internalHomeServerDomain, + ); + return; + } + if (!FederatedRoom.shouldUpdateMessage(newRawMessage, message)) { + return; + } + await this.internalMessageAdapter.editMessage( + senderUser, + newRawMessage, + newExternalFormattedText, + message, + this.internalHomeServerDomain, + ); + } + + public async onExternalFileMessageReceived(roomReceiveExternalMessageInput: FederationRoomReceiveExternalFileMessageDto): Promise { + const { externalRoomId, externalSenderId, messageBody, externalEventId, replyToEventId } = roomReceiveExternalMessageInput; + + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); + if (!federatedRoom) { + return; + } + + const senderUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId); + if (!senderUser) { + return; + } + const message = await this.internalMessageAdapter.getMessageByFederationId(externalEventId); + if (message) { + return; + } + const fileDetails = { + name: messageBody.filename, + size: messageBody.size, + type: messageBody.mimetype, + rid: federatedRoom.getInternalId(), + userId: senderUser.getInternalId(), + }; + const readableStream = await this.bridge.getReadStreamForFileFromUrl(senderUser.getExternalId(), messageBody.url); + const { files = [], attachments } = await this.internalFileAdapter.uploadFile( + readableStream, + federatedRoom.getInternalId(), + senderUser.getInternalReference(), + fileDetails, + ); + + if (replyToEventId) { + const messageToReplyTo = await this.internalMessageAdapter.getMessageByFederationId(replyToEventId); + if (!messageToReplyTo) { + return; + } + await this.internalMessageAdapter.sendQuoteFileMessage( + senderUser, + federatedRoom, + files, + attachments, + externalEventId, + messageToReplyTo, + this.internalHomeServerDomain, + ); + return; + } + + await this.internalMessageAdapter.sendFileMessage(senderUser, federatedRoom, files, attachments, externalEventId); + } + + public async onChangeJoinRules(roomJoinRulesChangeInput: FederationRoomChangeJoinRulesDto): Promise { + const { externalRoomId, roomType } = roomJoinRulesChangeInput; + + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); + if (!federatedRoom) { + return; + } + + const notAllowedChangeJoinRules = federatedRoom.isDirectMessage(); + if (notAllowedChangeJoinRules) { + return; + } + + federatedRoom.changeRoomType(roomType); + await this.internalRoomAdapter.updateRoomType(federatedRoom); + } + + public async onChangeRoomName(roomChangeNameInput: FederationRoomChangeNameDto): Promise { + const { externalRoomId, normalizedRoomName, externalSenderId } = roomChangeNameInput; + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); + if (!federatedRoom) { + return; + } + + const federatedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId); + if (!federatedUser) { + return; + } + const shouldUseExternalRoomIdAsRoomName = !FederatedRoom.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(externalRoomId), + this.internalHomeServerDomain, + ); + if (shouldUseExternalRoomIdAsRoomName) { + federatedRoom.changeRoomName(externalRoomId); + await this.internalRoomAdapter.updateRoomName(federatedRoom); + } + if (!federatedRoom.shouldUpdateDisplayRoomName(normalizedRoomName)) { + return; + } + + federatedRoom.changeDisplayRoomName(normalizedRoomName); + + await this.internalRoomAdapter.updateDisplayRoomName(federatedRoom, federatedUser); + } + + public async onChangeRoomTopic(roomChangeTopicInput: FederationRoomChangeTopicDto): Promise { + const { externalRoomId, roomTopic, externalSenderId } = roomChangeTopicInput; + + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); + if (!federatedRoom) { + return; + } + + if (!federatedRoom.shouldUpdateRoomTopic(roomTopic)) { + return; + } + + const federatedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId); + if (!federatedUser) { + return; + } + + federatedRoom.changeRoomTopic(roomTopic); + + await this.internalRoomAdapter.updateRoomTopic(federatedRoom, federatedUser); + } + + public async onRedactEvent(roomRedactEventInput: FederationRoomRedactEventDto): Promise { + const { externalRoomId, redactsEvent, externalSenderId } = roomRedactEventInput; + + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); + if (!federatedRoom) { + return; + } + + const federatedUser = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId); + if (!federatedUser) { + return; + } + const handler = await getRedactMessageHandler(this.internalMessageAdapter, redactsEvent, federatedUser); + if (!handler) { + return; + } + await handler.handle(); + } + + public async onChangeRoomPowerLevels(roomPowerLevelsInput: FederationRoomRoomChangePowerLevelsEventDto): Promise { + const { externalRoomId, roleChangesToApply = {}, externalSenderId } = roomPowerLevelsInput; + + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); + if (!federatedRoom) { + return; + } + + const federatedUserWhoChangedThePermission = await this.internalUserAdapter.getFederatedUserByExternalId(externalSenderId); + if (!federatedUserWhoChangedThePermission) { + return; + } + + const federatedUsers = await this.internalUserAdapter.getFederatedUsersByExternalIds(Object.keys(roleChangesToApply)); + + await Promise.all( + federatedUsers.map((targetFederatedUser) => { + const changes = roleChangesToApply[targetFederatedUser.getExternalId()]; + if (!changes) { + return; + } + const rolesToRemove = changes.filter((change) => change.action === 'remove').map((change) => change.role); + const rolesToAdd = changes.filter((change) => change.action === 'add').map((change) => change.role); + + return this.internalRoomAdapter.applyRoomRolesToUser({ + federatedRoom, + targetFederatedUser, + fromUser: federatedUserWhoChangedThePermission, + rolesToAdd, + rolesToRemove, + notifyChannel: true, + }); + }), + ); + } +} diff --git a/apps/meteor/app/federation-v2/server/application/listener/UserServiceListener.ts b/apps/meteor/app/federation-v2/server/application/listener/UserServiceListener.ts new file mode 100644 index 0000000000000..3a6a625038046 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/application/listener/UserServiceListener.ts @@ -0,0 +1,75 @@ +import type { IFederationBridge } from '../../domain/IFederationBridge'; +import type { RocketChatFileAdapter } from '../../infrastructure/rocket-chat/adapters/File'; +import type { RocketChatNotificationAdapter } from '../../infrastructure/rocket-chat/adapters/Notification'; +import type { RocketChatRoomAdapter } from '../../infrastructure/rocket-chat/adapters/Room'; +import type { RocketChatSettingsAdapter } from '../../infrastructure/rocket-chat/adapters/Settings'; +import type { RocketChatUserAdapter } from '../../infrastructure/rocket-chat/adapters/User'; +import { FederationService } from '../AbstractFederationService'; +import type { FederationUserTypingStatusEventDto } from './input/UserReceiverDto'; + +export class FederationUserServiceListener extends FederationService { + private usersTypingByRoomIdCache: Map[]> = new Map(); + + constructor( + protected internalRoomAdapter: RocketChatRoomAdapter, + protected internalUserAdapter: RocketChatUserAdapter, + protected internalFileAdapter: RocketChatFileAdapter, + protected internalNotificationAdapter: RocketChatNotificationAdapter, + protected internalSettingsAdapter: RocketChatSettingsAdapter, + protected bridge: IFederationBridge, + ) { + super(bridge, internalUserAdapter, internalFileAdapter, internalSettingsAdapter); + } + + private handleUsersWhoStoppedTyping(externalRoomId: string, internalRoomId: string, externalUserIdsTyping: string[]): void { + const isTyping = false; + const notTypingAnymore = this.usersTypingByRoomIdCache + .get(externalRoomId) + ?.filter((user) => !externalUserIdsTyping.includes(user.externalUserId)); + + const stillTyping = this.usersTypingByRoomIdCache + .get(externalRoomId) + ?.filter((user) => externalUserIdsTyping.includes(user.externalUserId)); + + notTypingAnymore?.forEach((user) => this.internalNotificationAdapter.notifyUserTypingOnRoom(internalRoomId, user.username, isTyping)); + this.usersTypingByRoomIdCache.set(externalRoomId, stillTyping || []); + } + + public async onUserTyping(userTypingInput: FederationUserTypingStatusEventDto): Promise { + const { externalUserIdsTyping, externalRoomId } = userTypingInput; + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByExternalId(externalRoomId); + if (!federatedRoom) { + return; + } + if (this.usersTypingByRoomIdCache.has(externalRoomId)) { + this.handleUsersWhoStoppedTyping(externalRoomId, federatedRoom.getInternalId(), externalUserIdsTyping); + } + + if (externalUserIdsTyping.length === 0) { + return; + } + + const federatedUsers = await this.internalUserAdapter.getFederatedUsersByExternalIds(externalUserIdsTyping); + if (federatedUsers.length === 0) { + return; + } + + const isTyping = true; + + this.usersTypingByRoomIdCache.set( + externalRoomId, + federatedUsers.map((federatedUser) => { + this.internalNotificationAdapter.notifyUserTypingOnRoom( + federatedRoom.getInternalId(), + federatedUser.getUsername() as string, + isTyping, + ); + + return { + externalUserId: federatedUser.getInternalId(), + username: federatedUser.getUsername() as string, + }; + }), + ); + } +} diff --git a/apps/meteor/app/federation-v2/server/application/listener/input/MessageReceiverDto.ts b/apps/meteor/app/federation-v2/server/application/listener/input/MessageReceiverDto.ts new file mode 100644 index 0000000000000..43dc255fef9a3 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/application/listener/input/MessageReceiverDto.ts @@ -0,0 +1,31 @@ +import type { IFederationReceiverBaseRoomInputDto } from './RoomReceiverDto'; +import { FederationBaseRoomInputDto } from './RoomReceiverDto'; + +interface IFederationRoomMessageReactionInputDto extends IFederationReceiverBaseRoomInputDto { + externalSenderId: string; + externalEventId: string; + externalReactedEventId: string; + emoji: string; +} + +export class FederationMessageReactionEventDto extends FederationBaseRoomInputDto { + constructor({ + externalRoomId, + normalizedRoomId, + externalEventId, + externalReactedEventId, + emoji, + externalSenderId, + }: IFederationRoomMessageReactionInputDto) { + super({ externalRoomId, normalizedRoomId, externalEventId }); + this.emoji = emoji; + this.externalSenderId = externalSenderId; + this.externalReactedEventId = externalReactedEventId; + } + + emoji: string; + + externalSenderId: string; + + externalReactedEventId: string; +} diff --git a/apps/meteor/app/federation-v2/server/application/listener/input/RoomReceiverDto.ts b/apps/meteor/app/federation-v2/server/application/listener/input/RoomReceiverDto.ts new file mode 100644 index 0000000000000..dacb02f3e2ee2 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/application/listener/input/RoomReceiverDto.ts @@ -0,0 +1,404 @@ +import type { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; + +import type { EVENT_ORIGIN } from '../../../domain/IFederationBridge'; +import type { ROCKET_CHAT_FEDERATION_ROLES } from '../../../infrastructure/rocket-chat/definitions/InternalFederatedRoomRoles'; + +interface IFederationBaseInputDto { + externalEventId: string; +} + +export interface IFederationReceiverBaseRoomInputDto extends IFederationBaseInputDto { + externalRoomId: string; + normalizedRoomId: string; +} + +export interface IFederationCreateInputDto extends IFederationReceiverBaseRoomInputDto { + externalInviterId: string; + normalizedInviterId: string; + externalRoomName?: string; + roomType?: RoomType; + wasInternallyProgramaticallyCreated?: boolean; + internalRoomId?: string; +} + +export interface IFederationChangeMembershipInputDto extends IFederationReceiverBaseRoomInputDto { + externalInviterId: string; + normalizedInviterId: string; + externalInviteeId: string; + normalizedInviteeId: string; + inviteeUsernameOnly: string; + inviterUsernameOnly: string; + eventOrigin: EVENT_ORIGIN; + leave?: boolean; + roomType?: RoomType; + externalRoomName?: string; + userProfile?: { + avatarUrl?: string; + displayName?: string; + }; + allInviteesExternalIdsWhenDM?: { + externalInviteeId: string; + normalizedInviteeId: string; + inviteeUsernameOnly: string; + }[]; +} + +export interface IFederationSendInternalMessageInputDto extends IFederationReceiverBaseRoomInputDto { + externalSenderId: string; + normalizedSenderId: string; + rawMessage: string; + externalFormattedText: string; + replyToEventId?: string; +} + +export interface IFederationRoomChangeJoinRulesDtoInputDto extends IFederationReceiverBaseRoomInputDto { + roomType: RoomType; +} + +export interface IFederationRoomNameChangeInputDto extends IFederationReceiverBaseRoomInputDto { + normalizedRoomName: string; + externalSenderId: string; +} + +export interface IFederationRoomTopicChangeInputDto extends IFederationReceiverBaseRoomInputDto { + roomTopic: string; + externalSenderId: string; +} + +export interface IFederationRoomRedactEventInputDto extends IFederationReceiverBaseRoomInputDto { + redactsEvent: string; + externalSenderId: string; +} +export interface IFederationRoomChangePowerLevelsInputDto extends IFederationReceiverBaseRoomInputDto { + roleChangesToApply: IExternalRolesChangesToApplyInputDto; + externalSenderId: string; +} + +export interface IFederationSendInternalMessageBaseInputDto extends IFederationReceiverBaseRoomInputDto { + externalSenderId: string; + normalizedSenderId: string; +} + +abstract class FederationBaseDto { + constructor({ externalEventId }: { externalEventId: string }) { + this.externalEventId = externalEventId; + } + + externalEventId: string; +} + +export class FederationBaseRoomInputDto extends FederationBaseDto { + constructor({ externalRoomId, normalizedRoomId, externalEventId }: IFederationReceiverBaseRoomInputDto) { + super({ externalEventId }); + this.externalRoomId = externalRoomId; + this.normalizedRoomId = normalizedRoomId; + } + + externalRoomId: string; + + normalizedRoomId: string; +} + +export class FederationRoomCreateInputDto extends FederationBaseRoomInputDto { + constructor({ + externalRoomId, + normalizedRoomId, + externalInviterId, + normalizedInviterId, + wasInternallyProgramaticallyCreated, + roomType, + externalRoomName, + internalRoomId, + externalEventId, + }: IFederationCreateInputDto) { + super({ externalRoomId, normalizedRoomId, externalEventId }); + this.externalInviterId = externalInviterId; + this.normalizedInviterId = normalizedInviterId; + this.wasInternallyProgramaticallyCreated = wasInternallyProgramaticallyCreated; + this.roomType = roomType; + this.externalRoomName = externalRoomName; + this.internalRoomId = internalRoomId; + } + + externalInviterId: string; + + normalizedInviterId: string; + + wasInternallyProgramaticallyCreated?: boolean; + + internalRoomId?: string; + + externalRoomName?: string; + + roomType?: RoomType; +} + +export class FederationRoomChangeMembershipDto extends FederationBaseRoomInputDto { + constructor({ + externalRoomId, + normalizedRoomId, + externalInviterId, + normalizedInviterId, + externalInviteeId, + normalizedInviteeId, + inviteeUsernameOnly, + inviterUsernameOnly, + eventOrigin, + leave, + roomType, + externalRoomName, + externalEventId, + userProfile, + allInviteesExternalIdsWhenDM = [], + }: IFederationChangeMembershipInputDto) { + super({ externalRoomId, normalizedRoomId, externalEventId }); + this.externalInviterId = externalInviterId; + this.normalizedInviterId = normalizedInviterId; + this.externalInviteeId = externalInviteeId; + this.normalizedInviteeId = normalizedInviteeId; + this.inviteeUsernameOnly = inviteeUsernameOnly; + this.inviterUsernameOnly = inviterUsernameOnly; + this.eventOrigin = eventOrigin; + this.leave = leave; + this.roomType = roomType; + this.externalRoomName = externalRoomName; + this.userProfile = userProfile; + this.allInviteesExternalIdsWhenDM = allInviteesExternalIdsWhenDM; + } + + externalInviterId: string; + + normalizedInviterId: string; + + inviterUsernameOnly: string; + + externalInviteeId: string; + + normalizedInviteeId: string; + + inviteeUsernameOnly: string; + + eventOrigin: EVENT_ORIGIN; + + roomType?: RoomType; + + leave?: boolean; + + externalRoomName?: string; + + allInviteesExternalIdsWhenDM?: { + externalInviteeId: string; + normalizedInviteeId: string; + inviteeUsernameOnly: string; + }[]; + + userProfile?: { avatarUrl?: string; displayName?: string }; +} + +class ExternalMessageBaseDto extends FederationBaseRoomInputDto { + constructor({ externalRoomId, normalizedRoomId, externalSenderId, normalizedSenderId, externalEventId }: Record) { + super({ externalRoomId, normalizedRoomId, externalEventId }); + this.externalSenderId = externalSenderId; + this.normalizedSenderId = normalizedSenderId; + } + + externalSenderId: string; + + normalizedSenderId: string; +} + +export class FederationRoomReceiveExternalMessageDto extends ExternalMessageBaseDto { + constructor({ + externalRoomId, + normalizedRoomId, + externalSenderId, + normalizedSenderId, + externalFormattedText, + rawMessage, + externalEventId, + replyToEventId, + }: IFederationSendInternalMessageInputDto) { + super({ externalRoomId, normalizedRoomId }); + this.externalSenderId = externalSenderId; + this.normalizedSenderId = normalizedSenderId; + this.externalFormattedText = externalFormattedText; + this.rawMessage = rawMessage; + this.replyToEventId = replyToEventId; + this.externalEventId = externalEventId; + } + + externalSenderId: string; + + normalizedSenderId: string; + + externalFormattedText: string; + + rawMessage: string; + + replyToEventId?: string; +} + +export class FederationRoomEditExternalMessageDto extends ExternalMessageBaseDto { + constructor({ + externalRoomId, + normalizedRoomId, + externalSenderId, + normalizedSenderId, + newRawMessage, + newExternalFormattedText, + editsEvent, + externalEventId, + }: IFederationSendInternalMessageBaseInputDto & { + newRawMessage: string; + newExternalFormattedText: string; + editsEvent: string; + }) { + super({ externalRoomId, normalizedRoomId, externalEventId }); + this.externalSenderId = externalSenderId; + this.normalizedSenderId = normalizedSenderId; + this.newRawMessage = newRawMessage; + this.newExternalFormattedText = newExternalFormattedText; + this.editsEvent = editsEvent; + } + + externalSenderId: string; + + normalizedSenderId: string; + + newExternalFormattedText: string; + + newRawMessage: string; + + editsEvent: string; +} + +export interface IFederationFileMessageInputDto { + filename: string; + mimetype: string; + size: number; + messageText: string; + url: string; + replyToEventId?: string; +} + +class FederationFileMessageInputDto { + constructor({ filename, mimetype, size, messageText, url }: IFederationFileMessageInputDto) { + this.filename = filename; + this.mimetype = mimetype; + this.size = size; + this.messageText = messageText; + this.url = url; + } + + filename: string; + + mimetype: string; + + size: number; + + messageText: string; + + url: string; +} + +export class FederationRoomReceiveExternalFileMessageDto extends ExternalMessageBaseDto { + constructor({ + externalRoomId, + normalizedRoomId, + externalSenderId, + normalizedSenderId, + filename, + mimetype, + size, + messageText, + url, + externalEventId, + replyToEventId, + }: IFederationSendInternalMessageBaseInputDto & IFederationFileMessageInputDto) { + super({ externalRoomId, normalizedRoomId, externalEventId }); + this.externalSenderId = externalSenderId; + this.normalizedSenderId = normalizedSenderId; + this.replyToEventId = replyToEventId; + this.messageBody = new FederationFileMessageInputDto({ filename, mimetype, size, messageText, url }); + } + + externalSenderId: string; + + normalizedSenderId: string; + + messageBody: FederationFileMessageInputDto; + + replyToEventId?: string; +} + +export class FederationRoomChangeJoinRulesDto extends FederationBaseRoomInputDto { + constructor({ externalRoomId, normalizedRoomId, roomType, externalEventId }: IFederationRoomChangeJoinRulesDtoInputDto) { + super({ externalRoomId, normalizedRoomId, externalEventId }); + this.roomType = roomType; + } + + roomType: RoomType; +} + +export class FederationRoomChangeNameDto extends FederationBaseRoomInputDto { + constructor({ + externalRoomId, + normalizedRoomId, + normalizedRoomName, + externalSenderId, + externalEventId, + }: IFederationRoomNameChangeInputDto) { + super({ externalRoomId, normalizedRoomId, externalEventId }); + this.normalizedRoomName = normalizedRoomName; + this.externalSenderId = externalSenderId; + } + + normalizedRoomName: string; + + externalSenderId: string; +} + +export class FederationRoomChangeTopicDto extends FederationBaseRoomInputDto { + constructor({ externalRoomId, normalizedRoomId, roomTopic, externalSenderId, externalEventId }: IFederationRoomTopicChangeInputDto) { + super({ externalRoomId, normalizedRoomId, externalEventId }); + this.roomTopic = roomTopic; + this.externalSenderId = externalSenderId; + } + + roomTopic: string; + + externalSenderId: string; +} + +export class FederationRoomRedactEventDto extends FederationBaseRoomInputDto { + constructor({ externalRoomId, normalizedRoomId, externalEventId, redactsEvent, externalSenderId }: IFederationRoomRedactEventInputDto) { + super({ externalRoomId, normalizedRoomId, externalEventId }); + this.redactsEvent = redactsEvent; + this.externalSenderId = externalSenderId; + } + + redactsEvent: string; + + externalSenderId: string; +} + +export interface IExternalRolesChangesToApplyInputDto { + [key: string]: { action: string; role: ROCKET_CHAT_FEDERATION_ROLES }[]; +} +export class FederationRoomRoomChangePowerLevelsEventDto extends FederationBaseRoomInputDto { + constructor({ + externalRoomId, + normalizedRoomId, + externalEventId, + roleChangesToApply, + externalSenderId, + }: IFederationRoomChangePowerLevelsInputDto) { + super({ externalRoomId, normalizedRoomId, externalEventId }); + this.roleChangesToApply = roleChangesToApply; + this.externalSenderId = externalSenderId; + } + + roleChangesToApply: IExternalRolesChangesToApplyInputDto; + + externalSenderId: string; +} diff --git a/apps/meteor/app/federation-v2/server/application/listener/input/UserReceiverDto.ts b/apps/meteor/app/federation-v2/server/application/listener/input/UserReceiverDto.ts new file mode 100644 index 0000000000000..221bf5aca63e4 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/application/listener/input/UserReceiverDto.ts @@ -0,0 +1,17 @@ +import type { IFederationReceiverBaseRoomInputDto } from './RoomReceiverDto'; +import { FederationBaseRoomInputDto } from './RoomReceiverDto'; + +interface IFederationUserTypingStatusInputDto extends IFederationReceiverBaseRoomInputDto { + externalUserIdsTyping: string[]; +} + +export class FederationUserTypingStatusEventDto extends FederationBaseRoomInputDto { + constructor({ externalRoomId, normalizedRoomId, externalUserIdsTyping }: IFederationUserTypingStatusInputDto) { + super({ externalRoomId, normalizedRoomId, externalEventId: '' }); + this.externalRoomId = externalRoomId; + this.normalizedRoomId = normalizedRoomId; + this.externalUserIdsTyping = externalUserIdsTyping; + } + + externalUserIdsTyping: string[]; +} diff --git a/apps/meteor/app/federation-v2/server/application/sender/MessageSenders.ts b/apps/meteor/app/federation-v2/server/application/sender/MessageSenders.ts new file mode 100644 index 0000000000000..78484c74d9c82 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/application/sender/MessageSenders.ts @@ -0,0 +1,119 @@ +import type { IMessage } from '@rocket.chat/core-typings'; + +import type { IFederationBridge } from '../../domain/IFederationBridge'; +import type { RocketChatFileAdapter } from '../../infrastructure/rocket-chat/adapters/File'; +import type { RocketChatMessageAdapter } from '../../infrastructure/rocket-chat/adapters/Message'; +import type { RocketChatUserAdapter } from '../../infrastructure/rocket-chat/adapters/User'; + +export interface IExternalMessageSender { + sendMessage(externalRoomId: string, externalSenderId: string, message: IMessage): Promise; + sendQuoteMessage(externalRoomId: string, externalSenderId: string, message: IMessage, messageToReplyTo: IMessage): Promise; +} + +class TextExternalMessageSender implements IExternalMessageSender { + constructor( + private readonly bridge: IFederationBridge, + private readonly internalMessageAdapter: RocketChatMessageAdapter, + private readonly internalUserAdapter: RocketChatUserAdapter, + ) {} + + public async sendMessage(externalRoomId: string, externalSenderId: string, message: IMessage): Promise { + const externalMessageId = await this.bridge.sendMessage(externalRoomId, externalSenderId, message); + + await this.internalMessageAdapter.setExternalFederationEventOnMessage(message._id, externalMessageId); + } + + public async sendQuoteMessage( + externalRoomId: string, + externalSenderId: string, + message: IMessage, + messageToReplyTo: IMessage, + ): Promise { + const originalSender = await this.internalUserAdapter.getFederatedUserByInternalId(messageToReplyTo?.u?._id); + const externalMessageId = await this.bridge.sendReplyToMessage( + externalRoomId, + externalSenderId, + messageToReplyTo.federation?.eventId as string, + originalSender?.getExternalId() as string, + message.msg, + ); + await this.internalMessageAdapter.setExternalFederationEventOnMessage(message._id, externalMessageId); + } +} + +class FileExternalMessageSender implements IExternalMessageSender { + constructor( + private readonly bridge: IFederationBridge, + private readonly internalFileHelper: RocketChatFileAdapter, + private readonly internalMessageAdapter: RocketChatMessageAdapter, + ) {} + + public async sendMessage(externalRoomId: string, externalSenderId: string, message: IMessage): Promise { + const file = await this.internalFileHelper.getFileRecordById((message.files || [])[0]?._id); + if (!file || !file.size || !file.type) { + return; + } + + const buffer = await this.internalFileHelper.getBufferFromFileRecord(file); + const metadata = await this.internalFileHelper.extractMetadataFromFile(file); + + const externalMessageId = await this.bridge.sendMessageFileToRoom(externalRoomId, externalSenderId, buffer, { + filename: file.name, + fileSize: file.size, + mimeType: file.type, + metadata: { + width: metadata?.width, + height: metadata?.height, + format: metadata?.format, + }, + }); + + await this.internalMessageAdapter.setExternalFederationEventOnMessage(message._id, externalMessageId); + } + + public async sendQuoteMessage( + externalRoomId: string, + externalSenderId: string, + message: IMessage, + messageToReplyTo: IMessage, + ): Promise { + const file = await this.internalFileHelper.getFileRecordById((message.files || [])[0]?._id); + if (!file || !file.size || !file.type) { + return; + } + + const buffer = await this.internalFileHelper.getBufferFromFileRecord(file); + const metadata = await this.internalFileHelper.extractMetadataFromFile(file); + + const externalMessageId = await this.bridge.sendReplyMessageFileToRoom( + externalRoomId, + externalSenderId, + buffer, + { + filename: file.name, + fileSize: file.size, + mimeType: file.type, + metadata: { + width: metadata?.width, + height: metadata?.height, + format: metadata?.format, + }, + }, + messageToReplyTo.federation?.eventId as string, + ); + + await this.internalMessageAdapter.setExternalFederationEventOnMessage(message._id, externalMessageId); + } +} + +export const getExternalMessageSender = ( + message: IMessage, + bridge: IFederationBridge, + internalFileHelper: RocketChatFileAdapter, + internalMessageAdapter: RocketChatMessageAdapter, + internalUserAdapter: RocketChatUserAdapter, +): IExternalMessageSender => { + return message.files + ? new FileExternalMessageSender(bridge, internalFileHelper, internalMessageAdapter) + : new TextExternalMessageSender(bridge, internalMessageAdapter, internalUserAdapter); +}; diff --git a/apps/meteor/app/federation-v2/server/application/sender/MessageServiceSender.ts b/apps/meteor/app/federation-v2/server/application/sender/MessageServiceSender.ts new file mode 100644 index 0000000000000..930a4e7df2ced --- /dev/null +++ b/apps/meteor/app/federation-v2/server/application/sender/MessageServiceSender.ts @@ -0,0 +1,98 @@ +import type { IMessage, IUser } from '@rocket.chat/core-typings'; +import { isMessageFromMatrixFederation } from '@rocket.chat/core-typings'; + +import { FederatedUser } from '../../domain/FederatedUser'; +import type { IFederationBridge } from '../../domain/IFederationBridge'; +import { Federation } from '../../Federation'; +import type { RocketChatMessageAdapter } from '../../infrastructure/rocket-chat/adapters/Message'; +import type { RocketChatRoomAdapter } from '../../infrastructure/rocket-chat/adapters/Room'; +import type { RocketChatSettingsAdapter } from '../../infrastructure/rocket-chat/adapters/Settings'; +import type { RocketChatUserAdapter } from '../../infrastructure/rocket-chat/adapters/User'; + +export class FederationMessageServiceSender { + constructor( + protected internalRoomAdapter: RocketChatRoomAdapter, + protected internalUserAdapter: RocketChatUserAdapter, + protected internalSettingsAdapter: RocketChatSettingsAdapter, + protected internalMessageAdapter: RocketChatMessageAdapter, + protected bridge: IFederationBridge, + ) {} + + public async sendExternalMessageReaction(internalMessage: IMessage, internalUser: IUser, reaction: string): Promise { + if (!internalMessage || !internalUser || !internalUser._id || !internalMessage.rid) { + return; + } + const federatedSender = await this.internalUserAdapter.getFederatedUserByInternalId(internalUser._id); + if (!federatedSender) { + return; + } + + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalMessage.rid); + if (!federatedRoom) { + return; + } + + if (!isMessageFromMatrixFederation(internalMessage)) { + return; + } + + const isUserFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(federatedSender.getExternalId()), + this.internalSettingsAdapter.getHomeServerDomain(), + ); + if (!isUserFromTheSameHomeServer) { + return; + } + + const eventId = await this.bridge.sendMessageReaction( + federatedRoom.getExternalId(), + federatedSender.getExternalId(), + internalMessage.federation?.eventId as string, + reaction, + ); + federatedSender.getUsername() && + (await this.internalMessageAdapter.setExternalFederationEventOnMessageReaction( + federatedSender.getUsername() as string, + internalMessage, + reaction, + eventId, + )); + } + + public async sendExternalMessageUnReaction(internalMessage: IMessage, internalUser: IUser, reaction: string): Promise { + if (!internalMessage || !internalUser || !internalUser._id || !internalMessage.rid) { + return; + } + const federatedSender = await this.internalUserAdapter.getFederatedUserByInternalId(internalUser._id); + if (!federatedSender) { + return; + } + + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalMessage.rid); + if (!federatedRoom) { + return; + } + + if (!isMessageFromMatrixFederation(internalMessage)) { + return; + } + + const isUserFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(federatedSender.getExternalId()), + this.internalSettingsAdapter.getHomeServerDomain(), + ); + if (!isUserFromTheSameHomeServer) { + return; + } + // TODO: leaked business logic, move this to the domain layer + const externalEventId = Object.keys(internalMessage.reactions?.[reaction].federationReactionEventIds || {}).find( + (key) => internalMessage.reactions?.[reaction].federationReactionEventIds?.[key] === internalUser.username, + ); + if (!externalEventId) { + return; + } + const normalizedEventId = Federation.unescapeExternalFederationEventId(externalEventId); + await this.bridge.redactEvent(federatedRoom.getExternalId(), federatedSender.getExternalId(), normalizedEventId); + await this.internalMessageAdapter.unsetExternalFederationEventOnMessageReaction(externalEventId, internalMessage, reaction); + } +} diff --git a/apps/meteor/app/federation-v2/server/application/sender/RoomInternalHooksValidator.ts b/apps/meteor/app/federation-v2/server/application/sender/RoomInternalHooksValidator.ts index f8ec436fb6f45..58f66763d782a 100644 --- a/apps/meteor/app/federation-v2/server/application/sender/RoomInternalHooksValidator.ts +++ b/apps/meteor/app/federation-v2/server/application/sender/RoomInternalHooksValidator.ts @@ -4,6 +4,7 @@ import { isDirectMessageRoom, isRoomFederated, isUserFederated } from '@rocket.c import { FederatedRoom } from '../../domain/FederatedRoom'; import { FederatedUser } from '../../domain/FederatedUser'; import type { IFederationBridge } from '../../domain/IFederationBridge'; +import type { RocketChatFileAdapter } from '../../infrastructure/rocket-chat/adapters/File'; import type { RocketChatRoomAdapter } from '../../infrastructure/rocket-chat/adapters/Room'; import type { RocketChatSettingsAdapter } from '../../infrastructure/rocket-chat/adapters/Settings'; import type { RocketChatUserAdapter } from '../../infrastructure/rocket-chat/adapters/User'; @@ -13,10 +14,11 @@ export class FederationRoomInternalHooksValidator extends FederationService { constructor( protected internalRoomAdapter: RocketChatRoomAdapter, protected internalUserAdapter: RocketChatUserAdapter, + protected internalFileAdapter: RocketChatFileAdapter, protected internalSettingsAdapter: RocketChatSettingsAdapter, protected bridge: IFederationBridge, ) { - super(bridge, internalUserAdapter, internalSettingsAdapter); + super(bridge, internalUserAdapter, internalFileAdapter, internalSettingsAdapter); } public async canAddFederatedUserToNonFederatedRoom(internalUser: IUser | string, internalRoom: IRoom): Promise { diff --git a/apps/meteor/app/federation-v2/server/application/sender/RoomServiceSender.ts b/apps/meteor/app/federation-v2/server/application/sender/RoomServiceSender.ts index 721ee5f651868..f118de8149bc9 100644 --- a/apps/meteor/app/federation-v2/server/application/sender/RoomServiceSender.ts +++ b/apps/meteor/app/federation-v2/server/application/sender/RoomServiceSender.ts @@ -1,8 +1,13 @@ -import type { IMessage } from '@rocket.chat/core-typings'; +import type { IMessage, MessageQuoteAttachment } from '@rocket.chat/core-typings'; +import { isDeletedMessage, isEditedMessage, isMessageFromMatrixFederation, isQuoteAttachment } from '@rocket.chat/core-typings'; +import type { FederatedRoom } from '../../domain/FederatedRoom'; import { DirectMessageFederatedRoom } from '../../domain/FederatedRoom'; import { FederatedUser } from '../../domain/FederatedUser'; import type { IFederationBridge } from '../../domain/IFederationBridge'; +import type { RocketChatFileAdapter } from '../../infrastructure/rocket-chat/adapters/File'; +import type { RocketChatMessageAdapter } from '../../infrastructure/rocket-chat/adapters/Message'; +import type { RocketChatNotificationAdapter } from '../../infrastructure/rocket-chat/adapters/Notification'; import type { RocketChatRoomAdapter } from '../../infrastructure/rocket-chat/adapters/Room'; import type { RocketChatSettingsAdapter } from '../../infrastructure/rocket-chat/adapters/Settings'; import type { RocketChatUserAdapter } from '../../infrastructure/rocket-chat/adapters/User'; @@ -12,16 +17,22 @@ import type { FederationAfterRemoveUserFromRoomDto, FederationCreateDMAndInviteUserDto, FederationRoomSendExternalMessageDto, -} from '../input/RoomSenderDto'; +} from './input/RoomSenderDto'; +import { getExternalMessageSender } from './MessageSenders'; +import { MATRIX_POWER_LEVELS } from '../../infrastructure/matrix/definitions/MatrixPowerLevels'; +import { ROCKET_CHAT_FEDERATION_ROLES } from '../../infrastructure/rocket-chat/definitions/InternalFederatedRoomRoles'; export class FederationRoomServiceSender extends FederationService { constructor( protected internalRoomAdapter: RocketChatRoomAdapter, protected internalUserAdapter: RocketChatUserAdapter, + protected internalFileAdapter: RocketChatFileAdapter, + protected internalMessageAdapter: RocketChatMessageAdapter, protected internalSettingsAdapter: RocketChatSettingsAdapter, + protected internalNotificationAdapter: RocketChatNotificationAdapter, protected bridge: IFederationBridge, ) { - super(bridge, internalUserAdapter, internalSettingsAdapter); + super(bridge, internalUserAdapter, internalFileAdapter, internalSettingsAdapter); } public async createDirectMessageRoomAndInviteUser(roomCreateDMAndInviteUserInput: FederationCreateDMAndInviteUserDto): Promise { @@ -29,13 +40,13 @@ export class FederationRoomServiceSender extends FederationService { const internalInviterUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalInviterId); if (!internalInviterUser) { - await this.createFederatedUserForInviterUsingLocalInformation(internalInviterId); + await this.createFederatedUserIncludingHomeserverUsingLocalInformation(internalInviterId); } const internalInviteeUser = await this.internalUserAdapter.getFederatedUserByInternalId(normalizedInviteeId); if (!internalInviteeUser) { const existsOnlyOnProxyServer = false; - await this.createFederatedUser(rawInviteeId, normalizedInviteeId, existsOnlyOnProxyServer); + await this.createFederatedUserInternallyOnly(rawInviteeId, normalizedInviteeId, existsOnlyOnProxyServer); } const federatedInviterUser = internalInviterUser || (await this.internalUserAdapter.getFederatedUserByInternalId(internalInviterId)); @@ -65,7 +76,11 @@ export class FederationRoomServiceSender extends FederationService { federatedInviterUser, federatedInviteeUser, ]); - await this.internalRoomAdapter.createFederatedRoomForDirectMessage(newFederatedRoom); + const createdInternalRoomId = await this.internalRoomAdapter.createFederatedRoomForDirectMessage(newFederatedRoom); + await this.internalNotificationAdapter.subscribeToUserTypingEventsOnFederatedRoomId( + createdInternalRoomId, + this.internalNotificationAdapter.broadcastUserTypingOnRoom.bind(this.internalNotificationAdapter), + ); } const federatedRoom = @@ -138,9 +153,8 @@ export class FederationRoomServiceSender extends FederationService { await this.bridge.kickUserFromRoom(federatedRoom.getExternalId(), federatedUser.getExternalId(), byWhom.getExternalId()); } - public async sendExternalMessage(roomSendExternalMessageInput: FederationRoomSendExternalMessageDto): Promise { + public async sendExternalMessage(roomSendExternalMessageInput: FederationRoomSendExternalMessageDto): Promise { const { internalRoomId, internalSenderId, message } = roomSendExternalMessageInput; - const federatedSender = await this.internalUserAdapter.getFederatedUserByInternalId(internalSenderId); if (!federatedSender) { throw new Error(`Could not find user id for ${internalSenderId}`); @@ -151,8 +165,300 @@ export class FederationRoomServiceSender extends FederationService { throw new Error(`Could not find room id for ${internalRoomId}`); } - await this.bridge.sendMessage(federatedRoom.getExternalId(), federatedSender.getExternalId(), message.msg); + if (message.federation?.eventId) { + return; + } + + if (message.attachments?.some((attachment) => isQuoteAttachment(attachment) && Boolean(attachment.message_link))) { + // TODO: move this to the domain layer in a proper entity + const messageLink = ( + message.attachments.find( + (attachment) => isQuoteAttachment(attachment) && Boolean(attachment.message_link), + ) as MessageQuoteAttachment + ).message_link; + if (!messageLink) { + return; + } + const messageToReplyToId = messageLink.includes('msg=') && messageLink?.split('msg=').pop(); + if (!messageToReplyToId) { + return; + } + const messageToReplyTo = await this.internalMessageAdapter.getMessageById(messageToReplyToId); + if (!messageToReplyTo) { + return; + } + + await getExternalMessageSender( + message, + this.bridge, + this.internalFileAdapter, + this.internalMessageAdapter, + this.internalUserAdapter, + ).sendQuoteMessage(federatedRoom.getExternalId(), federatedSender.getExternalId(), message, messageToReplyTo); + return; + } + + await getExternalMessageSender( + message, + this.bridge, + this.internalFileAdapter, + this.internalMessageAdapter, + this.internalUserAdapter, + ).sendMessage(federatedRoom.getExternalId(), federatedSender.getExternalId(), message); + } + + public async afterMessageDeleted(internalMessage: IMessage, internalRoomId: string): Promise { + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalRoomId); + if (!federatedRoom) { + return; + } + + const federatedUser = internalMessage.u?._id && (await this.internalUserAdapter.getFederatedUserByInternalId(internalMessage.u._id)); + if (!federatedUser) { + return; + } + + if (!isMessageFromMatrixFederation(internalMessage) || isDeletedMessage(internalMessage)) { + return; + } + + const isUserFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(federatedUser.getExternalId()), + this.internalSettingsAdapter.getHomeServerDomain(), + ); + if (!isUserFromTheSameHomeServer) { + return; + } + + await this.bridge.redactEvent( + federatedRoom.getExternalId(), + federatedUser.getExternalId(), + internalMessage.federation?.eventId as string, + ); + } + + public async afterMessageUpdated(internalMessage: IMessage, internalRoomId: string, internalUserId: string): Promise { + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalRoomId); + if (!federatedRoom) { + return; + } - return message; // this need to be here due to a limitation in the internal API that was expecting the return of the sendMessage function. + const federatedUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalUserId); + if (!federatedUser) { + return; + } + if (!isMessageFromMatrixFederation(internalMessage) || !isEditedMessage(internalMessage) || internalMessage.u._id !== internalUserId) { + return; + } + + const isUserFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(federatedUser.getExternalId()), + this.internalSettingsAdapter.getHomeServerDomain(), + ); + if (!isUserFromTheSameHomeServer) { + return; + } + + await this.bridge.updateMessage( + federatedRoom.getExternalId(), + federatedUser.getExternalId(), + internalMessage.federation?.eventId as string, + internalMessage.msg, + ); + } + + public async onRoomOwnerAdded(internalUserId: string, internalTargetUserId: string, internalRoomId: string): Promise { + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalRoomId); + if (!federatedRoom) { + return; + } + + const federatedUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalUserId); + if (!federatedUser) { + return; + } + + const federatedTargetUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalTargetUserId); + if (!federatedTargetUser) { + return; + } + + const userRoomRoles = await this.internalRoomAdapter.getInternalRoomRolesByUserId(internalRoomId, internalUserId); + const myself = federatedUser.getInternalId() === federatedTargetUser.getInternalId(); + if (!userRoomRoles?.includes(ROCKET_CHAT_FEDERATION_ROLES.OWNER) && !myself) { + throw new Error('Federation_Matrix_not_allowed_to_change_owner'); + } + + const isUserFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(federatedUser.getExternalId()), + this.internalSettingsAdapter.getHomeServerDomain(), + ); + if (!isUserFromTheSameHomeServer) { + return; + } + try { + await this.bridge.setRoomPowerLevels( + federatedRoom.getExternalId(), + federatedUser.getExternalId(), + federatedTargetUser.getExternalId(), + MATRIX_POWER_LEVELS.ADMIN, + ); + } catch (e) { + await this.rollbackRoomRoles(federatedRoom, federatedTargetUser, federatedUser, [], [ROCKET_CHAT_FEDERATION_ROLES.OWNER]); + } + } + + public async onRoomOwnerRemoved(internalUserId: string, internalTargetUserId: string, internalRoomId: string): Promise { + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalRoomId); + if (!federatedRoom) { + return; + } + + const federatedUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalUserId); + if (!federatedUser) { + return; + } + + const federatedTargetUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalTargetUserId); + if (!federatedTargetUser) { + return; + } + + const userRoomRoles = await this.internalRoomAdapter.getInternalRoomRolesByUserId(internalRoomId, internalUserId); + const myself = federatedUser.getInternalId() === federatedTargetUser.getInternalId(); + if (!userRoomRoles?.includes(ROCKET_CHAT_FEDERATION_ROLES.OWNER) && !myself) { + throw new Error('Federation_Matrix_not_allowed_to_change_owner'); + } + + const isUserFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(federatedUser.getExternalId()), + this.internalSettingsAdapter.getHomeServerDomain(), + ); + if (!isUserFromTheSameHomeServer) { + return; + } + try { + await this.bridge.setRoomPowerLevels( + federatedRoom.getExternalId(), + federatedUser.getExternalId(), + federatedTargetUser.getExternalId(), + MATRIX_POWER_LEVELS.USER, + ); + } catch (e) { + await this.rollbackRoomRoles(federatedRoom, federatedTargetUser, federatedUser, [ROCKET_CHAT_FEDERATION_ROLES.OWNER], []); + } + } + + public async onRoomModeratorAdded(internalUserId: string, internalTargetUserId: string, internalRoomId: string): Promise { + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalRoomId); + if (!federatedRoom) { + return; + } + + const federatedUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalUserId); + if (!federatedUser) { + return; + } + const federatedTargetUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalTargetUserId); + if (!federatedTargetUser) { + return; + } + + const userRoomRoles = await this.internalRoomAdapter.getInternalRoomRolesByUserId(internalRoomId, internalUserId); + const myself = federatedUser.getInternalId() === federatedTargetUser.getInternalId(); + if ( + !userRoomRoles?.includes(ROCKET_CHAT_FEDERATION_ROLES.OWNER) && + !userRoomRoles?.includes(ROCKET_CHAT_FEDERATION_ROLES.MODERATOR) && + !myself + ) { + throw new Error('Federation_Matrix_not_allowed_to_change_moderator'); + } + + const isUserFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(federatedUser.getExternalId()), + this.internalSettingsAdapter.getHomeServerDomain(), + ); + if (!isUserFromTheSameHomeServer) { + return; + } + + try { + await this.bridge.setRoomPowerLevels( + federatedRoom.getExternalId(), + federatedUser.getExternalId(), + federatedTargetUser.getExternalId(), + MATRIX_POWER_LEVELS.MODERATOR, + ); + } catch (e) { + await this.rollbackRoomRoles(federatedRoom, federatedTargetUser, federatedUser, [], [ROCKET_CHAT_FEDERATION_ROLES.MODERATOR]); + } + } + + public async onRoomModeratorRemoved(internalUserId: string, internalTargetUserId: string, internalRoomId: string): Promise { + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalRoomId); + if (!federatedRoom) { + return; + } + + const federatedUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalUserId); + if (!federatedUser) { + return; + } + + const federatedTargetUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalTargetUserId); + if (!federatedTargetUser) { + return; + } + + const userRoomRoles = await this.internalRoomAdapter.getInternalRoomRolesByUserId(internalRoomId, internalUserId); + const myself = federatedUser.getInternalId() === federatedTargetUser.getInternalId(); + if ( + !userRoomRoles?.includes(ROCKET_CHAT_FEDERATION_ROLES.OWNER) && + !userRoomRoles?.includes(ROCKET_CHAT_FEDERATION_ROLES.MODERATOR) && + !myself + ) { + throw new Error('Federation_Matrix_not_allowed_to_change_moderator'); + } + + const isUserFromTheSameHomeServer = FederatedUser.isOriginalFromTheProxyServer( + this.bridge.extractHomeserverOrigin(federatedUser.getExternalId()), + this.internalSettingsAdapter.getHomeServerDomain(), + ); + if (!isUserFromTheSameHomeServer) { + return; + } + + try { + await this.bridge.setRoomPowerLevels( + federatedRoom.getExternalId(), + federatedUser.getExternalId(), + federatedTargetUser.getExternalId(), + MATRIX_POWER_LEVELS.USER, + ); + } catch (e) { + await this.rollbackRoomRoles(federatedRoom, federatedTargetUser, federatedUser, [ROCKET_CHAT_FEDERATION_ROLES.MODERATOR], []); + } + } + + private async rollbackRoomRoles( + federatedRoom: FederatedRoom, + targetFederatedUser: FederatedUser, + fromUser: FederatedUser, + rolesToAdd: ROCKET_CHAT_FEDERATION_ROLES[], + rolesToRemove: ROCKET_CHAT_FEDERATION_ROLES[], + ): Promise { + await this.internalRoomAdapter.applyRoomRolesToUser({ + federatedRoom, + targetFederatedUser, + fromUser, + rolesToAdd, + rolesToRemove, + notifyChannel: false, + }); + this.internalNotificationAdapter.notifyWithEphemeralMessage( + 'Federation_Matrix_error_applying_room_roles', + fromUser.getInternalId(), + federatedRoom.getInternalId(), + ); } } diff --git a/apps/meteor/app/federation-v2/server/application/sender/UserServiceSender.ts b/apps/meteor/app/federation-v2/server/application/sender/UserServiceSender.ts new file mode 100644 index 0000000000000..540d202a46086 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/application/sender/UserServiceSender.ts @@ -0,0 +1,75 @@ +import type { IFederationBridge } from '../../domain/IFederationBridge'; +import type { RocketChatFileAdapter } from '../../infrastructure/rocket-chat/adapters/File'; +import type { RocketChatRoomAdapter } from '../../infrastructure/rocket-chat/adapters/Room'; +import type { RocketChatSettingsAdapter } from '../../infrastructure/rocket-chat/adapters/Settings'; +import type { RocketChatUserAdapter } from '../../infrastructure/rocket-chat/adapters/User'; +import { FederationService } from '../AbstractFederationService'; + +export class FederationUserServiceSender extends FederationService { + constructor( + protected internalRoomAdapter: RocketChatRoomAdapter, + protected internalUserAdapter: RocketChatUserAdapter, + protected internalFileAdapter: RocketChatFileAdapter, + protected internalSettingsAdapter: RocketChatSettingsAdapter, + protected bridge: IFederationBridge, + ) { + super(bridge, internalUserAdapter, internalFileAdapter, internalSettingsAdapter); + } + + public async afterUserAvatarChanged(internalUsername: string): Promise { + const federatedUser = await this.internalUserAdapter.getFederatedUserByInternalUsername(internalUsername); + if (!federatedUser) { + const internalUser = await this.internalUserAdapter.getInternalUserByUsername(internalUsername); + if (!internalUser) { + return; + } + await this.createFederatedUserIncludingHomeserverUsingLocalInformation(internalUser._id); + return; + } + + if (federatedUser.isRemote()) { + return; + } + + await this.updateUserAvatarExternally(federatedUser.getInternalReference(), federatedUser); + } + + public async afterUserRealNameChanged(internalUserId: string, name: string): Promise { + const federatedUser = await this.internalUserAdapter.getFederatedUserByInternalId(internalUserId); + if (!federatedUser) { + const internalUser = await this.internalUserAdapter.getInternalUserById(internalUserId); + if (!internalUser) { + return; + } + await this.createFederatedUserIncludingHomeserverUsingLocalInformation(internalUser._id); + return; + } + + if (federatedUser.isRemote()) { + return; + } + const externalUserProfileInformation = await this.bridge.getUserProfileInformation(federatedUser.getExternalId()); + if (!federatedUser.shouldUpdateDisplayName(externalUserProfileInformation?.displayName || '')) { + return; + } + + await this.bridge.setUserDisplayName(federatedUser.getExternalId(), name); + } + + public async onUserTyping(internalUsername: string, internalRoomId: string, isTyping: boolean): Promise { + if (!this.internalSettingsAdapter.isTypingStatusEnabled()) { + return; + } + const federatedUser = await this.internalUserAdapter.getFederatedUserByInternalUsername(internalUsername); + if (!federatedUser) { + return; + } + + const federatedRoom = await this.internalRoomAdapter.getFederatedRoomByInternalId(internalRoomId); + if (!federatedRoom) { + return; + } + + await this.bridge.notifyUserTyping(federatedRoom.getExternalId(), federatedUser.getExternalId(), isTyping); + } +} diff --git a/apps/meteor/app/federation-v2/server/application/input/RoomSenderDto.ts b/apps/meteor/app/federation-v2/server/application/sender/input/RoomSenderDto.ts similarity index 100% rename from apps/meteor/app/federation-v2/server/application/input/RoomSenderDto.ts rename to apps/meteor/app/federation-v2/server/application/sender/input/RoomSenderDto.ts diff --git a/apps/meteor/app/federation-v2/server/domain/FederatedRoom.ts b/apps/meteor/app/federation-v2/server/domain/FederatedRoom.ts index 5a740830ddf4c..e4c4cbdc4a6d5 100644 --- a/apps/meteor/app/federation-v2/server/domain/FederatedRoom.ts +++ b/apps/meteor/app/federation-v2/server/domain/FederatedRoom.ts @@ -1,5 +1,5 @@ import { RoomType } from '@rocket.chat/apps-engine/definition/rooms'; -import type { IRoom } from '@rocket.chat/core-typings'; +import type { IMessage, IRoom } from '@rocket.chat/core-typings'; import { ObjectId } from 'mongodb'; // This should not be in the domain layer, but its a known "problem" import type { FederatedUser } from './FederatedUser'; @@ -39,8 +39,12 @@ export abstract class AbstractFederatedRoom { return this.internalId; } + public getDisplayName(): string | undefined { + return this.internalReference.fname; + } + public getName(): string | undefined { - return this.internalReference.fname || this.internalReference.name; + return this.internalReference.name; } public getTopic(): string | undefined { @@ -62,6 +66,10 @@ export abstract class AbstractFederatedRoom { return this.internalReference.u?.username; } + public isTheCreator(userId: string): boolean { + return this.internalReference.u?._id === userId; + } + public getCreatorId(): string | undefined { return this.internalReference.u?._id; } @@ -73,12 +81,18 @@ export abstract class AbstractFederatedRoom { this.internalReference.t = type; } + public changeDisplayRoomName(displayName: string): void { + if (this.isDirectMessage()) { + throw new Error('Its not possible to change a direct message name'); + } + this.internalReference.fname = displayName; + } + public changeRoomName(name: string): void { if (this.isDirectMessage()) { throw new Error('Its not possible to change a direct message name'); } this.internalReference.name = name; - this.internalReference.fname = name; } public changeRoomTopic(topic: string): void { @@ -88,13 +102,17 @@ export abstract class AbstractFederatedRoom { this.internalReference.topic = topic; } - public shouldUpdateRoomName(aRoomName: string): boolean { - return this.internalReference?.name !== aRoomName && !this.isDirectMessage(); + public shouldUpdateDisplayRoomName(aRoomName: string): boolean { + return this.internalReference?.fname !== aRoomName && !this.isDirectMessage(); } public shouldUpdateRoomTopic(aRoomTopic: string): boolean { return this.internalReference?.topic !== aRoomTopic && !this.isDirectMessage(); } + + public static shouldUpdateMessage(newMessageText: string, originalMessage: IMessage): boolean { + return originalMessage.msg !== newMessageText; + } } export class FederatedRoom extends AbstractFederatedRoom { @@ -107,18 +125,19 @@ export class FederatedRoom extends AbstractFederatedRoom { normalizedExternalId: string, creator: FederatedUser, type: RoomType, + displayName?: string, name?: string, ): FederatedRoom { if (type === RoomType.DIRECT_MESSAGE) { throw new Error('For DMs please use the specific class'); } - const roomName = name || FederatedRoom.generateTemporaryName(normalizedExternalId); + const roomName = displayName || FederatedRoom.generateTemporaryName(normalizedExternalId); return new FederatedRoom({ externalId, internalReference: { t: type, - name: roomName, fname: roomName, + name, u: creator.getInternalReference(), }, }); diff --git a/apps/meteor/app/federation-v2/server/domain/FederatedUser.ts b/apps/meteor/app/federation-v2/server/domain/FederatedUser.ts index 3506965fc8823..0d99c349aae86 100644 --- a/apps/meteor/app/federation-v2/server/domain/FederatedUser.ts +++ b/apps/meteor/app/federation-v2/server/domain/FederatedUser.ts @@ -106,6 +106,14 @@ export class FederatedUser { return !this.existsOnlyOnProxyServer; } + public shouldUpdateFederationAvatar(federationAvatarUrl: string): boolean { + return this.internalReference.federation?.avatarUrl !== federationAvatarUrl; + } + + public shouldUpdateDisplayName(displayName: string): boolean { + return this.internalReference.name !== displayName; + } + public getInternalId(): string { return this.internalId; } diff --git a/apps/meteor/app/federation-v2/server/domain/IFederationBridge.ts b/apps/meteor/app/federation-v2/server/domain/IFederationBridge.ts index da62c804cb4db..99a5ae2321f84 100644 --- a/apps/meteor/app/federation-v2/server/domain/IFederationBridge.ts +++ b/apps/meteor/app/federation-v2/server/domain/IFederationBridge.ts @@ -1,5 +1,8 @@ +import type { IMessage } from '@rocket.chat/core-typings'; + export interface IExternalUserProfileInformation { displayName: string; + avatarUrl?: string; } export enum EVENT_ORIGIN { @@ -7,20 +10,80 @@ export enum EVENT_ORIGIN { REMOTE = 'REMOTE', } +interface IRegistrationFileNamespaceRule { + exclusive: boolean; + regex: string; +} + +interface IRegistrationFileNamespaces { + users: IRegistrationFileNamespaceRule[]; + rooms: IRegistrationFileNamespaceRule[]; + aliases: IRegistrationFileNamespaceRule[]; +} + +export interface IFederationBridgeRegistrationFile { + id: string; + homeserverToken: string; + applicationServiceToken: string; + bridgeUrl: string; + botName: string; + listenTo: IRegistrationFileNamespaces; + enableEphemeralEvents: boolean; +} + export interface IFederationBridge { start(): Promise; stop(): Promise; - onFederationAvailabilityChanged(enabled: boolean): Promise; + onFederationAvailabilityChanged( + enabled: boolean, + appServiceId: string, + homeServerUrl: string, + homeServerDomain: string, + bridgeUrl: string, + bridgePort: number, + homeServerRegistrationFile: IFederationBridgeRegistrationFile, + ): Promise; getUserProfileInformation(externalUserId: string): Promise; - joinRoom(externalRoomId: string, externalUserId: string): Promise; - createDirectMessageRoom(externalCreatorId: string, externalInviteeIds: string[], extraData?: Record): Promise; + joinRoom(externalRoomId: string, externalUserId: string, viaServers?: string[]): Promise; + createDirectMessageRoom(externalCreatorId: string, inviteesExternalIds: string[], extraData?: Record): Promise; inviteToRoom(externalRoomId: string, externalInviterId: string, externalInviteeId: string): Promise; - sendMessage(externalRoomId: string, externaSenderId: string, text: string): Promise; - createUser(username: string, name: string, domain: string): Promise; + sendMessage(externalRoomId: string, externalSenderId: string, message: IMessage): Promise; + createUser(username: string, name: string, domain: string, avatarUrl?: string): Promise; isUserIdFromTheSameHomeserver(externalUserId: string, domain: string): boolean; extractHomeserverOrigin(externalUserId: string): string; isRoomFromTheSameHomeserver(externalRoomId: string, domain: string): boolean; leaveRoom(externalRoomId: string, externalUserId: string): Promise; kickUserFromRoom(externalRoomId: string, externalUserId: string, externalOwnerId: string): Promise; logFederationStartupInfo(info?: string): void; + setUserAvatar(externalUserId: string, avatarUrl: string): Promise; + getReadStreamForFileFromUrl(externaUserId: string, fileUrl: string): Promise; + redactEvent(externalRoomId: string, externalUserId: string, externalEventId: string): Promise; + updateMessage(externalRoomId: string, externalUserId: string, externalEventId: string, newMessageText: string): Promise; + sendMessageReaction(externalRoomId: string, externalUserId: string, externalEventId: string, reaction: string): Promise; + sendMessageFileToRoom( + externalRoomId: string, + externaSenderId: string, + content: Buffer, + fileDetails: { filename: string; fileSize: number; mimeType: string; metadata?: { width?: number; height?: number; format?: string } }, + ): Promise; + uploadContent(externalSenderId: string, content: Buffer, options?: { name?: string; type?: string }): Promise; + convertMatrixUrlToHttp(externalUserId: string, matrixUrl: string): string; + sendReplyToMessage( + externalRoomId: string, + externalUserId: string, + eventToReplyTo: string, + eventOriginalSender: string, + message: string, + ): Promise; + sendReplyMessageFileToRoom( + externalRoomId: string, + externaSenderId: string, + content: Buffer, + fileDetails: { filename: string; fileSize: number; mimeType: string; metadata?: { width?: number; height?: number; format?: string } }, + eventToReplyTo: string, + ): Promise; + notifyUserTyping(externalRoomId: string, externalUserId: string, isTyping: boolean): Promise; + setUserDisplayName(externalUserId: string, displayName: string): Promise; + setRoomPowerLevels(externalRoomId: string, externalOwnerId: string, externalUserId: string, powerLevels: number): Promise; + getRoomHistoricalJoinEvents(externalRoomId: string, externalUserId: string, excludingUserIds?: string[]): Promise; } diff --git a/apps/meteor/app/federation-v2/server/index.ts b/apps/meteor/app/federation-v2/server/index.ts index c73d09a316774..dedbc9abf457e 100644 --- a/apps/meteor/app/federation-v2/server/index.ts +++ b/apps/meteor/app/federation-v2/server/index.ts @@ -1,58 +1,152 @@ +import type { FederationRoomServiceSender } from './application/sender/RoomServiceSender'; +import type { IFederationBridgeRegistrationFile } from './domain/IFederationBridge'; import { FederationFactory } from './infrastructure/Factory'; export const FEDERATION_PROCESSING_CONCURRENCY = 1; export const rocketSettingsAdapter = FederationFactory.buildRocketSettingsAdapter(); -export const queueInstance = FederationFactory.buildFederationQueue(); rocketSettingsAdapter.initialize(); export const federationQueueInstance = FederationFactory.buildFederationQueue(); +export const rocketFileAdapter = FederationFactory.buildRocketFileAdapter(); const federationBridge = FederationFactory.buildFederationBridge(rocketSettingsAdapter, federationQueueInstance); const rocketRoomAdapter = FederationFactory.buildRocketRoomAdapter(); const rocketUserAdapter = FederationFactory.buildRocketUserAdapter(); -const rocketMessageAdapter = FederationFactory.buildRocketMessageAdapter(); +export const rocketNotificationAdapter = FederationFactory.buildRocketNotificationAdapter(); +export const rocketMessageAdapter = FederationFactory.buildRocketMessageAdapter(); -const federationRoomServiceReceiver = FederationFactory.buildRoomServiceReceiver( +const federationRoomServiceListener = FederationFactory.buildRoomServiceListener( rocketRoomAdapter, rocketUserAdapter, rocketMessageAdapter, + rocketFileAdapter, rocketSettingsAdapter, + rocketNotificationAdapter, + federationQueueInstance, federationBridge, ); -const federationEventsHandler = FederationFactory.buildFederationEventHandler(federationRoomServiceReceiver, rocketSettingsAdapter); +const federationMessageServiceReceiver = FederationFactory.buildMessageServiceReceiver( + rocketRoomAdapter, + rocketUserAdapter, + rocketMessageAdapter, + rocketFileAdapter, + rocketSettingsAdapter, + federationBridge, +); -export const federationRoomServiceSender = FederationFactory.buildRoomServiceSender( +const federationUserServiceReceiver = FederationFactory.buildUserServiceReceiver( rocketRoomAdapter, rocketUserAdapter, + rocketFileAdapter, + rocketNotificationAdapter, rocketSettingsAdapter, federationBridge, ); +const federationEventsHandler = FederationFactory.buildFederationEventHandler( + federationRoomServiceListener, + federationMessageServiceReceiver, + federationUserServiceReceiver, + rocketSettingsAdapter, +); + +export let federationRoomServiceSender = FederationFactory.buildRoomServiceSender( + rocketRoomAdapter, + rocketUserAdapter, + rocketFileAdapter, + rocketMessageAdapter, + rocketSettingsAdapter, + rocketNotificationAdapter, + federationBridge, +); + const federationRoomInternalHooksValidator = FederationFactory.buildRoomInternalHooksValidator( + rocketRoomAdapter, + rocketUserAdapter, + rocketFileAdapter, + rocketSettingsAdapter, + federationBridge, +); + +export const federationUserServiceSender = FederationFactory.buildUserServiceSender( + rocketRoomAdapter, + rocketUserAdapter, + rocketFileAdapter, + rocketSettingsAdapter, + federationBridge, +); + +const federationMessageServiceSender = FederationFactory.buildMessageServiceSender( rocketRoomAdapter, rocketUserAdapter, rocketSettingsAdapter, + rocketMessageAdapter, federationBridge, ); -FederationFactory.setupListeners(federationRoomServiceSender, federationRoomInternalHooksValidator); let cancelSettingsObserver: () => void; +const onFederationEnabledStatusChanged = async ( + isFederationEnabled: boolean, + appServiceId: string, + homeServerUrl: string, + homeServerDomain: string, + bridgeUrl: string, + bridgePort: number, + homeServerRegistrationFile: IFederationBridgeRegistrationFile, +): Promise => { + federationBridge.onFederationAvailabilityChanged( + isFederationEnabled, + appServiceId, + homeServerUrl, + homeServerDomain, + bridgeUrl, + bridgePort, + homeServerRegistrationFile, + ); + if (isFederationEnabled) { + federationBridge.logFederationStartupInfo('Running Federation V2'); + FederationFactory.setupActions(federationRoomServiceSender, federationMessageServiceSender); + await import('./infrastructure/rocket-chat/slash-commands'); + return; + } + FederationFactory.removeCEListeners(); +}; + export const runFederation = async (): Promise => { + federationRoomServiceSender = FederationFactory.buildRoomServiceSender( + rocketRoomAdapter, + rocketUserAdapter, + rocketFileAdapter, + rocketMessageAdapter, + rocketSettingsAdapter, + rocketNotificationAdapter, + federationBridge, + ); + FederationFactory.setupValidators(federationRoomInternalHooksValidator); federationQueueInstance.setHandler(federationEventsHandler.handleEvent.bind(federationEventsHandler), FEDERATION_PROCESSING_CONCURRENCY); cancelSettingsObserver = rocketSettingsAdapter.onFederationEnabledStatusChanged( - federationBridge.onFederationAvailabilityChanged.bind(federationBridge), + onFederationEnabledStatusChanged.bind(onFederationEnabledStatusChanged), + ); + await rocketNotificationAdapter.subscribeToUserTypingEventsOnFederatedRooms( + rocketNotificationAdapter.broadcastUserTypingOnRoom.bind(rocketNotificationAdapter), ); if (!rocketSettingsAdapter.isFederationEnabled()) { return; } + FederationFactory.setupActions(federationRoomServiceSender, federationMessageServiceSender); await federationBridge.start(); federationBridge.logFederationStartupInfo('Running Federation V2'); - require('./infrastructure/rocket-chat/slash-commands'); + await import('./infrastructure/rocket-chat/slash-commands'); +}; + +const updateServiceSenderInstance = (federationRoomServiceSenderInstance: FederationRoomServiceSender) => { + federationRoomServiceSender = federationRoomServiceSenderInstance; }; -export const stopFederation = async (): Promise => { - FederationFactory.removeListeners(); +export const stopFederation = async (federationRoomServiceSenderInstance: FederationRoomServiceSender): Promise => { + updateServiceSenderInstance(federationRoomServiceSenderInstance); + FederationFactory.removeCEListeners(); await federationBridge.stop(); cancelSettingsObserver(); }; diff --git a/apps/meteor/app/federation-v2/server/infrastructure/Factory.ts b/apps/meteor/app/federation-v2/server/infrastructure/Factory.ts index d922f6b7aab0c..c973ef04b8b8e 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/Factory.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/Factory.ts @@ -1,16 +1,18 @@ -import type { IRoom, IUser } from '@rocket.chat/core-typings'; +import type { IMessage, IRoom, IUser } from '@rocket.chat/core-typings'; -import { FederationRoomServiceListener } from '../application/RoomServiceListener'; +import { FederationRoomServiceListener } from '../application/listener/RoomServiceListener'; import { FederationRoomServiceSender } from '../application/sender/RoomServiceSender'; import { MatrixBridge } from './matrix/Bridge'; import { MatrixEventsHandler } from './matrix/handlers'; import type { MatrixBaseEventHandler } from './matrix/handlers/BaseEvent'; import { MatrixRoomCreatedHandler, + MatrixRoomEventRedactedHandler, MatrixRoomJoinRulesChangedHandler, MatrixRoomMembershipChangedHandler, MatrixRoomMessageSentHandler, MatrixRoomNameChangedHandler, + MatrixRoomPowerLevelsChangedHandler, MatrixRoomTopicChangedHandler, } from './matrix/handlers/Room'; import { InMemoryQueue } from './queue/InMemoryQueue'; @@ -22,6 +24,14 @@ import type { IFederationBridge } from '../domain/IFederationBridge'; import { FederationHooks } from './rocket-chat/hooks'; import { FederationRoomSenderConverter } from './rocket-chat/converters/RoomSender'; import { FederationRoomInternalHooksValidator } from '../application/sender/RoomInternalHooksValidator'; +import { RocketChatFileAdapter } from './rocket-chat/adapters/File'; +import { FederationMessageServiceListener } from '../application/listener/MessageServiceListener'; +import { MatrixMessageReactedHandler } from './matrix/handlers/Message'; +import { FederationMessageServiceSender } from '../application/sender/MessageServiceSender'; +import { FederationUserServiceListener } from '../application/listener/UserServiceListener'; +import { MatrixUserTypingStatusChangedHandler } from './matrix/handlers/User'; +import { FederationUserServiceSender } from '../application/sender/UserServiceSender'; +import { RocketChatNotificationAdapter } from './rocket-chat/adapters/Notification'; export class FederationFactory { public static buildRocketSettingsAdapter(): RocketChatSettingsAdapter { @@ -40,36 +50,124 @@ export class FederationFactory { return new RocketChatMessageAdapter(); } + public static buildRocketFileAdapter(): RocketChatFileAdapter { + return new RocketChatFileAdapter(); + } + + public static buildRocketNotificationAdapter(): RocketChatNotificationAdapter { + return new RocketChatNotificationAdapter(); + } + public static buildFederationQueue(): InMemoryQueue { return new InMemoryQueue(); } - public static buildRoomServiceReceiver( + public static buildRoomServiceListener( rocketRoomAdapter: RocketChatRoomAdapter, rocketUserAdapter: RocketChatUserAdapter, rocketMessageAdapter: RocketChatMessageAdapter, + rocketFileAdapter: RocketChatFileAdapter, rocketSettingsAdapter: RocketChatSettingsAdapter, + rocketNotificationAdapter: RocketChatNotificationAdapter, + federationQueueInstance: InMemoryQueue, bridge: IFederationBridge, ): FederationRoomServiceListener { - return new FederationRoomServiceListener(rocketRoomAdapter, rocketUserAdapter, rocketMessageAdapter, rocketSettingsAdapter, bridge); + return new FederationRoomServiceListener( + rocketRoomAdapter, + rocketUserAdapter, + rocketMessageAdapter, + rocketFileAdapter, + rocketSettingsAdapter, + rocketNotificationAdapter, + federationQueueInstance, + bridge, + ); } public static buildRoomServiceSender( rocketRoomAdapter: RocketChatRoomAdapter, rocketUserAdapter: RocketChatUserAdapter, + rocketFileAdapter: RocketChatFileAdapter, + rocketMessageAdapter: RocketChatMessageAdapter, rocketSettingsAdapter: RocketChatSettingsAdapter, + rocketNotificationAdapter: RocketChatNotificationAdapter, bridge: IFederationBridge, ): FederationRoomServiceSender { - return new FederationRoomServiceSender(rocketRoomAdapter, rocketUserAdapter, rocketSettingsAdapter, bridge); + return new FederationRoomServiceSender( + rocketRoomAdapter, + rocketUserAdapter, + rocketFileAdapter, + rocketMessageAdapter, + rocketSettingsAdapter, + rocketNotificationAdapter, + bridge, + ); + } + + public static buildUserServiceSender( + rocketRoomAdapter: RocketChatRoomAdapter, + rocketUserAdapter: RocketChatUserAdapter, + rocketFileAdapter: RocketChatFileAdapter, + rocketSettingsAdapter: RocketChatSettingsAdapter, + bridge: IFederationBridge, + ): FederationUserServiceSender { + return new FederationUserServiceSender(rocketRoomAdapter, rocketUserAdapter, rocketFileAdapter, rocketSettingsAdapter, bridge); + } + + public static buildMessageServiceSender( + rocketRoomAdapter: RocketChatRoomAdapter, + rocketUserAdapter: RocketChatUserAdapter, + rocketSettingsAdapter: RocketChatSettingsAdapter, + rocketMessageAdapter: RocketChatMessageAdapter, + bridge: IFederationBridge, + ): FederationMessageServiceSender { + return new FederationMessageServiceSender(rocketRoomAdapter, rocketUserAdapter, rocketSettingsAdapter, rocketMessageAdapter, bridge); + } + + public static buildMessageServiceReceiver( + rocketRoomAdapter: RocketChatRoomAdapter, + rocketUserAdapter: RocketChatUserAdapter, + rocketMessageAdapter: RocketChatMessageAdapter, + rocketFileAdapter: RocketChatFileAdapter, + rocketSettingsAdapter: RocketChatSettingsAdapter, + bridge: IFederationBridge, + ): FederationMessageServiceListener { + return new FederationMessageServiceListener( + rocketRoomAdapter, + rocketUserAdapter, + rocketMessageAdapter, + rocketFileAdapter, + rocketSettingsAdapter, + bridge, + ); + } + + public static buildUserServiceReceiver( + rocketRoomAdapter: RocketChatRoomAdapter, + rocketUserAdapter: RocketChatUserAdapter, + rocketFileAdapter: RocketChatFileAdapter, + rocketNotificationAdapter: RocketChatNotificationAdapter, + rocketSettingsAdapter: RocketChatSettingsAdapter, + bridge: IFederationBridge, + ): FederationUserServiceListener { + return new FederationUserServiceListener( + rocketRoomAdapter, + rocketUserAdapter, + rocketFileAdapter, + rocketNotificationAdapter, + rocketSettingsAdapter, + bridge, + ); } public static buildRoomInternalHooksValidator( rocketRoomAdapter: RocketChatRoomAdapter, rocketUserAdapter: RocketChatUserAdapter, + rocketFileAdapter: RocketChatFileAdapter, rocketSettingsAdapter: RocketChatSettingsAdapter, bridge: IFederationBridge, ): FederationRoomInternalHooksValidator { - return new FederationRoomInternalHooksValidator(rocketRoomAdapter, rocketUserAdapter, rocketSettingsAdapter, bridge); + return new FederationRoomInternalHooksValidator(rocketRoomAdapter, rocketUserAdapter, rocketFileAdapter, rocketSettingsAdapter, bridge); } public static buildFederationBridge(rocketSettingsAdapter: RocketChatSettingsAdapter, queue: InMemoryQueue): IFederationBridge { @@ -86,13 +184,19 @@ export class FederationFactory { public static buildFederationEventHandler( roomServiceReceive: FederationRoomServiceListener, + messageServiceReceiver: FederationMessageServiceListener, + userServiceReceiver: FederationUserServiceListener, rocketSettingsAdapter: RocketChatSettingsAdapter, ): MatrixEventsHandler { - return new MatrixEventsHandler(FederationFactory.getEventHandlers(roomServiceReceive, rocketSettingsAdapter)); + return new MatrixEventsHandler( + FederationFactory.getEventHandlers(roomServiceReceive, messageServiceReceiver, userServiceReceiver, rocketSettingsAdapter), + ); } public static getEventHandlers( roomServiceReceiver: FederationRoomServiceListener, + messageServiceReceiver: FederationMessageServiceListener, + userServiceReceiver: FederationUserServiceListener, rocketSettingsAdapter: RocketChatSettingsAdapter, ): MatrixBaseEventHandler[] { return [ @@ -102,18 +206,23 @@ export class FederationFactory { new MatrixRoomJoinRulesChangedHandler(roomServiceReceiver), new MatrixRoomNameChangedHandler(roomServiceReceiver), new MatrixRoomTopicChangedHandler(roomServiceReceiver), + new MatrixRoomEventRedactedHandler(roomServiceReceiver), + new MatrixMessageReactedHandler(messageServiceReceiver), + new MatrixUserTypingStatusChangedHandler(userServiceReceiver), + new MatrixRoomPowerLevelsChangedHandler(roomServiceReceiver), ]; } public static setupListeners( roomServiceSender: FederationRoomServiceSender, roomInternalHooksValidator: FederationRoomInternalHooksValidator, + messageServiceSender: FederationMessageServiceSender, ): void { - FederationFactory.setupActions(roomServiceSender); + FederationFactory.setupActions(roomServiceSender, messageServiceSender); FederationFactory.setupValidators(roomInternalHooksValidator); } - private static setupActions(roomServiceSender: FederationRoomServiceSender): void { + public static setupActions(roomServiceSender: FederationRoomServiceSender, messageServiceSender: FederationMessageServiceSender): void { FederationHooks.afterUserLeaveRoom((user: IUser, room: IRoom) => roomServiceSender.afterUserLeaveRoom(FederationRoomSenderConverter.toAfterUserLeaveRoom(user._id, room._id)), ); @@ -122,9 +231,22 @@ export class FederationFactory { FederationRoomSenderConverter.toOnUserRemovedFromRoom(user._id, room._id, userWhoRemoved._id), ), ); + FederationHooks.afterMessageReacted((message: IMessage, user: IUser, reaction: string) => + messageServiceSender.sendExternalMessageReaction(message, user, reaction), + ); + FederationHooks.afterMessageunReacted((message: IMessage, user: IUser, reaction: string) => + messageServiceSender.sendExternalMessageUnReaction(message, user, reaction), + ); + FederationHooks.afterMessageDeleted((message: IMessage, roomId: string) => roomServiceSender.afterMessageDeleted(message, roomId)); + FederationHooks.afterMessageUpdated((message: IMessage, roomId: string, userId: string) => + roomServiceSender.afterMessageUpdated(message, roomId, userId), + ); + FederationHooks.afterMessageSent((message: IMessage, roomId: string, userId: string) => + roomServiceSender.sendExternalMessage(FederationRoomSenderConverter.toSendExternalMessageDto(userId, roomId, message)), + ); } - private static setupValidators(roomInternalHooksValidator: FederationRoomInternalHooksValidator): void { + public static setupValidators(roomInternalHooksValidator: FederationRoomInternalHooksValidator): void { FederationHooks.canAddFederatedUserToNonFederatedRoom((user: IUser | string, room: IRoom) => roomInternalHooksValidator.canAddFederatedUserToNonFederatedRoom(user, room), ); @@ -136,7 +258,7 @@ export class FederationFactory { ); } - public static removeListeners(): void { + public static removeCEListeners(): void { FederationHooks.removeCEValidation(); } } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/Bridge.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/Bridge.ts index fb9d6b614ec54..adae0a2504e0c 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/matrix/Bridge.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/Bridge.ts @@ -1,33 +1,20 @@ +import type { IMessage } from '@rocket.chat/core-typings'; import type { AppServiceOutput, Bridge } from '@rocket.chat/forked-matrix-appservice-bridge'; -import type { IExternalUserProfileInformation, IFederationBridge } from '../../domain/IFederationBridge'; +import { fetch } from '../../../../../server/lib/http/fetch'; +import type { IExternalUserProfileInformation, IFederationBridge, IFederationBridgeRegistrationFile } from '../../domain/IFederationBridge'; import { federationBridgeLogger } from '../rocket-chat/adapters/logger'; +import { toExternalMessageFormat, toExternalQuoteMessageFormat } from './converters/MessageTextParser'; +import { convertEmojisFromRCFormatToMatrixFormat } from './converters/MessageReceiver'; import type { AbstractMatrixEvent } from './definitions/AbstractMatrixEvent'; +import { MatrixEnumRelatesToRelType, MatrixEnumSendMessageType } from './definitions/events/RoomMessageSent'; +import { MatrixEventType } from './definitions/MatrixEventType'; import { MatrixRoomType } from './definitions/MatrixRoomType'; import { MatrixRoomVisibility } from './definitions/MatrixRoomVisibility'; +import { RoomMembershipChangedEventType } from './definitions/events/RoomMembershipChanged'; let MatrixUserInstance: any; -interface IRegistrationFileNamespaceRule { - exclusive: boolean; - regex: string; -} - -interface IRegistrationFileNamespaces { - users: IRegistrationFileNamespaceRule[]; - rooms: IRegistrationFileNamespaceRule[]; - aliases: IRegistrationFileNamespaceRule[]; -} - -export interface IFederationBridgeRegistrationFile { - id: string; - homeserverToken: string; - applicationServiceToken: string; - bridgeUrl: string; - botName: string; - listenTo: IRegistrationFileNamespaces; -} - export class MatrixBridge implements IFederationBridge { protected bridgeInstance: Bridge; @@ -45,7 +32,21 @@ export class MatrixBridge implements IFederationBridge { protected eventHandler: (event: AbstractMatrixEvent) => void, ) {} // eslint-disable-line no-empty-function - public async onFederationAvailabilityChanged(enabled: boolean): Promise { + public async onFederationAvailabilityChanged( + enabled: boolean, + appServiceId: string, + homeServerUrl: string, + homeServerDomain: string, + bridgeUrl: string, + bridgePort: number, + homeServerRegistrationFile: IFederationBridgeRegistrationFile, + ): Promise { + this.appServiceId = appServiceId; + this.homeServerUrl = homeServerUrl; + this.homeServerDomain = homeServerDomain; + this.bridgeUrl = bridgeUrl; + this.bridgePort = bridgePort; + this.homeServerRegistrationFile = homeServerRegistrationFile; if (!enabled) { await this.stop(); return; @@ -66,8 +67,8 @@ export class MatrixBridge implements IFederationBridge { await this.bridgeInstance.run(this.bridgePort); this.isRunning = true; } - } catch (e) { - federationBridgeLogger.error('Failed to initialize the matrix-appservice-bridge.', e); + } catch (err) { + federationBridgeLogger.error({ msg: 'Failed to initialize the matrix-appservice-bridge.', err }); } finally { this.isUpdatingBridgeStatus = false; } @@ -77,25 +78,56 @@ export class MatrixBridge implements IFederationBridge { if (!this.isRunning) { return; } - this.isRunning = false; - // the http server might take some minutes to shutdown, and this promise can take some time to be resolved - await this.bridgeInstance?.close(); + return new Promise(async (resolve: () => void): Promise => { + // the http server might take some minutes to shutdown, and this promise can take some time to be resolved + await this.bridgeInstance?.close(); + this.isRunning = false; + resolve(); + }); } public async getUserProfileInformation(externalUserId: string): Promise { try { - const externalInformation = await this.bridgeInstance.getIntent(externalUserId).getProfileInfo(externalUserId); + const externalInformation = await this.bridgeInstance.getIntent(externalUserId).getProfileInfo(externalUserId, undefined, false); return { displayName: externalInformation.displayname || '', + ...(externalInformation.avatar_url + ? { + avatarUrl: externalInformation.avatar_url, + } + : {}), }; } catch (err) { // no-op } } - public async joinRoom(externalRoomId: string, externalUserId: string): Promise { - await this.bridgeInstance.getIntent(externalUserId).join(externalRoomId); + public async joinRoom(externalRoomId: string, externalUserId: string, viaServers?: string[]): Promise { + await this.bridgeInstance.getIntent(externalUserId).join(externalRoomId, viaServers); + } + + public async getRoomHistoricalJoinEvents( + externalRoomId: string, + externalUserId: string, + excludingUserIds: string[] = [], + ): Promise { + const events = await this.bridgeInstance.getIntent(externalUserId).matrixClient.getRoomState(externalRoomId); + const roomCreator = events.find((event) => event.type === MatrixEventType.ROOM_CREATED)?.content?.creator; + if (!roomCreator) { + return []; + } + return events + .filter( + (event) => + event.type === MatrixEventType.ROOM_MEMBERSHIP_CHANGED && + event.content.membership === RoomMembershipChangedEventType.JOIN && + !excludingUserIds.includes(event.state_key), + ) + .map((event) => ({ + ...event, + sender: roomCreator, + })); } public async inviteToRoom(externalRoomId: string, externalInviterId: string, externalInviteeId: string): Promise { @@ -106,50 +138,125 @@ export class MatrixBridge implements IFederationBridge { } } - public async createUser(username: string, name: string, domain: string): Promise { + public async setUserAvatar(externalUserId: string, avatarUrl: string): Promise { + try { + await this.bridgeInstance.getIntent(externalUserId).matrixClient.setAvatarUrl(avatarUrl); + } catch (e) { + // no-op + } + } + + public async createUser(username: string, name: string, domain: string, avatarUrl?: string): Promise { if (!MatrixUserInstance) { throw new Error('Error loading the Matrix User instance from the external library'); } const matrixUserId = `@${username?.toLowerCase()}:${domain}`; const newUser = new MatrixUserInstance(matrixUserId); - await this.bridgeInstance.provisionUser(newUser, { name: `${username} (${name})` }); + await this.bridgeInstance.provisionUser(newUser, { name, ...(avatarUrl ? { url: avatarUrl } : {}) }); return matrixUserId; } + public async setUserDisplayName(externalUserId: string, displayName: string): Promise { + try { + await this.bridgeInstance.getIntent(externalUserId).setDisplayName(displayName); + } catch (e) { + // no-op + } + } + public async createDirectMessageRoom( externalCreatorId: string, - externalInviteeIds: string[], + inviteesExternalIds: string[], extraData: Record = {}, ): Promise { const intent = this.bridgeInstance.getIntent(externalCreatorId); const visibility = MatrixRoomVisibility.PRIVATE; const preset = MatrixRoomType.PRIVATE; + const matrixRoom = await intent.createRoom({ createAsClient: true, options: { visibility, preset, is_direct: true, - invite: externalInviteeIds, + invite: inviteesExternalIds, creation_content: { was_internally_programatically_created: true, ...extraData, + inviteesExternalIds, }, }, }); return matrixRoom.room_id; } - public async sendMessage(externalRoomId: string, externaSenderId: string, text: string): Promise { + public async sendMessage(externalRoomId: string, externalSenderId: string, message: IMessage): Promise { try { - await this.bridgeInstance.getIntent(externaSenderId).sendText(externalRoomId, text); + const messageId = await this.bridgeInstance + .getIntent(externalSenderId) + .matrixClient.sendRawEvent(externalRoomId, MatrixEventType.ROOM_MESSAGE_SENT, { + msgtype: 'm.text', + body: this.escapeEmojis(message.msg), + formatted_body: this.escapeEmojis( + await toExternalMessageFormat({ + message: message.msg, + externalRoomId, + homeServerDomain: this.homeServerDomain, + }), + ), + format: 'org.matrix.custom.html', + }); + + return messageId; } catch (e) { throw new Error('User is not part of the room.'); } } + public async sendReplyToMessage( + externalRoomId: string, + externalUserId: string, + eventToReplyTo: string, + originalEventSender: string, + replyMessage: string, + ): Promise { + const { formattedMessage, message } = await toExternalQuoteMessageFormat({ + externalRoomId, + eventToReplyTo, + originalEventSender, + message: this.escapeEmojis(replyMessage), + homeServerDomain: this.homeServerDomain, + }); + const messageId = await this.bridgeInstance + .getIntent(externalUserId) + .matrixClient.sendEvent(externalRoomId, MatrixEventType.ROOM_MESSAGE_SENT, { + 'body': message, + 'format': 'org.matrix.custom.html', + 'formatted_body': formattedMessage, + 'm.relates_to': { + 'm.in_reply_to': { event_id: eventToReplyTo }, + }, + 'msgtype': MatrixEnumSendMessageType.TEXT, + }); + + return messageId; + } + + private escapeEmojis(text: string): string { + return convertEmojisFromRCFormatToMatrixFormat(text); + } + + public async getReadStreamForFileFromUrl(externalUserId: string, fileUrl: string): Promise { + const response = await fetch(this.convertMatrixUrlToHttp(externalUserId, fileUrl)); + if (!response.body) { + throw new Error('Not able to download the file'); + } + + return response.body; + } + public isUserIdFromTheSameHomeserver(externalUserId: string, domain: string): boolean { const userDomain = this.extractHomeserverOrigin(externalUserId); @@ -185,6 +292,173 @@ export class MatrixBridge implements IFederationBridge { await this.bridgeInstance.getIntent(externalOwnerId).kick(externalRoomId, externalUserId); } + public async setRoomPowerLevels( + externalRoomId: string, + externalOwnerId: string, + externalUserId: string, + powerLevels: number, + ): Promise { + await this.bridgeInstance.getIntent(externalOwnerId).setPowerLevel(externalRoomId, externalUserId, powerLevels); + } + + public async redactEvent(externalRoomId: string, externalUserId: string, externalEventId: string): Promise { + await this.bridgeInstance.getIntent(externalUserId).matrixClient.redactEvent(externalRoomId, externalEventId); + } + + public async notifyUserTyping(externalRoomId: string, externalUserId: string, isTyping: boolean): Promise { + await this.bridgeInstance.getIntent(externalUserId).sendTyping(externalRoomId, isTyping); + } + + public async sendMessageReaction( + externalRoomId: string, + externalUserId: string, + externalEventId: string, + reaction: string, + ): Promise { + const eventId = await this.bridgeInstance + .getIntent(externalUserId) + .matrixClient.sendEvent(externalRoomId, MatrixEventType.MESSAGE_REACTED, { + 'm.relates_to': { + event_id: externalEventId, + key: convertEmojisFromRCFormatToMatrixFormat(reaction), + rel_type: 'm.annotation', + }, + }); + + return eventId; + } + + public async updateMessage( + externalRoomId: string, + externalUserId: string, + externalEventId: string, + newMessageText: string, + ): Promise { + const messageInExternalFormat = this.escapeEmojis( + await toExternalMessageFormat({ message: newMessageText, externalRoomId, homeServerDomain: this.homeServerDomain }), + ); + + await this.bridgeInstance.getIntent(externalUserId).matrixClient.sendEvent(externalRoomId, MatrixEventType.ROOM_MESSAGE_SENT, { + 'body': ` * ${this.escapeEmojis(newMessageText)}`, + 'format': 'org.matrix.custom.html', + 'formatted_body': messageInExternalFormat, + 'm.new_content': { + body: this.escapeEmojis(newMessageText), + format: 'org.matrix.custom.html', + formatted_body: messageInExternalFormat, + msgtype: MatrixEnumSendMessageType.TEXT, + }, + 'm.relates_to': { + rel_type: MatrixEnumRelatesToRelType.REPLACE, + event_id: externalEventId, + }, + 'msgtype': MatrixEnumSendMessageType.TEXT, + }); + } + + public async sendMessageFileToRoom( + externalRoomId: string, + externaSenderId: string, + content: Buffer, + fileDetails: { filename: string; fileSize: number; mimeType: string; metadata?: { width?: number; height?: number; format?: string } }, + ): Promise { + try { + const mxcUrl = await this.bridgeInstance.getIntent(externaSenderId).uploadContent(content); + const { event_id: messageId } = await this.bridgeInstance.getIntent(externaSenderId).sendMessage(externalRoomId, { + body: fileDetails.filename, + filename: fileDetails.filename, + info: { + size: fileDetails.fileSize, + mimetype: fileDetails.mimeType, + ...(fileDetails.metadata?.height && fileDetails.metadata?.width + ? { h: fileDetails.metadata?.height, w: fileDetails.metadata?.width } + : {}), + }, + msgtype: this.getMsgTypeBasedOnMimeType(fileDetails.mimeType), + url: mxcUrl, + }); + + return messageId; + } catch (e: any) { + if (e.body?.includes('413') || e.body?.includes('M_TOO_LARGE')) { + throw new Error('File is too large'); + } + return ''; + } + } + + public async sendReplyMessageFileToRoom( + externalRoomId: string, + externaSenderId: string, + content: Buffer, + fileDetails: { filename: string; fileSize: number; mimeType: string; metadata?: { width?: number; height?: number; format?: string } }, + eventToReplyTo: string, + ): Promise { + try { + const mxcUrl = await this.bridgeInstance.getIntent(externaSenderId).uploadContent(content); + const { event_id: messageId } = await this.bridgeInstance.getIntent(externaSenderId).sendMessage(externalRoomId, { + 'body': fileDetails.filename, + 'filename': fileDetails.filename, + 'info': { + size: fileDetails.fileSize, + mimetype: fileDetails.mimeType, + ...(fileDetails.metadata?.height && fileDetails.metadata?.width + ? { h: fileDetails.metadata?.height, w: fileDetails.metadata?.width } + : {}), + }, + 'm.relates_to': { + 'm.in_reply_to': { event_id: eventToReplyTo }, + }, + 'msgtype': this.getMsgTypeBasedOnMimeType(fileDetails.mimeType), + 'url': mxcUrl, + }); + + return messageId; + } catch (e: any) { + if (e.body?.includes('413') || e.body?.includes('M_TOO_LARGE')) { + throw new Error('File is too large'); + } + return ''; + } + } + + private getMsgTypeBasedOnMimeType(mimeType: string): MatrixEnumSendMessageType { + const knownImageMimeTypes = ['image/jpeg', 'image/png', 'image/gif']; + const knownAudioMimeTypes = ['audio/mpeg', 'audio/ogg', 'audio/wav']; + const knownVideoMimeTypes = ['video/mp4', 'video/ogg', 'video/webm']; + + if (knownImageMimeTypes.includes(mimeType)) { + return MatrixEnumSendMessageType.IMAGE; + } + if (knownAudioMimeTypes.includes(mimeType)) { + return MatrixEnumSendMessageType.AUDIO; + } + if (knownVideoMimeTypes.includes(mimeType)) { + return MatrixEnumSendMessageType.VIDEO; + } + return MatrixEnumSendMessageType.FILE; + } + + public async uploadContent( + externalSenderId: string, + content: Buffer, + options?: { name?: string; type?: string }, + ): Promise { + try { + const mxcUrl = await this.bridgeInstance.getIntent(externalSenderId).uploadContent(content, options); + + return mxcUrl; + } catch (e: any) { + if (e.body?.includes('413') || e.body?.includes('M_TOO_LARGE')) { + throw new Error('File is too large'); + } + } + } + + public convertMatrixUrlToHttp(externalUserId: string, matrixUrl: string): string { + return this.bridgeInstance.getIntent(externalUserId).matrixClient.mxcToHttp(matrixUrl); + } + protected async createInstance(): Promise { federationBridgeLogger.info('Performing Dynamic Import of matrix-appservice-bridge'); @@ -205,18 +479,27 @@ export class MatrixBridge implements IFederationBridge { onLog: async (line, isError): Promise => { console.log(line, isError); }, + ...(this.homeServerRegistrationFile.enableEphemeralEvents + ? { + onEphemeralEvent: async (request): Promise => { + const event = request.getData() as unknown as AbstractMatrixEvent; + this.eventHandler(event); + }, + } + : {}), }, }); } private convertRegistrationFileToMatrixFormat(): AppServiceOutput { return { - id: this.homeServerRegistrationFile.id, - hs_token: this.homeServerRegistrationFile.homeserverToken, - as_token: this.homeServerRegistrationFile.applicationServiceToken, - url: this.homeServerRegistrationFile.bridgeUrl, - sender_localpart: this.homeServerRegistrationFile.botName, - namespaces: this.homeServerRegistrationFile.listenTo, + 'id': this.homeServerRegistrationFile.id, + 'hs_token': this.homeServerRegistrationFile.homeserverToken, + 'as_token': this.homeServerRegistrationFile.applicationServiceToken, + 'url': this.homeServerRegistrationFile.bridgeUrl, + 'sender_localpart': this.homeServerRegistrationFile.botName, + 'namespaces': this.homeServerRegistrationFile.listenTo, + 'de.sorunome.msc2409.push_ephemeral': this.homeServerRegistrationFile.enableEphemeralEvents, }; } } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/MessageReceiver.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/MessageReceiver.ts new file mode 100644 index 0000000000000..b3087883058ea --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/MessageReceiver.ts @@ -0,0 +1,21 @@ +import emojione from 'emojione'; + +import type { MatrixEventMessageReact } from '../definitions/events/MessageReacted'; +import { FederationMessageReactionEventDto } from '../../../application/listener/input/MessageReceiverDto'; +import { convertExternalRoomIdToInternalRoomIdFormat } from './RoomReceiver'; + +const convertEmojisMatrixFormatToRCFormat = (emoji: string): string => emojione.toShort(emoji); +export const convertEmojisFromRCFormatToMatrixFormat = (emoji: string): string => emojione.shortnameToUnicode(emoji); + +export class MatrixMessageReceiverConverter { + public static toMessageReactionDto(externalEvent: MatrixEventMessageReact): FederationMessageReactionEventDto { + return new FederationMessageReactionEventDto({ + externalEventId: externalEvent.event_id, + externalRoomId: externalEvent.room_id, + normalizedRoomId: convertExternalRoomIdToInternalRoomIdFormat(externalEvent.room_id), + externalSenderId: externalEvent.sender, + emoji: convertEmojisMatrixFormatToRCFormat(externalEvent.content['m.relates_to'].key), + externalReactedEventId: externalEvent.content['m.relates_to'].event_id, + }); + } +} diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/MessageTextParser.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/MessageTextParser.ts new file mode 100644 index 0000000000000..a1f42e9b2ab31 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/MessageTextParser.ts @@ -0,0 +1,110 @@ +import type { MentionPill as MentionPillType } from '@rocket.chat/forked-matrix-bot-sdk'; +import { marked } from 'marked'; + +const INTERNAL_MENTIONS_FOR_EXTERNAL_USERS_REGEX = /@([0-9a-zA-Z-_.]+(@([0-9a-zA-Z-_.]+))?):+([0-9a-zA-Z-_.]+)(?=[^<>]*(?:<\w|$))/gm; // @username:server.com excluding any tags +const INTERNAL_MENTIONS_FOR_INTERNAL_USERS_REGEX = /(?:^|(?<=\s))@([0-9a-zA-Z-_.]+(@([0-9a-zA-Z-_.]+))?)(?=[^<>]*(?:<\w|$))/gm; // @username, @username.name excluding any tags and emails +const INTERNAL_GENERAL_REGEX = /(@all)|(@here)/gm; + +const replaceMessageMentions = async ( + message: string, + mentionRegex: RegExp, + parseMatchFn: (match: string) => Promise, +): Promise => { + const promises: Promise[] = []; + + message.replace(mentionRegex, (match: string): any => promises.push(parseMatchFn(match))); + + const mentions = await Promise.all(promises); + + return message.replace(mentionRegex, () => ` ${mentions.shift()?.html}`); +}; + +const replaceMentionsFromLocalExternalUsersForExternalFormat = async (message: string): Promise => { + const { MentionPill } = await import('@rocket.chat/forked-matrix-bot-sdk'); + + return replaceMessageMentions(message, INTERNAL_MENTIONS_FOR_EXTERNAL_USERS_REGEX, (match: string) => + MentionPill.forUser(match.trimStart()), + ); +}; + +const replaceInternalUsersMentionsForExternalFormat = async (message: string, homeServerDomain: string): Promise => { + const { MentionPill } = await import('@rocket.chat/forked-matrix-bot-sdk'); + + return replaceMessageMentions(message, INTERNAL_MENTIONS_FOR_INTERNAL_USERS_REGEX, (match: string) => + MentionPill.forUser(`${match.trimStart()}:${homeServerDomain}`), + ); +}; + +const replaceInternalGeneralMentionsForExternalFormat = async (message: string, externalRoomId: string): Promise => { + const { MentionPill } = await import('@rocket.chat/forked-matrix-bot-sdk'); + + return replaceMessageMentions(message, INTERNAL_GENERAL_REGEX, () => MentionPill.forRoom(externalRoomId)); +}; + +const removeAllExtraBlankSpacesForASingleOne = (message: string): string => message.replace(/\s+/g, ' ').trim(); + +const replaceInternalWithExternalMentions = async (message: string, externalRoomId: string, homeServerDomain: string): Promise => + replaceInternalUsersMentionsForExternalFormat( + await replaceMentionsFromLocalExternalUsersForExternalFormat( + await replaceInternalGeneralMentionsForExternalFormat(message, externalRoomId), + ), + homeServerDomain, + ); + +const convertMarkdownToHTML = (message: string): string => marked.parse(message); + +export const toExternalMessageFormat = async ({ + externalRoomId, + homeServerDomain, + message, +}: { + message: string; + externalRoomId: string; + homeServerDomain: string; +}): Promise => + removeAllExtraBlankSpacesForASingleOne( + convertMarkdownToHTML((await replaceInternalWithExternalMentions(message, externalRoomId, homeServerDomain)).trim()), + ); + +export const toExternalQuoteMessageFormat = async ({ + message, + eventToReplyTo, + externalRoomId, + homeServerDomain, + originalEventSender, +}: { + externalRoomId: string; + eventToReplyTo: string; + originalEventSender: string; + message: string; + homeServerDomain: string; +}): Promise<{ message: string; formattedMessage: string }> => { + const { RichReply } = await import('@rocket.chat/forked-matrix-bot-sdk'); + + const formattedMessage = convertMarkdownToHTML(message); + const finalFormattedMessage = convertMarkdownToHTML( + await toExternalMessageFormat({ + message, + externalRoomId, + homeServerDomain, + }), + ); + + const { formatted_body: formattedBody } = RichReply.createFor( + externalRoomId, + { event_id: eventToReplyTo, sender: originalEventSender }, + formattedMessage, + finalFormattedMessage, + ); + const { body } = RichReply.createFor( + externalRoomId, + { event_id: eventToReplyTo, sender: originalEventSender }, + message, + finalFormattedMessage, + ); + + return { + message: body, + formattedMessage: formattedBody, + }; +}; diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/RoomReceiver.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/RoomReceiver.ts index dc4cdcbf2c842..bb4e1661ded27 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/RoomReceiver.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/RoomReceiver.ts @@ -6,8 +6,13 @@ import { FederationRoomChangeNameDto, FederationRoomChangeTopicDto, FederationRoomCreateInputDto, + FederationRoomEditExternalMessageDto, + FederationRoomReceiveExternalFileMessageDto, FederationRoomReceiveExternalMessageDto, -} from '../../../application/input/RoomReceiverDto'; + FederationRoomRedactEventDto, + FederationRoomRoomChangePowerLevelsEventDto, +} from '../../../application/listener/input/RoomReceiverDto'; +import type { IExternalRolesChangesToApplyInputDto } from '../../../application/listener/input/RoomReceiverDto'; import { EVENT_ORIGIN } from '../../../domain/IFederationBridge'; import type { MatrixEventRoomMembershipChanged } from '../definitions/events/RoomMembershipChanged'; import { RoomMembershipChangedEventType } from '../definitions/events/RoomMembershipChanged'; @@ -19,15 +24,26 @@ import type { MatrixEventRoomJoinRulesChanged } from '../definitions/events/Room import type { MatrixEventRoomNameChanged } from '../definitions/events/RoomNameChanged'; import type { MatrixEventRoomTopicChanged } from '../definitions/events/RoomTopicChanged'; import type { AbstractMatrixEvent } from '../definitions/AbstractMatrixEvent'; +import type { MatrixEventRoomRedacted } from '../definitions/events/RoomEventRedacted'; +import type { + IMatrixEventContentRoomPowerLevelsChanged, + MatrixEventRoomRoomPowerLevelsChanged, +} from '../definitions/events/RoomPowerLevelsChanged'; +import { MATRIX_POWER_LEVELS } from '../definitions/MatrixPowerLevels'; +import { ROCKET_CHAT_FEDERATION_ROLES } from '../../rocket-chat/definitions/InternalFederatedRoomRoles'; export const removeExternalSpecificCharsFromExternalIdentifier = (matrixIdentifier = ''): string => { - return matrixIdentifier.replace('@', '').replace('!', ''); + return matrixIdentifier.replace('@', '').replace('!', '').replace('#', ''); }; export const formatExternalUserIdToInternalUsernameFormat = (matrixUserId = ''): string => { return matrixUserId.split(':')[0]?.replace('@', ''); }; +export const formatExternalAliasIdToInternalFormat = (alias = ''): string => { + return alias.split(':')[0]?.replace('#', ''); +}; + export const isAnExternalIdentifierFormat = (identifier: string): boolean => identifier.includes(':'); export const isAnExternalUserIdFormat = (userId: string): boolean => isAnExternalIdentifierFormat(userId) && userId.includes('@'); @@ -38,7 +54,7 @@ export const extractServerNameFromExternalIdentifier = (identifier = ''): string return splitted.length > 1 ? splitted[1] : ''; }; -const convertExternalRoomIdToInternalRoomIdFormat = (matrixRoomId = ''): string => { +export const convertExternalRoomIdToInternalRoomIdFormat = (matrixRoomId = ''): string => { const prefixedRoomIdOnly = matrixRoomId.split(':')[0]; const prefix = '!'; @@ -72,7 +88,7 @@ const tryToExtractExternalRoomNameFromTheRoomState = (roomState: AbstractMatrixE )?.content?.name; return { - ...(externalRoomName ? { externalRoomName } : {}), + ...(externalRoomName ? { externalRoomName: removeExternalSpecificCharsFromExternalIdentifier(externalRoomName) } : {}), }; }; @@ -92,9 +108,129 @@ const tryToExtractAndConvertRoomTypeFromTheRoomState = ( }; }; +const convertNumericalPowerLevelToInternalRole = (powerLevel: number): ROCKET_CHAT_FEDERATION_ROLES | undefined => { + const mapping: Record = { + [MATRIX_POWER_LEVELS.USER]: undefined, + [MATRIX_POWER_LEVELS.MODERATOR]: ROCKET_CHAT_FEDERATION_ROLES.MODERATOR, + [MATRIX_POWER_LEVELS.ADMIN]: ROCKET_CHAT_FEDERATION_ROLES.OWNER, + }; + + if (mapping[powerLevel]) { + return mapping[powerLevel]; + } + + if (powerLevel <= MATRIX_POWER_LEVELS.USER) { + return; + } + if (powerLevel > MATRIX_POWER_LEVELS.USER && powerLevel <= MATRIX_POWER_LEVELS.MODERATOR) { + return ROCKET_CHAT_FEDERATION_ROLES.MODERATOR; + } + return ROCKET_CHAT_FEDERATION_ROLES.OWNER; +}; + +const onlyRolesAddedToDefaultUsers = (previousRolesState: { [key: string]: number }, externalUserId: string): boolean => + !previousRolesState[externalUserId]; + +const verifyIfNewRolesWereAddedForDefaultUsers = ( + currentRolesState: { [key: string]: number }, + previousRolesState: { [key: string]: number }, + changesAlreadyMadeToRoles: IExternalRolesChangesToApplyInputDto, +): IExternalRolesChangesToApplyInputDto => + Object.keys(currentRolesState) + .filter((externalUserId) => onlyRolesAddedToDefaultUsers(previousRolesState, externalUserId)) + .reduce((externalRolesChangesForDefaultUsers, externalUserId) => { + const isCurrentRoleAnOwner = + convertNumericalPowerLevelToInternalRole(currentRolesState[externalUserId]) === ROCKET_CHAT_FEDERATION_ROLES.OWNER; + externalRolesChangesForDefaultUsers[externalUserId] = isCurrentRoleAnOwner + ? [{ action: 'add', role: ROCKET_CHAT_FEDERATION_ROLES.OWNER }] + : [{ action: 'add', role: ROCKET_CHAT_FEDERATION_ROLES.MODERATOR }]; + return externalRolesChangesForDefaultUsers; + }, changesAlreadyMadeToRoles); + +const createExternalRolesChangesActions = ( + currentRolesState: { [key: string]: number } = {}, + previousRolesState: { [key: string]: number } = {}, +): IExternalRolesChangesToApplyInputDto => { + const changesInRolesBasedOnPreviousState = Object.keys(previousRolesState).reduce((externalRolesChangesByUser, externalUserId) => { + const currentPowerLevel = currentRolesState[externalUserId]; + const previousPowerLevel = previousRolesState[externalUserId]; + const convertedPreviousExternalRole = convertNumericalPowerLevelToInternalRole(previousPowerLevel); + const convertedCurrentExternalRole = convertNumericalPowerLevelToInternalRole(currentPowerLevel); + const wasPreviousRoleAnOwner = convertedPreviousExternalRole === ROCKET_CHAT_FEDERATION_ROLES.OWNER; + const isCurrentRoleAnOwner = convertedCurrentExternalRole === ROCKET_CHAT_FEDERATION_ROLES.OWNER; + const isCurrentRoleADefault = currentPowerLevel === undefined; + const isStillTheSameRole = currentPowerLevel === previousPowerLevel; + const isDowngradingTheRole = currentPowerLevel < previousPowerLevel; + if (isCurrentRoleADefault) { + externalRolesChangesByUser[externalUserId] = wasPreviousRoleAnOwner + ? [{ action: 'remove', role: ROCKET_CHAT_FEDERATION_ROLES.OWNER }] + : [{ action: 'remove', role: ROCKET_CHAT_FEDERATION_ROLES.MODERATOR }]; + return externalRolesChangesByUser; + } + if (isStillTheSameRole) { + return externalRolesChangesByUser; + } + if (isDowngradingTheRole) { + externalRolesChangesByUser[externalUserId] = [ + ...(convertedPreviousExternalRole ? [{ action: 'remove', role: convertedPreviousExternalRole }] : []), + ...(convertedCurrentExternalRole ? [{ action: 'add', role: convertedCurrentExternalRole }] : []), + ]; + return externalRolesChangesByUser; + } + externalRolesChangesByUser[externalUserId] = isCurrentRoleAnOwner + ? [ + { action: 'add', role: ROCKET_CHAT_FEDERATION_ROLES.OWNER }, + { action: 'remove', role: ROCKET_CHAT_FEDERATION_ROLES.MODERATOR }, + ] + : [ + { action: 'add', role: ROCKET_CHAT_FEDERATION_ROLES.MODERATOR }, + { action: 'remove', role: ROCKET_CHAT_FEDERATION_ROLES.OWNER }, + ]; + + return externalRolesChangesByUser; + }, {} as IExternalRolesChangesToApplyInputDto); + + return verifyIfNewRolesWereAddedForDefaultUsers(currentRolesState, previousRolesState, changesInRolesBasedOnPreviousState); +}; + +const getInviteesFromRoomState = ( + roomState: AbstractMatrixEvent[] = [], +): { + externalInviteeId: string; + normalizedInviteeId: string; + inviteeUsernameOnly: string; +}[] => { + const inviteesFromRoomState = ( + roomState?.find((stateEvent) => stateEvent.type === MatrixEventType.ROOM_CREATED) as MatrixEventRoomCreated + )?.content.inviteesExternalIds; + if (inviteesFromRoomState) { + return inviteesFromRoomState.map((inviteeExternalId) => ({ + externalInviteeId: inviteeExternalId, + normalizedInviteeId: removeExternalSpecificCharsFromExternalIdentifier(inviteeExternalId), + inviteeUsernameOnly: formatExternalUserIdToInternalUsernameFormat(inviteeExternalId), + })); + } + return []; +}; + +const extractAllInviteeIdsWhenDM = ( + externalEvent: MatrixEventRoomMembershipChanged, +): { + externalInviteeId: string; + normalizedInviteeId: string; + inviteeUsernameOnly: string; +}[] => { + if (!externalEvent.invite_room_state && !externalEvent.unsigned?.invite_room_state) { + return []; + } + + return getInviteesFromRoomState(externalEvent.invite_room_state || externalEvent.unsigned?.invite_room_state || []); +}; + export class MatrixRoomReceiverConverter { public static toRoomCreateDto(externalEvent: MatrixEventRoomCreated): FederationRoomCreateInputDto { return new FederationRoomCreateInputDto({ + externalEventId: externalEvent.event_id, externalRoomId: externalEvent.room_id, normalizedRoomId: convertExternalRoomIdToInternalRoomIdFormat(externalEvent.room_id), ...tryToExtractExternalRoomNameFromTheRoomState(externalEvent.invite_room_state || externalEvent.unsigned?.invite_room_state), @@ -111,6 +247,7 @@ export class MatrixRoomReceiverConverter { homeServerDomain: string, ): FederationRoomChangeMembershipDto { return new FederationRoomChangeMembershipDto({ + externalEventId: externalEvent.event_id, externalRoomId: externalEvent.room_id, normalizedRoomId: convertExternalRoomIdToInternalRoomIdFormat(externalEvent.room_id), ...tryToExtractExternalRoomNameFromTheRoomState(externalEvent.invite_room_state || externalEvent.unsigned?.invite_room_state), @@ -126,21 +263,68 @@ export class MatrixRoomReceiverConverter { inviterUsernameOnly: formatExternalUserIdToInternalUsernameFormat(externalEvent.sender), eventOrigin: getEventOrigin(externalEvent.sender, homeServerDomain), leave: externalEvent.content?.membership === RoomMembershipChangedEventType.LEAVE, + userProfile: { + avatarUrl: externalEvent.content?.avatar_url, + displayName: externalEvent.content?.displayname, + }, + ...(externalEvent.content?.is_direct ? { allInviteesExternalIdsWhenDM: extractAllInviteeIdsWhenDM(externalEvent) } : {}), }); } public static toSendRoomMessageDto(externalEvent: MatrixEventRoomMessageSent): FederationRoomReceiveExternalMessageDto { return new FederationRoomReceiveExternalMessageDto({ + externalEventId: externalEvent.event_id, externalRoomId: externalEvent.room_id, normalizedRoomId: convertExternalRoomIdToInternalRoomIdFormat(externalEvent.room_id), externalSenderId: externalEvent.sender, normalizedSenderId: removeExternalSpecificCharsFromExternalIdentifier(externalEvent.sender), - messageText: externalEvent.content?.body, + externalFormattedText: externalEvent.content.formatted_body || '', + rawMessage: externalEvent.content.body, + replyToEventId: externalEvent.content?.['m.relates_to']?.['m.in_reply_to']?.event_id, + }); + } + + public static toEditRoomMessageDto(externalEvent: MatrixEventRoomMessageSent): FederationRoomEditExternalMessageDto { + return new FederationRoomEditExternalMessageDto({ + externalEventId: externalEvent.event_id, + externalRoomId: externalEvent.room_id, + normalizedRoomId: convertExternalRoomIdToInternalRoomIdFormat(externalEvent.room_id), + externalSenderId: externalEvent.sender, + normalizedSenderId: removeExternalSpecificCharsFromExternalIdentifier(externalEvent.sender), + newExternalFormattedText: externalEvent.content['m.new_content']?.formatted_body || '', + newRawMessage: externalEvent.content['m.new_content']?.body as string, + editsEvent: externalEvent.content['m.relates_to']?.event_id as string, + }); + } + + public static toSendRoomFileMessageDto(externalEvent: MatrixEventRoomMessageSent): FederationRoomReceiveExternalFileMessageDto { + if (!externalEvent.content.url) { + throw new Error('Missing url in the file message'); + } + if (!externalEvent.content.info?.mimetype) { + throw new Error('Missing mimetype in the file message info'); + } + if (!externalEvent.content.info?.size) { + throw new Error('Missing size in the file message info'); + } + return new FederationRoomReceiveExternalFileMessageDto({ + externalEventId: externalEvent.event_id, + externalRoomId: externalEvent.room_id, + normalizedRoomId: convertExternalRoomIdToInternalRoomIdFormat(externalEvent.room_id), + externalSenderId: externalEvent.sender, + normalizedSenderId: removeExternalSpecificCharsFromExternalIdentifier(externalEvent.sender), + filename: externalEvent.content.body, + url: externalEvent.content.url, + mimetype: externalEvent.content.info.mimetype, + size: externalEvent.content.info.size, + messageText: externalEvent.content.body, + replyToEventId: externalEvent.content?.['m.relates_to']?.['m.in_reply_to']?.event_id, }); } public static toRoomChangeJoinRulesDto(externalEvent: MatrixEventRoomJoinRulesChanged): FederationRoomChangeJoinRulesDto { return new FederationRoomChangeJoinRulesDto({ + externalEventId: externalEvent.event_id, externalRoomId: externalEvent.room_id, normalizedRoomId: convertExternalRoomIdToInternalRoomIdFormat(externalEvent.room_id), roomType: convertExternalJoinRuleToInternalRoomType(externalEvent.content?.join_rule), @@ -149,6 +333,7 @@ export class MatrixRoomReceiverConverter { public static toRoomChangeNameDto(externalEvent: MatrixEventRoomNameChanged): FederationRoomChangeNameDto { return new FederationRoomChangeNameDto({ + externalEventId: externalEvent.event_id, externalRoomId: externalEvent.room_id, normalizedRoomId: convertExternalRoomIdToInternalRoomIdFormat(externalEvent.room_id), externalSenderId: externalEvent.sender, @@ -158,10 +343,36 @@ export class MatrixRoomReceiverConverter { public static toRoomChangeTopicDto(externalEvent: MatrixEventRoomTopicChanged): FederationRoomChangeTopicDto { return new FederationRoomChangeTopicDto({ + externalEventId: externalEvent.event_id, externalRoomId: externalEvent.room_id, normalizedRoomId: convertExternalRoomIdToInternalRoomIdFormat(externalEvent.room_id), externalSenderId: externalEvent.sender, roomTopic: externalEvent.content?.topic, }); } + + public static toRoomRedactEventDto(externalEvent: MatrixEventRoomRedacted): FederationRoomRedactEventDto { + return new FederationRoomRedactEventDto({ + externalEventId: externalEvent.event_id, + externalRoomId: externalEvent.room_id, + normalizedRoomId: convertExternalRoomIdToInternalRoomIdFormat(externalEvent.room_id), + externalSenderId: externalEvent.sender, + redactsEvent: externalEvent.redacts as string, + }); + } + + public static toRoomChangePowerLevelsEventDto( + externalEvent: MatrixEventRoomRoomPowerLevelsChanged, + ): FederationRoomRoomChangePowerLevelsEventDto { + return new FederationRoomRoomChangePowerLevelsEventDto({ + externalEventId: externalEvent.event_id, + externalRoomId: externalEvent.room_id, + normalizedRoomId: convertExternalRoomIdToInternalRoomIdFormat(externalEvent.room_id), + externalSenderId: externalEvent.sender, + roleChangesToApply: createExternalRolesChangesActions( + externalEvent.content?.users, + (externalEvent.prev_content as IMatrixEventContentRoomPowerLevelsChanged)?.users || {}, + ), + }); + } } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/UserReceiver.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/UserReceiver.ts new file mode 100644 index 0000000000000..3f6e3563c5ec1 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/converters/UserReceiver.ts @@ -0,0 +1,14 @@ +import { FederationUserTypingStatusEventDto } from '../../../application/listener/input/UserReceiverDto'; +import type { MatrixEventUserTypingStatusChanged } from '../definitions/events/UserTypingStatusChanged'; +import { convertExternalRoomIdToInternalRoomIdFormat } from './RoomReceiver'; + +export class MatrixUserReceiverConverter { + public static toUserTypingDto(externalEvent: MatrixEventUserTypingStatusChanged): FederationUserTypingStatusEventDto { + return new FederationUserTypingStatusEventDto({ + externalEventId: '', + externalRoomId: externalEvent.room_id, + externalUserIdsTyping: externalEvent.content.user_ids, + normalizedRoomId: convertExternalRoomIdToInternalRoomIdFormat(externalEvent.room_id), + }); + } +} diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/AbstractMatrixEvent.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/AbstractMatrixEvent.ts index 4f141e8cabbb2..cf7a1e9a77a87 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/AbstractMatrixEvent.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/AbstractMatrixEvent.ts @@ -15,8 +15,12 @@ export abstract class AbstractMatrixEvent { public unsigned: { age: number; invite_room_state: AbstractMatrixEvent[] }; + public prev_content: IBaseEventContent; + public user_id: string; + public redacts?: string; + public abstract content: IBaseEventContent; public abstract type: string; diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixEventType.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixEventType.ts index fd0fa4b219245..0601aa944d8cc 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixEventType.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixEventType.ts @@ -4,9 +4,9 @@ export enum MatrixEventType { ROOM_MESSAGE_SENT = 'm.room.message', ROOM_JOIN_RULES_CHANGED = 'm.room.join_rules', ROOM_NAME_CHANGED = 'm.room.name', - // SET_ROOM_POWER_LEVELS = 'm.room.power_levels', - // SET_ROOM_CANONICAL_ALIAS = 'm.room.canonical_alias', - // SET_ROOM_HISTORY_VISIBILITY = 'm.room.history_visibility', - // SET_ROOM_GUEST_ACCESS = 'm.room.guest_access', + ROOM_POWER_LEVELS_CHANGED = 'm.room.power_levels', ROOM_TOPIC_CHANGED = 'm.room.topic', + ROOM_EVENT_REDACTED = 'm.room.redaction', + MESSAGE_REACTED = 'm.reaction', + USER_TYPING_STATUS_CHANGED = 'm.typing', } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixPowerLevels.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixPowerLevels.ts new file mode 100644 index 0000000000000..ad69516a159cf --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixPowerLevels.ts @@ -0,0 +1,5 @@ +export enum MATRIX_POWER_LEVELS { + USER = 0, + MODERATOR = 50, + ADMIN = 100, +} diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomJoinRules.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomJoinRules.ts index 9b9865feada6f..8639061a31f0d 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomJoinRules.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomJoinRules.ts @@ -1,4 +1,5 @@ export enum MatrixRoomJoinRules { JOIN = 'public', INVITE = 'invite', + KNOCK = 'knock', } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomVisibility.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomVisibility.ts index 0256caac480ca..06b854b8f2a15 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomVisibility.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/MatrixRoomVisibility.ts @@ -1,4 +1,4 @@ export enum MatrixRoomVisibility { PRIVATE = 'private', - PUBLIC = 'public ', + PUBLIC = 'public', } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/MessageReacted.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/MessageReacted.ts new file mode 100644 index 0000000000000..9275ca423ce4c --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/MessageReacted.ts @@ -0,0 +1,17 @@ +import type { IBaseEventContent } from '../AbstractMatrixEvent'; +import { AbstractMatrixEvent } from '../AbstractMatrixEvent'; +import { MatrixEventType } from '../MatrixEventType'; + +export interface IMatrixEventContentMessageReacted extends IBaseEventContent { + 'm.relates_to': { + event_id: string; + key: string; + rel_type: string; + }; +} + +export class MatrixEventMessageReact extends AbstractMatrixEvent { + public content: IMatrixEventContentMessageReacted; + + public type = MatrixEventType.MESSAGE_REACTED; +} diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomCreated.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomCreated.ts index 7518c19f7f254..8167dcc142226 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomCreated.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomCreated.ts @@ -7,6 +7,7 @@ export interface IMatrixEventContentRoomCreated extends IBaseEventContent { room_version: string; was_internally_programatically_created?: boolean; internalRoomId?: string; + inviteesExternalIds?: string[]; } export class MatrixEventRoomCreated extends AbstractMatrixEvent { diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomEventRedacted.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomEventRedacted.ts new file mode 100644 index 0000000000000..93dd83fb85f98 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomEventRedacted.ts @@ -0,0 +1,11 @@ +import type { IBaseEventContent } from '../AbstractMatrixEvent'; +import { AbstractMatrixEvent } from '../AbstractMatrixEvent'; +import { MatrixEventType } from '../MatrixEventType'; + +export type IMatrixEventContentRoomRedacted = IBaseEventContent; + +export class MatrixEventRoomRedacted extends AbstractMatrixEvent { + public content: IMatrixEventContentRoomRedacted; + + public type = MatrixEventType.ROOM_EVENT_REDACTED; +} diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomMembershipChanged.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomMembershipChanged.ts index a4015d41b8595..214ce2ef35c76 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomMembershipChanged.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomMembershipChanged.ts @@ -12,6 +12,7 @@ export interface IMatrixEventContentRoomMembershipChanged extends IBaseEventCont displayname: string; membership: RoomMembershipChangedEventType; is_direct?: boolean; + avatar_url?: string; } export class MatrixEventRoomMembershipChanged extends AbstractMatrixEvent { diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomMessageSent.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomMessageSent.ts index 52ad3de06b94b..e33d19a2027ed 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomMessageSent.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomMessageSent.ts @@ -2,13 +2,52 @@ import type { IBaseEventContent } from '../AbstractMatrixEvent'; import { AbstractMatrixEvent } from '../AbstractMatrixEvent'; import { MatrixEventType } from '../MatrixEventType'; -export enum MatrixSendMessageType { - 'm.text', +type MatrixSendMessageType = 'm.text' | 'm.emote' | 'm.notice' | 'm.image' | 'm.file' | 'm.audio' | 'm.location' | 'm.video' | string; + +export enum MatrixEnumSendMessageType { + TEXT = 'm.text', + EMOTE = 'm.emote', + NOTICE = 'm.notice', + IMAGE = 'm.image', + FILE = 'm.file', + AUDIO = 'm.audio', + LOCATION = 'm.location', + VIDEO = 'm.video', +} + +interface IMatrixContentInfo { + mimetype: string; + size: number; + duration?: number; +} + +type MatrixRelatesToRelType = 'm.replace'; + +export enum MatrixEnumRelatesToRelType { + REPLACE = 'm.replace', } export interface IMatrixEventContentRoomMessageSent extends IBaseEventContent { - body: string; - msgtype: MatrixSendMessageType; + 'body': string; + 'msgtype': MatrixSendMessageType; + 'info'?: IMatrixContentInfo; + 'url'?: string; + 'format'?: string; + 'formatted_body'?: string; + 'geo_uri'?: string; + 'm.new_content'?: { + body: string; + msgtype: MatrixSendMessageType; + format?: string; + formatted_body?: string; + }; + 'm.relates_to'?: { + 'rel_type': MatrixRelatesToRelType; + 'event_id': string; + 'm.in_reply_to'?: { + event_id: string; + }; + }; } export class MatrixEventRoomMessageSent extends AbstractMatrixEvent { diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomPowerLevelsChanged.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomPowerLevelsChanged.ts new file mode 100644 index 0000000000000..69cf940cbc8c9 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/RoomPowerLevelsChanged.ts @@ -0,0 +1,37 @@ +import type { IBaseEventContent } from '../AbstractMatrixEvent'; +import { AbstractMatrixEvent } from '../AbstractMatrixEvent'; +import { MatrixEventType } from '../MatrixEventType'; + +export enum RoomMembershipChangedEventType { + JOIN = 'join', + INVITE = 'invite', + LEAVE = 'leave', +} + +export interface IMatrixEventContentRoomPowerLevelsChanged extends IBaseEventContent { + ban: number; + events: { + 'm.room.avatar': number; + 'm.room.canonical_alias': number; + 'm.room.encryption': number; + 'm.room.history_visibility': number; + 'm.room.name': number; + 'm.room.power_levels': number; + 'm.room.server_acl': number; + 'm.room.tombstone': number; + }; + events_default: number; + historical: number; + invite: number; + kick: number; + redact: number; + state_default: number; + users: Record; + users_default: number; +} + +export class MatrixEventRoomRoomPowerLevelsChanged extends AbstractMatrixEvent { + public content: IMatrixEventContentRoomPowerLevelsChanged; + + public type = MatrixEventType.ROOM_POWER_LEVELS_CHANGED; +} diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/UserTypingStatusChanged.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/UserTypingStatusChanged.ts new file mode 100644 index 0000000000000..97607da44301d --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/definitions/events/UserTypingStatusChanged.ts @@ -0,0 +1,13 @@ +import type { IBaseEventContent } from '../AbstractMatrixEvent'; +import { AbstractMatrixEvent } from '../AbstractMatrixEvent'; +import { MatrixEventType } from '../MatrixEventType'; + +export interface IMatrixEventContentUserTypingStatusChanged extends IBaseEventContent { + user_ids: string[]; +} + +export class MatrixEventUserTypingStatusChanged extends AbstractMatrixEvent { + public content: IMatrixEventContentUserTypingStatusChanged; + + public type = MatrixEventType.USER_TYPING_STATUS_CHANGED; +} diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/Message.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/Message.ts new file mode 100644 index 0000000000000..67a754b2dd048 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/Message.ts @@ -0,0 +1,17 @@ +import type { FederationMessageServiceListener } from '../../../application/listener/MessageServiceListener'; +import { MatrixMessageReceiverConverter } from '../converters/MessageReceiver'; +import type { MatrixEventMessageReact } from '../definitions/events/MessageReacted'; +import { MatrixEventType } from '../definitions/MatrixEventType'; +import { MatrixBaseEventHandler } from './BaseEvent'; + +export class MatrixMessageReactedHandler extends MatrixBaseEventHandler { + public eventType: string = MatrixEventType.MESSAGE_REACTED; + + constructor(private messageService: FederationMessageServiceListener) { + super(); + } + + public async handle(externalEvent: MatrixEventMessageReact): Promise { + await this.messageService.onMessageReaction(MatrixMessageReceiverConverter.toMessageReactionDto(externalEvent)); + } +} diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/Room.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/Room.ts index b9d596cefbd7f..bc08ad73da7ad 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/Room.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/Room.ts @@ -1,4 +1,4 @@ -import type { FederationRoomServiceListener } from '../../../application/RoomServiceListener'; +import type { FederationRoomServiceListener } from '../../../application/listener/RoomServiceListener'; import type { RocketChatSettingsAdapter } from '../../rocket-chat/adapters/Settings'; import { MatrixRoomReceiverConverter } from '../converters/RoomReceiver'; import { MatrixBaseEventHandler } from './BaseEvent'; @@ -6,9 +6,12 @@ import type { MatrixEventRoomCreated } from '../definitions/events/RoomCreated'; import type { MatrixEventRoomMembershipChanged } from '../definitions/events/RoomMembershipChanged'; import type { MatrixEventRoomJoinRulesChanged } from '../definitions/events/RoomJoinRulesChanged'; import type { MatrixEventRoomNameChanged } from '../definitions/events/RoomNameChanged'; -import type { MatrixEventRoomMessageSent } from '../definitions/events/RoomMessageSent'; +import type { IMatrixEventContentRoomMessageSent, MatrixEventRoomMessageSent } from '../definitions/events/RoomMessageSent'; +import { MatrixEnumRelatesToRelType, MatrixEnumSendMessageType } from '../definitions/events/RoomMessageSent'; import type { MatrixEventRoomTopicChanged } from '../definitions/events/RoomTopicChanged'; import { MatrixEventType } from '../definitions/MatrixEventType'; +import type { MatrixEventRoomRedacted } from '../definitions/events/RoomEventRedacted'; +import type { MatrixEventRoomRoomPowerLevelsChanged } from '../definitions/events/RoomPowerLevelsChanged'; export class MatrixRoomCreatedHandler extends MatrixBaseEventHandler { public eventType: string = MatrixEventType.ROOM_CREATED; @@ -43,8 +46,39 @@ export class MatrixRoomMessageSentHandler extends MatrixBaseEventHandler { super(); } + private executeTextMessageHandler(eventContent: IMatrixEventContentRoomMessageSent, externalEvent: MatrixEventRoomMessageSent): any { + const isAnEditionEvent = + eventContent['m.new_content'] && + eventContent['m.relates_to'] && + eventContent['m.relates_to'].rel_type === MatrixEnumRelatesToRelType.REPLACE; + return isAnEditionEvent + ? this.roomService.onExternalMessageEditedReceived(MatrixRoomReceiverConverter.toEditRoomMessageDto(externalEvent)) + : this.roomService.onExternalMessageReceived(MatrixRoomReceiverConverter.toSendRoomMessageDto(externalEvent)); + } + public async handle(externalEvent: MatrixEventRoomMessageSent): Promise { - await this.roomService.onExternalMessageReceived(MatrixRoomReceiverConverter.toSendRoomMessageDto(externalEvent)); + const handlers = { + [MatrixEnumSendMessageType.TEXT]: () => this.executeTextMessageHandler(externalEvent.content, externalEvent), + [MatrixEnumSendMessageType.AUDIO]: () => + this.roomService.onExternalFileMessageReceived(MatrixRoomReceiverConverter.toSendRoomFileMessageDto(externalEvent)), + [MatrixEnumSendMessageType.FILE]: () => + this.roomService.onExternalFileMessageReceived(MatrixRoomReceiverConverter.toSendRoomFileMessageDto(externalEvent)), + [MatrixEnumSendMessageType.IMAGE]: () => + this.roomService.onExternalFileMessageReceived(MatrixRoomReceiverConverter.toSendRoomFileMessageDto(externalEvent)), + [MatrixEnumSendMessageType.NOTICE]: () => + this.roomService.onExternalMessageReceived(MatrixRoomReceiverConverter.toSendRoomMessageDto(externalEvent)), + [MatrixEnumSendMessageType.VIDEO]: () => + this.roomService.onExternalFileMessageReceived(MatrixRoomReceiverConverter.toSendRoomFileMessageDto(externalEvent)), + [MatrixEnumSendMessageType.EMOTE]: () => + this.roomService.onExternalMessageReceived(MatrixRoomReceiverConverter.toSendRoomMessageDto(externalEvent)), + [MatrixEnumSendMessageType.LOCATION]: () => { + throw new Error('Location events are not supported yet'); + }, + }; + const defaultHandler = () => + this.roomService.onExternalMessageReceived(MatrixRoomReceiverConverter.toSendRoomMessageDto(externalEvent)); + + await (handlers[externalEvent.content.msgtype as MatrixEnumSendMessageType] || defaultHandler)(); } } @@ -83,3 +117,27 @@ export class MatrixRoomTopicChangedHandler extends MatrixBaseEventHandler { await this.roomService.onChangeRoomTopic(MatrixRoomReceiverConverter.toRoomChangeTopicDto(externalEvent)); } } + +export class MatrixRoomEventRedactedHandler extends MatrixBaseEventHandler { + public eventType: string = MatrixEventType.ROOM_EVENT_REDACTED; + + constructor(private roomService: FederationRoomServiceListener) { + super(); + } + + public async handle(externalEvent: MatrixEventRoomRedacted): Promise { + await this.roomService.onRedactEvent(MatrixRoomReceiverConverter.toRoomRedactEventDto(externalEvent)); + } +} + +export class MatrixRoomPowerLevelsChangedHandler extends MatrixBaseEventHandler { + public eventType: string = MatrixEventType.ROOM_POWER_LEVELS_CHANGED; + + constructor(private roomService: FederationRoomServiceListener) { + super(); + } + + public async handle(externalEvent: MatrixEventRoomRoomPowerLevelsChanged): Promise { + await this.roomService.onChangeRoomPowerLevels(MatrixRoomReceiverConverter.toRoomChangePowerLevelsEventDto(externalEvent)); + } +} diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/User.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/User.ts new file mode 100644 index 0000000000000..5083d7d9544cc --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/User.ts @@ -0,0 +1,17 @@ +import { MatrixBaseEventHandler } from './BaseEvent'; +import { MatrixEventType } from '../definitions/MatrixEventType'; +import { MatrixUserReceiverConverter } from '../converters/UserReceiver'; +import type { FederationUserServiceListener } from '../../../application/listener/UserServiceListener'; +import type { MatrixEventUserTypingStatusChanged } from '../definitions/events/UserTypingStatusChanged'; + +export class MatrixUserTypingStatusChangedHandler extends MatrixBaseEventHandler { + public eventType: string = MatrixEventType.USER_TYPING_STATUS_CHANGED; + + constructor(private userService: FederationUserServiceListener) { + super(); + } + + public async handle(externalEvent: MatrixEventUserTypingStatusChanged): Promise { + await this.userService.onUserTyping(MatrixUserReceiverConverter.toUserTypingDto(externalEvent)); + } +} diff --git a/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/index.ts b/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/index.ts index d99a39edbf3ad..47469b74320b1 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/index.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/matrix/handlers/index.ts @@ -10,6 +10,10 @@ export class MatrixEventsHandler { if (!handler) { return console.log(`Could not find handler for ${event.type}`, event); } - return handler.handle(event); + try { + await handler.handle(event); + } catch (e: any) { + throw new Meteor.Error(e.message); + } } } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/File.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/File.ts new file mode 100644 index 0000000000000..0da8e901e693b --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/File.ts @@ -0,0 +1,86 @@ +import { Avatars, Uploads } from '@rocket.chat/models'; +import { Meteor } from 'meteor/meteor'; +import type { IMessage, IUpload, IUser } from '@rocket.chat/core-typings'; + +import { FileUpload } from '../../../../../file-upload/server'; +import { parseFileIntoMessageAttachments } from '../../../../../file-upload/server/methods/sendFileMessage'; + +export interface IAvatarMetadataFile { + type: string; + name: string; +} + +export class RocketChatFileAdapter { + public async uploadFile( + readableStream: ReadableStream, + internalRoomId: string, + internalUser: IUser, + fileRecord: Partial, + ): Promise<{ files: IMessage['files']; attachments: IMessage['attachments'] }> { + return new Promise<{ files: IMessage['files']; attachments: IMessage['attachments'] }>((resolve, reject) => { + const fileStore = FileUpload.getStore('Uploads'); + // this needs to be here due to a high coupling in the third party lib that rely on the logged in user + Meteor.runAsUser(internalUser._id, async () => { + const uploadedFile = fileStore.insertSync(fileRecord, readableStream); + try { + const { files, attachments } = await parseFileIntoMessageAttachments(uploadedFile, internalRoomId, internalUser); + + resolve({ files, attachments }); + } catch (error) { + reject(error); + } + }); + }); + } + + public async getBufferFromFileRecord(fileRecord: IUpload): Promise { + return new Promise((resolve, reject) => { + FileUpload.getBuffer(fileRecord, (err: Error, buffer: Buffer) => { + if (err) { + return reject(err); + } + resolve(buffer); + }); + }); + } + + public async getFileRecordById(fileId: string): Promise { + return Uploads.findOneById(fileId); + } + + public async extractMetadataFromFile(file: IUpload): Promise<{ height?: number; width?: number; format?: string }> { + if (file.type?.startsWith('image/')) { + const metadata = await FileUpload.extractMetadata(file); + + return { + format: metadata.format, + height: metadata.height, + width: metadata.width, + }; + } + if (file.type?.startsWith('video/')) { + return { + height: 200, + width: 250, + }; + } + return {}; + } + + public async getBufferForAvatarFile(username: string): Promise { + const file = (await Avatars.findOneByName(username)) as Record; + if (!file?._id) { + return; + } + return FileUpload.getBufferSync(file); + } + + public async getFileMetadataForAvatarFile(username: string): Promise { + const file = (await Avatars.findOneByName(username)) as Record; + + return { + type: file.type, + name: file.name, + }; + } +} diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Message.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Message.ts index 9b5761b47e630..4c45ea739d7e3 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Message.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Message.ts @@ -1,9 +1,251 @@ -import { sendMessage } from '../../../../../lib/server'; +import { Meteor } from 'meteor/meteor'; +import type { IMessage } from '@rocket.chat/core-typings'; +import { isQuoteAttachment } from '@rocket.chat/core-typings'; +import { Messages } from '@rocket.chat/models'; + +import { deleteMessage, sendMessage, updateMessage } from '../../../../../lib/server'; +import { executeSetReaction } from '../../../../../reactions/server/setReaction'; import type { FederatedRoom } from '../../../domain/FederatedRoom'; import type { FederatedUser } from '../../../domain/FederatedUser'; +import { roomCoordinator } from '../../../../../../server/lib/rooms/roomCoordinator'; +import { getURL } from '../../../../../utils/server'; +import { toInternalMessageFormat, toInternalQuoteMessageFormat } from '../converters/MessageTextParser'; + +const DEFAULT_EMOJI_TO_REACT_WHEN_RECEIVED_EMOJI_DOES_NOT_EXIST = ':grey_question:'; export class RocketChatMessageAdapter { - public async sendMessage(user: FederatedUser, room: FederatedRoom, messageText: string): Promise { - sendMessage(user.getInternalReference(), { msg: messageText }, room.getInternalReference()); + public async sendMessage( + user: FederatedUser, + room: FederatedRoom, + rawMessage: string, + externalFormattedMessage: string, + externalEventId: string, + homeServerDomain: string, + ): Promise { + sendMessage( + user.getInternalReference(), + { + federation: { eventId: externalEventId }, + msg: toInternalMessageFormat({ + rawMessage, + formattedMessage: externalFormattedMessage, + homeServerDomain, + senderExternalId: user.getExternalId(), + }), + }, + room.getInternalReference(), + ); + } + + public async sendQuoteMessage( + user: FederatedUser, + federatedRoom: FederatedRoom, + externalFormattedText: string, + rawMessage: string, + externalEventId: string, + messageToReplyTo: IMessage, + homeServerDomain: string, + ): Promise { + const room = federatedRoom.getInternalReference(); + sendMessage( + user.getInternalReference(), + { + federation: { eventId: externalEventId }, + msg: await this.getMessageToReplyToWhenQuoting( + federatedRoom, + messageToReplyTo, + externalFormattedText, + rawMessage, + homeServerDomain, + user, + ), + }, + room, + ); + } + + public async editMessage( + user: FederatedUser, + newRawMessageText: string, + newExternalFormattedMessage: string, + originalMessage: IMessage, + homeServerDomain: string, + ): Promise { + const updatedMessage = { + ...originalMessage, + msg: toInternalMessageFormat({ + rawMessage: newRawMessageText, + formattedMessage: newExternalFormattedMessage, + homeServerDomain, + senderExternalId: user.getExternalId(), + }), + }; + updateMessage(updatedMessage, user.getInternalReference(), originalMessage); + } + + private async getMessageToReplyToWhenQuoting( + federatedRoom: FederatedRoom, + messageToReplyTo: IMessage, + externalFormattedMessage: string, + rawMessage: string, + homeServerDomain: string, + senderUser: FederatedUser, + ): Promise { + const room = federatedRoom.getInternalReference(); + const messageToReplyToUrl = getURL( + `${roomCoordinator.getRouteLink(room.t as string, { rid: room._id, name: room.name })}?msg=${messageToReplyTo._id}`, + { full: true }, + ); + return toInternalQuoteMessageFormat({ + messageToReplyToUrl, + formattedMessage: externalFormattedMessage, + rawMessage, + homeServerDomain, + senderExternalId: senderUser.getExternalId(), + }); + } + + public async getMessageToEditWhenReplyAndQuote( + editedMessage: IMessage, + newExternalFormattedMessage: string, + newRawMessageText: string, + homeServerDomain: string, + senderUser: FederatedUser, + ): Promise { + const quotedMessageUrl = editedMessage.attachments?.filter(isQuoteAttachment)?.[0]?.message_link; + + return toInternalQuoteMessageFormat({ + messageToReplyToUrl: quotedMessageUrl || '', + formattedMessage: newExternalFormattedMessage, + rawMessage: newRawMessageText, + homeServerDomain, + senderExternalId: senderUser.getExternalId(), + }); + } + + public async editQuotedMessage( + user: FederatedUser, + newRawMessageText: string, + newExternalFormattedMessage: string, + editedMessage: IMessage, + homeServerDomain: string, + ): Promise { + const updatedMessage = { + ...editedMessage, + msg: await this.getMessageToEditWhenReplyAndQuote( + editedMessage, + newExternalFormattedMessage, + newRawMessageText, + homeServerDomain, + user, + ), + }; + updateMessage(updatedMessage, user.getInternalReference(), editedMessage); + } + + public async sendFileMessage( + user: FederatedUser, + room: FederatedRoom, + files: IMessage['files'], + attachments: IMessage['attachments'], + externalEventId: string, + ): Promise { + sendMessage( + user.getInternalReference(), + { + federation: { eventId: externalEventId }, + rid: room.getInternalId(), + ts: new Date(), + file: (files || [])[0], + files, + attachments, + }, + room.getInternalReference(), + ); + } + + public async sendQuoteFileMessage( + user: FederatedUser, + federatedRoom: FederatedRoom, + files: IMessage['files'], + attachments: IMessage['attachments'], + externalEventId: string, + messageToReplyTo: IMessage, + homeServerDomain: string, + ): Promise { + const room = federatedRoom.getInternalReference(); + + sendMessage( + user.getInternalReference(), + { + federation: { eventId: externalEventId }, + rid: federatedRoom.getInternalId(), + ts: new Date(), + file: (files || [])[0], + files, + attachments, + msg: await this.getMessageToReplyToWhenQuoting(federatedRoom, messageToReplyTo, '', '', homeServerDomain, user), + }, + room, + ); + } + + public async deleteMessage(message: IMessage, user: FederatedUser): Promise { + deleteMessage(message, user.getInternalReference()); + } + + public async reactToMessage(user: FederatedUser, message: IMessage, reaction: string, externalEventId: string): Promise { + // we need to run this as the user due to a high coupling in this function that relies on the logged in user + Meteor.runAsUser(user.getInternalId(), async () => { + try { + await executeSetReaction(reaction, message._id); + user.getUsername() && + (await Messages.setFederationReactionEventId(user.getUsername() as string, message._id, reaction, externalEventId)); + } catch (error: any) { + if (error?.message?.includes('Invalid emoji provided.')) { + await executeSetReaction(DEFAULT_EMOJI_TO_REACT_WHEN_RECEIVED_EMOJI_DOES_NOT_EXIST, message._id); + } + } + }); + } + + public async unreactToMessage(user: FederatedUser, message: IMessage, reaction: string, externalEventId: string): Promise { + // we need to run this as the user due to a high coupling in this function that relies on the logged in user + Meteor.runAsUser(user.getInternalId(), async () => { + await executeSetReaction(reaction, message._id); + await Messages.unsetFederationReactionEventId(externalEventId, message._id, reaction); + }); + } + + public async findOneByFederationIdOnReactions(federationEventId: string, user: FederatedUser): Promise { + return ( + (user.getUsername() && Messages.findOneByFederationIdAndUsernameOnReactions(federationEventId, user.getUsername() as string)) || + undefined + ); + } + + public async getMessageByFederationId(federationEventId: string): Promise { + return Messages.findOneByFederationId(federationEventId); + } + + public async setExternalFederationEventOnMessage(messageId: string, federationEventId: string): Promise { + return Messages.setFederationEventIdById(messageId, federationEventId); + } + + public async unsetExternalFederationEventOnMessageReaction(externalEventId: string, message: IMessage, reaction: string): Promise { + await Messages.unsetFederationReactionEventId(externalEventId, message._id, reaction); + } + + public async getMessageById(internalMessageId: string): Promise { + return Messages.findOneById(internalMessageId); + } + + public async setExternalFederationEventOnMessageReaction( + username: string, + message: IMessage, + reaction: string, + externalEventId: string, + ): Promise { + await Messages.setFederationReactionEventId(username, message._id, reaction, externalEventId); } } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/MessageConverter.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/MessageConverter.ts new file mode 100644 index 0000000000000..0559c471d4e7f --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/MessageConverter.ts @@ -0,0 +1,7 @@ +export const escapeExternalFederationEventId = (externalEventId: string): string => { + return externalEventId.replace(/\$/g, '__sign__'); +}; + +export const unescapeExternalFederationEventId = (externalEventId: string): string => { + return externalEventId.replace(/__sign__/g, '$'); +}; diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Notification.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Notification.ts new file mode 100644 index 0000000000000..e7eb8e5a816ec --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Notification.ts @@ -0,0 +1,47 @@ +import { Rooms } from '@rocket.chat/models'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import { api } from '@rocket.chat/core-services'; + +import notifications from '../../../../../notifications/server/lib/Notifications'; + +export class RocketChatNotificationAdapter { + public async notifyUserTypingOnRoom(internalRoomId: string, username: string, isTyping: boolean): Promise { + notifications.notifyRoom(internalRoomId, 'user-activity', username, isTyping ? ['user-typing'] : []); + } + + public async subscribeToUserTypingEventsOnFederatedRooms( + callback: (username: string, activity: string[], roomId: string) => void, + ): Promise { + await Rooms.findFederatedRooms({ projection: { _id: 1 } }).forEach((room) => + this.subscribeToUserTypingEventsOnFederatedRoomId(room._id, callback), + ); + } + + public subscribeToUserTypingEventsOnFederatedRoomId( + roomId: string, + callback: (username: string, activity: string[], roomId: string) => void, + ): void { + notifications.streamRoom.on(`${roomId}/user-activity`, (username, activity) => { + if (Array.isArray(activity) && (!activity.length || activity.includes('user-typing'))) { + callback(username, activity, roomId); + } + }); + } + + public async broadcastUserTypingOnRoom(username: string, activity: string[], roomId: string): Promise { + api.broadcast('user.typing', { + user: { username }, + isTyping: activity.includes('user-typing'), + roomId, + }); + } + + public notifyWithEphemeralMessage(i18nMessageKey: string, userId: string, roomId: string, language = 'en'): void { + api.broadcast('notify.ephemeralMessage', userId, roomId, { + msg: TAPi18n.__(i18nMessageKey, { + postProcess: 'sprintf', + lng: language, + }), + }); + } +} diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Room.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Room.ts index a773a065a9972..182e7950284d8 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Room.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Room.ts @@ -1,13 +1,16 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { isDirectMessageRoom } from '@rocket.chat/core-typings'; import { Rooms, Subscriptions, MatrixBridgedRoom } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; import { DirectMessageFederatedRoom, FederatedRoom } from '../../../domain/FederatedRoom'; import { createRoom, addUserToRoom, removeUserFromRoom } from '../../../../../lib/server'; import type { FederatedUser } from '../../../domain/FederatedUser'; -import { saveRoomName } from '../../../../../channel-settings/server/functions/saveRoomName'; import { saveRoomTopic } from '../../../../../channel-settings/server/functions/saveRoomTopic'; import { getFederatedUserByInternalUsername } from './User'; +import type { ROCKET_CHAT_FEDERATION_ROLES } from '../definitions/InternalFederatedRoomRoles'; +import { settings } from '../../../../../settings/server'; +import { Messages } from '../../../../../models/server'; export class RocketChatRoomAdapter { public async getFederatedRoomByExternalId(externalRoomId: string): Promise { @@ -37,15 +40,17 @@ export class RocketChatRoomAdapter { return Rooms.findOneById(internalRoomId); } - public async createFederatedRoom(federatedRoom: FederatedRoom): Promise { + public async createFederatedRoom(federatedRoom: FederatedRoom): Promise { const usernameOrId = federatedRoom.getCreatorUsername() || federatedRoom.getCreatorId(); if (!usernameOrId) { throw new Error('Cannot create a room without a creator'); } - const { rid, _id } = createRoom(federatedRoom.getRoomType(), federatedRoom.getName(), usernameOrId); + const { rid, _id } = createRoom(federatedRoom.getRoomType(), federatedRoom.getDisplayName(), usernameOrId); const roomId = rid || _id; await MatrixBridgedRoom.createOrUpdateByLocalRoomId(roomId, federatedRoom.getExternalId()); await Rooms.setAsFederated(roomId); + + return roomId; } public async removeDirectMessageRoom(federatedRoom: FederatedRoom): Promise { @@ -55,7 +60,7 @@ export class RocketChatRoomAdapter { await MatrixBridgedRoom.removeByLocalRoomId(roomId); } - public async createFederatedRoomForDirectMessage(federatedRoom: DirectMessageFederatedRoom): Promise { + public async createFederatedRoomForDirectMessage(federatedRoom: DirectMessageFederatedRoom): Promise { const creatorId = federatedRoom.getCreatorId(); const usernameOrId = federatedRoom.getCreatorUsername() || creatorId; if (!usernameOrId) { @@ -69,7 +74,7 @@ export class RocketChatRoomAdapter { const extraData = undefined; const { rid, _id } = createRoom( federatedRoom.getRoomType(), - federatedRoom.getName(), + federatedRoom.getDisplayName(), usernameOrId, federatedRoom.getMembersUsernames(), readonly, @@ -79,6 +84,8 @@ export class RocketChatRoomAdapter { const roomId = rid || _id; await MatrixBridgedRoom.createOrUpdateByLocalRoomId(roomId, federatedRoom.getExternalId()); await Rooms.setAsFederated(roomId); + + return roomId; } public async getDirectMessageFederatedRoomByUserIds(userIds: string[]): Promise { @@ -96,8 +103,8 @@ export class RocketChatRoomAdapter { } } - public async addUserToRoom(federatedRoom: FederatedRoom, inviteeUser: FederatedUser, inviterUser: FederatedUser): Promise { - addUserToRoom(federatedRoom.getInternalId(), inviteeUser.getInternalReference(), inviterUser.getInternalReference()); + public async addUserToRoom(federatedRoom: FederatedRoom, inviteeUser: FederatedUser, inviterUser?: FederatedUser): Promise { + addUserToRoom(federatedRoom.getInternalId(), inviteeUser.getInternalReference(), inviterUser?.getInternalReference()); } public async removeUserFromRoom(federatedRoom: FederatedRoom, affectedUser: FederatedUser, byUser: FederatedUser): Promise { @@ -117,8 +124,27 @@ export class RocketChatRoomAdapter { await Subscriptions.updateAllRoomTypesByRoomId(federatedRoom.getRoomType(), federatedRoom.getRoomType()); } - public async updateRoomName(federatedRoom: FederatedRoom, federatedUser: FederatedUser): Promise { - await saveRoomName(federatedRoom.getInternalId(), federatedRoom.getName(), federatedUser.getInternalReference()); + public async updateDisplayRoomName(federatedRoom: FederatedRoom, federatedUser: FederatedUser): Promise { + await Rooms.setFnameById(federatedRoom.getInternalId(), federatedRoom.getDisplayName()); + await Subscriptions.updateNameAndFnameByRoomId( + federatedRoom.getInternalId(), + federatedRoom.getName() || '', + federatedRoom.getDisplayName() || '', + ); + Messages.createRoomRenamedWithRoomIdRoomNameAndUser( + federatedRoom.getInternalId(), + federatedRoom.getDisplayName(), + federatedUser.getInternalReference(), + ); + } + + public async updateRoomName(federatedRoom: FederatedRoom): Promise { + await Rooms.setRoomNameById(federatedRoom.getInternalId(), federatedRoom.getName()); + await Subscriptions.updateNameAndFnameByRoomId( + federatedRoom.getInternalId(), + federatedRoom.getName() || '', + federatedRoom.getDisplayName() || '', + ); } public async updateRoomTopic(federatedRoom: FederatedRoom, federatedUser: FederatedUser): Promise { @@ -140,4 +166,110 @@ export class RocketChatRoomAdapter { await MatrixBridgedRoom.createOrUpdateByLocalRoomId(internalRoomId, externalRoomId); await Rooms.setAsFederated(internalRoomId); } + + public async getInternalRoomRolesByUserId(internalRoomId: string, internalUserId: string): Promise { + const subscription = await Subscriptions.findOneByRoomIdAndUserId(internalRoomId, internalUserId, { projection: { roles: 1 } }); + if (!subscription) { + return []; + } + return subscription.roles || []; + } + + public async applyRoomRolesToUser({ + federatedRoom, + fromUser, + targetFederatedUser, + notifyChannel, + rolesToAdd, + rolesToRemove, + }: { + federatedRoom: FederatedRoom; + targetFederatedUser: FederatedUser; + fromUser: FederatedUser; + rolesToAdd: ROCKET_CHAT_FEDERATION_ROLES[]; + rolesToRemove: ROCKET_CHAT_FEDERATION_ROLES[]; + notifyChannel: boolean; + }): Promise { + const subscription = await Subscriptions.findOneByRoomIdAndUserId(federatedRoom.getInternalId(), targetFederatedUser.getInternalId(), { + projection: { roles: 1 }, + }); + if (!subscription) { + return; + } + const { roles: currentRoles = [] } = subscription; + const toAdd = rolesToAdd.filter((role) => !currentRoles.includes(role)); + const toRemove = rolesToRemove.filter((role) => currentRoles.includes(role)); + const whoDidTheChange = { + _id: fromUser.getInternalId(), + username: fromUser.getUsername(), + }; + if (toAdd.length > 0) { + await Subscriptions.addRolesByUserId(targetFederatedUser.getInternalId(), toAdd, federatedRoom.getInternalId()); + if (notifyChannel) { + await Promise.all( + toAdd.map((role) => + Messages.createSubscriptionRoleAddedWithRoomIdAndUser( + federatedRoom.getInternalId(), + targetFederatedUser.getInternalReference(), + { + u: whoDidTheChange, + role, + }, + ), + ), + ); + } + } + if (toRemove.length > 0) { + await Subscriptions.removeRolesByUserId(targetFederatedUser.getInternalId(), toRemove, federatedRoom.getInternalId()); + if (notifyChannel) { + await Promise.all( + toRemove.map((role) => + Messages.createSubscriptionRoleRemovedWithRoomIdAndUser( + federatedRoom.getInternalId(), + targetFederatedUser.getInternalReference(), + { + u: whoDidTheChange, + role, + }, + ), + ), + ); + } + } + if (settings.get('UI_DisplayRoles')) { + this.notifyUIAboutRoomRolesChange(targetFederatedUser, federatedRoom, toAdd, toRemove); + } + } + + private notifyUIAboutRoomRolesChange( + targetFederatedUser: FederatedUser, + federatedRoom: FederatedRoom, + addedRoles: ROCKET_CHAT_FEDERATION_ROLES[], + removedRoles: ROCKET_CHAT_FEDERATION_ROLES[], + ): void { + const eventsForAddedRoles = addedRoles.map((role) => this.createRoleUpdateEvent(targetFederatedUser, federatedRoom, role, 'added')); + const eventsForRemovedRoles = removedRoles.map((role) => + this.createRoleUpdateEvent(targetFederatedUser, federatedRoom, role, 'removed'), + ); + [...eventsForAddedRoles, ...eventsForRemovedRoles].forEach((event) => api.broadcast('user.roleUpdate', event)); + } + + private createRoleUpdateEvent( + federatedUser: FederatedUser, + federatedRoom: FederatedRoom, + role: string, + action: 'added' | 'removed', + ): Record { + return { + type: action, + _id: role, + u: { + _id: federatedUser.getInternalId(), + username: federatedUser.getUsername(), + name: federatedUser.getName(), + }, + scope: federatedRoom.getInternalId(), + }; + } } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Settings.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Settings.ts index 9c85e1ffd7d76..c4e43678c64ec 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Settings.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/Settings.ts @@ -1,11 +1,13 @@ import crypto from 'crypto'; +import fs from 'fs'; +import { resolve } from 'path'; import yaml from 'js-yaml'; import { v4 as uuidv4 } from 'uuid'; import { Settings } from '@rocket.chat/models'; import { settings, settingsRegistry } from '../../../../../settings/server'; -import type { IFederationBridgeRegistrationFile } from '../../matrix/Bridge'; +import type { IFederationBridgeRegistrationFile } from '../../../domain/IFederationBridge'; const EVERYTHING_REGEX = '.*'; const LISTEN_RULES = EVERYTHING_REGEX; @@ -14,6 +16,7 @@ export class RocketChatSettingsAdapter { public initialize(): void { this.addFederationSettings(); this.watchChangesAndUpdateRegistrationFile(); + this.updateSettingsWithProvidedConfigFileIfNecessary(); } public getApplicationServiceId(): string { @@ -58,7 +61,25 @@ export class RocketChatSettingsAdapter { return settings.get('Federation_Matrix_enabled') === true; } - public onFederationEnabledStatusChanged(callback: (enabled: boolean) => Promise): () => void { + public areEphemeralEventsEnabled(): boolean { + return this.isTypingStatusEnabled(); + } + + public isTypingStatusEnabled(): boolean { + return this.getRegistrationFileFromHomeserver()?.enableEphemeralEvents === true; + } + + public onFederationEnabledStatusChanged( + callback: ( + enabled: boolean, + appServiceId: string, + homeServerUrl: string, + homeServerDomain: string, + bridgeUrl: string, + bridgePort: number, + homeServerRegistrationFile: IFederationBridgeRegistrationFile, + ) => Promise, + ): () => void { return settings.watchMultiple( [ 'Federation_Matrix_enabled', @@ -70,7 +91,18 @@ export class RocketChatSettingsAdapter { 'Federation_Matrix_bridge_url', 'Federation_Matrix_bridge_localpart', ], - ([enabled]) => Promise.await(callback(enabled === true)), + ([enabled]) => + Promise.await( + callback( + enabled === true, + this.getApplicationServiceId(), + this.getHomeServerUrl(), + this.getHomeServerDomain(), + this.getBridgeUrl(), + this.getBridgePort(), + this.generateRegistrationFileObject(), + ), + ), ); } @@ -81,6 +113,7 @@ export class RocketChatSettingsAdapter { applicationServiceToken: this.getApplicationApplicationServiceToken(), bridgeUrl: this.getBridgeUrl(), botName: this.getBridgeBotUsername(), + enableEphemeralEvents: this.areEphemeralEventsEnabled(), listenTo: { users: [ { @@ -106,15 +139,17 @@ export class RocketChatSettingsAdapter { private async updateRegistrationFile(): Promise { const registrationFile = this.generateRegistrationFileObject(); + await Settings.updateValueById( 'Federation_Matrix_registration_file', yaml.dump({ - id: registrationFile.id, - hs_token: registrationFile.homeserverToken, - as_token: registrationFile.applicationServiceToken, - url: registrationFile.bridgeUrl, - sender_localpart: registrationFile.botName, - namespaces: registrationFile.listenTo, + 'id': registrationFile.id, + 'hs_token': registrationFile.homeserverToken, + 'as_token': registrationFile.applicationServiceToken, + 'url': registrationFile.bridgeUrl, + 'sender_localpart': registrationFile.botName, + 'namespaces': registrationFile.listenTo, + 'de.sorunome.msc2409.push_ephemeral': registrationFile.enableEphemeralEvents, }), ); } @@ -135,9 +170,11 @@ export class RocketChatSettingsAdapter { } private addFederationSettings(): void { + const preExistingConfiguration = this.getRegistrationFileFromHomeserver(); + settingsRegistry.addGroup('Federation', function () { this.section('Matrix Bridge', function () { - this.add('Federation_Matrix_enabled', false, { + this.add('Federation_Matrix_enabled', Boolean(preExistingConfiguration), { readonly: false, type: 'boolean', i18nLabel: 'Federation_Matrix_enabled', @@ -150,48 +187,48 @@ export class RocketChatSettingsAdapter { const homeserverToken = crypto.createHash('sha256').update(`hs_${uniqueId}`).digest('hex'); const applicationServiceToken = crypto.createHash('sha256').update(`as_${uniqueId}`).digest('hex'); - this.add('Federation_Matrix_id', `rocketchat_${uniqueId}`, { + this.add('Federation_Matrix_id', preExistingConfiguration?.id || `rocketchat_${uniqueId}`, { readonly: true, type: 'string', i18nLabel: 'Federation_Matrix_id', i18nDescription: 'Federation_Matrix_id_desc', }); - this.add('Federation_Matrix_hs_token', homeserverToken, { + this.add('Federation_Matrix_hs_token', preExistingConfiguration?.homeserverToken || homeserverToken, { readonly: true, type: 'string', i18nLabel: 'Federation_Matrix_hs_token', i18nDescription: 'Federation_Matrix_hs_token_desc', }); - this.add('Federation_Matrix_as_token', applicationServiceToken, { + this.add('Federation_Matrix_as_token', preExistingConfiguration?.applicationServiceToken || applicationServiceToken, { readonly: true, type: 'string', i18nLabel: 'Federation_Matrix_as_token', i18nDescription: 'Federation_Matrix_as_token_desc', }); - this.add('Federation_Matrix_homeserver_url', 'http://localhost:8008', { + this.add('Federation_Matrix_homeserver_url', preExistingConfiguration?.rocketchat?.homeServerUrl || 'http://localhost:8008', { type: 'string', i18nLabel: 'Federation_Matrix_homeserver_url', i18nDescription: 'Federation_Matrix_homeserver_url_desc', alert: 'Federation_Matrix_homeserver_url_alert', }); - this.add('Federation_Matrix_homeserver_domain', 'local.rocket.chat', { + this.add('Federation_Matrix_homeserver_domain', preExistingConfiguration?.rocketchat?.domainName || 'local.rocket.chat', { type: 'string', i18nLabel: 'Federation_Matrix_homeserver_domain', i18nDescription: 'Federation_Matrix_homeserver_domain_desc', alert: 'Federation_Matrix_homeserver_domain_alert', }); - this.add('Federation_Matrix_bridge_url', 'http://host.docker.internal:3300', { + this.add('Federation_Matrix_bridge_url', preExistingConfiguration?.bridgeUrl || 'http://host.docker.internal:3300', { type: 'string', i18nLabel: 'Federation_Matrix_bridge_url', i18nDescription: 'Federation_Matrix_bridge_url_desc', }); - this.add('Federation_Matrix_bridge_localpart', 'rocket.cat', { + this.add('Federation_Matrix_bridge_localpart', preExistingConfiguration?.botName || 'rocket.cat', { type: 'string', i18nLabel: 'Federation_Matrix_bridge_localpart', i18nDescription: 'Federation_Matrix_bridge_localpart_desc', @@ -199,11 +236,56 @@ export class RocketChatSettingsAdapter { this.add('Federation_Matrix_registration_file', '', { readonly: true, + hidden: Boolean(preExistingConfiguration), type: 'code', i18nLabel: 'Federation_Matrix_registration_file', i18nDescription: 'Federation_Matrix_registration_file_desc', + alert: 'Federation_Matrix_registration_file_Alert', }); }); }); } + + private getRegistrationFileFromHomeserver(): Record | undefined { + try { + const registrationYaml = fs.readFileSync(this.getFilePathForHomeserverConfig(), 'utf8'); + + const parsedFile = yaml.load(registrationYaml as string) as Record; + return { + applicationServiceToken: parsedFile.as_token, + bridgeUrl: parsedFile.url, + botName: parsedFile.sender_localpart, + homeserverToken: parsedFile.hs_token, + id: parsedFile.id, + listenTo: parsedFile.namespaces, + enableEphemeralEvents: parsedFile['de.sorunome.msc2409.push_ephemeral'], + rocketchat: { domainName: parsedFile.rocketchat?.homeserver_domain, homeServerUrl: parsedFile.rocketchat?.homeserver_url }, + }; + } catch (e) { + // no-op + } + } + + private getFilePathForHomeserverConfig(): string { + return process.env.NODE_ENV === 'development' + ? '../../../../../matrix-federation-config/registration.yaml' + : resolve(process.cwd(), '../../../matrix-federation-config/registration.yaml'); + } + + private updateSettingsWithProvidedConfigFileIfNecessary(): void { + const existingConfiguration = this.getRegistrationFileFromHomeserver(); + if (!existingConfiguration) { + return; + } + + Promise.await(Settings.updateValueById('Federation_Matrix_enabled', true)); + Promise.await(Settings.updateValueById('Federation_Matrix_id', existingConfiguration.id)); + Promise.await(Settings.updateValueById('Federation_Matrix_hs_token', existingConfiguration.homeserverToken)); + Promise.await(Settings.updateValueById('Federation_Matrix_as_token', existingConfiguration.applicationServiceToken)); + Promise.await(Settings.updateValueById('Federation_Matrix_homeserver_url', existingConfiguration.rocketchat?.homeServerUrl)); + Promise.await(Settings.updateValueById('Federation_Matrix_homeserver_domain', existingConfiguration.rocketchat?.domainName)); + Promise.await(Settings.updateValueById('Federation_Matrix_bridge_url', existingConfiguration.bridgeUrl)); + Promise.await(Settings.updateValueById('Federation_Matrix_bridge_localpart', existingConfiguration.botName)); + Promise.await(Settings.update({ _id: 'Federation_Matrix_registration_file' }, { $set: { hidden: Boolean(existingConfiguration) } })); + } } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/User.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/User.ts index 3ed04a3cffabd..7fc4071e36b8c 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/User.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/adapters/User.ts @@ -1,6 +1,8 @@ +import { Meteor } from 'meteor/meteor'; import type { IUser } from '@rocket.chat/core-typings'; import { Users, MatrixBridgedUser } from '@rocket.chat/models'; +import { setUserAvatar, _setRealName as setRealName } from '../../../../../lib/server'; import { FederatedUser } from '../../../domain/FederatedUser'; const createFederatedUserInstance = (externalUserId: string, user: IUser, remote = true): FederatedUser => { @@ -25,18 +27,36 @@ export const getFederatedUserByInternalUsername = async (username: string): Prom export class RocketChatUserAdapter { public async getFederatedUserByExternalId(externalUserId: string): Promise { - const internalBridgedUserId = await MatrixBridgedUser.getLocalUserIdByExternalId(externalUserId); - if (!internalBridgedUserId) { + const internalBridgedUser = await MatrixBridgedUser.getBridgedUserByExternalUserId(externalUserId); + if (!internalBridgedUser) { return; } - const user = await Users.findOneById(internalBridgedUserId); + const user = await Users.findOneById(internalBridgedUser.uid); if (user) { - return createFederatedUserInstance(externalUserId, user); + return createFederatedUserInstance(externalUserId, user, internalBridgedUser.remote); } } + public async getFederatedUsersByExternalIds(externalUserIds: string[]): Promise { + const internalBridgedUsers = await MatrixBridgedUser.getLocalUsersByExternalIds(externalUserIds); + if (internalBridgedUsers.length === 0) { + return []; + } + const internalUserIds = internalBridgedUsers.map((bridgedUser) => bridgedUser.uid); + const internalUserIdsMap: Record> = internalBridgedUsers.reduce( + (acc, bridgedUser) => ({ ...acc, [bridgedUser.uid]: { mui: bridgedUser.mui, remote: bridgedUser.remote } }), + {}, + ); + const users = await Users.findByIds(internalUserIds).toArray(); + + if (users.length === 0) { + return []; + } + return users.map((user) => createFederatedUserInstance(internalUserIdsMap[user._id].mui, user, internalUserIdsMap[user._id].remote)); + } + public async getFederatedUserByInternalId(internalUserId: string): Promise { const internalBridgedUser = await MatrixBridgedUser.getBridgedUserByLocalId(internalUserId); if (!internalBridgedUser) { @@ -72,6 +92,10 @@ export class RocketChatUserAdapter { return user; } + public async getInternalUserByUsername(username: string): Promise { + return Users.findOneByUsername(username); + } + public async createFederatedUser(federatedUser: FederatedUser): Promise { const existingLocalUser = federatedUser.getUsername() && (await Users.findOneByUsername(federatedUser.getUsername() as string)); if (existingLocalUser) { @@ -80,4 +104,18 @@ export class RocketChatUserAdapter { const { insertedId } = await Users.insertOne(federatedUser.getStorageRepresentation()); return MatrixBridgedUser.createOrUpdateByLocalId(insertedId, federatedUser.getExternalId(), federatedUser.isRemote()); } + + public async setAvatar(federatedUser: FederatedUser, avatarUrl: string): Promise { + Meteor.runAsUser(federatedUser.getInternalId(), () => { + setUserAvatar(federatedUser.getInternalReference(), avatarUrl, 'image/jpeg', 'url'); // this mimetype is fixed here, but the function when called with a url as source don't use that mimetype + }); + } + + public async updateFederationAvatar(internalUserId: string, externalAvatarUrl: string): Promise { + await Users.setFederationAvatarUrlById(internalUserId, externalAvatarUrl); + } + + public async updateRealName(internalUser: IUser, name: string): Promise { + setRealName(internalUser._id, name, internalUser); + } } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/MessageTextParser.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/MessageTextParser.ts new file mode 100644 index 0000000000000..15e1cb7e68fb1 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/MessageTextParser.ts @@ -0,0 +1,138 @@ +import sanitizeHtml from 'sanitize-html'; +import type { IFrame } from 'sanitize-html'; + +import { FederatedUser } from '../../../domain/FederatedUser'; + +interface IInternalMention { + mention: string; + realName: string; +} + +const DEFAULT_LINK_FOR_MATRIX_MENTIONS = 'https://matrix.to/#/'; +const DEFAULT_TAGS_FOR_MATRIX_QUOTES = ['mx-reply', 'blockquote']; +const DEFAULT_QUOTES_SYMBOLS_FOR_MATRIX_IN_RAW_TEXT = /^>.*/; // > text + +const getAllMentionsWithTheirRealNames = (message: string, homeServerDomain: string, senderExternalId: string): IInternalMention[] => { + const mentions: IInternalMention[] = []; + sanitizeHtml(message, { + allowedTags: ['a'], + exclusiveFilter: (frame: IFrame): boolean => { + const { + attribs: { href = '' }, + tag, + text, + } = frame; + const validATag = tag === 'a' && href && text; + if (!validATag) { + return false; + } + const isUsernameMention = href.includes(DEFAULT_LINK_FOR_MATRIX_MENTIONS) && href.includes('@'); + if (isUsernameMention) { + const [, username] = href.split('@'); + const [, serverDomain] = username.split(':'); + + const withoutServerIdentification = `@${username.split(':').shift()}`; + const fullUsername = `@${username}`; + const isMentioningHimself = senderExternalId === text; + + mentions.push({ + mention: FederatedUser.isOriginalFromTheProxyServer(serverDomain, homeServerDomain) ? withoutServerIdentification : fullUsername, + realName: isMentioningHimself ? withoutServerIdentification : text, + }); + } + const isMentioningAll = href.includes(DEFAULT_LINK_FOR_MATRIX_MENTIONS) && !href.includes('@'); + if (isMentioningAll) { + mentions.push({ + mention: '@all', + realName: text, + }); + } + return false; + }, + }); + + return mentions; +}; + +export const toInternalMessageFormat = ({ + rawMessage, + formattedMessage, + homeServerDomain, + senderExternalId, +}: { + rawMessage: string; + formattedMessage: string; + homeServerDomain: string; + senderExternalId: string; +}): string => + replaceAllMentionsOneByOneSequentially( + rawMessage, + getAllMentionsWithTheirRealNames(formattedMessage, homeServerDomain, senderExternalId), + ); + +const MATCH_ANYTHING = 'w'; +const MATCH_ANYTHING_BUT_COLON = ':'; +const replaceAllMentionsOneByOneSequentially = (message: string, allMentionsWithRealNames: IInternalMention[]): string => { + let parsedMessage = ''; + let toCompareAgain = message; + + if (allMentionsWithRealNames.length === 0) { + return message; + } + + allMentionsWithRealNames.forEach(({ mention, realName }, mentionsIndex) => { + const negativeLookAhead = `(?!${realName.includes(':') ? MATCH_ANYTHING : MATCH_ANYTHING_BUT_COLON})`; + const realNameRegex = new RegExp(`(? => { + if (!rawMessage || !formattedMessage) { + return ''; + } + const withMentionsOnly = sanitizeHtml(formattedMessage, { + allowedTags: ['a'], + allowedAttributes: { + a: ['href'], + }, + nonTextTags: DEFAULT_TAGS_FOR_MATRIX_QUOTES, + }); + const rawMessageWithoutMatrixQuotingFormatting = rawMessage.replace(DEFAULT_QUOTES_SYMBOLS_FOR_MATRIX_IN_RAW_TEXT, '').trimStart(); + + return `[ ](${messageToReplyToUrl}) ${replaceAllMentionsOneByOneSequentially( + rawMessageWithoutMatrixQuotingFormatting, + getAllMentionsWithTheirRealNames(withMentionsOnly, homeServerDomain, senderExternalId), + )}`; +}; diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.ts index 1cef225a0b6a5..8728444ec0a2c 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/converters/RoomSender.ts @@ -5,7 +5,7 @@ import { FederationAfterRemoveUserFromRoomDto, FederationCreateDMAndInviteUserDto, FederationRoomSendExternalMessageDto, -} from '../../../application/input/RoomSenderDto'; +} from '../../../application/sender/input/RoomSenderDto'; import { formatExternalUserIdToInternalUsernameFormat, removeExternalSpecificCharsFromExternalIdentifier, diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/definitions/InternalFederatedRoomRoles.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/definitions/InternalFederatedRoomRoles.ts new file mode 100644 index 0000000000000..9aecf86849e49 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/definitions/InternalFederatedRoomRoles.ts @@ -0,0 +1,4 @@ +export enum ROCKET_CHAT_FEDERATION_ROLES { + MODERATOR = 'moderator', + OWNER = 'owner', +} diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/hooks/index.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/hooks/index.ts index 407d4f760b841..d99956432dea0 100644 --- a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/hooks/index.ts +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/hooks/index.ts @@ -1,13 +1,16 @@ -import type { IRoom, IUser } from '@rocket.chat/core-typings'; +import type { IMessage, IRoom, IUser } from '@rocket.chat/core-typings'; +import { isMessageFromMatrixFederation, isRoomFederated, isEditedMessage } from '@rocket.chat/core-typings'; import { callbacks } from '../../../../../../lib/callbacks'; +import type { FederationRoomServiceSender } from '../../../application/sender/RoomServiceSender'; +import { settings } from '../../../../../settings/server'; export class FederationHooks { public static afterUserLeaveRoom(callback: (user: IUser, room: IRoom) => Promise): void { callbacks.add( 'afterLeaveRoom', (user: IUser, room: IRoom | undefined): void => { - if (!room?.federated) { + if (!room || !isRoomFederated(room) || !user || !settings.get('Federation_Matrix_enabled')) { return; } Promise.await(callback(user, room)); @@ -21,7 +24,14 @@ export class FederationHooks { callbacks.add( 'afterRemoveFromRoom', (params: { removedUser: IUser; userWhoRemoved: IUser }, room: IRoom | undefined): void => { - if (!room?.federated) { + if ( + !room || + !isRoomFederated(room) || + !params || + !params.removedUser || + !params.userWhoRemoved || + !settings.get('Federation_Matrix_enabled') + ) { return; } Promise.await(callback(params.removedUser, room, params.userWhoRemoved)); @@ -33,8 +43,11 @@ export class FederationHooks { public static canAddFederatedUserToNonFederatedRoom(callback: (user: IUser | string, room: IRoom) => Promise): void { callbacks.add( - 'federation.beforeAddUserAToRoom', - (params: { user: IUser | string }, room: IRoom): void => { + 'federation.beforeAddUserToARoom', + (params: { user: IUser | string; inviter?: IUser }, room: IRoom): void => { + if (!params?.user || !room) { + return; + } Promise.await(callback(params.user, room)); }, callbacks.priority.HIGH, @@ -44,8 +57,12 @@ export class FederationHooks { public static canAddFederatedUserToFederatedRoom(callback: (user: IUser | string, inviter: IUser, room: IRoom) => Promise): void { callbacks.add( - 'federation.beforeAddUserAToRoom', + 'federation.beforeAddUserToARoom', (params: { user: IUser | string; inviter: IUser }, room: IRoom): void => { + if (!params?.user || !params.inviter || !room || !settings.get('Federation_Matrix_enabled')) { + return; + } + Promise.await(callback(params.user, params.inviter, room)); }, callbacks.priority.HIGH, @@ -57,6 +74,9 @@ export class FederationHooks { callbacks.add( 'federation.beforeCreateDirectMessage', (members: IUser[]): void => { + if (!members || !settings.get('Federation_Matrix_enabled')) { + return; + } Promise.await(callback(members)); }, callbacks.priority.HIGH, @@ -64,8 +84,145 @@ export class FederationHooks { ); } + public static afterMessageReacted(callback: (message: IMessage, user: IUser, reaction: string) => Promise): void { + callbacks.add( + 'afterSetReaction', + (message: IMessage, params: { user: IUser; reaction: string }): void => { + if ( + !message || + !isMessageFromMatrixFederation(message) || + !params || + !params.user || + !params.reaction || + !settings.get('Federation_Matrix_enabled') + ) { + return; + } + Promise.await(callback(message, params.user, params.reaction)); + }, + callbacks.priority.HIGH, + 'federation-v2-after-message-reacted', + ); + } + + public static afterMessageunReacted(callback: (message: IMessage, user: IUser, reaction: string) => Promise): void { + callbacks.add( + 'afterUnsetReaction', + (message: IMessage, params: { user: IUser; reaction: string; oldMessage: IMessage }): void => { + if ( + !message || + !isMessageFromMatrixFederation(message) || + !params || + !params.user || + !params.reaction || + !params.oldMessage || + !settings.get('Federation_Matrix_enabled') + ) { + return; + } + Promise.await(callback(params.oldMessage, params.user, params.reaction)); + }, + callbacks.priority.HIGH, + 'federation-v2-after-message-unreacted', + ); + } + + public static afterMessageDeleted(callback: (message: IMessage, roomId: IRoom['_id']) => Promise): void { + callbacks.add( + 'afterDeleteMessage', + (message: IMessage, room: IRoom): void => { + if ( + !room || + !message || + !isRoomFederated(room) || + !isMessageFromMatrixFederation(message) || + !settings.get('Federation_Matrix_enabled') + ) { + return; + } + Promise.await(callback(message, room._id)); + }, + callbacks.priority.HIGH, + 'federation-v2-after-room-message-deleted', + ); + } + + public static afterMessageUpdated(callback: (message: IMessage, roomId: IRoom['_id'], userId: string) => Promise): void { + callbacks.add( + 'afterSaveMessage', + (message: IMessage, room: IRoom): IMessage => { + if ( + !room || + !isRoomFederated(room) || + !message || + !isMessageFromMatrixFederation(message) || + !settings.get('Federation_Matrix_enabled') + ) { + return message; + } + if (!isEditedMessage(message)) { + return message; + } + Promise.await(callback(message, room._id, message.editedBy._id)); + return message; + }, + callbacks.priority.HIGH, + 'federation-v2-after-room-message-updated', + ); + } + + public static afterMessageSent(callback: (message: IMessage, roomId: IRoom['_id'], userId: string) => Promise): void { + callbacks.add( + 'afterSaveMessage', + (message: IMessage, room: IRoom): IMessage => { + if (!room || !isRoomFederated(room) || !message || !settings.get('Federation_Matrix_enabled')) { + return message; + } + if (isEditedMessage(message)) { + return message; + } + Promise.await(callback(message, room._id, message.u?._id)); + return message; + }, + callbacks.priority.HIGH, + 'federation-v2-after-room-message-sent', + ); + } + + public static afterRoomRoleChanged(federationRoomService: FederationRoomServiceSender, data?: Record): void { + if (!data || !settings.get('Federation_Matrix_enabled')) { + return; + } + const { + _id: role, + type: action, + scope: internalRoomId, + u: { _id: internalTargetUserId = undefined } = {}, + givenByUserId: internalUserId, + } = data; + const roleEventsInterestedIn = ['moderator', 'owner']; + if (!roleEventsInterestedIn.includes(role)) { + return; + } + const handlers: Record Promise> = { + 'owner-added': (internalUserId: string, internalTargetUserId: string, internalRoomId: string): Promise => + federationRoomService.onRoomOwnerAdded(internalUserId, internalTargetUserId, internalRoomId), + 'owner-removed': (internalUserId: string, internalTargetUserId: string, internalRoomId: string): Promise => + federationRoomService.onRoomOwnerRemoved(internalUserId, internalTargetUserId, internalRoomId), + 'moderator-added': (internalUserId: string, internalTargetUserId: string, internalRoomId: string): Promise => + federationRoomService.onRoomModeratorAdded(internalUserId, internalTargetUserId, internalRoomId), + 'moderator-removed': (internalUserId: string, internalTargetUserId: string, internalRoomId: string): Promise => + federationRoomService.onRoomModeratorRemoved(internalUserId, internalTargetUserId, internalRoomId), + }; + + if (!handlers[`${role}-${action}`]) { + return; + } + Promise.await(handlers[`${role}-${action}`](internalUserId, internalTargetUserId, internalRoomId)); + } + public static removeCEValidation(): void { - callbacks.remove('federation.beforeAddUserAToRoom', 'federation-v2-can-add-federated-user-to-federated-room'); + callbacks.remove('federation.beforeAddUserToARoom', 'federation-v2-can-add-federated-user-to-federated-room'); callbacks.remove('federation.beforeCreateDirectMessage', 'federation-v2-can-create-direct-message-from-ui-ce'); } } diff --git a/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/statistics.ts b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/statistics.ts new file mode 100644 index 0000000000000..d763483e43de6 --- /dev/null +++ b/apps/meteor/app/federation-v2/server/infrastructure/rocket-chat/statistics.ts @@ -0,0 +1,11 @@ +import { settings } from '../../../../settings/server'; + +export interface IFederationStatistics { + enabled: boolean; +} + +export const getMatrixFederationStatistics = async (): Promise => { + return { + enabled: settings.get('Federation_Matrix_enabled'), + }; +}; diff --git a/apps/meteor/app/federation/server/constants.js b/apps/meteor/app/federation/server/constants.ts similarity index 100% rename from apps/meteor/app/federation/server/constants.js rename to apps/meteor/app/federation/server/constants.ts diff --git a/apps/meteor/app/federation/server/endpoints/dispatch.js b/apps/meteor/app/federation/server/endpoints/dispatch.js index 05179c53144e1..60880c51fbaae 100644 --- a/apps/meteor/app/federation/server/endpoints/dispatch.js +++ b/apps/meteor/app/federation/server/endpoints/dispatch.js @@ -1,5 +1,6 @@ import { EJSON } from 'meteor/ejson'; import { FederationServers } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; import { API } from '../../../api/server'; import { serverLogger } from '../lib/logger'; @@ -7,7 +8,6 @@ import { contextDefinitions, eventTypes } from '../../../models/server/models/Fe import { FederationRoomEvents, Messages, Rooms, Subscriptions, Users } from '../../../models/server'; import { normalizers } from '../normalizers'; import { deleteRoom } from '../../../lib/server/functions'; -import { api } from '../../../../server/sdk/api'; import { FileUpload } from '../../../file-upload'; import { getFederationDomain } from '../lib/getFederationDomain'; import { decryptIfNeeded } from '../lib/crypt'; diff --git a/apps/meteor/app/federation/server/endpoints/index.js b/apps/meteor/app/federation/server/endpoints/index.ts similarity index 100% rename from apps/meteor/app/federation/server/endpoints/index.js rename to apps/meteor/app/federation/server/endpoints/index.ts diff --git a/apps/meteor/app/federation/server/functions/dashboard.js b/apps/meteor/app/federation/server/functions/dashboard.js index 149e2215f73f3..c31bf091e642a 100644 --- a/apps/meteor/app/federation/server/functions/dashboard.js +++ b/apps/meteor/app/federation/server/functions/dashboard.js @@ -6,7 +6,7 @@ import { FederationRoomEvents, Users } from '../../../models/server'; export async function getStatistics() { const numberOfEvents = FederationRoomEvents.find().count(); const numberOfFederatedUsers = Users.findRemote().count(); - const numberOfServers = await FederationServers.find().count(); + const numberOfServers = await FederationServers.col.estimatedDocumentCount(); return { numberOfEvents, numberOfFederatedUsers, numberOfServers }; } diff --git a/apps/meteor/app/federation/server/index.js b/apps/meteor/app/federation/server/index.ts similarity index 100% rename from apps/meteor/app/federation/server/index.js rename to apps/meteor/app/federation/server/index.ts diff --git a/apps/meteor/app/federation/server/methods/index.js b/apps/meteor/app/federation/server/methods/index.ts similarity index 100% rename from apps/meteor/app/federation/server/methods/index.js rename to apps/meteor/app/federation/server/methods/index.ts diff --git a/apps/meteor/app/federation/server/normalizers/index.js b/apps/meteor/app/federation/server/normalizers/index.ts similarity index 100% rename from apps/meteor/app/federation/server/normalizers/index.js rename to apps/meteor/app/federation/server/normalizers/index.ts diff --git a/apps/meteor/app/federation/server/startup/index.js b/apps/meteor/app/federation/server/startup/index.ts similarity index 100% rename from apps/meteor/app/federation/server/startup/index.js rename to apps/meteor/app/federation/server/startup/index.ts diff --git a/apps/meteor/app/federation/server/startup/settings.ts b/apps/meteor/app/federation/server/startup/settings.ts index ee216054db043..fa1c00eaa3653 100644 --- a/apps/meteor/app/federation/server/startup/settings.ts +++ b/apps/meteor/app/federation/server/startup/settings.ts @@ -15,7 +15,7 @@ settingsRegistry.addGroup('Federation', function () { type: 'boolean', i18nLabel: 'Enabled', i18nDescription: 'FEDERATION_Enabled', - alert: 'FEDERATION_Enabled_Alert', + alert: 'This_is_a_deprecated_feature_alert', public: true, }); diff --git a/apps/meteor/app/file-upload/server/config/GoogleStorage.js b/apps/meteor/app/file-upload/server/config/GoogleStorage.js index ce900d9811aa5..acdda2bf508d4 100644 --- a/apps/meteor/app/file-upload/server/config/GoogleStorage.js +++ b/apps/meteor/app/file-upload/server/config/GoogleStorage.js @@ -69,6 +69,7 @@ const GoogleCloudStorageUserDataFiles = new FileUploadClass({ const configure = _.debounce(function () { const bucket = settings.get('FileUpload_GoogleStorage_Bucket'); + const projectId = settings.get('FileUpload_GoogleStorage_ProjectId'); const accessId = settings.get('FileUpload_GoogleStorage_AccessId'); const secret = settings.get('FileUpload_GoogleStorage_Secret'); const URLExpiryTimeSpan = settings.get('FileUpload_S3_URLExpiryTimeSpan'); @@ -82,6 +83,7 @@ const configure = _.debounce(function () { credentials: { client_email: accessId, private_key: secret, + projectId, }, }, bucket, diff --git a/apps/meteor/app/file-upload/server/lib/FileUpload.js b/apps/meteor/app/file-upload/server/lib/FileUpload.js index dc99688c5642b..c310f6ca82341 100644 --- a/apps/meteor/app/file-upload/server/lib/FileUpload.js +++ b/apps/meteor/app/file-upload/server/lib/FileUpload.js @@ -17,13 +17,14 @@ import { Avatars, UserDataFiles, Uploads, Settings } from '@rocket.chat/models'; import { settings } from '../../../settings/server'; import Users from '../../../models/server/models/Users'; import Rooms from '../../../models/server/models/Rooms'; +import Subscriptions from '../../../models/server/models/Subscriptions'; import { mime } from '../../../utils/lib/mimeTypes'; import { hasPermission } from '../../../authorization/server/functions/hasPermission'; import { canAccessRoom } from '../../../authorization/server/functions/canAccessRoom'; import { fileUploadIsValidContentType } from '../../../utils/lib/fileUploadRestrictions'; import { isValidJWT, generateJWT } from '../../../utils/server/lib/JWTHelper'; import { Messages } from '../../../models/server'; -import { AppEvents, Apps } from '../../../apps/server'; +import { AppEvents, Apps } from '../../../../ee/server/apps'; import { streamToBuffer } from './streamToBuffer'; import { SystemLogger } from '../../../../server/lib/logger/system'; import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator'; @@ -292,6 +293,10 @@ export const FileUpload = { return result; }, + async extractMetadata(file) { + return sharp(FileUpload.getBufferSync(file)).metadata(); + }, + createImageThumbnail(file) { if (!settings.get('Message_Attachments_Thumbnails_Enabled')) { return; @@ -323,6 +328,8 @@ export const FileUpload = { name: `thumb-${file.name}`, size: buffer.length, type: file.type, + originalFileId: file._id, + typeGroup: 'thumb', rid, userId, }; @@ -331,7 +338,7 @@ export const FileUpload = { }, uploadsOnValidate(file) { - if (!/^image\/((x-windows-)?bmp|p?jpeg|png|gif)$/.test(file.type)) { + if (!/^image\/((x-windows-)?bmp|p?jpeg|png|gif|webp)$/.test(file.type)) { return; } @@ -425,7 +432,7 @@ export const FileUpload = { // console.log('upload finished ->', file); }, - requestCanAccessFiles({ headers = {}, query = {} }) { + requestCanAccessFiles({ headers = {}, query = {} }, file) { if (!settings.get('FileUpload_ProtectFiles')) { return true; } @@ -440,16 +447,37 @@ export const FileUpload = { rc_room_type = cookie.get('rc_room_type', headers.cookie); } - const isAuthorizedByCookies = rc_uid && rc_token && Users.findOneByIdAndLoginToken(rc_uid, rc_token); - const isAuthorizedByHeaders = - headers['x-user-id'] && headers['x-auth-token'] && Users.findOneByIdAndLoginToken(headers['x-user-id'], headers['x-auth-token']); - const isAuthorizedByRoom = + const isAuthorizedByRoom = () => rc_room_type && roomCoordinator.getRoomDirectives(rc_room_type)?.canAccessUploadedFile({ rc_uid, rc_rid, rc_token }); - const isAuthorizedByJWT = + const isAuthorizedByJWT = () => settings.get('FileUpload_Enable_json_web_token_for_files') && token && isValidJWT(token, settings.get('FileUpload_json_web_token_secret_for_files')); - return isAuthorizedByCookies || isAuthorizedByHeaders || isAuthorizedByRoom || isAuthorizedByJWT; + + if (isAuthorizedByRoom() || isAuthorizedByJWT()) { + return true; + } + + const uid = rc_uid || headers['x-user-id']; + const authToken = rc_token || headers['x-auth-token']; + + const user = uid && authToken && Users.findOneByIdAndLoginToken(uid, authToken, { fields: { _id: 1 } }); + + if (!user) { + return false; + } + + if (!settings.get('FileUpload_Restrict_to_room_members') || !file?.rid) { + return true; + } + + const subscription = Subscriptions.findOneByRoomIdAndUserId(file.rid, user._id, { fields: { _id: 1 } }); + + if (subscription) { + return true; + } + + return false; }, addExtensionTo(file) { if (mime.lookup(file.name) === file.type) { @@ -700,6 +728,11 @@ export class FileUploadClass { streamOrBuffer = Promise.await(streamToBuffer(streamOrBuffer)); } + if (streamOrBuffer instanceof Uint8Array) { + // Services compat :) + streamOrBuffer = Buffer.from(streamOrBuffer); + } + // Check if the fileData matches store filter const filter = this.store.getFilter(); if (filter && filter.check) { diff --git a/apps/meteor/app/file-upload/server/lib/proxy.js b/apps/meteor/app/file-upload/server/lib/proxy.js index 53be1e285a999..23331ff3f705b 100644 --- a/apps/meteor/app/file-upload/server/lib/proxy.js +++ b/apps/meteor/app/file-upload/server/lib/proxy.js @@ -4,7 +4,8 @@ import URL from 'url'; import { Meteor } from 'meteor/meteor'; import { WebApp } from 'meteor/webapp'; import { UploadFS } from 'meteor/jalik:ufs'; -import { InstanceStatus } from 'meteor/konecty:multiple-instances-status'; +import { InstanceStatus } from '@rocket.chat/instance-status'; +import { InstanceStatus as InstanceStatusModel } from '@rocket.chat/models'; import { Logger } from '../../../logger'; import { isDocker } from '../../../utils'; @@ -63,7 +64,7 @@ WebApp.connectHandlers.stack.unshift({ } // Proxy to other instance - const instance = InstanceStatus.getCollection().findOne({ _id: file.instanceId }); + const instance = Promise.await(InstanceStatusModel.findOneById(file.instanceId)); if (instance == null) { res.writeHead(404); diff --git a/apps/meteor/app/file-upload/server/lib/requests.js b/apps/meteor/app/file-upload/server/lib/requests.js index 87f934f4a4f33..f75cf9d8a3100 100644 --- a/apps/meteor/app/file-upload/server/lib/requests.js +++ b/apps/meteor/app/file-upload/server/lib/requests.js @@ -10,7 +10,7 @@ WebApp.connectHandlers.use(FileUpload.getPath(), async function (req, res, next) const file = await Uploads.findOneById(match[1]); if (file) { - if (!FileUpload.requestCanAccessFiles(req)) { + if (!FileUpload.requestCanAccessFiles(req, file)) { res.writeHead(403); return res.end(); } diff --git a/apps/meteor/app/file-upload/server/methods/sendFileMessage.ts b/apps/meteor/app/file-upload/server/methods/sendFileMessage.ts index a3f6332f1cf3b..8df934acacf37 100644 --- a/apps/meteor/app/file-upload/server/methods/sendFileMessage.ts +++ b/apps/meteor/app/file-upload/server/methods/sendFileMessage.ts @@ -1,13 +1,122 @@ import { Meteor } from 'meteor/meteor'; import { Match, check } from 'meteor/check'; -import _ from 'underscore'; -import type { MessageAttachment, FileAttachmentProps, IUser } from '@rocket.chat/core-typings'; +import type { MessageAttachment, FileAttachmentProps, IUser, IUpload, AtLeast } from '@rocket.chat/core-typings'; import { Rooms, Uploads } from '@rocket.chat/models'; import { callbacks } from '../../../../lib/callbacks'; import { FileUpload } from '../lib/FileUpload'; import { canAccessRoom } from '../../../authorization/server/functions/canAccessRoom'; import { SystemLogger } from '../../../../server/lib/logger/system'; +import { omit } from '../../../../lib/utils/omit'; +import { getFileExtension } from '../../../../lib/utils/getFileExtension'; + +function validateFileRequiredFields(file: Partial): asserts file is AtLeast { + const requiredFields = ['_id', 'name', 'type', 'size']; + requiredFields.forEach((field) => { + if (!Object.keys(file).includes(field)) { + throw new Meteor.Error('error-invalid-file', 'Invalid file'); + } + }); +} + +export const parseFileIntoMessageAttachments = async ( + file: Partial, + roomId: string, + user: IUser, +): Promise> => { + validateFileRequiredFields(file); + + await Uploads.updateFileComplete(file._id, user._id, omit(file, '_id')); + + const fileUrl = FileUpload.getPath(`${file._id}/${encodeURI(file.name)}`); + + const attachments: MessageAttachment[] = []; + + const files = [ + { + _id: file._id, + name: file.name, + type: file.type, + }, + ]; + + if (/^image\/.+/.test(file.type as string)) { + const attachment: FileAttachmentProps = { + title: file.name, + type: 'file', + description: file?.description, + title_link: fileUrl, + title_link_download: true, + image_url: fileUrl, + image_type: file.type as string, + image_size: file.size, + }; + + if (file.identify?.size) { + attachment.image_dimensions = file.identify.size; + } + + try { + attachment.image_preview = await FileUpload.resizeImagePreview(file); + const thumbResult = await FileUpload.createImageThumbnail(file); + if (thumbResult) { + const { data: thumbBuffer, width, height } = thumbResult; + const thumbnail = FileUpload.uploadImageThumbnail(file, thumbBuffer, roomId, user._id); + const thumbUrl = FileUpload.getPath(`${thumbnail._id}/${encodeURI(file.name)}`); + attachment.image_url = thumbUrl; + attachment.image_type = thumbnail.type; + attachment.image_dimensions = { + width, + height, + }; + files.push({ + _id: thumbnail._id, + name: file.name, + type: thumbnail.type, + }); + } + } catch (e) { + SystemLogger.error(e); + } + attachments.push(attachment); + } else if (/^audio\/.+/.test(file.type as string)) { + const attachment: FileAttachmentProps = { + title: file.name, + type: 'file', + description: file.description, + title_link: fileUrl, + title_link_download: true, + audio_url: fileUrl, + audio_type: file.type as string, + audio_size: file.size, + }; + attachments.push(attachment); + } else if (/^video\/.+/.test(file.type as string)) { + const attachment: FileAttachmentProps = { + title: file.name, + type: 'file', + description: file.description, + title_link: fileUrl, + title_link_download: true, + video_url: fileUrl, + video_type: file.type as string, + video_size: file.size as number, + }; + attachments.push(attachment); + } else { + const attachment = { + title: file.name, + type: 'file', + format: getFileExtension(file.name), + description: file.description, + title_link: fileUrl, + title_link_download: true, + size: file.size as number, + }; + attachments.push(attachment); + } + return { files, attachments }; +}; Meteor.methods({ async sendFileMessage(roomId, _store, file, msgData = {}) { @@ -36,93 +145,7 @@ Meteor.methods({ tmid: Match.Optional(String), }); - await Uploads.updateFileComplete(file._id, user._id, _.omit(file, '_id')); - - const fileUrl = FileUpload.getPath(`${file._id}/${encodeURI(file.name)}`); - - const attachments: MessageAttachment[] = []; - - const files = [ - { - _id: file._id, - name: file.name, - type: file.type, - }, - ]; - - if (/^image\/.+/.test(file.type)) { - const attachment: FileAttachmentProps = { - title: file.name, - type: 'file', - description: file.description, - title_link: fileUrl, - title_link_download: true, - image_url: fileUrl, - image_type: file.type, - image_size: file.size, - }; - - if (file.identify?.size) { - attachment.image_dimensions = file.identify.size; - } - - try { - attachment.image_preview = await FileUpload.resizeImagePreview(file); - const thumbResult = await FileUpload.createImageThumbnail(file); - if (thumbResult) { - const { data: thumbBuffer, width, height } = thumbResult; - const thumbnail = FileUpload.uploadImageThumbnail(file, thumbBuffer, roomId, user._id); - const thumbUrl = FileUpload.getPath(`${thumbnail._id}/${encodeURI(file.name)}`); - attachment.image_url = thumbUrl; - attachment.image_type = thumbnail.type; - attachment.image_dimensions = { - width, - height, - }; - files.push({ - _id: thumbnail._id, - name: file.name, - type: thumbnail.type, - }); - } - } catch (e) { - SystemLogger.error(e); - } - attachments.push(attachment); - } else if (/^audio\/.+/.test(file.type)) { - const attachment: FileAttachmentProps = { - title: file.name, - type: 'file', - description: file.description, - title_link: fileUrl, - title_link_download: true, - audio_url: fileUrl, - audio_type: file.type, - audio_size: file.size, - }; - attachments.push(attachment); - } else if (/^video\/.+/.test(file.type)) { - const attachment: FileAttachmentProps = { - title: file.name, - type: 'file', - description: file.description, - title_link: fileUrl, - title_link_download: true, - video_url: fileUrl, - video_type: file.type, - video_size: file.size, - }; - attachments.push(attachment); - } else { - const attachment = { - title: file.name, - type: 'file', - description: file.description, - title_link: fileUrl, - title_link_download: true, - }; - attachments.push(attachment); - } + const { files, attachments } = await parseFileIntoMessageAttachments(file, roomId, user); const msg = Meteor.call('sendMessage', { rid: roomId, diff --git a/apps/meteor/app/file-upload/server/startup/settings.ts b/apps/meteor/app/file-upload/server/startup/settings.ts index f55887f25993e..f4c7f72b4ca5b 100644 --- a/apps/meteor/app/file-upload/server/startup/settings.ts +++ b/apps/meteor/app/file-upload/server/startup/settings.ts @@ -30,6 +30,14 @@ settingsRegistry.addGroup('FileUpload', function () { i18nDescription: 'FileUpload_ProtectFilesDescription', }); + this.add('FileUpload_Restrict_to_room_members', false, { + type: 'boolean', + enableQuery: { + _id: 'FileUpload_ProtectFiles', + value: true, + }, + }); + this.add('FileUpload_RotateImages', true, { type: 'boolean', public: true, @@ -203,6 +211,18 @@ settingsRegistry.addGroup('FileUpload', function () { }, secret: true, }); + + this.add('FileUpload_GoogleStorage_ProjectId', '', { + type: 'string', + multiline: false, + private: true, + enableQuery: { + _id: 'FileUpload_Storage_Type', + value: 'GoogleCloudStorage', + }, + secret: true, + }); + this.add('FileUpload_GoogleStorage_Proxy_Avatars', false, { type: 'boolean', enableQuery: { diff --git a/apps/meteor/app/file-upload/ufs/Webdav/server.js b/apps/meteor/app/file-upload/ufs/Webdav/server.js index c635e38eb5858..7b2f8b95b64e0 100644 --- a/apps/meteor/app/file-upload/ufs/Webdav/server.js +++ b/apps/meteor/app/file-upload/ufs/Webdav/server.js @@ -76,7 +76,7 @@ export class WebdavStore extends UploadFS.Store { .then((data) => { callback && callback(null, data); }) - .catch(SystemLogger.error); + .catch((...args) => SystemLogger.error(...args)); }; /** @@ -107,7 +107,7 @@ export class WebdavStore extends UploadFS.Store { */ this.getWriteStream = function (fileId, file) { const writeStream = new stream.PassThrough(); - const webdavStream = client.createWriteStream(this.getPath(file)); + const webdavStream = client.createWriteStream(this.getPath(file), file.size || 0); // TODO remove timeout when UploadFS bug resolved const newListenerCallback = (event, listener) => { diff --git a/apps/meteor/app/file/index.js b/apps/meteor/app/file/index.ts similarity index 100% rename from apps/meteor/app/file/index.js rename to apps/meteor/app/file/index.ts diff --git a/apps/meteor/app/file/server/index.js b/apps/meteor/app/file/server/index.ts similarity index 100% rename from apps/meteor/app/file/server/index.js rename to apps/meteor/app/file/server/index.ts diff --git a/apps/meteor/app/github-enterprise/client/index.js b/apps/meteor/app/github-enterprise/client/index.ts similarity index 100% rename from apps/meteor/app/github-enterprise/client/index.js rename to apps/meteor/app/github-enterprise/client/index.ts diff --git a/apps/meteor/app/github-enterprise/server/index.js b/apps/meteor/app/github-enterprise/server/index.ts similarity index 100% rename from apps/meteor/app/github-enterprise/server/index.js rename to apps/meteor/app/github-enterprise/server/index.ts diff --git a/apps/meteor/app/gitlab/client/index.js b/apps/meteor/app/gitlab/client/index.ts similarity index 100% rename from apps/meteor/app/gitlab/client/index.js rename to apps/meteor/app/gitlab/client/index.ts diff --git a/apps/meteor/app/gitlab/server/index.js b/apps/meteor/app/gitlab/server/index.ts similarity index 100% rename from apps/meteor/app/gitlab/server/index.js rename to apps/meteor/app/gitlab/server/index.ts diff --git a/apps/meteor/app/highlight-words/client/client.js b/apps/meteor/app/highlight-words/client/client.js deleted file mode 100644 index 3ae03c2f9a4b8..0000000000000 --- a/apps/meteor/app/highlight-words/client/client.js +++ /dev/null @@ -1,18 +0,0 @@ -import { highlightWords, getRegexHighlight, getRegexHighlightUrl } from './helper'; - -export const createHighlightWordsMessageRenderer = ({ wordsToHighlight }) => { - const highlights = wordsToHighlight.map((highlight) => ({ - highlight, - regex: getRegexHighlight(highlight), - urlRegex: getRegexHighlightUrl(highlight), - })); - - return (message) => { - if (!message.html?.trim()) { - return message; - } - - message.html = highlightWords(message.html, highlights); - return message; - }; -}; diff --git a/apps/meteor/app/highlight-words/client/index.js b/apps/meteor/app/highlight-words/client/index.js deleted file mode 100644 index fb7467ca95b7b..0000000000000 --- a/apps/meteor/app/highlight-words/client/index.js +++ /dev/null @@ -1 +0,0 @@ -export { createHighlightWordsMessageRenderer } from './client'; diff --git a/apps/meteor/app/ui/index.ts b/apps/meteor/app/highlight-words/index.ts similarity index 100% rename from apps/meteor/app/ui/index.ts rename to apps/meteor/app/highlight-words/index.ts diff --git a/apps/meteor/app/iframe-login/client/iframe_client.js b/apps/meteor/app/iframe-login/client/iframe_client.js index 3a43db70ee6f9..acdc41a377522 100644 --- a/apps/meteor/app/iframe-login/client/iframe_client.js +++ b/apps/meteor/app/iframe-login/client/iframe_client.js @@ -1,5 +1,4 @@ import { Accounts } from 'meteor/accounts-base'; -import _ from 'underscore'; import { IframeLogin } from '../../ui-utils'; @@ -12,7 +11,7 @@ Accounts._unstoreLoginToken = function (...args) { }; window.addEventListener('message', (e) => { - if (!_.isObject(e.data)) { + if (!(typeof e.data === 'function' || (typeof e.data === 'object' && !!e.data))) { return; } diff --git a/apps/meteor/app/importer-hipchat-enterprise/server/importer.js b/apps/meteor/app/importer-hipchat-enterprise/server/importer.js index 86a59e058a69d..bb1a1c62d5cb2 100644 --- a/apps/meteor/app/importer-hipchat-enterprise/server/importer.js +++ b/apps/meteor/app/importer-hipchat-enterprise/server/importer.js @@ -220,7 +220,7 @@ export class HipChatEnterpriseImporter extends Base { } else if (m.GuestAccessMessage) { this.logger.warn('Guess Access Notification was ignored.'); } else { - this.logger.error("HipChat Enterprise importer isn't configured to handle this message:", m); + this.logger.error({ msg: "HipChat Enterprise importer isn't configured to handle this message:", file: m }); } } @@ -327,7 +327,7 @@ export class HipChatEnterpriseImporter extends Base { ); this.extract.on('error', (err) => { - this.logger.error('extract error:', err); + this.logger.error({ msg: 'extract error:', err }); reject(new Meteor.Error('error-import-file-extract-error')); }); @@ -342,7 +342,7 @@ export class HipChatEnterpriseImporter extends Base { const gunzip = this.zlib.createGunzip(); gunzip.on('error', (err) => { - this.logger.error('extract error:', err); + this.logger.error({ msg: 'extract error:', err }); reject(new Meteor.Error('error-import-file-extract-error')); }); this.logger.debug('start extracting import file'); diff --git a/apps/meteor/app/importer/server/classes/ImportDataConverter.ts b/apps/meteor/app/importer/server/classes/ImportDataConverter.ts index 74eec85b942d4..54400196b0271 100644 --- a/apps/meteor/app/importer/server/classes/ImportDataConverter.ts +++ b/apps/meteor/app/importer/server/classes/ImportDataConverter.ts @@ -1,6 +1,5 @@ import { Meteor } from 'meteor/meteor'; import { Accounts } from 'meteor/accounts-base'; -import _ from 'underscore'; import { ObjectId } from 'mongodb'; import type { IImportUser, @@ -217,7 +216,10 @@ export class ImportDataConverter { continue; } - updateData.$set[keyPath] = source[key]; + updateData.$set = { + ...updateData.$set, + ...{ [keyPath]: source[key] }, + }; } }; @@ -237,16 +239,16 @@ export class ImportDataConverter { } // #ToDo: #TODO: Move this to the model class - const updateData: Record = { - $set: { + const updateData: Record = Object.assign(Object.create(null), { + $set: Object.assign(Object.create(null), { ...(userData.roles && { roles: userData.roles }), ...(userData.type && { type: userData.type }), ...(userData.statusText && { statusText: userData.statusText }), ...(userData.bio && { bio: userData.bio }), ...(userData.services?.ldap && { ldap: true }), ...(userData.avatarUrl && { _pendingAvatarUrl: userData.avatarUrl }), - }, - }; + }), + }); this.addCustomFields(updateData, userData); this.addUserServices(updateData, userData); @@ -909,7 +911,7 @@ export class ImportDataConverter { } data.importIds = data.importIds.filter((item) => item); - data.users = _.uniq(data.users); + data.users = [...new Set(data.users)]; if (!data.importIds.length) { throw new Error('importer-channel-missing-import-id'); diff --git a/apps/meteor/app/importer/server/methods/getImportFileData.ts b/apps/meteor/app/importer/server/methods/getImportFileData.ts index fead1a54750e8..6220b9fe5261e 100644 --- a/apps/meteor/app/importer/server/methods/getImportFileData.ts +++ b/apps/meteor/app/importer/server/methods/getImportFileData.ts @@ -34,7 +34,7 @@ export const executeGetImportFileData = async (): Promise= 0) { - if (importer.instance.importRecord && importer.instance.importRecord.valid) { + if (importer.instance.importRecord?.valid) { return { waiting: true }; } throw new Meteor.Error('error-import-operation-invalid', 'Invalid Import Operation', 'getImportFileData'); diff --git a/apps/meteor/app/integrations/server/api/api.js b/apps/meteor/app/integrations/server/api/api.js index 724bfea9ad80c..5f85f492ba278 100644 --- a/apps/meteor/app/integrations/server/api/api.js +++ b/apps/meteor/app/integrations/server/api/api.js @@ -6,10 +6,10 @@ import { Livechat } from 'meteor/rocketchat:livechat'; import Fiber from 'fibers'; import Future from 'fibers/future'; import _ from 'underscore'; -import s from 'underscore.string'; import moment from 'moment'; import { Integrations } from '@rocket.chat/models'; +import * as s from '../../../../lib/utils/stringUtils'; import { incomingLogger } from '../logger'; import { processWebhookMessage } from '../../../lib/server'; import { API, APIClass, defaultRateLimiterOptions } from '../../../api/server'; diff --git a/apps/meteor/app/integrations/server/lib/triggerHandler.js b/apps/meteor/app/integrations/server/lib/triggerHandler.js index a44deaa537d3b..022d5180c48ab 100644 --- a/apps/meteor/app/integrations/server/lib/triggerHandler.js +++ b/apps/meteor/app/integrations/server/lib/triggerHandler.js @@ -3,18 +3,19 @@ import { Meteor } from 'meteor/meteor'; import { Random } from 'meteor/random'; import { HTTP } from 'meteor/http'; import _ from 'underscore'; -import s from 'underscore.string'; import moment from 'moment'; import Fiber from 'fibers'; import Future from 'fibers/future'; import { Integrations, IntegrationHistory } from '@rocket.chat/models'; import * as Models from '../../../models/server'; +import * as s from '../../../../lib/utils/stringUtils'; import { settings } from '../../../settings/server'; import { getRoomByNameOrIdWithOptionToJoin, processWebhookMessage } from '../../../lib/server'; import { outgoingLogger } from '../logger'; import { outgoingEvents } from '../../lib/outgoingEvents'; import { fetch } from '../../../../server/lib/http/fetch'; +import { omit } from '../../../../lib/utils/omit'; export class RocketChatIntegrationHandler { constructor() { @@ -103,7 +104,7 @@ export class RocketChatIntegrationHandler { history.data = { ...data }; if (data.user) { - history.data.user = _.omit(data.user, ['services']); + history.data.user = omit(data.user, 'services'); } if (data.room) { diff --git a/apps/meteor/app/integrations/server/methods/incoming/addIncomingIntegration.ts b/apps/meteor/app/integrations/server/methods/incoming/addIncomingIntegration.ts index 1c40d62dcec85..d88a56375638b 100644 --- a/apps/meteor/app/integrations/server/methods/incoming/addIncomingIntegration.ts +++ b/apps/meteor/app/integrations/server/methods/incoming/addIncomingIntegration.ts @@ -3,7 +3,6 @@ import { Match, check } from 'meteor/check'; import { Random } from 'meteor/random'; import { Babel } from 'meteor/babel-compiler'; import _ from 'underscore'; -import s from 'underscore.string'; import type { INewIncomingIntegration, IIncomingIntegration } from '@rocket.chat/core-typings'; import { Integrations, Roles } from '@rocket.chat/models'; @@ -38,7 +37,7 @@ Meteor.methods({ }); } - if (!_.isString(integration.channel)) { + if (!integration.channel || typeof integration.channel.valueOf() !== 'string') { throw new Meteor.Error('error-invalid-channel', 'Invalid channel', { method: 'addIncomingIntegration', }); @@ -50,7 +49,7 @@ Meteor.methods({ }); } - const channels = _.map(integration.channel.split(','), (channel) => s.trim(channel)); + const channels = integration.channel.split(',').map((channel) => channel.trim()); for (const channel of channels) { if (!validChannelChars.includes(channel[0])) { @@ -60,7 +59,7 @@ Meteor.methods({ } } - if (!_.isString(integration.username) || integration.username.trim() === '') { + if (!integration.username || typeof integration.username.valueOf() !== 'string' || integration.username.trim() === '') { throw new Meteor.Error('error-invalid-username', 'Invalid username', { method: 'addIncomingIntegration', }); diff --git a/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.js b/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.js index f3d161f539769..8f9153a587ded 100644 --- a/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.js +++ b/apps/meteor/app/integrations/server/methods/incoming/updateIncomingIntegration.js @@ -1,7 +1,6 @@ import { Meteor } from 'meteor/meteor'; import { Babel } from 'meteor/babel-compiler'; import _ from 'underscore'; -import s from 'underscore.string'; import { Integrations, Roles } from '@rocket.chat/models'; import { Rooms, Users, Subscriptions } from '../../../../models/server'; @@ -11,13 +10,13 @@ const validChannelChars = ['@', '#']; Meteor.methods({ async updateIncomingIntegration(integrationId, integration) { - if (!_.isString(integration.channel) || integration.channel.trim() === '') { + if (!integration.channel || typeof integration.channel.valueOf() !== 'string' || integration.channel.trim() === '') { throw new Meteor.Error('error-invalid-channel', 'Invalid channel', { method: 'updateIncomingIntegration', }); } - const channels = _.map(integration.channel.split(','), (channel) => s.trim(channel)); + const channels = integration.channel.split(',').map((channel) => channel.trim()); for (const channel of channels) { if (!validChannelChars.includes(channel[0])) { diff --git a/apps/meteor/app/invites/server/functions/findOrCreateInvite.js b/apps/meteor/app/invites/server/functions/findOrCreateInvite.js index 7d17dfae9c245..bd3810141b26d 100644 --- a/apps/meteor/app/invites/server/functions/findOrCreateInvite.js +++ b/apps/meteor/app/invites/server/functions/findOrCreateInvite.js @@ -1,9 +1,9 @@ import { Meteor } from 'meteor/meteor'; import { Random } from 'meteor/random'; import { Invites } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; import { hasPermission } from '../../../authorization/server'; -import { api } from '../../../../server/sdk/api'; import { Subscriptions, Rooms } from '../../../models/server'; import { settings } from '../../../settings/server'; import { getURL } from '../../../utils/lib/getURL'; @@ -52,7 +52,7 @@ export const findOrCreateInvite = async (userId, invite) => { } const room = Rooms.findOneById(invite.rid); - if (!roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.INVITE)) { + if (!roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.INVITE, userId)) { throw new Meteor.Error('error-room-type-not-allowed', 'Cannot create invite links for this room type', { method: 'findOrCreateInvite', }); diff --git a/apps/meteor/app/invites/server/functions/sendInvitationEmail.ts b/apps/meteor/app/invites/server/functions/sendInvitationEmail.ts new file mode 100644 index 0000000000000..ee666d4c8ba58 --- /dev/null +++ b/apps/meteor/app/invites/server/functions/sendInvitationEmail.ts @@ -0,0 +1,65 @@ +import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; +import { Settings } from '@rocket.chat/models'; + +import * as Mailer from '../../../mailer'; +import { hasPermission } from '../../../authorization/server'; +import { settings } from '../../../settings/server'; + +let html = ''; +Meteor.startup(() => { + Mailer.getTemplate('Invitation_Email', (value) => { + html = value; + }); +}); + +export const sendInvitationEmail = async (userId: string, emails: string[]) => { + check(emails, [String]); + if (!userId) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'sendInvitationEmail', + }); + } + if (!hasPermission(userId, 'bulk-register-user')) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { + method: 'sendInvitationEmail', + }); + } + const validEmails = emails.filter(Mailer.checkAddressFormat); + + if (!validEmails || validEmails.length === 0) { + throw new Meteor.Error('error-email-send-failed', 'No valid email addresses', { + method: 'sendInvitationEmail', + }); + } + + const subject = settings.get('Invitation_Subject'); + + if (!subject) { + throw new Meteor.Error('error-email-send-failed', 'No subject', { + method: 'sendInvitationEmail', + }); + } + + return validEmails.filter((email) => { + try { + const mailerResult = Mailer.send({ + to: email, + from: settings.get('From_Email'), + subject, + html, + data: { + email, + }, + }); + + Settings.incrementValueById('Invitation_Email_Count'); + return mailerResult; + } catch ({ message }) { + throw new Meteor.Error('error-email-send-failed', `Error trying to send email: ${message}`, { + method: 'sendInvitationEmail', + message, + }); + } + }); +}; diff --git a/apps/meteor/app/invites/server/functions/useInviteToken.js b/apps/meteor/app/invites/server/functions/useInviteToken.js index 6514ebe4e92f4..730db7a713f6d 100644 --- a/apps/meteor/app/invites/server/functions/useInviteToken.js +++ b/apps/meteor/app/invites/server/functions/useInviteToken.js @@ -24,7 +24,7 @@ export const useInviteToken = async (userId, token) => { const { inviteData, room } = await validateInviteToken(token); - if (!roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.INVITE)) { + if (!roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.INVITE, userId)) { throw new Meteor.Error('error-room-type-not-allowed', "Can't join room of this type via invite", { method: 'useInviteToken', field: 'token', diff --git a/apps/meteor/app/irc/server/irc-bridge/index.js b/apps/meteor/app/irc/server/irc-bridge/index.js index 855f68acddedb..220f938681796 100644 --- a/apps/meteor/app/irc/server/irc-bridge/index.js +++ b/apps/meteor/app/irc/server/irc-bridge/index.js @@ -1,7 +1,6 @@ import { Meteor } from 'meteor/meteor'; import Queue from 'queue-fifo'; import moment from 'moment'; -import _ from 'underscore'; import { Settings } from '@rocket.chat/models'; import * as peerCommandHandlers from './peerHandlers'; @@ -9,12 +8,13 @@ import * as localCommandHandlers from './localHandlers'; import { callbacks } from '../../../../lib/callbacks'; import * as servers from '../servers'; import { Logger } from '../../../logger/server'; +import { withThrottling } from '../../../../lib/utils/highOrderFunctions'; const logger = new Logger('IRC Bridge'); const queueLogger = logger.section('Queue'); let removed = false; -const updateLastPing = _.throttle( +const updateLastPing = withThrottling({ wait: 10_000 })( Meteor.bindEnvironment(() => { if (removed) { return; @@ -28,7 +28,6 @@ const updateLastPing = _.throttle( }, ); }), - 1000 * 10, ); class Bridge { diff --git a/apps/meteor/app/issuelinks/client/client.js b/apps/meteor/app/issuelinks/client/client.js deleted file mode 100644 index 0a149ba1dfb63..0000000000000 --- a/apps/meteor/app/issuelinks/client/client.js +++ /dev/null @@ -1,14 +0,0 @@ -export const createIssueLinksMessageRenderer = - ({ template }) => - (message) => { - if (!message.html?.trim()) { - return message; - } - - message.html = message.html.replace(/(?:^|\s|\n)(#[0-9]+)\b/g, (match, issueNumber) => { - const url = template.replace('%s', issueNumber.substring(1)); - return match.replace(issueNumber, `${issueNumber}`); - }); - - return message; - }; diff --git a/apps/meteor/app/issuelinks/client/index.js b/apps/meteor/app/issuelinks/client/index.js deleted file mode 100644 index bd72fbfb085e5..0000000000000 --- a/apps/meteor/app/issuelinks/client/index.js +++ /dev/null @@ -1 +0,0 @@ -export { createIssueLinksMessageRenderer } from './client'; diff --git a/apps/meteor/app/issuelinks/server/index.js b/apps/meteor/app/issuelinks/server/index.js deleted file mode 100644 index 97097791afdc4..0000000000000 --- a/apps/meteor/app/issuelinks/server/index.js +++ /dev/null @@ -1 +0,0 @@ -import './settings'; diff --git a/apps/meteor/app/issuelinks/server/settings.ts b/apps/meteor/app/issuelinks/server/settings.ts deleted file mode 100644 index ad38e55fd6b5c..0000000000000 --- a/apps/meteor/app/issuelinks/server/settings.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { settingsRegistry } from '../../settings/server'; - -settingsRegistry.add('IssueLinks_Enabled', false, { - type: 'boolean', - i18nLabel: 'Enabled', - i18nDescription: 'IssueLinks_Incompatible', - group: 'Message', - section: 'Issue_Links', - public: true, -}); - -settingsRegistry.add('IssueLinks_Template', '', { - type: 'string', - i18nLabel: 'IssueLinks_LinkTemplate', - i18nDescription: 'IssueLinks_LinkTemplate_Description', - group: 'Message', - section: 'Issue_Links', - public: true, -}); diff --git a/apps/meteor/app/lazy-load/client/index.js b/apps/meteor/app/lazy-load/client/index.js deleted file mode 100644 index 9c27467b09476..0000000000000 --- a/apps/meteor/app/lazy-load/client/index.js +++ /dev/null @@ -1,50 +0,0 @@ -import './lazyloadImage'; - -const map = new WeakMap(); - -const featureExists = !!window.IntersectionObserver; -const loadImage = (el) => { - const instance = map.get(el); - - map.delete(el); - - if (!instance) { - return; - } - - const img = new Image(); - const src = el.getAttribute('data-src'); - img.onload = () => { - el.className = el.className.replace('lazy-img', ''); - el.src = src; - el.removeAttribute('data-src'); - instance.loaded.set(true); - }; - img.src = src; -}; - -const observer = - featureExists && - new IntersectionObserver( - (entries, observer) => - entries.forEach((entry) => { - if (entry.isIntersecting) { - observer.unobserve(entry.target); - return loadImage(entry.target); - } - }), - { - threshold: [0], - trackVisibility: true, - delay: 230, - }, - ); - -export const addImage = (instance) => { - const el = instance.firstNode; - map.set(el, instance); - if (featureExists) { - return observer.observe(el); - } - loadImage(el); -}; diff --git a/apps/meteor/app/lazy-load/client/lazyloadImage.html b/apps/meteor/app/lazy-load/client/lazyloadImage.html deleted file mode 100644 index d39d91f28ca75..0000000000000 --- a/apps/meteor/app/lazy-load/client/lazyloadImage.html +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/apps/meteor/app/lazy-load/client/lazyloadImage.js b/apps/meteor/app/lazy-load/client/lazyloadImage.js deleted file mode 100644 index 93ec353e8564c..0000000000000 --- a/apps/meteor/app/lazy-load/client/lazyloadImage.js +++ /dev/null @@ -1,43 +0,0 @@ -import { ReactiveVar } from 'meteor/reactive-var'; -import { Template } from 'meteor/templating'; - -import './lazyloadImage.html'; -import { addImage } from '.'; - -const emptyImageEncoded = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8+/u3PQAJJAM0dIyWdgAAAABJRU5ErkJggg=='; - -const imgsrcs = new Set(); - -Template.lazyloadImage.helpers({ - class() { - const loaded = Template.instance().loaded.get(); - return `${this.class} ${loaded ? '' : 'lazy-img'}`; - }, - - srcUrl() { - if (Template.instance().loaded.get()) { - return; - } - return this.src; - }, - - lazySrcUrl() { - const { preview, placeholder, src } = this; - const { loaded } = Template.instance(); - - if (loaded.get() || (!preview && !placeholder) || imgsrcs.has(src)) { - return src; - } - - imgsrcs.add(this.src); - return `data:image/png;base64,${preview || emptyImageEncoded}`; - }, -}); - -Template.lazyloadImage.onCreated(function () { - this.loaded = new ReactiveVar(false); -}); - -Template.lazyloadImage.onRendered(function () { - addImage(this); -}); diff --git a/apps/meteor/app/lazy-load/index.js b/apps/meteor/app/lazy-load/index.js deleted file mode 100644 index 40a7340d38877..0000000000000 --- a/apps/meteor/app/lazy-load/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './client/index'; diff --git a/apps/meteor/app/lib/client/OAuthProxy.js b/apps/meteor/app/lib/client/OAuthProxy.js index 5836e145431c9..a5035783c6764 100644 --- a/apps/meteor/app/lib/client/OAuthProxy.js +++ b/apps/meteor/app/lib/client/OAuthProxy.js @@ -1,19 +1,19 @@ -import _ from 'underscore'; import { OAuth } from 'meteor/oauth'; -import { settings } from '../../settings'; +import { settings } from '../../settings/client'; -OAuth.launchLogin = _.wrap(OAuth.launchLogin, function (func, options) { - const proxy = settings.get('Accounts_OAuth_Proxy_services').replace(/\s/g, '').split(','); - if (proxy.includes(options.loginService)) { - const redirect_uri = options.loginUrl.match(/(&redirect_uri=)([^&]+|$)/)[2]; - options.loginUrl = options.loginUrl.replace( - /(&redirect_uri=)([^&]+|$)/, - `$1${encodeURIComponent(settings.get('Accounts_OAuth_Proxy_host'))}/oauth_redirect`, - ); - options.loginUrl = options.loginUrl.replace(/(&state=)([^&]+|$)/, `$1${redirect_uri}!$2`); - options.loginUrl = `${settings.get('Accounts_OAuth_Proxy_host')}/redirect/${encodeURIComponent(options.loginUrl)}`; - } +OAuth.launchLogin = ((func) => + function (options) { + const proxy = settings.get('Accounts_OAuth_Proxy_services').replace(/\s/g, '').split(','); + if (proxy.includes(options.loginService)) { + const redirect_uri = options.loginUrl.match(/(&redirect_uri=)([^&]+|$)/)[2]; + options.loginUrl = options.loginUrl.replace( + /(&redirect_uri=)([^&]+|$)/, + `$1${encodeURIComponent(settings.get('Accounts_OAuth_Proxy_host'))}/oauth_redirect`, + ); + options.loginUrl = options.loginUrl.replace(/(&state=)([^&]+|$)/, `$1${redirect_uri}!$2`); + options.loginUrl = `${settings.get('Accounts_OAuth_Proxy_host')}/redirect/${encodeURIComponent(options.loginUrl)}`; + } - return func(options); -}); + return func(options); + })(OAuth.launchLogin.bind(OAuth)); diff --git a/apps/meteor/app/lib/client/methods/sendMessage.js b/apps/meteor/app/lib/client/methods/sendMessage.js index dad647d5be03e..246c229f77b24 100644 --- a/apps/meteor/app/lib/client/methods/sendMessage.js +++ b/apps/meteor/app/lib/client/methods/sendMessage.js @@ -1,5 +1,4 @@ import { Meteor } from 'meteor/meteor'; -import s from 'underscore.string'; import { ChatMessage, Rooms } from '../../../models/client'; import { settings } from '../../../settings'; @@ -7,10 +6,11 @@ import { callbacks } from '../../../../lib/callbacks'; import { t } from '../../../utils/client'; import { dispatchToastMessage } from '../../../../client/lib/toast'; import { onClientMessageReceived } from '../../../../client/lib/onClientMessageReceived'; +import { trim } from '../../../../lib/utils/stringUtils'; Meteor.methods({ sendMessage(message) { - if (!Meteor.userId() || s.trim(message.msg) === '') { + if (!Meteor.userId() || trim(message.msg) === '') { return false; } const messageAlreadyExists = message._id && ChatMessage.findOne({ _id: message._id }); diff --git a/apps/meteor/app/lib/lib/MessageTypes.ts b/apps/meteor/app/lib/lib/MessageTypes.ts index ebed349dc5488..fe8d675e5d626 100644 --- a/apps/meteor/app/lib/lib/MessageTypes.ts +++ b/apps/meteor/app/lib/lib/MessageTypes.ts @@ -7,29 +7,27 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'r', system: true, - message: 'Room_name_changed', + message: 'Room_name_changed_to', data(message) { return { room_name: message.msg, - user_by: message.u.username, }; }, }); MessageTypes.registerType({ id: 'au', system: true, - message: 'User_added_by', + message: 'User_added_to', data(message) { return { user_added: message.msg, - user_by: message.u.username, }; }, }); MessageTypes.registerType({ id: 'added-user-to-team', system: true, - message: 'Added__username__to_team', + message: 'Added__username__to_this_team', data(message) { return { user_added: message.msg, @@ -39,18 +37,17 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'ru', system: true, - message: 'User_removed_by', + message: 'User_has_been_removed', data(message) { return { user_removed: message.msg, - user_by: message.u.username, }; }, }); MessageTypes.registerType({ id: 'removed-user-from-team', system: true, - message: 'Removed__username__from_team', + message: 'Removed__username__from_the_team', data(message) { return { user_removed: message.msg, @@ -60,27 +57,17 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'ul', system: true, - message: 'User_left', - data(message) { - return { - user_left: message.u.username, - }; - }, + message: 'User_left_this_channel', }); MessageTypes.registerType({ id: 'ult', system: true, - message: 'User_left_team', - data(message) { - return { - user_left: message.u.username, - }; - }, + message: 'User_left_this_team', }); MessageTypes.registerType({ id: 'user-converted-to-team', system: true, - message: 'Converted__roomName__to_team', + message: 'Converted__roomName__to_a_team', data(message) { return { roomName: message.msg, @@ -90,7 +77,7 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'user-converted-to-channel', system: true, - message: 'Converted__roomName__to_channel', + message: 'Converted__roomName__to_a_channel', data(message) { return { roomName: message.msg, @@ -100,7 +87,7 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'user-removed-room-from-team', system: true, - message: 'Removed__roomName__from_this_team', + message: 'Removed__roomName__from_the_team', data(message) { return { roomName: message.msg, @@ -110,7 +97,7 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'user-deleted-room-from-team', system: true, - message: 'Deleted__roomName__', + message: 'Deleted__roomName__room', data(message) { return { roomName: message.msg, @@ -120,7 +107,7 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'user-added-room-to-team', system: true, - message: 'added__roomName__to_team', + message: 'added__roomName__to_this_team', data(message) { return { roomName: message.msg, @@ -130,7 +117,7 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'uj', system: true, - message: 'User_joined_channel', + message: 'User_joined_the_channel', data(message) { return { user: message.u.username, @@ -140,7 +127,7 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'ujt', system: true, - message: 'User_joined_team', + message: 'User_joined_the_team', data(message) { return { user: message.u.username, @@ -150,7 +137,7 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'ut', system: true, - message: 'User_joined_conversation', + message: 'User_joined_the_conversation', data(message) { return { user: message.u.username, @@ -170,12 +157,7 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'rm', system: true, - message: 'Message_removed', - data(message) { - return { - user: message.u.username, - }; - }, + message: 'Message_is_removed', }); // MessageTypes.registerType({ // id: 'rtc', @@ -186,22 +168,20 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'user-muted', system: true, - message: 'User_muted_by', + message: 'User_has_been_muted', data(message) { return { user_muted: message.msg, - user_by: message.u.username, }; }, }); MessageTypes.registerType({ id: 'user-unmuted', system: true, - message: 'User_unmuted_by', + message: 'User_has_been_unmuted', data(message) { return { user_unmuted: message.msg, - user_by: message.u.username, }; }, }); @@ -232,67 +212,37 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'room-archived', system: true, - message: 'This_room_has_been_archived_by__username_', - data(message) { - return { - username: message.u.username, - }; - }, + message: 'This_room_has_been_archived', }); MessageTypes.registerType({ id: 'room-unarchived', system: true, - message: 'This_room_has_been_unarchived_by__username_', - data(message) { - return { - username: message.u.username, - }; - }, + message: 'This_room_has_been_unarchived', }); MessageTypes.registerType({ id: 'room-removed-read-only', system: true, - message: 'room_removed_read_only', - data(message) { - return { - user_by: message.u.username, - }; - }, + message: 'room_removed_read_only_permission', }); MessageTypes.registerType({ id: 'room-set-read-only', system: true, - message: 'room_set_read_only', - data(message) { - return { - user_by: message.u.username, - }; - }, + message: 'room_set_read_only_permission', }); MessageTypes.registerType({ id: 'room-allowed-reacting', system: true, - message: 'room_allowed_reacting', - data(message) { - return { - user_by: message.u.username, - }; - }, + message: 'room_allowed_reactions', }); MessageTypes.registerType({ id: 'room-disallowed-reacting', system: true, - message: 'room_disallowed_reacting', - data(message) { - return { - user_by: message.u.username, - }; - }, + message: 'room_disallowed_reactions', }); MessageTypes.registerType({ id: 'room_e2e_enabled', system: true, - message: 'This_room_encryption_has_been_enabled_by__username_', + message: 'Enabled_E2E_Encryption_for_this_room', data(message) { return { username: message.u.username, @@ -302,34 +252,39 @@ Meteor.startup(function () { MessageTypes.registerType({ id: 'room_e2e_disabled', system: true, - message: 'This_room_encryption_has_been_disabled_by__username_', + message: 'Disabled_E2E_Encryption_for_this_room', data(message) { return { username: message.u.username, }; }, }); + MessageTypes.registerType({ + id: 'videoconf', + system: false, + message: 'Video_Conference', + }); }); export const MessageTypesValues = [ { - key: 'uj', + key: 'uj', // user joined i18nLabel: 'Message_HideType_uj', }, { - key: 'ujt', + key: 'ujt', // user joined team i18nLabel: 'Message_HideType_ujt', }, { - key: 'ul', + key: 'ul', // user left i18nLabel: 'Message_HideType_ul', }, { - key: 'ult', + key: 'ult', // user left team i18nLabel: 'Message_HideType_ult', }, { - key: 'ru', + key: 'ru', // user removed i18nLabel: 'Message_HideType_ru', }, { @@ -337,7 +292,7 @@ export const MessageTypesValues = [ i18nLabel: 'Message_HideType_removed_user_from_team', }, { - key: 'au', + key: 'au', // added user i18nLabel: 'Message_HideType_au', }, { @@ -349,19 +304,19 @@ export const MessageTypesValues = [ i18nLabel: 'Message_HideType_mute_unmute', }, { - key: 'r', + key: 'r', // room name changed i18nLabel: 'Message_HideType_r', }, { - key: 'ut', + key: 'ut', // user joined conversation i18nLabel: 'Message_HideType_ut', }, { - key: 'wm', + key: 'wm', // welcome i18nLabel: 'Message_HideType_wm', }, { - key: 'rm', + key: 'rm', // message removed i18nLabel: 'Message_HideType_rm', }, { @@ -436,4 +391,12 @@ export const MessageTypesValues = [ key: 'user-removed-room-from-team', i18nLabel: 'Message_HideType_user_removed_room_from_team', }, + { + key: 'room_changed_announcement', + i18nLabel: 'Message_HideType_changed_announcement', + }, + { + key: 'room_changed_description', + i18nLabel: 'Message_HideType_changed_description', + }, ]; diff --git a/apps/meteor/app/lib/server/functions/addUserToRoom.ts b/apps/meteor/app/lib/server/functions/addUserToRoom.ts index b0086de4b3fb8..0ae7d3454f622 100644 --- a/apps/meteor/app/lib/server/functions/addUserToRoom.ts +++ b/apps/meteor/app/lib/server/functions/addUserToRoom.ts @@ -1,11 +1,11 @@ import { AppsEngineException } from '@rocket.chat/apps-engine/definition/exceptions'; import { Meteor } from 'meteor/meteor'; import type { IUser, IRoom } from '@rocket.chat/core-typings'; +import { Team } from '@rocket.chat/core-services'; -import { AppEvents, Apps } from '../../../apps/server'; +import { AppEvents, Apps } from '../../../../ee/server/apps'; import { callbacks } from '../../../../lib/callbacks'; import { Messages, Rooms, Subscriptions, Users } from '../../../models/server'; -import { Team } from '../../../../server/sdk'; import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator'; import { RoomMemberActions } from '../../../../definition/IRoomTypeConfig'; @@ -18,22 +18,21 @@ export const addUserToRoom = function ( const now = new Date(); const room: IRoom = Rooms.findOneById(rid); + const userToBeAdded = typeof user !== 'string' ? user : Users.findOneByUsername(user.replace('@', '')); const roomDirectives = roomCoordinator.getRoomDirectives(room.t); if ( - !roomDirectives?.allowMemberAction(room, RoomMemberActions.JOIN) && - !roomDirectives?.allowMemberAction(room, RoomMemberActions.INVITE) + !roomDirectives?.allowMemberAction(room, RoomMemberActions.JOIN, userToBeAdded._id) && + !roomDirectives?.allowMemberAction(room, RoomMemberActions.INVITE, userToBeAdded._id) ) { return; } try { - callbacks.run('federation.beforeAddUserAToRoom', { user, inviter }, room); + callbacks.run('federation.beforeAddUserToARoom', { user, inviter }, room); } catch (error) { throw new Meteor.Error((error as any)?.message); } - const userToBeAdded = typeof user !== 'string' ? user : Users.findOneByUsername(user.replace('@', '')); - // Check if user is already in room const subscription = Subscriptions.findOneByRoomIdAndUserId(rid, userToBeAdded._id); if (subscription) { diff --git a/apps/meteor/app/lib/server/functions/checkEmailAvailability.ts b/apps/meteor/app/lib/server/functions/checkEmailAvailability.ts index b946706dc6b8e..4ac8b724471f7 100644 --- a/apps/meteor/app/lib/server/functions/checkEmailAvailability.ts +++ b/apps/meteor/app/lib/server/functions/checkEmailAvailability.ts @@ -1,9 +1,8 @@ import { Meteor } from 'meteor/meteor'; -import s from 'underscore.string'; import { escapeRegExp } from '@rocket.chat/string-helpers'; export const checkEmailAvailability = function (email: string): boolean { return !Meteor.users.findOne({ - 'emails.address': { $regex: new RegExp(`^${s.trim(escapeRegExp(email))}$`, 'i') }, + 'emails.address': { $regex: new RegExp(`^${escapeRegExp(email).trim()}$`, 'i') }, }); }; diff --git a/apps/meteor/app/lib/server/functions/checkUsernameAvailability.ts b/apps/meteor/app/lib/server/functions/checkUsernameAvailability.ts index f98414ea23ed2..9372126f0e4ef 100644 --- a/apps/meteor/app/lib/server/functions/checkUsernameAvailability.ts +++ b/apps/meteor/app/lib/server/functions/checkUsernameAvailability.ts @@ -1,10 +1,9 @@ import { Meteor } from 'meteor/meteor'; -import s from 'underscore.string'; import _ from 'underscore'; import { escapeRegExp } from '@rocket.chat/string-helpers'; +import { Team } from '@rocket.chat/core-services'; import { settings } from '../../../settings/server'; -import { Team } from '../../../../server/sdk'; import { validateName } from './validateName'; let usernameBlackList: RegExp[] = []; @@ -16,7 +15,7 @@ settings.watch('Accounts_BlockedUsernameList', (value: string) => { }); const usernameIsBlocked = (username: string, usernameBlackList: RegExp[]): boolean | number => - usernameBlackList.length && usernameBlackList.some((restrictedUsername) => restrictedUsername.test(s.trim(escapeRegExp(username)))); + usernameBlackList.length && usernameBlackList.some((restrictedUsername) => restrictedUsername.test(escapeRegExp(username).trim())); export const checkUsernameAvailability = function (username: string): boolean { if (usernameIsBlocked(username, usernameBlackList) || !validateName(username)) { diff --git a/apps/meteor/app/lib/server/functions/cleanRoomHistory.ts b/apps/meteor/app/lib/server/functions/cleanRoomHistory.ts index fa119c0f16f9f..c9280d06bd809 100644 --- a/apps/meteor/app/lib/server/functions/cleanRoomHistory.ts +++ b/apps/meteor/app/lib/server/functions/cleanRoomHistory.ts @@ -1,11 +1,11 @@ import type { FindCursor } from 'mongodb'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import type { IMessage, IMessageDiscussion } from '@rocket.chat/core-typings'; +import { api } from '@rocket.chat/core-services'; import { deleteRoom } from './deleteRoom'; import { FileUpload } from '../../../file-upload/server'; import { Messages, Rooms, Subscriptions } from '../../../models/server'; -import { api } from '../../../../server/sdk/api'; export const cleanRoomHistory = function ({ rid = '', diff --git a/apps/meteor/app/lib/server/functions/closeOmnichannelConversations.ts b/apps/meteor/app/lib/server/functions/closeOmnichannelConversations.ts index 2c891c78d95eb..598bffad18873 100644 --- a/apps/meteor/app/lib/server/functions/closeOmnichannelConversations.ts +++ b/apps/meteor/app/lib/server/functions/closeOmnichannelConversations.ts @@ -3,18 +3,22 @@ import type { IUser } from '@rocket.chat/core-typings'; import { LivechatRooms } from '../../../models/server'; import { settings } from '../../../settings/server'; -import { Livechat } from '../../../livechat/server/lib/Livechat'; +import { Livechat } from '../../../livechat/server/lib/LivechatTyped'; type SubscribedRooms = { rid: string; t: string; }; -export const closeOmnichannelConversations = (user: IUser, subscribedRooms: SubscribedRooms[]): void => { +export const closeOmnichannelConversations = async (user: IUser, subscribedRooms: SubscribedRooms[]): Promise => { const roomsInfo = LivechatRooms.findByIds(subscribedRooms.map(({ rid }) => rid)); const language = settings.get('Language') || 'en'; const comment = TAPi18n.__('Agent_deactivated', { lng: language }); + + const promises: Promise[] = []; roomsInfo.forEach((room: any) => { - Livechat.closeRoom({ user, visitor: {}, room, comment }); + promises.push(Livechat.closeRoom({ user, room, comment })); }); + + await Promise.all(promises); }; diff --git a/apps/meteor/app/lib/server/functions/createDirectRoom.ts b/apps/meteor/app/lib/server/functions/createDirectRoom.ts index 78bcfb780a607..2db3477934657 100644 --- a/apps/meteor/app/lib/server/functions/createDirectRoom.ts +++ b/apps/meteor/app/lib/server/functions/createDirectRoom.ts @@ -4,13 +4,13 @@ import { Random } from 'meteor/random'; import type { ICreatedRoom, ISubscription, IUser } from '@rocket.chat/core-typings'; import { Subscriptions } from '@rocket.chat/models'; import type { MatchKeysAndValues } from 'mongodb'; +import type { ICreateRoomParams } from '@rocket.chat/core-services'; import { Users, Rooms } from '../../../models/server'; -import { Apps } from '../../../apps/server'; +import { Apps } from '../../../../ee/server/apps'; import { callbacks } from '../../../../lib/callbacks'; import { settings } from '../../../settings/server'; import { getDefaultSubscriptionPref } from '../../../utils/server'; -import type { ICreateRoomParams } from '../../../../server/sdk/types/IRoomService'; const generateSubscription = ( fname: string, diff --git a/apps/meteor/app/lib/server/functions/createRoom.ts b/apps/meteor/app/lib/server/functions/createRoom.ts index b0a228decd32f..0291eaf895561 100644 --- a/apps/meteor/app/lib/server/functions/createRoom.ts +++ b/apps/meteor/app/lib/server/functions/createRoom.ts @@ -1,20 +1,19 @@ import { AppsEngineException } from '@rocket.chat/apps-engine/definition/exceptions'; import { Meteor } from 'meteor/meteor'; import _ from 'underscore'; -import s from 'underscore.string'; import type { ICreatedRoom, IUser, IRoom, RoomType } from '@rocket.chat/core-typings'; +import { Team } from '@rocket.chat/core-services'; +import type { ICreateRoomParams, ISubscriptionExtraData } from '@rocket.chat/core-services'; -import { Apps } from '../../../apps/server'; +import { Apps } from '../../../../ee/server/apps'; import { addUserRoles } from '../../../../server/lib/roles/addUserRoles'; import { callbacks } from '../../../../lib/callbacks'; import { Messages, Rooms, Subscriptions, Users } from '../../../models/server'; import { getValidRoomName } from '../../../utils/server'; import { createDirectRoom } from './createDirectRoom'; -import { Team } from '../../../../server/sdk'; -import type { ICreateRoomParams, ISubscriptionExtraData } from '../../../../server/sdk/types/IRoomService'; const isValidName = (name: unknown): name is string => { - return typeof name === 'string' && s.trim(name).length > 0; + return typeof name === 'string' && name.trim().length > 0; }; export const createRoom = function ( @@ -134,7 +133,7 @@ export const createRoom = function ( } try { - callbacks.run('federation.beforeAddUserAToRoom', { user: member, inviter: owner }, room); + callbacks.run('federation.beforeAddUserToARoom', { user: member, inviter: owner }, room); } catch (error) { continue; } @@ -168,7 +167,7 @@ export const createRoom = function ( } callbacks.runAsync('afterCreateRoom', owner, room); if (shouldBeHandledByFederation) { - callbacks.run('federation.afterCreateFederatedRoom', room, { owner, originalMemberList: members as string[] }); + callbacks.runAsync('federation.afterCreateFederatedRoom', room, { owner, originalMemberList: members as string[] }); } Apps.triggerEvent('IPostRoomCreate', room); diff --git a/apps/meteor/app/lib/server/functions/deleteMessage.ts b/apps/meteor/app/lib/server/functions/deleteMessage.ts index b80a513c59f6e..87841dc6229b4 100644 --- a/apps/meteor/app/lib/server/functions/deleteMessage.ts +++ b/apps/meteor/app/lib/server/functions/deleteMessage.ts @@ -1,13 +1,13 @@ import { Meteor } from 'meteor/meteor'; import type { IMessage, IUser } from '@rocket.chat/core-typings'; import { Uploads } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; import { FileUpload } from '../../../file-upload/server'; import { settings } from '../../../settings/server'; import { Messages, Rooms } from '../../../models/server'; -import { api } from '../../../../server/sdk/api'; import { callbacks } from '../../../../lib/callbacks'; -import { Apps } from '../../../apps/server'; +import { Apps } from '../../../../ee/server/apps'; export const deleteMessage = async function (message: IMessage, user: IUser): Promise { const deletedMsg = Messages.findOneById(message._id); @@ -49,7 +49,7 @@ export const deleteMessage = async function (message: IMessage, user: IUser): Pr }); } - const room = Rooms.findOneById(message.rid, { fields: { lastMessage: 1, prid: 1, mid: 1 } }); + const room = Rooms.findOneById(message.rid, { fields: { lastMessage: 1, prid: 1, mid: 1, federated: 1 } }); callbacks.run('afterDeleteMessage', deletedMsg, room); // update last message diff --git a/apps/meteor/app/lib/server/functions/deleteUser.ts b/apps/meteor/app/lib/server/functions/deleteUser.ts index d80bfe7ad5d63..b6e20cd1798ed 100644 --- a/apps/meteor/app/lib/server/functions/deleteUser.ts +++ b/apps/meteor/app/lib/server/functions/deleteUser.ts @@ -2,6 +2,7 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import type { FileProp } from '@rocket.chat/core-typings'; import { Integrations, FederationServers, LivechatVisitors } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; import { FileUpload } from '../../../file-upload/server'; import { Users, Subscriptions, Messages, Rooms, LivechatDepartmentAgents } from '../../../models/server'; @@ -10,26 +11,17 @@ import { updateGroupDMsName } from './updateGroupDMsName'; import { relinquishRoomOwnerships } from './relinquishRoomOwnerships'; import { getSubscribedRoomsForUserWithDetails, shouldRemoveOrChangeOwner } from './getRoomsWithSingleOwner'; import { getUserSingleOwnedRooms } from './getUserSingleOwnedRooms'; -import { api } from '../../../../server/sdk/api'; import { LivechatUnitMonitors } from '../../../../ee/app/models/server'; export async function deleteUser(userId: string, confirmRelinquish = false): Promise { const user = Users.findOneById(userId, { - fields: { username: 1, avatarOrigin: 1, federation: 1, roles: 1 }, + fields: { username: 1, avatarOrigin: 1, roles: 1, federated: 1 }, }); if (!user) { return; } - if (user.federation) { - const existingSubscriptions = Subscriptions.find({ 'u._id': user._id }).count(); - - if (existingSubscriptions > 0) { - throw new Meteor.Error('FEDERATION_Error_user_is_federated_on_rooms'); - } - } - const subscribedRooms = getSubscribedRoomsForUserWithDetails(userId); if (shouldRemoveOrChangeOwner(subscribedRooms) && !confirmRelinquish) { @@ -65,15 +57,17 @@ export async function deleteUser(userId: string, confirmRelinquish = false): Pro if (user.roles.includes('livechat-agent')) { // Remove user as livechat agent LivechatDepartmentAgents.removeByAgentId(userId); - await LivechatVisitors.removeContactManagerByUsername(user.username); } if (user.roles.includes('livechat-monitor')) { // Remove user as Unit Monitor LivechatUnitMonitors.removeByMonitorId(userId); - await LivechatVisitors.removeContactManagerByUsername(user.username); } + // This is for compatibility. Since we allowed any user to be contact manager b4, we need to have the same logic + // for deletion. + await LivechatVisitors.removeContactManagerByUsername(user.username); + // removes user's avatar if (user.avatarOrigin === 'upload' || user.avatarOrigin === 'url' || user.avatarOrigin === 'rest') { FileUpload.getStore('Avatars').deleteByName(user.username); diff --git a/apps/meteor/app/lib/server/functions/getAvatarSuggestionForUser.js b/apps/meteor/app/lib/server/functions/getAvatarSuggestionForUser.js deleted file mode 100644 index e7bf5755f362e..0000000000000 --- a/apps/meteor/app/lib/server/functions/getAvatarSuggestionForUser.js +++ /dev/null @@ -1,160 +0,0 @@ -import { check } from 'meteor/check'; -import { Gravatar } from 'meteor/jparker:gravatar'; -import { ServiceConfiguration } from 'meteor/service-configuration'; - -import { settings } from '../../../settings/server'; -import { fetch } from '../../../../server/lib/http/fetch'; - -const avatarProviders = { - facebook(user) { - if (user.services && user.services.facebook && user.services.facebook.id && settings.get('Accounts_OAuth_Facebook')) { - return { - service: 'facebook', - url: `https://graph.facebook.com/${user.services.facebook.id}/picture?type=large`, - }; - } - }, - - google(user) { - if ( - user.services && - user.services.google && - user.services.google.picture && - user.services.google.picture !== 'https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAAA/4252rscbv5M/photo.jpg' && - settings.get('Accounts_OAuth_Google') - ) { - return { - service: 'google', - url: user.services.google.picture, - }; - } - }, - - github(user) { - if (user.services && user.services.github && user.services.github.username && settings.get('Accounts_OAuth_Github')) { - return { - service: 'github', - url: `https://avatars.githubusercontent.com/${user.services.github.username}?s=200`, - }; - } - }, - - linkedin(user) { - if ( - user.services && - user.services.linkedin && - user.services.linkedin.profilePicture && - user.services.linkedin.profilePicture.identifiersUrl && - user.services.linkedin.profilePicture.identifiersUrl.length > 0 && - settings.get('Accounts_OAuth_Linkedin') - ) { - const total = user.services.linkedin.profilePicture.identifiersUrl.length; - return { - service: 'linkedin', - url: user.services.linkedin.profilePicture.identifiersUrl[total - 1], - }; - } - }, - - twitter(user) { - if (user.services && user.services.twitter && user.services.twitter.profile_image_url_https && settings.get('Accounts_OAuth_Twitter')) { - return { - service: 'twitter', - url: user.services.twitter.profile_image_url_https.replace(/_normal|_bigger/, ''), - }; - } - }, - - gitlab(user) { - if (user.services && user.services.gitlab && user.services.gitlab.avatar_url && settings.get('Accounts_OAuth_Gitlab')) { - return { - service: 'gitlab', - url: user.services.gitlab.avatar_url, - }; - } - }, - - customOAuth(user) { - const avatars = []; - for (const service in user.services) { - if (user.services[service]._OAuthCustom) { - const services = ServiceConfiguration.configurations.find({ service }, { fields: { secret: 0 } }).fetch(); - - if (services.length > 0) { - if (user.services[service].avatarUrl) { - avatars.push({ - service, - url: user.services[service].avatarUrl, - }); - } - } - } - } - return avatars; - }, - - emails(user) { - const avatars = []; - if (user.emails && user.emails.length > 0) { - for (const email of user.emails) { - if (email.verified === true) { - avatars.push({ - service: 'gravatar', - url: Gravatar.imageUrl(email.address, { - default: '404', - size: 200, - secure: true, - }), - }); - } - - if (email.verified !== true) { - avatars.push({ - service: 'gravatar', - url: Gravatar.imageUrl(email.address, { - default: '404', - size: 200, - secure: true, - }), - }); - } - } - } - return avatars; - }, -}; - -export async function getAvatarSuggestionForUser(user) { - check(user, Object); - - const avatars = []; - - for (const avatarProvider of Object.values(avatarProviders)) { - const avatar = avatarProvider(user); - if (avatar) { - if (Array.isArray(avatar)) { - avatars.push(...avatar); - } else { - avatars.push(avatar); - } - } - } - - const validAvatars = {}; - for await (const avatar of avatars) { - try { - const response = await fetch(avatar.url); - - if (response.status === 200) { - let blob = `data:${response.headers.get('content-type')};base64,`; - blob += Buffer.from(await response.arrayBuffer()).toString('base64'); - avatar.blob = blob; - avatar.contentType = response.headers.get('content-type'); - validAvatars[avatar.service] = avatar; - } - } catch (error) { - // error; - } - } - return validAvatars; -} diff --git a/apps/meteor/app/lib/server/functions/getAvatarSuggestionForUser.ts b/apps/meteor/app/lib/server/functions/getAvatarSuggestionForUser.ts new file mode 100644 index 0000000000000..c1e50de9c75db --- /dev/null +++ b/apps/meteor/app/lib/server/functions/getAvatarSuggestionForUser.ts @@ -0,0 +1,168 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import { check } from 'meteor/check'; +import { Gravatar } from 'meteor/jparker:gravatar'; +import { ServiceConfiguration } from 'meteor/service-configuration'; +import type { IUser } from '@rocket.chat/core-typings'; + +import { settings } from '../../../settings/server'; +import { fetch } from '../../../../server/lib/http/fetch'; + +const avatarProviders = { + facebook(user: IUser) { + if (user.services?.facebook?.id && settings.get('Accounts_OAuth_Facebook')) { + return { + service: 'facebook', + url: `https://graph.facebook.com/${user.services.facebook.id}/picture?type=large`, + }; + } + }, + + google(user: IUser) { + if ( + user.services?.google?.picture && + user.services.google.picture !== 'https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAAA/4252rscbv5M/photo.jpg' && + settings.get('Accounts_OAuth_Google') + ) { + return { + service: 'google', + url: user.services.google.picture, + }; + } + }, + + github(user: IUser) { + if (user.services?.github?.username && settings.get('Accounts_OAuth_Github')) { + return { + service: 'github', + url: `https://avatars.githubusercontent.com/${user.services.github.username}?s=200`, + }; + } + }, + + linkedin(user: IUser) { + if ( + user.services?.linkedin?.profilePicture?.identifiersUrl && + user.services.linkedin.profilePicture.identifiersUrl.length > 0 && + settings.get('Accounts_OAuth_Linkedin') + ) { + const total = user.services.linkedin.profilePicture.identifiersUrl.length; + return { + service: 'linkedin', + url: user.services.linkedin.profilePicture.identifiersUrl[total - 1], + }; + } + }, + + twitter(user: IUser) { + if (user.services?.twitter?.profile_image_url_https && settings.get('Accounts_OAuth_Twitter')) { + return { + service: 'twitter', + url: user.services.twitter.profile_image_url_https.replace(/_normal|_bigger/, ''), + }; + } + }, + + gitlab(user: IUser) { + if (user.services?.gitlab?.avatar_url && settings.get('Accounts_OAuth_Gitlab')) { + return { + service: 'gitlab', + url: user.services.gitlab.avatar_url, + }; + } + }, + + customOAuth(user: IUser) { + const avatars = []; + for (const service in user.services) { + if (user.services[service as keyof typeof user.services]._OAuthCustom) { + const services = ServiceConfiguration.configurations.find({ service }, { fields: { secret: 0 } }).fetch(); + + if (services.length > 0) { + if (user.services[service as keyof typeof user.services].avatarUrl) { + avatars.push({ + service, + url: user.services[service as keyof typeof user.services].avatarUrl, + }); + } + } + } + } + return avatars; + }, + + emails(user: IUser) { + const avatars = []; + if (user.emails && user.emails.length > 0) { + for (const email of user.emails) { + if (email.verified === true) { + avatars.push({ + service: 'gravatar', + url: Gravatar.imageUrl(email.address, { + default: '404', + size: 200, + secure: true, + }), + }); + } + + if (email.verified !== true) { + avatars.push({ + service: 'gravatar', + url: Gravatar.imageUrl(email.address, { + default: '404', + size: 200, + secure: true, + }), + }); + } + } + } + return avatars; + }, +}; + +/** + * @return {Object} + */ +export async function getAvatarSuggestionForUser( + user: IUser, +): Promise> { + check(user, Object); + + const avatars = []; + + for (const avatarProvider of Object.values(avatarProviders)) { + const avatar = avatarProvider(user); + if (avatar) { + if (Array.isArray(avatar)) { + avatars.push(...avatar); + } else { + avatars.push(avatar); + } + } + } + + const validAvatars: Record = {}; + for await (const avatar of avatars) { + try { + const response = await fetch(avatar.url); + const newAvatar: { service: string; url: string; blob: string; contentType: string } = { + service: avatar.service, + url: avatar.url, + blob: '', + contentType: '', + }; + + if (response.status === 200) { + let blob = `data:${response.headers.get('content-type')};base64,`; + blob += Buffer.from(await response.arrayBuffer()).toString('base64'); + newAvatar.blob = blob; + newAvatar.contentType = response.headers.get('content-type')!; + validAvatars[avatar.service] = newAvatar; + } + } catch (error) { + // error; + } + } + return validAvatars; +} diff --git a/apps/meteor/app/lib/server/functions/getUserCreatedByApp.ts b/apps/meteor/app/lib/server/functions/getUserCreatedByApp.ts new file mode 100644 index 0000000000000..7073f9ccd541b --- /dev/null +++ b/apps/meteor/app/lib/server/functions/getUserCreatedByApp.ts @@ -0,0 +1,13 @@ +import type { FindOptions } from 'mongodb'; +import type { IUser } from '@rocket.chat/core-typings'; +import { Users } from '@rocket.chat/models'; +import type { UserType } from '@rocket.chat/apps-engine/definition/users'; + +export async function getUserCreatedByApp( + appId: string, + type: UserType.BOT | UserType.APP, + options?: FindOptions, +): Promise> { + const users = await Users.find({ appId, type }, options).toArray(); + return users ?? []; +} diff --git a/apps/meteor/app/lib/server/functions/index.ts b/apps/meteor/app/lib/server/functions/index.ts index 28b32d26b2033..857644be5f848 100644 --- a/apps/meteor/app/lib/server/functions/index.ts +++ b/apps/meteor/app/lib/server/functions/index.ts @@ -12,6 +12,7 @@ export { deleteRoom } from './deleteRoom'; export { deleteUser } from './deleteUser'; export { getRoomByNameOrIdWithOptionToJoin } from './getRoomByNameOrIdWithOptionToJoin'; export { getUserSingleOwnedRooms } from './getUserSingleOwnedRooms'; +export { getUserCreatedByApp } from './getUserCreatedByApp'; export { generateUsernameSuggestion } from './getUsernameSuggestion'; export { insertMessage } from './insertMessage'; export { isTheLastMessage } from './isTheLastMessage'; @@ -26,7 +27,7 @@ export { saveUserIdentity } from './saveUserIdentity'; export { sendMessage } from './sendMessage'; export { setEmail } from './setEmail'; export { setRealName, _setRealName } from './setRealName'; -export { setStatusText, _setStatusText, _setStatusTextPromise } from './setStatusText'; +export { setStatusText } from './setStatusText'; export { getStatusText } from './getStatusText'; export { setUserAvatar } from './setUserAvatar'; export { _setUsername, setUsername } from './setUsername'; diff --git a/apps/meteor/app/lib/server/functions/loadMessageHistory.ts b/apps/meteor/app/lib/server/functions/loadMessageHistory.ts index 3fe64be17d9ea..0dd28d080a574 100644 --- a/apps/meteor/app/lib/server/functions/loadMessageHistory.ts +++ b/apps/meteor/app/lib/server/functions/loadMessageHistory.ts @@ -1,5 +1,4 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ -import { settings } from '../../../settings/server'; import { Messages, Rooms } from '../../../models/server'; import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser'; import { getHiddenSystemMessages } from '../lib/getHiddenSystemMessages'; @@ -34,12 +33,6 @@ export function loadMessageHistory({ fields: {}, }; - if (!settings.get('Message_ShowEditedStatus')) { - options.fields = { - editedAt: 0, - }; - } - const records = end != null ? Messages.findVisibleByRoomIdBeforeTimestampNotContainingTypes(rid, end, hiddenMessageTypes, options, showThreadMessages).fetch() diff --git a/apps/meteor/app/lib/server/functions/notifications/desktop.js b/apps/meteor/app/lib/server/functions/notifications/desktop.js index d510431231397..ee2e56cd9935e 100644 --- a/apps/meteor/app/lib/server/functions/notifications/desktop.js +++ b/apps/meteor/app/lib/server/functions/notifications/desktop.js @@ -1,5 +1,6 @@ +import { api } from '@rocket.chat/core-services'; + import { roomCoordinator } from '../../../../../server/lib/rooms/roomCoordinator'; -import { api } from '../../../../../server/sdk/api'; import { metrics } from '../../../../metrics/server'; import { settings } from '../../../../settings/server'; diff --git a/apps/meteor/app/lib/server/functions/notifications/email.js b/apps/meteor/app/lib/server/functions/notifications/email.js index d9f9cf17d581f..2cc0d37b24ac4 100644 --- a/apps/meteor/app/lib/server/functions/notifications/email.js +++ b/apps/meteor/app/lib/server/functions/notifications/email.js @@ -1,6 +1,5 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import s from 'underscore.string'; import { escapeHTML } from '@rocket.chat/string-helpers'; import * as Mailer from '../../../../mailer'; @@ -9,6 +8,7 @@ import { metrics } from '../../../../metrics'; import { callbacks } from '../../../../../lib/callbacks'; import { getURL } from '../../../../utils/server'; import { roomCoordinator } from '../../../../../server/lib/rooms/roomCoordinator'; +import { ltrim } from '../../../../../lib/utils/stringUtils'; let advice = ''; let goToMessage = ''; @@ -101,7 +101,7 @@ function getEmailContent({ message, user, room }) { const getButtonUrl = (room, subscription, message) => { const basePath = roomCoordinator.getRouteLink(room.t, subscription).replace(Meteor.absoluteUrl(), ''); - const path = `${s.ltrim(basePath, '/')}?msg=${message._id}`; + const path = `${ltrim(basePath, '/')}?msg=${message._id}`; return getURL(path, { full: true, cloud: settings.get('Offline_Message_Use_DeepLink'), diff --git a/apps/meteor/app/lib/server/functions/parseUrlsInMessage.js b/apps/meteor/app/lib/server/functions/parseUrlsInMessage.js index 58a6d48772bda..b4141b094d6cb 100644 --- a/apps/meteor/app/lib/server/functions/parseUrlsInMessage.js +++ b/apps/meteor/app/lib/server/functions/parseUrlsInMessage.js @@ -1,4 +1,5 @@ import { Markdown } from '../../../markdown/server'; +import { getMessageUrlRegex } from '../../../../lib/getMessageUrlRegex.ts'; export const parseUrlsInMessage = (message) => { if (message.parseUrls === false) { @@ -8,10 +9,7 @@ export const parseUrlsInMessage = (message) => { message.html = message.msg; message = Markdown.code(message); - const urls = - message.html.match( - /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]*)?\??([-\+=&!:;%@\/\.\,\w]+)?(?:#([^\s\)]+))?)?/g, - ) || []; + const urls = message.html.match(getMessageUrlRegex()) || []; if (urls) { message.urls = [...new Set(urls)].map((url) => ({ url })); } diff --git a/apps/meteor/app/lib/server/functions/processWebhookMessage.js b/apps/meteor/app/lib/server/functions/processWebhookMessage.js index 26b4f17975c45..466964f400c29 100644 --- a/apps/meteor/app/lib/server/functions/processWebhookMessage.js +++ b/apps/meteor/app/lib/server/functions/processWebhookMessage.js @@ -1,11 +1,11 @@ import { Meteor } from 'meteor/meteor'; import _ from 'underscore'; -import s from 'underscore.string'; import { getRoomByNameOrIdWithOptionToJoin } from './getRoomByNameOrIdWithOptionToJoin'; import { sendMessage } from './sendMessage'; import { validateRoomMessagePermissions } from '../../../authorization/server/functions/canSendMessage'; import { SystemLogger } from '../../../../server/lib/logger/system'; +import { trim } from '../../../../lib/utils/stringUtils'; export const processWebhookMessage = function (messageObj, user, defaultValues = { channel: '', alias: '', avatar: '', emoji: '' }) { const sentData = []; @@ -71,7 +71,7 @@ export const processWebhookMessage = function (messageObj, user, defaultValues = const message = { alias: messageObj.username || messageObj.alias || defaultValues.alias, - msg: s.trim(messageObj.text || messageObj.msg || ''), + msg: trim(messageObj.text || messageObj.msg || ''), attachments: messageObj.attachments || [], parseUrls: messageObj.parseUrls !== undefined ? messageObj.parseUrls : !messageObj.attachments, bot: messageObj.bot, @@ -89,11 +89,11 @@ export const processWebhookMessage = function (messageObj, user, defaultValues = message.emoji = defaultValues.emoji; } - if (_.isArray(message.attachments)) { + if (Array.isArray(message.attachments)) { for (let i = 0; i < message.attachments.length; i++) { const attachment = message.attachments[i]; if (attachment.msg) { - attachment.text = s.trim(attachment.msg); + attachment.text = trim(attachment.msg); delete attachment.msg; } } diff --git a/apps/meteor/app/lib/server/functions/removeUserFromRoom.ts b/apps/meteor/app/lib/server/functions/removeUserFromRoom.ts index ea71bb240abfd..7bdf20e3f9a2c 100644 --- a/apps/meteor/app/lib/server/functions/removeUserFromRoom.ts +++ b/apps/meteor/app/lib/server/functions/removeUserFromRoom.ts @@ -2,11 +2,11 @@ import { AppsEngineException } from '@rocket.chat/apps-engine/definition/exceptions'; import { Meteor } from 'meteor/meteor'; import type { IUser } from '@rocket.chat/core-typings'; +import { Team } from '@rocket.chat/core-services'; import { Rooms, Messages, Subscriptions } from '../../../models/server'; -import { AppEvents, Apps } from '../../../apps/server'; +import { AppEvents, Apps } from '../../../../ee/server/apps'; import { callbacks } from '../../../../lib/callbacks'; -import { Team } from '../../../../server/sdk'; export const removeUserFromRoom = async function ( rid: string, diff --git a/apps/meteor/app/lib/server/functions/saveCustomFields.ts b/apps/meteor/app/lib/server/functions/saveCustomFields.ts index 228b3cb146580..4dc83a7bb3727 100644 --- a/apps/meteor/app/lib/server/functions/saveCustomFields.ts +++ b/apps/meteor/app/lib/server/functions/saveCustomFields.ts @@ -1,10 +1,9 @@ -import s from 'underscore.string'; - import { settings } from '../../../settings/server'; import { validateCustomFields, saveCustomFieldsWithoutValidation } from '.'; +import { trim } from '../../../../lib/utils/stringUtils'; export const saveCustomFields = function (userId: string, formData: unknown): void { - if (s.trim(settings.get('Accounts_CustomFields')) !== '') { + if (trim(settings.get('Accounts_CustomFields')) !== '') { validateCustomFields(formData); return saveCustomFieldsWithoutValidation(userId, formData); } diff --git a/apps/meteor/app/lib/server/functions/saveCustomFieldsWithoutValidation.js b/apps/meteor/app/lib/server/functions/saveCustomFieldsWithoutValidation.js index 17fcbbb90f453..ecbb57f47f3d3 100644 --- a/apps/meteor/app/lib/server/functions/saveCustomFieldsWithoutValidation.js +++ b/apps/meteor/app/lib/server/functions/saveCustomFieldsWithoutValidation.js @@ -1,11 +1,11 @@ import { Meteor } from 'meteor/meteor'; -import s from 'underscore.string'; import { settings } from '../../../settings/server'; import { Users, Subscriptions } from '../../../models/server'; +import { trim } from '../../../../lib/utils/stringUtils'; export const saveCustomFieldsWithoutValidation = function (userId, formData) { - if (s.trim(settings.get('Accounts_CustomFields')) !== '') { + if (trim(settings.get('Accounts_CustomFields')) !== '') { let customFieldsMeta; try { customFieldsMeta = JSON.parse(settings.get('Accounts_CustomFields')); diff --git a/apps/meteor/app/lib/server/functions/saveUser.js b/apps/meteor/app/lib/server/functions/saveUser.js index 0b808f1bb1f8f..5f6eeb411c37d 100644 --- a/apps/meteor/app/lib/server/functions/saveUser.js +++ b/apps/meteor/app/lib/server/functions/saveUser.js @@ -1,7 +1,6 @@ import { Meteor } from 'meteor/meteor'; import { Accounts } from 'meteor/accounts-base'; import _ from 'underscore'; -import s from 'underscore.string'; import { Gravatar } from 'meteor/jparker:gravatar'; import { isUserFederated } from '@rocket.chat/core-typings'; @@ -15,8 +14,9 @@ import { saveUserIdentity } from './saveUserIdentity'; import { checkEmailAvailability, checkUsernameAvailability, setUserAvatar, setEmail, setStatusText } from '.'; import { Users } from '../../../models/server'; import { callbacks } from '../../../../lib/callbacks'; -import { AppEvents, Apps } from '../../../apps/server/orchestrator'; +import { AppEvents, Apps } from '../../../../ee/server/apps/orchestrator'; import { safeGetMeteorUser } from '../../../utils/server/functions/safeGetMeteorUser'; +import { trim } from '../../../../lib/utils/stringUtils'; const MAX_BIO_LENGTH = 260; const MAX_NICKNAME_LENGTH = 120; @@ -83,21 +83,21 @@ function validateUserData(userId, userData) { }); } - if (userData.roles && _.indexOf(userData.roles, 'admin') >= 0 && !hasPermission(userId, 'assign-admin-role')) { + if (userData.roles && userData.roles.includes('admin') && !hasPermission(userId, 'assign-admin-role')) { throw new Meteor.Error('error-action-not-allowed', 'Assigning admin is not allowed', { method: 'insertOrUpdateUser', action: 'Assign_admin', }); } - if (settings.get('Accounts_RequireNameForSignUp') && !userData._id && !s.trim(userData.name)) { + if (settings.get('Accounts_RequireNameForSignUp') && !userData._id && !trim(userData.name)) { throw new Meteor.Error('error-the-field-is-required', 'The field Name is required', { method: 'insertOrUpdateUser', field: 'Name', }); } - if (!userData._id && !s.trim(userData.username)) { + if (!userData._id && !trim(userData.username)) { throw new Meteor.Error('error-the-field-is-required', 'The field Username is required', { method: 'insertOrUpdateUser', field: 'Username', diff --git a/apps/meteor/app/lib/server/functions/sendMessage.js b/apps/meteor/app/lib/server/functions/sendMessage.js index 7af4c0f11646b..8271f18749bdf 100644 --- a/apps/meteor/app/lib/server/functions/sendMessage.js +++ b/apps/meteor/app/lib/server/functions/sendMessage.js @@ -3,13 +3,13 @@ import { Match, check } from 'meteor/check'; import { settings } from '../../../settings/server'; import { callbacks } from '../../../../lib/callbacks'; import { Messages } from '../../../models/server'; -import { Apps } from '../../../apps/server'; +import { Apps } from '../../../../ee/server/apps'; import { isURL } from '../../../../lib/utils/isURL'; import { FileUpload } from '../../../file-upload/server'; import { hasPermission } from '../../../authorization/server'; -import { SystemLogger } from '../../../../server/lib/logger/system'; import { parseUrlsInMessage } from './parseUrlsInMessage'; import { isRelativeURL } from '../../../../lib/utils/isRelativeURL'; +import notifications from '../../../notifications/server/lib/Notifications'; /** * IMPORTANT @@ -219,10 +219,6 @@ export const sendMessage = function (user, message, room, upsert = false) { if (Apps && Apps.isLoaded()) { const prevent = Promise.await(Apps.getBridges().getListenerBridge().messageEvent('IPreMessageSentPrevent', message)); if (prevent) { - if (settings.get('Apps_Framework_Development_Mode')) { - SystemLogger.info({ msg: 'A Rocket.Chat App prevented the message sending.', message }); - } - return; } @@ -244,38 +240,40 @@ export const sendMessage = function (user, message, room, upsert = false) { message = callbacks.run('beforeSaveMessage', message, room); if (!settings.get('Livechat_kill_switch') || room.lastMessage.msg !== settings.get('Livechat_kill_switch_message')) { - if (message) { - if (message._id && upsert) { - const { _id } = message; - delete message._id; - Messages.upsert( - { - _id, - 'u._id': message.u._id, - }, - message, - ); - message._id = _id; - } else { - const messageAlreadyExists = message._id && Messages.findOneById(message._id, { fields: { _id: 1 } }); - if (messageAlreadyExists) { - return; - } - message._id = Messages.insert(message); - } - - if (Apps && Apps.isLoaded()) { - // This returns a promise, but it won't mutate anything about the message - // so, we don't really care if it is successful or fails - Apps.getBridges().getListenerBridge().messageEvent('IPostMessageSent', message); + if (message.t === 'otr') { + const otrStreamer = notifications.streamRoomMessage; + otrStreamer.emit(message.rid, message, user, room); + } else if (message._id && upsert) { + const { _id } = message; + delete message._id; + Messages.upsert( + { + _id, + 'u._id': message.u._id, + }, + message, + ); + message._id = _id; + } else { + const messageAlreadyExists = message._id && Messages.findOneById(message._id, { fields: { _id: 1 } }); + if (messageAlreadyExists) { + return; } + message._id = Messages.insert(message); + } - /* - Defer other updates as their return is not interesting to the user - */ - // Execute all callbacks - callbacks.runAsync('afterSaveMessage', message, room, user._id); - return message; + if (Apps && Apps.isLoaded()) { + // This returns a promise, but it won't mutate anything about the message + // so, we don't really care if it is successful or fails + Apps.getBridges().getListenerBridge().messageEvent('IPostMessageSent', message); } + + /* + Defer other updates as their return is not interesting to the user + */ + + // Execute all callbacks + callbacks.runAsync('afterSaveMessage', message, room); + return message; } }; diff --git a/apps/meteor/app/lib/server/functions/setEmail.ts b/apps/meteor/app/lib/server/functions/setEmail.ts index cc25ab97b6443..57dcd7489cd33 100644 --- a/apps/meteor/app/lib/server/functions/setEmail.ts +++ b/apps/meteor/app/lib/server/functions/setEmail.ts @@ -1,6 +1,4 @@ -/* eslint-disable @typescript-eslint/explicit-function-return-type */ import { Meteor } from 'meteor/meteor'; -import s from 'underscore.string'; import { escapeHTML } from '@rocket.chat/string-helpers'; import { Users } from '../../../models/server'; @@ -40,7 +38,7 @@ const _sendEmailChangeNotification = function (to: string, newEmail: string) { }; const _setEmail = function (userId: string, email: string, shouldSendVerificationEmail = true) { - email = s.trim(email); + email = email.trim(); if (!userId) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { function: '_setEmail' }); } diff --git a/apps/meteor/app/lib/server/functions/setRealName.ts b/apps/meteor/app/lib/server/functions/setRealName.ts index 493b211aab02f..af6cafff2f221 100644 --- a/apps/meteor/app/lib/server/functions/setRealName.ts +++ b/apps/meteor/app/lib/server/functions/setRealName.ts @@ -1,15 +1,14 @@ import { Meteor } from 'meteor/meteor'; -import s from 'underscore.string'; import type { IUser } from '@rocket.chat/core-typings'; +import { api } from '@rocket.chat/core-services'; import { Users } from '../../../models/server'; import { settings } from '../../../settings/server'; import { hasPermission } from '../../../authorization/server'; import { RateLimiter } from '../lib'; -import { api } from '../../../../server/sdk/api'; export const _setRealName = function (userId: string, name: string, fullUser: IUser): IUser | undefined { - name = s.trim(name); + name = name.trim(); if (!userId || (settings.get('Accounts_RequireNameForSignUp') && !name)) { return; @@ -22,7 +21,7 @@ export const _setRealName = function (userId: string, name: string, fullUser: IU } // User already has desired name, return - if (user.name && s.trim(user.name) === name) { + if (user.name && user.name.trim() === name) { return user; } @@ -41,6 +40,11 @@ export const _setRealName = function (userId: string, name: string, fullUser: IU username: user.username, }); } + api.broadcast('user.realNameChanged', { + _id: user._id, + name, + username: user.username, + }); return user; }; diff --git a/apps/meteor/app/lib/server/functions/setRoomAvatar.ts b/apps/meteor/app/lib/server/functions/setRoomAvatar.ts index d67eafd1c51c4..975bbb96adbad 100644 --- a/apps/meteor/app/lib/server/functions/setRoomAvatar.ts +++ b/apps/meteor/app/lib/server/functions/setRoomAvatar.ts @@ -1,11 +1,11 @@ import { Meteor } from 'meteor/meteor'; import type { IUser } from '@rocket.chat/core-typings'; import { Avatars } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; import { RocketChatFile } from '../../../file'; import { FileUpload } from '../../../file-upload/server'; import { Rooms, Messages } from '../../../models/server'; -import { api } from '../../../../server/sdk/api'; export const setRoomAvatar = async function (rid: string, dataURI: string, user: IUser): Promise { const fileStore = FileUpload.getStore('Avatars'); @@ -31,15 +31,16 @@ export const setRoomAvatar = async function (rid: string, dataURI: string, user: uid: user._id, }; + if (current) { + fileStore.deleteById(current._id); + } + fileStore.insert(file, buffer, (err: unknown, result: { etag: string }) => { if (err) { throw err; } Meteor.setTimeout(function () { - if (current) { - fileStore.deleteById(current._id); - } Rooms.setAvatarData(rid, 'upload', result.etag); Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser('room_changed_avatar', rid, '', user); api.broadcast('room.avatarUpdate', { _id: rid, avatarETag: result.etag }); diff --git a/apps/meteor/app/lib/server/functions/setStatusText.ts b/apps/meteor/app/lib/server/functions/setStatusText.ts index 3077061f48b7c..b6b6e69a043aa 100644 --- a/apps/meteor/app/lib/server/functions/setStatusText.ts +++ b/apps/meteor/app/lib/server/functions/setStatusText.ts @@ -1,21 +1,21 @@ import { Meteor } from 'meteor/meteor'; -import s from 'underscore.string'; import type { IUser } from '@rocket.chat/core-typings'; -import { Users as UsersRaw } from '@rocket.chat/models'; +import { Users } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; -import { Users } from '../../../models/server'; import { hasPermission } from '../../../authorization/server'; import { RateLimiter } from '../lib'; -import { api } from '../../../../server/sdk/api'; -export const _setStatusTextPromise = async function (userId: string, statusText: string): Promise { +async function _setStatusTextPromise(userId: string, statusText: string): Promise { if (!userId) { return false; } - statusText = s.trim(statusText).substr(0, 120); + statusText = statusText.trim().substr(0, 120); - const user = await UsersRaw.findOneById(userId); + const user = await Users.findOneById>(userId, { + projection: { username: 1, name: 1, status: 1, roles: 1, statusText: 1 }, + }); if (!user) { return false; @@ -25,44 +25,20 @@ export const _setStatusTextPromise = async function (userId: string, statusText: return true; } - await UsersRaw.updateStatusText(user._id, statusText); + await Users.updateStatusText(user._id, statusText); - const { _id, username, status } = user; + const { _id, username, status, name, roles } = user; api.broadcast('presence.status', { - user: { _id, username, status, statusText }, + user: { _id, username, status, statusText, name, roles }, + previousStatus: status, }); return true; -}; - -export const _setStatusText = function (userId: any, statusText: string): IUser | boolean { - statusText = s.trim(statusText); - if (statusText.length > 120) { - statusText = statusText.substr(0, 120); - } - - if (!userId) { - return false; - } - - const user = Users.findOneById(userId); +} - // User already has desired statusText, return - if (user.statusText === statusText) { - return user; - } - - // Set new statusText - Users.updateStatusText(user._id, statusText); - user.statusText = statusText; - - const { _id, username, status } = user; - api.broadcast('presence.status', { - user: { _id, username, status, statusText }, - }); - - return true; -}; +function _setStatusText(userId: any, statusText: string): boolean { + return Promise.await(_setStatusTextPromise(userId, statusText)); +} export const setStatusText = RateLimiter.limitFunction(_setStatusText, 5, 60000, { 0() { diff --git a/apps/meteor/app/lib/server/functions/setUserActiveStatus.ts b/apps/meteor/app/lib/server/functions/setUserActiveStatus.ts index 998074d89e610..efaba003ad367 100644 --- a/apps/meteor/app/lib/server/functions/setUserActiveStatus.ts +++ b/apps/meteor/app/lib/server/functions/setUserActiveStatus.ts @@ -2,6 +2,7 @@ import { Meteor } from 'meteor/meteor'; import { check } from 'meteor/check'; import { Accounts } from 'meteor/accounts-base'; import type { IUser, IUserEmail, IDirectMessageRoom } from '@rocket.chat/core-typings'; +import { isUserFederated } from '@rocket.chat/core-typings'; import * as Mailer from '../../../mailer'; import { Users, Subscriptions, Rooms } from '../../../models/server'; @@ -43,6 +44,12 @@ export function setUserActiveStatus(userId: string, active: boolean, confirmReli return false; } + if (isUserFederated(user)) { + throw new Meteor.Error('error-user-is-federated', 'Cannot change federated users status', { + method: 'setUserActiveStatus', + }); + } + // Users without username can't do anything, so there is no need to check for owned rooms if (user.username != null && !active) { const userAdmin = Users.findOneAdmin(userId); @@ -64,8 +71,13 @@ export function setUserActiveStatus(userId: string, active: boolean, confirmReli throw new Meteor.Error('user-last-owner', '', rooms); } - closeOmnichannelConversations(user, livechatSubscribedRooms); - Promise.await(relinquishRoomOwnerships(user, chatSubscribedRooms, false)); + Promise.await( + // We don't want one killing the other :) + Promise.allSettled([ + closeOmnichannelConversations(user, livechatSubscribedRooms), + relinquishRoomOwnerships(user, chatSubscribedRooms, false), + ]), + ); } if (active && !user.active) { diff --git a/apps/meteor/app/lib/server/functions/setUserAvatar.ts b/apps/meteor/app/lib/server/functions/setUserAvatar.ts index 4718303b21caa..f25745dc389d9 100644 --- a/apps/meteor/app/lib/server/functions/setUserAvatar.ts +++ b/apps/meteor/app/lib/server/functions/setUserAvatar.ts @@ -1,11 +1,11 @@ import { Meteor } from 'meteor/meteor'; import type { IUser } from '@rocket.chat/core-typings'; +import { api } from '@rocket.chat/core-services'; import { RocketChatFile } from '../../../file/server'; import { FileUpload } from '../../../file-upload/server'; import { Users } from '../../../models/server'; import { SystemLogger } from '../../../../server/lib/logger/system'; -import { api } from '../../../../server/sdk/api'; import { fetch } from '../../../../server/lib/http/fetch'; export function setUserAvatar( diff --git a/apps/meteor/app/lib/server/functions/setUsername.ts b/apps/meteor/app/lib/server/functions/setUsername.ts index 6dc5eb4b0fb16..bdb59f9cdf92e 100644 --- a/apps/meteor/app/lib/server/functions/setUsername.ts +++ b/apps/meteor/app/lib/server/functions/setUsername.ts @@ -1,21 +1,20 @@ import { Meteor } from 'meteor/meteor'; -import s from 'underscore.string'; import { Accounts } from 'meteor/accounts-base'; import type { IUser } from '@rocket.chat/core-typings'; import { Invites } from '@rocket.chat/models'; +import { api } from '@rocket.chat/core-services'; import { settings } from '../../../settings/server'; import { Users } from '../../../models/server'; import { hasPermission } from '../../../authorization/server'; import { RateLimiter } from '../lib'; import { addUserToRoom } from './addUserToRoom'; -import { api } from '../../../../server/sdk/api'; import { checkUsernameAvailability, setUserAvatar } from '.'; import { getAvatarSuggestionForUser } from './getAvatarSuggestionForUser'; import { SystemLogger } from '../../../../server/lib/logger/system'; export const _setUsername = function (userId: string, u: string, fullUser: IUser): unknown { - const username = s.trim(u); + const username = u.trim(); if (!userId || !username) { return false; } @@ -54,10 +53,11 @@ export const _setUsername = function (userId: string, u: string, fullUser: IUser Users.setUsername(user._id, username); user.username = username; if (!previousUsername && settings.get('Accounts_SetDefaultAvatar') === true) { - const avatarSuggestions = Promise.await(getAvatarSuggestionForUser(user)) as []; + // eslint-disable-next-line @typescript-eslint/ban-types + const avatarSuggestions = Promise.await(getAvatarSuggestionForUser(user)) as {}; let gravatar; Object.keys(avatarSuggestions).some((service) => { - const avatarData = avatarSuggestions[+service]; + const avatarData = avatarSuggestions[+service as keyof typeof avatarSuggestions]; if (service !== 'gravatar') { // eslint-disable-next-line dot-notation setUserAvatar(user, avatarData['blob'], avatarData['contentType'], service); diff --git a/apps/meteor/app/lib/server/functions/updateMessage.ts b/apps/meteor/app/lib/server/functions/updateMessage.ts index 410c7f276f5d1..52c93c9837ae7 100644 --- a/apps/meteor/app/lib/server/functions/updateMessage.ts +++ b/apps/meteor/app/lib/server/functions/updateMessage.ts @@ -1,10 +1,10 @@ +import type { IEditedMessage, IMessage, IUser } from '@rocket.chat/core-typings'; import { Meteor } from 'meteor/meteor'; -import type { IMessage, IMessageEdited, IUser } from '@rocket.chat/core-typings'; import { Messages, Rooms } from '../../../models/server'; import { settings } from '../../../settings/server'; import { callbacks } from '../../../../lib/callbacks'; -import { Apps } from '../../../apps/server'; +import { Apps } from '../../../../ee/server/apps'; import { parseUrlsInMessage } from './parseUrlsInMessage'; export const updateMessage = function (message: IMessage, user: IUser, originalMessage?: IMessage): void { @@ -35,11 +35,13 @@ export const updateMessage = function (message: IMessage, user: IUser, originalM Messages.cloneAndSaveAsHistoryById(message._id, user); } - (message as IMessageEdited).editedAt = new Date(); - (message as IMessageEdited).editedBy = { - _id: user._id, - username: user.username, - }; + Object.assign>(message, { + editedAt: new Date(), + editedBy: { + _id: user._id, + username: user.username, + }, + }); parseUrlsInMessage(message); @@ -47,7 +49,12 @@ export const updateMessage = function (message: IMessage, user: IUser, originalM const { _id, ...editedMessage } = message; - Messages.update({ _id }, { $set: editedMessage }); + if (!editedMessage.msg) { + delete editedMessage.md; + } + + // do not send $unset if not defined. Can cause exceptions in certain mongo versions. + Messages.update({ _id }, { $set: editedMessage, ...(!editedMessage.md && { $unset: { md: 1 } }) }); const room = Rooms.findOneById(message.rid); diff --git a/apps/meteor/app/lib/server/functions/validateCustomFields.js b/apps/meteor/app/lib/server/functions/validateCustomFields.js index b9580ce559d60..de420a9a4c795 100644 --- a/apps/meteor/app/lib/server/functions/validateCustomFields.js +++ b/apps/meteor/app/lib/server/functions/validateCustomFields.js @@ -1,12 +1,12 @@ import { Meteor } from 'meteor/meteor'; -import s from 'underscore.string'; +import { trim } from '../../../../lib/utils/stringUtils'; import { settings } from '../../../settings/server'; export const validateCustomFields = function (fields) { // Special Case: // If an admin didn't set any custom fields there's nothing to validate against so consider any customFields valid - if (s.trim(settings.get('Accounts_CustomFields')) === '') { + if (trim(settings.get('Accounts_CustomFields')) === '') { return; } @@ -23,7 +23,7 @@ export const validateCustomFields = function (fields) { const field = customFieldsMeta[fieldName]; customFields[fieldName] = fields[fieldName]; - const fieldValue = s.trim(fields[fieldName]); + const fieldValue = trim(fields[fieldName]); if (field.required && fieldValue === '') { throw new Meteor.Error('error-user-registration-custom-field', `Field ${fieldName} is required`, { method: 'registerUser' }); diff --git a/apps/meteor/app/lib/server/index.js b/apps/meteor/app/lib/server/index.js index a97db7ba85928..574a263123c88 100644 --- a/apps/meteor/app/lib/server/index.js +++ b/apps/meteor/app/lib/server/index.js @@ -42,8 +42,6 @@ import './methods/removeOAuthService'; import './methods/restartServer'; import './methods/saveSetting'; import './methods/saveSettings'; -import './methods/sendInvitationEmail'; -import './methods/sendInvitationSMS'; import './methods/sendMessage'; import './methods/sendSMTPTestEmail'; import './methods/setAdminStatus'; diff --git a/apps/meteor/app/lib/server/lib/debug.js b/apps/meteor/app/lib/server/lib/debug.js index 649da8d9d1bf7..f8215c8b9054a 100644 --- a/apps/meteor/app/lib/server/lib/debug.js +++ b/apps/meteor/app/lib/server/lib/debug.js @@ -1,6 +1,6 @@ import { Meteor } from 'meteor/meteor'; import { WebApp } from 'meteor/webapp'; -import { InstanceStatus } from 'meteor/konecty:multiple-instances-status'; +import { InstanceStatus } from '@rocket.chat/instance-status'; import _ from 'underscore'; import { settings } from '../../../settings/server'; diff --git a/apps/meteor/app/lib/server/lib/deprecationWarningLogger.ts b/apps/meteor/app/lib/server/lib/deprecationWarningLogger.ts index f3cc3149661b4..1c39c0e3489ff 100644 --- a/apps/meteor/app/lib/server/lib/deprecationWarningLogger.ts +++ b/apps/meteor/app/lib/server/lib/deprecationWarningLogger.ts @@ -5,3 +5,4 @@ const deprecationLogger = new Logger('DeprecationWarning'); export const apiDeprecationLogger = deprecationLogger.section('API'); export const methodDeprecationLogger = deprecationLogger.section('METHOD'); export const functionDeprecationLogger = deprecationLogger.section('FUNCTION'); +export const streamDeprecationLogger = deprecationLogger.section('STREAM'); diff --git a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.js b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.js index d01717912f3b1..de4fc6c0c3b3a 100644 --- a/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.js +++ b/apps/meteor/app/lib/server/lib/notifyUsersOnMessage.js @@ -63,14 +63,14 @@ export function getMentions(message) { const incGroupMentions = (rid, roomType, excludeUserId, unreadCount) => { const incUnreadByGroup = ['all_messages', 'group_mentions_only', 'user_and_group_mentions_only'].includes(unreadCount); - const incUnread = roomType === 'd' || incUnreadByGroup ? 1 : 0; + const incUnread = roomType === 'd' || roomType === 'l' || incUnreadByGroup ? 1 : 0; Subscriptions.incGroupMentionsAndUnreadForRoomIdExcludingUserId(rid, excludeUserId, 1, incUnread); }; const incUserMentions = (rid, roomType, uids, unreadCount) => { const incUnreadByUser = ['all_messages', 'user_mentions_only', 'user_and_group_mentions_only'].includes(unreadCount); - const incUnread = roomType === 'd' || incUnreadByUser ? 1 : 0; + const incUnread = roomType === 'd' || roomType === 'l' || incUnreadByUser ? 1 : 0; Subscriptions.incUserMentionsAndUnreadForRoomIdAndUserIds(rid, uids, 1, incUnread); }; @@ -86,6 +86,26 @@ const getUserIdsFromHighlights = (rid, message) => { .map(({ u: { _id: uid } }) => uid); }; +/* + * {IRoom['t']} roomType - The type of the room + * @returns {string} - The setting value for unread count + */ +const getUnreadSettingCount = (roomType) => { + let unreadSetting = 'Unread_Count'; + switch (roomType) { + case 'd': { + unreadSetting = 'Unread_Count_DM'; + break; + } + case 'l': { + unreadSetting = 'Unread_Count_Omni'; + break; + } + } + + return settings.get(unreadSetting); +}; + export async function updateUsersSubscriptions(message, room) { // Don't increase unread counter on thread messages if (room != null && !message.tmid) { @@ -93,8 +113,7 @@ export async function updateUsersSubscriptions(message, room) { const userIds = new Set(mentionIds); - const unreadSetting = room.t === 'd' ? 'Unread_Count_DM' : 'Unread_Count'; - const unreadCount = settings.get(unreadSetting); + const unreadCount = getUnreadSettingCount(room.t); getUserIdsFromHighlights(room._id, message).forEach((uid) => userIds.add(uid)); diff --git a/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js b/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js index 4574788a58c94..7ab19152ba71b 100644 --- a/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js +++ b/apps/meteor/app/lib/server/lib/sendNotificationsOnMessage.js @@ -372,7 +372,7 @@ export async function sendAllNotifications(message, room) { }), ) .then((users) => { - const subscriptions = Subscriptions.findByRoomIdAndUserIds(room._id, users); + const subscriptions = Subscriptions.findByRoomIdAndUserIds(room._id, users).fetch(); users.forEach((userId) => { const subscription = subscriptions.find((subscription) => subscription.u._id === userId); diff --git a/apps/meteor/app/lib/server/methods/addUsersToRoom.js b/apps/meteor/app/lib/server/methods/addUsersToRoom.js index a0f53cf457ca8..b9688ce3fd84c 100644 --- a/apps/meteor/app/lib/server/methods/addUsersToRoom.js +++ b/apps/meteor/app/lib/server/methods/addUsersToRoom.js @@ -1,12 +1,14 @@ import { Meteor } from 'meteor/meteor'; import { Match } from 'meteor/check'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import { api } from '@rocket.chat/core-services'; +import { isRoomFederated } from '@rocket.chat/core-typings'; import { Rooms, Subscriptions, Users } from '../../../models/server'; import { hasPermission } from '../../../authorization'; import { addUserToRoom } from '../functions'; -import { api } from '../../../../server/sdk/api'; import { Federation } from '../../../federation-v2/server/Federation'; +import { callbacks } from '../../../../lib/callbacks'; Meteor.methods({ addUsersToRoom(data = {}) { @@ -64,6 +66,11 @@ Meteor.methods({ // Validate each user, then add to room const user = Meteor.user(); + if (isRoomFederated(room)) { + callbacks.run('federation.onAddUsersToARoom', { invitees: data.users, inviter: user }, room); + return true; + } + data.users.forEach((username) => { const newUser = Users.findOneByUsernameIgnoringCase(username); if (!newUser && !Federation.isAFederatedUsername(username)) { diff --git a/apps/meteor/app/lib/server/methods/archiveRoom.ts b/apps/meteor/app/lib/server/methods/archiveRoom.ts index 0115cc285d360..2dbabd4bfd470 100644 --- a/apps/meteor/app/lib/server/methods/archiveRoom.ts +++ b/apps/meteor/app/lib/server/methods/archiveRoom.ts @@ -23,7 +23,7 @@ Meteor.methods({ throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'archiveRoom' }); } - if (!roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.ARCHIVE)) { + if (!roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.ARCHIVE, userId)) { throw new Meteor.Error('error-direct-message-room', `rooms type: ${room.t} can not be archived`, { method: 'archiveRoom' }); } diff --git a/apps/meteor/app/lib/server/methods/blockUser.ts b/apps/meteor/app/lib/server/methods/blockUser.ts index 66ce1c961a1d8..fc3aab5001b57 100644 --- a/apps/meteor/app/lib/server/methods/blockUser.ts +++ b/apps/meteor/app/lib/server/methods/blockUser.ts @@ -9,14 +9,15 @@ Meteor.methods({ blockUser({ rid, blocked }) { check(rid, String); check(blocked, String); + const userId = Meteor.userId(); - if (!Meteor.userId()) { + if (!userId) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'blockUser' }); } const room = Rooms.findOne({ _id: rid }); - if (!roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.BLOCK)) { + if (!roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.BLOCK, userId)) { throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'blockUser' }); } diff --git a/apps/meteor/app/lib/server/methods/checkUsernameAvailability.ts b/apps/meteor/app/lib/server/methods/checkUsernameAvailability.ts index 2a9f34780f2a1..f27688cc4c6ee 100644 --- a/apps/meteor/app/lib/server/methods/checkUsernameAvailability.ts +++ b/apps/meteor/app/lib/server/methods/checkUsernameAvailability.ts @@ -4,22 +4,25 @@ import { check } from 'meteor/check'; import { settings } from '../../../settings/server'; import { checkUsernameAvailability } from '../functions'; import { RateLimiter } from '../lib'; +import { methodDeprecationLogger } from '../lib/deprecationWarningLogger'; Meteor.methods({ checkUsernameAvailability(username) { + methodDeprecationLogger.warn('checkUsernameAvailability will be deprecated in future versions of Rocket.Chat'); + check(username, String); - if (!Meteor.userId()) { + const user = Meteor.user(); + + if (!user) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'setUsername' }); } - const user = Meteor.user(); - - if (user?.username && !settings.get('Accounts_AllowUsernameChange')) { + if (user.username && !settings.get('Accounts_AllowUsernameChange')) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'setUsername' }); } - if (user?.username === username) { + if (user.username === username) { return true; } return checkUsernameAvailability(username); diff --git a/apps/meteor/app/lib/server/methods/deleteMessage.ts b/apps/meteor/app/lib/server/methods/deleteMessage.ts index 8ae4ef8248d53..8f96fd670ba6c 100644 --- a/apps/meteor/app/lib/server/methods/deleteMessage.ts +++ b/apps/meteor/app/lib/server/methods/deleteMessage.ts @@ -28,6 +28,7 @@ Meteor.methods({ u: 1, rid: 1, file: 1, + files: 1, ts: 1, }, }); diff --git a/apps/meteor/app/lib/server/methods/deleteUserOwnAccount.ts b/apps/meteor/app/lib/server/methods/deleteUserOwnAccount.ts index ac98e1ed6fbf6..d409a46dbabc7 100644 --- a/apps/meteor/app/lib/server/methods/deleteUserOwnAccount.ts +++ b/apps/meteor/app/lib/server/methods/deleteUserOwnAccount.ts @@ -2,12 +2,12 @@ import { Meteor } from 'meteor/meteor'; import { check } from 'meteor/check'; import { Accounts } from 'meteor/accounts-base'; import { SHA256 } from 'meteor/sha'; -import s from 'underscore.string'; import { settings } from '../../../settings/server'; import { Users } from '../../../models/server'; import { deleteUser } from '../functions'; -import { AppEvents, Apps } from '../../../apps/server/orchestrator'; +import { AppEvents, Apps } from '../../../../ee/server/apps/orchestrator'; +import { trim } from '../../../../lib/utils/stringUtils'; Meteor.methods({ async deleteUserOwnAccount(password, confirmRelinquish) { @@ -34,7 +34,7 @@ Meteor.methods({ }); } - if (user.services?.password && s.trim(user.services.password.bcrypt)) { + if (user.services?.password && trim(user.services.password.bcrypt)) { const result = Accounts._checkPassword(user, { digest: password.toLowerCase(), algorithm: 'sha-256', @@ -44,7 +44,7 @@ Meteor.methods({ method: 'deleteUserOwnAccount', }); } - } else if (SHA256(user.username) !== s.trim(password)) { + } else if (SHA256(user.username) !== password.trim()) { throw new Meteor.Error('error-invalid-username', 'Invalid username', { method: 'deleteUserOwnAccount', }); diff --git a/apps/meteor/app/lib/server/methods/executeSlashCommandPreview.ts b/apps/meteor/app/lib/server/methods/executeSlashCommandPreview.ts index 8df013402607a..c350f51fffb77 100644 --- a/apps/meteor/app/lib/server/methods/executeSlashCommandPreview.ts +++ b/apps/meteor/app/lib/server/methods/executeSlashCommandPreview.ts @@ -1,7 +1,18 @@ +import type { IMessage, SlashCommandPreviewItem } from '@rocket.chat/core-typings'; import { Meteor } from 'meteor/meteor'; import { slashCommands } from '../../../utils/server'; +declare module '@rocket.chat/ui-contexts' { + // eslint-disable-next-line @typescript-eslint/naming-convention + export interface ServerMethods { + executeSlashCommandPreview( + command: { cmd: string; params: string; msg: Pick }, + preview: SlashCommandPreviewItem, + ): Promise; + } +} + Meteor.methods({ executeSlashCommandPreview(command, preview) { if (!Meteor.userId()) { diff --git a/apps/meteor/app/lib/server/methods/filterATAllTag.js b/apps/meteor/app/lib/server/methods/filterATAllTag.js index 2c1d52a950933..f6d4627d9d680 100644 --- a/apps/meteor/app/lib/server/methods/filterATAllTag.js +++ b/apps/meteor/app/lib/server/methods/filterATAllTag.js @@ -2,11 +2,11 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import _ from 'underscore'; import moment from 'moment'; +import { api } from '@rocket.chat/core-services'; import { hasPermission } from '../../../authorization'; import { callbacks } from '../../../../lib/callbacks'; import { Users } from '../../../models/server'; -import { api } from '../../../../server/sdk/api'; callbacks.add( 'beforeSaveMessage', diff --git a/apps/meteor/app/lib/server/methods/filterATHereTag.js b/apps/meteor/app/lib/server/methods/filterATHereTag.js index 0978520e1cdd6..821b0f1c8ba49 100644 --- a/apps/meteor/app/lib/server/methods/filterATHereTag.js +++ b/apps/meteor/app/lib/server/methods/filterATHereTag.js @@ -2,11 +2,11 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import _ from 'underscore'; import moment from 'moment'; +import { api } from '@rocket.chat/core-services'; import { hasPermission } from '../../../authorization'; import { callbacks } from '../../../../lib/callbacks'; import { Users } from '../../../models/server'; -import { api } from '../../../../server/sdk/api'; callbacks.add( 'beforeSaveMessage', diff --git a/apps/meteor/app/lib/server/methods/getChannelHistory.ts b/apps/meteor/app/lib/server/methods/getChannelHistory.ts index 948508dd5a3af..66dcf82869160 100644 --- a/apps/meteor/app/lib/server/methods/getChannelHistory.ts +++ b/apps/meteor/app/lib/server/methods/getChannelHistory.ts @@ -4,7 +4,6 @@ import _ from 'underscore'; import { canAccessRoom, hasPermission } from '../../../authorization/server'; import { Subscriptions, Messages, Rooms } from '../../../models/server'; -import { settings } from '../../../settings/server'; import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser'; import { getHiddenSystemMessages } from '../lib/getHiddenSystemMessages'; @@ -40,12 +39,12 @@ Meteor.methods({ } // Ensure latest is always defined. - if (_.isUndefined(latest)) { + if (latest === undefined) { latest = new Date(); } // Verify oldest is a date if it exists - if (!_.isUndefined(oldest) && !_.isDate(oldest)) { + if (oldest !== undefined && !_.isDate(oldest)) { throw new Meteor.Error('error-invalid-date', 'Invalid date', { method: 'getChannelHistory' }); } @@ -59,28 +58,25 @@ Meteor.methods({ limit: count, }; - if (!settings.get('Message_ShowEditedStatus')) { - options.fields = { editedAt: 0 }; - } - - const records = _.isUndefined(oldest) - ? Messages.findVisibleByRoomIdBeforeTimestampNotContainingTypes( - rid, - latest, - hiddenMessageTypes, - options, - showThreadMessages, - inclusive, - ).fetch() - : Messages.findVisibleByRoomIdBetweenTimestampsNotContainingTypes( - rid, - oldest, - latest, - hiddenMessageTypes, - options, - showThreadMessages, - inclusive, - ).fetch(); + const records = + oldest === undefined + ? Messages.findVisibleByRoomIdBeforeTimestampNotContainingTypes( + rid, + latest, + hiddenMessageTypes, + options, + showThreadMessages, + inclusive, + ).fetch() + : Messages.findVisibleByRoomIdBetweenTimestampsNotContainingTypes( + rid, + oldest, + latest, + hiddenMessageTypes, + options, + showThreadMessages, + inclusive, + ).fetch(); const messages = normalizeMessagesForUser(records, fromUserId); @@ -88,9 +84,9 @@ Meteor.methods({ let unreadNotLoaded = 0; let firstUnread = undefined; - if (!_.isUndefined(oldest)) { + if (oldest !== undefined) { const firstMsg = messages[messages.length - 1]; - if (!_.isUndefined(firstMsg) && firstMsg.ts > oldest) { + if (firstMsg !== undefined && firstMsg.ts > oldest) { const unreadMessages = Messages.findVisibleByRoomIdBetweenTimestampsNotContainingTypes( rid, oldest, diff --git a/apps/meteor/app/lib/server/methods/getSlashCommandPreviews.ts b/apps/meteor/app/lib/server/methods/getSlashCommandPreviews.ts index 2d8b7ce179b5f..33f87478caf66 100644 --- a/apps/meteor/app/lib/server/methods/getSlashCommandPreviews.ts +++ b/apps/meteor/app/lib/server/methods/getSlashCommandPreviews.ts @@ -1,7 +1,15 @@ +import type { IMessage, SlashCommandPreviews } from '@rocket.chat/core-typings'; import { Meteor } from 'meteor/meteor'; import { slashCommands } from '../../../utils/server'; +declare module '@rocket.chat/ui-contexts' { + // eslint-disable-next-line @typescript-eslint/naming-convention + export interface ServerMethods { + getSlashCommandPreviews(command: { cmd: string; params: string; msg: Pick }): Promise; + } +} + Meteor.methods({ getSlashCommandPreviews(command) { if (!Meteor.userId()) { diff --git a/apps/meteor/app/lib/server/methods/getUserRoles.js b/apps/meteor/app/lib/server/methods/getUserRoles.js index 4f5595efa0771..813c3e2eea1d6 100644 --- a/apps/meteor/app/lib/server/methods/getUserRoles.js +++ b/apps/meteor/app/lib/server/methods/getUserRoles.js @@ -1,6 +1,5 @@ import { Meteor } from 'meteor/meteor'; - -import { Authorization } from '../../../../server/sdk'; +import { Authorization } from '@rocket.chat/core-services'; Meteor.methods({ async getUserRoles() { diff --git a/apps/meteor/app/lib/server/methods/joinRoom.ts b/apps/meteor/app/lib/server/methods/joinRoom.ts index dcde906be1afc..843cf128dec93 100644 --- a/apps/meteor/app/lib/server/methods/joinRoom.ts +++ b/apps/meteor/app/lib/server/methods/joinRoom.ts @@ -23,7 +23,7 @@ Meteor.methods({ throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'joinRoom' }); } - if (!roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.JOIN)) { + if (!roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.JOIN, user._id)) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'joinRoom' }); } diff --git a/apps/meteor/app/lib/server/methods/leaveRoom.ts b/apps/meteor/app/lib/server/methods/leaveRoom.ts index d9216f65df592..611e527c57315 100644 --- a/apps/meteor/app/lib/server/methods/leaveRoom.ts +++ b/apps/meteor/app/lib/server/methods/leaveRoom.ts @@ -20,7 +20,7 @@ Meteor.methods({ const room = Rooms.findOneById(rid); const user = Meteor.user() as unknown as IUser; - if (!user || !roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.LEAVE)) { + if (!user || !roomCoordinator.getRoomDirectives(room.t)?.allowMemberAction(room, RoomMemberActions.LEAVE, user._id)) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'leaveRoom' }); } diff --git a/apps/meteor/app/lib/server/methods/sendInvitationEmail.ts b/apps/meteor/app/lib/server/methods/sendInvitationEmail.ts deleted file mode 100644 index 35909f5ba3680..0000000000000 --- a/apps/meteor/app/lib/server/methods/sendInvitationEmail.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { check } from 'meteor/check'; -import { Settings } from '@rocket.chat/models'; - -import * as Mailer from '../../../mailer'; -import { hasPermission } from '../../../authorization/server'; -import { settings } from '../../../settings/server'; -import { getAvatarURL } from '../../../utils/lib/getAvatarURL'; - -let html = ''; -Meteor.startup(() => { - Mailer.getTemplate('Invitation_Email', (value) => { - html = value; - }); -}); - -Meteor.methods({ - sendInvitationEmail(emails, language, realname) { - check(emails, [String]); - const uid = Meteor.userId(); - if (!uid) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { - method: 'sendInvitationEmail', - }); - } - if (!hasPermission(uid, 'bulk-register-user')) { - throw new Meteor.Error('error-not-allowed', 'Not allowed', { - method: 'sendInvitationEmail', - }); - } - const validEmails = emails.filter(Mailer.checkAddressFormat); - - if (!validEmails || validEmails.length === 0) { - throw new Meteor.Error('error-email-send-failed', 'No valid email addresses', { - method: 'sendInvitationEmail', - }); - } - - let inviter; - if (!realname) { - inviter = Meteor.user().username; - } else { - inviter = realname; - } - const subject = settings.get('Invitation_Subject'); - - if (!subject) { - throw new Meteor.Error('error-email-send-failed', 'No subject', { - method: 'sendInvitationEmail', - }); - } - - return validEmails.filter((email) => { - try { - const mailerResult = Mailer.send({ - to: email, - from: settings.get('From_Email'), - subject, - html, - data: { - email, - Invite_Link: Meteor.runAsUser(Meteor.userId(), () => Meteor.call('getInviteLink')), - Username: inviter, - Avatar_Link: `${settings.get('Site_Url').slice(0, -1)}${getAvatarURL(Meteor.user().username)}`, - }, - lng: language, - }); - - Settings.incrementValueById('Invitation_Email_Count'); - return mailerResult; - } catch ({ message }) { - throw new Meteor.Error('error-email-send-failed', `Error trying to send email: ${message}`, { - method: 'sendInvitationEmail', - message, - }); - } - }); - }, -}); diff --git a/apps/meteor/app/lib/server/methods/sendMessage.js b/apps/meteor/app/lib/server/methods/sendMessage.js index e9a68f91722e8..b782db45d4936 100644 --- a/apps/meteor/app/lib/server/methods/sendMessage.js +++ b/apps/meteor/app/lib/server/methods/sendMessage.js @@ -2,20 +2,16 @@ import { Meteor } from 'meteor/meteor'; import { check } from 'meteor/check'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import moment from 'moment'; -import { isRoomFederated } from '@rocket.chat/core-typings'; +import { api } from '@rocket.chat/core-services'; import { hasPermission } from '../../../authorization'; import { metrics } from '../../../metrics'; import { settings } from '../../../settings/server'; -import { messageProperties } from '../../../ui-utils'; import { Users, Messages } from '../../../models'; import { sendMessage } from '../functions'; import { RateLimiter } from '../lib'; import { canSendMessage } from '../../../authorization/server'; import { SystemLogger } from '../../../../server/lib/logger/system'; -import { api } from '../../../../server/sdk/api'; -import { federationRoomServiceSender } from '../../../federation-v2/server'; -import { FederationRoomSenderConverter } from '../../../federation-v2/server/infrastructure/rocket-chat/converters/RoomSender'; export function executeSendMessage(uid, message) { if (message.tshow && !message.tmid) { @@ -46,9 +42,7 @@ export function executeSendMessage(uid, message) { } if (message.msg) { - const adjustedMessage = messageProperties.messageWithoutEmojiShortnames(message.msg); - - if (messageProperties.length(adjustedMessage) > settings.get('Message_MaxAllowedSize')) { + if (message.msg.length > settings.get('Message_MaxAllowedSize')) { throw new Meteor.Error('error-message-size-exceeded', 'Message size exceeds Message_MaxAllowedSize', { method: 'sendMessage', }); @@ -77,27 +71,22 @@ export function executeSendMessage(uid, message) { try { const room = canSendMessage(rid, { uid, username: user.username, type: user.type }); - if (isRoomFederated(room)) { - return federationRoomServiceSender.sendExternalMessage( - FederationRoomSenderConverter.toSendExternalMessageDto(uid, message.rid, message), - ); - } metrics.messagesSent.inc(); // TODO This line needs to be moved to it's proper place. See the comments on: https://github.com/RocketChat/Rocket.Chat/pull/5736 return sendMessage(user, message, room, false); - } catch (error) { - SystemLogger.error('Error sending message:', error); + } catch (err) { + SystemLogger.error({ msg: 'Error sending message:', err }); - const errorMessage = typeof error === 'string' ? error : error.error || error.message; + const errorMessage = typeof err === 'string' ? err : err.error || err.message; api.broadcast('notify.ephemeralMessage', uid, message.rid, { msg: TAPi18n.__(errorMessage, {}, user.language), }); - if (typeof error === 'string') { - throw new Error(error); + if (typeof err === 'string') { + throw new Error(err); } - throw error; + throw err; } } diff --git a/apps/meteor/app/lib/server/methods/sendSMTPTestEmail.js b/apps/meteor/app/lib/server/methods/sendSMTPTestEmail.js index da8648a2bce5b..7f7cce26450fc 100644 --- a/apps/meteor/app/lib/server/methods/sendSMTPTestEmail.js +++ b/apps/meteor/app/lib/server/methods/sendSMTPTestEmail.js @@ -31,7 +31,7 @@ Meteor.methods({ }); } return { - message: 'Your_mail_was_sent_to_s', + message: 'Sending_your_mail_to_s', params: [user.emails[0].address], }; }, diff --git a/apps/meteor/app/lib/server/methods/setAdminStatus.ts b/apps/meteor/app/lib/server/methods/setAdminStatus.ts index 2f416fe8e6d77..0a86000f0e682 100644 --- a/apps/meteor/app/lib/server/methods/setAdminStatus.ts +++ b/apps/meteor/app/lib/server/methods/setAdminStatus.ts @@ -1,5 +1,6 @@ import { Meteor } from 'meteor/meteor'; import { Match, check } from 'meteor/check'; +import { isUserFederated } from '@rocket.chat/core-typings'; import { hasPermission } from '../../../authorization/server'; @@ -18,7 +19,10 @@ Meteor.methods({ throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'setAdminStatus' }); } - const user = Meteor.users.findOne({ _id: userId }, { fields: { username: 1 } }); + const user = Meteor.users.findOne({ _id: userId }, { fields: { username: 1, federated: 1 } }); + if (!user || isUserFederated(user)) { + throw new Meteor.Error('error-not-allowed', 'Federated Users cant be admins', { method: 'setAdminStatus' }); + } if (admin) { return Meteor.call('authorization:addUserToRole', 'admin', user?.username); diff --git a/apps/meteor/app/lib/server/methods/updateMessage.js b/apps/meteor/app/lib/server/methods/updateMessage.js index a615d679c52b8..e5f4bf14579c9 100644 --- a/apps/meteor/app/lib/server/methods/updateMessage.js +++ b/apps/meteor/app/lib/server/methods/updateMessage.js @@ -7,6 +7,8 @@ import { settings } from '../../../settings/server'; import { hasPermission, canSendMessage } from '../../../authorization/server'; import { updateMessage } from '../functions'; +const allowedEditedFields = ['tshow', 'alias', 'attachments', 'avatar', 'emoji', 'msg']; + Meteor.methods({ updateMessage(message) { check(message, Match.ObjectIncluding({ _id: String })); @@ -16,11 +18,20 @@ Meteor.methods({ } const originalMessage = Messages.findOneById(message._id); - if (!originalMessage || !originalMessage._id) { return; } - if (originalMessage.msg === message.msg) { + + Object.entries(message).forEach(([key, value]) => { + if (!allowedEditedFields.includes(key) && value !== originalMessage[key]) { + throw new Meteor.Error('error-invalid-update-key', `Cannot update the message ${key}`, { + method: 'updateMessage', + }); + } + }); + + const msgText = originalMessage?.attachments?.[0]?.description ?? originalMessage.msg; + if (msgText === message.msg) { return; } @@ -46,7 +57,9 @@ Meteor.methods({ } const blockEditInMinutes = settings.get('Message_AllowEditing_BlockEditInMinutes'); - if (Match.test(blockEditInMinutes, Number) && blockEditInMinutes !== 0) { + const bypassBlockTimeLimit = hasPermission(Meteor.userId(), 'bypass-time-limit-edit-and-delete'); + + if (!bypassBlockTimeLimit && Match.test(blockEditInMinutes, Number) && blockEditInMinutes !== 0) { let currentTsDiff; let msgTs; diff --git a/apps/meteor/app/lib/server/startup/email.ts b/apps/meteor/app/lib/server/startup/email.ts index 24cd0bd325270..39105d27a6b47 100644 --- a/apps/meteor/app/lib/server/startup/email.ts +++ b/apps/meteor/app/lib/server/startup/email.ts @@ -396,6 +396,13 @@ settingsRegistry.addGroup('Email', function () { return this.add('SMTP_Test_Button', 'sendSMTPTestEmail', { type: 'action', actionText: 'Send_a_test_mail_to_my_user', + enableQuery: { + _id: 'SMTP_Host', + value: { + $exists: true, + $ne: '', + }, + }, }); }); diff --git a/apps/meteor/app/lib/server/startup/settings.ts b/apps/meteor/app/lib/server/startup/settings.ts index e72d7276e2f74..a0890c01ed7c2 100644 --- a/apps/meteor/app/lib/server/startup/settings.ts +++ b/apps/meteor/app/lib/server/startup/settings.ts @@ -82,10 +82,6 @@ settingsRegistry.addGroup('Accounts', function () { type: 'int', public: true, }); - this.add('Accounts_ShowFormLogin', true, { - type: 'boolean', - public: true, - }); this.add('Accounts_EmailOrUsernamePlaceholder', '', { type: 'string', public: true, @@ -379,6 +375,25 @@ settingsRegistry.addGroup('Accounts', function () { public: true, i18nLabel: 'Group_by_Type', }); + this.add('Accounts_Default_User_Preferences_themeAppearence', 'auto', { + type: 'select', + values: [ + { + key: 'auto', + i18nLabel: 'Theme_match_system', + }, + { + key: 'light', + i18nLabel: 'Theme_light', + }, + { + key: 'dark', + i18nLabel: 'Theme_dark', + }, + ], + public: true, + i18nLabel: 'Theme_Appearence', + }); this.add('Accounts_Default_User_Preferences_sidebarViewMode', 'medium', { type: 'select', values: [ @@ -431,18 +446,19 @@ settingsRegistry.addGroup('Accounts', function () { values: [ { key: 'default', - i18nLabel: 'Default', + i18nLabel: 'Selected_first_reply_unselected_following_replies', }, { key: 'always', - i18nLabel: 'Always', + i18nLabel: 'Selected_by_default', }, { key: 'never', - i18nLabel: 'Never', + i18nLabel: 'Unselected_by_default', }, ], public: true, + i18nLabel: 'Also_send_thread_message_to_channel_behavior', }); this.add('Accounts_Default_User_Preferences_sidebarShowFavorites', true, { @@ -470,26 +486,6 @@ settingsRegistry.addGroup('Accounts', function () { public: true, i18nLabel: 'Enter_Behaviour', }); - - this.add('Accounts_Default_User_Preferences_messageViewMode', 0, { - type: 'select', - values: [ - { - key: 0, - i18nLabel: 'Normal', - }, - { - key: 1, - i18nLabel: 'Cozy', - }, - { - key: 2, - i18nLabel: 'Compact', - }, - ], - public: true, - i18nLabel: 'MessageBox_view_mode', - }); this.add('Accounts_Default_User_Preferences_emailNotificationMode', 'mentions', { type: 'select', values: [ @@ -548,11 +544,10 @@ settingsRegistry.addGroup('Accounts', function () { i18nLabel: 'Notifications_Sound_Volume', }); - this.add('Accounts_Default_User_Preferences_useLegacyMessageTemplate', false, { + this.add('Accounts_Default_User_Preferences_omnichannelTranscriptEmail', false, { type: 'boolean', public: true, - i18nLabel: 'Use_Legacy_Message_Template', - alert: 'Use_Legacy_Message_Template_alert', + i18nLabel: 'Omnichannel_transcript_email', }); }); @@ -883,6 +878,11 @@ settingsRegistry.addGroup('General', function () { type: 'boolean', }); + this.add('Extra_CSP_Domains', '', { + type: 'string', + multiline: true, + }); + this.add('Iframe_Restrict_Access', true, { type: 'boolean', secret: true, @@ -939,6 +939,20 @@ settingsRegistry.addGroup('General', function () { ], public: true, }); + this.add('Unread_Count_Omni', 'all_messages', { + type: 'select', + values: [ + { + key: 'all_messages', + i18nLabel: 'All_messages', + }, + { + key: 'mentions_only', + i18nLabel: 'Mentions_only', + }, + ], + public: true, + }); this.add('DeepLink_Url', 'https://go.rocket.chat', { type: 'string', @@ -1147,12 +1161,6 @@ settingsRegistry.addGroup('General', function () { settingsRegistry.addGroup('Message', function () { this.section('Message_Attachments', function () { - this.add('Message_Attachments_GroupAttach', false, { - type: 'boolean', - public: true, - i18nDescription: 'Message_Attachments_GroupAttachDescription', - }); - this.add('Message_Attachments_Thumbnails_Enabled', true, { type: 'boolean', public: true, @@ -1198,6 +1206,23 @@ settingsRegistry.addGroup('Message', function () { public: true, }); }); + this.section('Read_Receipts', function () { + this.add('Message_Read_Receipt_Enabled', false, { + type: 'boolean', + enterprise: true, + invalidValue: false, + modules: ['message-read-receipt'], + public: true, + }); + this.add('Message_Read_Receipt_Store_Users', false, { + type: 'boolean', + enterprise: true, + invalidValue: false, + modules: ['message-read-receipt'], + public: true, + enableQuery: { _id: 'Message_Read_Receipt_Enabled', value: true }, + }); + }); this.add('Message_AllowEditing', true, { type: 'boolean', public: true, @@ -1227,10 +1252,6 @@ settingsRegistry.addGroup('Message', function () { this.add('Message_AlwaysSearchRegExp', false, { type: 'boolean', }); - this.add('Message_ShowEditedStatus', true, { - type: 'boolean', - public: true, - }); this.add('Message_ShowDeletedStatus', false, { type: 'boolean', public: true, @@ -1263,10 +1284,6 @@ settingsRegistry.addGroup('Message', function () { type: 'boolean', public: true, }); - this.add('Message_ShowFormattingTips', true, { - type: 'boolean', - public: true, - }); this.add('Message_GroupingPeriod', 300, { type: 'int', public: true, @@ -1294,12 +1311,6 @@ settingsRegistry.addGroup('Message', function () { i18nLabel: 'clear_cache_now', }); // TODO: deprecate this setting in favor of App - this.add('API_EmbedDisabledFor', '', { - type: 'string', - public: true, - i18nDescription: 'API_EmbedDisabledFor_Description', - }); - // TODO: deprecate this setting in favor of App this.add('API_EmbedIgnoredHosts', 'localhost, 127.0.0.1, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16', { type: 'string', i18nDescription: 'API_EmbedIgnoredHosts_Description', @@ -1554,7 +1565,47 @@ settingsRegistry.addGroup('Push', function () { }); settingsRegistry.addGroup('Layout', function () { - this.section('Content', function () { + this.section('Login', function () { + this.add('Layout_Login_Hide_Logo', false, { + type: 'boolean', + public: true, + enterprise: true, + invalidValue: false, + }); + this.add('Layout_Login_Hide_Title', false, { + type: 'boolean', + public: true, + enterprise: true, + invalidValue: false, + }); + this.add('Layout_Login_Hide_Powered_By', false, { + type: 'boolean', + public: true, + enterprise: true, + invalidValue: false, + }); + this.add('Layout_Login_Template', 'horizontal-template', { + type: 'select', + values: [ + { + key: 'vertical-template', + i18nLabel: 'Layout_Login_Template_Vertical', + }, + { + key: 'horizontal-template', + i18nLabel: 'Layout_Login_Template_Horizontal', + }, + ], + public: true, + enterprise: true, + invalidValue: 'horizontal-template', + }); + this.add('Accounts_ShowFormLogin', true, { + type: 'boolean', + public: true, + }); + }); + this.section('Layout_Home_Page_Content_Title', function () { this.add('Layout_Home_Title', 'Home', { type: 'string', public: true, @@ -1563,27 +1614,57 @@ settingsRegistry.addGroup('Layout', function () { type: 'boolean', public: true, }); + this.add('Layout_Home_Body', '', { + i18nDescription: 'Layout_Custom_Content_Description', + type: 'code', + code: 'text/html', + multiline: true, + public: true, + }); + this.add('Layout_Home_Custom_Block_Visible', false, { + type: 'boolean', + invalidValue: false, + public: true, + enableQuery: [ + { + _id: 'Layout_Home_Body', + value: { + $exists: true, + $ne: '', + }, + }, + { + _id: 'Layout_Custom_Body_Only', + value: { + $exists: true, + $ne: true, + }, + }, + ], + }); this.add('Layout_Custom_Body_Only', false, { - i18nDescription: 'Layout_Custom_Body_Only_description', + i18nDescription: 'Layout_Custom_Body_Only_Description', type: 'boolean', invalidValue: false, enterprise: true, public: true, - }); - this.add( - 'Layout_Home_Body', - '

    ~~~~ Default html example ~~~~

    \nWelcome to (ENTER ORGANIZATION NAME HERE)\n\n

    All general communications should be done through #general

    \n

    find more information here

    ', - { - type: 'code', - enableQuery: { - _id: 'Layout_Custom_Body', - value: true, + enableQuery: [ + { + _id: 'Layout_Home_Body', + value: { + $exists: true, + $ne: '', + }, }, - code: 'text/html', - multiline: true, - public: true, - }, - ); + { + _id: 'Layout_Home_Custom_Block_Visible', + value: { + $exists: true, + $ne: false, + }, + }, + ], + }); this.add('Layout_Terms_of_Service', 'Terms of Service
    Go to APP SETTINGS → Layout to customize this page.', { type: 'code', code: 'text/html', @@ -1611,6 +1692,12 @@ settingsRegistry.addGroup('Layout', function () { multiline: true, public: true, }); + this.add('Layout_Sidenav_Footer_Dark', 'Home', { + type: 'code', + code: 'text/html', + public: true, + i18nDescription: 'Layout_Sidenav_Footer_description', + }); return this.add('Layout_Sidenav_Footer', 'Home', { type: 'code', code: 'text/html', @@ -3245,10 +3332,20 @@ settingsRegistry.addGroup('Troubleshoot', function () { type: 'boolean', alert: 'Troubleshoot_Disable_Notifications_Alert', }); + + // this settings will let clients know in case presence has been disabled + this.add('Presence_broadcast_disabled', false, { + type: 'boolean', + public: true, + readonly: true, + }); + this.add('Troubleshoot_Disable_Presence_Broadcast', false, { type: 'boolean', alert: 'Troubleshoot_Disable_Presence_Broadcast_Alert', + enableQuery: { _id: 'Presence_broadcast_disabled', value: false }, }); + this.add('Troubleshoot_Disable_Instance_Broadcast', false, { type: 'boolean', alert: 'Troubleshoot_Disable_Instance_Broadcast_Alert', @@ -3276,27 +3373,32 @@ settingsRegistry.addGroup('Troubleshoot', function () { }); settingsRegistry.addGroup('Call_Center', function () { + // TODO: Check with the backend team if an i18nPlaceholder is possible this.with({ tab: 'Settings' }, function () { - this.add('VoIP_Enabled', false, { - type: 'boolean', - public: true, - enableQuery: { - _id: 'Livechat_enabled', - value: true, - }, - }); - this.add('VoIP_JWT_Secret', '', { - type: 'password', - i18nDescription: 'VoIP_JWT_Secret_description', - enableQuery: { - _id: 'VoIP_Enabled', - value: true, - }, + this.section('General_Settings', function () { + this.add('VoIP_Enabled', false, { + type: 'boolean', + public: true, + i18nDescription: 'VoIP_Enabled_Description', + enableQuery: { + _id: 'Livechat_enabled', + value: true, + }, + }); + this.add('VoIP_JWT_Secret', '', { + type: 'password', + i18nDescription: 'VoIP_JWT_Secret_description', + enableQuery: { + _id: 'VoIP_Enabled', + value: true, + }, + }); }); - this.section('Server_Configuration', function () { + this.section('Voip_Server_Configuration', function () { this.add('VoIP_Server_Name', '', { type: 'string', public: true, + placeholder: 'WebSocket Server', enableQuery: { _id: 'VoIP_Enabled', value: true, @@ -3305,6 +3407,7 @@ settingsRegistry.addGroup('Call_Center', function () { this.add('VoIP_Server_Websocket_Path', '', { type: 'string', public: true, + placeholder: 'wss://your.domain.name', enableQuery: { _id: 'VoIP_Enabled', value: true, @@ -3313,6 +3416,8 @@ settingsRegistry.addGroup('Call_Center', function () { this.add('VoIP_Retry_Count', -1, { type: 'int', public: true, + i18nDescription: 'VoIP_Retry_Count_Description', + placeholder: '1', enableQuery: { _id: 'VoIP_Enabled', value: true, @@ -3333,6 +3438,7 @@ settingsRegistry.addGroup('Call_Center', function () { this.add('VoIP_Management_Server_Host', '', { type: 'string', public: true, + placeholder: 'https://your.domain.name', enableQuery: { _id: 'VoIP_Enabled', value: true, @@ -3342,6 +3448,7 @@ settingsRegistry.addGroup('Call_Center', function () { this.add('VoIP_Management_Server_Port', 0, { type: 'int', public: true, + placeholder: '8080', enableQuery: { _id: 'VoIP_Enabled', value: true, @@ -3351,6 +3458,7 @@ settingsRegistry.addGroup('Call_Center', function () { this.add('VoIP_Management_Server_Name', '', { type: 'string', public: true, + placeholder: 'Server Name', enableQuery: { _id: 'VoIP_Enabled', value: true, @@ -3360,6 +3468,7 @@ settingsRegistry.addGroup('Call_Center', function () { this.add('VoIP_Management_Server_Username', '', { type: 'string', public: true, + placeholder: 'Username', enableQuery: { _id: 'VoIP_Enabled', value: true, diff --git a/apps/meteor/app/lib/server/startup/settingsOnLoadCdnPrefix.js b/apps/meteor/app/lib/server/startup/settingsOnLoadCdnPrefix.js index e9026a04c9db5..38d8f2134dcbf 100644 --- a/apps/meteor/app/lib/server/startup/settingsOnLoadCdnPrefix.js +++ b/apps/meteor/app/lib/server/startup/settingsOnLoadCdnPrefix.js @@ -1,6 +1,5 @@ import { Meteor } from 'meteor/meteor'; import { WebAppInternals } from 'meteor/webapp'; -import _ from 'underscore'; import { settings } from '../../../settings/server'; @@ -9,14 +8,14 @@ function testWebAppInternals(fn) { } settings.change('CDN_PREFIX', function (value) { const useForAll = settings.get('CDN_PREFIX_ALL'); - if (_.isString(value) && value.trim() && useForAll) { + if (value && typeof value.valueOf() === 'string' && value.trim() && useForAll) { return testWebAppInternals((WebAppInternals) => WebAppInternals.setBundledJsCssPrefix(value)); } }); settings.change('CDN_JSCSS_PREFIX', function (value) { const useForAll = settings.get('CDN_PREFIX_ALL'); - if (_.isString(value) && value.trim() && !useForAll) { + if (value && typeof value.valueOf() === 'string' && value.trim() && !useForAll) { return testWebAppInternals((WebAppInternals) => WebAppInternals.setBundledJsCssPrefix(value)); } }); @@ -25,11 +24,11 @@ Meteor.startup(function () { const cdnValue = settings.get('CDN_PREFIX'); const useForAll = settings.get('CDN_PREFIX_ALL'); const cdnJsCss = settings.get('CDN_JSCSS_PREFIX'); - if (_.isString(cdnValue) && cdnValue.trim()) { + if (cdnValue && typeof cdnValue.valueOf() === 'string' && cdnValue.trim()) { if (useForAll) { return testWebAppInternals((WebAppInternals) => WebAppInternals.setBundledJsCssPrefix(cdnValue)); } - if (_.isString(cdnJsCss) && cdnJsCss.trim()) { + if (cdnJsCss && typeof cdnJsCss.valueOf() === 'string' && cdnJsCss.trim()) { return testWebAppInternals((WebAppInternals) => WebAppInternals.setBundledJsCssPrefix(cdnJsCss)); } } diff --git a/apps/meteor/app/livechat/client/lib/stream/queueManager.js b/apps/meteor/app/livechat/client/lib/stream/queueManager.js index 10bdfe1d58200..1a0bb6cd8f962 100644 --- a/apps/meteor/app/livechat/client/lib/stream/queueManager.js +++ b/apps/meteor/app/livechat/client/lib/stream/queueManager.js @@ -45,7 +45,7 @@ const updateCollection = (inquiry) => { }; const getInquiriesFromAPI = async () => { - const { inquiries } = await APIClient.get('/v1/livechat/inquiries.queuedForUser?sort={"ts": 1}'); + const { inquiries } = await APIClient.get('/v1/livechat/inquiries.queuedForUser'); return inquiries; }; diff --git a/apps/meteor/app/livechat/client/stylesheets/livechat.css b/apps/meteor/app/livechat/client/stylesheets/livechat.css index 53fb8737b7d2c..b6e8bf366940b 100644 --- a/apps/meteor/app/livechat/client/stylesheets/livechat.css +++ b/apps/meteor/app/livechat/client/stylesheets/livechat.css @@ -8,174 +8,15 @@ --color-gray: #9ea2a8; } -.department-agents { - list-style-type: none; - - li { - display: inline-block; - - margin: 1px 0; - padding: 2px 8px 2px 2px; - - cursor: pointer; - - border-radius: 10px; - background-color: #dddddd; - - .icon-plus-circled { - opacity: 0.5; - - font-size: 0.8rem; - } - } -} - -.agent-info { - input[type='text'] { - width: auto; - height: 24px; - - line-height: 24px; - } -} - -.visitor-custom-fields { - padding: 0 20px; -} - -.visitor-navigation, -.visitor-custom-fields { - .visitor-scroll { - overflow-y: auto; - - height: 130px; - margin-top: 4px; - margin-bottom: 20px; - padding: 4px; - - border: 1px solid #e7e7e7; - border-radius: 4px; - - ul { - li { - white-space: nowrap; - - a { - display: block; - overflow: hidden; - - text-decoration: underline; - text-overflow: ellipsis; - - color: var(--secondary-font-color); - - &:hover { - text-decoration: none; - } - } - } - } - } -} - -.livechat-status { - color: #9d9fa3; - - font-size: 20px; - line-height: 18px; -} - -.external-message { - position: relative; - - padding: 10px; - - &::after { - position: absolute; - right: 10px; - bottom: 0; - left: 10px; - - content: " "; - - border-bottom: 1px solid #cccccc; - } -} - -.user-view { - li { - color: var(--secondary-font-color); - - font-size: 12px; - font-weight: 300; - line-height: 18px; - } - - nav.centered-buttons { - margin-bottom: 1em; - - text-align: center; - - button { - display: inline-block; - - width: auto; - } - } -} - -.visitor-edit { - h3 { - margin-bottom: 8px; - - font-size: 24px; - line-height: 22px; - } -} - .external-frame { width: 100%; height: 100%; } -.chat-history-item { - cursor: pointer; - - border-bottom: 2px solid #f2f3f5; -} - .open { padding-left: 4% !important; } -.contact-chat-history { - padding: 0 !important; -} - -.contact-chat-history-messages { - padding: 0 !important; -} - -.contact-chat-history-search-wrapper { - padding: var(--default-padding); -} - -.contact-chat-history-messages-list .message-actions { - visibility: hidden; -} - -.chat-history-item-count-msg { - margin-top: 1%; - - color: grey; - - font-family: Inter; - font-size: 12px; - font-weight: bold; - font-style: normal; - line-height: 16px; -} - .closing-message-body-wrapper { margin-top: 3%; } @@ -199,7 +40,3 @@ font-style: italic; line-height: 16px; } - -.contact-chat-history-search-empty { - padding-left: 24px; -} diff --git a/apps/meteor/app/livechat/client/tabBar.ts b/apps/meteor/app/livechat/client/tabBar.ts index e7698b8f3239a..9a3cb9b5cfbbf 100644 --- a/apps/meteor/app/livechat/client/tabBar.ts +++ b/apps/meteor/app/livechat/client/tabBar.ts @@ -25,6 +25,7 @@ addAction('contact-chat-history', { id: 'contact-chat-history', title: 'Contact_Chat_History', icon: 'clock', - template: 'contactChatHistory', + // template: 'contactChatHistory', + template: lazy(() => import('../../../client/views/omnichannel/contactHistory/ContactHistory')), order: 11, }); diff --git a/apps/meteor/app/livechat/client/ui.js b/apps/meteor/app/livechat/client/ui.js index 6b7eade52a14e..364273909fa63 100644 --- a/apps/meteor/app/livechat/client/ui.js +++ b/apps/meteor/app/livechat/client/ui.js @@ -1,18 +1,7 @@ -import { Tracker } from 'meteor/tracker'; - import { settings } from '../../settings'; import { hasAllPermission } from '../../authorization'; import { AccountBox, MessageTypes } from '../../ui-utils'; -Tracker.autorun((c) => { - // import omnichannel tabbar templates right away if omnichannel enabled - if (!settings.get('Livechat_enabled')) { - return; - } - import('./views/regular'); - c.stop(); -}); - AccountBox.addItem({ name: 'Omnichannel', icon: 'headset', diff --git a/apps/meteor/app/livechat/client/views/app/livechatNotSubscribed.html b/apps/meteor/app/livechat/client/views/app/livechatNotSubscribed.html deleted file mode 100644 index 97e7c7e9f3087..0000000000000 --- a/apps/meteor/app/livechat/client/views/app/livechatNotSubscribed.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/apps/meteor/app/livechat/client/views/app/livechatReadOnly.html b/apps/meteor/app/livechat/client/views/app/livechatReadOnly.html deleted file mode 100644 index 0ff465acd25da..0000000000000 --- a/apps/meteor/app/livechat/client/views/app/livechatReadOnly.html +++ /dev/null @@ -1,28 +0,0 @@ - diff --git a/apps/meteor/app/livechat/client/views/app/livechatReadOnly.js b/apps/meteor/app/livechat/client/views/app/livechatReadOnly.js deleted file mode 100644 index 8df23b05e20cc..0000000000000 --- a/apps/meteor/app/livechat/client/views/app/livechatReadOnly.js +++ /dev/null @@ -1,129 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Template } from 'meteor/templating'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { FlowRouter } from 'meteor/kadira:flow-router'; - -import { ChatRoom, CachedChatRoom } from '../../../../models/client'; -import { callWithErrorHandling } from '../../../../../client/lib/utils/callWithErrorHandling'; -import { APIClient } from '../../../../utils/client'; -import { inquiryDataStream } from '../../lib/stream/inquiry'; -import { dispatchToastMessage } from '../../../../../client/lib/toast'; -import './livechatReadOnly.html'; - -Template.livechatReadOnly.helpers({ - inquiryOpen() { - const inquiry = Template.instance().inquiry.get(); - return inquiry && inquiry.status === 'queued'; - }, - - roomOpen() { - const room = Template.instance().room.get(); - return room && room.open === true; - }, - - showPreview() { - const config = Template.instance().routingConfig.get(); - return config.previewRoom || Template.currentData().onHold; - }, - - isPreparing() { - return Template.instance().preparing.get(); - }, - - isOnHold() { - return Template.currentData().onHold; - }, -}); - -Template.livechatReadOnly.events({ - async 'click .js-take-it'(event, instance) { - event.preventDefault(); - event.stopPropagation(); - - const inquiry = instance.inquiry.get(); - const { _id } = inquiry; - await callWithErrorHandling('livechat:takeInquiry', _id, { clientAction: true }); - instance.loadInquiry(inquiry.rid); - }, - - async 'click .js-resume-it'(event, instance) { - event.preventDefault(); - event.stopPropagation(); - - const room = instance.room.get(); - - await callWithErrorHandling('livechat:resumeOnHold', room._id, { clientAction: true }); - }, - - async 'click .js-join-it'(event) { - event.preventDefault(); - event.stopPropagation(); - - try { - const { success } = (await APIClient.get(`/v1/livechat/room.join`, { roomId: this.rid })) || {}; - if (!success) { - throw new Meteor.Error('error-join-room', 'Error joining room'); - } - } catch (error) { - dispatchToastMessage({ type: 'error', message: error }); - throw error; - } - }, -}); - -Template.livechatReadOnly.onCreated(async function () { - this.rid = Template.currentData().rid; - this.room = new ReactiveVar(); - this.inquiry = new ReactiveVar(); - this.routingConfig = new ReactiveVar({}); - this.preparing = new ReactiveVar(true); - this.updateInquiry = async ({ clientAction, ...inquiry }) => { - if (clientAction === 'removed') { - // this will force to refresh the room - // since the client wont get notified of room changes when chats are on queue (no one assigned) - // a better approach should be performed when refactoring these templates to use react - ChatRoom.remove(this.rid); - CachedChatRoom.save(); - return FlowRouter.go('/home'); - } - - this.inquiry.set(inquiry); - }; - - this.roomDataStream = new Meteor.Streamer('room-data'); - - Meteor.call('livechat:getRoutingConfig', (err, config) => { - if (config) { - this.routingConfig.set(config); - } - }); - - this.loadRoomAndInquiry = async (roomId) => { - this.preparing.set(true); - const { inquiry } = await APIClient.get(`/v1/livechat/inquiries.getOne`, { roomId }); - this.inquiry.set(inquiry); - if (inquiry && inquiry._id) { - inquiryDataStream.on(inquiry._id, this.updateInquiry); - } - - const { room } = await APIClient.get(`/v1/rooms.info`, { roomId }); - this.room.set(room); - if (room && room._id) { - this.roomDataStream.on(roomId, (room) => this.room.set(room)); - } - - this.preparing.set(false); - }; - - this.autorun(() => this.loadRoomAndInquiry(this.rid)); -}); - -Template.livechatReadOnly.onDestroyed(function () { - const inquiry = this.inquiry.get(); - if (inquiry && inquiry._id) { - inquiryDataStream.removeListener(inquiry._id, this.updateInquiry); - } - - const { rid } = Template.currentData(); - this.roomDataStream.removeListener(rid); -}); diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.html b/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.html deleted file mode 100644 index d99ade922013e..0000000000000 --- a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.html +++ /dev/null @@ -1,46 +0,0 @@ - diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.js b/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.js deleted file mode 100644 index 690402564a147..0000000000000 --- a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistory.js +++ /dev/null @@ -1,147 +0,0 @@ -import { Tracker } from 'meteor/tracker'; -import { Template } from 'meteor/templating'; -import moment from 'moment'; -import { ReactiveVar } from 'meteor/reactive-var'; -import './contactChatHistory.html'; -import './contactChatHistoryItem.html'; -import _ from 'underscore'; - -import { t, APIClient } from '../../../../../utils/client'; - -const HISTORY_LIMIT = 50; - -Template.contactChatHistory.helpers({ - isReady() { - return Template.instance().isReady.get(); - }, - hasChatHistory() { - return Template.instance().history.get().length > 0; - }, - history() { - return Template.instance().history.get(); - }, - isLoading() { - return Template.instance().isLoading.get(); - }, - isSearching() { - return Template.instance().searchTerm.get().length > 0; - }, - showChatHistoryMessages() { - return Template.instance().showChatHistoryMessages.get(); - }, - chatHistoryMessagesContext() { - return { - tabBar: Template.instance().tabBar, - clear: Template.instance().returnChatHistoryList, - ...Template.instance().chatHistoryMessagesContext.get(), - }; - }, - canSearch() { - return Template.instance().canSearch.get(); - }, -}); - -Template.contactChatHistory.onCreated(async function () { - const currentData = Template.currentData(); - this.offset = new ReactiveVar(0); - this.visitorId = new ReactiveVar(); - this.history = new ReactiveVar([]); - this.searchTerm = new ReactiveVar(''); - this.hasMore = new ReactiveVar(true); - this.isLoading = new ReactiveVar(true); - this.chatHistoryMessagesContext = new ReactiveVar(); - this.showChatHistoryMessages = new ReactiveVar(false); - this.limit = new ReactiveVar(HISTORY_LIMIT); - this.isReady = new ReactiveVar(false); - this.canSearch = new ReactiveVar(false); - this.tabBar = currentData.tabBar; - - this.returnChatHistoryList = () => { - this.showChatHistoryMessages.set(false); - this.chatHistoryMessagesContext.set(); - }; - - this.autorun(async () => { - if (!this.visitorId.get() || !currentData || !currentData.rid) { - return; - } - - const limit = this.limit.get(); - const offset = this.offset.get(); - const searchTerm = this.searchTerm.get(); - - const baseUrl = `/v1/livechat/visitors.searchChats/room/${currentData.rid}/visitor/${this.visitorId.get()}`; - const params = { - count: limit, - offset, - closedChatsOnly: true, - servedChatsOnly: true, - ...(searchTerm && { searchText: searchTerm }), - }; - - this.isLoading.set(true); - const { history, total } = await APIClient.get(baseUrl, params); - this.history.set(offset === 0 ? history : this.history.get().concat(history)); - this.hasMore.set(total > this.history.get().length); - this.isLoading.set(false); - }); - - this.autorun(async () => { - const { room } = await APIClient.get(`/v1/rooms.info`, { roomId: currentData.rid }); - if (room?.v) { - this.visitorId.set(room.v._id); - } - }); -}); - -Template.contactChatHistory.onRendered(function () { - Tracker.autorun((computation) => { - if (this.isLoading.get()) { - return; - } - - const history = this.history.get(); - this.canSearch.set(history && history.length > 0); - this.isReady.set(true); - - computation.stop(); - }); -}); - -Template.contactChatHistory.events({ - 'scroll .js-list': _.throttle(function (e, instance) { - if (e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight - 10 && instance.hasMore.get()) { - instance.offset.set(instance.offset.get() + instance.limit.get()); - } - }, 200), - 'click .chat-history-item'(event, instance) { - event.preventDefault(); - event.stopPropagation(); - - const { _id: rid, v: { name, username } = {}, closedAt } = this; - - const closedAtLabel = t('Closed_At'); - const closedDay = moment(closedAt).format('MMM D YYYY'); - - instance.chatHistoryMessagesContext.set({ - label: `${name || username}, ${closedAtLabel} ${closedDay}`, - rid, - }); - - instance.showChatHistoryMessages.set(true); - }, - 'keyup #chat-search': _.debounce(function (e, instance) { - if (e.keyCode === 13) { - return e.preventDefault(); - } - - const { value } = e.target; - - if (e.keyCode === 40 || e.keyCode === 38) { - return e.preventDefault(); - } - - instance.offset.set(0); - instance.searchTerm.set(value); - }, 300), -}); diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryItem.html b/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryItem.html deleted file mode 100644 index 2a10c9890d98f..0000000000000 --- a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryItem.html +++ /dev/null @@ -1,26 +0,0 @@ - diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryItem.js b/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryItem.js deleted file mode 100644 index 5d42478d4f204..0000000000000 --- a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryItem.js +++ /dev/null @@ -1,28 +0,0 @@ -import moment from 'moment'; -import './contactChatHistoryItem.html'; -import { Template } from 'meteor/templating'; -import { ReactiveVar } from 'meteor/reactive-var'; - -Template.contactChatHistoryItem.helpers({ - closedAt() { - const { closedAt } = Template.instance().room.get(); - return moment(closedAt).format('lll'); - }, - closingRoomMessage() { - const closingObj = Template.instance().closingRoomMessage.get(); - return closingObj.msg; - }, - i18nMessageCounter() { - const { msgs } = this; - return `${msgs}`; - }, -}); - -Template.contactChatHistoryItem.onCreated(function () { - this.room = new ReactiveVar(); - - this.autorun(async () => { - const currentData = Template.currentData(); - this.room.set(currentData); - }); -}); diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryMessages.html b/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryMessages.html deleted file mode 100644 index 7b83a9db8de7f..0000000000000 --- a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryMessages.html +++ /dev/null @@ -1,57 +0,0 @@ - diff --git a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryMessages.js b/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryMessages.js deleted file mode 100644 index f00adaf283541..0000000000000 --- a/apps/meteor/app/livechat/client/views/app/tabbar/contactChatHistoryMessages.js +++ /dev/null @@ -1,127 +0,0 @@ -import { Template } from 'meteor/templating'; -import './contactChatHistoryMessages.html'; -import { ReactiveVar } from 'meteor/reactive-var'; -import _ from 'underscore'; - -import { messageContext } from '../../../../../ui-utils/client/lib/messageContext'; -import { APIClient } from '../../../../../utils/client'; - -const MESSAGES_LIMIT = 50; - -Template.contactChatHistoryMessages.helpers({ - messages() { - return Template.instance().messages.get(); - }, - messageContext() { - const result = messageContext.call(this, { rid: Template.instance().rid }); - return { - ...result, - settings: { - ...result.settings, - showReplyButton: false, - showreply: false, - hideRoles: true, - }, - }; - }, - hasMore() { - return Template.instance().hasMore.get(); - }, - isLoading() { - return Template.instance().isLoading.get(); - }, - isSearching() { - return Template.instance().searchTerm.get().length > 0; - }, - empty() { - return Template.instance().messages.get().length === 0; - }, - hasError() { - return Template.instance().hasError.get(); - }, - error() { - return Template.instance().error.get(); - }, -}); - -Template.contactChatHistoryMessages.events({ - 'click .js-back'(e, instance) { - return instance.clear(); - }, - 'scroll .js-list': _.throttle(function (e, instance) { - if (e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight && instance.hasMore.get()) { - instance.offset.set(instance.offset.get() + instance.limit.get()); - } - }, 200), - 'keyup #message-search': _.debounce(function (e, instance) { - if (e.keyCode === 13) { - return e.preventDefault(); - } - - const { value } = e.target; - - if (e.keyCode === 40 || e.keyCode === 38) { - return e.preventDefault(); - } - - instance.offset.set(0); - instance.searchTerm.set(value); - }, 300), -}); - -Template.contactChatHistoryMessages.onCreated(function () { - const currentData = Template.currentData(); - this.rid = currentData.rid; - this.messages = new ReactiveVar([]); - this.hasMore = new ReactiveVar(true); - this.offset = new ReactiveVar(0); - this.searchTerm = new ReactiveVar(''); - this.isLoading = new ReactiveVar(true); - this.limit = new ReactiveVar(MESSAGES_LIMIT); - this.hasError = new ReactiveVar(false); - this.error = new ReactiveVar(null); - - this.loadMessages = async (url, params) => { - this.isLoading.set(true); - const offset = this.offset.get(); - - try { - const { messages, total } = await APIClient.get(url, params); - this.messages.set(offset === 0 ? messages : this.messages.get().concat(messages)); - this.hasMore.set(total > this.messages.get().length); - } catch (e) { - this.hasError.set(true); - this.error.set(e); - } finally { - this.isLoading.set(false); - } - }; - - this.autorun(() => { - const limit = this.limit.get(); - const offset = this.offset.get(); - const searchTerm = this.searchTerm.get(); - - if (searchTerm !== '') { - return this.loadMessages('/v1/chat.search', { - roomId: this.rid, - searchText: searchTerm, - count: limit, - offset, - sort: '{"ts": 1}', - }); - } - - this.loadMessages(`/v1/livechat/${this.rid}/messages`, { - count: limit, - offset, - sort: '{"ts": 1}', - }); - }); - - this.autorun(() => { - if (currentData.clear != null) { - this.clear = currentData.clear; - } - }); -}); diff --git a/apps/meteor/app/livechat/client/views/regular.js b/apps/meteor/app/livechat/client/views/regular.js deleted file mode 100644 index e81ecf8ca51a7..0000000000000 --- a/apps/meteor/app/livechat/client/views/regular.js +++ /dev/null @@ -1,5 +0,0 @@ -import './app/livechatReadOnly'; -import './app/livechatNotSubscribed.html'; -import './app/tabbar/contactChatHistory'; -import './app/tabbar/contactChatHistoryItem'; -import './app/tabbar/contactChatHistoryMessages'; diff --git a/apps/meteor/app/livechat/imports/server/rest/agent.js b/apps/meteor/app/livechat/imports/server/rest/agent.js deleted file mode 100644 index fc98c095e5fe2..0000000000000 --- a/apps/meteor/app/livechat/imports/server/rest/agent.js +++ /dev/null @@ -1,29 +0,0 @@ -import { Match, check } from 'meteor/check'; - -import { API } from '../../../../api/server'; -import { findAgentDepartments } from '../../../server/api/lib/agents'; - -API.v1.addRoute( - 'livechat/agents/:agentId/departments', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - get() { - check(this.urlParams, { - agentId: String, - }); - check(this.queryParams, { - enabledDepartmentsOnly: Match.Maybe(String), - }); - - const departments = Promise.await( - findAgentDepartments({ - userId: this.userId, - enabledDepartmentsOnly: this.queryParams.enabledDepartmentsOnly && this.queryParams.enabledDepartmentsOnly === 'true', - agentId: this.urlParams.agentId, - }), - ); - - return API.v1.success(departments); - }, - }, -); diff --git a/apps/meteor/app/livechat/imports/server/rest/agent.ts b/apps/meteor/app/livechat/imports/server/rest/agent.ts new file mode 100644 index 0000000000000..65ac3cd0b6714 --- /dev/null +++ b/apps/meteor/app/livechat/imports/server/rest/agent.ts @@ -0,0 +1,19 @@ +import { isGETLivechatAgentsAgentIdDepartmentsParams } from '@rocket.chat/rest-typings'; + +import { API } from '../../../../api/server'; +import { findAgentDepartments } from '../../../server/api/lib/agents'; + +API.v1.addRoute( + 'livechat/agents/:agentId/departments', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isGETLivechatAgentsAgentIdDepartmentsParams }, + { + async get() { + const departments = await findAgentDepartments({ + enabledDepartmentsOnly: this.queryParams.enabledDepartmentsOnly && this.queryParams.enabledDepartmentsOnly === 'true', + agentId: this.urlParams.agentId, + }); + + return API.v1.success(departments); + }, + }, +); diff --git a/apps/meteor/app/livechat/imports/server/rest/appearance.js b/apps/meteor/app/livechat/imports/server/rest/appearance.ts similarity index 100% rename from apps/meteor/app/livechat/imports/server/rest/appearance.js rename to apps/meteor/app/livechat/imports/server/rest/appearance.ts diff --git a/apps/meteor/app/livechat/imports/server/rest/businessHours.js b/apps/meteor/app/livechat/imports/server/rest/businessHours.js deleted file mode 100644 index 38aeaa0cafdf1..0000000000000 --- a/apps/meteor/app/livechat/imports/server/rest/businessHours.js +++ /dev/null @@ -1,16 +0,0 @@ -import { API } from '../../../../api/server'; -import { findLivechatBusinessHour } from '../../../server/api/lib/businessHours'; - -API.v1.addRoute( - 'livechat/business-hour', - { authRequired: true, permissionsRequired: ['view-livechat-business-hours'] }, - { - async get() { - const { _id, type } = this.queryParams; - const { businessHour } = await findLivechatBusinessHour(_id, type); - return API.v1.success({ - businessHour, - }); - }, - }, -); diff --git a/apps/meteor/app/livechat/imports/server/rest/businessHours.ts b/apps/meteor/app/livechat/imports/server/rest/businessHours.ts new file mode 100644 index 0000000000000..fc0f6209b423c --- /dev/null +++ b/apps/meteor/app/livechat/imports/server/rest/businessHours.ts @@ -0,0 +1,18 @@ +import { isGETBusinessHourParams } from '@rocket.chat/rest-typings'; + +import { API } from '../../../../api/server'; +import { findLivechatBusinessHour } from '../../../server/api/lib/businessHours'; + +API.v1.addRoute( + 'livechat/business-hour', + { authRequired: true, permissionsRequired: ['view-livechat-business-hours'], validateParams: isGETBusinessHourParams }, + { + async get() { + const { _id, type } = this.queryParams; + const { businessHour } = await findLivechatBusinessHour(_id, type); + return API.v1.success({ + businessHour, + }); + }, + }, +); diff --git a/apps/meteor/app/livechat/imports/server/rest/dashboards.js b/apps/meteor/app/livechat/imports/server/rest/dashboards.js deleted file mode 100644 index 672ad71f10ee0..0000000000000 --- a/apps/meteor/app/livechat/imports/server/rest/dashboards.js +++ /dev/null @@ -1,261 +0,0 @@ -import { Match, check } from 'meteor/check'; - -import { API } from '../../../../api/server'; -import { - findAllChatsStatus, - getProductivityMetrics, - getConversationsMetrics, - findAllChatMetricsByAgent, - findAllAgentsStatus, - findAllChatMetricsByDepartment, - findAllResponseTimeMetrics, - getAgentsProductivityMetrics, - getChatsMetrics, -} from '../../../server/lib/analytics/dashboards'; -import { Users } from '../../../../models/server'; - -API.v1.addRoute( - 'livechat/analytics/dashboards/conversation-totalizers', - { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, - { - get() { - let { start, end } = this.requestParams(); - const { departmentId } = this.requestParams(); - - check(start, String); - check(end, String); - check(departmentId, Match.Maybe(String)); - - if (isNaN(Date.parse(start))) { - return API.v1.failure('The "start" query parameter must be a valid date.'); - } - start = new Date(start); - - if (isNaN(Date.parse(end))) { - return API.v1.failure('The "end" query parameter must be a valid date.'); - } - end = new Date(end); - - const user = Users.findOneById(this.userId, { fields: { utcOffset: 1, language: 1 } }); - - const totalizers = getConversationsMetrics({ start, end, departmentId, user }); - return API.v1.success(totalizers); - }, - }, -); - -API.v1.addRoute( - 'livechat/analytics/dashboards/agents-productivity-totalizers', - { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, - { - get() { - let { start, end } = this.requestParams(); - const { departmentId } = this.requestParams(); - - check(start, String); - check(end, String); - check(departmentId, Match.Maybe(String)); - - if (isNaN(Date.parse(start))) { - return API.v1.failure('The "start" query parameter must be a valid date.'); - } - start = new Date(start); - - if (isNaN(Date.parse(end))) { - return API.v1.failure('The "end" query parameter must be a valid date.'); - } - end = new Date(end); - - const user = Users.findOneById(this.userId, { fields: { utcOffset: 1, language: 1 } }); - - const totalizers = getAgentsProductivityMetrics({ start, end, departmentId, user }); - return API.v1.success(totalizers); - }, - }, -); - -API.v1.addRoute( - 'livechat/analytics/dashboards/chats-totalizers', - { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, - { - get() { - let { start, end } = this.requestParams(); - const { departmentId } = this.requestParams(); - - check(start, String); - check(end, String); - check(departmentId, Match.Maybe(String)); - - if (isNaN(Date.parse(start))) { - return API.v1.failure('The "start" query parameter must be a valid date.'); - } - start = new Date(start); - - if (isNaN(Date.parse(end))) { - return API.v1.failure('The "end" query parameter must be a valid date.'); - } - end = new Date(end); - - const totalizers = getChatsMetrics({ start, end, departmentId }); - return API.v1.success(totalizers); - }, - }, -); - -API.v1.addRoute( - 'livechat/analytics/dashboards/productivity-totalizers', - { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, - { - get() { - let { start, end } = this.requestParams(); - const { departmentId } = this.requestParams(); - - check(start, String); - check(end, String); - check(departmentId, Match.Maybe(String)); - - if (isNaN(Date.parse(start))) { - return API.v1.failure('The "start" query parameter must be a valid date.'); - } - start = new Date(start); - - if (isNaN(Date.parse(end))) { - return API.v1.failure('The "end" query parameter must be a valid date.'); - } - end = new Date(end); - - const user = Users.findOneById(this.userId, { fields: { utcOffset: 1, language: 1 } }); - - const totalizers = getProductivityMetrics({ start, end, departmentId, user }); - - return API.v1.success(totalizers); - }, - }, -); - -API.v1.addRoute( - 'livechat/analytics/dashboards/charts/chats', - { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, - { - get() { - let { start, end } = this.requestParams(); - const { departmentId } = this.requestParams(); - - check(start, String); - check(end, String); - check(departmentId, Match.Maybe(String)); - - if (isNaN(Date.parse(start))) { - return API.v1.failure('The "start" query parameter must be a valid date.'); - } - start = new Date(start); - - if (isNaN(Date.parse(end))) { - return API.v1.failure('The "end" query parameter must be a valid date.'); - } - end = new Date(end); - const result = findAllChatsStatus({ start, end, departmentId }); - - return API.v1.success(result); - }, - }, -); - -API.v1.addRoute( - 'livechat/analytics/dashboards/charts/chats-per-agent', - { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, - { - get() { - let { start, end } = this.requestParams(); - const { departmentId } = this.requestParams(); - - check(start, String); - check(end, String); - check(departmentId, Match.Maybe(String)); - - if (isNaN(Date.parse(start))) { - return API.v1.failure('The "start" query parameter must be a valid date.'); - } - start = new Date(start); - - if (isNaN(Date.parse(end))) { - return API.v1.failure('The "end" query parameter must be a valid date.'); - } - end = new Date(end); - const result = findAllChatMetricsByAgent({ start, end, departmentId }); - - return API.v1.success(result); - }, - }, -); - -API.v1.addRoute( - 'livechat/analytics/dashboards/charts/agents-status', - { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, - { - get() { - const { departmentId } = this.requestParams(); - check(departmentId, Match.Maybe(String)); - - const result = findAllAgentsStatus({ departmentId }); - - return API.v1.success(result); - }, - }, -); - -API.v1.addRoute( - 'livechat/analytics/dashboards/charts/chats-per-department', - { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, - { - get() { - let { start, end } = this.requestParams(); - const { departmentId } = this.requestParams(); - - check(start, String); - check(end, String); - check(departmentId, Match.Maybe(String)); - - if (isNaN(Date.parse(start))) { - return API.v1.failure('The "start" query parameter must be a valid date.'); - } - start = new Date(start); - - if (isNaN(Date.parse(end))) { - return API.v1.failure('The "end" query parameter must be a valid date.'); - } - end = new Date(end); - const result = findAllChatMetricsByDepartment({ start, end, departmentId }); - - return API.v1.success(result); - }, - }, -); - -API.v1.addRoute( - 'livechat/analytics/dashboards/charts/timings', - { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, - { - get() { - let { start, end } = this.requestParams(); - const { departmentId } = this.requestParams(); - - check(start, String); - check(end, String); - check(departmentId, Match.Maybe(String)); - - if (isNaN(Date.parse(start))) { - return API.v1.failure('The "start" query parameter must be a valid date.'); - } - start = new Date(start); - - if (isNaN(Date.parse(end))) { - return API.v1.failure('The "end" query parameter must be a valid date.'); - } - end = new Date(end); - const result = findAllResponseTimeMetrics({ start, end, departmentId }); - - return API.v1.success(result); - }, - }, -); diff --git a/apps/meteor/app/livechat/imports/server/rest/dashboards.ts b/apps/meteor/app/livechat/imports/server/rest/dashboards.ts new file mode 100644 index 0000000000000..49895f9d907f7 --- /dev/null +++ b/apps/meteor/app/livechat/imports/server/rest/dashboards.ts @@ -0,0 +1,248 @@ +import { isGETDashboardTotalizerParams, isGETDashboardsAgentStatusParams } from '@rocket.chat/rest-typings'; + +import { API } from '../../../../api/server'; +import { + findAllChatsStatus, + getProductivityMetrics, + getConversationsMetrics, + findAllChatMetricsByAgent, + findAllAgentsStatus, + findAllChatMetricsByDepartment, + findAllResponseTimeMetrics, + getAgentsProductivityMetrics, + getChatsMetrics, +} from '../../../server/lib/analytics/dashboards'; +import { Users } from '../../../../models/server'; + +API.v1.addRoute( + 'livechat/analytics/dashboards/conversation-totalizers', + { + authRequired: true, + permissionsRequired: ['view-livechat-manager'], + validateParams: isGETDashboardTotalizerParams, + }, + { + async get() { + const { start, end } = this.requestParams(); + const { departmentId } = this.requestParams(); + + if (isNaN(Date.parse(start))) { + return API.v1.failure('The "start" query parameter must be a valid date.'); + } + const startDate = new Date(start); + + if (isNaN(Date.parse(end))) { + return API.v1.failure('The "end" query parameter must be a valid date.'); + } + const endDate = new Date(end); + + const user = Users.findOneById(this.userId, { fields: { utcOffset: 1, language: 1 } }); + + // @ts-expect-error TODO: fix this + const totalizers = getConversationsMetrics({ start: startDate, end: endDate, departmentId, user }); + return API.v1.success(totalizers); + }, + }, +); + +API.v1.addRoute( + 'livechat/analytics/dashboards/agents-productivity-totalizers', + { authRequired: true, permissionsRequired: ['view-livechat-manager'], validateParams: isGETDashboardTotalizerParams }, + { + async get() { + const { start, end } = this.requestParams(); + const { departmentId } = this.requestParams(); + + if (isNaN(Date.parse(start))) { + return API.v1.failure('The "start" query parameter must be a valid date.'); + } + const startDate = new Date(start); + + if (isNaN(Date.parse(end))) { + return API.v1.failure('The "end" query parameter must be a valid date.'); + } + const endDate = new Date(end); + + const user = Users.findOneById(this.userId, { fields: { utcOffset: 1, language: 1 } }); + + // @ts-expect-error TODO: fix this + const totalizers = getAgentsProductivityMetrics({ start: startDate, end: endDate, departmentId, user }); + return API.v1.success(totalizers); + }, + }, +); + +API.v1.addRoute( + 'livechat/analytics/dashboards/chats-totalizers', + { authRequired: true, permissionsRequired: ['view-livechat-manager'], validateParams: isGETDashboardTotalizerParams }, + { + async get() { + const { start, end } = this.requestParams(); + const { departmentId } = this.requestParams(); + + if (isNaN(Date.parse(start))) { + return API.v1.failure('The "start" query parameter must be a valid date.'); + } + const startDate = new Date(start); + + if (isNaN(Date.parse(end))) { + return API.v1.failure('The "end" query parameter must be a valid date.'); + } + const endDate = new Date(end); + + // @ts-expect-error TODO: fix this + const totalizers = getChatsMetrics({ start: startDate, end: endDate, departmentId }); + return API.v1.success(totalizers); + }, + }, +); + +API.v1.addRoute( + 'livechat/analytics/dashboards/productivity-totalizers', + { authRequired: true, permissionsRequired: ['view-livechat-manager'], validateParams: isGETDashboardTotalizerParams }, + { + async get() { + const { start, end } = this.requestParams(); + const { departmentId } = this.requestParams(); + + if (isNaN(Date.parse(start))) { + return API.v1.failure('The "start" query parameter must be a valid date.'); + } + const startDate = new Date(start); + + if (isNaN(Date.parse(end))) { + return API.v1.failure('The "end" query parameter must be a valid date.'); + } + const endDate = new Date(end); + + const user = Users.findOneById(this.userId, { fields: { utcOffset: 1, language: 1 } }); + + // @ts-expect-error TODO: fix this + const totalizers = getProductivityMetrics({ start: startDate, end: endDate, departmentId, user }); + + return API.v1.success(totalizers); + }, + }, +); + +API.v1.addRoute( + 'livechat/analytics/dashboards/charts/chats', + { authRequired: true, permissionsRequired: ['view-livechat-manager'], validateParams: isGETDashboardTotalizerParams }, + { + async get() { + const { start, end } = this.requestParams(); + const { departmentId } = this.requestParams(); + + if (isNaN(Date.parse(start))) { + return API.v1.failure('The "start" query parameter must be a valid date.'); + } + const startDate = new Date(start); + + if (isNaN(Date.parse(end))) { + return API.v1.failure('The "end" query parameter must be a valid date.'); + } + const endDate = new Date(end); + + // @ts-expect-error TODO: fix this + const result = findAllChatsStatus({ start: startDate, end: endDate, departmentId }); + + return API.v1.success(result); + }, + }, +); + +API.v1.addRoute( + 'livechat/analytics/dashboards/charts/chats-per-agent', + { authRequired: true, permissionsRequired: ['view-livechat-manager'], validateParams: isGETDashboardTotalizerParams }, + { + async get() { + const { start, end } = this.requestParams(); + const { departmentId } = this.requestParams(); + + if (isNaN(Date.parse(start))) { + return API.v1.failure('The "start" query parameter must be a valid date.'); + } + const startDate = new Date(start); + + if (isNaN(Date.parse(end))) { + return API.v1.failure('The "end" query parameter must be a valid date.'); + } + const endDate = new Date(end); + // @ts-expect-error TODO: fix this + const result = findAllChatMetricsByAgent({ start: startDate, end: endDate, departmentId }) as { + [k: string]: { open: number; closed: number; onhold: number }; + }; + + return API.v1.success(result); + }, + }, +); + +API.v1.addRoute( + 'livechat/analytics/dashboards/charts/agents-status', + { authRequired: true, permissionsRequired: ['view-livechat-manager'], validateParams: isGETDashboardsAgentStatusParams }, + { + async get() { + const { departmentId } = this.requestParams(); + + // @ts-expect-error TODO: fix this + const result = findAllAgentsStatus({ departmentId }); + + return API.v1.success(result); + }, + }, +); + +API.v1.addRoute( + 'livechat/analytics/dashboards/charts/chats-per-department', + { authRequired: true, permissionsRequired: ['view-livechat-manager'], validateParams: isGETDashboardTotalizerParams }, + { + async get() { + const { start, end } = this.requestParams(); + const { departmentId } = this.requestParams(); + + if (isNaN(Date.parse(start))) { + return API.v1.failure('The "start" query parameter must be a valid date.'); + } + const startDate = new Date(start); + + if (isNaN(Date.parse(end))) { + return API.v1.failure('The "end" query parameter must be a valid date.'); + } + const endDate = new Date(end); + + // @ts-expect-error TODO: fix this + const result = findAllChatMetricsByDepartment({ start: startDate, end: endDate, departmentId }) as { + [k: string]: { open: number; closed: number }; + }; + + return API.v1.success(result); + }, + }, +); + +API.v1.addRoute( + 'livechat/analytics/dashboards/charts/timings', + { authRequired: true, permissionsRequired: ['view-livechat-manager'], validateParams: isGETDashboardTotalizerParams }, + { + async get() { + const { start, end } = this.requestParams(); + const { departmentId } = this.requestParams(); + + if (isNaN(Date.parse(start))) { + return API.v1.failure('The "start" query parameter must be a valid date.'); + } + const startDate = new Date(start); + + if (isNaN(Date.parse(end))) { + return API.v1.failure('The "end" query parameter must be a valid date.'); + } + const endDate = new Date(end); + + // @ts-expect-error TODO: fix this + const result = findAllResponseTimeMetrics({ start: startDate, end: endDate, departmentId }); + + return API.v1.success(result); + }, + }, +); diff --git a/apps/meteor/app/livechat/imports/server/rest/departments.ts b/apps/meteor/app/livechat/imports/server/rest/departments.ts index c3a652fab1fbb..3384bf0fa611d 100644 --- a/apps/meteor/app/livechat/imports/server/rest/departments.ts +++ b/apps/meteor/app/livechat/imports/server/rest/departments.ts @@ -1,9 +1,9 @@ import { isGETLivechatDepartmentProps, isPOSTLivechatDepartmentProps } from '@rocket.chat/rest-typings'; import { Match, check } from 'meteor/check'; +import { LivechatDepartment, LivechatDepartmentAgents } from '@rocket.chat/models'; import { API } from '../../../../api/server'; import { hasPermission } from '../../../../authorization/server'; -import { LivechatDepartment, LivechatDepartmentAgents } from '../../../../models/server'; import { Livechat } from '../../../server/lib/Livechat'; import { findDepartments, @@ -11,7 +11,10 @@ import { findDepartmentsToAutocomplete, findDepartmentsBetweenIds, findDepartmentAgents, + findArchivedDepartments, } from '../../../server/api/lib/departments'; +import { LivechatEnterprise } from '../../../../../ee/app/livechat-enterprise/server/lib/LivechatEnterprise'; +import { DepartmentHelper } from '../../../server/lib/Departments'; API.v1.addRoute( 'livechat/department', @@ -28,12 +31,13 @@ API.v1.addRoute( const { offset, count } = this.getPaginationItems(); const { sort } = this.parseJsonQuery(); - const { text, enabled, onlyMyDepartments, excludeDepartmentId } = this.queryParams; + const { text, enabled, onlyMyDepartments, excludeDepartmentId, showArchived } = this.queryParams; const { departments, total } = await findDepartments({ userId: this.userId, text, enabled: enabled === 'true', + showArchived: showArchived === 'true', onlyMyDepartments: onlyMyDepartments === 'true', excludeDepartmentId, pagination: { @@ -54,12 +58,12 @@ API.v1.addRoute( }); const agents = this.bodyParams.agents ? { upsert: this.bodyParams.agents } : {}; - const department = Livechat.saveDepartment(null, this.bodyParams.department, agents); + const department = await LivechatEnterprise.saveDepartment(null, this.bodyParams.department, agents); if (department) { return API.v1.success({ department, - agents: LivechatDepartmentAgents.find({ departmentId: department._id }).fetch(), + agents: await LivechatDepartmentAgents.find({ departmentId: department._id }).toArray(), }); } @@ -99,57 +103,115 @@ API.v1.addRoute( return API.v1.success({ department, agents }); }, - put() { + async put() { const permissionToSave = hasPermission(this.userId, 'manage-livechat-departments'); const permissionToAddAgents = hasPermission(this.userId, 'add-livechat-department-agents'); - try { - check(this.urlParams, { - _id: String, - }); + check(this.urlParams, { + _id: String, + }); + + check(this.bodyParams, { + department: Object, + agents: Match.Maybe(Array), + }); + + const { _id } = this.urlParams; + const { department, agents } = this.bodyParams; + + let success; + if (permissionToSave) { + success = await LivechatEnterprise.saveDepartment(_id, department); + } + + if (success && agents && permissionToAddAgents) { + success = Livechat.saveDepartmentAgents(_id, { upsert: agents }); + } - check(this.bodyParams, { - department: Object, - agents: Match.Maybe(Array), + if (success) { + return API.v1.success({ + department: await LivechatDepartment.findOneById(_id), + agents: await LivechatDepartmentAgents.find({ departmentId: _id }).toArray(), }); + } + + return API.v1.failure(); + }, + async delete() { + check(this.urlParams, { + _id: String, + }); - const { _id } = this.urlParams; - const { department, agents } = this.bodyParams; + await DepartmentHelper.removeDepartment(this.urlParams._id); - let success; - if (permissionToSave) { - success = Livechat.saveDepartment(_id, department); - } + return API.v1.success(); + }, + }, +); - if (success && agents && permissionToAddAgents) { - success = Livechat.saveDepartmentAgents(_id, { upsert: agents }); - } +API.v1.addRoute( + 'livechat/departments/archived', + { + authRequired: true, + validateParams: { GET: isGETLivechatDepartmentProps }, + permissionsRequired: { + GET: { permissions: ['view-livechat-departments', 'view-l-room'], operation: 'hasAny' }, + }, + }, + { + async get() { + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); - if (success) { - return API.v1.success({ - department: LivechatDepartment.findOneById(_id), - agents: LivechatDepartmentAgents.find({ departmentId: _id }).fetch(), - }); - } + const { text, onlyMyDepartments, excludeDepartmentId } = this.queryParams; - return API.v1.failure(); - } catch (e) { - return API.v1.failure(e); + const { departments, total } = await findArchivedDepartments({ + userId: this.userId, + text, + onlyMyDepartments: onlyMyDepartments === 'true', + excludeDepartmentId, + pagination: { + offset, + count, + sort: sort as any, + }, + }); + + return API.v1.success({ departments, count: departments.length, offset, total }); + }, + }, +); + +API.v1.addRoute( + 'livechat/department/:_id/archive', + { + authRequired: true, + permissionsRequired: ['manage-livechat-departments'], + }, + { + async post() { + if (await Livechat.archiveDepartment(this.urlParams._id)) { + return API.v1.success(); } + + return API.v1.failure(); }, - delete() { - try { - check(this.urlParams, { - _id: String, - }); + }, +); - if (Livechat.removeDepartment(this.urlParams._id)) { - return API.v1.success(); - } - return API.v1.failure(); - } catch (e) { - return API.v1.failure(e); +API.v1.addRoute( + 'livechat/department/:_id/unarchive', + { + authRequired: true, + permissionsRequired: ['manage-livechat-departments'], + }, + { + async post() { + if (await Livechat.unarchiveDepartment(this.urlParams._id)) { + return API.v1.success(); } + + return API.v1.failure(); }, }, ); @@ -159,7 +221,7 @@ API.v1.addRoute( { authRequired: true, permissionsRequired: { GET: { permissions: ['view-livechat-departments', 'view-l-room'], operation: 'hasAny' } } }, { async get() { - const { selector, onlyMyDepartments } = this.queryParams; + const { selector, onlyMyDepartments, showArchived } = this.queryParams; if (!selector) { return API.v1.failure("The 'selector' param is required"); } @@ -169,6 +231,7 @@ API.v1.addRoute( uid: this.userId, selector: JSON.parse(selector), onlyMyDepartments: onlyMyDepartments === 'true', + showArchived: showArchived === 'true', }), ); }, @@ -176,7 +239,7 @@ API.v1.addRoute( ); API.v1.addRoute( - 'livechat/department/:departmentId/agents', + 'livechat/department/:_id/agents', { authRequired: true, permissionsRequired: { @@ -187,7 +250,7 @@ API.v1.addRoute( { async get() { check(this.urlParams, { - departmentId: String, + _id: String, }); const { offset, count } = this.getPaginationItems(); @@ -195,7 +258,7 @@ API.v1.addRoute( const agents = await findDepartmentAgents({ userId: this.userId, - departmentId: this.urlParams.departmentId, + departmentId: this.urlParams._id, pagination: { offset, count, @@ -205,9 +268,9 @@ API.v1.addRoute( return API.v1.success(agents); }, - post() { + async post() { check(this.urlParams, { - departmentId: String, + _id: String, }); check( @@ -217,7 +280,7 @@ API.v1.addRoute( remove: Array, }), ); - Livechat.saveDepartmentAgents(this.urlParams.departmentId, this.bodyParams); + Livechat.saveDepartmentAgents(this.urlParams._id, this.bodyParams); return API.v1.success(); }, @@ -247,3 +310,18 @@ API.v1.addRoute( }, }, ); +API.v1.addRoute( + 'livechat/department/isDepartmentCreationAvailable', + { + authRequired: true, + permissionsRequired: { + GET: { permissions: ['view-livechat-departments', 'manage-livechat-departments'], operation: 'hasAny' }, + }, + }, + { + async get() { + const isDepartmentCreationAvailable = true; + return API.v1.success({ isDepartmentCreationAvailable }); + }, + }, +); diff --git a/apps/meteor/app/livechat/imports/server/rest/facebook.js b/apps/meteor/app/livechat/imports/server/rest/facebook.js deleted file mode 100644 index db8f74ea264ca..0000000000000 --- a/apps/meteor/app/livechat/imports/server/rest/facebook.js +++ /dev/null @@ -1,100 +0,0 @@ -import crypto from 'crypto'; - -import { Random } from 'meteor/random'; -import { LivechatVisitors } from '@rocket.chat/models'; - -import { API } from '../../../../api/server'; -import { LivechatRooms } from '../../../../models/server'; -import { settings } from '../../../../settings/server'; -import { Livechat } from '../../../server/lib/Livechat'; - -/** - * @api {post} /livechat/facebook Send Facebook message - * @apiName Facebook - * @apiGroup Livechat - * - * @apiParam {String} mid Facebook message id - * @apiParam {String} page Facebook pages id - * @apiParam {String} token Facebook user's token - * @apiParam {String} first_name Facebook user's first name - * @apiParam {String} last_name Facebook user's last name - * @apiParam {String} [text] Facebook message text - * @apiParam {String} [attachments] Facebook message attachments - */ -API.v1.addRoute('livechat/facebook', { - async post() { - if (!this.bodyParams.text && !this.bodyParams.attachments) { - return { - success: false, - }; - } - - if (!this.request.headers['x-hub-signature']) { - return { - success: false, - }; - } - - if (!settings.get('Livechat_Facebook_Enabled')) { - return { - success: false, - error: 'Integration disabled', - }; - } - - // validate if request come from omni - const signature = crypto - .createHmac('sha1', settings.get('Livechat_Facebook_API_Secret')) - .update(JSON.stringify(this.request.body)) - .digest('hex'); - if (this.request.headers['x-hub-signature'] !== `sha1=${signature}`) { - return { - success: false, - error: 'Invalid signature', - }; - } - - const sendMessage = { - message: { - _id: this.bodyParams.mid, - }, - roomInfo: { - facebook: { - page: this.bodyParams.page, - }, - }, - }; - let visitor = await LivechatVisitors.getVisitorByToken(this.bodyParams.token); - if (visitor) { - const rooms = LivechatRooms.findOpenByVisitorToken(visitor.token).fetch(); - if (rooms && rooms.length > 0) { - sendMessage.message.rid = rooms[0]._id; - } else { - sendMessage.message.rid = Random.id(); - } - sendMessage.message.token = visitor.token; - } else { - sendMessage.message.rid = Random.id(); - sendMessage.message.token = this.bodyParams.token; - - const userId = await Livechat.registerGuest({ - token: sendMessage.message.token, - name: `${this.bodyParams.first_name} ${this.bodyParams.last_name}`, - }); - - visitor = await LivechatVisitors.findOneById(userId); - } - - sendMessage.message.msg = this.bodyParams.text; - sendMessage.guest = visitor; - - try { - return { - sucess: true, - message: Livechat.sendMessage(sendMessage), - }; - } catch (e) { - Livechat.logger.error('Error using Facebook ->', e); - } - }, -}); diff --git a/apps/meteor/app/livechat/imports/server/rest/inquiries.js b/apps/meteor/app/livechat/imports/server/rest/inquiries.js deleted file mode 100644 index cff351cad06ee..0000000000000 --- a/apps/meteor/app/livechat/imports/server/rest/inquiries.js +++ /dev/null @@ -1,140 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Match, check } from 'meteor/check'; -import { LivechatInquiryStatus } from '@rocket.chat/core-typings'; -import { LivechatInquiry } from '@rocket.chat/models'; - -import { API } from '../../../../api/server'; -import { Users, LivechatDepartment } from '../../../../models/server'; -import { findInquiries, findOneInquiryByRoomId } from '../../../server/api/lib/inquiries'; - -API.v1.addRoute( - 'livechat/inquiries.list', - { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, - { - async get() { - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - const { department } = this.requestParams(); - const ourQuery = Object.assign({}, { status: 'queued' }); - if (department) { - const departmentFromDB = LivechatDepartment.findOneByIdOrName(department); - if (departmentFromDB) { - ourQuery.department = departmentFromDB._id; - } - } - const { cursor, totalCount } = LivechatInquiry.findPaginated(ourQuery, { - sort: sort || { ts: -1 }, - skip: offset, - limit: count, - projection: { - rid: 1, - name: 1, - ts: 1, - status: 1, - department: 1, - }, - }); - - const [inquiries, total] = await Promise.all([cursor.toArray(), totalCount]); - - return API.v1.success({ - inquiries, - offset, - count: inquiries.length, - total, - }); - }, - }, -); - -API.v1.addRoute( - 'livechat/inquiries.take', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - post() { - check(this.bodyParams, { - inquiryId: String, - userId: Match.Maybe(String), - }); - if (this.bodyParams.userId && !Users.findOneById(this.bodyParams.userId, { fields: { _id: 1 } })) { - return API.v1.failure('The user is invalid'); - } - return API.v1.success({ - inquiry: Meteor.runAsUser(this.bodyParams.userId || this.userId, () => - Meteor.call('livechat:takeInquiry', this.bodyParams.inquiryId), - ), - }); - }, - }, -); - -API.v1.addRoute( - 'livechat/inquiries.queued', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - get() { - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - const { department } = this.requestParams(); - - return API.v1.success( - Promise.await( - findInquiries({ - userId: this.userId, - department, - status: 'queued', - pagination: { - offset, - count, - sort, - }, - }), - ), - ); - }, - }, -); - -API.v1.addRoute( - 'livechat/inquiries.queuedForUser', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - async get() { - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - const { department } = this.requestParams(); - - return API.v1.success( - await findInquiries({ - userId: this.userId, - filterDepartment: department, - status: LivechatInquiryStatus.QUEUED, - pagination: { - offset, - count, - sort, - }, - }), - ); - }, - }, -); - -API.v1.addRoute( - 'livechat/inquiries.getOne', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - async get() { - const { roomId } = this.queryParams; - if (!roomId) { - return API.v1.failure("The 'roomId' param is required"); - } - - return API.v1.success( - await findOneInquiryByRoomId({ - roomId, - }), - ); - }, - }, -); diff --git a/apps/meteor/app/livechat/imports/server/rest/inquiries.ts b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts new file mode 100644 index 0000000000000..b9c49671645d2 --- /dev/null +++ b/apps/meteor/app/livechat/imports/server/rest/inquiries.ts @@ -0,0 +1,143 @@ +import { + isGETLivechatInquiriesListParams, + isPOSTLivechatInquiriesTakeParams, + isGETLivechatInquiriesQueuedParams, + isGETLivechatInquiriesQueuedForUserParams, + isGETLivechatInquiriesGetOneParams, +} from '@rocket.chat/rest-typings'; +import { Meteor } from 'meteor/meteor'; +import { LivechatInquiryStatus } from '@rocket.chat/core-typings'; +import { LivechatInquiry } from '@rocket.chat/models'; + +import { API } from '../../../../api/server'; +import { Users, LivechatDepartment } from '../../../../models/server'; +import { findInquiries, findOneInquiryByRoomId } from '../../../server/api/lib/inquiries'; +import { deprecationWarning } from '../../../../api/server/helpers/deprecationWarning'; + +API.v1.addRoute( + 'livechat/inquiries.list', + { authRequired: true, permissionsRequired: ['view-livechat-manager'], validateParams: isGETLivechatInquiriesListParams }, + { + async get() { + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + const { department } = this.requestParams(); + const ourQuery: { status: string; department?: string } = { status: 'queued' }; + if (department) { + const departmentFromDB = LivechatDepartment.findOneByIdOrName(department); + if (departmentFromDB) { + ourQuery.department = departmentFromDB._id; + } + } + // @ts-expect-error - attachments... + const { cursor, totalCount } = LivechatInquiry.findPaginated(ourQuery, { + sort: sort || { ts: -1 }, + skip: offset, + limit: count, + projection: { + rid: 1, + name: 1, + ts: 1, + status: 1, + department: 1, + }, + }); + + const [inquiries, total] = await Promise.all([cursor.toArray(), totalCount]); + + return API.v1.success({ + inquiries, + offset, + count: inquiries.length, + total, + }); + }, + }, +); + +API.v1.addRoute( + 'livechat/inquiries.take', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isPOSTLivechatInquiriesTakeParams }, + { + async post() { + if (this.bodyParams.userId && !Users.findOneById(this.bodyParams.userId, { fields: { _id: 1 } })) { + return API.v1.failure('The user is invalid'); + } + return API.v1.success({ + inquiry: Meteor.runAsUser(this.bodyParams.userId || this.userId, () => + Meteor.call('livechat:takeInquiry', this.bodyParams.inquiryId), + ), + }); + }, + }, +); + +API.v1.addRoute( + 'livechat/inquiries.queued', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isGETLivechatInquiriesQueuedParams }, + { + async get() { + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + const { department } = this.requestParams(); + + return API.v1.success( + deprecationWarning({ + endpoint: 'livechat/inquiries.queued', + versionWillBeRemoved: '6.0', + response: await findInquiries({ + userId: this.userId, + department, + status: LivechatInquiryStatus.QUEUED, + pagination: { + offset, + count, + sort, + }, + }), + }), + ); + }, + }, +); + +API.v1.addRoute( + 'livechat/inquiries.queuedForUser', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isGETLivechatInquiriesQueuedForUserParams }, + { + async get() { + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + const { department } = this.requestParams(); + + return API.v1.success( + await findInquiries({ + userId: this.userId, + department, + status: LivechatInquiryStatus.QUEUED, + pagination: { + offset, + count, + sort, + }, + }), + ); + }, + }, +); + +API.v1.addRoute( + 'livechat/inquiries.getOne', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isGETLivechatInquiriesGetOneParams }, + { + async get() { + const { roomId } = this.queryParams; + + return API.v1.success( + await findOneInquiryByRoomId({ + roomId, + }), + ); + }, + }, +); diff --git a/apps/meteor/app/livechat/imports/server/rest/integrations.js b/apps/meteor/app/livechat/imports/server/rest/integrations.ts similarity index 100% rename from apps/meteor/app/livechat/imports/server/rest/integrations.js rename to apps/meteor/app/livechat/imports/server/rest/integrations.ts diff --git a/apps/meteor/app/livechat/imports/server/rest/queue.js b/apps/meteor/app/livechat/imports/server/rest/queue.js deleted file mode 100644 index 0e63f3a248212..0000000000000 --- a/apps/meteor/app/livechat/imports/server/rest/queue.js +++ /dev/null @@ -1,26 +0,0 @@ -import { API } from '../../../../api/server'; -import { findQueueMetrics } from '../../../server/api/lib/queue'; - -API.v1.addRoute( - 'livechat/queue', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - async get() { - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - const { agentId, includeOfflineAgents, departmentId } = this.requestParams(); - const users = await findQueueMetrics({ - agentId, - includeOfflineAgents: includeOfflineAgents === 'true', - departmentId, - pagination: { - offset, - count, - sort, - }, - }); - - return API.v1.success(users); - }, - }, -); diff --git a/apps/meteor/app/livechat/imports/server/rest/queue.ts b/apps/meteor/app/livechat/imports/server/rest/queue.ts new file mode 100644 index 0000000000000..fa7843c7492f4 --- /dev/null +++ b/apps/meteor/app/livechat/imports/server/rest/queue.ts @@ -0,0 +1,28 @@ +import { isGETLivechatQueueParams } from '@rocket.chat/rest-typings'; + +import { API } from '../../../../api/server'; +import { findQueueMetrics } from '../../../server/api/lib/queue'; + +API.v1.addRoute( + 'livechat/queue', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isGETLivechatQueueParams }, + { + async get() { + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + const { agentId, includeOfflineAgents, departmentId } = this.requestParams(); + const users = await findQueueMetrics({ + agentId, + includeOfflineAgents: includeOfflineAgents === 'true', + departmentId, + pagination: { + offset, + count, + sort, + }, + }); + + return API.v1.success(users); + }, + }, +); diff --git a/apps/meteor/app/livechat/imports/server/rest/rooms.js b/apps/meteor/app/livechat/imports/server/rest/rooms.js deleted file mode 100644 index c2b0e8236d5cd..0000000000000 --- a/apps/meteor/app/livechat/imports/server/rest/rooms.js +++ /dev/null @@ -1,73 +0,0 @@ -import { Match, check } from 'meteor/check'; - -import { API } from '../../../../api/server'; -import { findRooms } from '../../../server/api/lib/rooms'; -import { hasPermission } from '../../../../authorization/server'; - -const validateDateParams = (property, date) => { - if (date) { - date = JSON.parse(date); - } - if (date && date.start && isNaN(Date.parse(date.start))) { - throw new Error(`The "${property}.start" query parameter must be a valid date.`); - } - if (date && date.end && isNaN(Date.parse(date.end))) { - throw new Error(`The "${property}.end" query parameter must be a valid date.`); - } - return date; -}; - -API.v1.addRoute( - 'livechat/rooms', - { authRequired: true }, - { - async get() { - const { offset, count } = this.getPaginationItems(); - const { sort, fields } = this.parseJsonQuery(); - const { agents, departmentId, open, tags, roomName, onhold } = this.requestParams(); - let { createdAt, customFields, closedAt } = this.requestParams(); - check(agents, Match.Maybe([String])); - check(roomName, Match.Maybe(String)); - check(departmentId, Match.Maybe(String)); - check(open, Match.Maybe(String)); - check(onhold, Match.Maybe(String)); - check(tags, Match.Maybe([String])); - check(customFields, Match.Maybe(String)); - - createdAt = validateDateParams('createdAt', createdAt); - closedAt = validateDateParams('closedAt', closedAt); - - const hasAdminAccess = hasPermission(this.userId, 'view-livechat-rooms'); - const hasAgentAccess = hasPermission(this.userId, 'view-l-room') && agents?.includes(this.userId) && agents?.length === 1; - if (!hasAdminAccess && !hasAgentAccess) { - return API.v1.unauthorized(); - } - - if (customFields) { - try { - const parsedCustomFields = JSON.parse(customFields); - check(parsedCustomFields, Object); - // Model's already checking for the keys, so we don't need to do it here. - customFields = parsedCustomFields; - } catch (e) { - throw new Error('The "customFields" query parameter must be a valid JSON.'); - } - } - - return API.v1.success( - await findRooms({ - agents, - roomName, - departmentId, - open: open && open === 'true', - createdAt, - closedAt, - tags, - customFields, - onhold, - options: { offset, count, sort, fields }, - }), - ); - }, - }, -); diff --git a/apps/meteor/app/livechat/imports/server/rest/rooms.ts b/apps/meteor/app/livechat/imports/server/rest/rooms.ts new file mode 100644 index 0000000000000..1a417236c75ee --- /dev/null +++ b/apps/meteor/app/livechat/imports/server/rest/rooms.ts @@ -0,0 +1,87 @@ +import { isGETLivechatRoomsParams } from '@rocket.chat/rest-typings'; +import { LivechatRooms } from '@rocket.chat/models'; + +import { API } from '../../../../api/server'; +import { findRooms } from '../../../server/api/lib/rooms'; +import { hasPermission } from '../../../../authorization/server'; + +const validateDateParams = (property: string, date?: string) => { + let parsedDate: { start?: string; end?: string } | undefined = undefined; + if (date) { + parsedDate = JSON.parse(date) as { start?: string; end?: string }; + } + + if (parsedDate?.start && isNaN(Date.parse(parsedDate.start))) { + throw new Error(`The "${property}.start" query parameter must be a valid date.`); + } + if (parsedDate?.end && isNaN(Date.parse(parsedDate.end))) { + throw new Error(`The "${property}.end" query parameter must be a valid date.`); + } + return parsedDate; +}; + +const isBoolean = (value?: string | boolean): boolean => value === 'true' || value === 'false' || typeof value === 'boolean'; + +API.v1.addRoute( + 'livechat/rooms', + { authRequired: true, validateParams: isGETLivechatRoomsParams }, + { + async get() { + const { offset, count } = this.getPaginationItems(); + const { sort, fields } = this.parseJsonQuery(); + const { agents, departmentId, open, tags, roomName, onhold } = this.requestParams(); + const { createdAt, customFields, closedAt } = this.requestParams(); + + const createdAtParam = validateDateParams('createdAt', createdAt); + const closedAtParam = validateDateParams('closedAt', closedAt); + + const hasAdminAccess = hasPermission(this.userId, 'view-livechat-rooms'); + const hasAgentAccess = hasPermission(this.userId, 'view-l-room') && agents?.includes(this.userId) && agents?.length === 1; + if (!hasAdminAccess && !hasAgentAccess) { + return API.v1.unauthorized(); + } + + let parsedCf: { [key: string]: string } | undefined = undefined; + if (customFields) { + try { + const parsedCustomFields = JSON.parse(customFields) as { [key: string]: string }; + if (typeof parsedCustomFields !== 'object' || Array.isArray(parsedCustomFields) || parsedCustomFields === null) { + throw new Error('Invalid custom fields'); + } + + // Model's already checking for the keys, so we don't need to do it here. + parsedCf = parsedCustomFields; + } catch (e) { + throw new Error('The "customFields" query parameter must be a valid JSON.'); + } + } + + return API.v1.success( + await findRooms({ + agents, + roomName, + departmentId, + ...(isBoolean(open) && { open: open === 'true' }), + createdAt: createdAtParam, + closedAt: closedAtParam, + tags, + customFields: parsedCf, + onhold, + options: { offset, count, sort, fields }, + }), + ); + }, + }, +); + +API.v1.addRoute( + 'livechat/rooms/filters', + { authRequired: true, permissionsRequired: ['view-l-room'] }, + { + async get() { + return API.v1.success({ + filters: (await LivechatRooms.findAvailableSources().toArray())[0].fullTypes, + }); + }, + }, +); diff --git a/apps/meteor/app/livechat/imports/server/rest/sms.js b/apps/meteor/app/livechat/imports/server/rest/sms.js index 65a2d248ff307..3670360c7f6d0 100644 --- a/apps/meteor/app/livechat/imports/server/rest/sms.js +++ b/apps/meteor/app/livechat/imports/server/rest/sms.js @@ -158,8 +158,8 @@ API.v1.addRoute('livechat/sms-incoming/:service', { } else { attachment.title_link_download = true; } - } catch (e) { - Livechat.logger.error(`Attachment upload failed: ${e.message}`); + } catch (err) { + Livechat.logger.error({ msg: 'Attachment upload failed', err }); attachment = { fields: [ { @@ -197,6 +197,9 @@ API.v1.addRoute('livechat/sms-incoming/:service', { if (sms.extra.fromCity) { Meteor.call('livechat:setCustomField', sendMessage.message.token, 'city', sms.extra.fromCity); } + if (sms.extra.toPhone) { + Meteor.call('livechat:setCustomField', sendMessage.message.token, 'phoneNumber', sms.extra.toPhone); + } } }); diff --git a/apps/meteor/app/livechat/imports/server/rest/triggers.js b/apps/meteor/app/livechat/imports/server/rest/triggers.js deleted file mode 100644 index 59e055aa4ce4f..0000000000000 --- a/apps/meteor/app/livechat/imports/server/rest/triggers.js +++ /dev/null @@ -1,71 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { check } from 'meteor/check'; - -import { API } from '../../../../api/server'; -import { findTriggers, findTriggerById } from '../../../server/api/lib/triggers'; - -API.v1.addRoute( - 'livechat/trigger', - { authRequired: true }, - { - post() { - try { - check(this.bodyParams, { - _id: String, - name: String, - description: String, - enabled: Boolean, - runOnce: Boolean, - registeredOnly: Boolean, - conditions: Array, - actions: Array, - }); - - API.v1.success(Meteor.runAsUser(this.userId, () => Meteor.call('livechat:saveTrigger', this.bodyParams))); - } catch (e) { - return API.v1.failure(e); - } - }, - }, -); - -API.v1.addRoute( - 'livechat/triggers', - { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, - { - async get() { - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - - const triggers = await findTriggers({ - pagination: { - offset, - count, - sort, - }, - }); - - return API.v1.success(triggers); - }, - }, -); - -API.v1.addRoute( - 'livechat/triggers/:_id', - { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, - { - async get() { - check(this.urlParams, { - _id: String, - }); - - const trigger = await findTriggerById({ - triggerId: this.urlParams._id, - }); - - return API.v1.success({ - trigger, - }); - }, - }, -); diff --git a/apps/meteor/app/livechat/imports/server/rest/triggers.ts b/apps/meteor/app/livechat/imports/server/rest/triggers.ts new file mode 100644 index 0000000000000..fe406b2e7b6d3 --- /dev/null +++ b/apps/meteor/app/livechat/imports/server/rest/triggers.ts @@ -0,0 +1,68 @@ +import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; +import { isGETLivechatTriggersParams } from '@rocket.chat/rest-typings'; + +import { API } from '../../../../api/server'; +import { findTriggers, findTriggerById } from '../../../server/api/lib/triggers'; + +API.v1.addRoute( + 'livechat/trigger', + { authRequired: true }, + { + post() { + try { + check(this.bodyParams, { + _id: String, + name: String, + description: String, + enabled: Boolean, + runOnce: Boolean, + registeredOnly: Boolean, + conditions: Array, + actions: Array, + }); + + API.v1.success(Meteor.runAsUser(this.userId, () => Meteor.call('livechat:saveTrigger', this.bodyParams))); + } catch (e) { + return API.v1.failure(e); + } + }, + }, +); + +API.v1.addRoute( + 'livechat/triggers', + { authRequired: true, permissionsRequired: ['view-livechat-manager'], validateParams: isGETLivechatTriggersParams }, + { + async get() { + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + + const triggers = await findTriggers({ + pagination: { + offset, + count, + sort, + }, + }); + + return API.v1.success(triggers); + }, + }, +); + +API.v1.addRoute( + 'livechat/triggers/:_id', + { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, + { + async get() { + const trigger = await findTriggerById({ + triggerId: this.urlParams._id, + }); + + return API.v1.success({ + trigger, + }); + }, + }, +); diff --git a/apps/meteor/app/livechat/imports/server/rest/upload.js b/apps/meteor/app/livechat/imports/server/rest/upload.js deleted file mode 100644 index 079daec7be226..0000000000000 --- a/apps/meteor/app/livechat/imports/server/rest/upload.js +++ /dev/null @@ -1,81 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import filesize from 'filesize'; -import { LivechatVisitors, Settings } from '@rocket.chat/models'; - -import { settings } from '../../../../settings/server'; -import { LivechatRooms } from '../../../../models/server'; -import { fileUploadIsValidContentType } from '../../../../utils/server'; -import { FileUpload } from '../../../../file-upload/server'; -import { API } from '../../../../api/server'; -import { getUploadFormData } from '../../../../api/server/lib/getUploadFormData'; - -let maxFileSize; - -settings.watch('FileUpload_MaxFileSize', async function (value) { - try { - maxFileSize = parseInt(value); - } catch (e) { - maxFileSize = await Settings.findOneById('FileUpload_MaxFileSize').packageValue; - } -}); - -API.v1.addRoute('livechat/upload/:rid', { - async post() { - if (!this.request.headers['x-visitor-token']) { - return API.v1.unauthorized(); - } - - const visitorToken = this.request.headers['x-visitor-token']; - const visitor = await LivechatVisitors.getVisitorByToken(visitorToken); - - if (!visitor) { - return API.v1.unauthorized(); - } - - const room = LivechatRooms.findOneOpenByRoomIdAndVisitorToken(this.urlParams.rid, visitorToken); - if (!room) { - return API.v1.unauthorized(); - } - - const [file, fields] = await getUploadFormData( - { - request: this.request, - }, - { field: 'file' }, - ); - - if (!fileUploadIsValidContentType(file.mimetype)) { - return API.v1.failure({ - reason: 'error-type-not-allowed', - }); - } - - // -1 maxFileSize means there is no limit - if (maxFileSize > -1 && file.fileBuffer.length > maxFileSize) { - return API.v1.failure({ - reason: 'error-size-not-allowed', - sizeAllowed: filesize(maxFileSize), - }); - } - - const fileStore = FileUpload.getStore('Uploads'); - - const details = { - name: file.filename, - size: file.fileBuffer.length, - type: file.mimetype, - rid: this.urlParams.rid, - visitorToken, - }; - - const uploadedFile = fileStore.insertSync(details, file.fileBuffer); - if (!uploadedFile) { - return API.v1.error('Invalid file'); - } - - uploadedFile.description = fields.description; - - delete fields.description; - return API.v1.success(Meteor.call('sendFileLivechatMessage', this.urlParams.rid, visitorToken, uploadedFile, fields)); - }, -}); diff --git a/apps/meteor/app/livechat/imports/server/rest/upload.ts b/apps/meteor/app/livechat/imports/server/rest/upload.ts new file mode 100644 index 0000000000000..3abac872ec1ff --- /dev/null +++ b/apps/meteor/app/livechat/imports/server/rest/upload.ts @@ -0,0 +1,77 @@ +import { Meteor } from 'meteor/meteor'; +import filesize from 'filesize'; +import { LivechatVisitors } from '@rocket.chat/models'; + +import { settings } from '../../../../settings/server'; +import { LivechatRooms } from '../../../../models/server'; +import { fileUploadIsValidContentType } from '../../../../utils/server'; +import { FileUpload } from '../../../../file-upload/server'; +import { API } from '../../../../api/server'; +import { getUploadFormData } from '../../../../api/server/lib/getUploadFormData'; + +API.v1.addRoute('livechat/upload/:rid', { + async post() { + if (!this.request.headers['x-visitor-token']) { + return API.v1.unauthorized(); + } + + const visitorToken = this.request.headers['x-visitor-token']; + const visitor = await LivechatVisitors.getVisitorByToken(visitorToken as string, {}); + + if (!visitor) { + return API.v1.unauthorized(); + } + + const room = LivechatRooms.findOneOpenByRoomIdAndVisitorToken(this.urlParams.rid, visitorToken); + if (!room) { + return API.v1.unauthorized(); + } + + const maxFileSize = settings.get('FileUpload_MaxFileSize') || 104857600; + + const file = await getUploadFormData( + { + request: this.request, + }, + { field: 'file', sizeLimit: maxFileSize }, + ); + + const { fields, fileBuffer, filename, mimetype } = file; + + if (!fileUploadIsValidContentType(mimetype)) { + return API.v1.failure({ + reason: 'error-type-not-allowed', + }); + } + + const buffLength = fileBuffer.length; + + // -1 maxFileSize means there is no limit + if (maxFileSize > -1 && buffLength > maxFileSize) { + return API.v1.failure({ + reason: 'error-size-not-allowed', + sizeAllowed: filesize(maxFileSize), + }); + } + + const fileStore = FileUpload.getStore('Uploads'); + + const details = { + name: filename, + size: buffLength, + type: mimetype, + rid: this.urlParams.rid, + visitorToken, + }; + + const uploadedFile = await fileStore.insert(details, fileBuffer); + if (!uploadedFile) { + return API.v1.failure('Invalid file'); + } + + uploadedFile.description = fields.description; + + delete fields.description; + return API.v1.success(Meteor.call('sendFileLivechatMessage', this.urlParams.rid, visitorToken, uploadedFile, fields)); + }, +}); diff --git a/apps/meteor/app/livechat/imports/server/rest/users.js b/apps/meteor/app/livechat/imports/server/rest/users.js deleted file mode 100644 index 8d1bdc9af13ff..0000000000000 --- a/apps/meteor/app/livechat/imports/server/rest/users.js +++ /dev/null @@ -1,156 +0,0 @@ -import { check } from 'meteor/check'; -import _ from 'underscore'; - -import { API } from '../../../../api/server'; -import { Users } from '../../../../models/server'; -import { Livechat } from '../../../server/lib/Livechat'; -import { findAgents, findManagers } from '../../../server/api/lib/users'; -import { hasAtLeastOnePermissionAsync } from '../../../../authorization/server/functions/hasPermission'; - -API.v1.addRoute( - 'livechat/users/:type', - { - authRequired: true, - permissionsRequired: { - GET: { - permissions: ['manage-livechat-agents'], - operation: 'hasAll', - }, - POST: { permissions: ['view-livechat-manager'], operation: 'hasAll' }, - }, - }, - { - async get() { - check(this.urlParams, { - type: String, - }); - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - const { text } = this.queryParams; - - if (this.urlParams.type === 'agent') { - if (!(await hasAtLeastOnePermissionAsync(this.userId, ['transfer-livechat-guest', 'edit-omnichannel-contact']))) { - return API.v1.unauthorized(); - } - - return API.v1.success( - await findAgents({ - text, - pagination: { - offset, - count, - sort, - }, - }), - ); - } - if (this.urlParams.type === 'manager') { - if (!(await hasAtLeastOnePermissionAsync(this.userId, ['view-livechat-manager']))) { - return API.v1.unauthorized(); - } - - return API.v1.success( - await findManagers({ - text, - pagination: { - offset, - count, - sort, - }, - }), - ); - } - throw new Error('Invalid type'); - }, - post() { - check(this.urlParams, { - type: String, - }); - - check(this.bodyParams, { - username: String, - }); - - if (this.urlParams.type === 'agent') { - const user = Livechat.addAgent(this.bodyParams.username); - if (user) { - return API.v1.success({ user }); - } - } else if (this.urlParams.type === 'manager') { - const user = Livechat.addManager(this.bodyParams.username); - if (user) { - return API.v1.success({ user }); - } - } else { - throw new Error('Invalid type'); - } - - return API.v1.failure(); - }, - }, -); - -API.v1.addRoute( - 'livechat/users/:type/:_id', - { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, - { - get() { - check(this.urlParams, { - type: String, - _id: String, - }); - - const user = Users.findOneById(this.urlParams._id); - - if (!user) { - return API.v1.failure('User not found'); - } - - let role; - - if (this.urlParams.type === 'agent') { - role = 'livechat-agent'; - } else if (this.urlParams.type === 'manager') { - role = 'livechat-manager'; - } else { - throw new Error('Invalid type'); - } - - if (user.roles.indexOf(role) !== -1) { - return API.v1.success({ - user: _.pick(user, '_id', 'username', 'name', 'status', 'statusLivechat', 'emails', 'livechat'), - }); - } - - return API.v1.success({ - user: null, - }); - }, - delete() { - check(this.urlParams, { - type: String, - _id: String, - }); - - const user = Users.findOneById(this.urlParams._id); - - if (!user) { - return API.v1.failure(); - } - - if (this.urlParams.type === 'agent') { - if (Livechat.removeAgent(user.username)) { - return API.v1.success(); - } - } else if (this.urlParams.type === 'manager') { - if (Livechat.removeManager(user.username)) { - return API.v1.success(); - } - } else { - throw new Error('Invalid type'); - } - - return API.v1.failure(); - }, - }, -); diff --git a/apps/meteor/app/livechat/imports/server/rest/users.ts b/apps/meteor/app/livechat/imports/server/rest/users.ts new file mode 100644 index 0000000000000..e2625ecc0a42e --- /dev/null +++ b/apps/meteor/app/livechat/imports/server/rest/users.ts @@ -0,0 +1,143 @@ +import { check } from 'meteor/check'; +import _ from 'underscore'; +import { isLivechatUsersManagerGETProps, isPOSTLivechatUsersTypeProps } from '@rocket.chat/rest-typings'; + +import { API } from '../../../../api/server'; +import { Users } from '../../../../models/server'; +import { Livechat } from '../../../server/lib/Livechat'; +import { findAgents, findManagers } from '../../../server/api/lib/users'; +import { hasAtLeastOnePermissionAsync } from '../../../../authorization/server/functions/hasPermission'; + +API.v1.addRoute( + 'livechat/users/:type', + { + authRequired: true, + permissionsRequired: { + GET: { + permissions: ['manage-livechat-agents'], + operation: 'hasAll', + }, + POST: { permissions: ['view-livechat-manager'], operation: 'hasAll' }, + }, + validateParams: { + GET: isLivechatUsersManagerGETProps, + POST: isPOSTLivechatUsersTypeProps, + }, + }, + { + async get() { + check(this.urlParams, { + type: String, + }); + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + const { text } = this.queryParams; + + if (this.urlParams.type === 'agent') { + if (!(await hasAtLeastOnePermissionAsync(this.userId, ['transfer-livechat-guest', 'edit-omnichannel-contact']))) { + return API.v1.unauthorized(); + } + + return API.v1.success( + await findAgents({ + text, + pagination: { + offset, + count, + sort, + }, + }), + ); + } + if (this.urlParams.type === 'manager') { + if (!(await hasAtLeastOnePermissionAsync(this.userId, ['view-livechat-manager']))) { + return API.v1.unauthorized(); + } + + return API.v1.success( + await findManagers({ + text, + pagination: { + offset, + count, + sort, + }, + }), + ); + } + throw new Error('Invalid type'); + }, + async post() { + if (this.urlParams.type === 'agent') { + const user = Livechat.addAgent(this.bodyParams.username); + if (user) { + return API.v1.success({ user }); + } + } else if (this.urlParams.type === 'manager') { + const user = Livechat.addManager(this.bodyParams.username); + if (user) { + return API.v1.success({ user }); + } + } else { + throw new Error('Invalid type'); + } + + return API.v1.failure(); + }, + }, +); + +API.v1.addRoute( + 'livechat/users/:type/:_id', + { authRequired: true, permissionsRequired: ['view-livechat-manager'] }, + { + async get() { + const user = Users.findOneById(this.urlParams._id); + + if (!user) { + return API.v1.failure('User not found'); + } + + let role; + + if (this.urlParams.type === 'agent') { + role = 'livechat-agent'; + } else if (this.urlParams.type === 'manager') { + role = 'livechat-manager'; + } else { + throw new Error('Invalid type'); + } + + if (user.roles.indexOf(role) !== -1) { + return API.v1.success({ + user: _.pick(user, '_id', 'username', 'name', 'status', 'statusLivechat', 'emails', 'livechat'), + }); + } + + return API.v1.success({ + user: null, + }); + }, + async delete() { + const user = Users.findOneById(this.urlParams._id); + + if (!user) { + return API.v1.failure(); + } + + if (this.urlParams.type === 'agent') { + if (Livechat.removeAgent(user.username)) { + return API.v1.success(); + } + } else if (this.urlParams.type === 'manager') { + if (Livechat.removeManager(user.username)) { + return API.v1.success(); + } + } else { + throw new Error('Invalid type'); + } + + return API.v1.failure(); + }, + }, +); diff --git a/apps/meteor/app/livechat/imports/server/rest/visitors.js b/apps/meteor/app/livechat/imports/server/rest/visitors.js deleted file mode 100644 index 1bb8fba375e69..0000000000000 --- a/apps/meteor/app/livechat/imports/server/rest/visitors.js +++ /dev/null @@ -1,160 +0,0 @@ -import { escapeRegExp } from '@rocket.chat/string-helpers'; -import { Match, check } from 'meteor/check'; - -import { API } from '../../../../api/server'; -import { - findVisitorInfo, - findVisitedPages, - findChatHistory, - searchChats, - findVisitorsToAutocomplete, - findVisitorsByEmailOrPhoneOrNameOrUsernameOrCustomField, -} from '../../../server/api/lib/visitors'; - -API.v1.addRoute( - 'livechat/visitors.info', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - async get() { - check(this.queryParams, { - visitorId: String, - }); - - const visitor = await findVisitorInfo({ visitorId: this.queryParams.visitorId }); - - return API.v1.success(visitor); - }, - }, -); - -API.v1.addRoute( - 'livechat/visitors.pagesVisited/:roomId', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - async get() { - check(this.urlParams, { - roomId: String, - }); - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - - const pages = await findVisitedPages({ - roomId: this.urlParams.roomId, - pagination: { - offset, - count, - sort, - }, - }); - return API.v1.success(pages); - }, - }, -); - -API.v1.addRoute( - 'livechat/visitors.chatHistory/room/:roomId/visitor/:visitorId', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - async get() { - check(this.urlParams, { - visitorId: String, - roomId: String, - }); - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - const history = await findChatHistory({ - userId: this.userId, - roomId: this.urlParams.roomId, - visitorId: this.urlParams.visitorId, - pagination: { - offset, - count, - sort, - }, - }); - - return API.v1.success(history); - }, - }, -); - -API.v1.addRoute( - 'livechat/visitors.searchChats/room/:roomId/visitor/:visitorId', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - async get() { - check(this.urlParams, { - visitorId: String, - roomId: String, - }); - const { roomId, visitorId } = this.urlParams; - const { searchText, closedChatsOnly, servedChatsOnly } = this.queryParams; - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - const history = await searchChats({ - userId: this.userId, - roomId, - visitorId, - searchText, - closedChatsOnly, - servedChatsOnly, - pagination: { - offset, - count, - sort, - }, - }); - return API.v1.success(history); - }, - }, -); - -API.v1.addRoute( - 'livechat/visitors.autocomplete', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - async get() { - const { selector } = this.queryParams; - if (!selector) { - return API.v1.failure("The 'selector' param is required"); - } - - return API.v1.success( - await findVisitorsToAutocomplete({ - userId: this.userId, - selector: JSON.parse(selector), - }), - ); - }, - }, -); - -API.v1.addRoute( - 'livechat/visitors.search', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - async get() { - const { term } = this.requestParams(); - - check(term, Match.Maybe(String)); - - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - - const nameOrUsername = new RegExp(escapeRegExp(term), 'i'); - - return API.v1.success( - await findVisitorsByEmailOrPhoneOrNameOrUsernameOrCustomField({ - userId: this.userId, - emailOrPhone: term, - nameOrUsername, - pagination: { - offset, - count, - sort, - }, - }), - ); - }, - }, -); diff --git a/apps/meteor/app/livechat/imports/server/rest/visitors.ts b/apps/meteor/app/livechat/imports/server/rest/visitors.ts index 134286d700c4c..9da160bd43367 100644 --- a/apps/meteor/app/livechat/imports/server/rest/visitors.ts +++ b/apps/meteor/app/livechat/imports/server/rest/visitors.ts @@ -1,22 +1,170 @@ -import { check } from 'meteor/check'; +import { escapeRegExp } from '@rocket.chat/string-helpers'; +import { + isLivechatVisitorsInfoProps, + isGETLivechatVisitorsPagesVisitedRoomIdParams, + isGETLivechatVisitorsChatHistoryRoomRoomIdVisitorVisitorIdParams, + isGETLivechatVisitorsSearchChatsRoomRoomIdVisitorVisitorIdParams, + isGETLivechatVisitorsAutocompleteParams, + isLivechatRidMessagesProps, + isGETLivechatVisitorsSearch, +} from '@rocket.chat/rest-typings'; import { Messages } from '@rocket.chat/models'; import { API } from '../../../../api/server'; +import { + findVisitorInfo, + findVisitedPages, + findChatHistory, + searchChats, + findVisitorsToAutocomplete, + findVisitorsByEmailOrPhoneOrNameOrUsernameOrCustomField, +} from '../../../server/api/lib/visitors'; import { LivechatRooms } from '../../../../models/server'; import { normalizeMessagesForUser } from '../../../../utils/server/lib/normalizeMessagesForUser'; import { canAccessRoom } from '../../../../authorization/server'; API.v1.addRoute( - 'livechat/:rid/messages', - { authRequired: true, permissionsRequired: ['view-l-room'] }, + 'livechat/visitors.info', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isLivechatVisitorsInfoProps }, + { + async get() { + const visitor = await findVisitorInfo({ visitorId: this.queryParams.visitorId }); + return API.v1.success(visitor); + }, + }, +); + +API.v1.addRoute( + 'livechat/visitors.pagesVisited/:roomId', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isGETLivechatVisitorsPagesVisitedRoomIdParams }, + { + async get() { + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + + const pages = await findVisitedPages({ + roomId: this.urlParams.roomId, + pagination: { + offset, + count, + sort, + }, + }); + return API.v1.success(pages); + }, + }, +); + +API.v1.addRoute( + 'livechat/visitors.chatHistory/room/:roomId/visitor/:visitorId', + { + authRequired: true, + permissionsRequired: ['view-l-room'], + validateParams: isGETLivechatVisitorsChatHistoryRoomRoomIdVisitorVisitorIdParams, + }, { async get() { - check(this.urlParams, { - rid: String, + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + const history = await findChatHistory({ + userId: this.userId, + roomId: this.urlParams.roomId, + visitorId: this.urlParams.visitorId, + pagination: { + offset, + count, + sort, + }, }); + return API.v1.success(history); + }, + }, +); + +API.v1.addRoute( + 'livechat/visitors.searchChats/room/:roomId/visitor/:visitorId', + { + authRequired: true, + permissionsRequired: ['view-l-room'], + validateParams: isGETLivechatVisitorsSearchChatsRoomRoomIdVisitorVisitorIdParams, + }, + { + async get() { + const { roomId, visitorId } = this.urlParams; + const { searchText, closedChatsOnly, servedChatsOnly, source } = this.queryParams; + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + const history = await searchChats({ + userId: this.userId, + roomId, + visitorId, + searchText, + closedChatsOnly, + servedChatsOnly, + source, + pagination: { + offset, + count, + sort, + }, + }); + return API.v1.success(history); + }, + }, +); + +API.v1.addRoute( + 'livechat/visitors.autocomplete', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isGETLivechatVisitorsAutocompleteParams }, + { + async get() { + const { selector } = this.queryParams; + + return API.v1.success( + await findVisitorsToAutocomplete({ + selector: JSON.parse(selector), + }), + ); + }, + }, +); + +API.v1.addRoute( + 'livechat/visitors.search', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isGETLivechatVisitorsSearch }, + { + async get() { + const { term } = this.requestParams(); + + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + + const nameOrUsername = term ? new RegExp(escapeRegExp(term), 'i') : undefined; + + return API.v1.success( + await findVisitorsByEmailOrPhoneOrNameOrUsernameOrCustomField({ + emailOrPhone: term, + nameOrUsername, + pagination: { + offset, + count, + sort, + }, + }), + ); + }, + }, +); + +API.v1.addRoute( + 'livechat/:rid/messages', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isLivechatRidMessagesProps }, + { + async get() { const { offset, count } = this.getPaginationItems(); const { sort } = this.parseJsonQuery(); + const { searchTerm } = this.requestParams(); const room = LivechatRooms.findOneById(this.urlParams.rid); @@ -28,7 +176,7 @@ API.v1.addRoute( throw new Error('not-allowed'); } - const { cursor, totalCount } = Messages.findLivechatClosedMessages(this.urlParams.rid, { + const { cursor, totalCount } = Messages.findLivechatClosedMessages(this.urlParams.rid, searchTerm, { sort: sort || { ts: -1 }, skip: offset, limit: count, diff --git a/apps/meteor/app/livechat/lib/inquiries.ts b/apps/meteor/app/livechat/lib/inquiries.ts new file mode 100644 index 0000000000000..dddf32ee5467e --- /dev/null +++ b/apps/meteor/app/livechat/lib/inquiries.ts @@ -0,0 +1,30 @@ +import { OmnichannelSortingMechanismSettingType } from '@rocket.chat/core-typings'; + +type SortOrder = 1 | -1; + +type ReturnType = + | { + priorityWeight: SortOrder; + ts: SortOrder; + } + | { + estimatedWaitingTimeQueue: SortOrder; + ts: SortOrder; + } + | { + ts: SortOrder; + }; + +export const getOmniChatSortQuery = ( + sortByMechanism: OmnichannelSortingMechanismSettingType = OmnichannelSortingMechanismSettingType.Timestamp, +): ReturnType => { + switch (sortByMechanism) { + case OmnichannelSortingMechanismSettingType.Priority: + return { priorityWeight: 1, ts: 1 }; + case OmnichannelSortingMechanismSettingType.SLAs: + return { estimatedWaitingTimeQueue: 1, ts: 1 }; + case OmnichannelSortingMechanismSettingType.Timestamp: + default: + return { ts: 1 }; + } +}; diff --git a/apps/meteor/app/livechat/lib/messageTypes.ts b/apps/meteor/app/livechat/lib/messageTypes.ts index 1ee3397af6e06..c30916d4b4c9b 100644 --- a/apps/meteor/app/livechat/lib/messageTypes.ts +++ b/apps/meteor/app/livechat/lib/messageTypes.ts @@ -48,8 +48,20 @@ MessageTypes.registerType({ ...(comment && { comment }), }), queue: (): string => - TAPi18n.__('Livechat_transfer_return_to_the_queue', { + TAPi18n.__(`Livechat_transfer_return_to_the_queue${commentLabel}`, { from, + ...(comment && { comment }), + }), + autoTransferUnansweredChatsToAgent: (): string => + TAPi18n.__(`Livechat_transfer_to_agent_auto_transfer_unanswered_chat`, { + from, + to: message?.transferData?.transferredTo?.name || message?.transferData?.transferredTo?.username || '', + duration: comment, + }), + autoTransferUnansweredChatsToQueue: (): string => + TAPi18n.__(`Livechat_transfer_return_to_the_queue_auto_transfer_unanswered_chat`, { + from, + duration: comment, }), }; return { @@ -108,7 +120,7 @@ MessageTypes.registerType({ } return escapeHTML(message.msg); }, - message: 'room_changed_privacy', + message: 'room_changed_type', }); MessageTypes.registerType({ diff --git a/apps/meteor/app/livechat/server/agentStatus.js b/apps/meteor/app/livechat/server/agentStatus.js deleted file mode 100644 index a15d67f90eb71..0000000000000 --- a/apps/meteor/app/livechat/server/agentStatus.js +++ /dev/null @@ -1,10 +0,0 @@ -import { UserPresenceMonitor } from 'meteor/konecty:user-presence'; - -import { Livechat } from './lib/Livechat'; -import { hasAnyRole } from '../../authorization/server/functions/hasRole'; - -UserPresenceMonitor.onSetUserStatus((user, status) => { - if (hasAnyRole(user._id, ['livechat-manager', 'livechat-monitor', 'livechat-agent'])) { - Livechat.notifyAgentStatusChanged(user._id, status); - } -}); diff --git a/apps/meteor/app/livechat/server/api.js b/apps/meteor/app/livechat/server/api.js deleted file mode 100644 index 173e1dfafb538..0000000000000 --- a/apps/meteor/app/livechat/server/api.js +++ /dev/null @@ -1,17 +0,0 @@ -import '../imports/server/rest/agent.js'; -import '../imports/server/rest/departments'; -import '../imports/server/rest/facebook.js'; -import '../imports/server/rest/sms.js'; -import '../imports/server/rest/users.js'; -import '../imports/server/rest/upload.js'; -import '../imports/server/rest/inquiries.js'; -import '../imports/server/rest/rooms.js'; -import '../imports/server/rest/appearance.js'; -import '../imports/server/rest/filters.js'; -import '../imports/server/rest/triggers.js'; -import '../imports/server/rest/integrations.js'; -import '../imports/server/rest/visitors.js'; -import '../imports/server/rest/visitors.ts'; -import '../imports/server/rest/dashboards.js'; -import '../imports/server/rest/queue.js'; -import '../imports/server/rest/businessHours.js'; diff --git a/apps/meteor/app/livechat/server/api.ts b/apps/meteor/app/livechat/server/api.ts new file mode 100644 index 0000000000000..77a888606abb8 --- /dev/null +++ b/apps/meteor/app/livechat/server/api.ts @@ -0,0 +1,15 @@ +import '../imports/server/rest/agent'; +import '../imports/server/rest/departments'; +import '../imports/server/rest/sms.js'; +import '../imports/server/rest/users'; +import '../imports/server/rest/upload'; +import '../imports/server/rest/inquiries'; +import '../imports/server/rest/rooms'; +import '../imports/server/rest/appearance'; +import '../imports/server/rest/filters.js'; +import '../imports/server/rest/triggers'; +import '../imports/server/rest/integrations'; +import '../imports/server/rest/visitors'; +import '../imports/server/rest/dashboards'; +import '../imports/server/rest/queue'; +import '../imports/server/rest/businessHours'; diff --git a/apps/meteor/app/livechat/server/api/lib/agents.js b/apps/meteor/app/livechat/server/api/lib/agents.js deleted file mode 100644 index f2640bc797b7e..0000000000000 --- a/apps/meteor/app/livechat/server/api/lib/agents.js +++ /dev/null @@ -1,13 +0,0 @@ -import { LivechatDepartmentAgents } from '@rocket.chat/models'; - -export async function findAgentDepartments({ enabledDepartmentsOnly, agentId }) { - if (enabledDepartmentsOnly) { - return { - departments: await LivechatDepartmentAgents.findActiveDepartmentsByAgentId(agentId).toArray(), - }; - } - - return { - departments: await LivechatDepartmentAgents.find({ agentId }).toArray(), - }; -} diff --git a/apps/meteor/app/livechat/server/api/lib/agents.ts b/apps/meteor/app/livechat/server/api/lib/agents.ts new file mode 100644 index 0000000000000..3bc5180c2f597 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/lib/agents.ts @@ -0,0 +1,20 @@ +import type { ILivechatDepartmentAgents } from '@rocket.chat/core-typings'; +import { LivechatDepartmentAgents } from '@rocket.chat/models'; + +export async function findAgentDepartments({ + enabledDepartmentsOnly, + agentId, +}: { + enabledDepartmentsOnly?: boolean; + agentId: string; +}): Promise<{ departments: ILivechatDepartmentAgents[] }> { + if (enabledDepartmentsOnly) { + return { + departments: await LivechatDepartmentAgents.findActiveDepartmentsByAgentId(agentId).toArray(), + }; + } + + return { + departments: await LivechatDepartmentAgents.find({ agentId }).toArray(), + }; +} diff --git a/apps/meteor/app/livechat/server/api/lib/appearance.js b/apps/meteor/app/livechat/server/api/lib/appearance.js deleted file mode 100644 index e7ad911d43902..0000000000000 --- a/apps/meteor/app/livechat/server/api/lib/appearance.js +++ /dev/null @@ -1,34 +0,0 @@ -import { Settings } from '@rocket.chat/models'; - -export async function findAppearance() { - const query = { - _id: { - $in: [ - 'Livechat_title', - 'Livechat_title_color', - 'Livechat_enable_message_character_limit', - 'Livechat_message_character_limit', - 'Livechat_show_agent_info', - 'Livechat_show_agent_email', - 'Livechat_display_offline_form', - 'Livechat_offline_form_unavailable', - 'Livechat_offline_message', - 'Livechat_offline_success_message', - 'Livechat_offline_title', - 'Livechat_offline_title_color', - 'Livechat_offline_email', - 'Livechat_conversation_finished_message', - 'Livechat_registration_form', - 'Livechat_name_field_registration_form', - 'Livechat_email_field_registration_form', - 'Livechat_registration_form_message', - 'Livechat_conversation_finished_text', - 'Livechat_escalated_conversation_finished_text', - ], - }, - }; - - return { - appearance: await Settings.find(query).toArray(), - }; -} diff --git a/apps/meteor/app/livechat/server/api/lib/appearance.ts b/apps/meteor/app/livechat/server/api/lib/appearance.ts new file mode 100644 index 0000000000000..1a7c4258a393a --- /dev/null +++ b/apps/meteor/app/livechat/server/api/lib/appearance.ts @@ -0,0 +1,35 @@ +import type { ISetting } from '@rocket.chat/core-typings'; +import { Settings } from '@rocket.chat/models'; + +export async function findAppearance(): Promise<{ appearance: ISetting[] }> { + const query = { + _id: { + $in: [ + 'Livechat_title', + 'Livechat_title_color', + 'Livechat_enable_message_character_limit', + 'Livechat_message_character_limit', + 'Livechat_show_agent_info', + 'Livechat_show_agent_email', + 'Livechat_display_offline_form', + 'Livechat_offline_form_unavailable', + 'Livechat_offline_message', + 'Livechat_offline_success_message', + 'Livechat_offline_title', + 'Livechat_offline_title_color', + 'Livechat_offline_email', + 'Livechat_conversation_finished_message', + 'Livechat_registration_form', + 'Livechat_name_field_registration_form', + 'Livechat_email_field_registration_form', + 'Livechat_registration_form_message', + 'Livechat_conversation_finished_text', + 'Livechat_escalated_conversation_finished_text', + ], + }, + }; + + return { + appearance: await Settings.find(query).toArray(), + }; +} diff --git a/apps/meteor/app/livechat/server/api/lib/customFields.js b/apps/meteor/app/livechat/server/api/lib/customFields.js deleted file mode 100644 index 35fc27d4d8bce..0000000000000 --- a/apps/meteor/app/livechat/server/api/lib/customFields.js +++ /dev/null @@ -1,31 +0,0 @@ -import { escapeRegExp } from '@rocket.chat/string-helpers'; -import { LivechatCustomField } from '@rocket.chat/models'; - -export async function findLivechatCustomFields({ text, pagination: { offset, count, sort } }) { - const query = { - ...(text && { - $or: [{ label: new RegExp(escapeRegExp(text), 'i') }, { _id: new RegExp(escapeRegExp(text), 'i') }], - }), - }; - - const { cursor, totalCount } = LivechatCustomField.findPaginated(query, { - sort: sort || { label: 1 }, - skip: offset, - limit: count, - }); - - const [customFields, total] = await Promise.all([cursor.toArray(), totalCount]); - - return { - customFields, - count: customFields.length, - offset, - total, - }; -} - -export async function findCustomFieldById({ customFieldId }) { - return { - customField: await LivechatCustomField.findOneById(customFieldId), - }; -} diff --git a/apps/meteor/app/livechat/server/api/lib/customFields.ts b/apps/meteor/app/livechat/server/api/lib/customFields.ts new file mode 100644 index 0000000000000..e614b6dc1b789 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/lib/customFields.ts @@ -0,0 +1,43 @@ +import { escapeRegExp } from '@rocket.chat/string-helpers'; +import { LivechatCustomField } from '@rocket.chat/models'; +import type { PaginatedResult } from '@rocket.chat/rest-typings'; +import type { ILivechatCustomField } from '@rocket.chat/core-typings'; + +export async function findLivechatCustomFields({ + text, + pagination: { offset, count, sort }, +}: { + text?: string; + pagination: { offset: number; count: number; sort: Record }; +}): Promise }>> { + const query = { + ...(text && { + $or: [{ label: new RegExp(escapeRegExp(text), 'i') }, { _id: new RegExp(escapeRegExp(text), 'i') }], + }), + }; + + const { cursor, totalCount } = LivechatCustomField.findPaginated(query, { + sort: sort || { label: 1 }, + skip: offset, + limit: count, + }); + + const [customFields, total] = await Promise.all([cursor.toArray(), totalCount]); + + return { + customFields, + count: customFields.length, + offset, + total, + }; +} + +export async function findCustomFieldById({ + customFieldId, +}: { + customFieldId: string; +}): Promise<{ customField: ILivechatCustomField | null }> { + return { + customField: await LivechatCustomField.findOneById(customFieldId), + }; +} diff --git a/apps/meteor/app/livechat/server/api/lib/departments.ts b/apps/meteor/app/livechat/server/api/lib/departments.ts index f4d43735915f9..9f8b1240ccf13 100644 --- a/apps/meteor/app/livechat/server/api/lib/departments.ts +++ b/apps/meteor/app/livechat/server/api/lib/departments.ts @@ -14,6 +14,7 @@ type FindDepartmentParams = { text?: string; enabled?: boolean; excludeDepartmentId?: string; + showArchived?: boolean; } & Pagination; type FindDepartmentByIdParams = { userId: string; @@ -29,6 +30,7 @@ type FindDepartmentToAutocompleteParams = { term: string; }; onlyMyDepartments?: boolean; + showArchived?: boolean; }; type FindDepartmentAgentsParams = { userId: string; @@ -41,10 +43,12 @@ export async function findDepartments({ text, enabled, excludeDepartmentId, + showArchived = false, pagination: { offset, count, sort }, }: FindDepartmentParams): Promise> { let query = { $or: [{ type: { $eq: 'd' } }, { type: { $exists: false } }], + ...(!showArchived && { archived: { $ne: !showArchived } }), ...(enabled && { enabled: Boolean(enabled) }), ...(text && { name: new RegExp(escapeRegExp(text), 'i') }), ...(excludeDepartmentId && { _id: { $ne: excludeDepartmentId } }), @@ -70,6 +74,40 @@ export async function findDepartments({ }; } +export async function findArchivedDepartments({ + userId, + onlyMyDepartments = false, + text, + excludeDepartmentId, + pagination: { offset, count, sort }, +}: FindDepartmentParams): Promise> { + let query = { + $or: [{ type: { $eq: 'd' } }, { type: { $exists: false } }], + archived: { $eq: true }, + ...(text && { name: new RegExp(escapeRegExp(text), 'i') }), + ...(excludeDepartmentId && { _id: { $ne: excludeDepartmentId } }), + }; + + if (onlyMyDepartments) { + query = callbacks.run('livechat.applyDepartmentRestrictions', query, { userId }); + } + + const { cursor, totalCount } = LivechatDepartment.findPaginated(query, { + sort: sort || { name: 1 }, + skip: offset, + limit: count, + }); + + const [departments, total] = await Promise.all([cursor.toArray(), totalCount]); + + return { + departments, + count: departments.length, + offset, + total, + }; +} + export async function findDepartmentById({ userId, departmentId, @@ -102,6 +140,7 @@ export async function findDepartmentsToAutocomplete({ uid, selector, onlyMyDepartments = false, + showArchived = false, }: FindDepartmentToAutocompleteParams): Promise<{ items: ILivechatDepartmentRecord[] }> { const { exceptions = [] } = selector; let { conditions = {} } = selector; @@ -110,7 +149,9 @@ export async function findDepartmentsToAutocomplete({ conditions = callbacks.run('livechat.applyDepartmentRestrictions', conditions, { userId: uid }); } - const items = await LivechatDepartment.findByNameRegexWithExceptionsAndConditions(selector.term, exceptions, conditions, { + const conditionsWithArchived = { archived: { $ne: !showArchived }, ...conditions }; + + const items = await LivechatDepartment.findByNameRegexWithExceptionsAndConditions(selector.term, exceptions, conditionsWithArchived, { projection: { _id: 1, name: 1, diff --git a/apps/meteor/app/livechat/server/api/lib/inquiries.js b/apps/meteor/app/livechat/server/api/lib/inquiries.js deleted file mode 100644 index 052247cc807c7..0000000000000 --- a/apps/meteor/app/livechat/server/api/lib/inquiries.js +++ /dev/null @@ -1,62 +0,0 @@ -import { LivechatDepartmentAgents, LivechatDepartment, LivechatInquiry } from '@rocket.chat/models'; - -const agentDepartments = async (userId) => { - const agentDepartments = (await LivechatDepartmentAgents.findByAgentId(userId).toArray()).map(({ departmentId }) => departmentId); - return (await LivechatDepartment.find({ _id: { $in: agentDepartments }, enabled: true }).toArray()).map(({ _id }) => _id); -}; - -const applyDepartmentRestrictions = async (userId, filterDepartment) => { - const allowedDepartments = await agentDepartments(userId); - if (allowedDepartments && Array.isArray(allowedDepartments) && allowedDepartments.length > 0) { - if (!filterDepartment) { - return { $in: allowedDepartments }; - } - - if (!allowedDepartments.includes(filterDepartment)) { - throw new Error('error-not-authorized'); - } - - return filterDepartment; - } - - return { $exists: false }; -}; - -export async function findInquiries({ userId, department: filterDepartment, status, pagination: { offset, count, sort } }) { - const department = await applyDepartmentRestrictions(userId, filterDepartment); - - const options = { - limit: count, - sort: sort || { ts: -1 }, - skip: offset, - }; - - const filter = { - ...(status && { status }), - $or: [ - { - $and: [{ defaultAgent: { $exists: true } }, { 'defaultAgent.agentId': userId }], - }, - { ...(department && { department }) }, - // Add _always_ the "public queue" to returned list of inquiries, even if agent already has departments - { department: { $exists: false } }, - ], - }; - - const { cursor, totalCount } = LivechatInquiry.findPaginated(filter, options); - - const [inquiries, total] = await Promise.all([cursor.toArray(), totalCount]); - - return { - inquiries, - count: inquiries.length, - offset, - total, - }; -} - -export async function findOneInquiryByRoomId({ roomId }) { - return { - inquiry: await LivechatInquiry.findOneByRoomId(roomId), - }; -} diff --git a/apps/meteor/app/livechat/server/api/lib/inquiries.ts b/apps/meteor/app/livechat/server/api/lib/inquiries.ts new file mode 100644 index 0000000000000..527f5fb470f33 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/lib/inquiries.ts @@ -0,0 +1,81 @@ +import { LivechatInquiryStatus } from '@rocket.chat/core-typings'; +import type { ILivechatInquiryRecord, IRoom, IUser } from '@rocket.chat/core-typings'; +import { LivechatDepartmentAgents, LivechatDepartment, LivechatInquiry } from '@rocket.chat/models'; +import type { PaginatedResult } from '@rocket.chat/rest-typings'; +import type { Filter } from 'mongodb'; + +import { getOmniChatSortQuery } from '../../../lib/inquiries'; +import { getInquirySortMechanismSetting } from '../../lib/settings'; + +const agentDepartments = async (userId: IUser['_id']): Promise => { + const agentDepartments = (await LivechatDepartmentAgents.findByAgentId(userId).toArray()).map(({ departmentId }) => departmentId); + return (await LivechatDepartment.find({ _id: { $in: agentDepartments }, enabled: true }).toArray()).map(({ _id }) => _id); +}; + +const applyDepartmentRestrictions = async ( + userId: IUser['_id'], + filterDepartment?: string, +): Promise<{ $in: string[] } | { $exists: false } | string> => { + const allowedDepartments = await agentDepartments(userId); + if (allowedDepartments && Array.isArray(allowedDepartments) && allowedDepartments.length > 0) { + if (!filterDepartment) { + return { $in: allowedDepartments }; + } + + if (!allowedDepartments.includes(filterDepartment)) { + throw new Error('error-not-authorized'); + } + return filterDepartment; + } + + return { $exists: false }; +}; + +export async function findInquiries({ + userId, + department: filterDepartment, + status, + pagination: { offset, count, sort }, +}: { + userId: IUser['_id']; + department?: string; + status?: LivechatInquiryStatus; + pagination: { offset: number; count: number; sort: Record }; +}): Promise }>> { + const department = await applyDepartmentRestrictions(userId, filterDepartment); + const defaultSort = getOmniChatSortQuery(getInquirySortMechanismSetting()); + const options = { + limit: count, + skip: offset, + sort: { ...sort, ...defaultSort }, + }; + + const filter: Filter = { + ...(status && status in LivechatInquiryStatus && { status }), + $or: [ + { + $and: [{ defaultAgent: { $exists: true } }, { 'defaultAgent.agentId': userId }], + }, + { ...(department && { department }) }, + // Add _always_ the "public queue" to returned list of inquiries, even if agent already has departments + { department: { $exists: false } }, + ], + }; + + const { cursor, totalCount } = LivechatInquiry.findPaginated(filter, options); + + const [inquiries, total] = await Promise.all([cursor.toArray(), totalCount]); + + return { + inquiries, + count: inquiries.length, + offset, + total, + }; +} + +export async function findOneInquiryByRoomId({ roomId }: { roomId: IRoom['_id'] }): Promise<{ inquiry: ILivechatInquiryRecord | null }> { + return { + inquiry: await LivechatInquiry.findOneByRoomId(roomId, {}), + }; +} diff --git a/apps/meteor/app/livechat/server/api/lib/integrations.js b/apps/meteor/app/livechat/server/api/lib/integrations.js deleted file mode 100644 index a755f0f6ecc10..0000000000000 --- a/apps/meteor/app/livechat/server/api/lib/integrations.js +++ /dev/null @@ -1,18 +0,0 @@ -import { Settings } from '@rocket.chat/models'; - -export async function findIntegrationSettings() { - const settings = await Settings.findByIds([ - 'Livechat_webhookUrl', - 'Livechat_secret_token', - 'Livechat_webhook_on_start', - 'Livechat_webhook_on_close', - 'Livechat_webhook_on_chat_taken', - 'Livechat_webhook_on_chat_queued', - 'Livechat_webhook_on_forward', - 'Livechat_webhook_on_offline_msg', - 'Livechat_webhook_on_visitor_message', - 'Livechat_webhook_on_agent_message', - ]).toArray(); - - return { settings }; -} diff --git a/apps/meteor/app/livechat/server/api/lib/integrations.ts b/apps/meteor/app/livechat/server/api/lib/integrations.ts new file mode 100644 index 0000000000000..75446af07ec54 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/lib/integrations.ts @@ -0,0 +1,19 @@ +import type { ISetting } from '@rocket.chat/core-typings'; +import { Settings } from '@rocket.chat/models'; + +export async function findIntegrationSettings(): Promise<{ settings: ISetting[] }> { + const settings = await Settings.findByIds([ + 'Livechat_webhookUrl', + 'Livechat_secret_token', + 'Livechat_webhook_on_start', + 'Livechat_webhook_on_close', + 'Livechat_webhook_on_chat_taken', + 'Livechat_webhook_on_chat_queued', + 'Livechat_webhook_on_forward', + 'Livechat_webhook_on_offline_msg', + 'Livechat_webhook_on_visitor_message', + 'Livechat_webhook_on_agent_message', + ]).toArray(); + + return { settings }; +} diff --git a/apps/meteor/app/livechat/server/api/lib/livechat.js b/apps/meteor/app/livechat/server/api/lib/livechat.js deleted file mode 100644 index 15791ff04eb14..0000000000000 --- a/apps/meteor/app/livechat/server/api/lib/livechat.js +++ /dev/null @@ -1,267 +0,0 @@ -import URL from 'url'; - -import { Meteor } from 'meteor/meteor'; -import { Random } from 'meteor/random'; -import _ from 'underscore'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { EmojiCustom, LivechatTrigger, LivechatVisitors, LivechatFilter } from '@rocket.chat/models'; - -import { LivechatRooms, LivechatDepartment } from '../../../../models/server'; -import { Livechat } from '../../lib/Livechat'; -import { callbacks } from '../../../../../lib/callbacks'; -import { normalizeAgent } from '../../lib/Helper'; -import { Apps, AppEvents } from '../../../../apps/server'; - -export function online(department, skipSettingCheck = false, skipFallbackCheck = false) { - return Livechat.online(department, skipSettingCheck, skipFallbackCheck); -} - -async function findTriggers() { - const triggers = await LivechatTrigger.findEnabled().toArray(); - return triggers.map(({ _id, actions, conditions, runOnce }) => ({ - _id, - actions, - conditions, - runOnce, - })); -} - -export function findDepartments(businessUnit) { - return LivechatDepartment.findEnabledWithAgentsAndBusinessUnit(businessUnit, { - _id: 1, - name: 1, - showOnRegistration: 1, - showOnOfflineForm: 1, - }) - .fetch() - .map(({ _id, name, showOnRegistration, showOnOfflineForm }) => ({ - _id, - name, - showOnRegistration, - showOnOfflineForm, - })); -} - -async function findFilters() { - const filters = await LivechatFilter.findEnabled().toArray(); - return filters.map((filter) => _.pick(filter, '_id', 'regex', 'slug')); -} - -export function findGuest(token) { - return LivechatVisitors.getVisitorByToken(token, { - projection: { - name: 1, - username: 1, - token: 1, - visitorEmails: 1, - department: 1, - }, - }); -} - -export function findRoom(token, rid) { - const fields = { - t: 1, - departmentId: 1, - servedBy: 1, - open: 1, - v: 1, - ts: 1, - }; - - if (!rid) { - return LivechatRooms.findOneByVisitorToken(token, fields); - } - - return LivechatRooms.findOneByIdAndVisitorToken(rid, token, fields); -} - -export function findOpenRoom(token, departmentId) { - const options = { - fields: { - departmentId: 1, - servedBy: 1, - open: 1, - callStatus: 1, - }, - }; - - let room; - const rooms = departmentId - ? LivechatRooms.findOpenByVisitorTokenAndDepartmentId(token, departmentId, options).fetch() - : LivechatRooms.findOpenByVisitorToken(token, options).fetch(); - if (rooms && rooms.length > 0) { - room = rooms[0]; - } - - if (room) { - Livechat.addTypingListener(room._id, (username, typing, data) => { - Apps.triggerEvent(AppEvents.IRoomUserTyping, { roomId: room._id, username, typing, data }); - }); - } - return room; -} - -export function getRoom({ guest, rid, roomInfo, agent, extraParams }) { - const token = guest && guest.token; - - const message = { - _id: Random.id(), - rid, - msg: '', - token, - ts: new Date(), - }; - - Livechat.addTypingListener(rid, (username, typing, data) => { - Apps.triggerEvent(AppEvents.IRoomUserTyping, { roomId: rid, username, typing, data }); - }); - - return Livechat.getRoom(guest, message, roomInfo, agent, extraParams); -} - -export function findAgent(agentId) { - return normalizeAgent(agentId); -} - -export function normalizeHttpHeaderData(headers = {}) { - const httpHeaders = Object.assign({}, headers); - return { httpHeaders }; -} -export async function settings({ businessUnit = '', url } = {}) { - const initSettings = Livechat.getInitSettings(); - const triggers = await findTriggers(); - const filters = await findFilters(); - const departments = findDepartments(businessUnit); - const sound = `${Meteor.absoluteUrl()}sounds/chime.mp3`; - const emojis = await EmojiCustom.find().toArray(); - - const shouldShowRegistrationForm = () => { - if (!url) { - return initSettings.Livechat_registration_form; - } - - let skipOnDomainList = initSettings.Livechat_skip_registration_form_DomainsList; - skipOnDomainList = - (!_.isEmpty(skipOnDomainList.trim()) && - _.map(skipOnDomainList.split(','), function (domain) { - return domain.trim(); - })) || - []; - - const urlObject = URL.parse(url); - const { hostname: urlHost, pathname: urlPath } = urlObject; - - const matchedDomain = skipOnDomainList.find((domain) => { - if (!domain.match(/^[a-zA-Z]+:\/\//)) { - domain = `http://${domain}`; - } - const domainUrlObject = URL.parse(domain); - const { hostname: domainHost, pathname: domainPath } = domainUrlObject; - - if (domainPath !== '/') { - return domainHost.includes(urlHost) && domainPath === urlPath; - } - return domainHost.includes(urlHost); - }); - - return initSettings.Livechat_registration_form && !matchedDomain; - }; - - return { - enabled: initSettings.Livechat_enabled, - settings: { - registrationForm: shouldShowRegistrationForm(), - startSessionOnNewChat: initSettings.Livechat_start_session_on_new_chat, - allowSwitchingDepartments: initSettings.Livechat_allow_switching_departments, - nameFieldRegistrationForm: initSettings.Livechat_name_field_registration_form, - emailFieldRegistrationForm: initSettings.Livechat_email_field_registration_form, - guestDefaultAvatar: initSettings.Assets_livechat_guest_default_avatar, - displayOfflineForm: initSettings.Livechat_display_offline_form, - videoCall: initSettings.Omnichannel_call_provider === 'Jitsi', - fileUpload: initSettings.Livechat_fileupload_enabled && initSettings.FileUpload_Enabled, - language: initSettings.Language, - transcript: initSettings.Livechat_enable_transcript, - printTranscript: initSettings.Livechat_enable_print_transcript, - enableTranscriptMobile: initSettings.Livechat_enable_transcript_mobile, - historyMonitorType: initSettings.Livechat_history_monitor_type, - forceAcceptDataProcessingConsent: initSettings.Livechat_force_accept_data_processing_consent, - showConnecting: initSettings.Livechat_Show_Connecting, - agentHiddenInfo: initSettings.Livechat_show_agent_info === false, - clearLocalStorageWhenChatEnded: initSettings.Livechat_clear_local_storage_when_chat_ended, - limitTextLength: - initSettings.Livechat_enable_message_character_limit && - (initSettings.Livechat_message_character_limit || initSettings.Message_MaxAllowedSize), - hideSysMessages: initSettings.Livechat_hide_sys_messages, - isPostChatFeedbackEnabled: initSettings.Livechat_enable_post_chat_feedback, - - livechat_kill_switch: initSettings.Livechat_kill_switch, - livechat_kill_switch_message: initSettings.Livechat_kill_switch_message, - livechat_friendly_chat: initSettings.Livechat_friendly_chat, - livechat_enable_avatar: initSettings.Livechat_enable_avatar, - livechat_enable_elastic_search_logs: initSettings.Livechat_enable_elastic_search_logs, - livechat_elastic_search_url: initSettings.Livechat_elastic_search_url, - livechat_elastic_search_index: initSettings.Livechat_elastic_search_index, - livechat_elastic_search_access_key: initSettings.Livechat_elastic_search_access_key, - livechat_elastic_search_access_key_secret: initSettings.Livechat_elastic_search_access_key_secret, - livechat_chat_already_closed_message: initSettings.Livechat_chat_already_closed_message, - livechat_close_modal_message: initSettings.Livechat_close_modal_message, - }, - theme: { - title: initSettings.Livechat_title, - color: initSettings.Livechat_title_color, - offlineTitle: initSettings.Livechat_offline_title, - offlineColor: initSettings.Livechat_offline_title_color, - actionLinks: { - webrtc: [ - { - actionLinksAlignment: 'flex-start', - i18nLabel: 'Join_call', - label: TAPi18n.__('Join_call'), - method_id: 'joinLivechatWebRTCCall', - }, - { - i18nLabel: 'End_call', - label: TAPi18n.__('End_call'), - method_id: 'endLivechatWebRTCCall', - danger: true, - }, - ], - jitsi: [ - { icon: 'icon-videocam', i18nLabel: 'Accept' }, - { icon: 'icon-cancel', i18nLabel: 'Decline' }, - ], - }, - }, - messages: { - offlineMessage: initSettings.Livechat_offline_message, - offlineSuccessMessage: initSettings.Livechat_offline_success_message, - offlineUnavailableMessage: initSettings.Livechat_offline_form_unavailable, - conversationFinishedMessage: initSettings.Livechat_conversation_finished_message, - conversationFinishedText: initSettings.Livechat_conversation_finished_text, - transcriptMessage: initSettings.Livechat_transcript_message, - registrationFormMessage: initSettings.Livechat_registration_form_message, - dataProcessingConsentText: initSettings.Livechat_data_processing_consent_text, - escalatedConversationFinishedText: initSettings.Livechat_escalated_conversation_finished_text, - }, - survey: { - items: ['satisfaction', 'agentKnowledge', 'agentResposiveness', 'agentFriendliness'], - values: ['1', '2', '3', '4', '5'], - }, - triggers, - filters, - departments, - resources: { - sound, - emojis, - }, - }; -} - -export async function getExtraConfigInfo(room) { - return callbacks.run('livechat.onLoadConfigApi', { room }); -} - -export function onCheckRoomParams(params) { - return callbacks.run('livechat.onCheckRoomApiParams', params); -} diff --git a/apps/meteor/app/livechat/server/api/lib/livechat.ts b/apps/meteor/app/livechat/server/api/lib/livechat.ts new file mode 100644 index 0000000000000..66058f9e4284c --- /dev/null +++ b/apps/meteor/app/livechat/server/api/lib/livechat.ts @@ -0,0 +1,262 @@ +import URL from 'url'; + +import { Meteor } from 'meteor/meteor'; +import { Random } from 'meteor/random'; +import _ from 'underscore'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import { EmojiCustom, LivechatTrigger, LivechatVisitors, LivechatFilter } from '@rocket.chat/models'; +import type { + ILivechatAgent, + ILivechatDepartment, + ILivechatTrigger, + ILivechatVisitor, + IOmnichannelRoom, + OmnichannelSourceType, +} from '@rocket.chat/core-typings'; + +import { LivechatRooms, LivechatDepartment } from '../../../../models/server'; +import { Livechat } from '../../lib/Livechat'; +import { callbacks } from '../../../../../lib/callbacks'; +import { normalizeAgent } from '../../lib/Helper'; +import { Apps, AppEvents } from '../../../../../ee/server/apps'; + +export function online(department: string, skipSettingCheck = false, skipFallbackCheck = false): boolean { + return Livechat.online(department, skipSettingCheck, skipFallbackCheck); +} + +async function findTriggers(): Promise[]> { + const triggers = await LivechatTrigger.findEnabled().toArray(); + return triggers.map(({ _id, actions, conditions, runOnce }) => ({ + _id, + actions, + conditions, + runOnce, + })); +} + +export function findDepartments(businessUnit?: string): Promise { + // TODO: check this function usage + return LivechatDepartment.findEnabledWithAgentsAndBusinessUnit(businessUnit, { + _id: 1, + name: 1, + showOnRegistration: 1, + showOnOfflineForm: 1, + }) + .fetch() + .map(({ _id, name, showOnRegistration, showOnOfflineForm }: ILivechatDepartment) => ({ + _id, + name, + showOnRegistration, + showOnOfflineForm, + })); +} + +async function findFilters() { + const filters = await LivechatFilter.findEnabled().toArray(); + return filters.map((filter) => _.pick(filter, '_id', 'regex', 'slug')); +} + +export function findGuest(token: string): Promise { + return LivechatVisitors.getVisitorByToken(token, { + projection: { + name: 1, + username: 1, + token: 1, + visitorEmails: 1, + department: 1, + }, + }); +} + +export function findRoom(token: string, rid?: string): IOmnichannelRoom { + const fields = { + t: 1, + departmentId: 1, + servedBy: 1, + open: 1, + v: 1, + ts: 1, + }; + + if (!rid) { + return LivechatRooms.findOneByVisitorToken(token, fields); + } + + return LivechatRooms.findOneByIdAndVisitorToken(rid, token, fields); +} + +export function findOpenRoom(token: string, departmentId?: string): IOmnichannelRoom | undefined { + const options = { + fields: { + departmentId: 1, + servedBy: 1, + open: 1, + callStatus: 1, + }, + }; + + let room; + const rooms = departmentId + ? LivechatRooms.findOpenByVisitorTokenAndDepartmentId(token, departmentId, options).fetch() + : LivechatRooms.findOpenByVisitorToken(token, options).fetch(); + if (rooms && rooms.length > 0) { + room = rooms[0]; + } + + if (room) { + Livechat.addTypingListener(room._id, (username, typing, data) => { + Apps.triggerEvent(AppEvents.IRoomUserTyping, { roomId: room._id, username, typing, data }); + }); + } + return room; +} +export function getRoom({ + guest, + rid, + roomInfo, + agent, + extraParams, +}: { + guest: ILivechatVisitor; + rid?: string; + roomInfo?: { + source?: { type: OmnichannelSourceType; id?: string; alias?: string; label?: string; sidebarIcon?: string; defaultIcon?: string }; + }; + agent?: { agentId?: string; username?: string }; + extraParams?: Record; +}): Promise<{ room: IOmnichannelRoom; newRoom: boolean }> { + const token = guest?.token; + + const message = { + _id: Random.id(), + rid, + msg: '', + token, + ts: new Date(), + }; + + Livechat.addTypingListener(rid, (username, typing, data) => { + Apps.triggerEvent(AppEvents.IRoomUserTyping, { roomId: rid, username, typing, data }); + }); + + return Livechat.getRoom(guest, message, roomInfo, agent, extraParams); +} + +export function findAgent(agentId: string): void | { hiddenInfo: true } | ILivechatAgent { + return normalizeAgent(agentId); +} + +export function normalizeHttpHeaderData(headers: Record = {}): { + httpHeaders: Record; +} { + const httpHeaders = Object.assign({}, headers); + return { httpHeaders }; +} + +export async function settings({ businessUnit = '' }: { businessUnit?: string } = {}): Promise> { + // Putting this ugly conversion while we type the livechat service + const initSettings = Livechat.getInitSettings() as unknown as Record; + const triggers = await findTriggers(); + const filters = await findFilters(); + const departments = findDepartments(businessUnit); + const sound = `${Meteor.absoluteUrl()}sounds/chime.mp3`; + const emojis = await EmojiCustom.find().toArray(); + + return { + enabled: initSettings.Livechat_enabled, + settings: { + registrationForm: initSettings.Livechat_registration_form, + startSessionOnNewChat: initSettings.Livechat_start_session_on_new_chat, + allowSwitchingDepartments: initSettings.Livechat_allow_switching_departments, + nameFieldRegistrationForm: initSettings.Livechat_name_field_registration_form, + emailFieldRegistrationForm: initSettings.Livechat_email_field_registration_form, + guestDefaultAvatar: initSettings.Assets_livechat_guest_default_avatar, + displayOfflineForm: initSettings.Livechat_display_offline_form, + videoCall: initSettings.Omnichannel_call_provider === 'default-provider', + fileUpload: initSettings.Livechat_fileupload_enabled && initSettings.FileUpload_Enabled, + language: initSettings.Language, + transcript: initSettings.Livechat_enable_transcript, + printTranscript: initSettings.Livechat_enable_print_transcript, + enableTranscriptMobile: initSettings.Livechat_enable_transcript_mobile, + historyMonitorType: initSettings.Livechat_history_monitor_type, + forceAcceptDataProcessingConsent: initSettings.Livechat_force_accept_data_processing_consent, + showConnecting: initSettings.Livechat_Show_Connecting, + agentHiddenInfo: initSettings.Livechat_show_agent_info === false, + clearLocalStorageWhenChatEnded: initSettings.Livechat_clear_local_storage_when_chat_ended, + limitTextLength: + initSettings.Livechat_enable_message_character_limit && + (initSettings.Livechat_message_character_limit || initSettings.Message_MaxAllowedSize), + hideSysMessages: initSettings.Livechat_hide_sys_messages, + isPostChatFeedbackEnabled: initSettings.Livechat_enable_post_chat_feedback, + + livechat_kill_switch: initSettings.Livechat_kill_switch, + livechat_kill_switch_message: initSettings.Livechat_kill_switch_message, + livechat_friendly_chat: initSettings.Livechat_friendly_chat, + livechat_enable_avatar: initSettings.Livechat_enable_avatar, + livechat_enable_elastic_search_logs: initSettings.Livechat_enable_elastic_search_logs, + livechat_elastic_search_url: initSettings.Livechat_elastic_search_url, + livechat_elastic_search_index: initSettings.Livechat_elastic_search_index, + livechat_elastic_search_access_key: initSettings.Livechat_elastic_search_access_key, + livechat_elastic_search_access_key_secret: initSettings.Livechat_elastic_search_access_key_secret, + livechat_chat_already_closed_message: initSettings.Livechat_chat_already_closed_message, + livechat_close_modal_message: initSettings.Livechat_close_modal_message, + }, + theme: { + title: initSettings.Livechat_title, + color: initSettings.Livechat_title_color, + offlineTitle: initSettings.Livechat_offline_title, + offlineColor: initSettings.Livechat_offline_title_color, + actionLinks: { + webrtc: [ + { + actionLinksAlignment: 'flex-start', + i18nLabel: 'Join_call', + label: TAPi18n.__('Join_call'), + method_id: 'joinLivechatWebRTCCall', + }, + { + i18nLabel: 'End_call', + label: TAPi18n.__('End_call'), + method_id: 'endLivechatWebRTCCall', + danger: true, + }, + ], + jitsi: [ + { icon: 'icon-videocam', i18nLabel: 'Accept' }, + { icon: 'icon-cancel', i18nLabel: 'Decline' }, + ], + }, + }, + messages: { + offlineMessage: initSettings.Livechat_offline_message, + offlineSuccessMessage: initSettings.Livechat_offline_success_message, + offlineUnavailableMessage: initSettings.Livechat_offline_form_unavailable, + conversationFinishedMessage: initSettings.Livechat_conversation_finished_message, + conversationFinishedText: initSettings.Livechat_conversation_finished_text, + transcriptMessage: initSettings.Livechat_transcript_message, + registrationFormMessage: initSettings.Livechat_registration_form_message, + dataProcessingConsentText: initSettings.Livechat_data_processing_consent_text, + escalatedConversationFinishedText: initSettings.Livechat_escalated_conversation_finished_text, + }, + survey: { + items: ['satisfaction', 'agentKnowledge', 'agentResposiveness', 'agentFriendliness'], + values: ['1', '2', '3', '4', '5'], + }, + triggers, + filters, + departments, + resources: { + sound, + emojis, + }, + }; +} + +export async function getExtraConfigInfo(room?: IOmnichannelRoom): Promise { + return callbacks.run('livechat.onLoadConfigApi', { room }); +} + +// TODO: please forgive me for this. Still finding the good types for these callbacks +export function onCheckRoomParams(params: any): any { + return callbacks.run('livechat.onCheckRoomApiParams', params); +} diff --git a/apps/meteor/app/livechat/server/api/lib/queue.js b/apps/meteor/app/livechat/server/api/lib/queue.js deleted file mode 100644 index faaba3bc4ae10..0000000000000 --- a/apps/meteor/app/livechat/server/api/lib/queue.js +++ /dev/null @@ -1,26 +0,0 @@ -import { LivechatRooms } from '@rocket.chat/models'; - -export async function findQueueMetrics({ agentId, includeOfflineAgents, departmentId, pagination: { offset, count, sort } }) { - const result = await LivechatRooms.getQueueMetrics({ - departmentId, - agentId, - includeOfflineAgents, - options: { - sort: sort || { chats: -1 }, - offset, - count, - }, - }); - - const { - sortedResults: queue, - totalCount: [{ total } = { total: 0 }], - } = result[0]; - - return { - queue, - count: queue.length, - offset, - total, - }; -} diff --git a/apps/meteor/app/livechat/server/api/lib/queue.ts b/apps/meteor/app/livechat/server/api/lib/queue.ts new file mode 100644 index 0000000000000..c15401ce5c270 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/lib/queue.ts @@ -0,0 +1,46 @@ +import { LivechatRooms } from '@rocket.chat/models'; +import type { PaginatedResult } from '@rocket.chat/rest-typings'; + +export async function findQueueMetrics({ + agentId, + includeOfflineAgents, + departmentId, + pagination: { offset, count, sort }, +}: { + agentId?: string; + includeOfflineAgents?: boolean; + departmentId?: string; + pagination: { offset: number; count: number; sort: Record }; +}): Promise< + PaginatedResult<{ + queue: Array<{ + _id: string; + user: { _id: string; userId: string; username: string; status: string }; + department: { _id: string; name: string }; + chats: number; + }>; + }> +> { + const result = await LivechatRooms.getQueueMetrics({ + departmentId, + agentId, + includeOfflineAgents, + options: { + sort: sort || { chats: -1 }, + offset, + count, + }, + }); + + const { + sortedResults: queue, + totalCount: [{ total } = { total: 0 }], + } = result[0]; + + return { + queue, + count: queue.length, + offset, + total, + }; +} diff --git a/apps/meteor/app/livechat/server/api/lib/rooms.js b/apps/meteor/app/livechat/server/api/lib/rooms.js deleted file mode 100644 index ed5db48e92570..0000000000000 --- a/apps/meteor/app/livechat/server/api/lib/rooms.js +++ /dev/null @@ -1,57 +0,0 @@ -import { LivechatRooms, LivechatDepartment } from '@rocket.chat/models'; - -export async function findRooms({ - agents, - roomName, - departmentId, - open, - createdAt, - closedAt, - tags, - customFields, - onhold, - options: { offset, count, fields, sort }, -}) { - const { cursor, totalCount } = LivechatRooms.findRoomsWithCriteria({ - agents, - roomName, - departmentId, - open, - createdAt, - closedAt, - tags, - customFields, - onhold: ['t', 'true', '1'].includes(onhold), - options: { - sort: sort || { ts: -1 }, - offset, - count, - fields, - }, - }); - - const [rooms, total] = await Promise.all([cursor.toArray(), totalCount]); - - const departmentsIds = [...new Set(rooms.map((room) => room.departmentId).filter(Boolean))]; - if (departmentsIds.length) { - const departments = await LivechatDepartment.findInIds(departmentsIds, { - projection: { name: 1 }, - }).toArray(); - - rooms.forEach((room) => { - if (!room.departmentId) { - return; - } - const department = departments.find((dept) => dept._id === room.departmentId); - if (department) { - room.department = department; - } - }); - } - return { - rooms, - count: rooms.length, - offset, - total, - }; -} diff --git a/apps/meteor/app/livechat/server/api/lib/rooms.ts b/apps/meteor/app/livechat/server/api/lib/rooms.ts new file mode 100644 index 0000000000000..cb19bcfb626c6 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/lib/rooms.ts @@ -0,0 +1,78 @@ +import type { ILivechatDepartmentRecord, IOmnichannelRoom } from '@rocket.chat/core-typings'; +import { LivechatRooms, LivechatDepartment } from '@rocket.chat/models'; +import type { PaginatedResult } from '@rocket.chat/rest-typings'; + +export async function findRooms({ + agents, + roomName, + departmentId, + open, + createdAt, + closedAt, + tags, + customFields, + onhold, + options: { offset, count, fields, sort }, +}: { + agents?: Array; + roomName?: string; + departmentId?: string; + open?: boolean; + createdAt?: { + start?: string | undefined; + end?: string | undefined; + }; + closedAt?: { + start?: string | undefined; + end?: string | undefined; + }; + tags?: Array; + customFields?: Record; + onhold?: string | boolean; + options: { offset: number; count: number; fields: Record; sort: Record }; +}): Promise }>> { + const { cursor, totalCount } = LivechatRooms.findRoomsWithCriteria({ + agents, + roomName, + departmentId, + open, + createdAt, + closedAt, + tags, + customFields, + onhold: ['t', 'true', '1'].includes(`${onhold}`), + options: { + sort: sort || { ts: -1 }, + offset, + count, + fields, + }, + }); + + const [rooms, total] = await Promise.all([cursor.toArray(), totalCount]); + + const isRoomWithDepartmentId = (depId: string | undefined): depId is string => !!depId; + + const departmentsIds = [...new Set(rooms.map((room) => room.departmentId).filter(isRoomWithDepartmentId))]; + if (departmentsIds.length) { + const departments = await LivechatDepartment.findInIds(departmentsIds, { + projection: { name: 1 }, + }).toArray(); + + rooms.forEach((room: IOmnichannelRoom & { department?: ILivechatDepartmentRecord }) => { + if (!room.departmentId) { + return; + } + const department = departments.find((dept) => dept._id === room.departmentId); + if (department) { + room.department = department; + } + }); + } + return { + rooms, + count: rooms.length, + offset, + total, + }; +} diff --git a/apps/meteor/app/livechat/server/api/lib/transfer.js b/apps/meteor/app/livechat/server/api/lib/transfer.js deleted file mode 100644 index 0051a8970a408..0000000000000 --- a/apps/meteor/app/livechat/server/api/lib/transfer.js +++ /dev/null @@ -1,23 +0,0 @@ -import { Messages } from '@rocket.chat/models'; - -const normalizeTransferHistory = ({ transferData }) => transferData; -export async function findLivechatTransferHistory({ rid, pagination: { offset, count, sort } }) { - const { cursor, totalCount } = Messages.findPaginated( - { rid, t: 'livechat_transfer_history' }, - { - projection: { transferData: 1 }, - sort: sort || { ts: 1 }, - skip: offset, - limit: count, - }, - ); - - const [history, total] = await Promise.all([cursor.map(normalizeTransferHistory).toArray(), totalCount]); - - return { - history, - count: history.length, - offset, - total, - }; -} diff --git a/apps/meteor/app/livechat/server/api/lib/transfer.ts b/apps/meteor/app/livechat/server/api/lib/transfer.ts new file mode 100644 index 0000000000000..d01d85402cae5 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/lib/transfer.ts @@ -0,0 +1,34 @@ +import type { IOmnichannelSystemMessage } from '@rocket.chat/core-typings'; +import { Messages } from '@rocket.chat/models'; +import type { PaginatedResult } from '@rocket.chat/rest-typings'; + +const normalizeTransferHistory = ({ transferData }: IOmnichannelSystemMessage): IOmnichannelSystemMessage['transferData'] => transferData; + +const removeNulls = (value: S | undefined): value is S => value != null; + +export async function findLivechatTransferHistory({ + rid, + pagination: { offset, count, sort }, +}: { + rid: string; + pagination: { offset: number; count: number; sort: Record }; +}): Promise> { + const { cursor, totalCount } = Messages.findPaginated( + { rid, t: 'livechat_transfer_history' }, + { + projection: { transferData: 1 }, + sort: sort || { ts: 1 }, + skip: offset, + limit: count, + }, + ); + + const [history, total] = await Promise.all([cursor.map(normalizeTransferHistory).toArray(), totalCount]); + + return { + history: history.filter(removeNulls), + count: history.length, + offset, + total, + }; +} diff --git a/apps/meteor/app/livechat/server/api/lib/triggers.js b/apps/meteor/app/livechat/server/api/lib/triggers.js deleted file mode 100644 index 897ae647d1943..0000000000000 --- a/apps/meteor/app/livechat/server/api/lib/triggers.js +++ /dev/null @@ -1,25 +0,0 @@ -import { LivechatTrigger } from '@rocket.chat/models'; - -export async function findTriggers({ pagination: { offset, count, sort } }) { - const { cursor, totalCount } = LivechatTrigger.findPaginated( - {}, - { - sort: sort || { name: 1 }, - skip: offset, - limit: count, - }, - ); - - const [triggers, total] = await Promise.all([cursor.toArray(), totalCount]); - - return { - triggers, - count: triggers.length, - offset, - total, - }; -} - -export async function findTriggerById({ triggerId }) { - return LivechatTrigger.findOneById(triggerId); -} diff --git a/apps/meteor/app/livechat/server/api/lib/triggers.ts b/apps/meteor/app/livechat/server/api/lib/triggers.ts new file mode 100644 index 0000000000000..dbb6f8a6633a1 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/lib/triggers.ts @@ -0,0 +1,31 @@ +import type { ILivechatTrigger } from '@rocket.chat/core-typings'; +import { LivechatTrigger } from '@rocket.chat/models'; +import type { PaginatedResult } from '@rocket.chat/rest-typings'; + +export async function findTriggers({ + pagination: { offset, count, sort }, +}: { + pagination: { offset: number; count: number; sort: Record }; +}): Promise }>> { + const { cursor, totalCount } = LivechatTrigger.findPaginated( + {}, + { + sort: sort || { name: 1 }, + skip: offset, + limit: count, + }, + ); + + const [triggers, total] = await Promise.all([cursor.toArray(), totalCount]); + + return { + triggers, + count: triggers.length, + offset, + total, + }; +} + +export async function findTriggerById({ triggerId }: { triggerId: string }): Promise { + return LivechatTrigger.findOneById(triggerId); +} diff --git a/apps/meteor/app/livechat/server/api/lib/users.js b/apps/meteor/app/livechat/server/api/lib/users.js deleted file mode 100644 index e28b003a66986..0000000000000 --- a/apps/meteor/app/livechat/server/api/lib/users.js +++ /dev/null @@ -1,63 +0,0 @@ -import { escapeRegExp } from '@rocket.chat/string-helpers'; -import { Users } from '@rocket.chat/models'; - -/** - * @param {IRole['_id']} role the role id - * @param {string} text - * @param {any} pagination - */ -async function findUsers({ role, text, pagination: { offset, count, sort } }) { - const query = {}; - if (text) { - const filterReg = new RegExp(escapeRegExp(text), 'i'); - Object.assign(query, { - $or: [{ username: filterReg }, { name: filterReg }, { 'emails.address': filterReg }], - }); - } - - const { cursor, totalCount } = Users.findPaginatedUsersInRolesWithQuery(role, query, { - sort: sort || { name: 1 }, - skip: offset, - limit: count, - projection: { - username: 1, - name: 1, - status: 1, - statusLivechat: 1, - emails: 1, - livechat: 1, - }, - }); - - const [users, total] = await Promise.all([cursor.toArray(), totalCount]); - - return { - users, - count: users.length, - offset, - total, - }; -} -export async function findAgents({ text, pagination: { offset, count, sort } }) { - return findUsers({ - role: 'livechat-agent', - text, - pagination: { - offset, - count, - sort, - }, - }); -} - -export async function findManagers({ text, pagination: { offset, count, sort } }) { - return findUsers({ - role: 'livechat-manager', - text, - pagination: { - offset, - count, - sort, - }, - }); -} diff --git a/apps/meteor/app/livechat/server/api/lib/users.ts b/apps/meteor/app/livechat/server/api/lib/users.ts new file mode 100644 index 0000000000000..72833d67cea84 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/lib/users.ts @@ -0,0 +1,84 @@ +import { escapeRegExp } from '@rocket.chat/string-helpers'; +import { Users } from '@rocket.chat/models'; +import type { ILivechatAgent, IRole } from '@rocket.chat/core-typings'; + +/** + * @param {IRole['_id']} role the role id + * @param {string} text + * @param {any} pagination + */ +async function findUsers({ + role, + text, + pagination: { offset, count, sort }, +}: { + role: IRole['_id']; + text?: string; + pagination: { offset: number; count: number; sort: any }; +}): Promise<{ users: ILivechatAgent[]; count: number; offset: number; total: number }> { + const query = {}; + if (text) { + const filterReg = new RegExp(escapeRegExp(text), 'i'); + Object.assign(query, { + $or: [{ username: filterReg }, { name: filterReg }, { 'emails.address': filterReg }], + }); + } + + const { cursor, totalCount } = Users.findPaginatedUsersInRolesWithQuery(role, query, { + sort: sort || { name: 1 }, + skip: offset, + limit: count, + projection: { + username: 1, + name: 1, + status: 1, + statusLivechat: 1, + emails: 1, + livechat: 1, + }, + }); + + const [users, total] = await Promise.all([cursor.toArray(), totalCount]); + + return { + users, + count: users.length, + offset, + total, + }; +} +export async function findAgents({ + text, + pagination: { offset, count, sort }, +}: { + text?: string; + pagination: { offset: number; count: number; sort: any }; +}): Promise> { + return findUsers({ + role: 'livechat-agent', + text, + pagination: { + offset, + count, + sort, + }, + }); +} + +export async function findManagers({ + text, + pagination: { offset, count, sort }, +}: { + text?: string; + pagination: { offset: number; count: number; sort: any }; +}): Promise> { + return findUsers({ + role: 'livechat-manager', + text, + pagination: { + offset, + count, + sort, + }, + }); +} diff --git a/apps/meteor/app/livechat/server/api/lib/visitors.js b/apps/meteor/app/livechat/server/api/lib/visitors.js deleted file mode 100644 index cfa62ead68d64..0000000000000 --- a/apps/meteor/app/livechat/server/api/lib/visitors.js +++ /dev/null @@ -1,168 +0,0 @@ -import { LivechatVisitors, Messages, LivechatRooms, LivechatCustomField } from '@rocket.chat/models'; - -import { canAccessRoomAsync } from '../../../../authorization/server/functions/canAccessRoom'; - -export async function findVisitorInfo({ visitorId }) { - const visitor = await LivechatVisitors.findOneById(visitorId); - if (!visitor) { - throw new Error('visitor-not-found'); - } - - return { - visitor, - }; -} - -export async function findVisitedPages({ roomId, pagination: { offset, count, sort } }) { - const room = await LivechatRooms.findOneById(roomId); - if (!room) { - throw new Error('invalid-room'); - } - const { cursor, totalCount } = Messages.findPaginatedByRoomIdAndType(room._id, 'livechat_navigation_history', { - sort: sort || { ts: -1 }, - skip: offset, - limit: count, - }); - - const [pages, total] = await Promise.all([cursor.toArray(), totalCount]); - - return { - pages, - count: pages.length, - offset, - total, - }; -} - -export async function findChatHistory({ userId, roomId, visitorId, pagination: { offset, count, sort } }) { - const room = await LivechatRooms.findOneById(roomId); - if (!room) { - throw new Error('invalid-room'); - } - if (!(await canAccessRoomAsync(room, { _id: userId }))) { - throw new Error('error-not-allowed'); - } - - const { cursor, totalCount } = LivechatRooms.findPaginatedByVisitorId(visitorId, { - sort: sort || { ts: -1 }, - skip: offset, - limit: count, - }); - - const [history, total] = await Promise.all([cursor.toArray(), totalCount]); - - return { - history, - count: history.length, - offset, - total, - }; -} - -export async function searchChats({ - userId, - roomId, - visitorId, - searchText, - closedChatsOnly, - servedChatsOnly: served, - pagination: { offset, count, sort }, -}) { - const room = await LivechatRooms.findOneById(roomId); - if (!room) { - throw new Error('invalid-room'); - } - - if (!(await canAccessRoomAsync(room, { _id: userId }))) { - throw new Error('error-not-allowed'); - } - - const options = { - sort: sort || { ts: -1 }, - skip: offset, - limit: count, - }; - - const [total] = await LivechatRooms.findRoomsByVisitorIdAndMessageWithCriteria({ - visitorId, - open: closedChatsOnly !== 'true', - served: served !== 'true', - searchText, - onlyCount: true, - }).toArray(); - const cursor = await LivechatRooms.findRoomsByVisitorIdAndMessageWithCriteria({ - visitorId, - open: closedChatsOnly === 'true', - served: served === 'true', - searchText, - options, - }); - - const history = await cursor.toArray(); - - return { - history, - count: history.length, - offset, - total: (total && total.count) || 0, - }; -} - -export async function findVisitorsToAutocomplete({ selector }) { - const { exceptions = [], conditions = {} } = selector; - - const options = { - projection: { - _id: 1, - name: 1, - username: 1, - }, - limit: 10, - sort: { - name: 1, - }, - }; - - const items = await LivechatVisitors.findByNameRegexWithExceptionsAndConditions(selector.term, exceptions, conditions, options).toArray(); - return { - items, - }; -} - -export async function findVisitorsByEmailOrPhoneOrNameOrUsernameOrCustomField({ - emailOrPhone, - nameOrUsername, - pagination: { offset, count, sort }, -}) { - const allowedCF = await LivechatCustomField.findMatchingCustomFields('visitor', true, { projection: { _id: 1 } }) - .map((cf) => cf._id) - .toArray(); - - const { cursor, totalCount } = await LivechatVisitors.findPaginatedVisitorsByEmailOrPhoneOrNameOrUsernameOrCustomField( - emailOrPhone, - nameOrUsername, - allowedCF, - { - sort: sort || { ts: -1 }, - skip: offset, - limit: count, - projection: { - username: 1, - name: 1, - phone: 1, - livechatData: 1, - visitorEmails: 1, - lastChat: 1, - }, - }, - ); - - const [visitors, total] = await Promise.all([cursor.toArray(), totalCount]); - - return { - visitors, - count: visitors.length, - offset, - total, - }; -} diff --git a/apps/meteor/app/livechat/server/api/lib/visitors.ts b/apps/meteor/app/livechat/server/api/lib/visitors.ts new file mode 100644 index 0000000000000..29de95b48f42b --- /dev/null +++ b/apps/meteor/app/livechat/server/api/lib/visitors.ts @@ -0,0 +1,210 @@ +import type { ILivechatVisitor, IMessage, IOmnichannelRoom, IRoom, IUser, IVisitor } from '@rocket.chat/core-typings'; +import { LivechatVisitors, Messages, LivechatRooms, LivechatCustomField } from '@rocket.chat/models'; +import type { FindOptions } from 'mongodb'; + +import { canAccessRoomAsync } from '../../../../authorization/server/functions/canAccessRoom'; + +export async function findVisitorInfo({ visitorId }: { visitorId: IVisitor['_id'] }) { + const visitor = await LivechatVisitors.findOneById(visitorId); + if (!visitor) { + throw new Error('visitor-not-found'); + } + + return { + visitor, + }; +} + +export async function findVisitedPages({ + roomId, + pagination: { offset, count, sort }, +}: { + roomId: IRoom['_id']; + pagination: { offset: number; count: number; sort: FindOptions['sort'] }; +}) { + const room = await LivechatRooms.findOneById(roomId); + if (!room) { + throw new Error('invalid-room'); + } + const { cursor, totalCount } = Messages.findPaginatedByRoomIdAndType(room._id, 'livechat_navigation_history', { + sort: sort || { ts: -1 }, + skip: offset, + limit: count, + }); + + const [pages, total] = await Promise.all([cursor.toArray(), totalCount]); + + return { + pages, + count: pages.length, + offset, + total, + }; +} + +export async function findChatHistory({ + userId, + roomId, + visitorId, + pagination: { offset, count, sort }, +}: { + userId: IUser['_id']; + roomId: IRoom['_id']; + visitorId: IVisitor['_id']; + pagination: { offset: number; count: number; sort: FindOptions['sort'] }; +}) { + const room = await LivechatRooms.findOneById(roomId); + if (!room) { + throw new Error('invalid-room'); + } + if (!(await canAccessRoomAsync(room, { _id: userId }))) { + throw new Error('error-not-allowed'); + } + + const { cursor, totalCount } = LivechatRooms.findPaginatedByVisitorId(visitorId, { + sort: sort || { ts: -1 }, + skip: offset, + limit: count, + }); + + const [history, total] = await Promise.all([cursor.toArray(), totalCount]); + + return { + history, + count: history.length, + offset, + total, + }; +} + +export async function searchChats({ + userId, + roomId, + visitorId, + searchText, + closedChatsOnly, + servedChatsOnly: served, + source, + pagination: { offset, count, sort }, +}: { + userId: IUser['_id']; + roomId: IRoom['_id']; + visitorId: IVisitor['_id']; + searchText?: string; + closedChatsOnly?: string; + servedChatsOnly?: string; + source?: string; + pagination: { offset: number; count: number; sort: FindOptions['sort'] }; +}) { + const room = await LivechatRooms.findOneById(roomId); + if (!room) { + throw new Error('invalid-room'); + } + + if (!(await canAccessRoomAsync(room, { _id: userId }))) { + throw new Error('error-not-allowed'); + } + + const options = { + sort: sort || { ts: -1 }, + skip: offset, + limit: count, + }; + + const [total] = await LivechatRooms.findRoomsByVisitorIdAndMessageWithCriteria({ + visitorId, + open: closedChatsOnly !== 'true', + served: served === 'true', + searchText, + onlyCount: true, + source, + }).toArray(); + const cursor = await LivechatRooms.findRoomsByVisitorIdAndMessageWithCriteria({ + visitorId, + open: closedChatsOnly !== 'true', + served: served === 'true', + searchText, + options, + source, + }); + + const history = await cursor.toArray(); + + return { + history, + count: history.length, + offset, + total: total?.count ?? 0, + }; +} + +export async function findVisitorsToAutocomplete({ + selector, +}: { + selector: { + exceptions?: ILivechatVisitor['_id'][]; + conditions?: Record; + term: string; + }; +}) { + const { exceptions = [], conditions = {} } = selector; + + const options: FindOptions = { + projection: { + _id: 1, + name: 1, + username: 1, + }, + limit: 10, + sort: { + name: 1, + }, + }; + + const items = await LivechatVisitors.findByNameRegexWithExceptionsAndConditions(selector.term, exceptions, conditions, options).toArray(); + return { + items, + }; +} + +export async function findVisitorsByEmailOrPhoneOrNameOrUsernameOrCustomField({ + emailOrPhone, + nameOrUsername, + pagination: { offset, count, sort }, +}: { + emailOrPhone?: string; + nameOrUsername?: RegExp; + pagination: { offset: number; count: number; sort: FindOptions['sort'] }; +}) { + const allowedCF = await LivechatCustomField.findMatchingCustomFields('visitor', true, { projection: { _id: 1 } }) + .map((cf) => cf._id) + .toArray(); + + const { cursor, totalCount } = await LivechatVisitors.findPaginatedVisitorsByEmailOrPhoneOrNameOrUsernameOrCustomField( + emailOrPhone, + nameOrUsername, + allowedCF, + { + sort: sort || { ts: -1 }, + skip: offset, + limit: count, + projection: { + username: 1, + name: 1, + phone: 1, + livechatData: 1, + visitorEmails: 1, + lastChat: 1, + }, + }, + ); + + const [visitors, total] = await Promise.all([cursor.toArray(), totalCount]); + + return { + visitors, + count: visitors.length, + offset, + total, + }; +} diff --git a/apps/meteor/app/livechat/server/api/rest.js b/apps/meteor/app/livechat/server/api/rest.js deleted file mode 100644 index f7593c1856970..0000000000000 --- a/apps/meteor/app/livechat/server/api/rest.js +++ /dev/null @@ -1,13 +0,0 @@ -import './v1/config.js'; -import './v1/visitor'; -import './v1/transcript.js'; -import './v1/offlineMessage.js'; -import './v1/pageVisited.js'; -import './v1/agent.js'; -import './v1/message.js'; -import './v1/customField.js'; -import './v1/room.js'; -import './v1/videoCall.js'; -import './v1/transfer.js'; -import './v1/contact'; -import './v1/sns.ts'; diff --git a/apps/meteor/app/livechat/server/api/rest.ts b/apps/meteor/app/livechat/server/api/rest.ts new file mode 100644 index 0000000000000..2065f6c08f212 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/rest.ts @@ -0,0 +1,14 @@ +import './v1/config'; +import './v1/visitor'; +import './v1/transcript'; +import './v1/offlineMessage'; +import './v1/pageVisited'; +import './v1/agent'; +import './v1/message'; +import './v1/customField'; +import './v1/room'; +import './v1/videoCall'; +import './v1/transfer'; +import './v1/contact'; +import './v1/webhooks'; +import './v1/sns.ts'; diff --git a/apps/meteor/app/livechat/server/api/v1/agent.js b/apps/meteor/app/livechat/server/api/v1/agent.js deleted file mode 100644 index 104f0bc012e38..0000000000000 --- a/apps/meteor/app/livechat/server/api/v1/agent.js +++ /dev/null @@ -1,78 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Match, check } from 'meteor/check'; - -import { API } from '../../../../api/server'; -import { findRoom, findGuest, findAgent, findOpenRoom } from '../lib/livechat'; -import { Livechat } from '../../lib/Livechat'; - -API.v1.addRoute('livechat/agent.info/:rid/:token', { - async get() { - try { - check(this.urlParams, { - rid: String, - token: String, - }); - - const visitor = await findGuest(this.urlParams.token); - if (!visitor) { - throw new Meteor.Error('invalid-token'); - } - - const room = findRoom(this.urlParams.token, this.urlParams.rid); - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - const agent = room && room.servedBy && findAgent(room.servedBy._id); - if (!agent) { - throw new Meteor.Error('invalid-agent'); - } - - return API.v1.success({ agent }); - } catch (e) { - return API.v1.failure(e); - } - }, -}); - -API.v1.addRoute('livechat/agent.next/:token', { - get() { - try { - check(this.urlParams, { - token: String, - }); - - check(this.queryParams, { - department: Match.Maybe(String), - }); - - const { token } = this.urlParams; - const room = findOpenRoom(token); - if (room) { - return API.v1.success(); - } - - let { department } = this.queryParams; - if (!department) { - const requireDeparment = Livechat.getRequiredDepartment(); - if (requireDeparment) { - department = requireDeparment._id; - } - } - - const agentData = Promise.await(Livechat.getNextAgent(department)); - if (!agentData) { - throw new Meteor.Error('agent-not-found'); - } - - const agent = findAgent(agentData.agentId); - if (!agent) { - throw new Meteor.Error('invalid-agent'); - } - - return API.v1.success({ agent }); - } catch (e) { - return API.v1.failure(e); - } - }, -}); diff --git a/apps/meteor/app/livechat/server/api/v1/agent.ts b/apps/meteor/app/livechat/server/api/v1/agent.ts new file mode 100644 index 0000000000000..31075d41878ec --- /dev/null +++ b/apps/meteor/app/livechat/server/api/v1/agent.ts @@ -0,0 +1,110 @@ +import { isGETAgentNextToken, isPOSTLivechatAgentStatusProps } from '@rocket.chat/rest-typings'; +import { Users } from '@rocket.chat/models'; +import type { ILivechatAgent } from '@rocket.chat/core-typings'; +import { ILivechatAgentStatus } from '@rocket.chat/core-typings'; + +import { API } from '../../../../api/server'; +import { findRoom, findGuest, findAgent, findOpenRoom } from '../lib/livechat'; +import { Livechat } from '../../lib/Livechat'; +import { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission'; + +API.v1.addRoute('livechat/agent.info/:rid/:token', { + async get() { + const visitor = await findGuest(this.urlParams.token); + if (!visitor) { + throw new Error('invalid-token'); + } + + const room = findRoom(this.urlParams.token, this.urlParams.rid); + if (!room) { + throw new Error('invalid-room'); + } + + const agent = room?.servedBy && findAgent(room.servedBy._id); + if (!agent) { + throw new Error('invalid-agent'); + } + + return API.v1.success({ agent }); + }, +}); + +API.v1.addRoute( + 'livechat/agent.next/:token', + { validateParams: isGETAgentNextToken }, + { + async get() { + const { token } = this.urlParams; + const room = findOpenRoom(token); + if (room) { + return API.v1.success(); + } + + let { department } = this.queryParams; + if (!department) { + const requireDeparment = Livechat.getRequiredDepartment(); + if (requireDeparment) { + department = requireDeparment._id; + } + } + + const agentData = await Livechat.getNextAgent(department); + if (!agentData) { + throw new Error('agent-not-found'); + } + + const agent = findAgent(agentData.agentId); + if (!agent) { + throw new Error('invalid-agent'); + } + + return API.v1.success({ agent }); + }, + }, +); + +API.v1.addRoute( + 'livechat/agent.status', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isPOSTLivechatAgentStatusProps }, + { + async post() { + const { status, agentId: inputAgentId } = this.bodyParams; + + const agentId = inputAgentId || this.userId; + + const agent = await Users.findOneAgentById>(agentId, { + projection: { + status: 1, + statusLivechat: 1, + }, + }); + if (!agent) { + return API.v1.notFound('Agent not found'); + } + + const newStatus: ILivechatAgentStatus = + status || + (agent.statusLivechat === ILivechatAgentStatus.AVAILABLE ? ILivechatAgentStatus.NOT_AVAILABLE : ILivechatAgentStatus.AVAILABLE); + if (newStatus === agent.statusLivechat) { + return API.v1.success({ status: agent.statusLivechat }); + } + + if (agentId !== this.userId) { + if (!(await hasPermissionAsync(this.userId, 'manage-livechat-agents'))) { + return API.v1.unauthorized(); + } + Livechat.setUserStatusLivechat(agentId, newStatus); + + return API.v1.success({ status: newStatus }); + } + + if (!Livechat.allowAgentChangeServiceStatus(newStatus, agentId)) { + return API.v1.failure('error-business-hours-are-closed'); + } + + Livechat.setUserStatusLivechat(agentId, newStatus); + + return API.v1.success({ status: newStatus }); + }, + }, +); diff --git a/apps/meteor/app/livechat/server/api/v1/config.js b/apps/meteor/app/livechat/server/api/v1/config.js deleted file mode 100644 index c13387bc64771..0000000000000 --- a/apps/meteor/app/livechat/server/api/v1/config.js +++ /dev/null @@ -1,43 +0,0 @@ -import { Match, check } from 'meteor/check'; -import mem from 'mem'; - -import { API } from '../../../../api/server'; -import { Livechat } from '../../lib/Livechat'; -import { settings, findOpenRoom, getExtraConfigInfo, findAgent } from '../lib/livechat'; - -const cachedSettings = mem(settings, { maxAge: 1000, cacheKey: JSON.stringify }); - -API.v1.addRoute('livechat/config', { - async get() { - try { - check(this.queryParams, { - token: Match.Maybe(String), - department: Match.Maybe(String), - businessUnit: Match.Maybe(String), - url: Match.Maybe(String), - }); - const enabled = Livechat.enabled(); - - if (!enabled) { - return API.v1.success({ config: { enabled: false } }); - } - - const { token, department, businessUnit, url } = this.queryParams; - - const config = await cachedSettings({ businessUnit, url }); - - const status = Livechat.online(department); - const guest = token && (await Livechat.findGuest(token)); - - const room = guest && findOpenRoom(token); - const agent = guest && room && room.servedBy && findAgent(room.servedBy._id); - - const extra = await getExtraConfigInfo(room); - return API.v1.success({ - config: { ...config, online: status, guest, room, agent, ...extra }, - }); - } catch (e) { - return API.v1.failure(e); - } - }, -}); diff --git a/apps/meteor/app/livechat/server/api/v1/config.ts b/apps/meteor/app/livechat/server/api/v1/config.ts new file mode 100644 index 0000000000000..9cba2db92368b --- /dev/null +++ b/apps/meteor/app/livechat/server/api/v1/config.ts @@ -0,0 +1,37 @@ +import mem from 'mem'; +import { isGETLivechatConfigParams } from '@rocket.chat/rest-typings'; + +import { API } from '../../../../api/server'; +import { Livechat } from '../../lib/Livechat'; +import { settings, findOpenRoom, getExtraConfigInfo, findAgent } from '../lib/livechat'; + +const cachedSettings = mem(settings, { maxAge: 1000, cacheKey: JSON.stringify }); + +API.v1.addRoute( + 'livechat/config', + { validateParams: isGETLivechatConfigParams }, + { + async get() { + const enabled = Livechat.enabled(); + + if (!enabled) { + return API.v1.success({ config: { enabled: false } }); + } + + const { token, department, businessUnit } = this.queryParams; + + const config = await cachedSettings({ businessUnit }); + + const status = Livechat.online(department); + const guest = token ? await Livechat.findGuest(token) : null; + + const room = guest ? findOpenRoom(guest.token) : undefined; + const agent = guest && room && room.servedBy && findAgent(room.servedBy._id); + + const extra = await getExtraConfigInfo(room); + return API.v1.success({ + config: { ...config, online: status, ...extra, ...(guest && { guest }), ...(room && { room }), ...(agent && { agent }) }, + }); + }, + }, +); diff --git a/apps/meteor/app/livechat/server/api/v1/customField.js b/apps/meteor/app/livechat/server/api/v1/customField.js deleted file mode 100644 index d6f556a625f21..0000000000000 --- a/apps/meteor/app/livechat/server/api/v1/customField.js +++ /dev/null @@ -1,142 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Match, check } from 'meteor/check'; - -import { API } from '../../../../api/server'; -import { findGuest } from '../lib/livechat'; -import { Livechat } from '../../lib/Livechat'; -import { findLivechatCustomFields, findCustomFieldById } from '../lib/customFields'; - -API.v1.addRoute('livechat/custom.field', { - async post() { - try { - check(this.bodyParams, { - token: String, - key: String, - value: String, - overwrite: Boolean, - }); - - const { token, key, value, overwrite } = this.bodyParams; - - const guest = await findGuest(token); - if (!guest) { - throw new Meteor.Error('invalid-token'); - } - - if (!(await Livechat.setCustomFields({ token, key, value, overwrite }))) { - return API.v1.failure(); - } - - return API.v1.success({ field: { key, value, overwrite } }); - } catch (e) { - return API.v1.failure(e); - } - }, -}); - -API.v1.addRoute( - 'livechat/custom-field', - { authRequired: true }, - { - post() { - try { - check(this.bodyParams, { - field: String, - label: String, - scope: String, - visibility: Boolean, - regexp: String, - searchable: Boolean, - }); - - const { field, visibility } = this.bodyParams; - const { customField } = Promise.await(findCustomFieldById({ userId: this.userId, customFieldId: field })); - - API.v1.success( - Meteor.runAsUser(this.userId, () => - Meteor.call('livechat:saveCustomField', customField ? field : undefined, { - ...this.bodyParams, - visibility: visibility ? 'visible' : 'hidden', - }), - ), - ); - } catch (e) { - return API.v1.failure(e); - } - }, - }, -); - -API.v1.addRoute('livechat/custom.fields', { - async post() { - check(this.bodyParams, { - token: String, - customFields: [ - Match.ObjectIncluding({ - key: String, - value: String, - overwrite: Boolean, - }), - ], - }); - - const { token } = this.bodyParams; - const guest = await findGuest(token); - if (!guest) { - throw new Meteor.Error('invalid-token'); - } - - const fields = await Promise.all( - this.bodyParams.customFields.map(async (customField) => { - const data = Object.assign({ token }, customField); - if (!(await Livechat.setCustomFields(data))) { - return API.v1.failure(); - } - - return { Key: customField.key, value: customField.value, overwrite: customField.overwrite }; - }), - ); - - return API.v1.success({ fields }); - }, -}); - -API.v1.addRoute( - 'livechat/custom-fields', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - async get() { - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - const { text } = this.queryParams; - - const customFields = await findLivechatCustomFields({ - text, - pagination: { - offset, - count, - sort, - }, - }); - - return API.v1.success(customFields); - }, - }, -); - -API.v1.addRoute( - 'livechat/custom-fields/:_id', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - async get() { - check(this.urlParams, { - _id: String, - }); - const { customField } = await findCustomFieldById({ customFieldId: this.urlParams._id }); - - return API.v1.success({ - customField, - }); - }, - }, -); diff --git a/apps/meteor/app/livechat/server/api/v1/customField.ts b/apps/meteor/app/livechat/server/api/v1/customField.ts new file mode 100644 index 0000000000000..63e2ba371e2e4 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/v1/customField.ts @@ -0,0 +1,91 @@ +import { isLivechatCustomFieldsProps, isPOSTLivechatCustomFieldParams, isPOSTLivechatCustomFieldsParams } from '@rocket.chat/rest-typings'; + +import { API } from '../../../../api/server'; +import { findGuest } from '../lib/livechat'; +import { Livechat } from '../../lib/Livechat'; +import { findLivechatCustomFields, findCustomFieldById } from '../lib/customFields'; + +API.v1.addRoute( + 'livechat/custom.field', + { validateParams: isPOSTLivechatCustomFieldParams }, + { + async post() { + const { token, key, value, overwrite } = this.bodyParams; + + const guest = await findGuest(token); + if (!guest) { + throw new Error('invalid-token'); + } + + if (!(await Livechat.setCustomFields({ token, key, value, overwrite }))) { + return API.v1.failure(); + } + + return API.v1.success({ field: { key, value, overwrite } }); + }, + }, +); + +API.v1.addRoute( + 'livechat/custom.fields', + { validateParams: isPOSTLivechatCustomFieldsParams }, + { + async post() { + const { token } = this.bodyParams; + const guest = await findGuest(token); + if (!guest) { + throw new Error('invalid-token'); + } + + const fields = await Promise.all( + this.bodyParams.customFields.map(async (customField) => { + const data = Object.assign({ token }, customField); + if (!(await Livechat.setCustomFields(data))) { + throw new Error('error-setting-custom-field'); + } + + return { Key: customField.key, value: customField.value, overwrite: customField.overwrite }; + }), + ); + + return API.v1.success({ fields }); + }, + }, +); + +API.v1.addRoute( + 'livechat/custom-fields', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isLivechatCustomFieldsProps }, + { + async get() { + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + const { text } = this.queryParams; + + const customFields = await findLivechatCustomFields({ + text, + pagination: { + offset, + count, + sort, + }, + }); + + return API.v1.success(customFields); + }, + }, +); + +API.v1.addRoute( + 'livechat/custom-fields/:_id', + { authRequired: true, permissionsRequired: ['view-l-room'] }, + { + async get() { + const { customField } = await findCustomFieldById({ customFieldId: this.urlParams._id }); + + return API.v1.success({ + customField, + }); + }, + }, +); diff --git a/apps/meteor/app/livechat/server/api/v1/message.js b/apps/meteor/app/livechat/server/api/v1/message.js deleted file mode 100644 index 895ffd80b7ec1..0000000000000 --- a/apps/meteor/app/livechat/server/api/v1/message.js +++ /dev/null @@ -1,331 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Match, check } from 'meteor/check'; -import { Random } from 'meteor/random'; -import { OmnichannelSourceType } from '@rocket.chat/core-typings'; -import { LivechatVisitors } from '@rocket.chat/models'; - -import { Messages, LivechatRooms } from '../../../../models/server'; -import { API } from '../../../../api/server'; -import { loadMessageHistory } from '../../../../lib'; -import { findGuest, findRoom, normalizeHttpHeaderData } from '../lib/livechat'; -import { Livechat } from '../../lib/Livechat'; -import { normalizeMessageFileUpload } from '../../../../utils/server/functions/normalizeMessageFileUpload'; -import { settings } from '../../../../settings/server'; - -API.v1.addRoute('livechat/message', { - async post() { - try { - check(this.bodyParams, { - _id: Match.Maybe(String), - token: String, - rid: String, - msg: String, - avatar: Match.Optional(String), - agent: Match.Maybe({ - agentId: String, - username: String, - }), - }); - - const { token, rid, agent, msg, avatar } = this.bodyParams; - - const guest = await findGuest(token); - if (!guest) { - throw new Meteor.Error('invalid-token'); - } - - const room = findRoom(token, rid); - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - if (!room.open) { - throw new Meteor.Error('room-closed'); - } - - if ( - settings.get('Livechat_enable_message_character_limit') && - msg.length > parseInt(settings.get('Livechat_message_character_limit')) - ) { - throw new Meteor.Error('message-length-exceeds-character-limit'); - } - - const _id = this.bodyParams._id || Random.id(); - - const sendMessage = { - guest, - message: { - _id, - rid, - msg, - avatar, - token, - }, - agent, - roomInfo: { - source: { - type: this.isWidget() ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API, - }, - }, - }; - - const result = await Livechat.sendMessage(sendMessage); - if (result) { - const message = Messages.findOneById(_id); - return API.v1.success({ message }); - } - - return API.v1.failure(); - } catch (e) { - return API.v1.failure(e); - } - }, -}); - -API.v1.addRoute('livechat/message/:_id', { - async get() { - check(this.urlParams, { - _id: String, - }); - - check(this.queryParams, { - token: String, - rid: String, - }); - - const { token, rid } = this.queryParams; - const { _id } = this.urlParams; - - const guest = await findGuest(token); - if (!guest) { - throw new Meteor.Error('invalid-token'); - } - - const room = findRoom(token, rid); - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - let message = Messages.findOneById(_id); - if (!message) { - throw new Meteor.Error('invalid-message'); - } - - if (message.file) { - message = await normalizeMessageFileUpload(message); - } - - return API.v1.success({ message }); - }, - - async put() { - check(this.urlParams, { - _id: String, - }); - - check(this.bodyParams, { - token: String, - rid: String, - msg: String, - }); - - const { token, rid } = this.bodyParams; - const { _id } = this.urlParams; - - const guest = await findGuest(token); - if (!guest) { - throw new Meteor.Error('invalid-token'); - } - - const room = findRoom(token, rid); - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - const msg = Messages.findOneById(_id); - if (!msg) { - throw new Meteor.Error('invalid-message'); - } - - const result = Livechat.updateMessage({ - guest, - message: { _id: msg._id, msg: this.bodyParams.msg }, - }); - if (result) { - let message = Messages.findOneById(_id); - if (message.file) { - message = await normalizeMessageFileUpload(message); - } - - return API.v1.success({ message }); - } - - return API.v1.failure(); - }, - async delete() { - check(this.urlParams, { - _id: String, - }); - - check(this.bodyParams, { - token: String, - rid: String, - }); - - const { token, rid } = this.bodyParams; - const { _id } = this.urlParams; - - const guest = await findGuest(token); - if (!guest) { - throw new Meteor.Error('invalid-token'); - } - - const room = findRoom(token, rid); - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - const message = Messages.findOneById(_id); - if (!message) { - throw new Meteor.Error('invalid-message'); - } - - const result = await Livechat.deleteMessage({ guest, message }); - if (result) { - return API.v1.success({ - message: { - _id, - ts: new Date().toISOString(), - }, - }); - } - - return API.v1.failure(); - }, -}); - -API.v1.addRoute('livechat/messages.history/:rid', { - async get() { - check(this.urlParams, { - rid: String, - }); - - const { offset } = this.getPaginationItems(); - const { searchText: text, token } = this.queryParams; - const { rid } = this.urlParams; - const { sort } = this.parseJsonQuery(); - - if (!token) { - throw new Meteor.Error('error-token-param-not-provided', 'The required "token" query param is missing.'); - } - - const guest = await findGuest(token); - if (!guest) { - throw new Meteor.Error('invalid-token'); - } - - const room = findRoom(token, rid); - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - let ls = undefined; - if (this.queryParams.ls) { - ls = new Date(this.queryParams.ls); - } - - let end = undefined; - if (this.queryParams.end) { - end = new Date(this.queryParams.end); - } - - let limit = 20; - if (this.queryParams.limit) { - limit = parseInt(this.queryParams.limit); - } - - const messages = loadMessageHistory({ - userId: guest._id, - rid, - end, - limit, - ls, - sort, - offset, - text, - }).messages.map((...args) => Promise.await(normalizeMessageFileUpload(...args))); - return API.v1.success({ messages }); - }, -}); - -API.v1.addRoute( - 'livechat/messages', - { authRequired: true }, - { - async post() { - if (!this.bodyParams.visitor) { - return API.v1.failure('Body param "visitor" is required'); - } - if (!this.bodyParams.visitor.token) { - return API.v1.failure('Body param "visitor.token" is required'); - } - if (!this.bodyParams.messages) { - return API.v1.failure('Body param "messages" is required'); - } - if (!(this.bodyParams.messages instanceof Array)) { - return API.v1.failure('Body param "messages" is not an array'); - } - if (this.bodyParams.messages.length === 0) { - return API.v1.failure('Body param "messages" is empty'); - } - - const visitorToken = this.bodyParams.visitor.token; - - let visitor = await LivechatVisitors.getVisitorByToken(visitorToken); - let rid; - if (visitor) { - const rooms = LivechatRooms.findOpenByVisitorToken(visitorToken).fetch(); - if (rooms && rooms.length > 0) { - rid = rooms[0]._id; - } else { - rid = Random.id(); - } - } else { - rid = Random.id(); - - const guest = this.bodyParams.visitor; - guest.connectionData = normalizeHttpHeaderData(this.request.headers); - - const visitorId = await Livechat.registerGuest(guest); - visitor = await LivechatVisitors.findOneById(visitorId); - } - - const sentMessages = this.bodyParams.messages.map((message) => { - const sendMessage = { - guest: visitor, - message: { - _id: Random.id(), - rid, - token: visitorToken, - msg: message.msg, - }, - roomInfo: { - source: { - type: this.isWidget() ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API, - }, - }, - }; - const sentMessage = Promise.await(Livechat.sendMessage(sendMessage)); - return { - username: sentMessage.u.username, - msg: sentMessage.msg, - ts: sentMessage.ts, - }; - }); - - return API.v1.success({ - messages: sentMessages, - }); - }, - }, -); diff --git a/apps/meteor/app/livechat/server/api/v1/message.ts b/apps/meteor/app/livechat/server/api/v1/message.ts new file mode 100644 index 0000000000000..2c087d167b95d --- /dev/null +++ b/apps/meteor/app/livechat/server/api/v1/message.ts @@ -0,0 +1,292 @@ +import { Random } from 'meteor/random'; +import { OmnichannelSourceType } from '@rocket.chat/core-typings'; +import { + isPOSTLivechatMessageParams, + isGETLivechatMessageIdParams, + isPUTLivechatMessageIdParams, + isDELETELivechatMessageIdParams, + isGETLivechatMessagesHistoryRidParams, + isGETLivechatMessagesParams, +} from '@rocket.chat/rest-typings'; +import { LivechatVisitors } from '@rocket.chat/models'; + +import { Messages, LivechatRooms } from '../../../../models/server'; +import { API } from '../../../../api/server'; +import { loadMessageHistory } from '../../../../lib/server'; +import { findGuest, findRoom, normalizeHttpHeaderData } from '../lib/livechat'; +import { Livechat } from '../../lib/Livechat'; +import { normalizeMessageFileUpload } from '../../../../utils/server/functions/normalizeMessageFileUpload'; +import { settings } from '../../../../settings/server'; + +API.v1.addRoute( + 'livechat/message', + { validateParams: isPOSTLivechatMessageParams }, + { + async post() { + const { token, rid, agent, msg } = this.bodyParams; + + const guest = await findGuest(token); + if (!guest) { + throw new Error('invalid-token'); + } + + const room = findRoom(token, rid); + if (!room) { + throw new Error('invalid-room'); + } + + if (!room.open) { + throw new Error('room-closed'); + } + + if ( + settings.get('Livechat_enable_message_character_limit') && + msg.length > parseInt(settings.get('Livechat_message_character_limit')) + ) { + throw new Error('message-length-exceeds-character-limit'); + } + + const _id = this.bodyParams._id || Random.id(); + + const sendMessage = { + guest, + message: { + _id, + rid, + msg, + token, + }, + agent, + roomInfo: { + source: { + type: this.isWidget() ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API, + }, + }, + }; + + const result = await Livechat.sendMessage(sendMessage); + if (result) { + const message = Messages.findOneById(_id); + return API.v1.success({ message }); + } + + return API.v1.failure(); + }, + }, +); + +API.v1.addRoute( + 'livechat/message/:_id', + { validateParams: { GET: isGETLivechatMessageIdParams, PUT: isPUTLivechatMessageIdParams, DELETE: isDELETELivechatMessageIdParams } }, + { + async get() { + const { token, rid } = this.queryParams; + const { _id } = this.urlParams; + + const guest = await findGuest(token); + if (!guest) { + throw new Error('invalid-token'); + } + + const room = findRoom(token, rid); + if (!room) { + throw new Error('invalid-room'); + } + + let message = Messages.findOneById(_id); + if (!message) { + throw new Error('invalid-message'); + } + + if (message.file) { + message = await normalizeMessageFileUpload(message); + } + + return API.v1.success({ message }); + }, + + async put() { + const { token, rid } = this.bodyParams; + const { _id } = this.urlParams; + + const guest = await findGuest(token); + if (!guest) { + throw new Error('invalid-token'); + } + + const room = findRoom(token, rid); + if (!room) { + throw new Error('invalid-room'); + } + + const msg = Messages.findOneById(_id); + if (!msg) { + throw new Error('invalid-message'); + } + + const result = Livechat.updateMessage({ + guest, + message: { _id: msg._id, msg: this.bodyParams.msg }, + }); + if (result) { + let message = Messages.findOneById(_id); + if (message.file) { + message = await normalizeMessageFileUpload(message); + } + + return API.v1.success({ message }); + } + + return API.v1.failure(); + }, + async delete() { + const { token, rid } = this.bodyParams; + const { _id } = this.urlParams; + + const guest = await findGuest(token); + if (!guest) { + throw new Error('invalid-token'); + } + + const room = findRoom(token, rid); + if (!room) { + throw new Error('invalid-room'); + } + + const message = Messages.findOneById(_id); + if (!message) { + throw new Error('invalid-message'); + } + + const result = await Livechat.deleteMessage({ guest, message }); + if (result) { + return API.v1.success({ + message: { + _id, + ts: new Date().toISOString(), + }, + }); + } + + return API.v1.failure(); + }, + }, +); + +API.v1.addRoute( + 'livechat/messages.history/:rid', + { validateParams: isGETLivechatMessagesHistoryRidParams }, + { + async get() { + const { offset } = this.getPaginationItems(); + const { searchText: text, token } = this.queryParams; + const { rid } = this.urlParams; + const { sort } = this.parseJsonQuery(); + + if (!token) { + throw new Error('error-token-param-not-provided'); + } + + const guest = await findGuest(token); + if (!guest) { + throw new Error('invalid-token'); + } + + const room = findRoom(token, rid); + if (!room) { + throw new Error('invalid-room'); + } + + let ls = undefined; + if (this.queryParams.ls) { + ls = new Date(this.queryParams.ls); + } + + let end = undefined; + if (this.queryParams.end) { + end = new Date(this.queryParams.end); + } + + let limit = 20; + if (this.queryParams.limit) { + limit = parseInt(`${this.queryParams.limit}`, 10); + } + + const messages = await Promise.all( + loadMessageHistory({ + userId: guest._id, + rid, + // @ts-expect-error -- typings on loadMessageHistory are wrong + end, + limit, + // @ts-expect-error -- typings on loadMessageHistory are wrong + ls, + sort, + offset, + text, + }).messages.map((message) => normalizeMessageFileUpload(message)), + ); + return API.v1.success({ messages }); + }, + }, +); + +API.v1.addRoute( + 'livechat/messages', + { authRequired: true, validateParams: isGETLivechatMessagesParams }, + { + async post() { + const visitorToken = this.bodyParams.visitor.token; + + let visitor = await LivechatVisitors.getVisitorByToken(visitorToken, {}); + let rid: string; + if (visitor) { + const rooms = LivechatRooms.findOpenByVisitorToken(visitorToken).fetch(); + if (rooms && rooms.length > 0) { + rid = rooms[0]._id; + } else { + rid = Random.id(); + } + } else { + rid = Random.id(); + + const guest: typeof this.bodyParams.visitor & { connectionData?: unknown } = this.bodyParams.visitor; + guest.connectionData = normalizeHttpHeaderData(this.request.headers); + + // @ts-expect-error -- Typings on registerGuest are wrong + const visitorId = await Livechat.registerGuest(guest); + visitor = await LivechatVisitors.findOneById(visitorId); + } + + const sentMessages = await Promise.all( + this.bodyParams.messages.map(async (message) => { + const sendMessage = { + guest: visitor, + message: { + _id: Random.id(), + rid, + token: visitorToken, + msg: message.msg, + }, + roomInfo: { + source: { + type: this.isWidget() ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API, + }, + }, + }; + // @ts-expect-error -- Typings on sendMessage are wrong + const sentMessage = await Livechat.sendMessage(sendMessage); + return { + username: sentMessage.u.username, + msg: sentMessage.msg, + ts: sentMessage.ts, + }; + }), + ); + + return API.v1.success({ + messages: sentMessages, + }); + }, + }, +); diff --git a/apps/meteor/app/livechat/server/api/v1/offlineMessage.js b/apps/meteor/app/livechat/server/api/v1/offlineMessage.js deleted file mode 100644 index 8264228c97e7f..0000000000000 --- a/apps/meteor/app/livechat/server/api/v1/offlineMessage.js +++ /dev/null @@ -1,28 +0,0 @@ -import { Match, check } from 'meteor/check'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; - -import { API } from '../../../../api/server'; -import { Livechat } from '../../lib/Livechat'; - -API.v1.addRoute('livechat/offline.message', { - post() { - try { - check(this.bodyParams, { - name: String, - email: String, - message: String, - department: Match.Maybe(String), - host: Match.Maybe(String), - }); - - const { name, email, message, department, host } = this.bodyParams; - if (!Livechat.sendOfflineMessage({ name, email, message, department, host })) { - return API.v1.failure({ message: TAPi18n.__('Error_sending_livechat_offline_message') }); - } - - return API.v1.success({ message: TAPi18n.__('Livechat_offline_message_sent') }); - } catch (e) { - return API.v1.failure(e); - } - }, -}); diff --git a/apps/meteor/app/livechat/server/api/v1/offlineMessage.ts b/apps/meteor/app/livechat/server/api/v1/offlineMessage.ts new file mode 100644 index 0000000000000..6fee3e7fc1ee8 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/v1/offlineMessage.ts @@ -0,0 +1,20 @@ +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import { isPOSTLivechatOfflineMessageParams } from '@rocket.chat/rest-typings'; + +import { API } from '../../../../api/server'; +import { Livechat } from '../../lib/Livechat'; + +API.v1.addRoute( + 'livechat/offline.message', + { validateParams: isPOSTLivechatOfflineMessageParams }, + { + async post() { + const { name, email, message, department, host } = this.bodyParams; + if (!Livechat.sendOfflineMessage({ name, email, message, department, host })) { + return API.v1.failure({ message: TAPi18n.__('Error_sending_livechat_offline_message') }); + } + + return API.v1.success({ message: TAPi18n.__('Livechat_offline_message_sent') }); + }, + }, +); diff --git a/apps/meteor/app/livechat/server/api/v1/pageVisited.js b/apps/meteor/app/livechat/server/api/v1/pageVisited.js deleted file mode 100644 index ea6c05e2ce70a..0000000000000 --- a/apps/meteor/app/livechat/server/api/v1/pageVisited.js +++ /dev/null @@ -1,30 +0,0 @@ -import { Match, check } from 'meteor/check'; -import _ from 'underscore'; - -import { API } from '../../../../api/server'; -import { Livechat } from '../../lib/Livechat'; - -API.v1.addRoute('livechat/page.visited', { - post() { - check(this.bodyParams, { - token: String, - rid: Match.Maybe(String), - pageInfo: Match.ObjectIncluding({ - change: String, - title: String, - location: Match.ObjectIncluding({ - href: String, - }), - }), - }); - - const { token, rid, pageInfo } = this.bodyParams; - const obj = Livechat.savePageHistory(token, rid, pageInfo); - if (obj) { - const page = _.pick(obj, 'msg', 'navigation'); - return API.v1.success({ page }); - } - - return API.v1.success(); - }, -}); diff --git a/apps/meteor/app/livechat/server/api/v1/pageVisited.ts b/apps/meteor/app/livechat/server/api/v1/pageVisited.ts new file mode 100644 index 0000000000000..10c1fba01e318 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/v1/pageVisited.ts @@ -0,0 +1,22 @@ +import { isPOSTLivechatPageVisitedParams } from '@rocket.chat/rest-typings'; + +import { API } from '../../../../api/server'; +import { Livechat } from '../../lib/Livechat'; + +API.v1.addRoute( + 'livechat/page.visited', + { validateParams: isPOSTLivechatPageVisitedParams }, + { + async post() { + const { token, rid, pageInfo } = this.bodyParams; + const obj = Livechat.savePageHistory(token, rid, pageInfo); + if (obj) { + // @ts-expect-error -- typings on savePageHistory are wrong + const { msg, navigation } = obj; + return API.v1.success({ page: { msg, navigation } }); + } + + return API.v1.success(); + }, + }, +); diff --git a/apps/meteor/app/livechat/server/api/v1/room.js b/apps/meteor/app/livechat/server/api/v1/room.js deleted file mode 100644 index cbbbaaf4db568..0000000000000 --- a/apps/meteor/app/livechat/server/api/v1/room.js +++ /dev/null @@ -1,305 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Match, check } from 'meteor/check'; -import { Random } from 'meteor/random'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { OmnichannelSourceType } from '@rocket.chat/core-typings'; -import { LivechatVisitors, Users } from '@rocket.chat/models'; -import { isLiveChatRoomForwardProps } from '@rocket.chat/rest-typings'; - -import { settings as rcSettings } from '../../../../settings/server'; -import { Messages, LivechatRooms } from '../../../../models/server'; -import { API } from '../../../../api/server'; -import { findGuest, findRoom, getRoom, settings, findAgent, onCheckRoomParams } from '../lib/livechat'; -import { Livechat } from '../../lib/Livechat'; -import { normalizeTransferredByData } from '../../lib/Helper'; -import { findVisitorInfo } from '../lib/visitors'; -import { canAccessRoom } from '../../../../authorization/server'; -import { addUserToRoom } from '../../../../lib/server/functions'; - -API.v1.addRoute('livechat/room', { - async get() { - const defaultCheckParams = { - token: String, - rid: Match.Maybe(String), - agentId: Match.Maybe(String), - }; - - const extraCheckParams = onCheckRoomParams(defaultCheckParams); - - check(this.queryParams, extraCheckParams); - - const { token, rid: roomId, agentId, ...extraParams } = this.queryParams; - - const guest = await findGuest(token); - if (!guest) { - throw new Meteor.Error('invalid-token'); - } - - let room; - if (!roomId) { - room = LivechatRooms.findOneOpenByVisitorToken(token, {}); - if (room) { - return API.v1.success({ room, newRoom: false }); - } - - let agent; - const agentObj = agentId && findAgent(agentId); - if (agentObj) { - const { username } = agentObj; - agent = { agentId, username }; - } - - const rid = Random.id(); - const roomInfo = { - source: { - type: this.isWidget() ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API, - }, - }; - - room = await getRoom({ guest, rid, agent, roomInfo, extraParams }); - return API.v1.success(room); - } - - room = LivechatRooms.findOneOpenByRoomIdAndVisitorToken(roomId, token, {}); - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - return API.v1.success({ room, newRoom: false }); - }, -}); - -API.v1.addRoute('livechat/room.close', { - async post() { - try { - check(this.bodyParams, { - rid: String, - token: String, - }); - - const { rid, token } = this.bodyParams; - - const visitor = await findGuest(token); - if (!visitor) { - throw new Meteor.Error('invalid-token'); - } - - const room = findRoom(token, rid); - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - if (!room.open) { - throw new Meteor.Error('room-closed'); - } - - const language = rcSettings.get('Language') || 'en'; - const comment = TAPi18n.__('Closed_by_visitor', { lng: language }); - - if (!Livechat.closeRoom({ visitor, room, comment })) { - return API.v1.failure(); - } - - return API.v1.success({ rid, comment }); - } catch (e) { - return API.v1.failure(e); - } - }, -}); - -API.v1.addRoute('livechat/room.transfer', { - async post() { - try { - check(this.bodyParams, { - rid: String, - token: String, - department: String, - }); - - const { rid, token, department } = this.bodyParams; - - const guest = await findGuest(token); - if (!guest) { - throw new Meteor.Error('invalid-token'); - } - - let room = findRoom(token, rid); - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - // update visited page history to not expire - Messages.keepHistoryForToken(token); - - const { _id, username, name } = guest; - const transferredBy = normalizeTransferredByData({ _id, username, name, userType: 'visitor' }, room); - - if (!(await Livechat.transfer(room, guest, { roomId: rid, departmentId: department, transferredBy }))) { - return API.v1.failure(); - } - - room = findRoom(token, rid); - return API.v1.success({ room }); - } catch (e) { - return API.v1.failure(e); - } - }, -}); - -API.v1.addRoute('livechat/room.survey', { - async post() { - check(this.bodyParams, { - rid: String, - token: String, - data: [ - Match.ObjectIncluding({ - name: String, - value: String, - }), - ], - }); - - const { rid, token, data } = this.bodyParams; - - const visitor = await findGuest(token); - if (!visitor) { - throw new Meteor.Error('invalid-token'); - } - - const room = findRoom(token, rid); - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - const config = await settings(); - if (!config.survey || !config.survey.items || !config.survey.values) { - throw new Meteor.Error('invalid-livechat-config'); - } - - const updateData = {}; - for (const item of data) { - if ((config.survey.items.includes(item.name) && config.survey.values.includes(item.value)) || item.name === 'additionalFeedback') { - updateData[item.name] = item.value; - } - } - - if (Object.keys(updateData).length === 0) { - throw new Meteor.Error('invalid-data'); - } - - if (!LivechatRooms.updateSurveyFeedbackById(room._id, updateData)) { - return API.v1.failure(); - } - - return API.v1.success({ rid, data: updateData }); - }, -}); - -API.v1.addRoute( - 'livechat/room.forward', - { authRequired: true, permissionsRequired: ['view-l-room', 'transfer-livechat-guest'], validateParams: isLiveChatRoomForwardProps }, - { - async post() { - const transferData = this.bodyParams; - - const room = await LivechatRooms.findOneById(this.bodyParams.roomId); - if (!room || room.t !== 'l') { - throw new Error('error-invalid-room', 'Invalid room'); - } - - if (!room.open) { - throw new Error('This_conversation_is_already_closed'); - } - - const guest = await LivechatVisitors.findOneById(room.v && room.v._id); - transferData.transferredBy = normalizeTransferredByData(Meteor.user() || {}, room); - if (transferData.userId) { - const userToTransfer = await Users.findOneById(transferData.userId); - transferData.transferredTo = { - _id: userToTransfer._id, - username: userToTransfer.username, - name: userToTransfer.name, - }; - } - - const chatForwardedResult = await Livechat.transfer(room, guest, transferData); - - return chatForwardedResult ? API.v1.success() : API.v1.failure(); - }, - }, -); - -API.v1.addRoute( - 'livechat/room.visitor', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - put() { - try { - check(this.bodyParams, { - rid: String, - oldVisitorId: String, - newVisitorId: String, - }); - - const { rid, newVisitorId, oldVisitorId } = this.bodyParams; - - const { visitor } = Promise.await(findVisitorInfo({ userId: this.userId, visitorId: newVisitorId })); - if (!visitor) { - throw new Meteor.Error('invalid-visitor'); - } - - let room = LivechatRooms.findOneById(rid, { _id: 1 }); // TODO: check _id - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - const { v: { _id: roomVisitorId } = {} } = room; // TODO: v it will be undefined - if (roomVisitorId !== oldVisitorId) { - throw new Meteor.Error('invalid-room-visitor'); - } - - room = Livechat.changeRoomVisitor(this.userId, rid, visitor); - - return API.v1.success({ room }); - } catch (e) { - return API.v1.failure(e); - } - }, - }, -); - -API.v1.addRoute( - 'livechat/room.join', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - get() { - try { - check(this.queryParams, { roomId: String }); - - const { roomId } = this.queryParams; - - const { user } = this; - - if (!user) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'joinRoom' }); - } - - const room = LivechatRooms.findOneById(roomId); - - if (!room) { - throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'joinRoom' }); - } - - if (!canAccessRoom(room, user)) { - throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'joinRoom' }); - } - - addUserToRoom(roomId, user); - - return API.v1.success(); - } catch (e) { - return API.v1.failure(e); - } - }, - }, -); diff --git a/apps/meteor/app/livechat/server/api/v1/room.ts b/apps/meteor/app/livechat/server/api/v1/room.ts new file mode 100644 index 0000000000000..8b1925e6fc320 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/v1/room.ts @@ -0,0 +1,445 @@ +import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; +import { Random } from 'meteor/random'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import type { ILivechatAgent, IOmnichannelRoom, IUser } from '@rocket.chat/core-typings'; +import { isOmnichannelRoom, OmnichannelSourceType } from '@rocket.chat/core-typings'; +import { LivechatVisitors, Users, LivechatRooms as LivechatRoomsRaw, Subscriptions } from '@rocket.chat/models'; +import { + isLiveChatRoomForwardProps, + isPOSTLivechatRoomCloseParams, + isPOSTLivechatRoomTransferParams, + isPOSTLivechatRoomSurveyParams, + isLiveChatRoomJoinProps, + isPUTLivechatRoomVisitorParams, + isLiveChatRoomSaveInfoProps, + isPOSTLivechatRoomCloseByUserParams, +} from '@rocket.chat/rest-typings'; + +import { settings as rcSettings } from '../../../../settings/server'; +import { Messages, LivechatRooms } from '../../../../models/server'; +import { API } from '../../../../api/server'; +import { findGuest, findRoom, getRoom, settings, findAgent, onCheckRoomParams } from '../lib/livechat'; +import { Livechat } from '../../lib/Livechat'; +import { Livechat as LivechatTyped } from '../../lib/LivechatTyped'; +import { normalizeTransferredByData } from '../../lib/Helper'; +import { findVisitorInfo } from '../lib/visitors'; +import { canAccessRoom, hasPermission } from '../../../../authorization/server'; +import { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission'; +import { addUserToRoom } from '../../../../lib/server/functions'; +import { apiDeprecationLogger } from '../../../../lib/server/lib/deprecationWarningLogger'; +import { deprecationWarning } from '../../../../api/server/helpers/deprecationWarning'; +import { callbacks } from '../../../../../lib/callbacks'; +import type { CloseRoomParams } from '../../lib/LivechatTyped.d'; + +const isAgentWithInfo = (agentObj: ILivechatAgent | { hiddenInfo: true }): agentObj is ILivechatAgent => !('hiddenInfo' in agentObj); + +API.v1.addRoute('livechat/room', { + async get() { + // I'll temporary use check for validation, as validateParams doesnt support what's being done here + const extraCheckParams = onCheckRoomParams({ + token: String, + rid: Match.Maybe(String), + agentId: Match.Maybe(String), + }); + + check(this.queryParams, extraCheckParams); + + const { token, rid: roomId, agentId, ...extraParams } = this.queryParams; + + const guest = token && (await findGuest(token)); + if (!guest) { + throw new Error('invalid-token'); + } + + let room: IOmnichannelRoom; + if (!roomId) { + room = LivechatRooms.findOneOpenByVisitorToken(token, {}); + if (room) { + return API.v1.success({ room, newRoom: false }); + } + + let agent; + const agentObj = agentId && findAgent(agentId); + if (agentObj) { + if (isAgentWithInfo(agentObj)) { + const { username = undefined } = agentObj; + agent = { agentId, username }; + } else { + agent = { agentId }; + } + } + + const rid = Random.id(); + const roomInfo = { + source: { + type: this.isWidget() ? OmnichannelSourceType.WIDGET : OmnichannelSourceType.API, + }, + }; + + const newRoom = await getRoom({ guest, rid, agent, roomInfo, extraParams }); + return API.v1.success(newRoom); + } + + room = LivechatRooms.findOneOpenByRoomIdAndVisitorToken(roomId, token, {}); + if (!room) { + throw new Error('invalid-room'); + } + + return API.v1.success({ room, newRoom: false }); + }, +}); + +// Note: use this route if a visitor is closing a room +// If a RC user(like eg agent) is closing a room, use the `livechat/room.closeByUser` route +API.v1.addRoute( + 'livechat/room.close', + { validateParams: isPOSTLivechatRoomCloseParams }, + { + async post() { + const { rid, token } = this.bodyParams; + + const visitor = await findGuest(token); + if (!visitor) { + throw new Error('invalid-token'); + } + + const room = findRoom(token, rid); + if (!room) { + throw new Error('invalid-room'); + } + + if (!room.open) { + throw new Error('room-closed'); + } + + const language = rcSettings.get('Language') || 'en'; + const comment = TAPi18n.__('Closed_by_visitor', { lng: language }); + + const options: CloseRoomParams['options'] = {}; + if (room.servedBy) { + const servingAgent: Pick | null = + await Users.findOneById(room.servedBy._id, { + projection: { + name: 1, + username: 1, + utcOffset: 1, + settings: 1, + language: 1, + }, + }); + + if (servingAgent?.settings?.preferences?.omnichannelTranscriptPDF) { + options.pdfTranscript = { + requestedBy: servingAgent._id, + }; + } + + // We'll send the transcript by email only if the setting is disabled (that means, we're not asking the user if he wants to receive the transcript by email) + // And the agent has the preference enabled to send the transcript by email and the visitor has an email address + // When Livechat_enable_transcript is enabled, the email will be sent via livechat/transcript route + if ( + !rcSettings.get('Livechat_enable_transcript') && + servingAgent?.settings?.preferences?.omnichannelTranscriptEmail && + visitor.visitorEmails?.length && + visitor.visitorEmails?.[0]?.address + ) { + const visitorEmail = visitor.visitorEmails?.[0]?.address; + + const language = servingAgent.language || rcSettings.get('Language') || 'en'; + const t = (s: string): string => TAPi18n.__(s, { lng: language }); + const subject = t('Transcript_of_your_livechat_conversation'); + + options.emailTranscript = { + sendToVisitor: true, + requestData: { + email: visitorEmail, + requestedAt: new Date(), + requestedBy: servingAgent, + subject, + }, + }; + } + } + + await LivechatTyped.closeRoom({ visitor, room, comment, options }); + + return API.v1.success({ rid, comment }); + }, + }, +); + +API.v1.addRoute( + 'livechat/room.closeByUser', + { + validateParams: isPOSTLivechatRoomCloseByUserParams, + authRequired: true, + permissionsRequired: ['close-livechat-room'], + }, + { + async post() { + const { rid, comment, tags, generateTranscriptPdf, transcriptEmail } = this.bodyParams; + + const room = await LivechatRoomsRaw.findOneById(rid); + if (!room || !isOmnichannelRoom(room)) { + throw new Error('error-invalid-room'); + } + + if (!room.open) { + throw new Error('error-room-already-closed'); + } + + const subscription = await Subscriptions.findOneByRoomIdAndUserId(rid, this.userId, { projection: { _id: 1 } }); + if (!subscription && !(await hasPermissionAsync(this.userId, 'close-others-livechat-room'))) { + throw new Error('error-not-authorized'); + } + + const options: CloseRoomParams['options'] = { + clientAction: true, + tags, + ...(generateTranscriptPdf && { pdfTranscript: { requestedBy: this.userId } }), + ...(transcriptEmail && { + ...(transcriptEmail.sendToVisitor + ? { + emailTranscript: { + sendToVisitor: true, + requestData: { + email: transcriptEmail.requestData.email, + subject: transcriptEmail.requestData.subject, + requestedAt: new Date(), + requestedBy: this.user, + }, + }, + } + : { + emailTranscript: { + sendToVisitor: false, + }, + }), + }), + }; + + await LivechatTyped.closeRoom({ + room, + user: this.user, + options, + comment, + }); + + return API.v1.success(); + }, + }, +); + +API.v1.addRoute( + 'livechat/room.transfer', + { validateParams: isPOSTLivechatRoomTransferParams }, + { + async post() { + apiDeprecationLogger.warn('livechat/room.transfer has been deprecated. Use livechat/room.forward instead.'); + + const { rid, token, department } = this.bodyParams; + + const guest = await findGuest(token); + if (!guest) { + throw new Error('invalid-token'); + } + + let room = findRoom(token, rid); + if (!room) { + throw new Error('invalid-room'); + } + + // update visited page history to not expire + Messages.keepHistoryForToken(token); + + const { _id, username, name } = guest; + const transferredBy = normalizeTransferredByData({ _id, username, name, userType: 'visitor' }, room); + + if (!(await Livechat.transfer(room, guest, { roomId: rid, departmentId: department, transferredBy }))) { + return API.v1.failure(); + } + + room = findRoom(token, rid); + return API.v1.success( + deprecationWarning({ + endpoint: 'livechat/room.transfer', + versionWillBeRemoved: '6.0', + response: { room }, + }), + ); + }, + }, +); + +API.v1.addRoute( + 'livechat/room.survey', + { validateParams: isPOSTLivechatRoomSurveyParams }, + { + async post() { + const { rid, token, data } = this.bodyParams; + + const visitor = await findGuest(token); + if (!visitor) { + throw new Error('invalid-token'); + } + + const room = findRoom(token, rid); + if (!room) { + throw new Error('invalid-room'); + } + + const config = await settings(); + if (!config.survey || !config.survey.items || !config.survey.values) { + throw new Error('invalid-livechat-config'); + } + + const updateData: { [k: string]: string } = {}; + for (const item of data) { + if ((config.survey.items.includes(item.name) && config.survey.values.includes(item.value)) || item.name === 'additionalFeedback') { + updateData[item.name] = item.value; + } + } + + if (Object.keys(updateData).length === 0) { + throw new Error('invalid-data'); + } + + if (!LivechatRooms.updateSurveyFeedbackById(room._id, updateData)) { + return API.v1.failure(); + } + + return API.v1.success({ rid, data: updateData }); + }, + }, +); + +API.v1.addRoute( + 'livechat/room.forward', + { authRequired: true, permissionsRequired: ['view-l-room', 'transfer-livechat-guest'], validateParams: isLiveChatRoomForwardProps }, + { + async post() { + const transferData: typeof this.bodyParams & { + transferredBy?: unknown; + transferredTo?: { _id: string; username?: string; name?: string }; + } = this.bodyParams; + + const room = await LivechatRooms.findOneById(this.bodyParams.roomId); + if (!room || room.t !== 'l') { + throw new Error('error-invalid-room'); + } + + if (!room.open) { + throw new Error('This_conversation_is_already_closed'); + } + + const guest = await LivechatVisitors.findOneById(room.v?._id); + transferData.transferredBy = normalizeTransferredByData(Meteor.user() || {}, room); + if (transferData.userId) { + const userToTransfer = await Users.findOneById(transferData.userId); + if (userToTransfer) { + transferData.transferredTo = { + _id: userToTransfer._id, + username: userToTransfer.username, + name: userToTransfer.name, + }; + } + } + + const chatForwardedResult = await Livechat.transfer(room, guest, transferData); + + return chatForwardedResult ? API.v1.success() : API.v1.failure(); + }, + }, +); + +API.v1.addRoute( + 'livechat/room.visitor', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isPUTLivechatRoomVisitorParams }, + { + async put() { + // This endpoint is deprecated and will be removed in future versions. + const { rid, newVisitorId, oldVisitorId } = this.bodyParams; + + const { visitor } = await findVisitorInfo({ visitorId: newVisitorId }); + if (!visitor) { + throw new Error('invalid-visitor'); + } + + let room = LivechatRooms.findOneById(rid, { _id: 1, v: 1 }); // TODO: check _id + if (!room) { + throw new Error('invalid-room'); + } + + const { v: { _id: roomVisitorId = undefined } = {} } = room; // TODO: v it will be undefined + if (roomVisitorId !== oldVisitorId) { + throw new Error('invalid-room-visitor'); + } + + room = Livechat.changeRoomVisitor(this.userId, rid, visitor); + + return API.v1.success(deprecationWarning({ endpoint: 'livechat/room.visitor', versionWillBeRemoved: '6.0', response: { room } })); + }, + }, +); + +API.v1.addRoute( + 'livechat/room.join', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isLiveChatRoomJoinProps }, + { + async get() { + const { roomId } = this.queryParams; + + const { user } = this; + + if (!user) { + throw new Error('error-invalid-user'); + } + + const room = LivechatRooms.findOneById(roomId); + + if (!room) { + throw new Error('error-invalid-room'); + } + + if (!canAccessRoom(room, user)) { + throw new Error('error-not-allowed'); + } + + addUserToRoom(roomId, user); + + return API.v1.success(); + }, + }, +); + +API.v1.addRoute( + 'livechat/room.saveInfo', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isLiveChatRoomSaveInfoProps }, + { + async post() { + const { roomData, guestData } = this.bodyParams; + const room = await LivechatRooms.findOneById(roomData._id); + if (!room || !isOmnichannelRoom(room)) { + throw new Error('error-invalid-room'); + } + + if ((!room.servedBy || room.servedBy._id !== this.userId) && !hasPermission(this.userId, 'save-others-livechat-room-info')) { + return API.v1.unauthorized(); + } + + if (room.sms) { + delete guestData.phone; + } + + await Promise.allSettled([Livechat.saveGuest(guestData, this.userId), Livechat.saveRoomInfo(roomData)]); + + callbacks.run('livechat.saveInfo', LivechatRooms.findOneById(roomData._id), { + user: this.user, + oldRoom: room, + }); + + return API.v1.success(); + }, + }, +); diff --git a/apps/meteor/app/livechat/server/api/v1/transcript.js b/apps/meteor/app/livechat/server/api/v1/transcript.js deleted file mode 100644 index 8357a730816ae..0000000000000 --- a/apps/meteor/app/livechat/server/api/v1/transcript.js +++ /dev/null @@ -1,60 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { check } from 'meteor/check'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; - -import { API } from '../../../../api/server'; -import { Livechat } from '../../lib/Livechat'; -import { hasPermission } from '../../../../authorization'; - -API.v1.addRoute('livechat/transcript', { - async post() { - try { - check(this.bodyParams, { - token: String, - rid: String, - email: String, - }); - - const { token, rid, email } = this.bodyParams; - const transcript = Promise.await(Livechat.sendTranscript({ token, rid, email })); - if (!transcript) { - return API.v1.failure({ message: TAPi18n.__('Error_sending_livechat_transcript') }); - } - - return API.v1.success({ message: TAPi18n.__('Livechat_transcript_sent'), transcript }); - } catch (e) { - return API.v1.failure(e); - } - }, -}); - -API.v1.addRoute( - 'livechat/gettranscript', - { authRequired: true }, - { - post() { - try { - check(this.bodyParams, { - token: String, - rid: String, - }); - - const { token, rid } = this.bodyParams; - - if (!hasPermission(this.userId, 'send-omnichannel-chat-transcript')) { - throw new Meteor.Error('not-authorized', 'Not Authorized'); - } - - const response = Livechat.getTranscript({ token, rid }); - if (!response) { - return API.v1.failure({ message: TAPi18n.__('Error_sending_livechat_transcript') }); - } - - return API.v1.success(response); - } catch (e) { - Livechat.logger.error(e); - return API.v1.failure(e); - } - }, - }, -); diff --git a/apps/meteor/app/livechat/server/api/v1/transcript.ts b/apps/meteor/app/livechat/server/api/v1/transcript.ts new file mode 100644 index 0000000000000..82b1bf7dde432 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/v1/transcript.ts @@ -0,0 +1,56 @@ +import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import { isPOSTLivechatTranscriptParams } from '@rocket.chat/rest-typings'; + +import { API } from '../../../../api/server'; +import { Livechat } from '../../lib/LivechatTyped'; + +API.v1.addRoute( + 'livechat/transcript', + { validateParams: isPOSTLivechatTranscriptParams }, + { + async post() { + const { token, rid, email } = this.bodyParams; + const transcript = Promise.await(Livechat.sendTranscript({ token, rid, email })); + if (!transcript) { + return API.v1.failure({ message: TAPi18n.__('Error_sending_livechat_transcript') }); + } + + return API.v1.success({ message: TAPi18n.__('Livechat_transcript_sent'), transcript }); + } catch (e) { + return API.v1.failure(e); + } + }, +}); + +API.v1.addRoute( + 'livechat/gettranscript', + { authRequired: true }, + { + post() { + try { + check(this.bodyParams, { + token: String, + rid: String, + }); + + const { token, rid } = this.bodyParams; + + if (!hasPermission(this.userId, 'send-omnichannel-chat-transcript')) { + throw new Meteor.Error('not-authorized', 'Not Authorized'); + } + + const response = Livechat.getTranscript({ token, rid }); + if (!response) { + return API.v1.failure({ message: TAPi18n.__('Error_sending_livechat_transcript') }); + } + + return API.v1.success(response); + } catch (e) { + Livechat.logger.error(e); + return API.v1.failure(e); + } + }, + }, +); diff --git a/apps/meteor/app/livechat/server/api/v1/transfer.js b/apps/meteor/app/livechat/server/api/v1/transfer.js deleted file mode 100644 index 726906330bb37..0000000000000 --- a/apps/meteor/app/livechat/server/api/v1/transfer.js +++ /dev/null @@ -1,39 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { check } from 'meteor/check'; - -import { LivechatRooms } from '../../../../models/server'; -import { API } from '../../../../api/server'; -import { findLivechatTransferHistory } from '../lib/transfer'; - -API.v1.addRoute( - 'livechat/transfer.history/:rid', - { authRequired: true, permissionsRequired: ['view-livechat-rooms'] }, - { - async get() { - check(this.urlParams, { - rid: String, - }); - - const { rid } = this.urlParams; - - const room = LivechatRooms.findOneById(rid, { _id: 1 }); - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - const { offset, count } = this.getPaginationItems(); - const { sort } = this.parseJsonQuery(); - - const history = await findLivechatTransferHistory({ - rid, - pagination: { - offset, - count, - sort, - }, - }); - - return API.v1.success(history); - }, - }, -); diff --git a/apps/meteor/app/livechat/server/api/v1/transfer.ts b/apps/meteor/app/livechat/server/api/v1/transfer.ts new file mode 100644 index 0000000000000..22a70d2053303 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/v1/transfer.ts @@ -0,0 +1,32 @@ +import { LivechatRooms } from '../../../../models/server'; +import { API } from '../../../../api/server'; +import { findLivechatTransferHistory } from '../lib/transfer'; + +API.v1.addRoute( + 'livechat/transfer.history/:rid', + { authRequired: true, permissionsRequired: ['view-livechat-rooms'] }, + { + async get() { + const { rid } = this.urlParams; + + const room = LivechatRooms.findOneById(rid, { _id: 1 }); + if (!room) { + throw new Error('invalid-room'); + } + + const { offset, count } = this.getPaginationItems(); + const { sort } = this.parseJsonQuery(); + + const history = await findLivechatTransferHistory({ + rid, + pagination: { + offset, + count, + sort, + }, + }); + + return API.v1.success(history); + }, + }, +); diff --git a/apps/meteor/app/livechat/server/api/v1/videoCall.js b/apps/meteor/app/livechat/server/api/v1/videoCall.js deleted file mode 100644 index ab3fb0f4578ab..0000000000000 --- a/apps/meteor/app/livechat/server/api/v1/videoCall.js +++ /dev/null @@ -1,116 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Match, check } from 'meteor/check'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { Settings } from '@rocket.chat/models'; - -import { Messages, Rooms } from '../../../../models'; -import { settings as rcSettings } from '../../../../settings/server'; -import { API } from '../../../../api/server'; -import { settings } from '../lib/livechat'; -import { canSendMessage } from '../../../../authorization'; -import { Livechat } from '../../lib/Livechat'; -import { Logger } from '../../../../logger'; - -const logger = new Logger('LivechatVideoCallApi'); - -API.v1.addRoute( - 'livechat/webrtc.call', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - async get() { - try { - check(this.queryParams, { - rid: Match.Maybe(String), - }); - - const room = canSendMessage(this.queryParams.rid, { - uid: this.userId, - username: this.user.username, - type: this.user.type, - }); - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - const webrtcCallingAllowed = rcSettings.get('WebRTC_Enabled') === true && rcSettings.get('Omnichannel_call_provider') === 'WebRTC'; - if (!webrtcCallingAllowed) { - throw new Meteor.Error('webRTC calling not enabled'); - } - - const config = await settings(); - if (!config.theme || !config.theme.actionLinks || !config.theme.actionLinks.webrtc) { - throw new Meteor.Error('invalid-livechat-config'); - } - - let { callStatus } = room; - - if (!callStatus || callStatus === 'ended' || callStatus === 'declined') { - await Settings.incrementValueById('WebRTC_Calls_Count'); - callStatus = 'ringing'; - await Rooms.setCallStatusAndCallStartTime(room._id, callStatus); - await Messages.createWithTypeRoomIdMessageAndUser( - 'livechat_webrtc_video_call', - room._id, - TAPi18n.__('Join_my_room_to_start_the_video_call'), - this.user, - { - actionLinks: config.theme.actionLinks.webrtc, - }, - ); - } - const videoCall = { - rid: room._id, - provider: 'webrtc', - callStatus, - }; - return API.v1.success({ videoCall }); - } catch (e) { - logger.error(e); - return API.v1.failure(e); - } - }, - }, -); - -API.v1.addRoute( - 'livechat/webrtc.call/:callId', - { authRequired: true, permissionsRequired: ['view-l-room'] }, - { - put() { - try { - check(this.urlParams, { - callId: String, - }); - - check(this.bodyParams, { - rid: Match.Maybe(String), - status: Match.Maybe(String), - }); - - const { callId } = this.urlParams; - const { rid, status } = this.bodyParams; - - const room = canSendMessage(rid, { - uid: this.userId, - username: this.user.username, - type: this.user.type, - }); - if (!room) { - throw new Meteor.Error('invalid-room'); - } - - const call = Promise.await(Messages.findOneById(callId)); - if (!call || call.t !== 'livechat_webrtc_video_call') { - throw new Meteor.Error('invalid-callId'); - } - - Livechat.updateCallStatus(callId, rid, status, this.user); - - return API.v1.success({ status }); - } catch (e) { - logger.error(e); - return API.v1.failure(e); - } - }, - }, -); diff --git a/apps/meteor/app/livechat/server/api/v1/videoCall.ts b/apps/meteor/app/livechat/server/api/v1/videoCall.ts new file mode 100644 index 0000000000000..d7b57536d216c --- /dev/null +++ b/apps/meteor/app/livechat/server/api/v1/videoCall.ts @@ -0,0 +1,97 @@ +import { isGETWebRTCCall, isPUTWebRTCCallId } from '@rocket.chat/rest-typings'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import { Settings } from '@rocket.chat/models'; + +import { Messages, Rooms } from '../../../../models/server'; +import { settings as rcSettings } from '../../../../settings/server'; +import { API } from '../../../../api/server'; +import { settings } from '../lib/livechat'; +import { canSendMessage } from '../../../../authorization/server'; +import { Livechat } from '../../lib/Livechat'; + +API.v1.addRoute( + 'livechat/webrtc.call', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isGETWebRTCCall }, + { + async get() { + const room = canSendMessage( + this.queryParams.rid, + { + uid: this.userId, + username: this.user.username, + type: this.user.type, + }, + {}, + ); + if (!room) { + throw new Error('invalid-room'); + } + + const webrtcCallingAllowed = rcSettings.get('WebRTC_Enabled') === true && rcSettings.get('Omnichannel_call_provider') === 'WebRTC'; + if (!webrtcCallingAllowed) { + throw new Error('webRTC calling not enabled'); + } + + const config = await settings(); + if (!config.theme || !config.theme.actionLinks || !config.theme.actionLinks.webrtc) { + throw new Error('invalid-livechat-config'); + } + + let { callStatus } = room; + + if (!callStatus || callStatus === 'ended' || callStatus === 'declined') { + await Settings.incrementValueById('WebRTC_Calls_Count'); + callStatus = 'ringing'; + await Rooms.setCallStatusAndCallStartTime(room._id, callStatus); + await Messages.createWithTypeRoomIdMessageAndUser( + 'livechat_webrtc_video_call', + room._id, + TAPi18n.__('Join_my_room_to_start_the_video_call'), + this.user, + { + actionLinks: config.theme.actionLinks.webrtc, + }, + ); + } + const videoCall = { + rid: room._id, + provider: 'webrtc', + callStatus, + }; + return API.v1.success({ videoCall }); + }, + }, +); + +API.v1.addRoute( + 'livechat/webrtc.call/:callId', + { authRequired: true, permissionsRequired: ['view-l-room'], validateParams: isPUTWebRTCCallId }, + { + async put() { + const { callId } = this.urlParams; + const { rid, status } = this.bodyParams; + + const room = canSendMessage( + rid, + { + uid: this.userId, + username: this.user.username, + type: this.user.type, + }, + {}, + ); + if (!room) { + throw new Error('invalid-room'); + } + + const call = await Messages.findOneById(callId); + if (!call || call.t !== 'livechat_webrtc_video_call') { + throw new Error('invalid-callId'); + } + + Livechat.updateCallStatus(callId, rid, status, this.user); + + return API.v1.success({ status }); + }, + }, +); diff --git a/apps/meteor/app/livechat/server/api/v1/visitor.ts b/apps/meteor/app/livechat/server/api/v1/visitor.ts index 2286a6b868516..f10c9fc18e06f 100644 --- a/apps/meteor/app/livechat/server/api/v1/visitor.ts +++ b/apps/meteor/app/livechat/server/api/v1/visitor.ts @@ -46,7 +46,7 @@ API.v1.addRoute('livechat/visitor', { await Promise.all(rooms.map((room: IRoom) => Livechat.saveRoomInfo(room, visitor))); } - if (customFields && customFields instanceof Array) { + if (customFields && Array.isArray(customFields)) { customFields.forEach((field) => { const customField = Promise.await(LivechatCustomField.findOneById(field.key)); if (!customField) { diff --git a/apps/meteor/app/livechat/server/api/v1/webhooks.ts b/apps/meteor/app/livechat/server/api/v1/webhooks.ts new file mode 100644 index 0000000000000..daf77676d1930 --- /dev/null +++ b/apps/meteor/app/livechat/server/api/v1/webhooks.ts @@ -0,0 +1,86 @@ +import { HTTP } from 'meteor/http'; + +import { API } from '../../../../api/server'; +import { settings } from '../../../../settings/server'; +import { Livechat } from '../../lib/Livechat'; + +API.v1.addRoute( + 'livechat/webhook.test', + { authRequired: true, permissionsRequired: ['view-livechat-webhooks'] }, + { + async post() { + const sampleData = { + type: 'LivechatSession', + _id: 'fasd6f5a4sd6f8a4sdf', + label: 'title', + topic: 'asiodojf', + createdAt: new Date(), + lastMessageAt: new Date(), + tags: ['tag1', 'tag2', 'tag3'], + customFields: { + productId: '123456', + }, + visitor: { + _id: '', + name: 'visitor name', + username: 'visitor-username', + department: 'department', + email: 'email@address.com', + phone: '192873192873', + ip: '123.456.7.89', + browser: 'Chrome', + os: 'Linux', + customFields: { + customerId: '123456', + }, + }, + agent: { + _id: 'asdf89as6df8', + username: 'agent.username', + name: 'Agent Name', + email: 'agent@email.com', + }, + messages: [ + { + username: 'visitor-username', + msg: 'message content', + ts: new Date(), + }, + { + username: 'agent.username', + agentId: 'asdf89as6df8', + msg: 'message content from agent', + ts: new Date(), + }, + ], + }; + const options = { + headers: { + 'X-RocketChat-Livechat-Token': settings.get('Livechat_secret_token'), + }, + data: sampleData, + }; + + const webhookUrl = settings.get('Livechat_webhookUrl'); + + if (!webhookUrl) { + return API.v1.failure('Webhook URL is not set'); + } + + try { + Livechat.logger.debug(`Testing webhook ${webhookUrl}`); + const response = HTTP.post(webhookUrl, options); + + Livechat.logger.debug({ response }); + if (response?.statusCode === 200) { + return API.v1.success(); + } + + throw new Error('Invalid status code'); + } catch (error) { + Livechat.logger.error(`Error testing webhook: ${error}`); + throw new Error('error-invalid-webhook-response'); + } + }, + }, +); diff --git a/apps/meteor/app/livechat/server/business-hour/AbstractBusinessHour.ts b/apps/meteor/app/livechat/server/business-hour/AbstractBusinessHour.ts index 874e27010a639..59e059acbfe49 100644 --- a/apps/meteor/app/livechat/server/business-hour/AbstractBusinessHour.ts +++ b/apps/meteor/app/livechat/server/business-hour/AbstractBusinessHour.ts @@ -2,6 +2,7 @@ import moment from 'moment-timezone'; import type { ILivechatBusinessHour, ILivechatDepartment } from '@rocket.chat/core-typings'; import type { ILivechatBusinessHoursModel, IUsersModel } from '@rocket.chat/model-typings'; import { LivechatBusinessHours, Users } from '@rocket.chat/models'; +import type { UpdateFilter } from 'mongodb'; import type { IWorkHoursCronJobsWrapper } from '../../../../server/models/raw/LivechatBusinessHours'; @@ -62,7 +63,9 @@ export abstract class AbstractBusinessHourType { businessHourData.active = Boolean(businessHourData.active); businessHourData = this.convertWorkHours(businessHourData); if (businessHourData._id) { - await this.BusinessHourRepository.updateOne({ _id: businessHourData._id }, { $set: businessHourData }); + await this.BusinessHourRepository.updateOne({ _id: businessHourData._id }, { + $set: businessHourData, + } as UpdateFilter); // TODO: Remove this cast when TypeScript is updated return businessHourData._id; } const { insertedId } = await this.BusinessHourRepository.insertOne(businessHourData); diff --git a/apps/meteor/app/livechat/server/business-hour/Helper.ts b/apps/meteor/app/livechat/server/business-hour/Helper.ts index 08c0a8e47c014..771533931f539 100644 --- a/apps/meteor/app/livechat/server/business-hour/Helper.ts +++ b/apps/meteor/app/livechat/server/business-hour/Helper.ts @@ -57,7 +57,7 @@ export const openBusinessHourDefault = async (): Promise => { }; export const createDefaultBusinessHourIfNotExists = async (): Promise => { - if ((await LivechatBusinessHours.find({ type: LivechatBusinessHourTypes.DEFAULT }).count()) === 0) { + if ((await LivechatBusinessHours.col.countDocuments({ type: LivechatBusinessHourTypes.DEFAULT })) === 0) { await LivechatBusinessHours.insertOne(createDefaultBusinessHourRow()); } }; diff --git a/apps/meteor/app/livechat/server/config.ts b/apps/meteor/app/livechat/server/config.ts index de54e14ca1893..732d2eaa7c060 100644 --- a/apps/meteor/app/livechat/server/config.ts +++ b/apps/meteor/app/livechat/server/config.ts @@ -543,6 +543,14 @@ Meteor.startup(function () { group: 'Omnichannel', public: true, i18nLabel: 'Transcript_Enabled_Mobile', + }); + + this.add('Omnichannel_enable_department_removal', false, { + type: 'boolean', + group: 'Omnichannel', + public: true, + i18nLabel: 'Omnichannel_enable_department_removal', + alert: 'Omnichannel_enable_department_removal_alert', enableQuery: omnichannelEnabledQuery, }); @@ -582,29 +590,6 @@ Meteor.startup(function () { i18nLabel: 'Channel_name', }); - this.add('Livechat_Facebook_Enabled', false, { - type: 'boolean', - group: 'Omnichannel', - section: 'Facebook', - enableQuery: omnichannelEnabledQuery, - }); - - this.add('Livechat_Facebook_API_Key', '', { - type: 'string', - group: 'Omnichannel', - section: 'Facebook', - i18nDescription: 'If_you_dont_have_one_send_an_email_to_omni_rocketchat_to_get_yours', - enableQuery: omnichannelEnabledQuery, - }); - - this.add('Livechat_Facebook_API_Secret', '', { - type: 'string', - group: 'Omnichannel', - section: 'Facebook', - i18nDescription: 'If_you_dont_have_one_send_an_email_to_omni_rocketchat_to_get_yours', - enableQuery: omnichannelEnabledQuery, - }); - this.add('Livechat_Routing_Method', 'Auto_Selection', { type: 'select', group: 'Omnichannel', @@ -764,13 +749,10 @@ Meteor.startup(function () { section: 'Video_and_Audio_Call', values: [ { key: 'none', i18nLabel: 'None' }, - { key: 'Jitsi', i18nLabel: 'Jitsi' }, - { key: 'WebRTC', i18nLabel: 'WebRTC' }, + { key: 'default-provider', i18nLabel: 'Default Provider' }, ], i18nDescription: 'Feature_depends_on_selected_call_provider_to_be_enabled_from_administration_settings', i18nLabel: 'Call_provider', - alert: - 'The WebRTC provider is currently in alpha!
    We recommend using Firefox Browser for this feature since there are some known bugs within other browsers that still need to be fixed.
    Please report bugs to github.com/RocketChat/Rocket.Chat/issues', enableQuery: omnichannelEnabledQuery, }); diff --git a/apps/meteor/app/livechat/server/hooks/afterUserActions.ts b/apps/meteor/app/livechat/server/hooks/afterUserActions.ts new file mode 100644 index 0000000000000..57a44173e6629 --- /dev/null +++ b/apps/meteor/app/livechat/server/hooks/afterUserActions.ts @@ -0,0 +1,33 @@ +import type { IUser } from '@rocket.chat/core-typings'; +import { Users } from '@rocket.chat/models'; +import type { UsersUpdateParamsPOST } from '@rocket.chat/rest-typings'; + +import { callbacks } from '../../../../lib/callbacks'; + +type UserData = UsersUpdateParamsPOST['data'] & { _id: string }; + +const handleAgentUpdated = async (userData: UserData) => { + if (!userData?.roles?.includes('livechat-agent')) { + await Users.unsetExtension(userData._id); + } +}; + +const handleDeactivateUser = async (userData: IUser) => { + if (userData?.roles?.includes('livechat-agent')) { + await Users.unsetExtension(userData._id); + } +}; + +callbacks.add( + 'afterSaveUser', + (user: UserData) => Promise.await(handleAgentUpdated(user)), + callbacks.priority.LOW, + 'livechat-after-save-user-remove-extension', +); + +callbacks.add( + 'afterDeactivateUser', + (user: IUser) => Promise.await(handleDeactivateUser(user)), + callbacks.priority.LOW, + 'livechat-after-deactivate-user-remove-extension', +); diff --git a/apps/meteor/app/livechat/server/hooks/beforeCloseRoom.js b/apps/meteor/app/livechat/server/hooks/beforeCloseRoom.js deleted file mode 100644 index 641b2bbb7b962..0000000000000 --- a/apps/meteor/app/livechat/server/hooks/beforeCloseRoom.js +++ /dev/null @@ -1,46 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { callbacks } from '../../../../lib/callbacks'; -import { LivechatDepartment } from '../../../models/server'; - -const concatUnique = (...arrays) => [...new Set([].concat(...arrays.filter(Array.isArray)))]; - -const normalizeParams = (params, tags = []) => Object.assign(params, { extraData: { tags } }); - -callbacks.add( - 'livechat.beforeCloseRoom', - (originalParams = {}) => { - const { room, options } = originalParams; - const { departmentId, tags: optionsTags } = room; - const { clientAction, tags: oldRoomTags } = options; - const roomTags = concatUnique(oldRoomTags, optionsTags); - - if (!departmentId) { - return normalizeParams({ ...originalParams }, roomTags); - } - - const department = LivechatDepartment.findOneById(departmentId); - if (!department) { - return normalizeParams({ ...originalParams }, roomTags); - } - - const { requestTagBeforeClosingChat, chatClosingTags } = department; - const extraRoomTags = concatUnique(roomTags, chatClosingTags); - - if (!requestTagBeforeClosingChat) { - return normalizeParams({ ...originalParams }, extraRoomTags); - } - - const checkRoomTags = !clientAction || (roomTags && roomTags.length > 0); - const checkDepartmentTags = chatClosingTags && chatClosingTags.length > 0; - if (!checkRoomTags || !checkDepartmentTags) { - throw new Meteor.Error('error-tags-must-be-assigned-before-closing-chat', 'Tag(s) must be assigned before closing the chat', { - method: 'livechat.beforeCloseRoom', - }); - } - - return normalizeParams({ ...originalParams }, extraRoomTags); - }, - callbacks.priority.HIGH, - 'livechat-before-close-Room', -); diff --git a/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.js b/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.js index e3453f6e14513..4cffd99123ff3 100644 --- a/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.js +++ b/apps/meteor/app/livechat/server/hooks/processRoomAbandonment.js @@ -58,20 +58,22 @@ const getSecondsSinceLastAgentResponse = async (room, agentLastMessage) => { callbacks.add( 'livechat.closeRoom', - (room) => { + (params) => { + const { room } = params; + const closedByAgent = room.closer !== 'visitor'; const wasTheLastMessageSentByAgent = room.lastMessage && !room.lastMessage.token; if (!closedByAgent || !wasTheLastMessageSentByAgent) { - return; + return params; } const agentLastMessage = Messages.findAgentLastMessageByVisitorLastMessageTs(room._id, room.v.lastMessageTs); if (!agentLastMessage) { - return; + return params; } const secondsSinceLastAgentResponse = Promise.await(getSecondsSinceLastAgentResponse(room, agentLastMessage)); LivechatRooms.setVisitorInactivityInSecondsById(room._id, secondsSinceLastAgentResponse); - return room; + return params; }, callbacks.priority.HIGH, 'process-room-abandonment', diff --git a/apps/meteor/app/livechat/server/hooks/saveAnalyticsData.js b/apps/meteor/app/livechat/server/hooks/saveAnalyticsData.js index 1a82c6152b3e3..692040a67771a 100644 --- a/apps/meteor/app/livechat/server/hooks/saveAnalyticsData.js +++ b/apps/meteor/app/livechat/server/hooks/saveAnalyticsData.js @@ -3,10 +3,12 @@ import { isOmnichannelRoom } from '@rocket.chat/core-typings'; import { callbacks } from '../../../../lib/callbacks'; import { LivechatRooms } from '../../../models/server'; import { normalizeMessageFileUpload } from '../../../utils/server/functions/normalizeMessageFileUpload'; +import { callbackLogger } from '../lib/callbackLogger'; callbacks.add( 'afterSaveMessage', function (message, room) { + callbackLogger.debug(`Calculating Omnichannel metrics for room ${room._id}`); // check if room is livechat if (!isOmnichannelRoom(room)) { return message; @@ -19,6 +21,10 @@ callbacks.add( // if the message has a token, it was sent by the visitor if (message.token) { + // When visitor sends a mesage, most metrics wont be calculated/served. + // But, v.lq (last query) will be updated to the message time. This has to be done + // As not doing it will cause the metrics to be crazy and not have real values. + LivechatRooms.saveAnalyticsDataByRoomId(room, message); return message; } @@ -37,6 +43,7 @@ callbacks.add( const isResponseTotal = room.metrics && room.metrics.response && room.metrics.response.total; if (agentLastReply === room.ts) { + callbackLogger.debug('Calculating: first message from agent'); // first response const firstResponseDate = now; const firstResponseTime = (now.getTime() - visitorLastQuery) / 1000; @@ -58,6 +65,7 @@ callbacks.add( reactionTime, }; } else if (visitorLastQuery > agentLastReply) { + callbackLogger.debug('Calculating: visitor sent a message after agent'); // response, not first const responseTime = (now.getTime() - visitorLastQuery) / 1000; const avgResponseTime = diff --git a/apps/meteor/app/livechat/server/hooks/saveLastMessageToInquiry.ts b/apps/meteor/app/livechat/server/hooks/saveLastMessageToInquiry.ts index fe726a73a4106..2ca6567728473 100644 --- a/apps/meteor/app/livechat/server/hooks/saveLastMessageToInquiry.ts +++ b/apps/meteor/app/livechat/server/hooks/saveLastMessageToInquiry.ts @@ -8,12 +8,7 @@ import { RoutingManager } from '../lib/RoutingManager'; callbacks.add( 'afterSaveMessage', (message, room) => { - if (!isOmnichannelRoom(room)) { - return message; - } - - // skip callback if message was edited - if (isEditedMessage(message)) { + if (!isOmnichannelRoom(room) || isEditedMessage(message) || message.t) { return message; } diff --git a/apps/meteor/app/livechat/server/hooks/sendEmailTranscriptOnClose.ts b/apps/meteor/app/livechat/server/hooks/sendEmailTranscriptOnClose.ts new file mode 100644 index 0000000000000..f79aa692c052a --- /dev/null +++ b/apps/meteor/app/livechat/server/hooks/sendEmailTranscriptOnClose.ts @@ -0,0 +1,71 @@ +import type { IOmnichannelRoom } from '@rocket.chat/core-typings'; +import { isOmnichannelRoom } from '@rocket.chat/core-typings'; +import { LivechatRooms } from '@rocket.chat/models'; + +import { callbacks } from '../../../../lib/callbacks'; +import { Livechat } from '../lib/LivechatTyped'; +import type { CloseRoomParams } from '../lib/LivechatTyped.d'; + +type LivechatCloseCallbackParams = { + room: IOmnichannelRoom; + options: CloseRoomParams['options']; +}; + +const sendEmailTranscriptOnClose = async (params: LivechatCloseCallbackParams): Promise => { + const { room, options } = params; + + if (!isOmnichannelRoom(room)) { + return params; + } + + const { _id: rid, v: { token } = {} } = room; + if (!token) { + return params; + } + + const transcriptData = resolveTranscriptData(room, options); + if (!transcriptData) { + return params; + } + + const { email, subject, requestedBy: user } = transcriptData; + + await Promise.all([ + Livechat.sendTranscript({ token, rid, email, subject, user }), + LivechatRooms.unsetEmailTranscriptRequestedByRoomId(rid), + ]); + + delete room.transcriptRequest; + + return { + room, + options, + }; +}; + +const resolveTranscriptData = ( + room: IOmnichannelRoom, + options: LivechatCloseCallbackParams['options'] = {}, +): IOmnichannelRoom['transcriptRequest'] | undefined => { + const { transcriptRequest: roomTranscriptRequest } = room; + + const { emailTranscript: optionsTranscriptRequest } = options; + + // Note: options.emailTranscript will override the room.transcriptRequest check + // If options.emailTranscript is not set, then the room.transcriptRequest will be checked + if (optionsTranscriptRequest === undefined) { + return roomTranscriptRequest; + } + + if (!optionsTranscriptRequest.sendToVisitor) { + return undefined; + } + return optionsTranscriptRequest.requestData; +}; + +callbacks.add( + 'livechat.closeRoom', + (params: LivechatCloseCallbackParams) => Promise.await(sendEmailTranscriptOnClose(params)), + callbacks.priority.HIGH, + 'livechat-send-email-transcript-on-close-room', +); diff --git a/apps/meteor/app/livechat/server/hooks/sendToCRM.js b/apps/meteor/app/livechat/server/hooks/sendToCRM.js index 6dcb951b0bb2c..8eb491b5df5ff 100644 --- a/apps/meteor/app/livechat/server/hooks/sendToCRM.js +++ b/apps/meteor/app/livechat/server/hooks/sendToCRM.js @@ -64,7 +64,8 @@ function sendToCRM(type, room, includeMessages = true) { const msg = { _id: message._id, username: message.u.username, - msg: message.msg, + msg: message.msg || JSON.stringify(message.blocks), + ...(message.blocks && message.blocks.length > 0 ? { blocks: message.blocks } : {}), ts: message.ts, editedAt: message.editedAt, }; @@ -105,12 +106,15 @@ function sendToCRM(type, room, includeMessages = true) { callbacks.add( 'livechat.closeRoom', - (room) => { + (params) => { + const { room } = params; if (!settings.get('Livechat_webhook_on_close')) { - return room; + return params; } - return sendToCRM('LivechatSession', room); + sendToCRM('LivechatSession', room); + + return params; }, callbacks.priority.MEDIUM, 'livechat-send-crm-close-room', diff --git a/apps/meteor/app/livechat/server/hooks/sendToFacebook.js b/apps/meteor/app/livechat/server/hooks/sendToFacebook.js deleted file mode 100644 index 2b77c18e5b560..0000000000000 --- a/apps/meteor/app/livechat/server/hooks/sendToFacebook.js +++ /dev/null @@ -1,49 +0,0 @@ -import { isOmnichannelRoom } from '@rocket.chat/core-typings'; - -import { callbacks } from '../../../../lib/callbacks'; -import { settings } from '../../../settings/server'; -import OmniChannel from '../lib/OmniChannel'; -import { normalizeMessageFileUpload } from '../../../utils/server/functions/normalizeMessageFileUpload'; - -callbacks.add( - 'afterSaveMessage', - function (message, room) { - // skips this callback if the message was edited - if (message.editedAt) { - return message; - } - - // only send the sms by SMS if it is a livechat room with SMS set to true - if (!(isOmnichannelRoom(room) && room.facebook && room.v && room.v.token)) { - return message; - } - - if (!settings.get('Livechat_Facebook_Enabled') || !settings.get('Livechat_Facebook_API_Key')) { - return message; - } - - // if the message has a token, it was sent from the visitor, so ignore it - if (message.token) { - return message; - } - - // if the message has a type means it is a special message (like the closing comment), so skips - if (message.t) { - return message; - } - - if (message.file) { - message = Promise.await(normalizeMessageFileUpload(message)); - } - - OmniChannel.reply({ - page: room.facebook.page.id, - token: room.v.token, - text: message.msg, - }); - - return message; - }, - callbacks.priority.LOW, - 'sendMessageToFacebook', -); diff --git a/apps/meteor/app/livechat/server/hooks/sendTranscriptOnClose.js b/apps/meteor/app/livechat/server/hooks/sendTranscriptOnClose.js deleted file mode 100644 index 597d656b2f0ee..0000000000000 --- a/apps/meteor/app/livechat/server/hooks/sendTranscriptOnClose.js +++ /dev/null @@ -1,20 +0,0 @@ -import { callbacks } from '../../../../lib/callbacks'; -import { Livechat } from '../lib/Livechat'; -import { LivechatRooms } from '../../../models/server'; - -const sendTranscriptOnClose = (room) => { - const { _id: rid, transcriptRequest, v: { token } = {} } = room; - if (!transcriptRequest || !token) { - return room; - } - - const { email, subject, requestedBy: user } = transcriptRequest; - // TODO: refactor this to use normal await - Promise.await(Livechat.sendTranscript({ token, rid, email, subject, user })); - - LivechatRooms.removeTranscriptRequestByRoomId(rid); - - return LivechatRooms.findOneById(rid); -}; - -callbacks.add('livechat.closeRoom', sendTranscriptOnClose, callbacks.priority.HIGH, 'livechat-send-transcript-on-close-room'); diff --git a/apps/meteor/app/livechat/server/index.js b/apps/meteor/app/livechat/server/index.js index 3586992dd640c..f58c5ad3b506b 100644 --- a/apps/meteor/app/livechat/server/index.js +++ b/apps/meteor/app/livechat/server/index.js @@ -1,10 +1,7 @@ import './livechat'; import './config'; import './startup'; -import './visitorStatus'; -import './agentStatus'; import '../lib/messageTypes'; -import './hooks/beforeCloseRoom'; import './hooks/beforeDelegateAgent'; import './hooks/leadCapture'; import './hooks/markRoomResponded'; @@ -12,20 +9,18 @@ import './hooks/offlineMessage'; import './hooks/offlineMessageToChannel'; import './hooks/saveAnalyticsData'; import './hooks/sendToCRM'; -import './hooks/sendToFacebook'; import './hooks/processRoomAbandonment'; import './hooks/saveLastVisitorMessageTs'; import './hooks/markRoomNotResponded'; -import './hooks/sendTranscriptOnClose'; +import './hooks/sendEmailTranscriptOnClose'; import './hooks/saveContactLastChat'; import './hooks/saveLastMessageToInquiry'; +import './hooks/afterUserActions'; import './methods/addAgent'; import './methods/addManager'; import './methods/changeLivechatStatus'; -import './methods/closeByVisitor'; import './methods/closeRoom'; import './methods/discardTranscript'; -import './methods/facebook'; import './methods/getCustomFields'; import './methods/getAgentData'; import './methods/getAgentOverviewData'; diff --git a/apps/meteor/app/livechat/server/lib/Contacts.ts b/apps/meteor/app/livechat/server/lib/Contacts.ts index 80dd4c1afea96..0bcb271290592 100644 --- a/apps/meteor/app/livechat/server/lib/Contacts.ts +++ b/apps/meteor/app/livechat/server/lib/Contacts.ts @@ -1,6 +1,5 @@ import { check } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; -import s from 'underscore.string'; import type { MatchKeysAndValues, OnlyFieldsOfType } from 'mongodb'; import { LivechatVisitors, Users, LivechatRooms, LivechatCustomField } from '@rocket.chat/models'; import type { ILivechatCustomField, ILivechatVisitor, IOmnichannelRoom } from '@rocket.chat/core-typings'; @@ -32,7 +31,7 @@ export const Contacts = { }: RegisterContactProps): Promise { check(token, String); - const visitorEmail = s.trim(email).toLowerCase(); + const visitorEmail = email.trim().toLowerCase(); if (contactManager?.username) { // verify if the user exists with this username and has a livechat-agent role diff --git a/apps/meteor/app/livechat/server/lib/Departments.ts b/apps/meteor/app/livechat/server/lib/Departments.ts new file mode 100644 index 0000000000000..ec9e66093470e --- /dev/null +++ b/apps/meteor/app/livechat/server/lib/Departments.ts @@ -0,0 +1,56 @@ +import { LivechatDepartment, LivechatDepartmentAgents, LivechatRooms } from '@rocket.chat/models'; + +import { callbacks } from '../../../../lib/callbacks'; +import { Logger } from '../../../logger/server'; + +class DepartmentHelperClass { + logger = new Logger('Omnichannel:DepartmentHelper'); + + async removeDepartment(departmentId: string) { + this.logger.debug(`Removing department: ${departmentId}`); + + const department = await LivechatDepartment.findOneById(departmentId); + if (!department) { + this.logger.debug(`Department not found: ${departmentId}`); + throw new Error('error-department-not-found'); + } + + const { _id } = department; + + const ret = await LivechatDepartment.removeById(_id); + if (ret.acknowledged !== true) { + this.logger.error(`Department record not removed: ${_id}. Result from db: ${ret}`); + throw new Error('error-failed-to-delete-department'); + } + this.logger.debug(`Department record removed: ${_id}`); + + const agentsIds: string[] = await LivechatDepartmentAgents.findAgentsByDepartmentId(department._id) + .cursor.map((agent) => agent.agentId) + .toArray(); + + this.logger.debug( + `Performing post-department-removal actions: ${_id}. Removing department agents, unsetting fallback department and removing department from rooms`, + ); + + const promiseResponses = await Promise.allSettled([ + LivechatDepartmentAgents.removeByDepartmentId(_id), + LivechatDepartment.unsetFallbackDepartmentByDepartmentId(_id), + LivechatRooms.bulkRemoveDepartmentAndUnitsFromRooms(_id), + ]); + promiseResponses.forEach((response, index) => { + if (response.status === 'rejected') { + this.logger.error(`Error while performing post-department-removal actions: ${_id}. Action No: ${index}. Error:`, response.reason); + } + }); + + this.logger.debug(`Post-department-removal actions completed: ${_id}. Notifying callbacks with department and agentsIds`); + + Meteor.defer(() => { + callbacks.run('livechat.afterRemoveDepartment', { department, agentsIds }); + }); + + return ret; + } +} + +export const DepartmentHelper = new DepartmentHelperClass(); diff --git a/apps/meteor/app/livechat/server/lib/Helper.js b/apps/meteor/app/livechat/server/lib/Helper.js index f26890c35655f..fe82cb23f0db7 100644 --- a/apps/meteor/app/livechat/server/lib/Helper.js +++ b/apps/meteor/app/livechat/server/lib/Helper.js @@ -2,7 +2,9 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import { Match, check } from 'meteor/check'; import { LivechatTransferEventType } from '@rocket.chat/apps-engine/definition/livechat'; -import { OmnichannelSourceType } from '@rocket.chat/core-typings'; +import { OmnichannelSourceType, DEFAULT_SLA_CONFIG } from '@rocket.chat/core-typings'; +import { LivechatPriorityWeight } from '@rocket.chat/core-typings/src/ILivechatPriority'; +import { api } from '@rocket.chat/core-services'; import { hasRole } from '../../../authorization'; import { @@ -20,12 +22,11 @@ import { RoutingManager } from './RoutingManager'; import { callbacks } from '../../../../lib/callbacks'; import { Logger } from '../../../logger'; import { settings } from '../../../settings/server'; -import { Apps, AppEvents } from '../../../apps/server'; +import { Apps, AppEvents } from '../../../../ee/server/apps'; import { sendNotification } from '../../../lib/server'; import { sendMessage } from '../../../lib/server/functions/sendMessage'; import { queueInquiry, saveQueueInquiry } from './QueueManager'; import { validateEmail as validatorFunc } from '../../../../lib/emailValidator'; -import { api } from '../../../../server/sdk/api'; const logger = new Logger('LivechatHelper'); @@ -85,6 +86,9 @@ export const createLivechatRoom = (rid, name, guest, roomInfo = {}, extraData = alias: 'unknown', }, queuedAt: newRoomAt, + + priorityWeight: LivechatPriorityWeight.NOT_SPECIFIED, + estimatedWaitingTimeQueue: DEFAULT_SLA_CONFIG.ESTIMATED_WAITING_TIME_QUEUE, }, extraRoomInfo, ); @@ -128,27 +132,25 @@ export const createLivechatInquiry = ({ rid, name, guest, message, initialStatus logger.debug(`Creating livechat inquiry for visitor ${_id}`); - const inquiry = Object.assign( - { - rid, - name, - ts, - department, - message: msg, - status: initialStatus || 'ready', - v: { - _id, - username, - token, - status, - }, - t: 'l', - queueOrder: 1, - estimatedWaitingTimeQueue: 0, - estimatedServiceTimeAt: ts, + const inquiry = { + rid, + name, + ts, + department, + message: msg, + status: initialStatus || 'ready', + v: { + _id, + username, + token, + status, }, - extraInquiryInfo, - ); + t: 'l', + priorityWeight: LivechatPriorityWeight.NOT_SPECIFIED, + estimatedWaitingTimeQueue: DEFAULT_SLA_CONFIG.ESTIMATED_WAITING_TIME_QUEUE, + + ...extraInquiryInfo, + }; const result = LivechatInquiry.insert(inquiry); logger.debug(`Inquiry ${result} created for visitor ${_id}`); diff --git a/apps/meteor/app/livechat/server/lib/Livechat.js b/apps/meteor/app/livechat/server/lib/Livechat.js index 693e0a4a73fa3..3e4ba64d9a84b 100644 --- a/apps/meteor/app/livechat/server/lib/Livechat.js +++ b/apps/meteor/app/livechat/server/lib/Livechat.js @@ -1,3 +1,6 @@ +// Note: Please don't add any new methods to this file, since its still in js and we are migrating to ts +// Please add new methods to LivechatTyped.ts + import dns from 'dns'; import { Meteor } from 'meteor/meteor'; @@ -5,11 +8,20 @@ import { Match, check } from 'meteor/check'; import { Random } from 'meteor/random'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import { HTTP } from 'meteor/http'; -import _ from 'underscore'; -import s from 'underscore.string'; -import moment from 'moment-timezone'; import UAParser from 'ua-parser-js'; -import { Users as UsersRaw, LivechatVisitors, LivechatCustomField, Settings } from '@rocket.chat/models'; +import moment from 'moment-timezone'; +import { + Users as UsersRaw, + LivechatVisitors, + LivechatCustomField, + Settings, + LivechatRooms as LivechatRoomsRaw, + LivechatInquiry as LivechatInquiryRaw, + Subscriptions as SubscriptionsRaw, + Messages as MessagesRaw, + LivechatDepartment as LivechatDepartmentRaw, +} from '@rocket.chat/models'; +import { VideoConf, api } from '@rocket.chat/core-services'; import { QueueManager } from './QueueManager'; import { RoutingManager } from './RoutingManager'; @@ -35,13 +47,13 @@ import { updateMessage } from '../../../lib/server/functions/updateMessage'; import { deleteMessage } from '../../../lib/server/functions/deleteMessage'; import { FileUpload } from '../../../file-upload/server'; import { normalizeTransferredByData, parseAgentCustomFields, updateDepartmentAgents, validateEmail } from './Helper'; -import { Apps, AppEvents } from '../../../apps/server'; +import { Apps, AppEvents } from '../../../../ee/server/apps'; import { businessHourManager } from '../business-hour'; import { addUserRoles } from '../../../../server/lib/roles/addUserRoles'; import { removeUserFromRoles } from '../../../../server/lib/roles/removeUserFromRoles'; import { Notifications } from '../../../notifications'; -import { VideoConf } from '../../../../server/sdk'; -import { api } from '../../../../server/sdk/api'; +import { trim } from '../../../../lib/utils/stringUtils'; +import { Livechat as LivechatTyped } from './LivechatTyped'; const PDFMakePrinter = require('pdfmake/src/printer'); @@ -90,7 +102,7 @@ export const Livechat = { findGuest(token) { return LivechatVisitors.getVisitorByToken(token, { - fields: { + projection: { name: 1, username: 1, token: 1, @@ -277,7 +289,7 @@ export const Livechat = { if (guest.name) { message.alias = guest.name; } - return _.extend(sendMessage(guest, message, room), { + return Object.assign(sendMessage(guest, message, room), { newRoom, showConnecting: this.showConnecting(), }); @@ -439,7 +451,8 @@ export const Livechat = { return false; }, - async saveGuest({ _id, name, email, phone, livechatData = {} }, userId) { + async saveGuest(guestData, userId) { + const { _id, name, email, phone, livechatData = {} } = guestData; Livechat.logger.debug(`Saving data for visitor ${_id}`); const updateData = {}; @@ -462,7 +475,7 @@ export const Livechat = { if (!livechatData.hasOwnProperty(field._id)) { continue; } - const value = s.trim(livechatData[field._id]); + const value = trim(livechatData[field._id]); if (value !== '' && field.regexp !== undefined && field.regexp !== '') { const regexp = new RegExp(field.regexp); if (!regexp.test(value)) { @@ -562,21 +575,33 @@ export const Livechat = { return true; }, - removeRoom(rid) { + async removeRoom(rid) { Livechat.logger.debug(`Deleting room ${rid}`); check(rid, String); - const room = LivechatRooms.findOneById(rid); + const room = await LivechatRooms.findOneById(rid); if (!room) { throw new Meteor.Error('error-invalid-room', 'Invalid room', { method: 'livechat:removeRoom', }); } - Messages.removeByRoomId(rid); - Subscriptions.removeByRoomId(rid); - LivechatInquiry.removeByRoomId(rid); + const result = await Promise.allSettled([ + MessagesRaw.removeByRoomId(rid), + SubscriptionsRaw.removeByRoomId(rid), + LivechatInquiryRaw.removeByRoomId(rid), + LivechatRoomsRaw.removeById(rid), + ]); + Livechat.removeTypingListener(rid); - return LivechatRooms.removeById(rid); + + const errors = result.filter((r) => r.status === 'rejected').map((r) => r.reason); + if (errors.length > 0) { + this.logger.error(`Error removing room ${rid}: ${errors.join(', ')}`); + throw new Meteor.Error('error-removing-room', 'Error removing room', { + method: 'livechat:removeRoom', + errors, + }); + } }, async setCustomFields({ token, key, value, overwrite } = {}) { @@ -681,9 +706,9 @@ export const Livechat = { const fields = LivechatCustomField.findByScope('room'); for await (const field of fields) { if (!livechatData.hasOwnProperty(field._id)) { - return; + continue; } - const value = s.trim(livechatData[field._id]); + const value = trim(livechatData[field._id]); if (value !== '' && field.regexp !== undefined && field.regexp !== '') { const regexp = new RegExp(field.regexp); if (!regexp.test(value)) { @@ -719,12 +744,17 @@ export const Livechat = { } }, - closeOpenChats(userId, comment) { + async closeOpenChats(userId, comment) { Livechat.logger.debug(`Closing open chats for user ${userId}`); const user = Users.findOneById(userId); - LivechatRooms.findOpenByAgent(userId).forEach((room) => { - this.closeRoom({ user, room, comment }); + + const openChats = LivechatRooms.findOpenByAgent(userId); + const promises = []; + openChats.forEach((room) => { + promises.push(LivechatTyped.closeRoom({ user, room, comment })); }); + + await Promise.all(promises); }, forwardOpenChats(userId) { @@ -840,7 +870,7 @@ export const Livechat = { return RoutingManager.transferRoom(room, guest, transferData); }, - returnRoomAsInquiry(rid, departmentId) { + returnRoomAsInquiry(rid, departmentId, overrideTransferData = {}) { Livechat.logger.debug(`Transfering room ${rid} to ${departmentId ? 'department' : ''} queue`); const room = LivechatRooms.findOneById(rid); if (!room) { @@ -880,7 +910,7 @@ export const Livechat = { const transferredBy = normalizeTransferredByData(user, room); Livechat.logger.debug(`Transfering room ${room._id} by user ${transferredBy._id}`); - const transferData = { roomId: rid, scope: 'queue', departmentId, transferredBy }; + const transferData = { roomId: rid, scope: 'queue', departmentId, transferredBy, ...overrideTransferData }; try { this.saveTransferHistory(room, transferData); RoutingManager.unassignAgent(inquiry, departmentId); @@ -908,8 +938,8 @@ export const Livechat = { }; try { return HTTP.post(settings.get('Livechat_webhookUrl'), options); - } catch (e) { - Livechat.webhookLogger.error(`Response error on ${11 - attempts} try ->`, e); + } catch (err) { + Livechat.webhookLogger.error({ msg: `Response error on ${11 - attempts} try ->`, err }); // try 10 times after 10 seconds each attempts - 1 && Livechat.webhookLogger.warn('Will try again in 10 seconds ...'); setTimeout( @@ -1035,7 +1065,7 @@ export const Livechat = { Users.removeLivechatData(_id); this.setUserStatusLivechat(_id, 'not-available'); LivechatDepartmentAgents.removeByAgentId(_id); - Promise.await(LivechatVisitors.removeContactManagerByUsername(username)); + Promise.await(Promise.all([LivechatVisitors.removeContactManagerByUsername(username), UsersRaw.unsetExtension(_id)])); return true; } @@ -1133,74 +1163,6 @@ export const Livechat = { return updateDepartmentAgents(_id, departmentAgents, department.enabled); }, - saveDepartment(_id, departmentData, departmentAgents) { - check(_id, Match.Maybe(String)); - - const defaultValidations = { - enabled: Boolean, - name: String, - description: Match.Optional(String), - showOnRegistration: Boolean, - email: String, - showOnOfflineForm: Boolean, - requestTagBeforeClosingChat: Match.Optional(Boolean), - chatClosingTags: Match.Optional([String]), - fallbackForwardDepartment: Match.Optional(String), - }; - - // The Livechat Form department support addition/custom fields, so those fields need to be added before validating - Object.keys(departmentData).forEach((field) => { - if (!defaultValidations.hasOwnProperty(field)) { - defaultValidations[field] = Match.OneOf(String, Match.Integer, Boolean); - } - }); - - check(departmentData, defaultValidations); - check( - departmentAgents, - Match.Maybe({ - upsert: Match.Maybe(Array), - remove: Match.Maybe(Array), - }), - ); - - const { requestTagBeforeClosingChat, chatClosingTags, fallbackForwardDepartment } = departmentData; - if (requestTagBeforeClosingChat && (!chatClosingTags || chatClosingTags.length === 0)) { - throw new Meteor.Error( - 'error-validating-department-chat-closing-tags', - 'At least one closing tag is required when the department requires tag(s) on closing conversations.', - { method: 'livechat:saveDepartment' }, - ); - } - - if (_id) { - const department = LivechatDepartment.findOneById(_id); - if (!department) { - throw new Meteor.Error('error-department-not-found', 'Department not found', { - method: 'livechat:saveDepartment', - }); - } - } - - if (fallbackForwardDepartment === _id) { - throw new Meteor.Error( - 'error-fallback-department-circular', - 'Cannot save department. Circular reference between fallback department and department', - ); - } - - if (fallbackForwardDepartment && !LivechatDepartment.findOneById(fallbackForwardDepartment)) { - throw new Meteor.Error('error-fallback-department-not-found', 'Fallback department not found', { method: 'livechat:saveDepartment' }); - } - - const departmentDB = LivechatDepartment.createOrUpdateDepartment(_id, departmentData); - if (departmentDB && departmentAgents) { - updateDepartmentAgents(departmentDB._id, departmentAgents, departmentDB.enabled); - } - - return departmentDB; - }, - saveAgentInfo(_id, agentData, agentDepartments) { check(_id, Match.Maybe(String)); check(agentData, Object); @@ -1222,7 +1184,15 @@ export const Livechat = { removeDepartment(_id) { check(_id, String); - const department = LivechatDepartment.findOneById(_id, { fields: { _id: 1 } }); + const departmentRemovalEnabled = settings.get('Omnichannel_enable_department_removal'); + + if (!departmentRemovalEnabled) { + throw new Meteor.Error('department-removal-disabled', 'Department removal is disabled', { + method: 'livechat:removeDepartment', + }); + } + + const department = LivechatDepartment.findOneById(_id, { projection: { _id: 1 } }); if (!department) { throw new Meteor.Error('department-not-found', 'Department not found', { @@ -1243,6 +1213,34 @@ export const Livechat = { return ret; }, + async unarchiveDepartment(_id) { + check(_id, String); + + const department = await LivechatDepartmentRaw.findOneById(_id, { projection: { _id: 1 } }); + + if (!department) { + throw new Meteor.Error('department-not-found', 'Department not found', { + method: 'livechat:removeDepartment', + }); + } + + return LivechatDepartmentRaw.unarchiveDepartment(_id); + }, + + async archiveDepartment(_id) { + check(_id, String); + + const department = await LivechatDepartmentRaw.findOneById(_id, { projection: { _id: 1 } }); + + if (!department) { + throw new Meteor.Error('department-not-found', 'Department not found', { + method: 'livechat:removeDepartment', + }); + } + + return LivechatDepartmentRaw.archiveDepartment(_id); + }, + showConnecting() { const { showConnecting } = RoutingManager.getConfig(); return showConnecting; @@ -1401,7 +1399,7 @@ export const Livechat = { return response; }, - requestTranscript({ rid, email, subject, user }) { + async requestTranscript({ rid, email, subject, user }) { check(rid, String); check(email, String); check(subject, String); @@ -1438,7 +1436,7 @@ export const Livechat = { subject, }; - LivechatRooms.requestTranscriptByRoomId(rid, transcriptRequest); + await LivechatRoomsRaw.setEmailTranscriptRequestedByRoomId(rid, transcriptRequest); return true; }, diff --git a/apps/meteor/app/livechat/server/lib/LivechatTyped.d.ts b/apps/meteor/app/livechat/server/lib/LivechatTyped.d.ts new file mode 100644 index 0000000000000..ab71ccaf62782 --- /dev/null +++ b/apps/meteor/app/livechat/server/lib/LivechatTyped.d.ts @@ -0,0 +1,31 @@ +import type { IOmnichannelRoom, IUser, ILivechatVisitor } from '@rocket.chat/core-typings'; + +type GenericCloseRoomParams = { + room: IOmnichannelRoom; + comment?: string; + options?: { + clientAction?: boolean; + tags?: string[]; + emailTranscript?: + | { + sendToVisitor: false; + } + | { + sendToVisitor: true; + requestData: NonNullable; + }; + pdfTranscript?: { + requestedBy: string; + }; + }; +}; + +export type CloseRoomParamsByUser = { + user: IUser; +} & GenericCloseRoomParams; + +export type CloseRoomParamsByVisitor = { + visitor: ILivechatVisitor; +} & GenericCloseRoomParams; + +export type CloseRoomParams = CloseRoomParamsByUser | CloseRoomParamsByVisitor; diff --git a/apps/meteor/app/livechat/server/lib/LivechatTyped.ts b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts new file mode 100644 index 0000000000000..c602f81cac006 --- /dev/null +++ b/apps/meteor/app/livechat/server/lib/LivechatTyped.ts @@ -0,0 +1,302 @@ +import type { IOmnichannelRoom, IOmnichannelRoomClosingInfo, IUser, MessageTypesValues } from '@rocket.chat/core-typings'; +import { isOmnichannelRoom } from '@rocket.chat/core-typings'; +import { LivechatDepartment, LivechatInquiry, LivechatRooms, Subscriptions, LivechatVisitors, Messages, Users } from '@rocket.chat/models'; +import moment from 'moment-timezone'; +import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; + +import { callbacks } from '../../../../lib/callbacks'; +import { Logger } from '../../../logger/server'; +import type { CloseRoomParams, CloseRoomParamsByUser, CloseRoomParamsByVisitor } from './LivechatTyped.d'; +import { sendMessage } from '../../../lib/server/functions/sendMessage'; +import { Apps, AppEvents } from '../../../../ee/server/apps'; +import { Messages as LegacyMessage } from '../../../models/server'; +import { getTimezone } from '../../../utils/server/lib/getTimezone'; +import { settings } from '../../../settings/server'; +import * as Mailer from '../../../mailer'; + +class LivechatClass { + logger: Logger; + + constructor() { + this.logger = new Logger('Livechat'); + } + + async closeRoom(params: CloseRoomParams): Promise { + const { comment } = params; + let { room } = params; + + this.logger.debug(`Attempting to close room ${room._id}`); + if (!room || !isOmnichannelRoom(room) || !room.open) { + this.logger.debug(`Room ${room._id} is not open`); + return; + } + + const { updatedOptions: options } = await this.resolveChatTags(room, params.options); + this.logger.debug(`Resolved chat tags for room ${room._id}`); + + const now = new Date(); + const { _id: rid, servedBy, transcriptRequest } = room; + const serviceTimeDuration = servedBy && (now.getTime() - new Date(servedBy.ts).getTime()) / 1000; + + const closeData: IOmnichannelRoomClosingInfo = { + closedAt: now, + chatDuration: (now.getTime() - new Date(room.ts).getTime()) / 1000, + ...(serviceTimeDuration && { serviceTimeDuration }), + ...options, + }; + this.logger.debug(`Room ${room._id} was closed at ${closeData.closedAt} (duration ${closeData.chatDuration})`); + + const isRoomClosedByUserParams = (params: CloseRoomParams): params is CloseRoomParamsByUser => + (params as CloseRoomParamsByUser).user !== undefined; + const isRoomClosedByVisitorParams = (params: CloseRoomParams): params is CloseRoomParamsByVisitor => + (params as CloseRoomParamsByVisitor).visitor !== undefined; + + let chatCloser: any; + if (isRoomClosedByUserParams(params)) { + const { user } = params; + this.logger.debug(`Closing by user ${user._id}`); + closeData.closer = 'user'; + closeData.closedBy = { + _id: user._id, + username: user.username, + }; + chatCloser = user; + } else if (isRoomClosedByVisitorParams(params)) { + const { visitor } = params; + this.logger.debug(`Closing by visitor ${params.visitor._id}`); + closeData.closer = 'visitor'; + closeData.closedBy = { + _id: visitor._id, + username: visitor.username, + }; + chatCloser = visitor; + } else { + throw new Error('Error: Please provide details of the user or visitor who closed the room'); + } + + this.logger.debug(`Updating DB for room ${room._id} with close data`); + + await Promise.all([ + LivechatRooms.closeRoomById(rid, closeData), + LivechatInquiry.removeByRoomId(rid), + Subscriptions.removeByRoomId(rid), + ]); + + this.logger.debug(`DB updated for room ${room._id}`); + + const message = { + t: 'livechat-close', + msg: comment, + groupable: false, + transcriptRequested: !!transcriptRequest, + }; + + // Retrieve the closed room + room = (await LivechatRooms.findOneById(rid)) as IOmnichannelRoom; + + this.logger.debug(`Sending closing message to room ${room._id}`); + sendMessage(chatCloser, message, room); + + LegacyMessage.createCommandWithRoomIdAndUser('promptTranscript', rid, closeData.closedBy); + + this.logger.debug(`Running callbacks for room ${room._id}`); + + Meteor.defer(() => { + /** + * @deprecated the `AppEvents.ILivechatRoomClosedHandler` event will be removed + * in the next major version of the Apps-Engine + */ + Apps.getBridges()?.getListenerBridge().livechatEvent(AppEvents.ILivechatRoomClosedHandler, room); + Apps.getBridges()?.getListenerBridge().livechatEvent(AppEvents.IPostLivechatRoomClosed, room); + }); + callbacks.runAsync('livechat.closeRoom', { + room, + options, + }); + + this.logger.debug(`Room ${room._id} was closed`); + } + + private async resolveChatTags( + room: IOmnichannelRoom, + options: CloseRoomParams['options'] = {}, + ): Promise<{ updatedOptions: CloseRoomParams['options'] }> { + this.logger.debug(`Resolving chat tags for room ${room._id}`); + + const concatUnique = (...arrays: (string[] | undefined)[]): string[] => [ + ...new Set(([] as string[]).concat(...arrays.filter((a): a is string[] => !!a))), + ]; + + const { departmentId, tags: optionsTags } = room; + const { clientAction, tags: oldRoomTags } = options; + const roomTags = concatUnique(oldRoomTags, optionsTags); + + if (!departmentId) { + return { + updatedOptions: { + ...options, + ...(roomTags.length && { tags: roomTags }), + }, + }; + } + + const department = await LivechatDepartment.findOneById(departmentId); + if (!department) { + return { + updatedOptions: { + ...options, + ...(roomTags.length && { tags: roomTags }), + }, + }; + } + + const { requestTagBeforeClosingChat, chatClosingTags } = department; + const extraRoomTags = concatUnique(roomTags, chatClosingTags); + + if (!requestTagBeforeClosingChat) { + return { + updatedOptions: { + ...options, + ...(extraRoomTags.length && { tags: extraRoomTags }), + }, + }; + } + + const checkRoomTags = !clientAction || (roomTags && roomTags.length > 0); + const checkDepartmentTags = chatClosingTags && chatClosingTags.length > 0; + if (!checkRoomTags || !checkDepartmentTags) { + throw new Error('error-tags-must-be-assigned-before-closing-chat'); + } + + return { + updatedOptions: { + ...options, + ...(extraRoomTags.length && { tags: extraRoomTags }), + }, + }; + } + + private sendEmail(from: string, to: string, replyTo: string, subject: string, html: string): void { + Mailer.send({ + to, + from, + replyTo, + subject, + html, + }); + } + + async sendTranscript({ + token, + rid, + email, + subject, + user, + }: { + token: string; + rid: string; + email: string; + subject?: string; + user?: Pick; + }): Promise { + check(rid, String); + check(email, String); + this.logger.debug(`Sending conversation transcript of room ${rid} to user with token ${token}`); + + const room = await LivechatRooms.findOneById(rid); + + const visitor = await LivechatVisitors.getVisitorByToken(token, { + projection: { _id: 1, token: 1, language: 1, username: 1, name: 1 }, + }); + + if (!visitor) { + throw new Error('error-invalid-token'); + } + + // @ts-expect-error - Visitor typings should include language? + const userLanguage = visitor?.language || settings.get('Language') || 'en'; + const timezone = getTimezone(user); + this.logger.debug(`Transcript will be sent using ${timezone} as timezone`); + + if (!room) { + throw new Error('error-invalid-room'); + } + + // allow to only user to send transcripts from their own chats + if (room.t !== 'l' || !room.v || room.v.token !== token) { + throw new Error('error-invalid-room'); + } + + const showAgentInfo = settings.get('Livechat_show_agent_info'); + const closingMessage = await Messages.findLivechatClosingMessage(rid, { projection: { ts: 1 } }); + const ignoredMessageTypes: MessageTypesValues[] = [ + 'livechat_navigation_history', + 'livechat_transcript_history', + 'command', + 'livechat-close', + 'livechat-started', + 'livechat_video_call', + ]; + const messages = await Messages.findVisibleByRoomIdNotContainingTypesBeforeTs( + rid, + ignoredMessageTypes, + closingMessage?.ts ? new Date(closingMessage.ts) : new Date(), + { + sort: { ts: 1 }, + }, + ); + + let html = '

    '; + await messages.forEach((message) => { + let author; + if (message.u._id === visitor._id) { + author = TAPi18n.__('You', { lng: userLanguage }); + } else { + author = showAgentInfo ? message.u.name || message.u.username : TAPi18n.__('Agent', { lng: userLanguage }); + } + + const datetime = moment.tz(message.ts, timezone).locale(userLanguage).format('LLL'); + const singleMessage = ` +

    ${author} ${datetime}

    +

    ${message.msg}

    + `; + html += singleMessage; + }); + + html = `${html}
    `; + + const fromEmail = settings.get('From_Email').match(/\b[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}\b/i); + let emailFromRegexp = ''; + if (fromEmail) { + emailFromRegexp = fromEmail[0]; + } else { + emailFromRegexp = settings.get('From_Email'); + } + + const mailSubject = subject || TAPi18n.__('Transcript_of_your_livechat_conversation', { lng: userLanguage }); + + this.sendEmail(emailFromRegexp, email, emailFromRegexp, mailSubject, html); + + Meteor.defer(() => { + callbacks.run('livechat.sendTranscript', messages, email); + }); + + let type = 'user'; + if (!user) { + const cat = await Users.findOneById('rocket.cat', { projection: { _id: 1, username: 1, name: 1 } }); + if (!cat) { + this.logger.error('rocket.cat user not found'); + throw new Error('No user provided and rocket.cat not found'); + } + user = cat; + type = 'visitor'; + } + + LegacyMessage.createTranscriptHistoryWithRoomIdMessageAndUser(room._id, '', user, { + requestData: { type, visitor, user }, + }); + return true; + } +} + +export const Livechat = new LivechatClass(); diff --git a/apps/meteor/app/livechat/server/lib/OmniChannel.js b/apps/meteor/app/livechat/server/lib/OmniChannel.js deleted file mode 100644 index 0a46511148906..0000000000000 --- a/apps/meteor/app/livechat/server/lib/OmniChannel.js +++ /dev/null @@ -1,70 +0,0 @@ -import { HTTP } from 'meteor/http'; - -import { settings } from '../../../settings/server'; - -const gatewayURL = 'https://omni.rocket.chat'; - -export default { - enable() { - const result = HTTP.call('POST', `${gatewayURL}/facebook/enable`, { - headers: { - 'authorization': `Bearer ${settings.get('Livechat_Facebook_API_Key')}`, - 'content-type': 'application/json', - }, - data: { - url: settings.get('Site_Url'), - }, - }); - return result.data; - }, - - disable() { - const result = HTTP.call('DELETE', `${gatewayURL}/facebook/enable`, { - headers: { - 'authorization': `Bearer ${settings.get('Livechat_Facebook_API_Key')}`, - 'content-type': 'application/json', - }, - }); - return result.data; - }, - - listPages() { - const result = HTTP.call('GET', `${gatewayURL}/facebook/pages`, { - headers: { - authorization: `Bearer ${settings.get('Livechat_Facebook_API_Key')}`, - }, - }); - return result.data; - }, - - subscribe(pageId) { - const result = HTTP.call('POST', `${gatewayURL}/facebook/page/${pageId}/subscribe`, { - headers: { - authorization: `Bearer ${settings.get('Livechat_Facebook_API_Key')}`, - }, - }); - return result.data; - }, - - unsubscribe(pageId) { - const result = HTTP.call('DELETE', `${gatewayURL}/facebook/page/${pageId}/subscribe`, { - headers: { - authorization: `Bearer ${settings.get('Livechat_Facebook_API_Key')}`, - }, - }); - return result.data; - }, - - reply({ page, token, text }) { - return HTTP.call('POST', `${gatewayURL}/facebook/reply`, { - headers: { - authorization: `Bearer ${settings.get('Livechat_Facebook_API_Key')}`, - }, - data: { - page, - token, - text, - }, - }); - }, -}; diff --git a/apps/meteor/app/livechat/server/lib/QueueManager.js b/apps/meteor/app/livechat/server/lib/QueueManager.js index 5ffea4cb78818..3c42be858f205 100644 --- a/apps/meteor/app/livechat/server/lib/QueueManager.js +++ b/apps/meteor/app/livechat/server/lib/QueueManager.js @@ -1,5 +1,6 @@ import { Meteor } from 'meteor/meteor'; import { Match, check } from 'meteor/check'; +import { LivechatInquiry as LivechatInquiryRaw } from '@rocket.chat/models'; import { LivechatRooms, LivechatInquiry, Users } from '../../../models/server'; import { checkServiceStatus, createLivechatRoom, createLivechatInquiry } from './Helper'; @@ -98,7 +99,7 @@ export const QueueManager = { const oldInquiry = LivechatInquiry.findOneByRoomId(rid); if (oldInquiry) { logger.debug(`Removing old inquiry (${oldInquiry._id}) for room ${rid}`); - LivechatInquiry.removeByRoomId(rid); + await LivechatInquiryRaw.removeByRoomId(rid); } const guest = { diff --git a/apps/meteor/app/livechat/server/lib/RoutingManager.js b/apps/meteor/app/livechat/server/lib/RoutingManager.js index 3f81513e58b26..be5b01152e85c 100644 --- a/apps/meteor/app/livechat/server/lib/RoutingManager.js +++ b/apps/meteor/app/livechat/server/lib/RoutingManager.js @@ -14,7 +14,7 @@ import { import { callbacks } from '../../../../lib/callbacks'; import { Logger } from '../../../../server/lib/logger/Logger'; import { LivechatRooms, Rooms, Messages, Users, LivechatInquiry, Subscriptions } from '../../../models/server'; -import { Apps, AppEvents } from '../../../apps/server'; +import { Apps, AppEvents } from '../../../../ee/server/apps'; const logger = new Logger('RoutingManager'); @@ -197,11 +197,6 @@ export const RoutingManager = { return callbacks.run('livechat.onAgentAssignmentFailed', { inquiry, room, options }); } - if (room.onHold) { - logger.debug(`Room ${room._id} is on hold. Remove current assignments before routing`); - Subscriptions.removeByRoomIdAndUserId(room._id, agent.agentId); - } - LivechatInquiry.takeInquiry(_id); const inq = this.assignAgent(inquiry, agent); logger.debug(`Inquiry ${inquiry._id} taken by agent ${agent.agentId}`); diff --git a/apps/meteor/app/livechat/server/lib/routing/External.js b/apps/meteor/app/livechat/server/lib/routing/External.js index cc31f109dbb0b..c9ebf29c97b4e 100644 --- a/apps/meteor/app/livechat/server/lib/routing/External.js +++ b/apps/meteor/app/livechat/server/lib/routing/External.js @@ -48,8 +48,8 @@ class ExternalQueue { }; } } - } catch (e) { - SystemLogger.error('Error requesting agent from external queue.', e); + } catch (err) { + SystemLogger.error({ msg: 'Error requesting agent from external queue.', err }); break; } } diff --git a/apps/meteor/app/livechat/server/lib/settings.ts b/apps/meteor/app/livechat/server/lib/settings.ts new file mode 100644 index 0000000000000..e0604d8ea27a5 --- /dev/null +++ b/apps/meteor/app/livechat/server/lib/settings.ts @@ -0,0 +1,6 @@ +import { OmnichannelSortingMechanismSettingType } from '@rocket.chat/core-typings'; + +import { settings } from '../../../settings/server'; + +export const getInquirySortMechanismSetting = (): OmnichannelSortingMechanismSettingType => + settings.get('Omnichannel_sorting_mechanism') || OmnichannelSortingMechanismSettingType.Timestamp; diff --git a/apps/meteor/app/livechat/server/lib/stream/agentStatus.ts b/apps/meteor/app/livechat/server/lib/stream/agentStatus.ts index 34c470c03f46b..049c8d2813b22 100644 --- a/apps/meteor/app/livechat/server/lib/stream/agentStatus.ts +++ b/apps/meteor/app/livechat/server/lib/stream/agentStatus.ts @@ -69,7 +69,7 @@ export const onlineAgents = { try { if (action === 'close') { - return Livechat.closeOpenChats(userId, comment); + return Promise.await(Livechat.closeOpenChats(userId, comment)); } if (action === 'forward') { diff --git a/apps/meteor/app/livechat/server/methods/addAgent.js b/apps/meteor/app/livechat/server/methods/addAgent.js index f391d2ed2835a..dd9b49b42adc9 100644 --- a/apps/meteor/app/livechat/server/methods/addAgent.js +++ b/apps/meteor/app/livechat/server/methods/addAgent.js @@ -1,10 +1,12 @@ import { Meteor } from 'meteor/meteor'; import { hasPermission } from '../../../authorization'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; import { Livechat } from '../lib/Livechat'; Meteor.methods({ 'livechat:addAgent'(username) { + methodDeprecationLogger.warn('livechat:addAgent will be deprecated in future versions of Rocket.Chat'); if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'manage-livechat-agents')) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:addAgent' }); } diff --git a/apps/meteor/app/livechat/server/methods/addManager.js b/apps/meteor/app/livechat/server/methods/addManager.js index 3ffddfe07625e..d365f3f6f4eeb 100644 --- a/apps/meteor/app/livechat/server/methods/addManager.js +++ b/apps/meteor/app/livechat/server/methods/addManager.js @@ -2,9 +2,11 @@ import { Meteor } from 'meteor/meteor'; import { hasPermission } from '../../../authorization'; import { Livechat } from '../lib/Livechat'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ 'livechat:addManager'(username) { + methodDeprecationLogger.warn('livechat:addManager will be deprecated in future versions of Rocket.Chat'); if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'manage-livechat-managers')) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:addManager' }); } diff --git a/apps/meteor/app/livechat/server/methods/changeLivechatStatus.js b/apps/meteor/app/livechat/server/methods/changeLivechatStatus.js index f023cd62710c3..09fcbdfeb9e81 100644 --- a/apps/meteor/app/livechat/server/methods/changeLivechatStatus.js +++ b/apps/meteor/app/livechat/server/methods/changeLivechatStatus.js @@ -3,9 +3,14 @@ import { Meteor } from 'meteor/meteor'; import { Livechat } from '../lib/Livechat'; import { hasPermission } from '../../../authorization'; import Users from '../../../models/server/models/Users'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ 'livechat:changeLivechatStatus'({ status, agentId = Meteor.userId() } = {}) { + methodDeprecationLogger.warn( + 'livechat:changeLivechatStatus is deprecated and will be removed in future versions of Rocket.Chat. Use /api/v1/livechat/agent.status REST API instead.', + ); + const uid = Meteor.userId(); if (!uid || !agentId) { @@ -22,8 +27,14 @@ Meteor.methods({ }); if (!agent) { - throw new Meteor.Error('error-not-allowed', 'Not allowed', { - method: 'livechat:saveAgentInfo', + throw new Meteor.Error('error-not-allowed', 'Invalid Agent Id', { + method: 'livechat:changeLivechatStatus', + }); + } + + if (status && !['available', 'not-available'].includes(status)) { + throw new Meteor.Error('error-not-allowed', 'Invalid Status', { + method: 'livechat:changeLivechatStatus', }); } diff --git a/apps/meteor/app/livechat/server/methods/closeByVisitor.js b/apps/meteor/app/livechat/server/methods/closeByVisitor.js deleted file mode 100644 index 022e614bb7f0b..0000000000000 --- a/apps/meteor/app/livechat/server/methods/closeByVisitor.js +++ /dev/null @@ -1,21 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { LivechatVisitors } from '@rocket.chat/models'; - -import { settings } from '../../../settings/server'; -import { LivechatRooms } from '../../../models/server'; -import { Livechat } from '../lib/Livechat'; - -Meteor.methods({ - async 'livechat:closeByVisitor'({ roomId, token }) { - const visitor = await LivechatVisitors.getVisitorByToken(token); - - const language = (visitor && visitor.language) || settings.get('Language') || 'en'; - - return Livechat.closeRoom({ - visitor, - room: LivechatRooms.findOneOpenByRoomIdAndVisitorToken(roomId, token), - comment: TAPi18n.__('Closed_by_visitor', { lng: language }), - }); - }, -}); diff --git a/apps/meteor/app/livechat/server/methods/closeRoom.js b/apps/meteor/app/livechat/server/methods/closeRoom.js deleted file mode 100644 index 14a55f87cd678..0000000000000 --- a/apps/meteor/app/livechat/server/methods/closeRoom.js +++ /dev/null @@ -1,57 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { hasPermission } from '../../../authorization'; -import { Subscriptions, LivechatRooms } from '../../../models/server'; -import { Livechat } from '../lib/Livechat'; -import { SNS } from '../lib/SNS'; - -Meteor.methods({ - 'livechat:closeRoom'(roomId, comment, options = {}) { - const userId = Meteor.userId(); - if (!userId || !hasPermission(userId, 'close-livechat-room')) { - throw new Meteor.Error('error-not-authorized', 'Not authorized', { - method: 'livechat:closeRoom', - }); - } - - const room = LivechatRooms.findOneById(roomId); - if (!room || room.t !== 'l') { - throw new Meteor.Error('error-invalid-room', 'Invalid room', { - method: 'livechat:closeRoom', - }); - } - - if (!room.open) { - throw new Meteor.Error('room-closed', 'Room closed', { method: 'livechat:closeRoom' }); - } - - const user = Meteor.user(); - - const subscription = Subscriptions.findOneByRoomIdAndUserId(roomId, user._id, { _id: 1 }); - if (!subscription && !hasPermission(userId, 'close-others-livechat-room')) { - throw new Meteor.Error('error-not-authorized', 'Not authorized', { - method: 'livechat:closeRoom', - }); - } - - const closeRoomPromise = Livechat.closeRoom({ - user, - room: LivechatRooms.findOneById(roomId), - comment, - options, - }); - - SNS.sendEvent({ - roomId, - category: 'Chat Session', - action: 'closed', - eventType: 'session', - timestamp: new Date().toISOString(), - properties: { - close_method: 'manual', - }, - }); - - return closeRoomPromise; - }, -}); diff --git a/apps/meteor/app/livechat/server/methods/closeRoom.ts b/apps/meteor/app/livechat/server/methods/closeRoom.ts new file mode 100644 index 0000000000000..f1fa700f0dd9e --- /dev/null +++ b/apps/meteor/app/livechat/server/methods/closeRoom.ts @@ -0,0 +1,129 @@ +import type { IOmnichannelRoom } from '@rocket.chat/core-typings'; +import { Meteor } from 'meteor/meteor'; +import { Users, LivechatRooms, Subscriptions as SubscriptionRaw } from '@rocket.chat/models'; + +import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; +import { Livechat } from '../lib/LivechatTyped'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; + +type CloseRoomOptions = { + clientAction?: boolean; + tags?: string[]; + emailTranscript?: + | { + sendToVisitor: false; + } + | { + sendToVisitor: true; + requestData: Pick, 'email' | 'subject'>; + }; + generateTranscriptPdf?: boolean; +}; + +type LivechatCloseRoomOptions = Omit & { + emailTranscript?: + | { + sendToVisitor: false; + } + | { + sendToVisitor: true; + requestData: NonNullable; + }; + pdfTranscript?: { + requestedBy: string; + }; +}; + +Meteor.methods({ + async 'livechat:closeRoom'(roomId: string, comment?: string, options?: CloseRoomOptions) { + methodDeprecationLogger.warn( + 'livechat:closeRoom is deprecated and will be removed in next major version. Use /api/v1/livechat/room.closeByUser API instead.', + ); + + const userId = Meteor.userId(); + if (!userId || !(await hasPermissionAsync(userId, 'close-livechat-room'))) { + throw new Meteor.Error('error-not-authorized', 'Not authorized', { + method: 'livechat:closeRoom', + }); + } + + const room = await LivechatRooms.findOneById(roomId); + if (!room || room.t !== 'l') { + throw new Meteor.Error('error-invalid-room', 'Invalid room', { + method: 'livechat:closeRoom', + }); + } + + if (!room.open) { + throw new Meteor.Error('room-closed', 'Room closed', { method: 'livechat:closeRoom' }); + } + + const user = await Users.findOneById(userId); + if (!user) { + throw new Meteor.Error('error-invalid-user', 'Invalid user', { + method: 'livechat:closeRoom', + }); + } + + const subscription = await SubscriptionRaw.findOneByRoomIdAndUserId(roomId, user._id, { + projection: { + _id: 1, + }, + }); + if (!subscription && !(await hasPermissionAsync(userId, 'close-others-livechat-room'))) { + throw new Meteor.Error('error-not-authorized', 'Not authorized', { + method: 'livechat:closeRoom', + }); + } + + await Livechat.closeRoom({ + user, + room, + comment, + options: resolveOptions(user, options), + }); + }, +}); + +const resolveOptions = ( + user: NonNullable['requestedBy'], + options?: CloseRoomOptions, +): LivechatCloseRoomOptions | undefined => { + if (!options) { + return undefined; + } + + const resolvedOptions: LivechatCloseRoomOptions = { + clientAction: options.clientAction, + tags: options.tags, + }; + + if (options.generateTranscriptPdf) { + resolvedOptions.pdfTranscript = { + requestedBy: user._id, + }; + } + + if (!options?.emailTranscript) { + return resolvedOptions; + } + if (options?.emailTranscript.sendToVisitor === false) { + return { + ...resolvedOptions, + emailTranscript: { + sendToVisitor: false, + }, + }; + } + return { + ...resolvedOptions, + emailTranscript: { + sendToVisitor: true, + requestData: { + ...options.emailTranscript.requestData, + requestedBy: user, + requestedAt: new Date(), + }, + }, + }; +}; diff --git a/apps/meteor/app/livechat/server/methods/discardTranscript.js b/apps/meteor/app/livechat/server/methods/discardTranscript.js deleted file mode 100644 index 099c8ad002d8e..0000000000000 --- a/apps/meteor/app/livechat/server/methods/discardTranscript.js +++ /dev/null @@ -1,32 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { check } from 'meteor/check'; - -import { hasPermission } from '../../../authorization'; -import { LivechatRooms } from '../../../models/server'; - -Meteor.methods({ - 'livechat:discardTranscript'(rid) { - check(rid, String); - - if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'send-omnichannel-chat-transcript')) { - throw new Meteor.Error('error-not-allowed', 'Not allowed', { - method: 'livechat:requestTranscript', - }); - } - - const room = LivechatRooms.findOneById(rid); - if (!room || !room.open) { - throw new Meteor.Error('error-invalid-room', 'Invalid room', { - method: 'livechat:requestTranscript', - }); - } - - if (!room.transcriptRequest) { - throw new Meteor.Error('error-transcript-not-requested', 'No transcript requested for this chat', { - method: 'livechat:requestTranscript', - }); - } - - return LivechatRooms.removeTranscriptRequestByRoomId(rid); - }, -}); diff --git a/apps/meteor/app/livechat/server/methods/discardTranscript.ts b/apps/meteor/app/livechat/server/methods/discardTranscript.ts new file mode 100644 index 0000000000000..c9336b64a2eda --- /dev/null +++ b/apps/meteor/app/livechat/server/methods/discardTranscript.ts @@ -0,0 +1,36 @@ +import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; +import { LivechatRooms } from '@rocket.chat/models'; + +import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; + +Meteor.methods({ + async 'livechat:discardTranscript'(rid: string) { + check(rid, String); + + const user = Meteor.userId(); + + if (!user || !(await hasPermissionAsync(user, 'send-omnichannel-chat-transcript'))) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { + method: 'livechat:requestTranscript', + }); + } + + const room = await LivechatRooms.findOneById(rid); + if (!room || !room.open) { + throw new Meteor.Error('error-invalid-room', 'Invalid room', { + method: 'livechat:discardTranscript', + }); + } + + if (!room.transcriptRequest) { + throw new Meteor.Error('error-transcript-not-requested', 'No transcript requested for this chat', { + method: 'livechat:discardTranscript', + }); + } + + await LivechatRooms.unsetEmailTranscriptRequestedByRoomId(rid); + + return true; + }, +}); diff --git a/apps/meteor/app/livechat/server/methods/facebook.js b/apps/meteor/app/livechat/server/methods/facebook.js deleted file mode 100644 index 40c7f24e52f63..0000000000000 --- a/apps/meteor/app/livechat/server/methods/facebook.js +++ /dev/null @@ -1,68 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Settings } from '@rocket.chat/models'; - -import { hasPermission } from '../../../authorization'; -import { SystemLogger } from '../../../../server/lib/logger/system'; -import { settings } from '../../../settings/server'; -import OmniChannel from '../lib/OmniChannel'; - -Meteor.methods({ - 'livechat:facebook'(options) { - if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'view-livechat-manager')) { - throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:addAgent' }); - } - - try { - switch (options.action) { - case 'initialState': { - return { - enabled: settings.get('Livechat_Facebook_Enabled'), - hasToken: !!settings.get('Livechat_Facebook_API_Key'), - }; - } - - case 'enable': { - const result = OmniChannel.enable(); - - if (!result.success) { - return result; - } - - return Settings.updateValueById('Livechat_Facebook_Enabled', true); - } - - case 'disable': { - OmniChannel.disable(); - - return Settings.updateValueById('Livechat_Facebook_Enabled', false); - } - - case 'list-pages': { - return OmniChannel.listPages(); - } - - case 'subscribe': { - return OmniChannel.subscribe(options.page); - } - - case 'unsubscribe': { - return OmniChannel.unsubscribe(options.page); - } - } - } catch (e) { - if (e.response && e.response.data && e.response.data.error) { - if (e.response.data.error.error) { - throw new Meteor.Error(e.response.data.error.error, e.response.data.error.message); - } - if (e.response.data.error.response) { - throw new Meteor.Error('integration-error', e.response.data.error.response.error.message); - } - if (e.response.data.error.message) { - throw new Meteor.Error('integration-error', e.response.data.error.message); - } - } - SystemLogger.error('Error contacting omni.rocket.chat:', e); - throw new Meteor.Error('integration-error', e.error); - } - }, -}); diff --git a/apps/meteor/app/livechat/server/methods/getCustomFields.js b/apps/meteor/app/livechat/server/methods/getCustomFields.js index c880d1cf5094b..a18c8018a64d6 100644 --- a/apps/meteor/app/livechat/server/methods/getCustomFields.js +++ b/apps/meteor/app/livechat/server/methods/getCustomFields.js @@ -1,8 +1,11 @@ import { Meteor } from 'meteor/meteor'; import { LivechatCustomField } from '@rocket.chat/models'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; + Meteor.methods({ async 'livechat:getCustomFields'() { + methodDeprecationLogger.warn('livechat:getCustomFields will be deprecated in future versions of Rocket.Chat'); return LivechatCustomField.find().toArray(); }, }); diff --git a/apps/meteor/app/livechat/server/methods/getDepartmentForwardRestrictions.js b/apps/meteor/app/livechat/server/methods/getDepartmentForwardRestrictions.js index 7e6e57f4c636a..cda1b678dc31c 100644 --- a/apps/meteor/app/livechat/server/methods/getDepartmentForwardRestrictions.js +++ b/apps/meteor/app/livechat/server/methods/getDepartmentForwardRestrictions.js @@ -1,9 +1,11 @@ import { Meteor } from 'meteor/meteor'; import { callbacks } from '../../../../lib/callbacks'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ 'livechat:getDepartmentForwardRestrictions'(departmentId) { + methodDeprecationLogger.warn('livechat:getDepartmentForwardRestrictions will be deprecated in future versions of Rocket.Chat'); if (!Meteor.userId()) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'livechat:getDepartmentForwardRestrictions', diff --git a/apps/meteor/app/livechat/server/methods/getFirstRoomMessage.js b/apps/meteor/app/livechat/server/methods/getFirstRoomMessage.js index 3c9cc06015774..c32a883fd9f96 100644 --- a/apps/meteor/app/livechat/server/methods/getFirstRoomMessage.js +++ b/apps/meteor/app/livechat/server/methods/getFirstRoomMessage.js @@ -3,9 +3,11 @@ import { check } from 'meteor/check'; import { LivechatRooms, Messages } from '../../../models/server'; import { hasPermission } from '../../../authorization'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ 'livechat:getFirstRoomMessage'({ rid }) { + methodDeprecationLogger.warn('livechat:getFirstRoomMessage will be deprecated in future versions of Rocket.Chat'); if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'view-l-room')) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:getFirstRoomMessage', diff --git a/apps/meteor/app/livechat/server/methods/getNextAgent.js b/apps/meteor/app/livechat/server/methods/getNextAgent.js index d2f0074e2d1c3..f0a770bc79a23 100644 --- a/apps/meteor/app/livechat/server/methods/getNextAgent.js +++ b/apps/meteor/app/livechat/server/methods/getNextAgent.js @@ -3,9 +3,11 @@ import { check } from 'meteor/check'; import { LivechatRooms, Users } from '../../../models/server'; import { Livechat } from '../lib/Livechat'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ async 'livechat:getNextAgent'({ token, department }) { + methodDeprecationLogger.warn('livechat:getNextAgent will be deprecated in future versions of Rocket.Chat'); check(token, String); const room = LivechatRooms.findOpenByVisitorToken(token).fetch(); diff --git a/apps/meteor/app/livechat/server/methods/getTagsList.js b/apps/meteor/app/livechat/server/methods/getTagsList.js index 9510be4fc2be3..f0329e83aefde 100644 --- a/apps/meteor/app/livechat/server/methods/getTagsList.js +++ b/apps/meteor/app/livechat/server/methods/getTagsList.js @@ -1,9 +1,11 @@ import { Meteor } from 'meteor/meteor'; import { callbacks } from '../../../../lib/callbacks'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ 'livechat:getTagsList'() { + methodDeprecationLogger.warn('livechat:getTagsList will be deprecated in future versions of Rocket.Chat'); if (!Meteor.userId()) { throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'livechat:getTagsList', diff --git a/apps/meteor/app/livechat/server/methods/loadHistory.js b/apps/meteor/app/livechat/server/methods/loadHistory.js index 7e2fd97d5329d..eda067876ed8e 100644 --- a/apps/meteor/app/livechat/server/methods/loadHistory.js +++ b/apps/meteor/app/livechat/server/methods/loadHistory.js @@ -3,9 +3,12 @@ import { LivechatVisitors } from '@rocket.chat/models'; import { loadMessageHistory } from '../../../lib'; import { LivechatRooms } from '../../../models/server'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ async 'livechat:loadHistory'({ token, rid, end, limit = 20, ls }) { + methodDeprecationLogger.warn('livechat:loadHistory will be deprecated in future versions of Rocket.Chat'); + if (!token || typeof token !== 'string') { return; } diff --git a/apps/meteor/app/livechat/server/methods/loginByToken.js b/apps/meteor/app/livechat/server/methods/loginByToken.js index 4c2c7c6583658..07bca98f0cff0 100644 --- a/apps/meteor/app/livechat/server/methods/loginByToken.js +++ b/apps/meteor/app/livechat/server/methods/loginByToken.js @@ -1,8 +1,11 @@ import { Meteor } from 'meteor/meteor'; import { LivechatVisitors } from '@rocket.chat/models'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; + Meteor.methods({ async 'livechat:loginByToken'(token) { + methodDeprecationLogger.warn('livechat:loginByToken will be deprecated in future versions of Rocket.Chat'); const visitor = await LivechatVisitors.getVisitorByToken(token, { projection: { _id: 1 } }); if (!visitor) { diff --git a/apps/meteor/app/livechat/server/methods/pageVisited.js b/apps/meteor/app/livechat/server/methods/pageVisited.js index c9c88e95ddc59..6c24b93a1161a 100644 --- a/apps/meteor/app/livechat/server/methods/pageVisited.js +++ b/apps/meteor/app/livechat/server/methods/pageVisited.js @@ -1,9 +1,11 @@ import { Meteor } from 'meteor/meteor'; import { Livechat } from '../lib/Livechat'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ 'livechat:pageVisited'(token, room, pageInfo) { + methodDeprecationLogger.warn('livechat:pageVisited will be deprecated in future versions of Rocket.Chat'); Livechat.savePageHistory(token, room, pageInfo); }, }); diff --git a/apps/meteor/app/livechat/server/methods/registerGuest.js b/apps/meteor/app/livechat/server/methods/registerGuest.js index d242c365ef76b..18d47caca6c15 100644 --- a/apps/meteor/app/livechat/server/methods/registerGuest.js +++ b/apps/meteor/app/livechat/server/methods/registerGuest.js @@ -3,9 +3,12 @@ import { LivechatVisitors } from '@rocket.chat/models'; import { Messages, LivechatRooms } from '../../../models/server'; import { Livechat } from '../lib/Livechat'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ async 'livechat:registerGuest'({ token, name, email, department, customFields } = {}) { + methodDeprecationLogger.warn('livechat:registerGuest will be deprecated in future versions of Rocket.Chat'); + const userId = await Livechat.registerGuest.call(this, { token, name, diff --git a/apps/meteor/app/livechat/server/methods/removeAgent.js b/apps/meteor/app/livechat/server/methods/removeAgent.js index 009b6badd3fe3..d9362b1eb1bc6 100644 --- a/apps/meteor/app/livechat/server/methods/removeAgent.js +++ b/apps/meteor/app/livechat/server/methods/removeAgent.js @@ -2,9 +2,11 @@ import { Meteor } from 'meteor/meteor'; import { hasPermission } from '../../../authorization'; import { Livechat } from '../lib/Livechat'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ 'livechat:removeAgent'(username) { + methodDeprecationLogger.warn('livechat:removeAgent will be deprecated in future versions of Rocket.Chat'); if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'manage-livechat-agents')) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:removeAgent', diff --git a/apps/meteor/app/livechat/server/methods/removeAllClosedRooms.js b/apps/meteor/app/livechat/server/methods/removeAllClosedRooms.js deleted file mode 100644 index 36514d64238a5..0000000000000 --- a/apps/meteor/app/livechat/server/methods/removeAllClosedRooms.js +++ /dev/null @@ -1,23 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { hasPermission } from '../../../authorization'; -import { LivechatRooms } from '../../../models/server'; -import { Livechat } from '../lib/Livechat'; - -Meteor.methods({ - 'livechat:removeAllClosedRooms'(fromDate, toDate, departmentIds) { - if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'remove-closed-livechat-rooms')) { - throw new Meteor.Error('error-not-allowed', 'Not allowed', { - method: 'livechat:removeAllClosedRoom', - }); - } - - let count = 0; - LivechatRooms.findClosedRooms(fromDate, toDate, departmentIds).forEach(({ _id }) => { - Livechat.removeRoom(_id); - count++; - }); - - return count; - }, -}); diff --git a/apps/meteor/app/livechat/server/methods/removeAllClosedRooms.ts b/apps/meteor/app/livechat/server/methods/removeAllClosedRooms.ts new file mode 100644 index 0000000000000..ffc711d0716b4 --- /dev/null +++ b/apps/meteor/app/livechat/server/methods/removeAllClosedRooms.ts @@ -0,0 +1,30 @@ +import type { IOmnichannelRoom } from '@rocket.chat/core-typings'; +import { Meteor } from 'meteor/meteor'; + +import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; +import { LivechatRooms } from '../../../models/server'; +import { Livechat } from '../lib/Livechat'; + +Meteor.methods({ + async 'livechat:removeAllClosedRooms'(departmentIds: string[]) { + const user = Meteor.userId(); + + if (!user || !(await hasPermissionAsync(user, 'remove-closed-livechat-rooms'))) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { + method: 'livechat:removeAllClosedRoom', + }); + } + + // These are not debug logs since we want to know when the action is performed + Livechat.logger.info(`User ${Meteor.userId()} is removing all closed rooms`); + + const promises: Promise[] = []; + LivechatRooms.findClosedRooms(departmentIds).forEach(({ _id }: IOmnichannelRoom) => { + promises.push(Livechat.removeRoom(_id)); + }); + await Promise.all(promises); + + Livechat.logger.info(`User ${Meteor.userId()} removed ${promises.length} closed rooms`); + return promises.length; + }, +}); diff --git a/apps/meteor/app/livechat/server/methods/removeDepartment.js b/apps/meteor/app/livechat/server/methods/removeDepartment.js index 1d9d9323f759d..c4d64ee25c127 100644 --- a/apps/meteor/app/livechat/server/methods/removeDepartment.js +++ b/apps/meteor/app/livechat/server/methods/removeDepartment.js @@ -1,16 +1,22 @@ import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; import { hasPermission } from '../../../authorization'; -import { Livechat } from '../lib/Livechat'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; +import { DepartmentHelper } from '../lib/Departments'; Meteor.methods({ 'livechat:removeDepartment'(_id) { + methodDeprecationLogger.warn('livechat:removeDepartment will be deprecated in future versions of Rocket.Chat'); + + check(_id, String); + if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'manage-livechat-departments')) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:removeDepartment', }); } - return Livechat.removeDepartment(_id); + return DepartmentHelper.removeDepartment(_id); }, }); diff --git a/apps/meteor/app/livechat/server/methods/removeManager.js b/apps/meteor/app/livechat/server/methods/removeManager.js index 7de6d8051a7e7..53eaa068ce634 100644 --- a/apps/meteor/app/livechat/server/methods/removeManager.js +++ b/apps/meteor/app/livechat/server/methods/removeManager.js @@ -2,9 +2,12 @@ import { Meteor } from 'meteor/meteor'; import { hasPermission } from '../../../authorization'; import { Livechat } from '../lib/Livechat'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ 'livechat:removeManager'(username) { + methodDeprecationLogger.warn('livechat:removeManager will be deprecated in future versions of Rocket.Chat'); + if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'manage-livechat-managers')) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:removeManager', diff --git a/apps/meteor/app/livechat/server/methods/removeRoom.js b/apps/meteor/app/livechat/server/methods/removeRoom.js deleted file mode 100644 index a39a0abb4f020..0000000000000 --- a/apps/meteor/app/livechat/server/methods/removeRoom.js +++ /dev/null @@ -1,35 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { hasPermission } from '../../../authorization'; -import { LivechatRooms } from '../../../models/server'; -import { Livechat } from '../lib/Livechat'; - -Meteor.methods({ - 'livechat:removeRoom'(rid) { - if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'remove-closed-livechat-rooms')) { - throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:removeRoom' }); - } - - const room = LivechatRooms.findOneById(rid); - - if (!room) { - throw new Meteor.Error('error-invalid-room', 'Invalid room', { - method: 'livechat:removeRoom', - }); - } - - if (room.t !== 'l') { - throw new Meteor.Error('error-this-is-not-a-livechat-room', 'This is not a Livechat room', { - method: 'livechat:removeRoom', - }); - } - - if (room.open) { - throw new Meteor.Error('error-room-is-not-closed', 'Room is not closed', { - method: 'livechat:removeRoom', - }); - } - - return Livechat.removeRoom(rid); - }, -}); diff --git a/apps/meteor/app/livechat/server/methods/removeRoom.ts b/apps/meteor/app/livechat/server/methods/removeRoom.ts new file mode 100644 index 0000000000000..9b207c682d86b --- /dev/null +++ b/apps/meteor/app/livechat/server/methods/removeRoom.ts @@ -0,0 +1,36 @@ +import { Meteor } from 'meteor/meteor'; + +import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; +import { LivechatRooms } from '../../../models/server'; +import { Livechat } from '../lib/Livechat'; + +Meteor.methods({ + async 'livechat:removeRoom'(rid: string) { + const user = Meteor.userId(); + if (!user || !(await hasPermissionAsync(user, 'remove-closed-livechat-rooms'))) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:removeRoom' }); + } + + const room = LivechatRooms.findOneById(rid); + + if (!room) { + throw new Meteor.Error('error-invalid-room', 'Invalid room', { + method: 'livechat:removeRoom', + }); + } + + if (room.t !== 'l') { + throw new Meteor.Error('error-this-is-not-a-livechat-room', 'This is not a Livechat room', { + method: 'livechat:removeRoom', + }); + } + + if (room.open) { + throw new Meteor.Error('error-room-is-not-closed', 'Room is not closed', { + method: 'livechat:removeRoom', + }); + } + + await Livechat.removeRoom(rid); + }, +}); diff --git a/apps/meteor/app/livechat/server/methods/requestTranscript.js b/apps/meteor/app/livechat/server/methods/requestTranscript.js deleted file mode 100644 index 8e3424c8d00f2..0000000000000 --- a/apps/meteor/app/livechat/server/methods/requestTranscript.js +++ /dev/null @@ -1,24 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { check } from 'meteor/check'; - -import { hasPermission } from '../../../authorization'; -import { Users } from '../../../models/server'; -import { Livechat } from '../lib/Livechat'; - -Meteor.methods({ - 'livechat:requestTranscript'(rid, email, subject) { - check(rid, String); - check(email, String); - - if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'send-omnichannel-chat-transcript')) { - throw new Meteor.Error('error-not-allowed', 'Not allowed', { - method: 'livechat:requestTranscript', - }); - } - - const user = Users.findOneById(Meteor.userId(), { - fields: { _id: 1, username: 1, name: 1, utcOffset: 1 }, - }); - return Livechat.requestTranscript({ rid, email, subject, user }); - }, -}); diff --git a/apps/meteor/app/livechat/server/methods/requestTranscript.ts b/apps/meteor/app/livechat/server/methods/requestTranscript.ts new file mode 100644 index 0000000000000..f10c6ce27d1c8 --- /dev/null +++ b/apps/meteor/app/livechat/server/methods/requestTranscript.ts @@ -0,0 +1,29 @@ +import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; + +import { Users } from '../../../models/server'; +import { Livechat } from '../lib/Livechat'; +import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; + +Meteor.methods({ + async 'livechat:requestTranscript'(rid: string, email: string, subject: string) { + check(rid, String); + check(email, String); + + const userId = Meteor.userId(); + + if (!userId || !(await hasPermissionAsync(userId, 'send-omnichannel-chat-transcript'))) { + throw new Meteor.Error('error-not-allowed', 'Not allowed', { + method: 'livechat:requestTranscript', + }); + } + + const user = Users.findOneById(userId, { + fields: { _id: 1, username: 1, name: 1, utcOffset: 1 }, + }); + + await Livechat.requestTranscript({ rid, email, subject, user }); + + return true; + }, +}); diff --git a/apps/meteor/app/livechat/server/methods/saveDepartment.js b/apps/meteor/app/livechat/server/methods/saveDepartment.js index 581f2a7c0651e..6b2cb4d0449ff 100644 --- a/apps/meteor/app/livechat/server/methods/saveDepartment.js +++ b/apps/meteor/app/livechat/server/methods/saveDepartment.js @@ -1,16 +1,16 @@ import { Meteor } from 'meteor/meteor'; import { hasPermission } from '../../../authorization'; -import { Livechat } from '../lib/Livechat'; +import { LivechatEnterprise } from '../../../../ee/app/livechat-enterprise/server/lib/LivechatEnterprise'; Meteor.methods({ - 'livechat:saveDepartment'(_id, departmentData, departmentAgents) { + async 'livechat:saveDepartment'(_id, departmentData, departmentAgents) { if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'manage-livechat-departments')) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:saveDepartment', }); } - return Livechat.saveDepartment(_id, departmentData, { upsert: departmentAgents }); + return LivechatEnterprise.saveDepartment(_id, departmentData, { upsert: departmentAgents }); }, }); diff --git a/apps/meteor/app/livechat/server/methods/saveDepartmentAgents.js b/apps/meteor/app/livechat/server/methods/saveDepartmentAgents.js index 904bae1b8c407..4a26b45c63a76 100644 --- a/apps/meteor/app/livechat/server/methods/saveDepartmentAgents.js +++ b/apps/meteor/app/livechat/server/methods/saveDepartmentAgents.js @@ -2,9 +2,12 @@ import { Meteor } from 'meteor/meteor'; import { hasPermission } from '../../../authorization'; import { Livechat } from '../lib/Livechat'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ 'livechat:saveDepartmentAgents'(_id, departmentAgents) { + methodDeprecationLogger.warn('livechat:saveDepartmentAgents will be deprecated in future versions of Rocket.Chat'); + if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'add-livechat-department-agents')) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:saveDepartmentAgents', diff --git a/apps/meteor/app/livechat/server/methods/saveInfo.js b/apps/meteor/app/livechat/server/methods/saveInfo.js index 9c944d65d2bcf..4d52c6489935b 100644 --- a/apps/meteor/app/livechat/server/methods/saveInfo.js +++ b/apps/meteor/app/livechat/server/methods/saveInfo.js @@ -6,9 +6,16 @@ import { hasPermission } from '../../../authorization'; import { LivechatRooms } from '../../../models/server'; import { callbacks } from '../../../../lib/callbacks'; import { Livechat } from '../lib/Livechat'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; +/** + * @deprecated Will be removed in future versions. + */ Meteor.methods({ async 'livechat:saveInfo'(guestData, roomData) { + methodDeprecationLogger.warn( + 'livechat:saveInfo method will be deprecated in future versions of Rocket.Chat. Use "livechat/room.saveInfo" endpoint instead.', + ); const userId = Meteor.userId(); if (!userId || !hasPermission(userId, 'view-l-room')) { @@ -34,6 +41,7 @@ Meteor.methods({ tags: Match.Optional([String]), livechatData: Match.Optional(Object), priorityId: Match.Optional(String), + slaId: Match.Optional(String), }), ); diff --git a/apps/meteor/app/livechat/server/methods/saveIntegration.ts b/apps/meteor/app/livechat/server/methods/saveIntegration.ts index 7422ba3625261..868c60652dea7 100644 --- a/apps/meteor/app/livechat/server/methods/saveIntegration.ts +++ b/apps/meteor/app/livechat/server/methods/saveIntegration.ts @@ -1,8 +1,8 @@ import { Settings } from '@rocket.chat/models'; import { Meteor } from 'meteor/meteor'; -import s from 'underscore.string'; import { hasPermission } from '../../../authorization/server'; +import { trim } from '../../../../lib/utils/stringUtils'; Meteor.methods({ async 'livechat:saveIntegration'(values) { @@ -14,11 +14,11 @@ Meteor.methods({ } if (typeof values.Livechat_webhookUrl !== 'undefined') { - await Settings.updateValueById('Livechat_webhookUrl', s.trim(values.Livechat_webhookUrl)); + await Settings.updateValueById('Livechat_webhookUrl', trim(values.Livechat_webhookUrl)); } if (typeof values.Livechat_secret_token !== 'undefined') { - await Settings.updateValueById('Livechat_secret_token', s.trim(values.Livechat_secret_token)); + await Settings.updateValueById('Livechat_secret_token', trim(values.Livechat_secret_token)); } if (typeof values.Livechat_webhook_on_start !== 'undefined') { diff --git a/apps/meteor/app/livechat/server/methods/saveSurveyFeedback.js b/apps/meteor/app/livechat/server/methods/saveSurveyFeedback.js index 7d908cdc7a904..0b5ac26021aba 100644 --- a/apps/meteor/app/livechat/server/methods/saveSurveyFeedback.js +++ b/apps/meteor/app/livechat/server/methods/saveSurveyFeedback.js @@ -3,8 +3,12 @@ import { Match, check } from 'meteor/check'; import _ from 'underscore'; import { LivechatRooms, LivechatVisitors } from '@rocket.chat/models'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; + Meteor.methods({ async 'livechat:saveSurveyFeedback'(visitorToken, visitorRoom, formData) { + methodDeprecationLogger.warn('livechat:saveSurveyFeedback will be deprecated in future versions of Rocket.Chat'); + check(visitorToken, String); check(visitorRoom, String); check(formData, [Match.ObjectIncluding({ name: String, value: String })]); diff --git a/apps/meteor/app/livechat/server/methods/searchAgent.js b/apps/meteor/app/livechat/server/methods/searchAgent.js index 600a28150bad2..120aea169bb03 100644 --- a/apps/meteor/app/livechat/server/methods/searchAgent.js +++ b/apps/meteor/app/livechat/server/methods/searchAgent.js @@ -1,18 +1,20 @@ import { Meteor } from 'meteor/meteor'; -import _ from 'underscore'; import { hasPermission } from '../../../authorization'; import { Users } from '../../../models/server'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ 'livechat:searchAgent'(username) { + methodDeprecationLogger.warn('livechat:searchAgent will be deprecated in future versions of Rocket.Chat'); + if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'view-livechat-manager')) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:searchAgent', }); } - if (!username || !_.isString(username)) { + if (!username || typeof username.valueOf() !== 'string') { throw new Meteor.Error('error-invalid-arguments', 'Invalid arguments', { method: 'livechat:searchAgent', }); diff --git a/apps/meteor/app/livechat/server/methods/sendFileLivechatMessage.js b/apps/meteor/app/livechat/server/methods/sendFileLivechatMessage.js index 3f2a3e7c98bbd..3ef92b450ee0c 100644 --- a/apps/meteor/app/livechat/server/methods/sendFileLivechatMessage.js +++ b/apps/meteor/app/livechat/server/methods/sendFileLivechatMessage.js @@ -67,6 +67,13 @@ Meteor.methods({ name: file.name, type: file.type, }, + files: [ + { + _id: file._id, + name: file.name, + type: file.type, + }, + ], groupable: false, attachments: [attachment], token: visitorToken, diff --git a/apps/meteor/app/livechat/server/methods/sendOfflineMessage.js b/apps/meteor/app/livechat/server/methods/sendOfflineMessage.js index 27e59f137dff0..00ddd26cba149 100644 --- a/apps/meteor/app/livechat/server/methods/sendOfflineMessage.js +++ b/apps/meteor/app/livechat/server/methods/sendOfflineMessage.js @@ -3,9 +3,12 @@ import { check } from 'meteor/check'; import { DDPRateLimiter } from 'meteor/ddp-rate-limiter'; import { Livechat } from '../lib/Livechat'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ 'livechat:sendOfflineMessage'(data) { + methodDeprecationLogger.warn('livechat:sendOfflineMessage will be deprecated in future versions of Rocket.Chat'); + check(data, { name: String, email: String, diff --git a/apps/meteor/app/livechat/server/methods/sendTranscript.js b/apps/meteor/app/livechat/server/methods/sendTranscript.js index a29b732365336..1b6ce7a7cb7f7 100644 --- a/apps/meteor/app/livechat/server/methods/sendTranscript.js +++ b/apps/meteor/app/livechat/server/methods/sendTranscript.js @@ -4,7 +4,7 @@ import { DDPRateLimiter } from 'meteor/ddp-rate-limiter'; import { Users } from '../../../models/server'; import { hasPermission } from '../../../authorization'; -import { Livechat } from '../lib/Livechat'; +import { Livechat } from '../lib/LivechatTyped'; Meteor.methods({ 'livechat:sendTranscript'(token, rid, email, subject) { diff --git a/apps/meteor/app/livechat/server/methods/setCustomField.js b/apps/meteor/app/livechat/server/methods/setCustomField.js index e9764ed827a05..67155cffb0fb6 100644 --- a/apps/meteor/app/livechat/server/methods/setCustomField.js +++ b/apps/meteor/app/livechat/server/methods/setCustomField.js @@ -2,9 +2,12 @@ import { Meteor } from 'meteor/meteor'; import { LivechatVisitors, LivechatCustomField } from '@rocket.chat/models'; import { LivechatRooms } from '../../../models/server'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ async 'livechat:setCustomField'(token, key, value, overwrite = true) { + methodDeprecationLogger.warn('livechat:setCustomField will be deprecated in future versions of Rocket.Chat'); + const customField = await LivechatCustomField.findOneById(key); if (customField) { if (customField.scope === 'room') { diff --git a/apps/meteor/app/livechat/server/methods/setDepartmentForVisitor.js b/apps/meteor/app/livechat/server/methods/setDepartmentForVisitor.js index ada1703b34c6e..0fc5cab2cbc23 100644 --- a/apps/meteor/app/livechat/server/methods/setDepartmentForVisitor.js +++ b/apps/meteor/app/livechat/server/methods/setDepartmentForVisitor.js @@ -5,9 +5,12 @@ import { LivechatVisitors } from '@rocket.chat/models'; import { LivechatRooms, Messages } from '../../../models/server'; import { Livechat } from '../lib/Livechat'; import { normalizeTransferredByData } from '../lib/Helper'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ async 'livechat:setDepartmentForVisitor'({ roomId, visitorToken, departmentId } = {}) { + methodDeprecationLogger.warn('livechat:setDepartmentForVisitor will be deprecated in future versions of Rocket.Chat'); + check(roomId, String); check(visitorToken, String); check(departmentId, String); diff --git a/apps/meteor/app/livechat/server/methods/transfer.js b/apps/meteor/app/livechat/server/methods/transfer.js index f9f556386aca4..4384d7651c252 100644 --- a/apps/meteor/app/livechat/server/methods/transfer.js +++ b/apps/meteor/app/livechat/server/methods/transfer.js @@ -6,11 +6,13 @@ import { hasPermission } from '../../../authorization/server'; import { LivechatRooms, Subscriptions, Users } from '../../../models/server'; import { Livechat } from '../lib/Livechat'; import { normalizeTransferredByData } from '../lib/Helper'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; // Deprecated in favor of "livechat/room.forward" endpoint // TODO: Deprecated: Remove in v6.0.0 Meteor.methods({ async 'livechat:transfer'(transferData) { + methodDeprecationLogger.warn('livechat:transfer method is deprecated in favor of "livechat/room.forward" endpoint'); if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'view-l-room')) { throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'livechat:transfer' }); } diff --git a/apps/meteor/app/livechat/server/methods/webhookTest.js b/apps/meteor/app/livechat/server/methods/webhookTest.js index dc02b578614e7..c0578ff123bc1 100644 --- a/apps/meteor/app/livechat/server/methods/webhookTest.js +++ b/apps/meteor/app/livechat/server/methods/webhookTest.js @@ -3,6 +3,7 @@ import { HTTP } from 'meteor/http'; import { settings } from '../../../settings/server'; import { SystemLogger } from '../../../../server/lib/logger/system'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; const postCatchError = function (url, options) { try { @@ -14,6 +15,7 @@ const postCatchError = function (url, options) { Meteor.methods({ 'livechat:webhookTest'() { + methodDeprecationLogger.info(`Method 'livechat:webhookTest' is deprecated and will be removed in future versions of Rocket.Chat`); this.unblock(); const sampleData = { diff --git a/apps/meteor/app/livechat/server/roomAccessValidator.compatibility.js b/apps/meteor/app/livechat/server/roomAccessValidator.compatibility.js index fe6e1d4a63673..93bc0915fa53e 100644 --- a/apps/meteor/app/livechat/server/roomAccessValidator.compatibility.js +++ b/apps/meteor/app/livechat/server/roomAccessValidator.compatibility.js @@ -70,4 +70,14 @@ export const validators = [ } return hasPermission(user._id, 'view-livechat-room-closed-same-department'); }, + function (room, user) { + // Check if user is rocket.cat + if (!user?._id) { + return false; + } + + // This opens the ability for rocketcat to upload files to a livechat room without being included in it :) + // Worst case, someone manages to log in as rocketcat lol + return user._id === 'rocket.cat'; + }, ]; diff --git a/apps/meteor/app/livechat/server/roomAccessValidator.internalService.ts b/apps/meteor/app/livechat/server/roomAccessValidator.internalService.ts index 3ab3c37843de8..381a40d371f3a 100644 --- a/apps/meteor/app/livechat/server/roomAccessValidator.internalService.ts +++ b/apps/meteor/app/livechat/server/roomAccessValidator.internalService.ts @@ -1,7 +1,7 @@ import type { IUser, IOmnichannelRoom } from '@rocket.chat/core-typings'; +import type { IAuthorizationLivechat } from '@rocket.chat/core-services'; +import { ServiceClassInternal } from '@rocket.chat/core-services'; -import type { IAuthorizationLivechat } from '../../../server/sdk/types/IAuthorizationLivechat'; -import { ServiceClassInternal } from '../../../server/sdk/types/ServiceClass'; import { validators } from './roomAccessValidator.compatibility'; export class AuthorizationLivechat extends ServiceClassInternal implements IAuthorizationLivechat { diff --git a/apps/meteor/app/livechat/server/visitorStatus.js b/apps/meteor/app/livechat/server/visitorStatus.js deleted file mode 100644 index 466d82c8efc45..0000000000000 --- a/apps/meteor/app/livechat/server/visitorStatus.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { UserPresenceEvents } from 'meteor/konecty:user-presence'; - -import { Livechat } from './lib/Livechat'; - -Meteor.startup(() => { - UserPresenceEvents.on('setStatus', (session, status, metadata) => { - if (metadata && metadata.visitor) { - Livechat.notifyGuestStatusChanged(metadata.visitor, status); - } - }); -}); diff --git a/apps/meteor/app/livestream/.gitignore b/apps/meteor/app/livestream/.gitignore deleted file mode 100644 index f22188fc0aaf6..0000000000000 --- a/apps/meteor/app/livestream/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.npm/ diff --git a/apps/meteor/app/livestream/client/index.js b/apps/meteor/app/livestream/client/index.js deleted file mode 100644 index 7e341b72aa89b..0000000000000 --- a/apps/meteor/app/livestream/client/index.js +++ /dev/null @@ -1,10 +0,0 @@ -import './views/liveStreamTab.html'; -import './views/liveStreamTab'; -import './views/livestreamBroadcast.html'; -import './views/livestreamBroadcast'; -import './views/broadcastView.html'; -import './views/broadcastView'; -import './views/liveStreamView.html'; -import './views/liveStreamView'; -import './tabBar'; -import './styles/liveStreamTab.css'; diff --git a/apps/meteor/app/livestream/client/oauth.js b/apps/meteor/app/livestream/client/oauth.js deleted file mode 100644 index e422a5a43f726..0000000000000 --- a/apps/meteor/app/livestream/client/oauth.js +++ /dev/null @@ -1,22 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { settings } from '../../settings'; - -export const close = (popup) => - new Promise(function (resolve) { - const checkInterval = setInterval(() => { - if (popup.closed) { - clearInterval(checkInterval); - resolve(); - } - }, 300); - }); - -export const auth = async () => { - const oauthWindow = window.open( - `${settings.get('Site_Url')}/api/v1/livestream/oauth?userId=${Meteor.userId()}`, - 'youtube-integration-oauth', - 'width=400,height=600', - ); - return close(oauthWindow); -}; diff --git a/apps/meteor/app/livestream/client/styles/liveStreamTab.css b/apps/meteor/app/livestream/client/styles/liveStreamTab.css deleted file mode 100644 index 243d0cb0c0fad..0000000000000 --- a/apps/meteor/app/livestream/client/styles/liveStreamTab.css +++ /dev/null @@ -1,64 +0,0 @@ -.contextual-bar__content { - &.livestream { - justify-content: flex-start; - } - - & .rc-button--stack { - width: 100%; - } -} - -.thumbnail-container { - position: relative; - - height: 270px; - - & .popout { - &--absolute-center { - position: absolute; - top: calc(50% - 25px); - left: calc(50% - 25px); - - font-size: 50px; - } - - &--play-solid { - fill: white; - } - } -} - -.liveStreamTab__form { - & .rc-switch { - padding: 15px 5px; - } - - & .rc-input__label p { - padding: 10px 0; - } -} - -.livestream--url { - overflow: hidden; - - margin: 10px 5px; - padding: 10px 0; - - white-space: nowrap; - - text-overflow: ellipsis; - - font-size: 15px; - - & .current-setting { - display: inline-block; - - text-decoration: none; - - color: black; - } - - & .rc-button { - width: 49%; - } -} diff --git a/apps/meteor/app/livestream/client/tabBar.tsx b/apps/meteor/app/livestream/client/tabBar.tsx deleted file mode 100644 index eb4eb76678401..0000000000000 --- a/apps/meteor/app/livestream/client/tabBar.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import type { ReactNode } from 'react'; -import React, { useMemo } from 'react'; -import { Option, Badge } from '@rocket.chat/fuselage'; -import { useSetting, useTranslation } from '@rocket.chat/ui-contexts'; -import { isRoomFederated } from '@rocket.chat/core-typings'; - -import { addAction } from '../../../client/views/room/lib/Toolbox'; -import Header from '../../../client/components/Header'; - -addAction('livestream', ({ room }) => { - const enabled = useSetting('Livestream_enabled'); - const t = useTranslation(); - const federated = isRoomFederated(room); - const isLive = room?.streamingOptions?.id && room.streamingOptions.type === 'livestream'; - - return useMemo( - () => - enabled - ? { - groups: ['channel', 'group', 'team'], - id: 'livestream', - title: 'Livestream', - icon: 'podcast', - template: 'liveStreamTab', - order: isLive ? -1 : 15, - ...(federated && { - 'data-tooltip': federated ? 'Livestream_unavailable_for_federation' : '', - 'disabled': true, - }), - renderAction: (props): ReactNode => ( - - {isLive ? ( - - ! - - ) : null} - - ), - renderOption: ({ label: { title, icon }, ...props }: any): ReactNode => ( - - ), - } - : null, - [enabled, isLive, t, federated], - ); -}); diff --git a/apps/meteor/app/livestream/client/views/broadcastView.html b/apps/meteor/app/livestream/client/views/broadcastView.html deleted file mode 100644 index 44d69807f7a5b..0000000000000 --- a/apps/meteor/app/livestream/client/views/broadcastView.html +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/apps/meteor/app/livestream/client/views/broadcastView.js b/apps/meteor/app/livestream/client/views/broadcastView.js deleted file mode 100644 index ae4ef148ca45f..0000000000000 --- a/apps/meteor/app/livestream/client/views/broadcastView.js +++ /dev/null @@ -1,172 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { Session } from 'meteor/session'; -import { Template } from 'meteor/templating'; - -import { dispatchToastMessage } from '../../../../client/lib/toast'; -import { settings } from '../../../settings/client'; - -const getMedia = () => navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; -const createAndConnect = (url) => { - if (!('WebSocket' in window)) { - // eslint-disable-line no-negated-in-lhs - return false; - } - - const ws = new WebSocket(url); - ws.onerror = (evt) => console.error(`Error: ${evt.data}`); - return ws; -}; -const sendMessageToWebSocket = (message, ws) => { - if (ws != null) { - if (ws.readyState === 1) { - ws.send(message); - } - } -}; -export const call = (...args) => - new Promise(function (resolve, reject) { - Meteor.call(...args, function (error, result) { - if (error) { - dispatchToastMessage({ type: 'error', message: error }); - reject(error); - return; - } - - resolve(result); - }); - }); - -const delay = (time) => new Promise((resolve) => setTimeout(resolve, time)); - -const waitForStreamStatus = async (id, status) => { - const streamActive = new Promise(async (resolve) => { - // eslint-disable-next-line no-constant-condition - while (true) { - const currentStatus = await call('livestreamStreamStatus', { streamId: id }); // eslint-disable-line no-await-in-loop - if (currentStatus === status) { - return resolve(status); - } - await delay(1500); // eslint-disable-line no-await-in-loop - } - }); - await streamActive; -}; -const waitForBroadcastStatus = async (id, status) => { - const broadcastActive = new Promise(async (resolve) => { - // eslint-disable-next-line no-constant-condition - while (true) { - const currentStatus = await call('getBroadcastStatus', { broadcastId: id }); // eslint-disable-line no-await-in-loop - if (currentStatus === status) { - return resolve(status); - } - await delay(1500); // eslint-disable-line no-await-in-loop - } - }); - await broadcastActive; -}; - -Template.broadcastView.helpers({ - broadcastSource() { - return Template.instance().mediaStream.get() ? window.URL.createObjectURL(Template.instance().mediaStream.get()) : ''; - }, - mediaRecorder() { - Template.instance().mediaRecorder.get(); - }, -}); - -Template.broadcastView.onCreated(async function () { - const connection = createAndConnect(`${settings.get('Broadcasting_media_server_url')}/${this.data.id}`); - this.mediaStream = new ReactiveVar(null); - this.mediaRecorder = new ReactiveVar(null); - this.connection = new ReactiveVar(connection); -}); -Template.broadcastView.onDestroyed(function () { - if (this.connection.get()) { - this.connection.get().close(); - } - if (this.mediaRecorder.get()) { - this.mediaRecorder.get().stop(); - this.mediaRecorder.set(null); - } - if (this.mediaStream.get()) { - this.mediaStream - .get() - .getTracks() - .map((track) => track.stop()); - this.mediaStream.set(null); - } -}); -Template.broadcastView.onRendered(async function () { - navigator.getMedia = getMedia(); - if (!navigator.getMedia) { - return alert('getUserMedia() is not supported in your browser!'); - } - const localMediaStream = await new Promise((resolve, reject) => navigator.getMedia({ video: true, audio: true }, resolve, reject)); - - const connection = this.connection.get(); - - this.mediaStream.set(localMediaStream); - let options = { mimeType: 'video/webm;codecs=vp9' }; - if (!MediaRecorder.isTypeSupported(options.mimeType)) { - options = { mimeType: 'video/webm;codecs=vp8' }; - if (!MediaRecorder.isTypeSupported(options.mimeType)) { - options = { mimeType: 'video/webm' }; - if (!MediaRecorder.isTypeSupported(options.mimeType)) { - options = { mimeType: '' }; - } - } - } - try { - const mediaRecorder = new MediaRecorder(localMediaStream, options); - mediaRecorder.ondataavailable = (event) => { - if (!(event.data || event.data.size > 0)) { - return; - } - sendMessageToWebSocket(event.data, connection); - }; - mediaRecorder.start(100); // collect 100ms of data - this.mediaRecorder.set(mediaRecorder); - - await waitForStreamStatus(this.data.stream.id, 'active'); - await call('setLivestreamStatus', { broadcastId: this.data.broadcast.id, status: 'testing' }); - await waitForBroadcastStatus(this.data.broadcast.id, 'testing'); - document.querySelector('.streaming-popup').dispatchEvent(new Event('broadcastStreamReady')); - } catch (e) { - console.log(e); - } -}); - -Template.broadcastView.events({ - async 'startStreaming .streaming-popup'(e, i) { - await call('setLivestreamStatus', { broadcastId: i.data.broadcast.id, status: 'live' }); - document.querySelector('.streaming-popup').dispatchEvent(new Event('broadcastStream')); - await call('saveRoomSettings', Session.get('openedRoom'), 'streamingOptions', { - id: i.data.broadcast.id, - url: `https://www.youtube.com/embed/${i.data.broadcast.id}`, - thumbnail: `https://img.youtube.com/vi/${i.data.broadcast.id}/0.jpg`, - }); - }, - async 'stopStreaming .streaming-popup'(e, i) { - await call('setBroadcastStatus', { broadcastId: i.data.broadcast.id, status: 'complete' }); - await call('saveRoomSettings', Session.get('openedRoom'), 'streamingOptions', {}, (error) => { - if (error) { - dispatchToastMessage({ type: 'error', message: error }); - return; - } - i.editing.set(false); - i.streamingOptions.set({}); - }); - if (i.mediaRecorder.get()) { - i.mediaRecorder.get().stop(); - i.mediaRecorder.set(null); - } - if (i.mediaStream.get()) { - i.mediaStream - .get() - .getTracks() - .map((track) => track.stop()); - i.mediaStream.set(null); - } - }, -}); diff --git a/apps/meteor/app/livestream/client/views/liveStreamTab.html b/apps/meteor/app/livestream/client/views/liveStreamTab.html deleted file mode 100644 index c92bd08c043f5..0000000000000 --- a/apps/meteor/app/livestream/client/views/liveStreamTab.html +++ /dev/null @@ -1,64 +0,0 @@ - diff --git a/apps/meteor/app/livestream/client/views/liveStreamTab.js b/apps/meteor/app/livestream/client/views/liveStreamTab.js deleted file mode 100644 index f958bbb15f139..0000000000000 --- a/apps/meteor/app/livestream/client/views/liveStreamTab.js +++ /dev/null @@ -1,320 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { Blaze } from 'meteor/blaze'; -import { Session } from 'meteor/session'; -import { Template } from 'meteor/templating'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; - -import { auth } from '../oauth.js'; -import { RocketChatAnnouncement } from '../../../lib'; -import { popout } from '../../../ui-utils'; -import { t } from '../../../utils'; -import { settings } from '../../../settings'; -import { callbacks } from '../../../../lib/callbacks'; -import { hasAllPermission } from '../../../authorization'; -import { Users, Rooms } from '../../../models/client'; -import { dispatchToastMessage } from '../../../../client/lib/toast'; - -export const call = (...args) => - new Promise(function (resolve, reject) { - Meteor.call(...args, function (error, result) { - if (error) { - dispatchToastMessage({ type: 'error', message: error }); - reject(error); - return; - } - resolve(result); - }); - }); - -export const close = (popup) => - new Promise(function (resolve) { - const checkInterval = setInterval(() => { - if (popup.closed) { - clearInterval(checkInterval); - resolve(); - } - }, 300); - }); - -function optionsFromUrl(url) { - const options = {}; - const parsedUrl = url.match( - /(http:|https:|)\/\/(www.)?(youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/|embed\?clip=)?([A-Za-z0-9._%-]*)(\&\S+)?/, - ); - options.url = url; - if (parsedUrl != null) { - options.id = parsedUrl[6]; - if (parsedUrl[3].includes('youtu')) { - options.url = `https://www.youtube.com/embed/${parsedUrl[6]}`; - options.thumbnail = `https://img.youtube.com/vi/${parsedUrl[6]}/0.jpg`; - } - // @TODO add support for other urls - } - return options; -} - -Template.liveStreamTab.helpers({ - broadcastEnabled() { - return !!settings.get('Broadcasting_enabled'); - }, - streamingSource() { - return Template.instance().streamingOptions.get() ? Template.instance().streamingOptions.get().url : ''; - }, - streamingUnavailableMessage() { - return Template.instance().streamingOptions.get() && - Template.instance().streamingOptions.get().message && - Template.instance().streamingOptions.get().message !== '' - ? Template.instance().streamingOptions.get().message - : t('Livestream_not_found'); - }, - thumbnailUrl() { - return Template.instance().streamingOptions.get() ? Template.instance().streamingOptions.get().thumbnail : ''; - }, - hasThumbnail() { - return ( - !!Template.instance().streamingOptions.get() && - !!Template.instance().streamingOptions.get().thumbnail && - Template.instance().streamingOptions.get().thumbnail !== '' - ); - }, - hasSource() { - return ( - !!Template.instance().streamingOptions.get() && - !!Template.instance().streamingOptions.get().url && - Template.instance().streamingOptions.get().url !== '' - ); - }, - canEdit() { - return hasAllPermission('edit-room', this.rid); - }, - editing() { - return ( - Template.instance().editing.get() || - Template.instance().streamingOptions.get() == null || - (Template.instance().streamingOptions.get() != null && - (Template.instance().streamingOptions.get().url == null || Template.instance().streamingOptions.get().url === '')) - ); - }, - canDock() { - const livestreamTabSource = Template.instance().streamingOptions.get().url; - let popoutSource = null; - try { - if (popout.context) { - popoutSource = Blaze.getData(popout.context).data && Blaze.getData(popout.context).data.streamingSource; - } - if (popoutSource != null && livestreamTabSource === popoutSource) { - return true; - } - } catch (e) { - return false; - } - return false; - }, - isPopoutOpen() { - return Template.instance().popoutOpen.get(); - }, - isAudioOnly() { - return Template.instance().streamingOptions.get() ? Template.instance().streamingOptions.get().isAudioOnly : false; - }, -}); - -Template.liveStreamTab.onCreated(function () { - this.editing = new ReactiveVar(false); - this.streamingOptions = new ReactiveVar(); - this.popoutOpen = new ReactiveVar(popout.context != null); - - this.autorun(() => { - const room = Rooms.findOne(this.data.rid, { fields: { streamingOptions: 1 } }); - this.streamingOptions.set(room.streamingOptions); - }); -}); - -Template.liveStreamTab.onDestroyed(function () { - if (popout.docked) { - popout.close(); - } -}); - -Template.liveStreamTab.events({ - 'click .js-cancel'(e, i) { - e.preventDefault(); - i.editing.set(false); - }, - 'click .js-clear'(e, i) { - e.preventDefault(); - - const clearedObject = {}; - - Meteor.call('saveRoomSettings', this.rid, 'streamingOptions', clearedObject, function (error) { - if (error) { - dispatchToastMessage({ type: 'error', message: error }); - return; - } - i.editing.set(false); - i.streamingOptions.set(clearedObject); - const roomAnnouncement = new RocketChatAnnouncement().getByRoom(i.data.rid); - if (roomAnnouncement.getMessage() !== '') { - roomAnnouncement.clear(); - } - return dispatchToastMessage({ - type: 'success', - message: TAPi18n.__('Livestream_source_changed_succesfully'), - }); - }); - }, - 'click .js-save'(e, i) { - e.preventDefault(); - - const streamingOptions = { - ...optionsFromUrl(i.find('[name=streaming-source]').value), - isAudioOnly: i.find('[name=streaming-audio-only]').checked, - message: i.find('[name=streaming-message]').value, - type: 'livestream', - }; - - Meteor.call('saveRoomSettings', this.rid, 'streamingOptions', streamingOptions, function (error) { - if (error) { - dispatchToastMessage({ type: 'error', message: error }); - return; - } - i.editing.set(false); - i.streamingOptions.set(streamingOptions); - if (streamingOptions.url !== '') { - new RocketChatAnnouncement({ - room: i.data.rid, - message: 'Broadcast is now live. Click here to watch!', - callback: 'openBroadcast', - }).save(); - } else { - const roomAnnouncement = new RocketChatAnnouncement().getByRoom(i.data.rid); - if (roomAnnouncement.getMessage() !== '') { - roomAnnouncement.clear(); - } - } - - return dispatchToastMessage({ - type: 'success', - message: TAPi18n.__('Livestream_source_changed_succesfully'), - }); - }); - }, - 'click .streaming-source-settings'(e, i) { - e.preventDefault(); - i.editing.set(true); - }, - 'click .js-dock'(e) { - e.stopPropagation(); - popout.docked = true; - }, - 'click .js-close'(e, i) { - e.stopPropagation(); - let popoutSource = ''; - if (popout.context) { - popoutSource = Blaze.getData(popout.context).data && Blaze.getData(popout.context).data.streamingSource; - } - popout.close(); - if (popoutSource !== Template.instance().streamingOptions.get().url) { - popout.open({ - content: 'liveStreamView', - data: { - streamingSource: i.streamingOptions.get().url, - isAudioOnly: i.streamingOptions.get().isAudioOnly, - showVideoControls: true, - streamingOptions: i.streamingOptions.get(), - }, - onCloseCallback: () => i.popoutOpen.set(false), - }); - } - }, - 'submit .liveStreamTab__form'(e, i) { - e.preventDefault(); - e.stopPropagation(); - - const streamingOptions = { - ...optionsFromUrl(i.find('[name=streaming-source]').value), - isAudioOnly: i.find('[name=streaming-audio-only]').checked, - message: i.find('[name=streaming-message]').value, - type: 'livestream', - }; - - Meteor.call('saveRoomSettings', this.rid, 'streamingOptions', streamingOptions, function (error) { - if (error) { - dispatchToastMessage({ type: 'error', message: error }); - return; - } - i.editing.set(false); - i.streamingOptions.set(streamingOptions); - if (streamingOptions.url !== '') { - new RocketChatAnnouncement({ - room: i.data.rid, - message: 'Broadcast is now live. Click here to watch!', - callback: 'openBroadcast', - }).save(); - } else { - const roomAnnouncement = new RocketChatAnnouncement().getByRoom(i.data.rid); - if (roomAnnouncement.getMessage() !== '') { - roomAnnouncement.clear(); - } - } - return dispatchToastMessage({ - type: 'success', - message: TAPi18n.__('Livestream_source_changed_succesfully'), - }); - }); - }, - 'click .js-popout'(e, i) { - e.preventDefault(); - popout.open({ - content: 'liveStreamView', - data: { - streamingSource: i.streamingOptions.get().url, - isAudioOnly: i.streamingOptions.get().isAudioOnly, - showVideoControls: true, - streamingOptions: i.streamingOptions.get(), - }, - onCloseCallback: () => i.popoutOpen.set(false), - }); - i.popoutOpen.set(true); - }, - async 'click .js-broadcast'(e, i) { - e.preventDefault(); - e.currentTarget.classList.add('loading'); - try { - const user = Users.findOne({ _id: Meteor.userId() }, { fields: { 'settings.livestream': 1 } }); - if (!user.settings || !user.settings.livestream) { - await auth(); - } - const result = await call('livestreamGet', { rid: i.data.rid }); - popout.open({ - content: 'broadcastView', - data: { - ...result, - showVideoControls: false, - showStreamControls: true, - }, - onCloseCallback: () => i.popoutOpen.set(false), - }); - } catch (e) { - console.log(e); - } finally { - e.currentTarget.classList.remove('loading'); - } - }, -}); - -callbacks.add('openBroadcast', (rid) => { - const roomData = Session.get(`roomData${rid}`); - if (!roomData) { - return; - } - popout.open({ - content: 'liveStreamView', - data: { - streamingSource: roomData.streamingOptions.url, - isAudioOnly: roomData.streamingOptions.isAudioOnly, - showVideoControls: true, - streamingOptions: roomData.streamingOptions, - }, - }); -}); diff --git a/apps/meteor/app/livestream/client/views/liveStreamView.html b/apps/meteor/app/livestream/client/views/liveStreamView.html deleted file mode 100644 index 765b2b52bcf7e..0000000000000 --- a/apps/meteor/app/livestream/client/views/liveStreamView.html +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/apps/meteor/app/livestream/client/views/liveStreamView.js b/apps/meteor/app/livestream/client/views/liveStreamView.js deleted file mode 100644 index 06368ad6cfa06..0000000000000 --- a/apps/meteor/app/livestream/client/views/liveStreamView.js +++ /dev/null @@ -1,68 +0,0 @@ -import { ReactiveVar } from 'meteor/reactive-var'; -import { Template } from 'meteor/templating'; - -this.onYouTubePlayerAPIReady = function () { - const playerReadyEvent = new Event('playerReady'); - document.querySelector('.streaming-popup').dispatchEvent(playerReadyEvent); -}; -this.liveStreamPlayer = null; - -Template.liveStreamView.onCreated(function () { - this.streamingOptions = new ReactiveVar(this.data.streamingOptions); -}); - -Template.liveStreamView.onRendered(function () { - if (window.YT) { - window.liveStreamPlayer = new window.YT.Player('ytplayer', { - width: '380', - height: '214', - videoId: this.data.streamingOptions.id || '', - playerVars: { - autoplay: 1, - controls: 0, - showinfo: 0, - enablejsapi: 1, - fs: 0, - modestbranding: 1, - rel: 0, - }, - events: { - onStateChange: (e) => { - const playerStateChangedEvent = new CustomEvent('playerStateChanged', { detail: e.data }); - document.querySelector('.rc-popout').dispatchEvent(playerStateChangedEvent); - }, - }, - }); - } else { - const tag = document.createElement('script'); - tag.src = 'https://www.youtube.com/player_api'; - tag.type = 'text/javascript'; - const firstScriptTag = document.body.getElementsByTagName('script')[0]; - firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); - } -}); - -Template.liveStreamView.events({ - 'playerReady .streaming-popup'(e, i) { - window.liveStreamPlayer = new window.YT.Player('ytplayer', { - width: '380', - height: '214', - videoId: i.streamingOptions.get().id || '', - playerVars: { - autoplay: 1, - controls: 0, - showinfo: 0, - enablejsapi: 1, - fs: 0, - modestbranding: 1, - rel: 0, - }, - events: { - onStateChange: (e) => { - const playerStateChangedEvent = new CustomEvent('playerStateChanged', { detail: e.data }); - document.querySelector('.rc-popout').dispatchEvent(playerStateChangedEvent); - }, - }, - }); - }, -}); diff --git a/apps/meteor/app/livestream/client/views/livestreamBroadcast.html b/apps/meteor/app/livestream/client/views/livestreamBroadcast.html deleted file mode 100644 index 1340a89ddf950..0000000000000 --- a/apps/meteor/app/livestream/client/views/livestreamBroadcast.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/apps/meteor/app/livestream/client/views/livestreamBroadcast.js b/apps/meteor/app/livestream/client/views/livestreamBroadcast.js deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/apps/meteor/app/livestream/server/functions/livestream.js b/apps/meteor/app/livestream/server/functions/livestream.js deleted file mode 100644 index f17a5524c93d9..0000000000000 --- a/apps/meteor/app/livestream/server/functions/livestream.js +++ /dev/null @@ -1,158 +0,0 @@ -import { google } from 'googleapis'; - -const { OAuth2 } = google.auth; - -const p = (fn) => - new Promise(function (resolve, reject) { - fn(function (err, value) { - if (err) { - return reject(err); - } - resolve(value.data); - }); - }); - -export const getBroadcastStatus = async ({ id, access_token, refresh_token, clientId, clientSecret }) => { - const auth = new OAuth2(clientId, clientSecret); - - auth.setCredentials({ - access_token, - refresh_token, - }); - const youtube = google.youtube({ version: 'v3', auth }); - const result = await p((resolve) => - youtube.liveBroadcasts.list( - { - part: 'id,status', - id, - }, - resolve, - ), - ); - return result.items && result.items[0] && result.items[0].status.lifeCycleStatus; -}; - -export const statusStreamLiveStream = async ({ id, access_token, refresh_token, clientId, clientSecret }) => { - const auth = new OAuth2(clientId, clientSecret); - - auth.setCredentials({ - access_token, - refresh_token, - }); - - const youtube = google.youtube({ version: 'v3', auth }); - const result = await p((resolve) => - youtube.liveStreams.list( - { - part: 'id,status', - id, - }, - resolve, - ), - ); - return result.items && result.items[0].status.streamStatus; -}; - -export const statusLiveStream = ({ id, access_token, refresh_token, clientId, clientSecret, status }) => { - const auth = new OAuth2(clientId, clientSecret); - - auth.setCredentials({ - access_token, - refresh_token, - }); - - const youtube = google.youtube({ version: 'v3', auth }); - - return p((resolve) => - youtube.liveBroadcasts.transition( - { - part: 'id,status', - id, - broadcastStatus: status, - }, - resolve, - ), - ); -}; - -export const setBroadcastStatus = ({ id, access_token, refresh_token, clientId, clientSecret, status }) => { - const auth = new OAuth2(clientId, clientSecret); - - auth.setCredentials({ - access_token, - refresh_token, - }); - - const youtube = google.youtube({ version: 'v3', auth }); - - return p((resolve) => - youtube.liveBroadcasts.transition( - { - part: 'id,status', - id, - broadcastStatus: status, - }, - resolve, - ), - ); -}; - -export const createLiveStream = async ({ room, access_token, refresh_token, clientId, clientSecret }) => { - const auth = new OAuth2(clientId, clientSecret); - auth.setCredentials({ - access_token, - refresh_token, - }); - const youtube = google.youtube({ version: 'v3', auth }); - - const [stream, broadcast] = await Promise.all([ - p((resolve) => - youtube.liveStreams.insert( - { - part: 'id,snippet,cdn,contentDetails,status', - resource: { - snippet: { - title: room.name || 'RocketChat Broadcast', - }, - cdn: { - format: '480p', - ingestionType: 'rtmp', - }, - }, - }, - resolve, - ), - ), - p((resolve) => - youtube.liveBroadcasts.insert( - { - part: 'id,snippet,contentDetails,status', - resource: { - snippet: { - title: room.name || 'RocketChat Broadcast', - scheduledStartTime: new Date().toISOString(), - }, - status: { - privacyStatus: 'unlisted', - }, - }, - }, - resolve, - ), - ), - ]); - - await p((resolve) => - youtube.liveBroadcasts.bind( - { - part: 'id,snippet,status', - // resource: { - id: broadcast.id, - streamId: stream.id, - }, - resolve, - ), - ); - - return { id: stream.cdn.ingestionInfo.streamName, stream, broadcast }; -}; diff --git a/apps/meteor/app/livestream/server/index.js b/apps/meteor/app/livestream/server/index.js deleted file mode 100644 index 9254662a155af..0000000000000 --- a/apps/meteor/app/livestream/server/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import './routes.js'; -import './methods.js'; -import './settings'; diff --git a/apps/meteor/app/livestream/server/methods.js b/apps/meteor/app/livestream/server/methods.js deleted file mode 100644 index f9942c3e7d8a9..0000000000000 --- a/apps/meteor/app/livestream/server/methods.js +++ /dev/null @@ -1,139 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { createLiveStream, statusLiveStream, statusStreamLiveStream, getBroadcastStatus, setBroadcastStatus } from './functions/livestream'; -import { settings } from '../../settings/server'; -import { Rooms } from '../../models/server'; - -const selectLivestreamSettings = (user) => user && user.settings && user.settings.livestream; - -Meteor.methods({ - async livestreamStreamStatus({ streamId }) { - if (!streamId) { - // TODO: change error - throw new Meteor.Error('error-not-allowed', 'Livestream ID not found', { - method: 'livestreamStreamStatus', - }); - } - const livestreamSettings = selectLivestreamSettings(Meteor.user()); - - if (!livestreamSettings) { - throw new Meteor.Error('error-not-allowed', 'You have no settings to stream', { - method: 'livestreamStreamStatus', - }); - } - - const { access_token, refresh_token } = livestreamSettings; - - return statusStreamLiveStream({ - id: streamId, - access_token, - refresh_token, - clientId: settings.get('Broadcasting_client_id'), - clientSecret: settings.get('Broadcasting_client_secret'), - }); - }, - async setLivestreamStatus({ broadcastId, status }) { - if (!broadcastId) { - // TODO: change error - throw new Meteor.Error('error-not-allowed', 'You have no settings to livestream', { - method: 'livestreamStart', - }); - } - const livestreamSettings = selectLivestreamSettings(Meteor.user()); - - if (!livestreamSettings) { - throw new Meteor.Error('error-not-allowed', 'You have no settings to livestream', { - method: 'livestreamStart', - }); - } - - const { access_token, refresh_token } = livestreamSettings; - - return statusLiveStream({ - id: broadcastId, - access_token, - refresh_token, - status, - clientId: settings.get('Broadcasting_client_id'), - clientSecret: settings.get('Broadcasting_client_secret'), - }); - }, - async livestreamGet({ rid }) { - const livestreamSettings = selectLivestreamSettings(Meteor.user()); - - if (!livestreamSettings) { - throw new Meteor.Error('error-not-allowed', 'You have no settings to livestream', { - method: 'livestreamGet', - }); - } - - const room = Rooms.findOne({ _id: rid }); - - if (!room) { - // TODO: change error - throw new Meteor.Error('error-not-allowed', 'You have no settings to livestream', { - method: 'livestreamGet', - }); - } - - const { access_token, refresh_token } = livestreamSettings; - return createLiveStream({ - room, - access_token, - refresh_token, - clientId: settings.get('Broadcasting_client_id'), - clientSecret: settings.get('Broadcasting_client_secret'), - }); - }, - async getBroadcastStatus({ broadcastId }) { - if (!broadcastId) { - // TODO: change error - throw new Meteor.Error('error-not-allowed', 'Broadcast ID not found', { - method: 'getBroadcastStatus', - }); - } - const livestreamSettings = selectLivestreamSettings(Meteor.user()); - - if (!livestreamSettings) { - throw new Meteor.Error('error-not-allowed', 'You have no settings to stream', { - method: 'getBroadcastStatus', - }); - } - - const { access_token, refresh_token } = livestreamSettings; - - return getBroadcastStatus({ - id: broadcastId, - access_token, - refresh_token, - clientId: settings.get('Broadcasting_client_id'), - clientSecret: settings.get('Broadcasting_client_secret'), - }); - }, - async setBroadcastStatus({ broadcastId, status }) { - if (!broadcastId) { - // TODO: change error - throw new Meteor.Error('error-not-allowed', 'Broadcast ID not found', { - method: 'setBroadcastStatus', - }); - } - const livestreamSettings = selectLivestreamSettings(Meteor.user()); - - if (!livestreamSettings) { - throw new Meteor.Error('error-not-allowed', 'You have no settings to stream', { - method: 'setBroadcastStatus', - }); - } - - const { access_token, refresh_token } = livestreamSettings; - - return setBroadcastStatus({ - id: broadcastId, - access_token, - refresh_token, - status, - clientId: settings.get('Broadcasting_client_id'), - clientSecret: settings.get('Broadcasting_client_secret'), - }); - }, -}); diff --git a/apps/meteor/app/livestream/server/routes.js b/apps/meteor/app/livestream/server/routes.js deleted file mode 100644 index 93f340ff5eebd..0000000000000 --- a/apps/meteor/app/livestream/server/routes.js +++ /dev/null @@ -1,65 +0,0 @@ -import { google } from 'googleapis'; - -import { settings } from '../../settings/server'; -import { Users } from '../../models/server'; -import { API } from '../../api/server'; - -const { OAuth2 } = google.auth; - -API.v1.addRoute('livestream/oauth', { - get: function functionName() { - const clientAuth = new OAuth2( - settings.get('Broadcasting_client_id'), - settings.get('Broadcasting_client_secret'), - `${settings.get('Site_Url')}/api/v1/livestream/oauth/callback`.replace(/\/{2}api/g, '/api'), - ); - const { userId } = this.queryParams; - const url = clientAuth.generateAuthUrl({ - access_type: 'offline', - scope: ['https://www.googleapis.com/auth/youtube'], - state: JSON.stringify({ - userId, - }), - }); - - return { - statusCode: 302, - headers: { - Location: url, - }, - body: 'Oauth redirect', - }; - }, -}); - -API.v1.addRoute('livestream/oauth/callback', { - get: function functionName() { - const { code, state } = this.queryParams; - - const { userId } = JSON.parse(state); - - const clientAuth = new OAuth2( - settings.get('Broadcasting_client_id'), - settings.get('Broadcasting_client_secret'), - `${settings.get('Site_Url')}/api/v1/livestream/oauth/callback`.replace(/\/{2}api/g, '/api'), - ); - - const ret = Promise.await(clientAuth.getToken(code)); - - Users.update( - { _id: userId }, - { - $set: { - 'settings.livestream': ret, - }, - }, - ); - - return { - headers: { - 'content-type': 'text/html', - }, - body: '', - }; - }, -}); diff --git a/apps/meteor/app/livestream/server/settings.ts b/apps/meteor/app/livestream/server/settings.ts deleted file mode 100644 index 3e859bb32ca2f..0000000000000 --- a/apps/meteor/app/livestream/server/settings.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { settingsRegistry } from '../../settings/server'; - -Meteor.startup(function () { - settingsRegistry.addGroup('LiveStream & Broadcasting', function () { - this.add('Livestream_enabled', false, { - type: 'boolean', - public: true, - alert: 'This feature is currently in beta! Please report bugs to github.com/RocketChat/Rocket.Chat/issues', - }); - - this.add('Broadcasting_enabled', false, { - type: 'boolean', - public: true, - alert: 'This feature is currently in beta! Please report bugs to github.com/RocketChat/Rocket.Chat/issues', - enableQuery: { _id: 'Livestream_enabled', value: true }, - }); - - this.add('Broadcasting_client_id', '', { - type: 'string', - public: false, - enableQuery: { _id: 'Broadcasting_enabled', value: true }, - }); - this.add('Broadcasting_client_secret', '', { - type: 'string', - public: false, - enableQuery: { _id: 'Broadcasting_enabled', value: true }, - }); - this.add('Broadcasting_api_key', '', { - type: 'string', - public: false, - enableQuery: { _id: 'Broadcasting_enabled', value: true }, - }); - this.add('Broadcasting_media_server_url', '', { - type: 'string', - public: true, - enableQuery: { _id: 'Broadcasting_enabled', value: true }, - }); - }); -}); diff --git a/apps/meteor/app/logger/client/logger.js b/apps/meteor/app/logger/client/logger.js index 5d3bbe9e90c7a..342165032e6f9 100644 --- a/apps/meteor/app/logger/client/logger.js +++ b/apps/meteor/app/logger/client/logger.js @@ -1,5 +1,4 @@ import { Template } from 'meteor/templating'; -import _ from 'underscore'; import { getConfig } from '../../../client/lib/utils/getConfig'; @@ -43,10 +42,7 @@ if (Template.log) { return dict[name]; } }; - _.each(name, (fn, name) => { - fn1(name, fn); - }); - return original.call(template, dict); + return original.call(this, Object.fromEntries(Object.entries(dict).map(([key, value]) => [key, fn1(key, value)]))); }; }; @@ -61,7 +57,7 @@ if (Template.log) { const wrap = function (...args) { const result = fn.apply(this, args); if (Template.log === true) { - const completeName = `${prefix}:${template.viewName.replace('Template.', '')}.${name}`; + const completeName = `${prefix}:${template.viewName.replace('Template.', '')}`; if (Template.logMatch.test(completeName)) { console.log(`%c${completeName}`, `color: ${color}; font-weight: bold`, { args, diff --git a/apps/meteor/app/mail-messages/server/functions/sendMail.ts b/apps/meteor/app/mail-messages/server/functions/sendMail.ts index cec6b8c6d1c29..36dd1ad5c7a9e 100644 --- a/apps/meteor/app/mail-messages/server/functions/sendMail.ts +++ b/apps/meteor/app/mail-messages/server/functions/sendMail.ts @@ -9,7 +9,19 @@ import { placeholders } from '../../../utils/server'; import { SystemLogger } from '../../../../server/lib/logger/system'; import * as Mailer from '../../../mailer'; -export const sendMail = function (from: string, subject: string, body: string, dryrun: boolean, query: string): void { +export const sendMail = function ({ + from, + subject, + body, + dryrun, + query, +}: { + from: string; + subject: string; + body: string; + dryrun?: boolean; + query?: string; +}): void { Mailer.checkAddressFormatAndThrow(from, 'Mailer.sendMail'); if (body.indexOf('[unsubscribe]') === -1) { diff --git a/apps/meteor/app/mail-messages/server/methods/sendMail.ts b/apps/meteor/app/mail-messages/server/methods/sendMail.ts index 80f3df8a40739..48253c07ab83b 100644 --- a/apps/meteor/app/mail-messages/server/methods/sendMail.ts +++ b/apps/meteor/app/mail-messages/server/methods/sendMail.ts @@ -2,9 +2,12 @@ import { Meteor } from 'meteor/meteor'; import { Mailer } from '../lib/Mailer'; import { hasPermission } from '../../../authorization/server'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ 'Mailer.sendMail'(from, subject, body, dryrun, query) { + methodDeprecationLogger.warn('Mailer.sendMail will be deprecated in future versions of Rocket.Chat'); + const userId = Meteor.userId(); if (!userId || !hasPermission(userId, 'send-mail')) { @@ -13,7 +16,7 @@ Meteor.methods({ }); } - return Mailer.sendMail(from, subject, body, dryrun, query); + return Mailer.sendMail({ from, subject, body, dryrun, query }); }, }); diff --git a/apps/meteor/app/mail-messages/server/methods/unsubscribe.ts b/apps/meteor/app/mail-messages/server/methods/unsubscribe.ts index 4dc886c6c94c2..75e5398bae7de 100644 --- a/apps/meteor/app/mail-messages/server/methods/unsubscribe.ts +++ b/apps/meteor/app/mail-messages/server/methods/unsubscribe.ts @@ -2,9 +2,12 @@ import { Meteor } from 'meteor/meteor'; import { DDPRateLimiter } from 'meteor/ddp-rate-limiter'; import { Mailer } from '../lib/Mailer'; +import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger'; Meteor.methods({ 'Mailer:unsubscribe'(_id, createdAt) { + methodDeprecationLogger.warn('Mailer:unsubscribe will be deprecated in future versions of Rocket.Chat'); + return Mailer.unsubscribe(_id, createdAt); }, }); diff --git a/apps/meteor/app/mailer/server/api.ts b/apps/meteor/app/mailer/server/api.ts index 6f9bb6e7d6676..451d67a3f2fab 100644 --- a/apps/meteor/app/mailer/server/api.ts +++ b/apps/meteor/app/mailer/server/api.ts @@ -2,7 +2,6 @@ import { Meteor } from 'meteor/meteor'; import { Email } from 'meteor/email'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; import _ from 'underscore'; -import s from 'underscore.string'; import juice from 'juice'; import stripHtml from 'string-strip-html'; import { escapeHTML } from '@rocket.chat/string-helpers'; @@ -11,8 +10,9 @@ import { Settings } from '@rocket.chat/models'; import { settings } from '../../settings/server'; import { replaceVariables } from './replaceVariables'; -import { Apps } from '../../apps/server'; +import { Apps } from '../../../ee/server/apps'; import { validateEmail } from '../../../lib/emailValidator'; +import { strLeft, strRightBack } from '../../../lib/utils/stringUtils'; let contentHeader: string | undefined; let contentFooter: string | undefined; @@ -41,8 +41,8 @@ export const replace = (str: string, data: { [key: string]: unknown } = {}): str Site_URL_Slash: settings.get('Site_Url')?.replace(/\/?$/, '/'), ...(data.name ? { - fname: s.strLeft(String(data.name), ' '), - lname: s.strRightBack(String(data.name), ' '), + fname: strLeft(String(data.name), ' '), + lname: strRightBack(String(data.name), ' '), } : {}), ...data, @@ -145,7 +145,7 @@ export const sendNoWrap = ({ text, headers, }: { - to: string; + to: string | string[]; from: string; replyTo?: string; subject: string; @@ -184,7 +184,7 @@ export const send = ({ data, headers, }: { - to: string; + to: string | string[]; from: string; replyTo?: string; subject: string; diff --git a/apps/meteor/app/markdown/lib/markdown.js b/apps/meteor/app/markdown/lib/markdown.js index 7ee511d403e48..8a8c67f7ef72b 100644 --- a/apps/meteor/app/markdown/lib/markdown.js +++ b/apps/meteor/app/markdown/lib/markdown.js @@ -5,15 +5,12 @@ import { Meteor } from 'meteor/meteor'; import { escapeHTML } from '@rocket.chat/string-helpers'; -import { marked } from './parser/marked/marked'; import { original } from './parser/original/original'; import { filtered } from './parser/filtered/filtered'; import { code } from './parser/original/code'; -import { settings } from '../../settings'; const parsers = { original, - marked, filtered, }; @@ -33,29 +30,11 @@ class MarkdownClass { } parseMessageNotEscaped(message) { - const parser = settings.get('Markdown_Parser'); - - if (parser === 'disabled') { - return message; - } - const options = { - supportSchemesForLink: settings.get('Markdown_SupportSchemesForLink'), - headers: settings.get('Markdown_Headers'), rootUrl: Meteor.absoluteUrl(), - marked: { - gfm: settings.get('Markdown_Marked_GFM'), - tables: settings.get('Markdown_Marked_Tables'), - breaks: settings.get('Markdown_Marked_Breaks'), - pedantic: settings.get('Markdown_Marked_Pedantic'), - smartLists: settings.get('Markdown_Marked_SmartLists'), - smartypants: settings.get('Markdown_Marked_Smartypants'), - }, }; - const parse = typeof parsers[parser] === 'function' ? parsers[parser] : parsers.original; - - return parse(message, options); + return parsers.original(message, options); } mountTokensBackRecursively(message, tokenList, useHtml = true) { @@ -91,9 +70,7 @@ class MarkdownClass { } filterMarkdownFromMessage(message) { - return parsers.filtered(message, { - supportSchemesForLink: settings.get('Markdown_SupportSchemesForLink'), - }); + return parsers.filtered(message); } } @@ -101,20 +78,15 @@ export const Markdown = new MarkdownClass(); export const filterMarkdown = (message) => Markdown.filterMarkdownFromMessage(message); -export const createMarkdownMessageRenderer = ({ parser, ...options }) => { - if (!parser || parser === 'disabled') { - return (message) => message; - } - - const parse = typeof parsers[parser] === 'function' ? parsers[parser] : parsers.original; - - return (message) => { +export const createMarkdownMessageRenderer = ({ ...options }) => { + const markedParser = parsers.marked; + return (message, useMarkedParser = false) => { if (!message?.html?.trim()) { return message; } - return parse(message, options); + return useMarkedParser ? markedParser(message, options) : parsers.original(message, options); }; }; -export const createMarkdownNotificationRenderer = (options) => (message) => parsers.filtered(message, options); +export const createMarkdownNotificationRenderer = () => (message) => parsers.filtered(message); diff --git a/apps/meteor/app/markdown/lib/parser/marked/marked.js b/apps/meteor/app/markdown/lib/parser/marked/marked.js deleted file mode 100644 index a1aff30618c42..0000000000000 --- a/apps/meteor/app/markdown/lib/parser/marked/marked.js +++ /dev/null @@ -1,106 +0,0 @@ -import { Random } from 'meteor/random'; -import _ from 'underscore'; -import { marked as _marked } from 'marked'; -import createDOMPurify from 'dompurify'; -import { unescapeHTML, escapeHTML } from '@rocket.chat/string-helpers'; - -import hljs, { register } from '../../hljs'; -import { getGlobalWindow } from '../../getGlobalWindow'; - -const renderer = new _marked.Renderer(); - -let msg = null; - -renderer.code = function (code, lang, escaped) { - if (this.options.highlight) { - const out = this.options.highlight(code, lang); - if (out != null && out !== code) { - escaped = true; - code = out; - } - } - - let text = null; - - if (!lang) { - text = `
    ${escaped ? code : escapeHTML(code)}
    `; - } else { - text = `
    ${escaped ? code : escapeHTML(code)}
    `; - } - - if (_.isString(msg)) { - return text; - } - - const token = `=!=${Random.id()}=!=`; - msg.tokens.push({ - highlight: true, - token, - text, - }); - - return token; -}; - -renderer.codespan = function (text) { - text = `${text}`; - if (_.isString(msg)) { - return text; - } - - const token = `=!=${Random.id()}=!=`; - msg.tokens.push({ - token, - text, - }); - - return token; -}; - -renderer.blockquote = function (quote) { - return `
    ${quote}
    `; -}; - -const linkRenderer = renderer.link; -renderer.link = function (href, title, text) { - const html = linkRenderer.call(renderer, href, title, text); - return html.replace(/^ { - msg = message; - - if (!message.tokens) { - message.tokens = []; - } - - message.html = _marked.parse(unescapeHTML(message.html), { - gfm, - tables, - breaks, - pedantic, - smartLists, - smartypants, - renderer, - highlight, - }); - - const window = getGlobalWindow(); - const DomPurify = createDOMPurify(window); - message.html = DomPurify.sanitize(message.html, { ADD_ATTR: ['target'], FORBID_ATTR: ['style'], FORBID_TAGS: ['style'] }); - - return message; -}; diff --git a/apps/meteor/app/markdown/server/index.js b/apps/meteor/app/markdown/server/index.js index 9b4f3084c58b8..8cf4e3078e484 100644 --- a/apps/meteor/app/markdown/server/index.js +++ b/apps/meteor/app/markdown/server/index.js @@ -2,35 +2,20 @@ import { Meteor } from 'meteor/meteor'; import { Tracker } from 'meteor/tracker'; import { callbacks } from '../../../lib/callbacks'; -import { settings } from '../../settings/server'; import { createMarkdownMessageRenderer, createMarkdownNotificationRenderer } from '../lib/markdown'; -import './settings'; export { Markdown } from '../lib/markdown'; Meteor.startup(() => { Tracker.autorun(() => { const options = { - parser: settings.get('Markdown_Parser'), - supportSchemesForLink: settings.get('Markdown_SupportSchemesForLink'), - headers: settings.get('Markdown_Headers'), rootUrl: Meteor.absoluteUrl(), - marked: { - gfm: settings.get('Markdown_Marked_GFM'), - tables: settings.get('Markdown_Marked_Tables'), - breaks: settings.get('Markdown_Marked_Breaks'), - pedantic: settings.get('Markdown_Marked_Pedantic'), - smartLists: settings.get('Markdown_Marked_SmartLists'), - smartypants: settings.get('Markdown_Marked_Smartypants'), - }, }; const renderMessage = createMarkdownMessageRenderer(options); callbacks.add('renderMessage', renderMessage, callbacks.priority.HIGH, 'markdown'); }); - const renderNotification = createMarkdownNotificationRenderer({ - supportSchemesForLink: settings.get('Markdown_SupportSchemesForLink'), - }); + const renderNotification = createMarkdownNotificationRenderer(); callbacks.add('renderNotification', renderNotification, callbacks.priority.HIGH, 'filter-markdown'); }); diff --git a/apps/meteor/app/markdown/server/settings.ts b/apps/meteor/app/markdown/server/settings.ts deleted file mode 100644 index b2f2310590970..0000000000000 --- a/apps/meteor/app/markdown/server/settings.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { settingsRegistry } from '../../settings/server'; - -settingsRegistry.add('Markdown_Parser', 'original', { - type: 'select', - values: [ - { - key: 'disabled', - i18nLabel: 'Disabled', - }, - { - key: 'original', - i18nLabel: 'Original', - }, - { - key: 'marked', - i18nLabel: 'Marked', - }, - ], - group: 'Message', - section: 'Markdown', - public: true, - alert: 'Use_Legacy_Message_Template_alert', -}); - -const enableQueryOriginal = { _id: 'Markdown_Parser', value: 'original' }; -settingsRegistry.add('Markdown_Headers', false, { - type: 'boolean', - group: 'Message', - section: 'Markdown', - public: true, - enableQuery: enableQueryOriginal, -}); -settingsRegistry.add('Markdown_SupportSchemesForLink', 'http,https', { - type: 'string', - group: 'Message', - section: 'Markdown', - public: true, - i18nDescription: 'Markdown_SupportSchemesForLink_Description', - enableQuery: enableQueryOriginal, -}); - -const enableQueryMarked = { _id: 'Markdown_Parser', value: 'marked' }; -settingsRegistry.add('Markdown_Marked_GFM', true, { - type: 'boolean', - group: 'Message', - section: 'Markdown', - public: true, - enableQuery: enableQueryMarked, -}); -settingsRegistry.add('Markdown_Marked_Tables', true, { - type: 'boolean', - group: 'Message', - section: 'Markdown', - public: true, - enableQuery: enableQueryMarked, -}); -settingsRegistry.add('Markdown_Marked_Breaks', true, { - type: 'boolean', - group: 'Message', - section: 'Markdown', - public: true, - enableQuery: enableQueryMarked, -}); -settingsRegistry.add('Markdown_Marked_Pedantic', false, { - type: 'boolean', - group: 'Message', - section: 'Markdown', - public: true, - enableQuery: [ - { - _id: 'Markdown_Parser', - value: 'marked', - }, - { - _id: 'Markdown_Marked_GFM', - value: false, - }, - ], -}); -settingsRegistry.add('Markdown_Marked_SmartLists', true, { - type: 'boolean', - group: 'Message', - section: 'Markdown', - public: true, - enableQuery: enableQueryMarked, -}); -settingsRegistry.add('Markdown_Marked_Smartypants', true, { - type: 'boolean', - group: 'Message', - section: 'Markdown', - public: true, - enableQuery: enableQueryMarked, -}); diff --git a/apps/meteor/app/mentions-flextab/client/actionButton.ts b/apps/meteor/app/mentions-flextab/client/actionButton.ts deleted file mode 100644 index 564f519d908f9..0000000000000 --- a/apps/meteor/app/mentions-flextab/client/actionButton.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Template } from 'meteor/templating'; -import { FlowRouter } from 'meteor/kadira:flow-router'; - -import { MessageAction, RoomHistoryManager } from '../../ui-utils/client'; -import { messageArgs } from '../../../client/lib/utils/messageArgs'; -import { Rooms } from '../../models/client'; - -Meteor.startup(function () { - MessageAction.addButton({ - id: 'jump-to-message', - icon: 'jump', - label: 'Jump_to_message', - context: ['mentions', 'threads'], - action(e, props) { - e.preventDefault(); - e.stopPropagation(); - const { message = messageArgs(this).msg } = props; - if (window.matchMedia('(max-width: 500px)').matches) { - (Template.currentData() as any).tabBar.close(); - } - if (message.tmid) { - return FlowRouter.go( - FlowRouter.getRouteName(), - { - tab: 'thread', - context: message.tmid, - rid: message.rid, - name: Rooms.findOne({ _id: message.rid }).name, - }, - { - jump: message._id, - }, - ); - } - RoomHistoryManager.getSurroundingMessages(message, 50); - }, - order: 100, - group: ['message', 'menu'], - }); -}); diff --git a/apps/meteor/app/mentions-flextab/client/index.js b/apps/meteor/app/mentions-flextab/client/index.js deleted file mode 100644 index f1443a9803229..0000000000000 --- a/apps/meteor/app/mentions-flextab/client/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import './views/mentionsFlexTab.html'; -import './views/mentionsFlexTab'; -import './actionButton'; -import './tabBar'; diff --git a/apps/meteor/app/mentions-flextab/client/tabBar.ts b/apps/meteor/app/mentions-flextab/client/tabBar.ts deleted file mode 100644 index 1699005c02f1d..0000000000000 --- a/apps/meteor/app/mentions-flextab/client/tabBar.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { isRoomFederated } from '@rocket.chat/core-typings'; - -import { addAction } from '../../../client/views/room/lib/Toolbox'; - -addAction('mentions', ({ room }) => { - const federated = isRoomFederated(room); - - return { - groups: ['channel', 'group', 'team'], - id: 'mentions', - title: 'Mentions', - icon: 'at', - template: 'mentionsFlexTab', - ...(federated && { - 'disabled': true, - 'data-tooltip': 'Mentions_unavailable_for_federation', - }), - order: 9, - }; -}); diff --git a/apps/meteor/app/mentions-flextab/client/views/mentionsFlexTab.html b/apps/meteor/app/mentions-flextab/client/views/mentionsFlexTab.html deleted file mode 100644 index 4884793a3156b..0000000000000 --- a/apps/meteor/app/mentions-flextab/client/views/mentionsFlexTab.html +++ /dev/null @@ -1,21 +0,0 @@ - diff --git a/apps/meteor/app/mentions-flextab/client/views/mentionsFlexTab.js b/apps/meteor/app/mentions-flextab/client/views/mentionsFlexTab.js deleted file mode 100644 index 92b10b8a57d06..0000000000000 --- a/apps/meteor/app/mentions-flextab/client/views/mentionsFlexTab.js +++ /dev/null @@ -1,86 +0,0 @@ -import _ from 'underscore'; -import { Meteor } from 'meteor/meteor'; -import { Mongo } from 'meteor/mongo'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { Template } from 'meteor/templating'; - -import { messageContext } from '../../../ui-utils/client/lib/messageContext'; -import { upsertMessageBulk } from '../../../ui-utils/client/lib/RoomHistoryManager'; -import { APIClient } from '../../../utils/client'; -import { Messages, Users } from '../../../models/client'; -import { getCommonRoomEvents } from '../../../ui/client/views/app/lib/getCommonRoomEvents'; - -const LIMIT_DEFAULT = 50; - -Template.mentionsFlexTab.helpers({ - hasMessages() { - return Template.instance().messages.find().count(); - }, - messages() { - const instance = Template.instance(); - return instance.messages.find({}, { limit: instance.limit.get(), sort: { ts: -1 } }); - }, - hasMore() { - return Template.instance().hasMore.get(); - }, - messageContext, -}); - -Template.mentionsFlexTab.onCreated(function () { - this.messages = new Mongo.Collection(null); - - this.hasMore = new ReactiveVar(true); - this.limit = new ReactiveVar(LIMIT_DEFAULT); - - this.autorun(() => { - const query = { - '_hidden': { $ne: true }, - 'mentions.username': Users.findOne(Meteor.userId(), { fields: { username: 1 } }).username, - 'rid': this.data.rid, - '_updatedAt': { - $gt: new Date(), - }, - }; - - this.cursor && this.cursor.stop(); - - this.limit.set(LIMIT_DEFAULT); - - this.cursor = Messages.find(query).observe({ - added: ({ _id, ...message }) => { - this.messages.upsert({ _id }, message); - }, - changed: ({ _id, ...message }) => { - this.messages.upsert({ _id }, message); - }, - removed: ({ _id }) => { - this.messages.remove({ _id }); - }, - }); - }); - - this.autorun(async () => { - const limit = this.limit.get(); - const { messages, total } = await APIClient.get('/v1/chat.getMentionedMessages', { - roomId: this.data.rid, - count: limit, - }); - - upsertMessageBulk({ msgs: messages }, this.messages); - - this.hasMore.set(total > limit); - }); -}); - -Template.mentionsFlexTab.onDestroyed(function () { - this.cursor.stop(); -}); - -Template.mentionsFlexTab.events({ - ...getCommonRoomEvents(), - 'scroll .js-list': _.throttle(function (e, instance) { - if (e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight && instance.hasMore.get()) { - return instance.limit.set(instance.limit.get() + 50); - } - }, 200), -}); diff --git a/apps/meteor/app/mentions/client/index.js b/apps/meteor/app/mentions/client/index.ts similarity index 100% rename from apps/meteor/app/mentions/client/index.js rename to apps/meteor/app/mentions/client/index.ts diff --git a/apps/meteor/app/mentions/client/mentionLink.css b/apps/meteor/app/mentions/client/mentionLink.css index e338b20ea1f29..5deed00646c95 100644 --- a/apps/meteor/app/mentions/client/mentionLink.css +++ b/apps/meteor/app/mentions/client/mentionLink.css @@ -1,4 +1,3 @@ -.message .mention-link, .mention-link { padding: 0 2px 2px; diff --git a/apps/meteor/app/mentions/lib/MentionsParser.js b/apps/meteor/app/mentions/lib/MentionsParser.js index ed5f448094bcc..609bf34855a4b 100644 --- a/apps/meteor/app/mentions/lib/MentionsParser.js +++ b/apps/meteor/app/mentions/lib/MentionsParser.js @@ -38,7 +38,7 @@ export class MentionsParser { } get userMentionRegex() { - return new RegExp(`(^|\\s|> ?)@(${this.pattern}(@(${this.pattern}))?)`, 'gm'); + return new RegExp(`(^|\\s|> ?)@(${this.pattern}(@(${this.pattern}))?(:([0-9a-zA-Z-_.]+))?)`, 'gm'); } get channelMentionRegex() { diff --git a/apps/meteor/app/mentions/server/server.js b/apps/meteor/app/mentions/server/server.js index c82a7c3449e83..32e14d28612a6 100644 --- a/apps/meteor/app/mentions/server/server.js +++ b/apps/meteor/app/mentions/server/server.js @@ -1,11 +1,11 @@ import { Meteor } from 'meteor/meteor'; import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; +import { api } from '@rocket.chat/core-services'; import MentionsServer from './Mentions'; import { settings } from '../../settings/server'; import { callbacks } from '../../../lib/callbacks'; import { Users, Subscriptions, Rooms } from '../../models/server'; -import { api } from '../../../server/sdk/api'; export class MentionQueries { getUsers(usernames) { @@ -28,7 +28,20 @@ export class MentionQueries { } getChannels(channels) { - return Rooms.find({ name: { $in: [...new Set(channels)] }, t: { $in: ['c', 'p'] } }, { fields: { _id: 1, name: 1 } }).fetch(); + return Rooms.find( + { + $and: [ + { + $or: [ + { $and: [{ $or: [{ federated: { $exists: false } }, { federated: false }], name: { $in: [...new Set(channels)] } }] }, + { federated: true, fname: { $in: [...new Set(channels)] } }, + ], + }, + ], + t: { $in: ['c', 'p'] }, + }, + { fields: { _id: 1, name: 1, fname: 1, federated: 1 } }, + ).fetch(); } } diff --git a/apps/meteor/app/message-mark-as-unread/client/actionButton.ts b/apps/meteor/app/message-mark-as-unread/client/actionButton.ts index bbf558e65e4df..93e56085d702d 100644 --- a/apps/meteor/app/message-mark-as-unread/client/actionButton.ts +++ b/apps/meteor/app/message-mark-as-unread/client/actionButton.ts @@ -35,6 +35,11 @@ Meteor.startup(() => { if (isLivechatRoom) { return false; } + + if (!user) { + return false; + } + return message.u._id !== user._id; }, order: 10, diff --git a/apps/meteor/app/message-pin/client/actionButton.ts b/apps/meteor/app/message-pin/client/actionButton.ts deleted file mode 100644 index a41788fe621c2..0000000000000 --- a/apps/meteor/app/message-pin/client/actionButton.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Template } from 'meteor/templating'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { FlowRouter } from 'meteor/kadira:flow-router'; - -import { RoomHistoryManager, MessageAction } from '../../ui-utils/client'; -import { messageArgs } from '../../../client/lib/utils/messageArgs'; -import { settings } from '../../settings/client'; -import { hasAtLeastOnePermission } from '../../authorization/client'; -import { Rooms } from '../../models/client'; -import { dispatchToastMessage } from '../../../client/lib/toast'; -import { roomCoordinator } from '../../../client/lib/rooms/roomCoordinator'; - -Meteor.startup(function () { - MessageAction.addButton({ - id: 'pin-message', - icon: 'pin', - label: 'Pin', - context: ['pinned', 'message', 'message-mobile', 'threads', 'direct'], - action(_, props) { - const { message = messageArgs(this).msg } = props; - message.pinned = true; - Meteor.call('pinMessage', message, function (error: Error) { - if (error) { - dispatchToastMessage({ type: 'error', message: error }); - } - }); - }, - condition({ message, subscription, room }) { - if (!settings.get('Message_AllowPinning') || message.pinned || !subscription) { - return false; - } - const isLivechatRoom = roomCoordinator.isLivechatRoom(room.t); - if (isLivechatRoom) { - return false; - } - return hasAtLeastOnePermission('pin-message', message.rid); - }, - order: 7, - group: 'menu', - }); - - MessageAction.addButton({ - id: 'unpin-message', - icon: 'pin', - label: 'Unpin', - context: ['pinned', 'message', 'message-mobile', 'threads', 'direct'], - action(_, props) { - const { message = messageArgs(this).msg } = props; - message.pinned = false; - Meteor.call('unpinMessage', message, function (error: Error) { - if (error) { - dispatchToastMessage({ type: 'error', message: error }); - } - }); - }, - condition({ message, subscription }) { - if (!subscription || !settings.get('Message_AllowPinning') || !message.pinned) { - return false; - } - - return hasAtLeastOnePermission('pin-message', message.rid); - }, - order: 8, - group: 'menu', - }); - - MessageAction.addButton({ - id: 'jump-to-pin-message', - icon: 'jump', - label: 'Jump_to_message', - context: ['pinned', 'message-mobile', 'direct'], - action(_, props) { - const { message = messageArgs(this).msg } = props; - if (window.matchMedia('(max-width: 500px)').matches) { - (Template.currentData() as any).tabBar.close(); - } - if (message.tmid) { - return FlowRouter.go( - FlowRouter.getRouteName(), - { - tab: 'thread', - context: message.tmid, - rid: message.rid, - jump: message._id, - name: Rooms.findOne({ _id: message.rid }).name, - }, - { - jump: message._id, - }, - ); - } - return RoomHistoryManager.getSurroundingMessages(message, 50); - }, - condition({ subscription }) { - return !!subscription; - }, - order: 100, - group: ['message', 'menu'], - }); - - MessageAction.addButton({ - id: 'permalink-pinned', - icon: 'permalink', - label: 'Get_link', - // classes: 'clipboard', - context: ['pinned'], - async action(_, props) { - const { message = messageArgs(this).msg } = props; - const permalink = await MessageAction.getPermaLink(message._id); - navigator.clipboard.writeText(permalink); - dispatchToastMessage({ type: 'success', message: TAPi18n.__('Copied') }); - }, - condition({ subscription }) { - return !!subscription; - }, - order: 101, - group: 'menu', - }); -}); diff --git a/apps/meteor/app/message-pin/client/index.js b/apps/meteor/app/message-pin/client/index.js deleted file mode 100644 index c48cf4ab0b981..0000000000000 --- a/apps/meteor/app/message-pin/client/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import './actionButton'; -import './messageType'; -import './pinMessage'; -import './tabBar'; -import './views/pinnedMessages.html'; -import './views/pinnedMessages'; -import './views/stylesheets/messagepin.css'; diff --git a/apps/meteor/app/message-pin/client/messageType.js b/apps/meteor/app/message-pin/client/messageType.js deleted file mode 100644 index 0ce3da33853db..0000000000000 --- a/apps/meteor/app/message-pin/client/messageType.js +++ /dev/null @@ -1,11 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { MessageTypes } from '../../ui-utils'; - -Meteor.startup(function () { - MessageTypes.registerType({ - id: 'message_pinned', - system: true, - message: 'Pinned_a_message', - }); -}); diff --git a/apps/meteor/app/message-pin/client/pinMessage.js b/apps/meteor/app/message-pin/client/pinMessage.js deleted file mode 100644 index b45bed7839c3d..0000000000000 --- a/apps/meteor/app/message-pin/client/pinMessage.js +++ /dev/null @@ -1,69 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; - -import { settings } from '../../settings'; -import { ChatMessage, Subscriptions } from '../../models/client'; -import { dispatchToastMessage } from '../../../client/lib/toast'; - -Meteor.methods({ - pinMessage(message) { - if (!Meteor.userId()) { - dispatchToastMessage({ type: 'error', message: TAPi18n.__('error-not-authorized') }); - return false; - } - if (!settings.get('Message_AllowPinning')) { - dispatchToastMessage({ type: 'error', message: TAPi18n.__('pinning-not-allowed') }); - return false; - } - if (Subscriptions.findOne({ rid: message.rid }) == null) { - dispatchToastMessage({ type: 'error', message: TAPi18n.__('error-pinning-message') }); - return false; - } - if (typeof message._id !== 'string') { - dispatchToastMessage({ type: 'error', message: TAPi18n.__('error-pinning-message') }); - return false; - } - dispatchToastMessage({ type: 'success', message: TAPi18n.__('Message_has_been_pinned') }); - return ChatMessage.update( - { - _id: message._id, - rid: message.rid, - }, - { - $set: { - pinned: true, - }, - }, - ); - }, - unpinMessage(message) { - if (!Meteor.userId()) { - dispatchToastMessage({ type: 'error', message: TAPi18n.__('error-not-authorized') }); - return false; - } - if (!settings.get('Message_AllowPinning')) { - dispatchToastMessage({ type: 'error', message: TAPi18n.__('unpinning-not-allowed') }); - return false; - } - if (Subscriptions.findOne({ rid: message.rid }) == null) { - dispatchToastMessage({ type: 'error', message: TAPi18n.__('error-unpinning-message') }); - return false; - } - if (typeof message._id !== 'string') { - dispatchToastMessage({ type: 'error', message: TAPi18n.__('error-unpinning-message') }); - return false; - } - dispatchToastMessage({ type: 'success', message: TAPi18n.__('Message_has_been_unpinned') }); - return ChatMessage.update( - { - _id: message._id, - rid: message.rid, - }, - { - $set: { - pinned: false, - }, - }, - ); - }, -}); diff --git a/apps/meteor/app/message-pin/client/tabBar.ts b/apps/meteor/app/message-pin/client/tabBar.ts deleted file mode 100644 index 6065172f7cb62..0000000000000 --- a/apps/meteor/app/message-pin/client/tabBar.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { useMemo } from 'react'; -import { useSetting } from '@rocket.chat/ui-contexts'; -import { isRoomFederated } from '@rocket.chat/core-typings'; - -import { addAction } from '../../../client/views/room/lib/Toolbox'; - -addAction('pinned-messages', ({ room }) => { - const pinningAllowed = useSetting('Message_AllowPinning'); - const federated = isRoomFederated(room); - return useMemo( - () => - pinningAllowed - ? { - groups: ['channel', 'group', 'direct', 'direct_multiple', 'team'], - id: 'pinned-messages', - title: 'Pinned_Messages', - icon: 'pin', - template: 'pinnedMessages', - ...(federated && { - 'data-tooltip': 'Pinned_messages_unavailable_for_federation', - 'disabled': true, - }), - order: 11, - } - : null, - [pinningAllowed, federated], - ); -}); diff --git a/apps/meteor/app/message-pin/client/views/pinnedMessages.html b/apps/meteor/app/message-pin/client/views/pinnedMessages.html deleted file mode 100644 index 69aa06225a8bb..0000000000000 --- a/apps/meteor/app/message-pin/client/views/pinnedMessages.html +++ /dev/null @@ -1,22 +0,0 @@ - diff --git a/apps/meteor/app/message-pin/client/views/pinnedMessages.js b/apps/meteor/app/message-pin/client/views/pinnedMessages.js deleted file mode 100644 index 75fc482f913c2..0000000000000 --- a/apps/meteor/app/message-pin/client/views/pinnedMessages.js +++ /dev/null @@ -1,87 +0,0 @@ -import _ from 'underscore'; -import { Mongo } from 'meteor/mongo'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { Template } from 'meteor/templating'; - -import { upsertMessageBulk } from '../../../ui-utils/client/lib/RoomHistoryManager'; -import { messageContext } from '../../../ui-utils/client/lib/messageContext'; -import { APIClient } from '../../../utils/client'; -import { Messages } from '../../../models/client'; -import { getCommonRoomEvents } from '../../../ui/client/views/app/lib/getCommonRoomEvents'; - -const LIMIT_DEFAULT = 50; - -Template.pinnedMessages.helpers({ - hasMessages() { - return Template.instance().messages.find().count(); - }, - messages() { - const instance = Template.instance(); - return instance.messages.find({}, { limit: instance.limit.get(), sort: { ts: -1 } }); - }, - hasMore() { - return Template.instance().hasMore.get(); - }, - messageContext, -}); - -Template.pinnedMessages.onCreated(function () { - this.pinnedMessages = new ReactiveVar([]); - this.hasMore = new ReactiveVar(true); - this.limit = new ReactiveVar(LIMIT_DEFAULT); - this.rid = this.data.rid; - this.messages = new Mongo.Collection(null); - - this.autorun(() => { - const query = { - t: { $ne: 'rm' }, - _hidden: { $ne: true }, - pinned: true, - rid: this.data.rid, - _updatedAt: { - $gte: new Date(), - }, - }; - - this.cursor && this.cursor.stop(); - - this.limit.set(LIMIT_DEFAULT); - - this.cursor = Messages.find(query).observe({ - added: ({ _id, ...message }) => { - this.messages.upsert({ _id }, message); - }, - changed: ({ _id, ...message }) => { - this.messages.upsert({ _id }, message); - }, - removed: ({ _id }) => { - this.messages.remove({ _id }); - }, - }); - }); - - this.autorun(async () => { - const limit = this.limit.get(); - const { messages, total } = await APIClient.get('/v1/chat.getPinnedMessages', { - roomId: this.rid, - count: limit, - }); - - upsertMessageBulk({ msgs: messages }, this.messages); - - this.hasMore.set(total > limit); - }); -}); - -Template.mentionsFlexTab.onDestroyed(function () { - this.cursor.stop(); -}); - -Template.pinnedMessages.events({ - ...getCommonRoomEvents(), - 'scroll .js-list': _.throttle(function (e, instance) { - if (e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight && instance.hasMore.get()) { - return instance.limit.set(instance.limit.get() + 50); - } - }, 200), -}); diff --git a/apps/meteor/app/message-pin/client/views/stylesheets/messagepin.css b/apps/meteor/app/message-pin/client/views/stylesheets/messagepin.css deleted file mode 100644 index c4dc8a9b1cef5..0000000000000 --- a/apps/meteor/app/message-pin/client/views/stylesheets/messagepin.css +++ /dev/null @@ -1,25 +0,0 @@ -.icon-pin.rotate-45::before { - transform: rotate(45deg); -} - -.pinned-messages-list { - & li.empty { - margin-top: 60px; - - text-align: center; - - color: #7f7f7f; - } - - & .load-more { - text-align: center; - text-transform: lowercase; - - font-style: italic; - line-height: 40px; - - & .load-more-loading { - color: #aaaaaa; - } - } -} diff --git a/apps/meteor/app/message-pin/server/pinMessage.js b/apps/meteor/app/message-pin/server/pinMessage.js index c176d16acd45a..48fbd43fa4354 100644 --- a/apps/meteor/app/message-pin/server/pinMessage.js +++ b/apps/meteor/app/message-pin/server/pinMessage.js @@ -7,7 +7,7 @@ import { isTheLastMessage } from '../../lib/server'; import { getUserAvatarURL } from '../../utils/lib/getUserAvatarURL'; import { canAccessRoom, hasPermission, roomAccessAttributes } from '../../authorization/server'; import { Subscriptions, Messages, Users, Rooms } from '../../models/server'; -import { Apps, AppEvents } from '../../apps/server/orchestrator'; +import { Apps, AppEvents } from '../../../ee/server/apps/orchestrator'; const recursiveRemove = (msg, deep = 1) => { if (!msg) { diff --git a/apps/meteor/app/message-snippet/client/index.js b/apps/meteor/app/message-snippet/client/index.js deleted file mode 100644 index d5b4777732047..0000000000000 --- a/apps/meteor/app/message-snippet/client/index.js +++ /dev/null @@ -1,8 +0,0 @@ -import './messageType'; -import './snippetMessage'; -import './page/snippetPage.html'; -import './page/snippetPage'; -import './tabBar/tabBar'; -import './tabBar/views/snippetedMessages.html'; -import './tabBar/views/snippetedMessages'; -import './page/stylesheets/snippetPage.css'; diff --git a/apps/meteor/app/message-snippet/client/lib/collections.js b/apps/meteor/app/message-snippet/client/lib/collections.js deleted file mode 100644 index ff80211fc3a38..0000000000000 --- a/apps/meteor/app/message-snippet/client/lib/collections.js +++ /dev/null @@ -1,3 +0,0 @@ -import { Mongo } from 'meteor/mongo'; - -export const SnippetedMessages = new Mongo.Collection('rocketchat_snippeted_message'); diff --git a/apps/meteor/app/message-snippet/client/messageType.js b/apps/meteor/app/message-snippet/client/messageType.js deleted file mode 100644 index ccc2075553cc7..0000000000000 --- a/apps/meteor/app/message-snippet/client/messageType.js +++ /dev/null @@ -1,18 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { escapeHTML } from '@rocket.chat/string-helpers'; - -import { MessageTypes } from '../../ui-utils'; - -Meteor.startup(function () { - MessageTypes.registerType({ - id: 'message_snippeted', - system: true, - message: 'Snippeted_a_message', - data(message) { - const snippetLink = `${escapeHTML( - message.snippetName, - )}`; - return { snippetLink }; - }, - }); -}); diff --git a/apps/meteor/app/message-snippet/client/page/snippetPage.html b/apps/meteor/app/message-snippet/client/page/snippetPage.html deleted file mode 100644 index 139c9ae9210af..0000000000000 --- a/apps/meteor/app/message-snippet/client/page/snippetPage.html +++ /dev/null @@ -1,21 +0,0 @@ - diff --git a/apps/meteor/app/message-snippet/client/page/snippetPage.js b/apps/meteor/app/message-snippet/client/page/snippetPage.js deleted file mode 100644 index 0cd662305e7d7..0000000000000 --- a/apps/meteor/app/message-snippet/client/page/snippetPage.js +++ /dev/null @@ -1,44 +0,0 @@ -import { FlowRouter } from 'meteor/kadira:flow-router'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { Template } from 'meteor/templating'; -import moment from 'moment'; - -import { settings } from '../../../settings'; -import { Markdown } from '../../../markdown/client'; -import { APIClient } from '../../../utils/client'; -import { formatTime } from '../../../../client/lib/utils/formatTime'; - -Template.snippetPage.helpers({ - snippet() { - return Template.instance().message.get(); - }, - snippetContent() { - const message = Template.instance().message.get(); - if (message === undefined) { - return null; - } - message.html = message.msg; - const markdown = Markdown.parse(message); - return markdown.tokens[0].text; - }, - date() { - const snippet = Template.instance().message.get(); - if (snippet !== undefined) { - return moment(snippet.ts).format(settings.get('Message_DateFormat')); - } - }, - time() { - const snippet = Template.instance().message.get(); - if (snippet !== undefined) { - return formatTime(snippet.ts); - } - }, -}); - -Template.snippetPage.onCreated(async function () { - const snippetId = FlowRouter.getParam('snippetId'); - this.message = new ReactiveVar({}); - - const { message } = await APIClient.get('/v1/chat.getSnippetedMessageById', { messageId: snippetId }); - this.message.set(message); -}); diff --git a/apps/meteor/app/message-snippet/client/page/stylesheets/snippetPage.css b/apps/meteor/app/message-snippet/client/page/stylesheets/snippetPage.css deleted file mode 100644 index 1b3462721efd5..0000000000000 --- a/apps/meteor/app/message-snippet/client/page/stylesheets/snippetPage.css +++ /dev/null @@ -1,62 +0,0 @@ -:root { - --snippet-page-left-border-size: 30px; - --snippet-page-top-border-size: 20px; - --snippet-informations-height: 40px; - --snippet-page-right-border-size: 30px; -} - -.snippet-page { - overflow-x: hidden; - overflow-y: auto; - - width: auto; - height: 100%; - padding-top: var(--snippet-page-top-border-size); - padding-right: var(--snippet-page-right-border-size); - padding-left: var(--snippet-page-left-border-size); - - & pre code, - & h1, - & span { - user-select: all; - } - - & .snippet-informations { - display: inline-block; - - width: 100%; - height: 60px; - - & .avatar { - display: block; - float: left; - clear: left; - - margin-right: 10px; - } - - & .username { - display: block; - - width: 100%; - } - - & .snippet-filename { - display: block; - - width: 100%; - - font-weight: bold; - } - } - - & .info { - color: darkgrey; - - font-style: italic; - } - - & .download-button { - float: right; - } -} diff --git a/apps/meteor/app/message-snippet/client/snippetMessage.js b/apps/meteor/app/message-snippet/client/snippetMessage.js deleted file mode 100644 index 3c8a35d6cfdc9..0000000000000 --- a/apps/meteor/app/message-snippet/client/snippetMessage.js +++ /dev/null @@ -1,35 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { settings } from '../../settings'; -import { ChatMessage, Subscriptions } from '../../models/client'; - -Meteor.methods({ - snippetMessage(message) { - if (typeof Meteor.userId() === 'undefined' || Meteor.userId() === null) { - return false; - } - if ( - typeof settings.get('Message_AllowSnippeting') === 'undefined' || - settings.get('Message_AllowSnippeting') === null || - settings.get('Message_AllowSnippeting') === false - ) { - return false; - } - - const subscription = Subscriptions.findOne({ 'rid': message.rid, 'u._id': Meteor.userId() }); - - if (subscription === undefined) { - return false; - } - ChatMessage.update( - { - _id: message._id, - }, - { - $set: { - snippeted: true, - }, - }, - ); - }, -}); diff --git a/apps/meteor/app/message-snippet/client/tabBar/tabBar.ts b/apps/meteor/app/message-snippet/client/tabBar/tabBar.ts deleted file mode 100644 index 6e36a47833a89..0000000000000 --- a/apps/meteor/app/message-snippet/client/tabBar/tabBar.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { useMemo } from 'react'; -import { useSetting } from '@rocket.chat/ui-contexts'; - -import { addAction } from '../../../../client/views/room/lib/Toolbox'; - -addAction('snippeted-messages', () => { - const snippetingEnabled = useSetting('Message_AllowSnippeting'); - return useMemo( - () => - snippetingEnabled - ? { - groups: ['channel', 'group', 'direct', 'direct_multiple', 'team'], - id: 'snippeted-messages', - title: 'snippet-message', - icon: 'code', - template: 'snippetedMessages', - order: 20, - } - : null, - [snippetingEnabled], - ); -}); diff --git a/apps/meteor/app/message-snippet/client/tabBar/views/snippetedMessages.html b/apps/meteor/app/message-snippet/client/tabBar/views/snippetedMessages.html deleted file mode 100644 index 2c047fbb9d34d..0000000000000 --- a/apps/meteor/app/message-snippet/client/tabBar/views/snippetedMessages.html +++ /dev/null @@ -1,24 +0,0 @@ - diff --git a/apps/meteor/app/message-snippet/client/tabBar/views/snippetedMessages.js b/apps/meteor/app/message-snippet/client/tabBar/views/snippetedMessages.js deleted file mode 100644 index 4ee7fee88472a..0000000000000 --- a/apps/meteor/app/message-snippet/client/tabBar/views/snippetedMessages.js +++ /dev/null @@ -1,80 +0,0 @@ -import _ from 'underscore'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { Template } from 'meteor/templating'; -import { Mongo } from 'meteor/mongo'; - -import { messageContext } from '../../../../ui-utils/client/lib/messageContext'; -import { APIClient } from '../../../../utils/client'; -import { Messages } from '../../../../models/client'; -import { upsertMessageBulk } from '../../../../ui-utils/client/lib/RoomHistoryManager'; - -const LIMIT_DEFAULT = 50; - -Template.snippetedMessages.helpers({ - hasMessages() { - return Template.instance().messages.find().count(); - }, - messages() { - const instance = Template.instance(); - return instance.messages.find({}, { limit: instance.limit.get(), sort: { ts: -1 } }); - }, - hasMore() { - return Template.instance().hasMore.get(); - }, - messageContext, -}); - -Template.snippetedMessages.onCreated(function () { - this.rid = this.data.rid; - this.hasMore = new ReactiveVar(true); - this.messages = new Mongo.Collection(null); - this.limit = new ReactiveVar(LIMIT_DEFAULT); - - this.autorun(() => { - const query = { - _hidden: { $ne: true }, - snippeted: true, - rid: this.rid, - }; - - this.cursor && this.cursor.stop(); - - this.limit.set(LIMIT_DEFAULT); - - this.cursor = Messages.find(query).observe({ - added: ({ _id, ...message }) => { - this.messages.upsert({ _id }, message); - }, - changed: ({ _id, ...message }) => { - this.messages.upsert({ _id }, message); - }, - removed: ({ _id }) => { - this.messages.remove({ _id }); - }, - }); - }); - - this.autorun(async () => { - const limit = this.limit.get(); - const { messages, total } = await APIClient.get('/v1/chat.getSnippetedMessages', { - roomId: this.rid, - count: limit, - }); - - upsertMessageBulk({ msgs: messages }, this.messages); - - this.hasMore.set(total > limit); - }); -}); - -Template.mentionsFlexTab.onDestroyed(function () { - this.cursor.stop(); -}); - -Template.snippetedMessages.events({ - 'scroll .js-list': _.throttle(function (e, instance) { - if (e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight && instance.hasMore.get()) { - return instance.limit.set(instance.limit.get() + 50); - } - }, 200), -}); diff --git a/apps/meteor/app/message-snippet/server/index.js b/apps/meteor/app/message-snippet/server/index.js deleted file mode 100644 index 74e7fa9524c26..0000000000000 --- a/apps/meteor/app/message-snippet/server/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import './startup/settings'; -import './methods/snippetMessage'; -import './requests'; diff --git a/apps/meteor/app/message-snippet/server/methods/snippetMessage.js b/apps/meteor/app/message-snippet/server/methods/snippetMessage.js deleted file mode 100644 index 987c3102c71dd..0000000000000 --- a/apps/meteor/app/message-snippet/server/methods/snippetMessage.js +++ /dev/null @@ -1,55 +0,0 @@ -import { Meteor } from 'meteor/meteor'; - -import { Subscriptions, Messages, Users, Rooms } from '../../../models/server'; -import { settings } from '../../../settings/server'; -import { callbacks } from '../../../../lib/callbacks'; -import { isTheLastMessage } from '../../../lib'; - -Meteor.methods({ - snippetMessage(message, filename) { - if (Meteor.userId() == null) { - // noinspection JSUnresolvedFunction - throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'snippetMessage' }); - } - - const room = Rooms.findOne({ _id: message.rid }); - - if (typeof room === 'undefined' || room === null) { - return false; - } - - const subscription = Subscriptions.findOneByRoomIdAndUserId(message.rid, Meteor.userId(), { - fields: { _id: 1 }, - }); - if (!subscription) { - return false; - } - - const me = Users.findOneById(Meteor.userId()); - - // If we keep history of edits, insert a new message to store history information - if (settings.get('Message_KeepHistory')) { - Messages.cloneAndSaveAsHistoryById(message._id, me); - } - - message.snippeted = true; - message.snippetedAt = Date.now; - message.snippetedBy = { - _id: Meteor.userId(), - username: me.username, - }; - - message = callbacks.run('beforeSaveMessage', message); - - // Create the SnippetMessage - Messages.setSnippetedByIdAndUserId(message, filename, message.snippetedBy, message.snippeted, Date.now, filename); - if (isTheLastMessage(room, message)) { - Rooms.setLastMessageSnippeted(room._id, message, filename, message.snippetedBy, message.snippeted, Date.now, filename); - } - - Messages.createWithTypeRoomIdMessageAndUser('message_snippeted', message.rid, '', me, { - snippetId: message._id, - snippetName: filename, - }); - }, -}); diff --git a/apps/meteor/app/message-snippet/server/requests.js b/apps/meteor/app/message-snippet/server/requests.js deleted file mode 100644 index 63f74bf59a005..0000000000000 --- a/apps/meteor/app/message-snippet/server/requests.js +++ /dev/null @@ -1,63 +0,0 @@ -import { WebApp } from 'meteor/webapp'; -import { Cookies } from 'meteor/ostrio:cookies'; - -import { Users, Rooms, Messages } from '../../models/server'; - -WebApp.connectHandlers.use('/snippet/download', function (req, res) { - let rawCookies; - let token; - let uid; - const cookie = new Cookies(); - - if (req.headers && req.headers.cookie !== null) { - rawCookies = req.headers.cookie; - } - - if (rawCookies !== null) { - uid = cookie.get('rc_uid', rawCookies); - } - - if (rawCookies !== null) { - token = cookie.get('rc_token', rawCookies); - } - - if (uid === null) { - uid = req.query.rc_uid; - token = req.query.rc_token; - } - - const user = Users.findOneByIdAndLoginToken(uid, token); - - if (!(uid && token && user)) { - res.writeHead(403); - res.end(); - return false; - } - const match = /^\/([^\/]+)\/(.*)/.exec(req.url); - - if (match[1]) { - const snippet = Messages.findOne({ - _id: match[1], - snippeted: true, - }); - const room = Rooms.findOne({ _id: snippet.rid, usernames: { $in: [user.username] } }); - if (room === undefined) { - res.writeHead(403); - res.end(); - return false; - } - - res.setHeader('Content-Disposition', `attachment; filename*=UTF-8''${encodeURIComponent(snippet.snippetName)}`); - res.setHeader('Content-Type', 'application/octet-stream'); - - // Removing the ``` contained in the msg. - const snippetContent = snippet.msg.substr(3, snippet.msg.length - 6); - res.setHeader('Content-Length', snippetContent.length); - res.write(snippetContent); - res.end(); - return; - } - - res.writeHead(404); - res.end(); -}); diff --git a/apps/meteor/app/message-snippet/server/startup/settings.ts b/apps/meteor/app/message-snippet/server/startup/settings.ts deleted file mode 100644 index c7de88a07d018..0000000000000 --- a/apps/meteor/app/message-snippet/server/startup/settings.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { settingsRegistry } from '../../../settings/server'; - -settingsRegistry.add('Message_AllowSnippeting', false, { - type: 'boolean', - public: true, - group: 'Message', -}); diff --git a/apps/meteor/app/message-star/client/actionButton.ts b/apps/meteor/app/message-star/client/actionButton.ts deleted file mode 100644 index 3ed76dfe5f622..0000000000000 --- a/apps/meteor/app/message-star/client/actionButton.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { Template } from 'meteor/templating'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; -import { FlowRouter } from 'meteor/kadira:flow-router'; - -import { settings } from '../../settings/client'; -import { RoomHistoryManager, MessageAction } from '../../ui-utils/client'; -import { messageArgs } from '../../../client/lib/utils/messageArgs'; -import { Rooms } from '../../models/client'; -import { dispatchToastMessage } from '../../../client/lib/toast'; -import { roomCoordinator } from '../../../client/lib/rooms/roomCoordinator'; - -Meteor.startup(function () { - MessageAction.addButton({ - id: 'star-message', - icon: 'star', - label: 'Star', - context: ['starred', 'message', 'message-mobile', 'threads', 'federated'], - action(_, props) { - const { message = messageArgs(this).msg } = props; - Meteor.call('starMessage', { ...message, starred: true }, function (error: any) { - if (error) { - dispatchToastMessage({ type: 'error', message: error }); - } - }); - }, - condition({ message, subscription, user, room }) { - if (subscription == null && settings.get('Message_AllowStarring')) { - return false; - } - const isLivechatRoom = roomCoordinator.isLivechatRoom(room.t); - if (isLivechatRoom) { - return false; - } - - return !Array.isArray(message.starred) || !message.starred.find((star: any) => star._id === user._id); - }, - order: 9, - group: 'menu', - }); - - MessageAction.addButton({ - id: 'unstar-message', - icon: 'star', - label: 'Unstar_Message', - context: ['starred', 'message', 'message-mobile', 'threads', 'federated'], - action(_, props) { - const { message = messageArgs(this).msg } = props; - - Meteor.call('starMessage', { ...message, starred: false }, function (error?: any) { - if (error) { - dispatchToastMessage({ type: 'error', message: error }); - } - }); - }, - condition({ message, subscription, user }) { - if (subscription == null && settings.get('Message_AllowStarring')) { - return false; - } - - return Boolean(message.starred?.find((star: any) => star._id === user._id)); - }, - order: 9, - group: 'menu', - }); - - MessageAction.addButton({ - id: 'jump-to-star-message', - icon: 'jump', - label: 'Jump_to_message', - - context: ['starred', 'threads', 'message-mobile'], - action() { - const { msg: message } = messageArgs(this); - if (window.matchMedia('(max-width: 500px)').matches) { - (Template.currentData() as any).tabBar.close(); - } - if (message.tmid) { - return FlowRouter.go( - FlowRouter.getRouteName(), - { - tab: 'thread', - context: message.tmid, - rid: message.rid, - jump: message._id, - name: Rooms.findOne({ _id: message.rid }).name, - }, - { - jump: message._id, - }, - ); - } - RoomHistoryManager.getSurroundingMessages(message, 50); - }, - condition({ message, subscription, user }) { - if (subscription == null || !settings.get('Message_AllowStarring')) { - return false; - } - - return Boolean(message.starred?.find((star) => star._id === user._id)); - }, - order: 100, - group: ['message', 'menu'], - }); - - MessageAction.addButton({ - id: 'permalink-star', - icon: 'permalink', - label: 'Get_link', - // classes: 'clipboard', - context: ['starred', 'threads'], - async action(_, props) { - const { message = messageArgs(this).msg } = props; - const permalink = await MessageAction.getPermaLink(message._id); - navigator.clipboard.writeText(permalink); - dispatchToastMessage({ type: 'success', message: TAPi18n.__('Copied') }); - }, - condition({ message, subscription, user }) { - if (subscription == null) { - return false; - } - - return Boolean(message.starred?.find((star) => star._id === user._id)); - }, - order: 101, - group: 'menu', - }); -}); diff --git a/apps/meteor/app/message-star/client/index.js b/apps/meteor/app/message-star/client/index.js deleted file mode 100644 index 68b7c64343347..0000000000000 --- a/apps/meteor/app/message-star/client/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import './actionButton'; -import './starMessage'; -import './tabBar'; -import './views/starredMessages.html'; -import './views/starredMessages'; -import './views/stylesheets/messagestar.css'; diff --git a/apps/meteor/app/message-star/client/starMessage.js b/apps/meteor/app/message-star/client/starMessage.js deleted file mode 100644 index 41e2c7ac77755..0000000000000 --- a/apps/meteor/app/message-star/client/starMessage.js +++ /dev/null @@ -1,42 +0,0 @@ -import { Meteor } from 'meteor/meteor'; -import { TAPi18n } from 'meteor/rocketchat:tap-i18n'; - -import { settings } from '../../settings'; -import { ChatMessage, Subscriptions } from '../../models/client'; -import { dispatchToastMessage } from '../../../client/lib/toast'; - -Meteor.methods({ - starMessage(message) { - if (!Meteor.userId()) { - dispatchToastMessage({ type: 'error', message: TAPi18n.__('error-starring-message') }); - return false; - } - if (Subscriptions.findOne({ rid: message.rid }) == null) { - dispatchToastMessage({ type: 'error', message: TAPi18n.__('error-starring-message') }); - return false; - } - if (!ChatMessage.findOneByRoomIdAndMessageId(message.rid, message._id)) { - dispatchToastMessage({ type: 'error', message: TAPi18n.__('error-starring-message') }); - return false; - } - if (!settings.get('Message_AllowStarring')) { - dispatchToastMessage({ type: 'error', message: TAPi18n.__('error-starring-message') }); - return false; - } - if (message.starred) { - dispatchToastMessage({ type: 'success', message: TAPi18n.__('Message_has_been_starred') }); - } else { - dispatchToastMessage({ type: 'success', message: TAPi18n.__('Message_has_been_unstarred') }); - } - return ChatMessage.update( - { - _id: message._id, - }, - { - $addToSet: { - starred: !!message.starred, - }, - }, - ); - }, -}); diff --git a/apps/meteor/app/message-star/client/tabBar.ts b/apps/meteor/app/message-star/client/tabBar.ts deleted file mode 100644 index d4cf0680ba646..0000000000000 --- a/apps/meteor/app/message-star/client/tabBar.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { addAction } from '../../../client/views/room/lib/Toolbox'; - -addAction('starred-messages', { - groups: ['channel', 'group', 'direct', 'direct_multiple', 'team'], - id: 'starred-messages', - title: 'Starred_Messages', - icon: 'star', - template: 'starredMessages', - order: 10, -}); diff --git a/apps/meteor/app/message-star/client/views/starredMessages.html b/apps/meteor/app/message-star/client/views/starredMessages.html deleted file mode 100644 index 1f2e711500859..0000000000000 --- a/apps/meteor/app/message-star/client/views/starredMessages.html +++ /dev/null @@ -1,23 +0,0 @@ - diff --git a/apps/meteor/app/message-star/client/views/starredMessages.js b/apps/meteor/app/message-star/client/views/starredMessages.js deleted file mode 100644 index 8b44b85e3f7f1..0000000000000 --- a/apps/meteor/app/message-star/client/views/starredMessages.js +++ /dev/null @@ -1,86 +0,0 @@ -import _ from 'underscore'; -import { Meteor } from 'meteor/meteor'; -import { ReactiveVar } from 'meteor/reactive-var'; -import { Template } from 'meteor/templating'; -import { Mongo } from 'meteor/mongo'; - -import { messageContext } from '../../../ui-utils/client/lib/messageContext'; -import { Messages } from '../../../models/client'; -import { upsertMessageBulk } from '../../../ui-utils/client/lib/RoomHistoryManager'; -import { APIClient } from '../../../utils/client'; -import { getCommonRoomEvents } from '../../../ui/client/views/app/lib/getCommonRoomEvents'; - -const LIMIT_DEFAULT = 50; - -Template.starredMessages.helpers({ - hasMessages() { - return Template.instance().messages.find().count(); - }, - messages() { - const instance = Template.instance(); - return instance.messages.find({}, { limit: instance.limit.get(), sort: { ts: -1 } }); - }, - hasMore() { - return Template.instance().hasMore.get(); - }, - messageContext, -}); - -Template.starredMessages.onCreated(function () { - this.rid = this.data.rid; - this.messages = new Mongo.Collection(null); - this.hasMore = new ReactiveVar(true); - this.limit = new ReactiveVar(LIMIT_DEFAULT); - - this.autorun(() => { - const query = { - '_hidden': { $ne: true }, - 'starred._id': Meteor.userId(), - 'rid': this.rid, - '_updatedAt': { - $gt: new Date(), - }, - }; - - this.cursor && this.cursor.stop(); - - this.limit.set(LIMIT_DEFAULT); - - this.cursor = Messages.find(query).observe({ - added: ({ _id, ...message }) => { - this.messages.upsert({ _id }, message); - }, - changed: ({ _id, ...message }) => { - this.messages.upsert({ _id }, message); - }, - removed: ({ _id }) => { - this.messages.remove({ _id }); - }, - }); - }); - - this.autorun(async () => { - const limit = this.limit.get(); - const { messages, total } = await APIClient.get('/v1/chat.getStarredMessages', { - roomId: this.rid, - count: limit, - }); - - upsertMessageBulk({ msgs: messages }, this.messages); - - this.hasMore.set(total > limit); - }); -}); - -Template.mentionsFlexTab.onDestroyed(function () { - this.cursor.stop(); -}); - -Template.starredMessages.events({ - ...getCommonRoomEvents(), - 'scroll .js-list': _.throttle(function (e, instance) { - if (e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight) { - return instance.limit.set(instance.limit.get() + 50); - } - }, 200), -}); diff --git a/apps/meteor/app/message-star/client/views/stylesheets/messagestar.css b/apps/meteor/app/message-star/client/views/stylesheets/messagestar.css deleted file mode 100644 index 12ac25a3efb38..0000000000000 --- a/apps/meteor/app/message-star/client/views/stylesheets/messagestar.css +++ /dev/null @@ -1,21 +0,0 @@ -.starred-messages-list { - & li.empty { - margin-top: 60px; - - text-align: center; - - color: #7f7f7f; - } - - & .load-more { - text-align: center; - text-transform: lowercase; - - font-style: italic; - line-height: 40px; - - & .load-more-loading { - color: #aaaaaa; - } - } -} diff --git a/apps/meteor/app/message-star/server/starMessage.js b/apps/meteor/app/message-star/server/starMessage.js index 8e42921707509..98a7fb47cea0c 100644 --- a/apps/meteor/app/message-star/server/starMessage.js +++ b/apps/meteor/app/message-star/server/starMessage.js @@ -4,7 +4,7 @@ import { settings } from '../../settings/server'; import { isTheLastMessage } from '../../lib/server'; import { canAccessRoom, roomAccessAttributes } from '../../authorization/server'; import { Subscriptions, Rooms, Messages } from '../../models/server'; -import { Apps, AppEvents } from '../../apps/server/orchestrator'; +import { Apps, AppEvents } from '../../../ee/server/apps/orchestrator'; Meteor.methods({ starMessage(message) { diff --git a/apps/meteor/app/meteor-autocomplete/client/autocomplete-client.js b/apps/meteor/app/meteor-autocomplete/client/autocomplete-client.js index 55db42563b266..77357c0e77819 100755 --- a/apps/meteor/app/meteor-autocomplete/client/autocomplete-client.js +++ b/apps/meteor/app/meteor-autocomplete/client/autocomplete-client.js @@ -2,14 +2,13 @@ import { Meteor } from 'meteor/meteor'; import { Match } from 'meteor/check'; import { Blaze } from 'meteor/blaze'; import { Deps } from 'meteor/deps'; -import _ from 'underscore'; import { getCaretCoordinates } from 'meteor/dandv:caret-position'; import AutoCompleteRecords from './collection'; import { APIClient } from '../../utils/client'; const isServerSearch = function (rule) { - return _.isString(rule.collection); + return Object.prototype.toString.call(rule.collection) === '[object String]'; }; const validateRule = function (rule) { @@ -39,7 +38,7 @@ const getRegExp = function (rule) { const getFindParams = function (rule, filter, limit) { // This is a different 'filter' - the selector from the settings // We need to extend so that we don't copy over rule.filter - const selector = _.extend({}, rule.filter || {}); + const selector = Object.assign({}, rule.filter || {}); const options = { limit, }; @@ -53,9 +52,9 @@ const getFindParams = function (rule, filter, limit) { sortspec[rule.field] = 1; options.sort = sortspec; } - if (_.isFunction(rule.selector)) { + if (Object.prototype.toString.call(rule.selector) === '[object Function]') { // Custom selector - _.extend(selector, rule.selector(filter)); + Object.assign(selector, rule.selector(filter)); } else { selector[rule.field] = { $regex: rule.matchAll ? filter : `^${filter}`, diff --git a/apps/meteor/app/meteor-autocomplete/client/inputs.html b/apps/meteor/app/meteor-autocomplete/client/inputs.html index 289caa58ff7e8..bb7374ef3a95c 100755 --- a/apps/meteor/app/meteor-autocomplete/client/inputs.html +++ b/apps/meteor/app/meteor-autocomplete/client/inputs.html @@ -3,11 +3,6 @@ {{> autocompleteContainer}} - -