diff --git a/.circleci/config.yml b/.circleci/config.yml
index 8d6ca5b206c7..bbad59281e8c 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -44,7 +44,7 @@ test-save-npm-cache: &test-save-npm-cache
- ./node_modules
test-docker-image: &test-docker-image
- circleci/node:8.15-stretch-browsers
+ circleci/node:8.16-stretch-browsers
test-with-oplog: &test-with-oplog
<<: *defaults
@@ -69,7 +69,7 @@ jobs:
build: &build
<<: *defaults
docker:
- - image: circleci/node:8.15-stretch
+ - image: circleci/node:8.16-stretch
- image: mongo:3.4
steps:
@@ -147,7 +147,7 @@ jobs:
- run:
name: Build Rocket.Chat
environment:
- TOOL_NODE_FLAGS: --max_old_space_size=3072
+ TOOL_NODE_FLAGS: --max_old_space_size=4096
command: |
if [[ $CIRCLE_TAG ]] || [[ $CIRCLE_BRANCH == 'develop' ]]; then
meteor reset;
@@ -220,7 +220,7 @@ jobs:
deploy:
<<: *defaults
docker:
- - image: circleci/node:8.15-stretch
+ - image: circleci/node:8.16-stretch
steps:
- attach_workspace:
@@ -268,7 +268,7 @@ jobs:
export CIRCLE_TAG=${CIRCLE_TAG:=}
- cp ~/repo/.docker/Dockerfile.local ./Dockerfile
+ cp ~/repo/.docker/Dockerfile .
docker login -u $DOCKER_USER -p $DOCKER_PASS
if [[ $CIRCLE_TAG ]]; then
@@ -314,7 +314,16 @@ workflows:
version: 2
build-and-test:
jobs:
+ - hold-all:
+ type: approval
+ filters:
+ branches:
+ only: develop
+ tags:
+ only: /^[0-9]+\.[0-9]+\.[0-9]+(?:-(?:rc|beta)\.[0-9]+)?$/
- build:
+ requires:
+ - hold-all
filters:
tags:
only: /^v[0-9]+\.[0-9]+\.[0-9]-[0-9]+\.[0-9]+\.[0-9]+$/
diff --git a/.circleci/docker.sh b/.circleci/docker.sh
deleted file mode 100644
index 4edf27c21775..000000000000
--- a/.circleci/docker.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-set -euvo pipefail
-IFS=$'\n\t'
-
-CURL_URL="https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$DOCKER_TRIGGER_TOKEN/"
-
-if [[ $CIRCLE_TAG ]]; then
- CURL_DATA='{"source_type":"Tag","source_name":"'"$CIRCLE_TAG"'"}';
-else
- CURL_DATA='{"source_type":"Branch","source_name":"'"$CIRCLE_BRANCH"'"}';
-fi
-
-curl -H "Content-Type: application/json" --data "$CURL_DATA" -X POST "$CURL_URL"
diff --git a/.circleci/snap.sh b/.circleci/snap.sh
index d4d30c371248..afd047de0e15 100644
--- a/.circleci/snap.sh
+++ b/.circleci/snap.sh
@@ -3,7 +3,9 @@ set -euvo pipefail
IFS=$'\n\t'
# Add launchpad to known hosts
-ssh-keyscan -t rsa -H git.launchpad.net > ~/.ssh/known_hosts
+
+mkdir -p $HOME/.ssh
+ssh-keyscan -t rsa -H git.launchpad.net >> $HOME/.ssh/known_hosts
echo "Preparing to trigger a snap release for $SNAP_CHANNEL channel"
diff --git a/.docker/Dockerfile b/.docker/Dockerfile
index 0f4d275a87d3..1c2a93fe8077 100644
--- a/.docker/Dockerfile
+++ b/.docker/Dockerfile
@@ -1,15 +1,10 @@
-FROM rocketchat/base:8
+FROM rocketchat/base:8.17.0
-ENV RC_VERSION 2.1.2
-MAINTAINER buildmaster@rocket.chat
+ADD . /app
+
+LABEL maintainer="buildmaster@rocket.chat"
RUN set -x \
- && curl -SLf "https://releases.rocket.chat/${RC_VERSION}/download/" -o rocket.chat.tgz \
- && curl -SLf "https://releases.rocket.chat/${RC_VERSION}/asc" -o rocket.chat.tgz.asc \
- && gpg --verify rocket.chat.tgz.asc \
- && mkdir -p /app \
- && tar -zxf rocket.chat.tgz -C /app \
- && rm rocket.chat.tgz rocket.chat.tgz.asc \
&& cd /app/bundle/programs/server \
&& npm install \
&& npm cache clear --force \
diff --git a/.docker/Dockerfile.rhel b/.docker/Dockerfile.rhel
index 7347f3f8be08..99f2b51c9770 100644
--- a/.docker/Dockerfile.rhel
+++ b/.docker/Dockerfile.rhel
@@ -1,6 +1,6 @@
FROM registry.access.redhat.com/rhscl/nodejs-8-rhel7
-ENV RC_VERSION 2.3.2
+ENV RC_VERSION 2.4.7
MAINTAINER buildmaster@rocket.chat
diff --git a/.docker/startup.sh b/.docker/startup.sh
deleted file mode 100644
index 1bba3b95a7f1..000000000000
--- a/.docker/startup.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-# in a container environment, we may need to determine the INSTANCE_IP
-# for each container so that uploads are working even if load-balanced in a group
-if [ -z $INSTANCE_IP ]
-then
- export INSTANCE_IP=$(hostname -i)
- echo "Got INSTANCE_IP via hostname: $INSTANCE_IP"
-fi
-
-if [ -z $INSTANCE_IP ]
-then
- export INSTANCE_IP=$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4 --connect-timeout 2)
- echo "Got INSTANCE_IP via ECS metadata API: $INSTANCE_IP"
-fi
-
-node main.js
\ No newline at end of file
diff --git a/.eslintignore b/.eslintignore
index 81b9e250bd69..dee29d8e38d0 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -19,3 +19,4 @@ public/livechat/
!.scripts
public/pdf.worker.min.js
imports/client/
+!/.storybook/
diff --git a/.eslintrc b/.eslintrc
index a8bdb5166000..46805bc5b654 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,23 +1,104 @@
{
- "extends": ["@rocket.chat/eslint-config"],
- "parser": "babel-eslint",
- "globals": {
- "__meteor_bootstrap__" : false,
- "__meteor_runtime_config__" : false,
- "Assets" : false,
- "chrome" : false
+ "extends": [
+ "@rocket.chat/eslint-config"
+ ],
+ "parser": "babel-eslint",
+ "globals": {
+ "__meteor_bootstrap__": false,
+ "__meteor_runtime_config__": false,
+ "Assets": false,
+ "chrome": false,
+ "jscolor": false
},
- "plugins": ["react"],
- "rules": {
- "jsx-quotes": ["error", "prefer-single"],
+ "plugins": [
+ "react"
+ ],
+ "rules": {
+ "jsx-quotes": [
+ "error",
+ "prefer-single"
+ ],
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"react/jsx-no-undef": "error",
- "react/jsx-fragments": ["error", "syntax"],
+ "react/jsx-fragments": [
+ "error",
+ "syntax"
+ ],
},
"settings": {
"react": {
"version": "detect",
},
},
+ "overrides": [
+ {
+ "files": [
+ "**/*.ts",
+ "**/*.tsx"
+ ],
+ "extends": [
+ "@rocket.chat/eslint-config",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:@typescript-eslint/eslint-recommended"
+ ],
+ "globals": {
+ "Atomics": "readonly",
+ "SharedArrayBuffer": "readonly"
+ },
+ "parser": "@typescript-eslint/parser",
+ "parserOptions": {
+ "sourceType": "module",
+ "ecmaVersion": 2018,
+ "warnOnUnsupportedTypeScriptVersion": false,
+ "ecmaFeatures": {
+ "experimentalObjectRestSpread": true,
+ "legacyDecorators": true
+ }
+ },
+ "plugins": [
+ "react",
+ "@typescript-eslint"
+ ],
+ "rules": {
+ "jsx-quotes": [
+ "error",
+ "prefer-single"
+ ],
+ "react/jsx-uses-react": "error",
+ "react/jsx-uses-vars": "error",
+ "react/jsx-no-undef": "error",
+ "react/jsx-fragments": [
+ "error",
+ "syntax"
+ ],
+ "@typescript-eslint/ban-ts-ignore": "off",
+ "@typescript-eslint/no-explicit-any": "off",
+ "@typescript-eslint/interface-name-prefix": [
+ "error",
+ "always"
+ ]
+ },
+ "env": {
+ "browser": true,
+ "commonjs": true,
+ "es6": true,
+ "node": true
+ },
+ "settings": {
+ "import/resolver": {
+ "node": {
+ "extensions": [
+ ".js",
+ ".ts",
+ ".tsx"
+ ]
+ }
+ },
+ "react": {
+ "version": "detect"
+ }
+ }
+ }
+ ]
}
diff --git a/.github/history.json b/.github/history.json
index 4a215c606e22..8d301c76dcaa 100644
--- a/.github/history.json
+++ b/.github/history.json
@@ -37299,6 +37299,1037 @@
]
}
]
+ },
+ "2.4.0-rc.0": {
+ "node_version": "8.17.0",
+ "npm_version": "6.13.4",
+ "mongo_versions": [
+ "3.4",
+ "3.6",
+ "4.0"
+ ],
+ "pull_requests": [
+ {
+ "pr": "16043",
+ "title": "Update NodeJS to 8.17.0",
+ "userLogin": "rodrigok",
+ "milestone": "2.4.0",
+ "contributors": [
+ "rodrigok"
+ ]
+ },
+ {
+ "pr": "15933",
+ "title": "[NEW] Invite links: share a link to invite users",
+ "userLogin": "pierre-lehnen-rc",
+ "milestone": "2.4.0",
+ "contributors": [
+ "pierre-lehnen-rc",
+ "web-flow",
+ "rodrigok"
+ ]
+ },
+ {
+ "pr": "15998",
+ "title": "Fix typo in Italian translation",
+ "userLogin": "iannuzzelli",
+ "milestone": "2.4.0",
+ "contributors": [
+ "iannuzzelli"
+ ]
+ },
+ {
+ "pr": "16037",
+ "title": "Update Meteor to 1.8.3",
+ "userLogin": "sampaiodiego",
+ "milestone": "2.4.0",
+ "contributors": [
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "16010",
+ "title": "[FIX] Importer: Variable name appearing instead of it's value",
+ "userLogin": "ashwaniYDV",
+ "milestone": "2.4.0",
+ "contributors": [
+ "ashwaniYDV"
+ ]
+ },
+ {
+ "pr": "15977",
+ "title": "[IMPROVE] Replace livechat:inquiry publication by REST and Streamer",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "renatobecker"
+ ]
+ },
+ {
+ "pr": "16021",
+ "title": "[IMPROVE] Sorting on livechat analytics queries were wrong",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto"
+ ]
+ },
+ {
+ "pr": "15650",
+ "title": "[IMPROVE] Replace fullUserData publication by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "15885",
+ "title": "[IMPROVE] Replace integrations and integrationHistory publications by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "sampaiodiego",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "15886",
+ "title": "Some performance improvements",
+ "userLogin": "sampaiodiego",
+ "contributors": [
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "15930",
+ "title": "[FIX]Add time format for latest message on the sidebar",
+ "userLogin": "ritwizsinha",
+ "contributors": [
+ "ritwizsinha",
+ "ggazzo"
+ ]
+ },
+ {
+ "pr": "15994",
+ "title": "[FIX] Admin Setting descriptions and Storybook",
+ "userLogin": "tassoevan",
+ "milestone": "2.4.0",
+ "contributors": [
+ "tassoevan"
+ ]
+ },
+ {
+ "pr": "16033",
+ "title": "[IMPROVE] Notify logged agents when their departments change",
+ "userLogin": "renatobecker",
+ "milestone": "2.4.0",
+ "contributors": [
+ "renatobecker"
+ ]
+ },
+ {
+ "pr": "15901",
+ "title": "[IMPROVE] Replace fullEmojiData publication by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "sampaiodiego",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "15948",
+ "title": "[IMPROVE] Replace adminRooms publication by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "15926",
+ "title": "[IMPROVE] Replace webdavAccounts publication by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "sampaiodiego",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "15878",
+ "title": "[IMPROVE] Replace oauth publications by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "sampaiodiego",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "15956",
+ "title": "[IMPROVE] Replace userAutocomplete publication by REST",
+ "userLogin": "MarcosSpessatto",
+ "contributors": [
+ "MarcosSpessatto",
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "15908",
+ "title": "[IMPROVE] Replace discussionsOfARoom publication by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "16023",
+ "title": "[FIX] width of upload-progress-text",
+ "userLogin": "mariaeduardacunha",
+ "milestone": "2.4.0",
+ "contributors": [
+ "mariaeduardacunha"
+ ]
+ },
+ {
+ "pr": "15685",
+ "title": "[IMPROVE] Move 'Reply in Thread' button from menu to message actions",
+ "userLogin": "antkaz",
+ "milestone": "2.4.0",
+ "contributors": [
+ "antkaz",
+ "ggazzo"
+ ]
+ },
+ {
+ "pr": "15570",
+ "title": "Fixed Grammatical Mistakes.",
+ "userLogin": "breaking-let",
+ "milestone": "2.4.0",
+ "contributors": [
+ "breaking-let"
+ ]
+ },
+ {
+ "pr": "16020",
+ "title": "Upgrade limax to 2.0.0",
+ "userLogin": "rodrigok",
+ "milestone": "2.4.0",
+ "contributors": [
+ "rodrigok"
+ ]
+ },
+ {
+ "pr": "15907",
+ "title": "[IMPROVE] Replace customSounds publication by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "sampaiodiego",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "16018",
+ "title": "[FIX] Message list scrolling to bottom on reactions",
+ "userLogin": "ggazzo",
+ "milestone": "2.4.0",
+ "contributors": [
+ "ggazzo",
+ "mariaeduardacunha"
+ ]
+ },
+ {
+ "pr": "16004",
+ "title": "[IMPROVE] Replace stdout publication by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "15978",
+ "title": "[FIX] SAML logout error",
+ "userLogin": "sampaiodiego",
+ "milestone": "2.4.0",
+ "contributors": [
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "16016",
+ "title": "[FIX]Added Join button to Read Only rooms.",
+ "userLogin": "gabriellsh",
+ "milestone": "2.4.0",
+ "contributors": [
+ "gabriellsh",
+ "MartinSchoeler"
+ ]
+ },
+ {
+ "pr": "15942",
+ "title": "[IMPROVE] Replace fullUserStatusData publication by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "sampaiodiego",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "15916",
+ "title": "[IMPROVE] Replace userData subscriptions by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "16013",
+ "title": "[FIX] z-index of new message button",
+ "userLogin": "mariaeduardacunha",
+ "contributors": [
+ "mariaeduardacunha"
+ ]
+ },
+ {
+ "pr": "16017",
+ "title": "[FIX] new message popup",
+ "userLogin": "mariaeduardacunha",
+ "milestone": "2.4.0",
+ "contributors": [
+ "mariaeduardacunha"
+ ]
+ },
+ {
+ "pr": "16012",
+ "title": "[FIX] Changed renderMessage priority, fixed Katex on/off setting",
+ "userLogin": "gabriellsh",
+ "contributors": [
+ "gabriellsh"
+ ]
+ },
+ {
+ "pr": "16009",
+ "title": "[FIX] Empty security section when 2fa is disabled",
+ "userLogin": "MartinSchoeler",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MartinSchoeler"
+ ]
+ },
+ {
+ "pr": "16006",
+ "title": "[FIX] Dropzone being stuck when dragging to thread",
+ "userLogin": "MartinSchoeler",
+ "contributors": [
+ "MartinSchoeler"
+ ]
+ },
+ {
+ "pr": "15910",
+ "title": "[IMPROVE] Replace roles publication by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto"
+ ]
+ },
+ {
+ "pr": "15792",
+ "title": "[IMPROVE] Livechat realtime dashboard",
+ "userLogin": "MarcosSpessatto",
+ "contributors": [
+ "MarcosSpessatto"
+ ]
+ },
+ {
+ "pr": "16001",
+ "title": "[FIX] Fix sort livechat rooms",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto"
+ ]
+ },
+ {
+ "pr": "15927",
+ "title": "[NEW] Logout other clients when changing password",
+ "userLogin": "rodrigok",
+ "milestone": "2.4.0",
+ "contributors": [
+ "rodrigok"
+ ]
+ },
+ {
+ "pr": "15991",
+ "title": "[FIX] Guest's name field missing when forwarding livechat rooms",
+ "userLogin": "renatobecker",
+ "milestone": "2.4.0",
+ "contributors": [
+ "renatobecker"
+ ]
+ },
+ {
+ "pr": "15968",
+ "title": "[IMPROVE] Replace livechat:rooms publication by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto"
+ ]
+ },
+ {
+ "pr": "15989",
+ "title": "Remove unnecessary cron starts",
+ "userLogin": "rodrigok",
+ "milestone": "2.4.0",
+ "contributors": [
+ "rodrigok"
+ ]
+ },
+ {
+ "pr": "15979",
+ "title": "Enable typescript lint",
+ "userLogin": "rodrigok",
+ "milestone": "2.4.0",
+ "contributors": [
+ "rodrigok"
+ ]
+ },
+ {
+ "pr": "15988",
+ "title": "LingoHub based on develop",
+ "userLogin": "engelgabriel",
+ "contributors": [
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "15928",
+ "title": "[NEW] Do not print emails in console on production mode",
+ "userLogin": "rodrigok",
+ "milestone": "2.4.0",
+ "contributors": [
+ "rodrigok"
+ ]
+ },
+ {
+ "pr": "15985",
+ "title": "[FIX] Error of bind environment on user data export",
+ "userLogin": "rodrigok",
+ "milestone": "2.4.0",
+ "contributors": [
+ "rodrigok"
+ ]
+ },
+ {
+ "pr": "15503",
+ "title": "[IMPROVE] Replace livechat:officeHour publication to REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto"
+ ]
+ },
+ {
+ "pr": "15975",
+ "title": "[FIX] Incorrect translation key on Livechat Appearance template",
+ "userLogin": "ritwizsinha",
+ "milestone": "2.4.0",
+ "contributors": [
+ "ritwizsinha"
+ ]
+ },
+ {
+ "pr": "15970",
+ "title": "[IMPROVE] Replace forgotten livechat:departmentAgents subscriptions",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "renatobecker"
+ ]
+ },
+ {
+ "pr": "15966",
+ "title": "[FIX] Livechat Widget version 1.3.0",
+ "userLogin": "renatobecker",
+ "milestone": "2.3.2",
+ "contributors": [
+ "renatobecker"
+ ]
+ },
+ {
+ "pr": "15962",
+ "title": "Fix 'How it all started' link on README",
+ "userLogin": "zdumitru",
+ "contributors": [
+ "zdumitru",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "15957",
+ "title": "[FIX] Invalid Redirect URI on Custom OAuth",
+ "userLogin": "pierre-lehnen-rc",
+ "milestone": "2.3.2",
+ "contributors": [
+ "pierre-lehnen-rc"
+ ]
+ },
+ {
+ "pr": "15961",
+ "title": "Check package-lock consistency with package.json on CI",
+ "userLogin": "rodrigok",
+ "contributors": [
+ "rodrigok"
+ ]
+ },
+ {
+ "pr": "15873",
+ "title": "Meteor update to 1.8.2",
+ "userLogin": "sampaiodiego",
+ "contributors": [
+ "sampaiodiego",
+ "rodrigok"
+ ]
+ },
+ {
+ "pr": "15918",
+ "title": "GitHub CI",
+ "userLogin": "rodrigok",
+ "contributors": [
+ "rodrigok",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "15944",
+ "title": "[IMPROVE] Replace livechat:managers publication by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto"
+ ]
+ },
+ {
+ "pr": "15943",
+ "title": "[IMPROVE] Replace livechat:visitorHistory publication by REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "renatobecker"
+ ]
+ },
+ {
+ "pr": "15903",
+ "title": "[FIX] Livechat build without NodeJS installed",
+ "userLogin": "localguru",
+ "contributors": [
+ "localguru"
+ ]
+ },
+ {
+ "pr": "15940",
+ "title": "Change migration number 169 <-> 170",
+ "userLogin": "sampaiodiego",
+ "contributors": [
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "15939",
+ "title": "LingoHub based on develop",
+ "userLogin": "engelgabriel",
+ "contributors": [
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "15612",
+ "title": "[IMPROVE] Replace livechat:queue subscription",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "renatobecker",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "15935",
+ "title": "[IMPROVE] Add deprecate warning in some unused publications",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto"
+ ]
+ },
+ {
+ "pr": "15937",
+ "title": "[FIX] Admin menu not showing after renamed integration permissions",
+ "userLogin": "n-se",
+ "milestone": "2.3.1",
+ "contributors": [
+ "n-se"
+ ]
+ },
+ {
+ "pr": "15934",
+ "title": "[FIX] Administration UI issues",
+ "userLogin": "tassoevan",
+ "milestone": "2.3.1",
+ "contributors": [
+ "tassoevan"
+ ]
+ },
+ {
+ "pr": "15496",
+ "title": "[IMPROVE] Replace livechat:customFields to REST",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "sampaiodiego",
+ "web-flow",
+ "renatobecker"
+ ]
+ },
+ {
+ "pr": "15919",
+ "title": "[FIX] Server crash on sync with no response",
+ "userLogin": "geekgonecrazy",
+ "contributors": [
+ "geekgonecrazy",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "15915",
+ "title": "[FIX] Livechat permissions being overwrite on server restart",
+ "userLogin": "renatobecker",
+ "milestone": "2.3.1",
+ "contributors": [
+ "renatobecker"
+ ]
+ },
+ {
+ "pr": "15897",
+ "title": "[FIX] Livechat triggers not firing",
+ "userLogin": "renatobecker",
+ "milestone": "2.3.1",
+ "contributors": [
+ "renatobecker"
+ ]
+ },
+ {
+ "pr": "15895",
+ "title": "[FIX] Auto load image user preference",
+ "userLogin": "ggazzo",
+ "milestone": "2.3.1",
+ "contributors": [
+ "ggazzo",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "15887",
+ "title": "[IMPROVE] Validate user identity on send message process",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.0",
+ "contributors": [
+ "MarcosSpessatto",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "15850",
+ "title": "[FIX] Don't throw an error when a message is prevented from apps engine",
+ "userLogin": "wreiske",
+ "contributors": [
+ "wreiske",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "15898",
+ "title": "[FIX] Default value of the Livechat WebhookUrl setting",
+ "userLogin": "renatobecker",
+ "milestone": "2.3.1",
+ "contributors": [
+ "renatobecker"
+ ]
+ },
+ {
+ "pr": "15888",
+ "title": "[IMPROVE] Update ui for Roles field",
+ "userLogin": "antkaz",
+ "milestone": "2.4.0",
+ "contributors": [
+ "antkaz"
+ ]
+ },
+ {
+ "pr": "15837",
+ "title": "[NEW] Apps-Engine event for when a livechat room is closed",
+ "userLogin": "lolimay",
+ "milestone": "2.4.0",
+ "contributors": [
+ "lolimay",
+ "renatobecker",
+ "d-gubert"
+ ]
+ },
+ {
+ "pr": "15894",
+ "title": "[CHORE] Replace findOne with findOneById methods (Omnichannel)",
+ "userLogin": "renatobecker",
+ "milestone": "2.4.0",
+ "contributors": [
+ "renatobecker"
+ ]
+ },
+ {
+ "pr": "15841",
+ "title": "[FIX] Thread Replies in Search",
+ "userLogin": "MartinSchoeler",
+ "contributors": [
+ "MartinSchoeler"
+ ]
+ },
+ {
+ "pr": "15872",
+ "title": "Merge master into develop & Set version to 3.0.0-develop",
+ "userLogin": "sampaiodiego",
+ "contributors": [
+ "rodrigok",
+ "web-flow",
+ "sampaiodiego"
+ ]
+ }
+ ]
+ },
+ "2.4.0-rc.1": {
+ "node_version": "8.17.0",
+ "npm_version": "6.13.4",
+ "mongo_versions": [
+ "3.4",
+ "3.6",
+ "4.0"
+ ],
+ "pull_requests": [
+ {
+ "pr": "16053",
+ "title": "Regression: Update components",
+ "userLogin": "tassoevan",
+ "milestone": "2.4.0",
+ "contributors": [
+ "tassoevan"
+ ]
+ }
+ ]
+ },
+ "2.4.0-rc.2": {
+ "node_version": "8.17.0",
+ "npm_version": "6.13.4",
+ "mongo_versions": [
+ "3.4",
+ "3.6",
+ "4.0"
+ ],
+ "pull_requests": [
+ {
+ "pr": "16084",
+ "title": "Regression: Missing button to copy Invite links",
+ "userLogin": "ggazzo",
+ "milestone": "2.4.0",
+ "contributors": [
+ "ggazzo"
+ ]
+ },
+ {
+ "pr": "16062",
+ "title": "[FIX] Registration form was hidden when login form was disabled",
+ "userLogin": "rodrigok",
+ "milestone": "2.4.0",
+ "contributors": [
+ "rodrigok"
+ ]
+ }
+ ]
+ },
+ "2.4.0-rc.3": {
+ "node_version": "8.17.0",
+ "npm_version": "6.13.4",
+ "mongo_versions": [
+ "3.4",
+ "3.6",
+ "4.0"
+ ],
+ "pull_requests": []
+ },
+ "2.4.0": {
+ "node_version": "8.17.0",
+ "npm_version": "6.13.4",
+ "mongo_versions": [
+ "3.4",
+ "3.6",
+ "4.0"
+ ],
+ "pull_requests": []
+ },
+ "2.4.1": {
+ "node_version": "8.17.0",
+ "npm_version": "6.13.4",
+ "mongo_versions": [
+ "3.4",
+ "3.6",
+ "4.0"
+ ],
+ "pull_requests": [
+ {
+ "pr": "16189",
+ "title": "[FIX] Enable apps change properties of the sender on the message as before",
+ "userLogin": "d-gubert",
+ "milestone": "2.4.1",
+ "contributors": [
+ "d-gubert",
+ "sampaiodiego",
+ "web-flow"
+ ]
+ },
+ {
+ "pr": "16171",
+ "title": "[FIX] Add missing password field back to administration area",
+ "userLogin": "rodrigok",
+ "milestone": "2.4.1",
+ "contributors": [
+ "rodrigok",
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "16139",
+ "title": "[FIX] JS errors on Administration page",
+ "userLogin": "mariaeduardacunha",
+ "milestone": "2.4.1",
+ "contributors": [
+ "mariaeduardacunha"
+ ]
+ }
+ ]
+ },
+ "2.3.3": {
+ "node_version": "8.15.1",
+ "npm_version": "6.9.0",
+ "mongo_versions": [],
+ "pull_requests": [
+ {
+ "pr": "16171",
+ "title": "[FIX] Add missing password field back to administration area",
+ "userLogin": "rodrigok",
+ "milestone": "2.4.1",
+ "contributors": [
+ "rodrigok",
+ "sampaiodiego"
+ ]
+ }
+ ]
+ },
+ "2.4.2": {
+ "node_version": "8.17.0",
+ "npm_version": "6.13.4",
+ "mongo_versions": [
+ "3.4",
+ "3.6",
+ "4.0"
+ ],
+ "pull_requests": [
+ {
+ "pr": "16147",
+ "title": "[FIX] Setup Wizard inputs and Admin Settings",
+ "userLogin": "tassoevan",
+ "milestone": "2.4.2",
+ "contributors": [
+ "tassoevan",
+ "ggazzo"
+ ]
+ },
+ {
+ "pr": "16253",
+ "title": "[FIX] Slack CSV User Importer",
+ "userLogin": "ggazzo",
+ "milestone": "2.4.2",
+ "contributors": [
+ "ggazzo"
+ ]
+ },
+ {
+ "pr": "16233",
+ "title": "[FIX] Integrations list without pagination and outgoing integration creation",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.2",
+ "contributors": [
+ "MarcosSpessatto"
+ ]
+ },
+ {
+ "pr": "16184",
+ "title": "[FIX] User stuck after reset password",
+ "userLogin": "sampaiodiego",
+ "milestone": "2.4.2",
+ "contributors": [
+ "sampaiodiego"
+ ]
+ }
+ ]
+ },
+ "2.4.3": {
+ "node_version": "8.17.0",
+ "npm_version": "6.13.4",
+ "mongo_versions": [
+ "3.4",
+ "3.6",
+ "4.0"
+ ],
+ "pull_requests": [
+ {
+ "pr": "16347",
+ "title": "[FIX] Unknown error when sending message if 'Set a User Name to Alias in Message' setting is enabled",
+ "userLogin": "sampaiodiego",
+ "milestone": "2.4.3",
+ "contributors": [
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "16176",
+ "title": "[FIX] Invite links usage by channel owners/moderators",
+ "userLogin": "pierre-lehnen-rc",
+ "milestone": "2.4.3",
+ "contributors": [
+ "pierre-lehnen-rc",
+ "web-flow",
+ "sampaiodiego"
+ ]
+ }
+ ]
+ },
+ "2.4.4": {
+ "node_version": "8.17.0",
+ "npm_version": "6.13.4",
+ "mongo_versions": [
+ "3.4",
+ "3.6",
+ "4.0"
+ ],
+ "pull_requests": [
+ {
+ "pr": "16377",
+ "title": "Release 2.4.4",
+ "userLogin": "sampaiodiego",
+ "contributors": [
+ "rodrigok",
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "16361",
+ "title": "Regression: Rate limiter was not working due to Meteor internal changes",
+ "userLogin": "rodrigok",
+ "milestone": "2.4.4",
+ "contributors": [
+ "rodrigok"
+ ]
+ },
+ {
+ "pr": "16362",
+ "title": "[FIX] App removal was moving logs to the trash collection",
+ "userLogin": "rodrigok",
+ "milestone": "2.4.4",
+ "contributors": [
+ "rodrigok"
+ ]
+ }
+ ]
+ },
+ "2.4.5": {
+ "node_version": "8.17.0",
+ "npm_version": "6.13.4",
+ "mongo_versions": [
+ "3.4",
+ "3.6",
+ "4.0"
+ ],
+ "pull_requests": []
+ },
+ "2.4.6": {
+ "node_version": "8.17.0",
+ "npm_version": "6.13.4",
+ "mongo_versions": [
+ "3.4",
+ "3.6",
+ "4.0"
+ ],
+ "pull_requests": [
+ {
+ "pr": "16395",
+ "title": "Revert message properties validation",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "3.0.0",
+ "contributors": [
+ "MarcosSpessatto"
+ ]
+ },
+ {
+ "pr": "16401",
+ "title": "Fix index creation for apps_logs collection",
+ "userLogin": "rodrigok",
+ "milestone": "3.0.0",
+ "contributors": [
+ "rodrigok"
+ ]
+ }
+ ]
+ },
+ "2.4.7": {
+ "node_version": "8.17.0",
+ "npm_version": "6.13.4",
+ "mongo_versions": [
+ "3.4",
+ "3.6",
+ "4.0"
+ ],
+ "pull_requests": [
+ {
+ "pr": "16433",
+ "title": "[FIX] Option to make a channel default",
+ "userLogin": "MarcosSpessatto",
+ "milestone": "2.4.7",
+ "contributors": [
+ "MarcosSpessatto"
+ ]
+ }
+ ]
}
}
}
\ No newline at end of file
diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
new file mode 100644
index 000000000000..22e25d56bc06
--- /dev/null
+++ b/.github/workflows/build_and_test.yml
@@ -0,0 +1,397 @@
+name: Build and Test
+
+on:
+ release:
+ types: [published]
+ pull_request:
+ branches: '**'
+ push:
+ branches:
+ - develop
+
+env:
+ CI: true
+ MONGO_URL: mongodb://localhost:27017
+ TOOL_NODE_FLAGS: --max_old_space_size=4096
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ 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: Use Node.js 8.17.0
+ uses: actions/setup-node@v1
+ with:
+ node-version: "8.17.0"
+
+ - uses: actions/checkout@v1
+
+ - name: check package-lock
+ run: |
+ npx package-lock-check
+
+ - name: Cache node modules
+ id: cache-nodemodules
+ uses: actions/cache@v1
+ with:
+ path: node_modules
+ key: ${{ runner.OS }}-node_modules-${{ hashFiles('**/package-lock.json') }}
+
+ - name: Cache meteor local
+ uses: actions/cache@v1
+ with:
+ path: ./.meteor/local
+ key: ${{ runner.OS }}-meteor_cache-${{ hashFiles('.meteor/versions') }}
+
+ - name: Cache meteor
+ uses: actions/cache@v1
+ with:
+ path: ~/.meteor
+ key: ${{ runner.OS }}-meteor-${{ hashFiles('.meteor/release') }}
+
+ - 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
+ node -v
+ meteor --version
+ meteor npm --versions
+ meteor node -v
+ git version
+
+ - name: npm install
+ if: steps.cache-nodemodules.outputs.cache-hit != 'true'
+ run: |
+ meteor npm install
+
+ - run: npm run lint
+
+ - name: Launch MongoDB
+ uses: wbari/start-mongoDB@v0.2
+ with:
+ mongoDBVersion: "4.0"
+
+ - run: npm run testunit
+
+ # To reduce memory need during actual build, build the packages solely first
+ # - name: Build a Meteor cache
+ # run: |
+ # # to do this we can clear the main files and it build the rest
+ # echo "" > server/main.js
+ # echo "" > client/main.js
+ # sed -i.backup 's/rocketchat:livechat/#rocketchat:livechat/' .meteor/packages
+ # meteor build --server-only --debug --directory /tmp/build-temp
+ # git checkout -- server/main.js client/main.js .meteor/packages
+
+ - name: Reset Meteor
+ if: startsWith(github.ref, 'refs/tags/') == 'true' || github.ref == 'refs/heads/develop'
+ run: |
+ meteor reset
+
+ - name: Build Rocket.Chat From Pull Request
+ if: startsWith(github.ref, 'refs/pull/') == true
+ env:
+ METEOR_PROFILE: 1000
+ run: |
+ meteor build --server-only --directory --debug /tmp/build-test
+
+ - name: Build Rocket.Chat
+ if: startsWith(github.ref, 'refs/pull/') != true
+ run: |
+ meteor build --server-only --directory /tmp/build-test
+
+ - name: Prepare build
+ run: |
+ mkdir /tmp/build/
+ cd /tmp/build-test
+ tar czf /tmp/build/Rocket.Chat.tar.gz bundle
+ cd /tmp/build-test/bundle/programs/server
+ npm install
+ cd /tmp
+ tar czf Rocket.Chat.test.tar.gz ./build-test
+
+ - name: Store build for tests
+ uses: actions/upload-artifact@v1
+ with:
+ name: build-test
+ path: /tmp/Rocket.Chat.test.tar.gz
+
+ - name: Store build
+ uses: actions/upload-artifact@v1
+ with:
+ name: build
+ path: /tmp/build
+
+ test:
+ runs-on: ubuntu-16.04
+ needs: build
+
+ strategy:
+ matrix:
+ node-version: ["8.17.0"]
+ mongodb-version: ["4.0"]
+
+ steps:
+ - name: Launch MongoDB
+ uses: wbari/start-mongoDB@v0.2
+ with:
+ mongoDBVersion: ${{ matrix.mongodb-version }} --noprealloc --smallfiles --replSet=rs0
+
+ - name: Restore build for tests
+ uses: actions/download-artifact@v1
+ with:
+ name: build-test
+ path: /tmp
+
+ - name: Decompress build
+ run: |
+ cd /tmp
+ tar xzf Rocket.Chat.test.tar.gz
+ cd -
+
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v1
+ with:
+ node-version: ${{ matrix.node-version }}
+
+ - name: Setup Chrome
+ run: |
+ npm i chromedriver
+
+ - name: Configure Replica Set
+ run: |
+ docker exec mongo mongo --eval 'rs.initiate({_id:"rs0", members: [{"_id":1, "host":"localhost:27017"}]})'
+ docker exec mongo mongo --eval 'rs.status()'
+
+ - uses: actions/checkout@v1
+
+ - name: Cache node modules
+ id: cache-nodemodules
+ uses: actions/cache@v1
+ with:
+ path: node_modules
+ key: ${{ runner.OS }}-build-${{ hashFiles('**/package-lock.json') }}
+
+ - name: NPM install
+ if: steps.cache-nodemodules.outputs.cache-hit != 'true'
+ run: |
+ npm install
+
+ - name: Test
+ env:
+ TEST_MODE: "true"
+ MONGO_URL: mongodb://localhost:27017/rocketchat
+ MONGO_OPLOG_URL: mongodb://localhost:27017/local
+ run: |
+ for i in $(seq 1 5); do (docker exec mongo mongo rocketchat --eval 'db.dropDatabase()') && xvfb-run --auto-servernum npm test && s=0 && break || s=$? && sleep 1; done; (exit $s)
+
+# notification:
+# runs-on: ubuntu-latest
+# needs: test
+
+# steps:
+# - name: Rocket.Chat Notification
+# uses: RocketChat/Rocket.Chat.GitHub.Action.Notification@1.1.1
+# with:
+# type: ${{ job.status }}
+# job_name: '**Build and Test**'
+# url: ${{ secrets.ROCKETCHAT_WEBHOOK }}
+# commit: true
+# token: ${{ secrets.GITHUB_TOKEN }}
+
+ build-image-pr:
+ runs-on: ubuntu-latest
+ if: github.event_name == 'pull_request'
+
+ steps:
+ - uses: actions/checkout@v1
+
+ - name: Cache node modules
+ id: cache-nodemodules
+ uses: actions/cache@v1
+ with:
+ path: node_modules
+ key: ${{ runner.OS }}-node_modules-${{ hashFiles('**/package-lock.json') }}
+
+ - name: Cache meteor local
+ uses: actions/cache@v1
+ with:
+ path: ./.meteor/local
+ key: ${{ runner.OS }}-meteor_cache-${{ hashFiles('.meteor/versions') }}
+
+ - name: Cache meteor
+ uses: actions/cache@v1
+ with:
+ path: ~/.meteor
+ key: ${{ runner.OS }}-meteor-${{ hashFiles('.meteor/release') }}
+
+ - name: Use Node.js 8.17.0
+ uses: actions/setup-node@v1
+ with:
+ node-version: "8.17.0"
+
+ - 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
+ node -v
+ meteor --version
+ meteor npm --versions
+ meteor node -v
+ git version
+ echo $GITHUB_REF
+
+ - name: npm install
+ if: steps.cache-nodemodules.outputs.cache-hit != 'true'
+ run: |
+ meteor npm install
+
+ # To reduce memory need during actual build, build the packages solely first
+ # - name: Build a Meteor cache
+ # run: |
+ # # to do this we can clear the main files and it build the rest
+ # echo "" > server/main.js
+ # echo "" > client/main.js
+ # sed -i.backup 's/rocketchat:livechat/#rocketchat:livechat/' .meteor/packages
+ # meteor build --server-only --debug --directory /tmp/build-temp
+ # git checkout -- server/main.js client/main.js .meteor/packages
+
+ - name: Build Rocket.Chat
+ run: |
+ meteor build --server-only --directory /tmp/build-pr
+
+ - name: Build Docker image for PRs
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ VERSION: pr-${{ github.event.number }}
+ run: |
+ cd /tmp/build-pr
+
+ export OWNER="${GITHUB_REPOSITORY%/*}"
+
+ docker login docker.pkg.github.com -u "${GITHUB_ACTOR}" -p "${GITHUB_TOKEN}"
+
+ cp $GITHUB_WORKSPACE/.docker/Dockerfile .
+
+ export LOWERCASE_REPOSITORY=$(echo "$GITHUB_REPOSITORY" | tr "[:upper:]" "[:lower:]")
+
+ export IMAGE_NAME="docker.pkg.github.com/${LOWERCASE_REPOSITORY}/rocket.chat:${VERSION}"
+
+ echo "Build official Docker image ${IMAGE_NAME}"
+
+ docker build -t $IMAGE_NAME .
+ docker push $IMAGE_NAME
+
+ image-build:
+ runs-on: ubuntu-latest
+ needs: test
+
+ strategy:
+ matrix:
+ release: ["official"]
+
+ env:
+ IMAGE: "assistify/chat"
+
+ steps:
+ - uses: actions/checkout@v1
+
+ - name: Restore build
+ uses: actions/download-artifact@v1
+ with:
+ name: build
+ path: /tmp/build
+
+ - name: Unpack build
+ env:
+ DOCKER_USER: ${{ secrets.DOCKER_USER }}
+ DOCKER_PASS: ${{ secrets.DOCKER_PASS }}
+ run: |
+ cd /tmp/build
+ tar xzf Rocket.Chat.tar.gz
+ rm Rocket.Chat.tar.gz
+
+ export DOCKER_PATH="${GITHUB_WORKSPACE}/.docker"
+ if [[ '${{ matrix.release }}' = 'preview' ]]; then
+ export IMAGE="${IMAGE}.preview"
+ export DOCKER_PATH="${DOCKER_PATH}-mongo"
+ fi;
+
+ echo "Build ${{ matrix.release }} Docker image"
+ cp ${DOCKER_PATH}/Dockerfile .
+ if [ -e ${DOCKER_PATH}/entrypoint.sh ]; then
+ cp ${DOCKER_PATH}/entrypoint.sh .
+ fi;
+
+ docker login -u $DOCKER_USER -p $DOCKER_PASS
+
+ - name: Build Docker image for tag
+ if: github.event_name == 'release'
+ run: |
+ cd /tmp/build
+ export CIRCLE_TAG="${GITHUB_REF#*tags/}"
+
+ docker build -t ${IMAGE}:$CIRCLE_TAG .
+ docker push ${IMAGE}:$CIRCLE_TAG
+
+ if echo "$CIRCLE_TAG" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' ; then
+ export RELEASE="latest"
+ elif echo "$CIRCLE_TAG" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$' ; then
+ export RELEASE="release-candidate"
+ fi
+
+ docker tag ${IMAGE}:$CIRCLE_TAG ${IMAGE}:${RELEASE}
+ docker push ${IMAGE}:${RELEASE}
+
+ - name: Build Docker image for develop
+ if: github.ref == 'refs/heads/develop'
+ run: |
+ cd /tmp/build
+ docker build -t ${IMAGE}:develop .
+ docker push ${IMAGE}:develop
diff --git a/.gitignore b/.gitignore
index 1d778eda57fe..af1cd3d52034 100644
--- a/.gitignore
+++ b/.gitignore
@@ -78,3 +78,4 @@ packages/rocketchat-i18n/i18n/livechat.*
tests/end-to-end/temporary_staged_test
.screenshots
/private/livechat
+/storybook-static
diff --git a/.meteor/.finished-upgraders b/.meteor/.finished-upgraders
index 8f397c7dad01..bc5b50f7cd47 100644
--- a/.meteor/.finished-upgraders
+++ b/.meteor/.finished-upgraders
@@ -17,3 +17,4 @@ notices-for-facebook-graph-api-2
1.4.3-split-account-service-packages
1.5-add-dynamic-import-package
1.7-split-underscore-from-meteor-base
+1.8.3-split-jquery-from-blaze
diff --git a/.meteor/packages b/.meteor/packages
index 263feae546d3..78743cc07118 100644
--- a/.meteor/packages
+++ b/.meteor/packages
@@ -7,16 +7,17 @@ rocketchat:mongo-config
accounts-facebook@1.3.2
accounts-github@1.4.2
-accounts-google@1.3.2
+accounts-google@1.3.3
accounts-meteor-developer@1.4.2
-accounts-password@1.5.1
+accounts-password@1.5.2
accounts-twitter@1.4.2
blaze-html-templates
check@1.3.1
ddp-rate-limiter@1.0.7
ddp-common@1.4.0
dynamic-import@0.5.1
-ecmascript@0.12.4
+ecmascript@0.13.2
+typescript@3.7.1
ejson@1.1.0
email@1.2.3
fastclick@1.0.13
@@ -25,7 +26,7 @@ jquery@1.11.10
logging@1.1.20
meteor-base@1.4.0
mobile-experience@1.0.5
-mongo@1.6.2
+mongo@1.7.0
random@1.1.0
rate-limit@1.0.9
reactive-dict@1.3.0
@@ -35,7 +36,7 @@ service-configuration@1.0.11
session@1.2.0
shell-server@0.4.0
spacebars
-standard-minifier-js@2.4.1
+standard-minifier-js@2.5.2
tracker@1.2.0
#rocketchat:google-natural-language
@@ -57,7 +58,6 @@ jparker:gravatar
kadira:blaze-layout
kadira:flow-router
keepnox:perfect-scrollbar
-mizzao:autocomplete
mizzao:timesync
mrt:reactive-store
mystor:device-detection
@@ -77,10 +77,10 @@ littledata:synced-cron
edgee:slingshot
jalik:ufs-local@0.2.5
-accounts-base@1.4.3
+accounts-base@1.4.5
accounts-oauth@1.1.16
autoupdate@1.6.0
-babel-compiler@7.3.4
+babel-compiler@7.4.2
google-oauth@1.2.6
htmljs
less
@@ -92,7 +92,8 @@ raix:eventemitter
routepolicy@1.1.0
sha@1.0.9
templating
-webapp@1.7.3
+webapp@1.7.5
webapp-hashing@1.0.9
rocketchat:oauth2-server
rocketchat:i18n
+dandv:caret-position
diff --git a/.meteor/release b/.meteor/release
index 97064e19937b..bfccdc2c96b3 100644
--- a/.meteor/release
+++ b/.meteor/release
@@ -1 +1 @@
-METEOR@1.8.1
+METEOR@1.8.3
diff --git a/.meteor/versions b/.meteor/versions
index 4f242ffbf31d..ccdee8133729 100644
--- a/.meteor/versions
+++ b/.meteor/versions
@@ -1,25 +1,25 @@
-accounts-base@1.4.4
+accounts-base@1.4.5
accounts-facebook@1.3.2
accounts-github@1.4.2
accounts-google@1.3.3
accounts-meteor-developer@1.4.2
accounts-oauth@1.1.16
-accounts-password@1.5.1
+accounts-password@1.5.2
accounts-twitter@1.4.2
aldeed:simple-schema@1.5.4
allow-deny@1.1.0
autoupdate@1.6.0
-babel-compiler@7.3.4
-babel-runtime@1.3.0
+babel-compiler@7.4.2
+babel-runtime@1.4.0
base64@1.0.12
binary-heap@1.0.11
-blaze@2.3.3
+blaze@2.3.4
blaze-html-templates@1.1.2
blaze-tools@1.0.10
boilerplate-generator@1.6.0
caching-compiler@1.2.1
caching-html-compiler@1.1.3
-callback-hook@1.1.0
+callback-hook@1.2.0
cfs:http-methods@0.0.32
check@1.3.1
coffeescript@1.0.17
@@ -34,12 +34,12 @@ deps@1.0.12
diff-sequence@1.1.1
dispatch:run-as-user@1.1.1
dynamic-import@0.5.1
-ecmascript@0.12.7
+ecmascript@0.13.2
ecmascript-runtime@0.7.0
-ecmascript-runtime-client@0.8.0
-ecmascript-runtime-server@0.7.1
+ecmascript-runtime-client@0.9.0
+ecmascript-runtime-server@0.8.0
edgee:slingshot@0.7.1
-ejson@1.1.0
+ejson@1.1.1
email@1.2.3
es5-shim@4.8.0
facebook-oauth@1.6.0
@@ -76,24 +76,23 @@ littledata:synced-cron@1.5.1
livedata@1.0.18
localstorage@1.2.0
logging@1.1.20
-matb33:collection-hooks@0.8.4
+matb33:collection-hooks@0.9.1
mdg:validation-error@0.5.1
meteor@1.9.3
meteor-base@1.4.0
meteor-developer-oauth@1.2.1
meteorhacks:inject-initial@1.0.4
meteorspark:util@0.2.0
-minifier-css@1.4.2
-minifier-js@2.4.1
+minifier-css@1.4.3
+minifier-js@2.5.1
minimongo@1.4.5
-mizzao:autocomplete@0.5.1
mizzao:timesync@0.3.4
mobile-experience@1.0.5
mobile-status-bar@1.0.14
modern-browsers@0.1.4
-modules@0.13.0
-modules-runtime@0.10.3
-mongo@1.6.3
+modules@0.14.0
+modules-runtime@0.11.0
+mongo@1.7.0
mongo-decimal@0.1.1
mongo-dev-server@1.1.0
mongo-id@1.0.7
@@ -103,13 +102,13 @@ mystor:device-detection@0.2.0
nimble:restivus@0.8.12
nooitaf:colors@1.1.2_1
npm-bcrypt@0.9.3
-npm-mongo@3.1.2
+npm-mongo@3.2.0
oauth@1.2.8
oauth1@1.2.2
oauth2@1.2.1
observe-sequence@1.0.16
ordered-dict@1.1.0
-ostrio:cookies@2.4.0
+ostrio:cookies@2.5.0
pauli:accounts-linkedin@5.0.0
pauli:linkedin-oauth@5.0.0
promise@0.11.2
@@ -128,7 +127,7 @@ rocketchat:livechat@0.0.1
rocketchat:mongo-config@0.0.1
rocketchat:oauth2-server@2.1.0
rocketchat:push@3.3.1
-rocketchat:streamer@1.0.2
+rocketchat:streamer@1.1.0
rocketchat:tap-i18n@1.9.1
rocketchat:version@1.0.0
routepolicy@1.1.0
@@ -141,7 +140,7 @@ socket-stream-client@0.2.2
spacebars@1.0.15
spacebars-compiler@1.1.3
srp@1.0.12
-standard-minifier-js@2.4.1
+standard-minifier-js@2.5.2
templating@1.3.2
templating-compiler@1.3.3
templating-runtime@1.3.2
@@ -150,8 +149,9 @@ tmeasday:check-npm-versions@0.3.2
todda00:friendly-slugs@0.6.0
tracker@1.2.0
twitter-oauth@1.2.0
+typescript@3.7.1
ui@1.0.13
underscore@1.0.10
url@1.2.0
-webapp@1.7.4
+webapp@1.7.5
webapp-hashing@1.0.9
diff --git a/.scripts/houstonMetadata.js b/.scripts/houstonMetadata.js
new file mode 100644
index 000000000000..34de398bc857
--- /dev/null
+++ b/.scripts/houstonMetadata.js
@@ -0,0 +1,51 @@
+const getMongoVersion = async function({ version, git }) {
+ try {
+ const workflows = await git.show([`${ version }:.github/workflows/build_and_test.yml`]);
+
+ const mongoMatch = workflows.match(/mongodb\-version: \[([^\]]+)\]/);
+ if (!mongoMatch) {
+ return [];
+ }
+
+ return mongoMatch[1].replace(/"/g, '').replace(/ /g, '').split(',');
+ } catch (e) {
+ console.error(e);
+ }
+ return [];
+};
+
+const getNodeNpmVersions = async function({ version, git, request }) {
+ try {
+ const meteorRelease = await git.show([`${ version }:.meteor/release`]);
+ if (!/^METEOR@(\d+\.){1,2}\d/.test(meteorRelease)) {
+ return {};
+ }
+
+ const meteorVersion = meteorRelease.replace(/\n|\s/g, '');
+
+ const requestResult = await request(`https://raw.githubusercontent.com/meteor/meteor/release/${ meteorVersion }/scripts/build-dev-bundle-common.sh`);
+
+ return {
+ node_version: requestResult.match(/NODE_VERSION=((?:\d+\.){2}\d)/m)[1],
+ npm_version: requestResult.match(/NPM_VERSION=((?:\d+\.){2}\d)/m)[1],
+ };
+ } catch (e) {
+ console.error(e);
+ }
+
+ return {};
+};
+
+module.exports = async function({ version, git, request }) {
+ const mongo_versions = await getMongoVersion({ version, git });
+ const {
+ node_version,
+ npm_version,
+ } = await getNodeNpmVersions({ version, git, request });
+
+ return {
+ node_version,
+ npm_version,
+ mongo_versions,
+ };
+};
diff --git a/.scripts/separateTesting.sh b/.scripts/separateTesting.sh
index 43abdff24bf0..ba9858201905 100755
--- a/.scripts/separateTesting.sh
+++ b/.scripts/separateTesting.sh
@@ -4,7 +4,7 @@ rm -rf $tmpPath
mkdir -p $tmpPath
[ -z "$RETRY_TESTS" ] && RETRY_TESTS=1
-paths=("tests/end-to-end/ui/*.js" "tests/end-to-end/ui_smarti/*.js")
+paths=("tests/end-to-end/api/*.js" "tests/end-to-end/ui/*.js" "tests/end-to-end/ui_smarti/*.js")
for path in ${paths}; do
for file in $path; do
diff --git a/.scripts/set-version.js b/.scripts/set-version.js
index 6524ce70017b..102f8e14cb97 100644
--- a/.scripts/set-version.js
+++ b/.scripts/set-version.js
@@ -13,7 +13,7 @@ let pkgJson = {};
try {
pkgJson = require(path.resolve( // eslint-disable-line import/no-dynamic-require
process.cwd(),
- './package.json'
+ './package.json',
));
} catch (err) {
console.error('no root package.json found');
@@ -21,7 +21,6 @@ try {
const files = [
'./package.json',
- './.travis/snap.sh',
'./.circleci/snap.sh',
'./.circleci/update-releases.sh',
'./.docker/Dockerfile',
@@ -88,7 +87,7 @@ git.status()
type: 'confirm',
message: 'Commit files?',
name: 'commit',
- }])
+ }]),
)
.then((answers) => {
if (!answers.commit) {
diff --git a/.scripts/start-xvfb.sh b/.scripts/start-xvfb.sh
deleted file mode 100755
index 70be0b2e6bd7..000000000000
--- a/.scripts/start-xvfb.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/env bash
-
-if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
- sh -e /etc/init.d/xvfb start
- sleep 3
-fi
diff --git a/.scripts/start.js b/.scripts/start.js
index 70844ab61c2b..deadb683a3ef 100644
--- a/.scripts/start.js
+++ b/.scripts/start.js
@@ -43,7 +43,7 @@ function startProcess(opts, callback) {
const proc = spawn(
opts.command,
opts.params,
- opts.options
+ opts.options,
);
if (opts.waitForMessage) {
diff --git a/.scripts/version.js b/.scripts/version.js
index 461003c2d585..73fc12c46db4 100644
--- a/.scripts/version.js
+++ b/.scripts/version.js
@@ -5,7 +5,7 @@ let pkgJson = {};
try {
pkgJson = require(path.resolve( // eslint-disable-line import/no-dynamic-require
process.cwd(),
- './package.json'
+ './package.json',
));
} catch (err) {
console.error('no root package.json found');
diff --git a/.snapcraft/resources/preparenode b/.snapcraft/resources/preparenode
index a9f4807fed1f..9490792ba201 100755
--- a/.snapcraft/resources/preparenode
+++ b/.snapcraft/resources/preparenode
@@ -1,6 +1,6 @@
#!/bin/bash
-node_version="v8.15.1"
+node_version="v8.17.0"
unamem="$(uname -m)"
if [[ $unamem == *aarch64* ]]; then
diff --git a/.storybook/config.js b/.storybook/config.js
index 5de80993cf9f..95a8b682d7a6 100644
--- a/.storybook/config.js
+++ b/.storybook/config.js
@@ -1,11 +1,8 @@
-import { action } from '@storybook/addon-actions';
-import { withKnobs }from '@storybook/addon-knobs';
+import { withKnobs } from '@storybook/addon-knobs';
import { MINIMAL_VIEWPORTS, INITIAL_VIEWPORTS } from '@storybook/addon-viewport/dist/defaults';
import { addDecorator, addParameters, configure } from '@storybook/react';
-import React from 'react';
-import { ConnectionStatusProvider } from '../client/components/providers/ConnectionStatusProvider.mock';
-import { TranslationProvider } from '../client/components/providers/TranslationProvider.mock';
+import { rocketChatDecorator } from './mocks/decorators';
addParameters({
viewport: {
@@ -15,35 +12,9 @@ addParameters({
},
defaultViewport: 'responsive',
},
-})
-
-addDecorator(function RocketChatDecorator(fn) {
- const linkElement = document.getElementById('theme-styles') || document.createElement('link');
- if (linkElement.id !== 'theme-styles') {
- require('../app/theme/client/main.css');
- require('../app/theme/client/vendor/fontello/css/fontello.css');
- require('../client/RocketChat.font.css');
- linkElement.setAttribute('id', 'theme-styles');
- linkElement.setAttribute('rel', 'stylesheet');
- linkElement.setAttribute('href', 'https://open.rocket.chat/theme.css');
- document.head.appendChild(linkElement);
- }
-
- return
-
-
-
-
- {fn()}
-
-
- ;
});
+addDecorator(rocketChatDecorator);
addDecorator(withKnobs);
configure(require.context('../client', true, /\.stories\.js$/), module);
diff --git a/.storybook/mocks/decorators.js b/.storybook/mocks/decorators.js
new file mode 100644
index 000000000000..8bf073a3b108
--- /dev/null
+++ b/.storybook/mocks/decorators.js
@@ -0,0 +1,31 @@
+import React from 'react';
+
+import { MeteorProviderMock } from './providers';
+
+export const rocketChatDecorator = (fn) => {
+ const linkElement = document.getElementById('theme-styles') || document.createElement('link');
+ if (linkElement.id !== 'theme-styles') {
+ require('../../app/theme/client/main.css');
+ require('../../app/theme/client/vendor/fontello/css/fontello.css');
+ require('../../client/rocketchat.font.css');
+ linkElement.setAttribute('id', 'theme-styles');
+ linkElement.setAttribute('rel', 'stylesheet');
+ linkElement.setAttribute('href', 'https://open.rocket.chat/theme.css');
+ document.head.appendChild(linkElement);
+ }
+
+ // eslint-disable-next-line import/no-unresolved
+ const { default: icons } = require('!!raw-loader!../../private/public/icons.svg');
+
+ return
+
+
+
+ {fn()}
+
+ ;
+};
diff --git a/.storybook/empty.js b/.storybook/mocks/empty.js
similarity index 100%
rename from .storybook/empty.js
rename to .storybook/mocks/empty.js
diff --git a/.storybook/meteor.js b/.storybook/mocks/meteor.js
similarity index 97%
rename from .storybook/meteor.js
rename to .storybook/mocks/meteor.js
index 13f507c7ef32..e4a5761e50d2 100644
--- a/.storybook/meteor.js
+++ b/.storybook/mocks/meteor.js
@@ -27,7 +27,7 @@ export const Mongo = {
find: () => ({
observe: () => {},
fetch: () => [],
- })
+ }),
}),
};
@@ -63,7 +63,7 @@ window.Blaze = Blaze;
export const check = () => {};
export const FlowRouter = {
- route: () => {}
+ route: () => {},
};
export const BlazeLayout = {};
diff --git a/.storybook/mocks/providers.js b/.storybook/mocks/providers.js
new file mode 100644
index 000000000000..1cdd00b7dac1
--- /dev/null
+++ b/.storybook/mocks/providers.js
@@ -0,0 +1,67 @@
+import i18next from 'i18next';
+import React from 'react';
+
+import { TranslationContext } from '../../client/contexts/TranslationContext';
+
+let contextValue;
+
+const getContextValue = () => {
+ if (contextValue) {
+ return contextValue;
+ }
+
+ i18next.init({
+ fallbackLng: 'en',
+ defaultNS: 'project',
+ resources: {
+ en: {
+ project: require('../../packages/rocketchat-i18n/i18n/en.i18n.json'),
+ },
+ },
+ interpolation: {
+ prefix: '__',
+ suffix: '__',
+ },
+ initImmediate: false,
+ });
+
+ const translate = (key, ...replaces) => {
+ if (typeof replaces[0] === 'object') {
+ const [options] = replaces;
+ return i18next.t(key, options);
+ }
+
+ if (replaces.length === 0) {
+ return i18next.t(key);
+ }
+
+ return i18next.t(key, {
+ postProcess: 'sprintf',
+ sprintf: replaces,
+ });
+ };
+
+ translate.has = (key) => key && i18next.exists(key);
+
+ contextValue = {
+ languages: [{
+ name: 'English',
+ en: 'English',
+ key: 'en',
+ }],
+ language: 'en',
+ translate,
+ };
+
+ return contextValue;
+};
+
+function TranslationProviderMock({ children }) {
+ return ;
+}
+
+export function MeteorProviderMock({ children }) {
+ return
+ {children}
+ ;
+}
diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js
index b9d6efb821d6..03a6a91feede 100644
--- a/.storybook/webpack.config.js
+++ b/.storybook/webpack.config.js
@@ -33,12 +33,12 @@ module.exports = async ({ config }) => {
config.plugins.push(new webpack.NormalModuleReplacementPlugin(
/^meteor/,
- require.resolve('./meteor.js'),
+ require.resolve('./mocks/meteor.js'),
));
config.plugins.push(new webpack.NormalModuleReplacementPlugin(
/\.\/server\/index.js/,
- require.resolve('./empty.js'),
+ require.resolve('./mocks/empty.js'),
));
config.mode = 'development';
diff --git a/.stylelintignore b/.stylelintignore
index c62f04a77570..4fc5d8a09035 100644
--- a/.stylelintignore
+++ b/.stylelintignore
@@ -1,4 +1,4 @@
app/theme/client/vendor/fontello/css/fontello.css
-packages/meteor-autocomplete/client/autocomplete.css
+app/meteor-autocomplete/client/autocomplete.css
app/katex/katex.min.css
app/emoji-emojione/client/*.css
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 31f618fadec9..000000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,104 +0,0 @@
-language: node_js
-services:
-- docker
-- mongodb
-branches:
- only:
- - develop
- - "/^\\d+\\.\\d+\\.\\d+(-rc\\.\\d+)?$/"
-git:
- depth: 1
-node_js:
-- '8'
-addons:
- apt:
- sources:
- - google-chrome
- - ubuntu-toolchain-r-test
- packages:
- - google-chrome-stable
- - g++-4.8
- firefox: "latest"
-before_cache:
-- rm -rf $HOME/build/RocketChat/Rocket.Chat/.meteor/local/log
-- rm -rf $HOME/build/RocketChat/Rocket.Chat/.meteor/local/run
-- rm -rf $HOME/build/RocketChat/Rocket.Chat/.meteor/local/db
-cache:
- directories:
- - "$HOME/node_modules"
- - "$HOME/.meteor"
- - "$HOME/.npm"
- - "$HOME/.node-gyp"
- - "$HOME/build/RocketChat/Rocket.Chat/node_modules"
- - "$HOME/build/RocketChat/Rocket.Chat/.meteor/local"
- - "$HOME/build/RocketChat/Rocket.Chat/packages/rocketchat-livechat/.npm"
- - "$HOME/build/RocketChat/Rocket.Chat/packages/rocketchat-livechat/.app/node_modules"
- - "$HOME/build/RocketChat/Rocket.Chat/packages/rocketchat-livechat/.app/.meteor/local"
-before_install:
-- if [ ! -e "$HOME/.meteor/meteor" ]; then curl https://install.meteor.com | sed s/--progress-bar/-sL/g | /bin/sh; fi
-# Start X Virtual Frame Buffer for headless testing with real browsers
-- .scripts/start-xvfb.sh
-install:
-- export PATH="$HOME/.meteor:$PATH"
-before_script:
-- if [[ $TRAVIS_TAG ]]; then meteor reset; fi
-- echo "replication:" | sudo tee -a /etc/mongod.conf
-- |-
- echo " replSetName: \"rs0\"" | sudo tee -a /etc/mongod.conf
-- sudo service mongod restart
-- mkdir /tmp/build
-- meteor --version
-- travis_retry meteor npm install
-- |-
- mongo --eval 'rs.initiate({_id:"rs0", members: [{"_id":1, "host":"localhost:27017"}]})'
-- meteor npm run lint
-- meteor npm run testunit
-- travis_retry meteor build --headless /tmp/build
-- mkdir /tmp/build-test
-- tar -xf /tmp/build/Rocket.Chat.tar.gz -C /tmp/build-test/
-- cd /tmp/build-test/bundle/programs/server
-- npm install
-- cd -
-- mongo --eval 'rs.status()'
-- mongo meteor --eval 'db.getCollectionNames()'
-script:
-- travis_retry npm test
-- mongo meteor --eval 'db.dropDatabase()'
-- unset MONGO_OPLOG_URL
-- travis_retry npm test
-before_deploy:
-- source ".travis/setartname.sh"
-- source ".travis/setdeploydir.sh"
-- ".travis/setupsig.sh"
-- ".travis/namefiles.sh"
-deploy:
- - provider: s3
- access_key_id: AKIAIKIA7H7D47KUHYCA
- secret_access_key: "$ACCESSKEY"
- bucket: download.rocket.chat
- skip_cleanup: true
- upload_dir: build
- local_dir: "$ROCKET_DEPLOY_DIR"
- on:
- condition: "$TRAVIS_PULL_REQUEST=false"
- all_branches: true
- # - provider: releases
- # api-key: "$GITHUB_TOKEN"
- # file_glob: true
- # file: build/*
- # skip_cleanup: true
- # on:
- # tags: true
-
-after_deploy:
-- ".travis/docker.sh"
-- ".travis/update-releases.sh"
-- ".travis/snap.sh"
-env:
- global:
- - DISPLAY=:99.0
- - CXX=g++-4.8
- - secure: HrPOM5sBibYkMcf9aeQThYPCDiXeLkg0Xgv0HvH88/ku/gphDpNEjHNReHZM3cyfm9y3RhHpVdD+Zzy38S2goKyewRzpXJsuyerOYkjND0v3tivhs9CAX8PAUxj1U5zllTyH4bgW2ZwRtNnwnmtIM/JJlnySMpKVDqIZBpbhn3ph9bJ2J+BW3D3Jw8meQ1vCX8szIibyJK/5QX6HG2RBFXJGYoQ8DmR8jQv0aJQvT1Az5DO4yImk8tX4NP95qOc19Jywr1DsbaSBZeJ8lFJAmBpIGx7KAmUVCcxSxfbXGRhs2K4iEYb3rJ/dU6KiyPsKGUG4aYNGgbvcX0ZxX/BZ6ZU9ff0E4IIf43IxoN3ElrOqOFk5msJAXbrJEreINSzDqKOy8NFYtCQ49E2gwzfage4ZXkhFyx3wMPa5bzpr3ncsTceMjMVz03uL781X6NLuCkUmXv+n8K2MNhJU9Xinpdx1GRJm+0lXJspNNJ1ruHeJtls4epj4bmCwKmmZbFKPXqa5e8xVcMIkwt1LMiHduhE+WgKNHdOMhXrCcTxF62ybLlsHXmyLLJeNjTeKS8QG2XSoonClDAz/1R41I1DsMPblcgz9uvYCf7UtyftbhJ83bnJeEmOYQiwijLG0+QMq+B2+mmZan3Z7Hl7O53dnwuLxz7EO7EhQhY+CqHVgc6s=
- - MONGO_OPLOG_URL: "mongodb://localhost:27017/local"
- - MONGO_URL: "mongodb://localhost:27017/meteor"
- - TEST_MODE: "true"
diff --git a/.travis/docker.sh b/.travis/docker.sh
deleted file mode 100755
index 29a7b1b0d8db..000000000000
--- a/.travis/docker.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-set -x
-set -euvo pipefail
-IFS=$'\n\t'
-
-CURL_URL="https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSHTOKEN/"
-
-if [[ $TRAVIS_TAG ]]
- then
- CURL_DATA='{"source_type":"Tag","source_name":"'"$TRAVIS_TAG"'"}';
-else
- CURL_DATA='{"source_type":"Branch","source_name":"'"$TRAVIS_BRANCH"'"}';
-fi
-
-curl -H "Content-Type: application/json" --data "$CURL_DATA" -X POST "$CURL_URL"
diff --git a/.travis/namefiles.sh b/.travis/namefiles.sh
deleted file mode 100755
index 4b497de93bf6..000000000000
--- a/.travis/namefiles.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-set -x
-set -euvo pipefail
-IFS=$'\n\t'
-
-FILENAME="$ROCKET_DEPLOY_DIR/rocket.chat-$ARTIFACT_NAME.tgz";
-
-ln -s /tmp/build/Rocket.Chat.tar.gz "$FILENAME"
-gpg --armor --detach-sign "$FILENAME"
diff --git a/.travis/setartname.sh b/.travis/setartname.sh
deleted file mode 100755
index 38253aac315f..000000000000
--- a/.travis/setartname.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-if [[ $TRAVIS_TAG ]]
- then
- export ARTIFACT_NAME="$(meteor npm run version --silent)"
-else
- export ARTIFACT_NAME="$(meteor npm run version --silent).$TRAVIS_BUILD_NUMBER"
-fi
diff --git a/.travis/setdeploydir.sh b/.travis/setdeploydir.sh
deleted file mode 100755
index 2c49e4a7027a..000000000000
--- a/.travis/setdeploydir.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-export ROCKET_DEPLOY_DIR="/tmp/deploy"
-mkdir -p $ROCKET_DEPLOY_DIR
diff --git a/.travis/setupsig.sh b/.travis/setupsig.sh
deleted file mode 100755
index c5c424635d06..000000000000
--- a/.travis/setupsig.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-set -x
-set -euvo pipefail
-IFS=$'\n\t'
-
-cp .travis/sign.key.gpg /tmp
-gpg --yes --batch --passphrase=$mypass /tmp/sign.key.gpg
-gpg --allow-secret-key-import --import /tmp/sign.key
-rm /tmp/sign.key
diff --git a/.travis/sign.key.gpg b/.travis/sign.key.gpg
deleted file mode 100644
index 488e275998d5..000000000000
Binary files a/.travis/sign.key.gpg and /dev/null differ
diff --git a/.travis/snap.sh b/.travis/snap.sh
deleted file mode 100755
index f548e5961d26..000000000000
--- a/.travis/snap.sh
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/bash
-set -euvo pipefail
-IFS=$'\n\t'
-
-# Add launchpad to known hosts
-ssh-keyscan -t rsa -H git.launchpad.net > ~/.ssh/known_hosts
-
-git config user.name "CI Bot"
-git config user.email "rocketchat.buildmaster@git.launchpad.net"
-
-# Determine the channel to push snap to.
-if [[ $TRAVIS_TAG =~ ^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+ ]]; then
- CHANNEL=candidate
- RC_VERSION=$TRAVIS_TAG
-elif [[ $TRAVIS_TAG ]]; then
- CHANNEL=stable
- RC_VERSION=$TRAVIS_TAG
-else
- CHANNEL=edge
- RC_VERSION=2.3.2
-fi
-
-echo "Preparing to trigger a snap release for $CHANNEL channel"
-
-cd $PWD/.snapcraft
-
-# Decrypt key
-openssl aes-256-cbc -K $encrypted_f5c8ae370556_key -iv $encrypted_f5c8ae370556_iv -in launchpadkey.enc -out launchpadkey -d
-
-# Change permissions
-chmod 0600 launchpadkey
-
-# We need some meta data so it'll actually commit. This could be useful to have for debugging later.
-echo "Tag: $TRAVIS_TAG \r\nBranch: $TRAVIS_BRANCH\r\nBuild: $TRAVIS_BUILD_NUMBER\r\nCommit: $TRAVIS_COMMIT" > buildinfo
-
-# Clone launchpad repo for the channel down.
-GIT_SSH_COMMAND="ssh -i launchpadkey" git clone -b $CHANNEL git+ssh://rocket.chat.buildmaster@git.launchpad.net/rocket.chat launchpad
-
-# Rarely will change, but just incase we copy it all
-cp -r resources buildinfo launchpad/
-sed s/#{RC_VERSION}/$RC_VERSION/ snapcraft.yaml > launchpad/snapcraft.yaml
-
-cd launchpad
-git add resources snapcraft.yaml buildinfo
-
-# Another place where basic meta data will live for at a glance info
-git commit -m "Travis Build: $TRAVIS_BUILD_NUMBER Travis Commit: $TRAVIS_COMMIT"
-
-# Push up up to the branch of choice.
-GIT_SSH_COMMAND="ssh -i ../launchpadkey" git push origin $CHANNEL
-
-# Clean up
-cd ..
-rm -rf launchpadkey launchpad
diff --git a/.travis/update-releases.sh b/.travis/update-releases.sh
deleted file mode 100755
index 658000b9b8a0..000000000000
--- a/.travis/update-releases.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-set -x
-set -euvo pipefail
-IFS=$'\n\t'
-
-CURL_URL="https://rocket.chat/releases/update"
-
-curl -X POST "$CURL_URL"
diff --git a/HISTORY.md b/HISTORY.md
index 4216268cd744..cd65fb376ac3 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,4 +1,276 @@
+# 2.4.7
+`2020-02-03 · 1 🐛 · 1 👩💻👨💻`
+
+### Engine versions
+- Node: `8.17.0`
+- NPM: `6.13.4`
+- MongoDB: `3.4, 3.6, 4.0`
+
+### 🐛 Bug fixes
+
+- Option to make a channel default ([#16433](https://github.com/RocketChat/Rocket.Chat/pull/16433))
+
+### 👩💻👨💻 Core Team 🤓
+
+- [@MarcosSpessatto](https://github.com/MarcosSpessatto)
+
+# 2.4.6
+`2020-01-31 · 2 🔍 · 2 👩💻👨💻`
+
+### Engine versions
+- Node: `8.17.0`
+- NPM: `6.13.4`
+- MongoDB: `3.4, 3.6, 4.0`
+
+
+🔍 Minor changes
+
+- Revert message properties validation ([#16395](https://github.com/RocketChat/Rocket.Chat/pull/16395))
+- Fix index creation for apps_logs collection ([#16401](https://github.com/RocketChat/Rocket.Chat/pull/16401))
+
+
+
+### 👩💻👨💻 Core Team 🤓
+
+- [@MarcosSpessatto](https://github.com/MarcosSpessatto)
+- [@rodrigok](https://github.com/rodrigok)
+
+# 2.4.5
+`2020-01-29 · 1 🐛 `
+
+### Engine versions
+- Node: `8.17.0`
+- NPM: `6.13.4`
+- MongoDB: `3.4, 3.6, 4.0`
+
+### 🐛 Bug fixes
+
+- Update Apps Engine to version 1.11.2
+
+# 2.4.4
+`2020-01-29 · 1 🐛 · 2 🔍 · 2 👩💻👨💻`
+
+### Engine versions
+- Node: `8.17.0`
+- NPM: `6.13.4`
+- MongoDB: `3.4, 3.6, 4.0`
+
+### 🐛 Bug fixes
+
+- App removal was moving logs to the trash collection ([#16362](https://github.com/RocketChat/Rocket.Chat/pull/16362))
+
+
+🔍 Minor changes
+
+- Release 2.4.4 ([#16377](https://github.com/RocketChat/Rocket.Chat/pull/16377))
+- Regression: Rate limiter was not working due to Meteor internal changes ([#16361](https://github.com/RocketChat/Rocket.Chat/pull/16361))
+
+
+
+### 👩💻👨💻 Core Team 🤓
+
+- [@rodrigok](https://github.com/rodrigok)
+- [@sampaiodiego](https://github.com/sampaiodiego)
+
+# 2.4.3
+`2020-01-28 · 2 🐛 · 2 👩💻👨💻`
+
+### Engine versions
+- Node: `8.17.0`
+- NPM: `6.13.4`
+- MongoDB: `3.4, 3.6, 4.0`
+
+### 🐛 Bug fixes
+
+- Unknown error when sending message if 'Set a User Name to Alias in Message' setting is enabled ([#16347](https://github.com/RocketChat/Rocket.Chat/pull/16347))
+- Invite links usage by channel owners/moderators ([#16176](https://github.com/RocketChat/Rocket.Chat/pull/16176))
+
+### 👩💻👨💻 Core Team 🤓
+
+- [@pierre-lehnen-rc](https://github.com/pierre-lehnen-rc)
+- [@sampaiodiego](https://github.com/sampaiodiego)
+
+# 2.4.2
+`2020-01-17 · 4 🐛 · 4 👩💻👨💻`
+
+### Engine versions
+- Node: `8.17.0`
+- NPM: `6.13.4`
+- MongoDB: `3.4, 3.6, 4.0`
+
+### 🐛 Bug fixes
+
+- Setup Wizard inputs and Admin Settings ([#16147](https://github.com/RocketChat/Rocket.Chat/pull/16147))
+- Slack CSV User Importer ([#16253](https://github.com/RocketChat/Rocket.Chat/pull/16253))
+- Integrations list without pagination and outgoing integration creation ([#16233](https://github.com/RocketChat/Rocket.Chat/pull/16233))
+- User stuck after reset password ([#16184](https://github.com/RocketChat/Rocket.Chat/pull/16184))
+
+### 👩💻👨💻 Core Team 🤓
+
+- [@MarcosSpessatto](https://github.com/MarcosSpessatto)
+- [@ggazzo](https://github.com/ggazzo)
+- [@sampaiodiego](https://github.com/sampaiodiego)
+- [@tassoevan](https://github.com/tassoevan)
+
+# 2.4.1
+`2020-01-10 · 2 🐛 · 3 👩💻👨💻`
+
+### Engine versions
+- Node: `8.17.0`
+- NPM: `6.13.4`
+- MongoDB: `3.4, 3.6, 4.0`
+
+### 🐛 Bug fixes
+
+- Enable apps change properties of the sender on the message as before ([#16189](https://github.com/RocketChat/Rocket.Chat/pull/16189))
+- JS errors on Administration page ([#16139](https://github.com/RocketChat/Rocket.Chat/pull/16139))
+
+### 👩💻👨💻 Core Team 🤓
+
+- [@d-gubert](https://github.com/d-gubert)
+- [@mariaeduardacunha](https://github.com/mariaeduardacunha)
+- [@sampaiodiego](https://github.com/sampaiodiego)
+
+# 2.4.0
+`2019-12-27 · 4 🎉 · 28 🚀 · 21 🐛 · 19 🔍 · 21 👩💻👨💻`
+
+### Engine versions
+- Node: `8.17.0`
+- NPM: `6.13.4`
+- MongoDB: `3.4, 3.6, 4.0`
+
+### 🎉 New features
+
+- Invite links: share a link to invite users ([#15933](https://github.com/RocketChat/Rocket.Chat/pull/15933))
+- Logout other clients when changing password ([#15927](https://github.com/RocketChat/Rocket.Chat/pull/15927))
+- Do not print emails in console on production mode ([#15928](https://github.com/RocketChat/Rocket.Chat/pull/15928))
+- Apps-Engine event for when a livechat room is closed ([#15837](https://github.com/RocketChat/Rocket.Chat/pull/15837))
+
+### 🚀 Improvements
+
+- Replace livechat:inquiry publication by REST and Streamer ([#15977](https://github.com/RocketChat/Rocket.Chat/pull/15977))
+- Sorting on livechat analytics queries were wrong ([#16021](https://github.com/RocketChat/Rocket.Chat/pull/16021))
+- Replace fullUserData publication by REST ([#15650](https://github.com/RocketChat/Rocket.Chat/pull/15650))
+- Replace integrations and integrationHistory publications by REST ([#15885](https://github.com/RocketChat/Rocket.Chat/pull/15885))
+- Notify logged agents when their departments change ([#16033](https://github.com/RocketChat/Rocket.Chat/pull/16033))
+- Replace fullEmojiData publication by REST ([#15901](https://github.com/RocketChat/Rocket.Chat/pull/15901))
+- Replace adminRooms publication by REST ([#15948](https://github.com/RocketChat/Rocket.Chat/pull/15948))
+- Replace webdavAccounts publication by REST ([#15926](https://github.com/RocketChat/Rocket.Chat/pull/15926))
+- Replace oauth publications by REST ([#15878](https://github.com/RocketChat/Rocket.Chat/pull/15878))
+- Replace userAutocomplete publication by REST ([#15956](https://github.com/RocketChat/Rocket.Chat/pull/15956))
+- Replace discussionsOfARoom publication by REST ([#15908](https://github.com/RocketChat/Rocket.Chat/pull/15908))
+- Move 'Reply in Thread' button from menu to message actions ([#15685](https://github.com/RocketChat/Rocket.Chat/pull/15685) by [@antkaz](https://github.com/antkaz))
+- Replace customSounds publication by REST ([#15907](https://github.com/RocketChat/Rocket.Chat/pull/15907))
+- Replace stdout publication by REST ([#16004](https://github.com/RocketChat/Rocket.Chat/pull/16004))
+- Replace fullUserStatusData publication by REST ([#15942](https://github.com/RocketChat/Rocket.Chat/pull/15942))
+- Replace userData subscriptions by REST ([#15916](https://github.com/RocketChat/Rocket.Chat/pull/15916))
+- Replace roles publication by REST ([#15910](https://github.com/RocketChat/Rocket.Chat/pull/15910))
+- Livechat realtime dashboard ([#15792](https://github.com/RocketChat/Rocket.Chat/pull/15792))
+- Replace livechat:rooms publication by REST ([#15968](https://github.com/RocketChat/Rocket.Chat/pull/15968))
+- Replace livechat:officeHour publication to REST ([#15503](https://github.com/RocketChat/Rocket.Chat/pull/15503))
+- Replace forgotten livechat:departmentAgents subscriptions ([#15970](https://github.com/RocketChat/Rocket.Chat/pull/15970))
+- Replace livechat:managers publication by REST ([#15944](https://github.com/RocketChat/Rocket.Chat/pull/15944))
+- Replace livechat:visitorHistory publication by REST ([#15943](https://github.com/RocketChat/Rocket.Chat/pull/15943))
+- Replace livechat:queue subscription ([#15612](https://github.com/RocketChat/Rocket.Chat/pull/15612))
+- Add deprecate warning in some unused publications ([#15935](https://github.com/RocketChat/Rocket.Chat/pull/15935))
+- Replace livechat:customFields to REST ([#15496](https://github.com/RocketChat/Rocket.Chat/pull/15496))
+- Validate user identity on send message process ([#15887](https://github.com/RocketChat/Rocket.Chat/pull/15887))
+- Update ui for Roles field ([#15888](https://github.com/RocketChat/Rocket.Chat/pull/15888) by [@antkaz](https://github.com/antkaz))
+
+### 🐛 Bug fixes
+
+- Importer: Variable name appearing instead of it's value ([#16010](https://github.com/RocketChat/Rocket.Chat/pull/16010) by [@ashwaniYDV](https://github.com/ashwaniYDV))
+- Add time format for latest message on the sidebar ([#15930](https://github.com/RocketChat/Rocket.Chat/pull/15930) by [@ritwizsinha](https://github.com/ritwizsinha))
+- Admin Setting descriptions and Storybook ([#15994](https://github.com/RocketChat/Rocket.Chat/pull/15994))
+- width of upload-progress-text ([#16023](https://github.com/RocketChat/Rocket.Chat/pull/16023))
+- Message list scrolling to bottom on reactions ([#16018](https://github.com/RocketChat/Rocket.Chat/pull/16018))
+- SAML logout error ([#15978](https://github.com/RocketChat/Rocket.Chat/pull/15978))
+- Added Join button to Read Only rooms. ([#16016](https://github.com/RocketChat/Rocket.Chat/pull/16016))
+- z-index of new message button ([#16013](https://github.com/RocketChat/Rocket.Chat/pull/16013))
+- new message popup ([#16017](https://github.com/RocketChat/Rocket.Chat/pull/16017))
+- Changed renderMessage priority, fixed Katex on/off setting ([#16012](https://github.com/RocketChat/Rocket.Chat/pull/16012))
+- Empty security section when 2fa is disabled ([#16009](https://github.com/RocketChat/Rocket.Chat/pull/16009))
+- Dropzone being stuck when dragging to thread ([#16006](https://github.com/RocketChat/Rocket.Chat/pull/16006))
+- Fix sort livechat rooms ([#16001](https://github.com/RocketChat/Rocket.Chat/pull/16001))
+- Guest's name field missing when forwarding livechat rooms ([#15991](https://github.com/RocketChat/Rocket.Chat/pull/15991))
+- Error of bind environment on user data export ([#15985](https://github.com/RocketChat/Rocket.Chat/pull/15985))
+- Incorrect translation key on Livechat Appearance template ([#15975](https://github.com/RocketChat/Rocket.Chat/pull/15975) by [@ritwizsinha](https://github.com/ritwizsinha))
+- Livechat build without NodeJS installed ([#15903](https://github.com/RocketChat/Rocket.Chat/pull/15903) by [@localguru](https://github.com/localguru))
+- Server crash on sync with no response ([#15919](https://github.com/RocketChat/Rocket.Chat/pull/15919))
+- Don't throw an error when a message is prevented from apps engine ([#15850](https://github.com/RocketChat/Rocket.Chat/pull/15850) by [@wreiske](https://github.com/wreiske))
+- Thread Replies in Search ([#15841](https://github.com/RocketChat/Rocket.Chat/pull/15841))
+- Registration form was hidden when login form was disabled ([#16062](https://github.com/RocketChat/Rocket.Chat/pull/16062))
+
+
+🔍 Minor changes
+
+- Update NodeJS to 8.17.0 ([#16043](https://github.com/RocketChat/Rocket.Chat/pull/16043))
+- Fix typo in Italian translation ([#15998](https://github.com/RocketChat/Rocket.Chat/pull/15998) by [@iannuzzelli](https://github.com/iannuzzelli))
+- Update Meteor to 1.8.3 ([#16037](https://github.com/RocketChat/Rocket.Chat/pull/16037))
+- Some performance improvements ([#15886](https://github.com/RocketChat/Rocket.Chat/pull/15886))
+- Fixed Grammatical Mistakes. ([#15570](https://github.com/RocketChat/Rocket.Chat/pull/15570) by [@breaking-let](https://github.com/breaking-let))
+- Upgrade limax to 2.0.0 ([#16020](https://github.com/RocketChat/Rocket.Chat/pull/16020))
+- Remove unnecessary cron starts ([#15989](https://github.com/RocketChat/Rocket.Chat/pull/15989))
+- Enable typescript lint ([#15979](https://github.com/RocketChat/Rocket.Chat/pull/15979))
+- LingoHub based on develop ([#15988](https://github.com/RocketChat/Rocket.Chat/pull/15988))
+- Fix 'How it all started' link on README ([#15962](https://github.com/RocketChat/Rocket.Chat/pull/15962) by [@zdumitru](https://github.com/zdumitru))
+- Check package-lock consistency with package.json on CI ([#15961](https://github.com/RocketChat/Rocket.Chat/pull/15961))
+- Meteor update to 1.8.2 ([#15873](https://github.com/RocketChat/Rocket.Chat/pull/15873))
+- GitHub CI ([#15918](https://github.com/RocketChat/Rocket.Chat/pull/15918))
+- Change migration number 169 <-> 170 ([#15940](https://github.com/RocketChat/Rocket.Chat/pull/15940))
+- LingoHub based on develop ([#15939](https://github.com/RocketChat/Rocket.Chat/pull/15939))
+- [CHORE] Replace findOne with findOneById methods (Omnichannel) ([#15894](https://github.com/RocketChat/Rocket.Chat/pull/15894))
+- Merge master into develop & Set version to 3.0.0-develop ([#15872](https://github.com/RocketChat/Rocket.Chat/pull/15872))
+- Regression: Update components ([#16053](https://github.com/RocketChat/Rocket.Chat/pull/16053))
+- Regression: Missing button to copy Invite links ([#16084](https://github.com/RocketChat/Rocket.Chat/pull/16084))
+
+
+
+### 👩💻👨💻 Contributors 😍
+
+- [@antkaz](https://github.com/antkaz)
+- [@ashwaniYDV](https://github.com/ashwaniYDV)
+- [@breaking-let](https://github.com/breaking-let)
+- [@iannuzzelli](https://github.com/iannuzzelli)
+- [@localguru](https://github.com/localguru)
+- [@ritwizsinha](https://github.com/ritwizsinha)
+- [@wreiske](https://github.com/wreiske)
+- [@zdumitru](https://github.com/zdumitru)
+
+### 👩💻👨💻 Core Team 🤓
+
+- [@MarcosSpessatto](https://github.com/MarcosSpessatto)
+- [@MartinSchoeler](https://github.com/MartinSchoeler)
+- [@d-gubert](https://github.com/d-gubert)
+- [@gabriellsh](https://github.com/gabriellsh)
+- [@geekgonecrazy](https://github.com/geekgonecrazy)
+- [@ggazzo](https://github.com/ggazzo)
+- [@lolimay](https://github.com/lolimay)
+- [@mariaeduardacunha](https://github.com/mariaeduardacunha)
+- [@pierre-lehnen-rc](https://github.com/pierre-lehnen-rc)
+- [@renatobecker](https://github.com/renatobecker)
+- [@rodrigok](https://github.com/rodrigok)
+- [@sampaiodiego](https://github.com/sampaiodiego)
+- [@tassoevan](https://github.com/tassoevan)
+
+# 2.3.3
+`2020-01-10 · 1 🐛 · 2 👩💻👨💻`
+
+### Engine versions
+- Node: `8.15.1`
+- NPM: `6.9.0`
+- MongoDB: ``
+
+### 🐛 Bug fixes
+
+- Add missing password field back to administration area ([#16171](https://github.com/RocketChat/Rocket.Chat/pull/16171))
+
+### 👩💻👨💻 Core Team 🤓
+
+- [@rodrigok](https://github.com/rodrigok)
+- [@sampaiodiego](https://github.com/sampaiodiego)
+
# 2.3.2
`2019-12-12 · 2 🐛 · 2 👩💻👨💻`
@@ -100,9 +372,9 @@
- Livechat transfer history messages ([#15780](https://github.com/RocketChat/Rocket.Chat/pull/15780))
- Add button to reset.css ([#15773](https://github.com/RocketChat/Rocket.Chat/pull/15773))
- Mentions before blockquote ([#15774](https://github.com/RocketChat/Rocket.Chat/pull/15774))
-- Sidebar font color was not respecting theming ([#15745](https://github.com/RocketChat/Rocket.Chat/pull/15745) by [@mariaeduardacunha](https://github.com/mariaeduardacunha))
+- Sidebar font color was not respecting theming ([#15745](https://github.com/RocketChat/Rocket.Chat/pull/15745))
- Add livechat agents into departments ([#15732](https://github.com/RocketChat/Rocket.Chat/pull/15732))
-- Changed cmsPage Style ([#15632](https://github.com/RocketChat/Rocket.Chat/pull/15632) by [@gabriellsh](https://github.com/gabriellsh))
+- Changed cmsPage Style ([#15632](https://github.com/RocketChat/Rocket.Chat/pull/15632))
- Forward Livechat UI and the related permissions ([#15718](https://github.com/RocketChat/Rocket.Chat/pull/15718))
- line-height to show entire letters ([#15581](https://github.com/RocketChat/Rocket.Chat/pull/15581) by [@nstseek](https://github.com/nstseek))
- Apply server side filters on Livechat lists ([#15717](https://github.com/RocketChat/Rocket.Chat/pull/15717))
@@ -110,7 +382,7 @@
- Livechat webhook broken when sending an image ([#15699](https://github.com/RocketChat/Rocket.Chat/pull/15699) by [@tatosjb](https://github.com/tatosjb))
- Sending messages to livechat rooms without a subscription ([#15707](https://github.com/RocketChat/Rocket.Chat/pull/15707))
- Duplicate label 'Hide Avatars' in accounts ([#15694](https://github.com/RocketChat/Rocket.Chat/pull/15694) by [@rajvaibhavdubey](https://github.com/rajvaibhavdubey))
-- Block Show_Setup_Wizard Option ([#15623](https://github.com/RocketChat/Rocket.Chat/pull/15623) by [@gabriellsh](https://github.com/gabriellsh))
+- Block Show_Setup_Wizard Option ([#15623](https://github.com/RocketChat/Rocket.Chat/pull/15623))
- Use Media Devices API to guess if a microphone is not available ([#15636](https://github.com/RocketChat/Rocket.Chat/pull/15636))
- Ignore file uploads from message box if text/plain content is being pasted ([#15631](https://github.com/RocketChat/Rocket.Chat/pull/15631))
- typo on PT-BR translation ([#15645](https://github.com/RocketChat/Rocket.Chat/pull/15645))
@@ -147,9 +419,7 @@
- [@Exordian](https://github.com/Exordian)
- [@Montel](https://github.com/Montel)
- [@antkaz](https://github.com/antkaz)
-- [@gabriellsh](https://github.com/gabriellsh)
- [@hmagarotto](https://github.com/hmagarotto)
-- [@mariaeduardacunha](https://github.com/mariaeduardacunha)
- [@mpdbl](https://github.com/mpdbl)
- [@nstseek](https://github.com/nstseek)
- [@oguhpereira](https://github.com/oguhpereira)
@@ -164,9 +434,11 @@
- [@MartinSchoeler](https://github.com/MartinSchoeler)
- [@d-gubert](https://github.com/d-gubert)
- [@engelgabriel](https://github.com/engelgabriel)
+- [@gabriellsh](https://github.com/gabriellsh)
- [@geekgonecrazy](https://github.com/geekgonecrazy)
- [@ggazzo](https://github.com/ggazzo)
- [@mar-v](https://github.com/mar-v)
+- [@mariaeduardacunha](https://github.com/mariaeduardacunha)
- [@pierre-lehnen-rc](https://github.com/pierre-lehnen-rc)
- [@renatobecker](https://github.com/renatobecker)
- [@rodrigok](https://github.com/rodrigok)
diff --git a/README.md b/README.md
index e5c9bc73ed31..54ef952d36e1 100644
--- a/README.md
+++ b/README.md
@@ -83,7 +83,7 @@ Join thousands of members worldwide 24/7 in our [community server](https://open.
[![Rocket.Chat](https://open.rocket.chat/api/v1/shield.svg?type=channel&name=Rocket.Chat&channel=dev)](https://open.rocket.chat/channel/dev) for developers needing help from the community to developing new features.
-You can also join the conversation at [Twitter](https://twitter.com/RocketChat) and [Facebook](https://www.facebook.com/RocketChatApp).
+You can also join the conversation on [Twitter](https://twitter.com/RocketChat) and [Facebook](https://www.facebook.com/RocketChatApp).
# Desktop Apps
Download the Native Cross-Platform Desktop Application at [Rocket.Chat.Electron](https://github.com/RocketChat/Rocket.Chat.Electron/releases)
@@ -138,7 +138,7 @@ The easiest way to install a ready-to-run Rocket.Chat server on a Linux machine,
[![DP deploy](https://raw.githubusercontent.com/DFabric/DPlatform-ShellCore/images/logo.png)](https://dfabric.github.io/DPlatform-ShellCore)
## IndieHosters
-Get your Rocket.Chat instance hosted in a "as a Service" style. You register and we manage it for you! (updates, backup...).
+Get your Rocket.Chat instance hosted in an "as a Service" style. You register and we manage it for you! (updates, backup...).
[![Rocket.Chat on IndieHosters](https://indie.host/signup.png)](https://indiehosters.net/shop/product/rocket-chat-21)
@@ -236,7 +236,7 @@ Run Rocket.Chat on your easy to use personal device.
# About Rocket.Chat
-Rocket.Chat is a Web Chat Server, developed in JavaScript, using the [Meteor](https://www.meteor.com/install) fullstack framework.
+Rocket.Chat is a Web Chat Server, developed in JavaScript, using the [Meteor](https://www.meteor.com/install) full stack framework.
It is a great solution for communities and companies wanting to privately host their own chat service or for developers looking forward to build and evolve their own chat platforms.
@@ -321,12 +321,12 @@ It is a great solution for communities and companies wanting to privately host t
## Roadmap
-To see an up to date view of what we have planned view our [milestones](https://github.com/RocketChat/Rocket.Chat/milestones).
+To see an up to date view of what we have planned, view our [milestones](https://github.com/RocketChat/Rocket.Chat/milestones).
## How it all started
-Read about [how it all started](https://blog.blackducksoftware.com/rocket-chat-enabling-privately-hosted-chat-services).
+Read about [how it all started](https://www.synopsys.com/blogs/software-security/rocket-chat-privately-hosted-chat-services/).
## Awards
[![InfoWorld Bossie Awards 2016 - Best Open Source Applications](https://raw.githubusercontent.com/Sing-Li/bbug/master/images/bossie.png)](http://www.infoworld.com/article/3122000/open-source-tools/bossie-awards-2016-the-best-open-source-applications.html#slide4)
@@ -352,7 +352,7 @@ Please use the [Stack Overflow TAG](http://stackoverflow.com/questions/tagged/ro
#### Hubot
The docker image is ready.
-Everyone can start hacking the adapter code, or launch his/her own bot within a few minutes now.
+Everyone can start hacking the adapter code or launch his/her own bot within a few minutes now.
Please head over to the [Hubot Integration Project](https://github.com/RocketChat/hubot-rocketchat) for more information.
@@ -393,7 +393,7 @@ meteor npm install
meteor npm start
```
-In order to debug the server part use [meteor debugging](https://docs.meteor.com/commandline.html#meteordebug). You should use Chrome for best debugging experience:
+To debug the server part, use [meteor debugging](https://docs.meteor.com/commandline.html#meteordebug). You should use Chrome for best debugging experience:
```sh
meteor debug
@@ -416,7 +416,7 @@ If you want to help, send an email to support at rocket.chat to be invited to th
## How to Contribute
-Already a JavaScript developer? Familiar with Meteor? [Pick an issue](https://github.com/RocketChat/Rocket.Chat/labels/contrib%3A%20easy), push a PR and instantly become a member of Rocket.Chat's international contributors community. For more information, check out our [Contributing Guide](.github/CONTRIBUTING.md) and our [Official Documentation for Contributors](https://rocket.chat/docs/contributing/).
+Already a JavaScript developer? Familiar with Meteor? [Pick an issue](https://github.com/RocketChat/Rocket.Chat/labels/contrib%3A%20easy), push a PR and instantly become a member of Rocket.Chat's international contributors' community. For more information, check out our [Contributing Guide](.github/CONTRIBUTING.md) and our [Official Documentation for Contributors](https://rocket.chat/docs/contributing/).
A lot of work has already gone into Rocket.Chat, but we have much bigger plans for it!
@@ -434,7 +434,7 @@ Thanks to our core team
[Marcelo Schmidt](https://github.com/marceloschmidt),
[Rodrigo Nascimento](https://github.com/rodrigok),
[Sing Li](https://github.com/Sing-Li),
-and to hundreds of awesome [contributors](https://github.com/RocketChat/Rocket.Chat/graphs/contributors).
+and hundreds of awesome [contributors](https://github.com/RocketChat/Rocket.Chat/graphs/contributors).
![JoyPixels](https://i.imgur.com/OrhYvLe.png)
diff --git a/app/api/server/api.js b/app/api/server/api.js
index 22e7e8c26d92..dd4125e36643 100644
--- a/app/api/server/api.js
+++ b/app/api/server/api.js
@@ -1,4 +1,5 @@
import { Meteor } from 'meteor/meteor';
+import { Random } from 'meteor/random';
import { DDPCommon } from 'meteor/ddp-common';
import { DDP } from 'meteor/ddp';
import { Accounts } from 'meteor/accounts-base';
@@ -312,6 +313,13 @@ export class APIClass extends Restivus {
route: `${ this.request.route }${ this.request.method.toLowerCase() }`,
};
let result;
+
+ const connection = {
+ id: Random.id(),
+ close() {},
+ token: this.token,
+ };
+
try {
api.enforceRateLimit(objectForRateLimitMatch, this.request, this.response);
@@ -321,7 +329,18 @@ export class APIClass extends Restivus {
});
}
- result = originalAction.apply(this);
+ const invocation = new DDPCommon.MethodInvocation({
+ connection,
+ isSimulation: false,
+ userId: this.userId,
+ });
+
+ Accounts._accountData[connection.id] = {
+ connection,
+ };
+ Accounts._setAccountData(connection.id, 'loginToken', this.token);
+
+ result = DDP._CurrentInvocation.withValue(invocation, () => originalAction.apply(this));
} catch (e) {
logger.debug(`${ method } ${ route } threw an error:`, e.stack);
@@ -331,6 +350,8 @@ export class APIClass extends Restivus {
}[e.error] || 'failure';
result = API.v1[apiMethod](e.message, e.error);
+ } finally {
+ delete Accounts._accountData[connection.id];
}
result = result || API.v1.success();
@@ -545,6 +566,8 @@ const getUserAuth = function _getUserAuth(...args) {
token = Accounts._hashLoginToken(this.request.headers['x-auth-token']);
}
+ this.token = token;
+
return {
userId: this.request.headers['x-user-id'],
token,
diff --git a/app/api/server/index.js b/app/api/server/index.js
index a45220f00a0f..be4ade59e8cf 100644
--- a/app/api/server/index.js
+++ b/app/api/server/index.js
@@ -20,6 +20,7 @@ import './v1/emoji-custom';
import './v1/groups';
import './v1/im';
import './v1/integrations';
+import './v1/invites';
import './v1/import';
import './v1/misc';
import './v1/permissions';
@@ -32,5 +33,9 @@ import './v1/subscriptions';
import './v1/users';
import './v1/video-conference';
import './v1/autotranslate';
+import './v1/webdav';
+import './v1/oauthapps';
+import './v1/custom-sounds';
+import './v1/custom-user-status';
export { API, APIClass, defaultRateLimiterOptions } from './api';
diff --git a/app/api/server/lib/custom-sounds.js b/app/api/server/lib/custom-sounds.js
new file mode 100644
index 000000000000..0579e99f38e7
--- /dev/null
+++ b/app/api/server/lib/custom-sounds.js
@@ -0,0 +1,20 @@
+import { CustomSounds } from '../../../models/server/raw';
+
+export async function findCustomSounds({ query = {}, pagination: { offset, count, sort } }) {
+ const cursor = await CustomSounds.find(query, {
+ sort: sort || { name: 1 },
+ skip: offset,
+ limit: count,
+ });
+
+ const total = await cursor.count();
+
+ const sounds = await cursor.toArray();
+
+ return {
+ sounds,
+ count: sounds.length,
+ offset,
+ total,
+ };
+}
diff --git a/app/api/server/lib/custom-user-status.js b/app/api/server/lib/custom-user-status.js
new file mode 100644
index 000000000000..6108af3c6a72
--- /dev/null
+++ b/app/api/server/lib/custom-user-status.js
@@ -0,0 +1,20 @@
+import { CustomUserStatus } from '../../../models/server/raw';
+
+export async function findCustomUserStatus({ query = {}, pagination: { offset, count, sort } }) {
+ const cursor = await CustomUserStatus.find(query, {
+ sort: sort || { name: 1 },
+ skip: offset,
+ limit: count,
+ });
+
+ const total = await cursor.count();
+
+ const statuses = await cursor.toArray();
+
+ return {
+ statuses,
+ count: statuses.length,
+ offset,
+ total,
+ };
+}
diff --git a/app/api/server/lib/emoji-custom.js b/app/api/server/lib/emoji-custom.js
new file mode 100644
index 000000000000..1d7dde270664
--- /dev/null
+++ b/app/api/server/lib/emoji-custom.js
@@ -0,0 +1,20 @@
+import { EmojiCustom } from '../../../models/server/raw';
+
+export async function findEmojisCustom({ query = {}, pagination: { offset, count, sort } }) {
+ const cursor = EmojiCustom.find(query, {
+ sort: sort || { name: 1 },
+ skip: offset,
+ limit: count,
+ });
+
+ const total = await cursor.count();
+
+ const emojis = await cursor.toArray();
+
+ return {
+ emojis,
+ count: emojis.length,
+ offset,
+ total,
+ };
+}
diff --git a/app/api/server/lib/integrations.js b/app/api/server/lib/integrations.js
new file mode 100644
index 000000000000..55db33a636a5
--- /dev/null
+++ b/app/api/server/lib/integrations.js
@@ -0,0 +1,27 @@
+import { Integrations } from '../../../models/server/raw';
+import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
+
+const hasIntegrationsPermission = async (userId, integration) => {
+ const type = integration.type === 'webhook-incoming' ? 'incoming' : 'outgoing';
+
+ if (await hasPermissionAsync(userId, `manage-${ type }-integrations`)) {
+ return true;
+ }
+
+ if (userId === integration._createdBy._id) {
+ return hasPermissionAsync(userId, `manage-own-${ type }-integrations`);
+ }
+
+ return false;
+};
+
+export const findOneIntegration = async ({ userId, integrationId, createdBy }) => {
+ const integration = await Integrations.findOneByIdAndCreatedByIfExists({ _id: integrationId, createdBy });
+ if (!integration) {
+ throw new Error('The integration does not exists.');
+ }
+ if (!await hasIntegrationsPermission(userId, integration)) {
+ throw new Error('not-authorized');
+ }
+ return integration;
+};
diff --git a/app/api/server/lib/messages.js b/app/api/server/lib/messages.js
index 9fdd48b33e5b..18b0b71ca176 100644
--- a/app/api/server/lib/messages.js
+++ b/app/api/server/lib/messages.js
@@ -115,3 +115,28 @@ export async function findSnippetedMessages({ uid, roomId, pagination: { offset,
total,
};
}
+
+export async function findDiscussionsFromRoom({ uid, roomId, pagination: { offset, count, sort } }) {
+ const room = await Rooms.findOneById(roomId);
+
+ if (!await canAccessRoomAsync(room, { _id: uid })) {
+ throw new Error('error-not-allowed');
+ }
+
+ const cursor = Messages.findDiscussionsByRoom(roomId, {
+ sort: sort || { ts: -1 },
+ skip: offset,
+ limit: count,
+ });
+
+ const total = await cursor.count();
+
+ const messages = await cursor.toArray();
+
+ return {
+ messages,
+ count: messages.length,
+ offset,
+ total,
+ };
+}
diff --git a/app/api/server/lib/oauthApps.js b/app/api/server/lib/oauthApps.js
new file mode 100644
index 000000000000..f1312fc7101b
--- /dev/null
+++ b/app/api/server/lib/oauthApps.js
@@ -0,0 +1,13 @@
+import { OAuthApps } from '../../../models/server/raw';
+import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
+
+export async function findOAuthApps({ uid }) {
+ if (!await hasPermissionAsync(uid, 'manage-oauth-apps')) {
+ throw new Error('error-not-allowed');
+ }
+ return OAuthApps.find().toArray();
+}
+
+export async function findOneAuthApp({ clientId, appId }) {
+ return OAuthApps.findOneAuthAppByIdOrClientId({ clientId, appId });
+}
diff --git a/app/api/server/lib/rooms.js b/app/api/server/lib/rooms.js
new file mode 100644
index 000000000000..a0c371d1f59d
--- /dev/null
+++ b/app/api/server/lib/rooms.js
@@ -0,0 +1,77 @@
+import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
+import { Rooms } from '../../../models/server/raw';
+
+export async function findAdminRooms({ uid, filter, types = [], pagination: { offset, count, sort } }) {
+ if (!await hasPermissionAsync(uid, 'view-room-administration')) {
+ throw new Error('error-not-authorized');
+ }
+ const fields = {
+ prid: 1,
+ fname: 1,
+ name: 1,
+ t: 1,
+ cl: 1,
+ u: 1,
+ usernames: 1,
+ usersCount: 1,
+ muted: 1,
+ unmuted: 1,
+ ro: 1,
+ default: 1,
+ topic: 1,
+ msgs: 1,
+ archived: 1,
+ tokenpass: 1,
+ };
+
+ const name = filter && filter.trim();
+ const discussion = types && types.includes('discussions');
+ const showTypes = Array.isArray(types) ? types.filter((type) => type !== 'discussions') : [];
+ const options = {
+ fields,
+ sort: sort || { default: -1, name: 1 },
+ skip: offset,
+ limit: count,
+ };
+
+ let cursor = Rooms.findByNameContaining(name, discussion, options);
+
+ if (name && showTypes.length) {
+ cursor = Rooms.findByNameContainingAndTypes(name, showTypes, discussion, options);
+ } else if (showTypes.length) {
+ cursor = Rooms.findByTypes(showTypes, discussion, options);
+ }
+
+ const total = await cursor.count();
+
+ const rooms = await cursor.toArray();
+
+ return {
+ rooms,
+ count: rooms.length,
+ offset,
+ total,
+ };
+}
+
+export async function findChannelAndPrivateAutocomplete({ uid, selector }) {
+ if (!await hasPermissionAsync(uid, 'view-other-user-channels')) {
+ return { items: [] };
+ }
+ const options = {
+ fields: {
+ _id: 1,
+ name: 1,
+ },
+ limit: 10,
+ sort: {
+ name: 1,
+ },
+ };
+
+ const rooms = await Rooms.findChannelAndPrivateByNameStarting(selector.name, options).toArray();
+
+ return {
+ items: rooms,
+ };
+}
diff --git a/app/api/server/lib/users.js b/app/api/server/lib/users.js
new file mode 100644
index 000000000000..0742c9feab7d
--- /dev/null
+++ b/app/api/server/lib/users.js
@@ -0,0 +1,27 @@
+import { Users } from '../../../models/server/raw';
+import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
+
+export async function findUsersToAutocomplete({ uid, selector }) {
+ if (!await hasPermissionAsync(uid, 'view-outside-room')) {
+ return { items: [] };
+ }
+ const exceptions = selector.exceptions || [];
+ const conditions = selector.conditions || {};
+ const options = {
+ fields: {
+ name: 1,
+ username: 1,
+ status: 1,
+ },
+ sort: {
+ username: 1,
+ },
+ limit: 10,
+ };
+
+ const users = await Users.findActiveByUsernameOrNameRegexWithExceptionsAndConditions(selector.term, exceptions, conditions, options).toArray();
+
+ return {
+ items: users,
+ };
+}
diff --git a/app/api/server/lib/webdav.js b/app/api/server/lib/webdav.js
new file mode 100644
index 000000000000..cf5a3c8ea8f1
--- /dev/null
+++ b/app/api/server/lib/webdav.js
@@ -0,0 +1,14 @@
+import { WebdavAccounts } from '../../../models/server/raw';
+
+export async function findWebdavAccountsByUserId({ uid }) {
+ return {
+ accounts: await WebdavAccounts.findWithUserId(uid, {
+ fields: {
+ _id: 1,
+ username: 1,
+ server_url: 1,
+ name: 1,
+ },
+ }).toArray(),
+ };
+}
diff --git a/app/api/server/v1/chat.js b/app/api/server/v1/chat.js
index 4d1610a79d94..8e5ac669d229 100644
--- a/app/api/server/v1/chat.js
+++ b/app/api/server/v1/chat.js
@@ -9,7 +9,7 @@ import { API } from '../api';
import Rooms from '../../../models/server/models/Rooms';
import Users from '../../../models/server/models/Users';
import { settings } from '../../../settings';
-import { findMentionedMessages, findStarredMessages, findSnippetedMessageById, findSnippetedMessages } from '../lib/messages';
+import { findMentionedMessages, findStarredMessages, findSnippetedMessageById, findSnippetedMessages, findDiscussionsFromRoom } from '../lib/messages';
API.v1.addRoute('chat.delete', { authRequired: true }, {
post() {
@@ -680,3 +680,25 @@ API.v1.addRoute('chat.getSnippetedMessages', { authRequired: true }, {
return API.v1.success(messages);
},
});
+
+API.v1.addRoute('chat.getDiscussions', { 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(findDiscussionsFromRoom({
+ uid: this.userId,
+ roomId,
+ pagination: {
+ offset,
+ count,
+ sort,
+ },
+ }));
+ return API.v1.success(messages);
+ },
+});
diff --git a/app/api/server/v1/custom-sounds.js b/app/api/server/v1/custom-sounds.js
new file mode 100644
index 000000000000..76197b6cbaeb
--- /dev/null
+++ b/app/api/server/v1/custom-sounds.js
@@ -0,0 +1,18 @@
+import { API } from '../api';
+import { findCustomSounds } from '../lib/custom-sounds';
+
+API.v1.addRoute('custom-sounds.list', { authRequired: true }, {
+ get() {
+ const { offset, count } = this.getPaginationItems();
+ const { sort, query } = this.parseJsonQuery();
+
+ return API.v1.success(Promise.await(findCustomSounds({
+ query,
+ pagination: {
+ offset,
+ count,
+ sort,
+ },
+ })));
+ },
+});
diff --git a/app/api/server/v1/custom-user-status.js b/app/api/server/v1/custom-user-status.js
new file mode 100644
index 000000000000..14764be6248f
--- /dev/null
+++ b/app/api/server/v1/custom-user-status.js
@@ -0,0 +1,18 @@
+import { API } from '../api';
+import { findCustomUserStatus } from '../lib/custom-user-status';
+
+API.v1.addRoute('custom-user-status.list', { authRequired: true }, {
+ get() {
+ const { offset, count } = this.getPaginationItems();
+ const { sort, query } = this.parseJsonQuery();
+
+ return API.v1.success(Promise.await(findCustomUserStatus({
+ query,
+ pagination: {
+ offset,
+ count,
+ sort,
+ },
+ })));
+ },
+});
diff --git a/app/api/server/v1/emoji-custom.js b/app/api/server/v1/emoji-custom.js
index 15b4035dd2be..249331a3e832 100644
--- a/app/api/server/v1/emoji-custom.js
+++ b/app/api/server/v1/emoji-custom.js
@@ -3,6 +3,7 @@ import Busboy from 'busboy';
import { EmojiCustom } from '../../../models';
import { API } from '../api';
+import { findEmojisCustom } from '../lib/emoji-custom';
// DEPRECATED
// Will be removed after v3.0.0
@@ -51,6 +52,22 @@ API.v1.addRoute('emoji-custom.list', { authRequired: true }, {
},
});
+API.v1.addRoute('emoji-custom.all', { authRequired: true }, {
+ get() {
+ const { offset, count } = this.getPaginationItems();
+ const { sort, query } = this.parseJsonQuery();
+
+ return API.v1.success(Promise.await(findEmojisCustom({
+ query,
+ pagination: {
+ offset,
+ count,
+ sort,
+ },
+ })));
+ },
+});
+
API.v1.addRoute('emoji-custom.create', { authRequired: true }, {
post() {
Meteor.runAsUser(this.userId, () => {
diff --git a/app/api/server/v1/integrations.js b/app/api/server/v1/integrations.js
index a5d7d9ec2b41..8c71129a41e1 100644
--- a/app/api/server/v1/integrations.js
+++ b/app/api/server/v1/integrations.js
@@ -5,6 +5,7 @@ import { hasAtLeastOnePermission } from '../../../authorization/server';
import { IntegrationHistory, Integrations } from '../../../models';
import { API } from '../api';
import { mountIntegrationHistoryQueryBasedOnPermissions, mountIntegrationQueryBasedOnPermissions } from '../../../integrations/server/lib/mountQueriesBasedOnPermission';
+import { findOneIntegration } from '../lib/integrations';
API.v1.addRoute('integrations.create', { authRequired: true }, {
post() {
@@ -172,3 +173,20 @@ API.v1.addRoute('integrations.remove', { authRequired: true }, {
}
},
});
+
+API.v1.addRoute('integrations.get', { authRequired: true }, {
+ get() {
+ const { integrationId, createdBy } = this.queryParams;
+ if (!integrationId) {
+ return API.v1.failure('The query parameter "integrationId" is required.');
+ }
+
+ return API.v1.success({
+ integration: Promise.await(findOneIntegration({
+ userId: this.userId,
+ integrationId,
+ createdBy,
+ })),
+ });
+ },
+});
diff --git a/app/api/server/v1/invites.js b/app/api/server/v1/invites.js
new file mode 100644
index 000000000000..513f99f7808e
--- /dev/null
+++ b/app/api/server/v1/invites.js
@@ -0,0 +1,61 @@
+import { Meteor } from 'meteor/meteor';
+
+import { API } from '../api';
+import { findOrCreateInvite } from '../../../invites/server/functions/findOrCreateInvite';
+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';
+
+API.v1.addRoute('listInvites', { authRequired: true }, {
+ get() {
+ const result = listInvites(this.userId);
+ return API.v1.success(result);
+ },
+});
+
+API.v1.addRoute('findOrCreateInvite', { authRequired: true }, {
+ post() {
+ const { rid, days, maxUses } = this.bodyParams;
+ const result = findOrCreateInvite(this.userId, { rid, days, maxUses });
+
+ return API.v1.success(result);
+ },
+});
+
+API.v1.addRoute('removeInvite/:_id', { authRequired: true }, {
+ delete() {
+ const { _id } = this.urlParams;
+ const result = removeInvite(this.userId, { _id });
+
+ return API.v1.success(result);
+ },
+});
+
+API.v1.addRoute('useInviteToken', { authRequired: true }, {
+ post() {
+ const { token } = this.bodyParams;
+ const result = useInviteToken(this.userId, token);
+
+ return API.v1.success(result);
+ },
+});
+
+API.v1.addRoute('validateInviteToken', { authRequired: false }, {
+ post() {
+ const { token } = this.bodyParams;
+
+ if (!token) {
+ throw new Meteor.Error('error-invalid-token', 'The invite token is invalid.', { method: 'validateInviteToken', field: 'token' });
+ }
+
+ let valid = true;
+ try {
+ validateInviteToken(token);
+ } catch (e) {
+ valid = false;
+ }
+
+ return API.v1.success({ valid });
+ },
+});
diff --git a/app/api/server/v1/misc.js b/app/api/server/v1/misc.js
index 51892359ec20..258cdd9a70c3 100644
--- a/app/api/server/v1/misc.js
+++ b/app/api/server/v1/misc.js
@@ -3,13 +3,14 @@ import { check } from 'meteor/check';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';
import s from 'underscore.string';
-import { hasRole } from '../../../authorization';
-import { Info } from '../../../utils';
-import { Users } from '../../../models';
-import { settings } from '../../../settings';
+import { hasRole, hasPermission } from '../../../authorization/server';
+import { Info } from '../../../utils/server';
+import { Users } from '../../../models/server';
+import { settings } from '../../../settings/server';
import { API } from '../api';
import { getDefaultUserFields } from '../../../utils/server/functions/getDefaultUserFields';
import { getURL } from '../../../utils/lib/getURL';
+import { StdOut } from '../../../logger/server/publish';
// DEPRECATED
@@ -162,7 +163,7 @@ API.v1.addRoute('spotlight', { authRequired: true }, {
const { query } = this.queryParams;
const result = Meteor.runAsUser(this.userId, () =>
- Meteor.call('spotlight', query)
+ Meteor.call('spotlight', query),
);
return API.v1.success(result);
@@ -202,3 +203,12 @@ API.v1.addRoute('directory', { authRequired: true }, {
});
},
});
+
+API.v1.addRoute('stdout.queue', { authRequired: true }, {
+ get() {
+ if (!hasPermission(this.userId, 'view-logs')) {
+ return API.v1.unauthorized();
+ }
+ return API.v1.success({ queue: StdOut.queue });
+ },
+});
diff --git a/app/api/server/v1/oauthapps.js b/app/api/server/v1/oauthapps.js
new file mode 100644
index 000000000000..9cc40c33a59c
--- /dev/null
+++ b/app/api/server/v1/oauthapps.js
@@ -0,0 +1,23 @@
+import { API } from '../api';
+import { findOAuthApps, findOneAuthApp } from '../lib/oauthApps';
+
+API.v1.addRoute('oauth-apps.list', { authRequired: true }, {
+ get() {
+ return API.v1.success({
+ oauthApps: Promise.await(findOAuthApps({ uid: this.userId })),
+ });
+ },
+});
+
+API.v1.addRoute('oauth-apps.get', { authRequired: true }, {
+ get() {
+ const { clientId, appId } = this.queryParams;
+ if (!clientId && !appId) {
+ return API.v1.failure('At least one of the query parameters "clientId" or "appId" is required.');
+ }
+
+ return API.v1.success({
+ oauthApp: Promise.await(findOneAuthApp({ clientId, appId })),
+ });
+ },
+});
diff --git a/app/api/server/v1/rooms.js b/app/api/server/v1/rooms.js
index 92225c64fee0..85924d77d27f 100644
--- a/app/api/server/v1/rooms.js
+++ b/app/api/server/v1/rooms.js
@@ -4,6 +4,7 @@ import Busboy from 'busboy';
import { FileUpload } from '../../../file-upload';
import { Rooms, Messages } from '../../../models';
import { API } from '../api';
+import { findAdminRooms, findChannelAndPrivateAutocomplete } from '../lib/rooms';
function findRoomByIdOrName({ params, checkedArchived = true }) {
if ((!params.roomId || !params.roomId.trim()) && (!params.roomName || !params.roomName.trim())) {
@@ -134,8 +135,8 @@ API.v1.addRoute('rooms.saveNotification', { authRequired: true }, {
const saveNotifications = (notifications, roomId) => {
Object.keys(notifications).forEach((notificationKey) =>
Meteor.runAsUser(this.userId, () =>
- Meteor.call('saveNotificationSettings', roomId, notificationKey, notifications[notificationKey])
- )
+ Meteor.call('saveNotificationSettings', roomId, notificationKey, notifications[notificationKey]),
+ ),
);
};
const { roomId, notifications } = this.bodyParams;
@@ -274,3 +275,36 @@ API.v1.addRoute('rooms.getDiscussions', { authRequired: true }, {
});
},
});
+
+API.v1.addRoute('rooms.adminRooms', { authRequired: true }, {
+ get() {
+ const { offset, count } = this.getPaginationItems();
+ const { sort } = this.parseJsonQuery();
+ const { types, filter } = this.requestParams();
+
+ return API.v1.success(Promise.await(findAdminRooms({
+ uid: this.userId,
+ filter,
+ types,
+ pagination: {
+ offset,
+ count,
+ sort,
+ },
+ })));
+ },
+});
+
+API.v1.addRoute('rooms.autocomplete.channelAndPrivate', { authRequired: true }, {
+ get() {
+ const { selector } = this.queryParams;
+ if (!selector) {
+ return API.v1.failure('The \'selector\' param is required');
+ }
+
+ return API.v1.success(Promise.await(findChannelAndPrivateAutocomplete({
+ uid: this.userId,
+ selector: JSON.parse(selector),
+ })));
+ },
+});
diff --git a/app/api/server/v1/subscriptions.js b/app/api/server/v1/subscriptions.js
index 8ffa8711a335..236089ad1d62 100644
--- a/app/api/server/v1/subscriptions.js
+++ b/app/api/server/v1/subscriptions.js
@@ -62,7 +62,7 @@ API.v1.addRoute('subscriptions.read', { authRequired: true }, {
});
Meteor.runAsUser(this.userId, () =>
- Meteor.call('readMessages', this.bodyParams.rid)
+ Meteor.call('readMessages', this.bodyParams.rid),
);
return API.v1.success();
@@ -77,7 +77,7 @@ API.v1.addRoute('subscriptions.unread', { authRequired: true }, {
}
Meteor.runAsUser(this.userId, () =>
- Meteor.call('unreadMessages', firstUnreadMessage, roomId)
+ Meteor.call('unreadMessages', firstUnreadMessage, roomId),
);
return API.v1.success();
diff --git a/app/api/server/v1/users.js b/app/api/server/v1/users.js
index ec3a3090a47b..9110f09abee9 100644
--- a/app/api/server/v1/users.js
+++ b/app/api/server/v1/users.js
@@ -3,6 +3,7 @@ import { Match, check } from 'meteor/check';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';
import _ from 'underscore';
import Busboy from 'busboy';
+import moment from 'moment';
import { Users, Subscriptions } from '../../../models/server';
import { hasPermission } from '../../../authorization';
@@ -16,9 +17,10 @@ import {
setUserAvatar,
saveCustomFields,
} from '../../../lib';
-import { getFullUserData } from '../../../lib/server/functions/getFullUserData';
+import { getFullUserData, getFullUserDataById } from '../../../lib/server/functions/getFullUserData';
import { API } from '../api';
import { setStatusText } from '../../../lib/server';
+import { findUsersToAutocomplete } from '../lib/users';
API.v1.addRoute('users.create', { authRequired: true }, {
post() {
@@ -131,6 +133,42 @@ API.v1.addRoute('users.setActiveStatus', { authRequired: true }, {
},
});
+API.v1.addRoute('users.deactivateIdle', { authRequired: true }, {
+ post() {
+ check(this.bodyParams, {
+ daysIdle: Match.Integer,
+ role: Match.Optional(String),
+ });
+
+ const { daysIdle, role } = this.bodyParams;
+
+ if (!hasPermission(this.userId, 'edit-other-user-active-status')) {
+ return API.v1.unauthorized();
+ }
+
+ const lastLoggedIn = moment(new Date()).subtract(daysIdle, 'days');
+
+ const resultCursor = Users.findActiveNotLoggedInAfterWithRole(lastLoggedIn.toDate(), role || 'user', {
+ fields: {
+ _id: 1,
+ },
+ });
+
+ // cache the count since it will be 0 after deactivation
+ const count = resultCursor.count();
+
+ Meteor.runAsUser(this.userId, () => {
+ resultCursor.forEach((user) => {
+ Meteor.call('setUserActiveStatus', user._id, false);
+ });
+ });
+
+ return API.v1.success({
+ count,
+ });
+ },
+});
+
API.v1.addRoute('users.getPresence', { authRequired: true }, {
get() {
if (this.isUserFromParams()) {
@@ -152,14 +190,18 @@ API.v1.addRoute('users.getPresence', { authRequired: true }, {
API.v1.addRoute('users.info', { authRequired: true }, {
get() {
- const { username } = this.getUserFromParams();
+ const { username, userId } = this.requestParams();
const { fields } = this.parseJsonQuery();
-
- const result = getFullUserData({
+ const params = {
userId: this.userId,
filter: username,
limit: 1,
- });
+ };
+
+ const result = userId
+ ? getFullUserDataById({ userId: this.userId, filterId: userId })
+ : getFullUserData(params);
+
if (!result || result.count() !== 1) {
return API.v1.failure(`Failed to get the user data for the userId of "${ this.userId }".`);
}
@@ -685,3 +727,27 @@ API.v1.addRoute('users.requestDataDownload', { authRequired: true }, {
});
},
});
+
+API.v1.addRoute('users.logoutOtherClients', { authRequired: true }, {
+ post() {
+ try {
+ Meteor.runAsUser(this.userId, () => API.v1.success(Meteor.call('logoutOtherClients')));
+ } catch (error) {
+ return API.v1.failure(error);
+ }
+ },
+});
+
+API.v1.addRoute('users.autocomplete', { authRequired: true }, {
+ get() {
+ const { selector } = this.queryParams;
+ if (!selector) {
+ return API.v1.failure('The \'selector\' param is required');
+ }
+
+ return API.v1.success(Promise.await(findUsersToAutocomplete({
+ uid: this.userId,
+ selector: JSON.parse(selector),
+ })));
+ },
+});
diff --git a/app/api/server/v1/webdav.js b/app/api/server/v1/webdav.js
new file mode 100644
index 000000000000..33781eef1232
--- /dev/null
+++ b/app/api/server/v1/webdav.js
@@ -0,0 +1,8 @@
+import { API } from '../api';
+import { findWebdavAccountsByUserId } from '../lib/webdav';
+
+API.v1.addRoute('webdav.getMyAccounts', { authRequired: true }, {
+ get() {
+ return API.v1.success(Promise.await(findWebdavAccountsByUserId({ uid: this.userId })));
+ },
+});
diff --git a/app/apps/client/admin/appLogs.html b/app/apps/client/admin/appLogs.html
index 47e901331c89..2200921d8f3a 100644
--- a/app/apps/client/admin/appLogs.html
+++ b/app/apps/client/admin/appLogs.html
@@ -31,6 +31,10 @@
+ {{#if log.instanceId}}
+
Instance: {{log.instanceId}}
+ {{/if}}
+
{{#each entry in log.entries}}
{{ entry.severity }}: {{ entry.timestamp }} (Caller: {{ entry.caller }})
diff --git a/app/apps/server/bridges/commands.js b/app/apps/server/bridges/commands.js
index 9eefe1906117..aab50a25bc29 100644
--- a/app/apps/server/bridges/commands.js
+++ b/app/apps/server/bridges/commands.js
@@ -170,7 +170,7 @@ export class AppCommandsBridge {
Object.freeze(user),
Object.freeze(room),
Object.freeze(params),
- threadId
+ threadId,
);
return Promise.await(this.orch.getManager().getCommandManager().getPreviews(command, context));
}
@@ -185,7 +185,7 @@ export class AppCommandsBridge {
Object.freeze(user),
Object.freeze(room),
Object.freeze(params),
- threadId
+ threadId,
);
Promise.await(this.orch.getManager().getCommandManager().executePreview(command, preview, context));
}
diff --git a/app/apps/server/bridges/listeners.js b/app/apps/server/bridges/listeners.js
index 26f0b7163089..01c039d62e64 100644
--- a/app/apps/server/bridges/listeners.js
+++ b/app/apps/server/bridges/listeners.js
@@ -36,4 +36,14 @@ export class AppListenerBridge {
// this.orch.debugLog(e.stack);
// }
}
+
+ async livechatEvent(inte, room) {
+ const rm = this.orch.getConverters().get('rooms').convertRoom(room);
+ const result = await this.orch.getManager().getListenerManager().executeListener(inte, rm);
+
+ if (typeof result === 'boolean') {
+ return result;
+ }
+ return this.orch.getConverters().get('rooms').convertAppRoom(result);
+ }
}
diff --git a/app/apps/server/bridges/livechat.js b/app/apps/server/bridges/livechat.js
index edd3aabf00be..5437246a0333 100644
--- a/app/apps/server/bridges/livechat.js
+++ b/app/apps/server/bridges/livechat.js
@@ -2,8 +2,9 @@ import { Random } from 'meteor/random';
import { getRoom } from '../../../livechat/server/api/lib/livechat';
import { Livechat } from '../../../livechat/server/lib/Livechat';
-import Rooms from '../../../models/server/models/Rooms';
+import LivechatRooms from '../../../models/server/models/LivechatRooms';
import LivechatVisitors from '../../../models/server/models/LivechatVisitors';
+import LivechatDepartment from '../../../models/server/models/LivechatDepartment';
import Users from '../../../models/server/models/Users';
export class AppLivechatBridge {
@@ -11,6 +12,10 @@ export class AppLivechatBridge {
this.orch = orch;
}
+ isOnline() {
+ return Livechat.online();
+ }
+
async createMessage(message, appId) {
this.orch.debugLog(`The App ${ appId } is creating a new message.`);
@@ -48,14 +53,19 @@ export class AppLivechatBridge {
async createRoom(visitor, agent, appId) {
this.orch.debugLog(`The App ${ appId } is creating a livechat room.`);
- const agentUser = Users.findOneById(agent.id);
- agentUser.agentId = agentUser._id;
+ let agentRoom;
+ if (agent && agent.id) {
+ const user = Users.getAgentInfo(agent.id);
+ agentRoom = Object.assign({}, { agentId: user._id });
+ }
- return this.orch.getConverters().get('rooms').convertRoom(getRoom({
+ const result = await getRoom({
guest: this.orch.getConverters().get('visitors').convertAppVisitor(visitor),
- agent: agentUser,
+ agent: agentRoom,
rid: Random.id(),
- }).room);
+ });
+
+ return this.orch.getConverters().get('rooms').convertRoom(result.room);
}
async closeRoom(room, comment, appId) {
@@ -78,9 +88,9 @@ export class AppLivechatBridge {
let result;
if (departmentId) {
- result = Rooms.findOpenByVisitorTokenAndDepartmentId(visitor.token, departmentId).fetch();
+ result = LivechatRooms.findOpenByVisitorTokenAndDepartmentId(visitor.token, departmentId).fetch();
} else {
- result = Rooms.findOpenByVisitorToken(visitor.token).fetch();
+ result = LivechatRooms.findOpenByVisitorToken(visitor.token).fetch();
}
return result.map((room) => this.orch.getConverters().get('rooms').convertRoom(room));
@@ -130,6 +140,40 @@ export class AppLivechatBridge {
async findVisitors(query, appId) {
this.orch.debugLog(`The App ${ appId } is looking for livechat visitors.`);
+ if (this.orch.isDebugging()) {
+ console.warn('The method AppLivechatBridge.findVisitors is deprecated. Please consider using its alternatives');
+ }
+
return LivechatVisitors.find(query).fetch().map((visitor) => this.orch.getConverters().get('visitors').convertVisitor(visitor));
}
+
+ async findVisitorById(id, appId) {
+ this.orch.debugLog(`The App ${ appId } is looking for livechat visitors.`);
+
+ return this.orch.getConverters().get('visitors').convertById(id);
+ }
+
+ async findVisitorByEmail(email, appId) {
+ this.orch.debugLog(`The App ${ appId } is looking for livechat visitors.`);
+
+ return this.orch.getConverters().get('visitors').convertVisitor(LivechatVisitors.findOneGuestByEmailAddress(email));
+ }
+
+ async findVisitorByToken(token, appId) {
+ this.orch.debugLog(`The App ${ appId } is looking for livechat visitors.`);
+
+ return this.orch.getConverters().get('visitors').convertVisitor(LivechatVisitors.getVisitorByToken(token));
+ }
+
+ async findVisitorByPhoneNumber(phoneNumber, appId) {
+ this.orch.debugLog(`The App ${ appId } is looking for livechat visitors.`);
+
+ return this.orch.getConverters().get('visitors').convertVisitor(LivechatVisitors.findOneVisitorByPhone(phoneNumber));
+ }
+
+ async findDepartmentByIdOrName(value, appId) {
+ this.orch.debugLog(`The App ${ appId } is looking for livechat departments.`);
+
+ return this.orch.getConverters().get('departments').convertDepartment(LivechatDepartment.findOneByIdOrName(value));
+ }
}
diff --git a/app/apps/server/bridges/messages.js b/app/apps/server/bridges/messages.js
index 062efcd64b8a..1071117d180e 100644
--- a/app/apps/server/bridges/messages.js
+++ b/app/apps/server/bridges/messages.js
@@ -1,9 +1,9 @@
-import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import { Messages, Users, Subscriptions } from '../../../models';
import { Notifications } from '../../../notifications';
import { updateMessage } from '../../../lib/server/functions/updateMessage';
+import { executeSendMessage } from '../../../lib/server/methods/sendMessage';
export class AppMessageBridge {
constructor(orch) {
@@ -13,13 +13,11 @@ export class AppMessageBridge {
async create(message, appId) {
this.orch.debugLog(`The App ${ appId } is creating a new message.`);
- let msg = this.orch.getConverters().get('messages').convertAppMessage(message);
+ const convertedMessage = this.orch.getConverters().get('messages').convertAppMessage(message);
- Meteor.runAsUser(msg.u._id, () => {
- msg = Meteor.call('sendMessage', msg);
- });
+ const sentMessage = executeSendMessage(convertedMessage.u._id, convertedMessage);
- return msg._id;
+ return sentMessage._id;
}
async getById(messageId, appId) {
@@ -77,7 +75,7 @@ export class AppMessageBridge {
Users.findByIds(users, { fields: { _id: 1 } })
.fetch()
.forEach(({ _id }) =>
- Notifications.notifyUser(_id, 'message', rmsg)
+ Notifications.notifyUser(_id, 'message', rmsg),
);
}
}
diff --git a/app/apps/server/converters/messages.js b/app/apps/server/converters/messages.js
index aaac047a2ef2..9d7afc428941 100644
--- a/app/apps/server/converters/messages.js
+++ b/app/apps/server/converters/messages.js
@@ -135,6 +135,7 @@ export class AppMessagesConverter {
attachments,
reactions: message.reactions,
parseUrls: message.parseUrls,
+ token: message.token,
};
return Object.assign(newMessage, message._unmappedProperties_);
diff --git a/app/apps/server/converters/visitors.js b/app/apps/server/converters/visitors.js
index 66ab62158249..55151577b3fb 100644
--- a/app/apps/server/converters/visitors.js
+++ b/app/apps/server/converters/visitors.js
@@ -48,7 +48,8 @@ export class AppVisitorsConverter {
name: visitor.name,
token: visitor.token,
phone: visitor.phone,
- visitorEmails: visitor.visitorEmails,
+ ...visitor.visitorEmails && { visitorEmails: visitor.visitorEmails },
+ ...visitor.department && { department: visitor.department },
};
return Object.assign(newVisitor, visitor._unmappedProperties_);
diff --git a/app/apps/server/cron.js b/app/apps/server/cron.js
index 0e51170734d9..3201612ea6b6 100644
--- a/app/apps/server/cron.js
+++ b/app/apps/server/cron.js
@@ -93,7 +93,7 @@ export const appsUpdateMarketplaceInfo = Meteor.bindEnvironment(function _appsUp
Promise.await(
Apps.updateAppsMarketplaceInfo(data)
.then(notifyAdminsAboutInvalidApps)
- .then(notifyAdminsAboutRenewedApps)
+ .then(notifyAdminsAboutRenewedApps),
);
});
@@ -104,5 +104,3 @@ SyncedCron.add({
appsUpdateMarketplaceInfo();
},
});
-
-SyncedCron.start();
diff --git a/app/apps/server/storage/logs-storage.js b/app/apps/server/storage/logs-storage.js
index 78ef627ba599..005a69e70c8f 100644
--- a/app/apps/server/storage/logs-storage.js
+++ b/app/apps/server/storage/logs-storage.js
@@ -1,5 +1,6 @@
import { AppConsole } from '@rocket.chat/apps-engine/server/logging';
import { AppLogStorage } from '@rocket.chat/apps-engine/server/storage';
+import { InstanceStatus } from 'meteor/konecty:multiple-instances-status';
export class AppRealLogsStorage extends AppLogStorage {
constructor(model) {
@@ -25,6 +26,8 @@ export class AppRealLogsStorage extends AppLogStorage {
return new Promise((resolve, reject) => {
const item = AppConsole.toStorageEntry(appId, logger);
+ item.instanceId = InstanceStatus.id();
+
try {
const id = this.db.insert(item);
diff --git a/app/assistify/ai/client/chatpalAdoption.js b/app/assistify/ai/client/chatpalAdoption.js
deleted file mode 100644
index 8d3126eeef74..000000000000
--- a/app/assistify/ai/client/chatpalAdoption.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// import { TAPi18n } from 'meteor/tap:i18n';
-// TAPi18n.loadTranslations({
-// en: {
-// CHATPAL_ENTER_SEARCH_STRING: 'Search knowledge base',
-// },
-// de: {
-// CHATPAL_ENTER_SEARCH_STRING: 'Wissensbasis durchsuchen',
-// },
-// });
-
-// TODO: How to overwrite translations
diff --git a/app/assistify/ai/client/index.js b/app/assistify/ai/client/index.js
index 710ea45caeb5..841a5a0ae86a 100644
--- a/app/assistify/ai/client/index.js
+++ b/app/assistify/ai/client/index.js
@@ -4,7 +4,6 @@ import './tabbar.js';
import './models/MessagesExtension.js';
import '../public/stylesheets/smarti.css';
import './hooks/openAiTab.js';
-import './chatpalAdoption.js';
import './views/app/tabbar/smarti.html';
import './views/app/tabbar/smarti.js';
import './smartiLoader.js';
diff --git a/app/assistify/ai/client/tabbar.js b/app/assistify/ai/client/tabbar.js
index 621ab0aadfd0..8ef404ea25e7 100755
--- a/app/assistify/ai/client/tabbar.js
+++ b/app/assistify/ai/client/tabbar.js
@@ -1,12 +1,28 @@
+
+import { Tracker } from 'meteor/tracker';
+
import { TabBar } from '../../../ui-utils/client';
+import { settings } from '../../../settings/client';
+// always remove the TabBar button displaying information from api.ai - we never need that
TabBar.removeButton('external-search');
-TabBar.addButton({
- groups: ['channel', 'group', 'live'],
- id: 'assistify-ai',
- i18nTitle: 'Knowledge_Base',
- icon: 'lightbulb',
- template: 'AssistifySmarti',
- order: 0,
+Tracker.autorun(() => {
+ const enabled = settings.get('Assistify_AI_Enabled');
+ if (enabled) {
+ TabBar.addButton({
+ groups: ['channel', 'group', 'live'],
+ id: 'assistify-ai',
+ i18nTitle: 'Knowledge_Base',
+ icon: 'lightbulb',
+ template: 'AssistifySmarti',
+ order: 0,
+ });
+ } else {
+ try {
+ TabBar.removeButton('assistify-ai');
+ } catch (err) {
+ // may not exist, not an issue
+ }
+ }
});
diff --git a/app/assistify/ai/package.js b/app/assistify/ai/package.js
deleted file mode 100755
index 80cd05201343..000000000000
--- a/app/assistify/ai/package.js
+++ /dev/null
@@ -1,73 +0,0 @@
-// /* globals Npm */
-// Package.describe({
-// name: 'assistify:ai',
-// version: '0.2.0',
-// summary: 'Integration of artificial knowledge',
-// git: 'http://github.com/assistify/Rocket.Chat',
-// documentation: 'README.md',
-// });
-
-// function addDirectory(api, pathInPackage, environment) {
-// const _ = Npm.require('underscore');
-// const fs = Npm.require('fs');
-
-// const PACKAGE_PATH = 'packages/assistify-ai/';
-// const files = _.compact(_.map(fs.readdirSync(PACKAGE_PATH + pathInPackage), function(filename) {
-// return `${ pathInPackage }/${ filename }`;
-// }));
-// api.addFiles(files, environment);
-// }
-
-// Package.onUse(function(api) {
-// api.use(['ecmascript', 'underscore']);
-// api.use('templating', 'client');
-// api.use('meteorhacks:inject-initial'); // for provisioning of svg-icons
-
-// // Extensions to the RocketChat models
-// api.addFiles('client/models/MessagesExtension.js', 'client');
-// api.addFiles('client/models/MessagesExtension.js', 'server');
-
-// // Libraries
-// api.addFiles('server/inject.js', 'server');
-
-// // common components for client and server
-// api.addFiles('models/AssistifySmarti.js', ['client', 'server']);
-
-// // Server business logic
-// addDirectory(api, 'server/lib', 'server');
-// addDirectory(api, 'server/hooks', 'server');
-// addDirectory(api, 'server/methods', 'server');
-
-// // Smarti proxy and router
-// api.addFiles('server/SmartiProxy.js', 'server');
-// api.addFiles('server/SmartiRouter.js', 'server');
-
-// // Configuration
-// api.addFiles('config.js', 'server');
-
-// // migration scripts
-// api.addFiles('server/migrations.js', 'server');
-
-// // Client business logic
-// api.addFiles('client/tabbar.js', 'client');
-// api.addFiles('client/hooks/openAiTab.js', 'client');
-// api.addFiles('client/messageRenderer.js', 'client');
-
-// // client views
-// addDirectory(api, 'client/views/app/tabbar', 'client');
-// api.addFiles('client/smartiLoader.js', 'client');
-
-// // styling
-// api.addFiles('client/public/stylesheets/smarti.css', 'client');
-
-// // Assets
-// api.addAssets('client/public/assistify.png', 'client');
-
-// // UI artifacts which are pre-processed or packaged by the server
-// api.addAssets('client/public/icons.svg', 'server');
-
-// // i18n in Rocket.Chat-package (packages/rocketchat-i18n/i18n
-
-// api.mainModule('assistify-ai.js', 'server');
-
-// });
diff --git a/app/assistify/ai/server/index.js b/app/assistify/ai/server/index.js
index dc57d58e660c..bbe95259af67 100644
--- a/app/assistify/ai/server/index.js
+++ b/app/assistify/ai/server/index.js
@@ -12,5 +12,4 @@ import './hooks/closeLivechatKnowledgeAdapter.js';
import './lib/SmartiAdapter.js';
import './lib/AiApiAdapter.js';
import './lib/KnowledgeAdapterProvider.js';
-import './migrations.js';
import '../../migrations/server/startup/migrations.js';
diff --git a/app/assistify/ai/server/lib/SmartiAdapter.js b/app/assistify/ai/server/lib/SmartiAdapter.js
index 2e1cc7897ee9..f14db05cbd4a 100644
--- a/app/assistify/ai/server/lib/SmartiAdapter.js
+++ b/app/assistify/ai/server/lib/SmartiAdapter.js
@@ -614,7 +614,7 @@ export class SmartiAdapter {
conversationId,
}, {
upsert: true,
- }
+ },
);
}
diff --git a/app/assistify/ai/server/methods/SmartiWidgetBackend.js b/app/assistify/ai/server/methods/SmartiWidgetBackend.js
index 6f1cda903f47..6d150116ebd3 100644
--- a/app/assistify/ai/server/methods/SmartiWidgetBackend.js
+++ b/app/assistify/ai/server/methods/SmartiWidgetBackend.js
@@ -29,7 +29,7 @@ Meteor.methods({
userId(userId) {
return !hasPermission(userId, 'send-many-messages');
},
- }
+ },
)(channelId);
},
@@ -46,7 +46,7 @@ Meteor.methods({
userId(userId) {
return !hasPermission(userId, 'send-many-messages');
},
- }
+ },
)(verbs.get, `conversation/${ conversationId }/analysis`, null, null, (error) => {
// 404 is expected if no mapping exists
if (error.response && error.response.statusCode === 404) {
@@ -66,7 +66,7 @@ Meteor.methods({
userId(userId) {
return !hasPermission(userId, 'send-many-messages');
},
- }
+ },
)(roomId);
},
@@ -87,7 +87,7 @@ Meteor.methods({
userId(userId) {
return !hasPermission(userId, 'send-many-messages');
},
- }
+ },
)(verbs.get, `conversation/${ conversationId }/analysis/template/${ templateIndex }/result/${ creator }`, { start, rows });
},
@@ -113,7 +113,7 @@ Meteor.methods({
userId(userId) {
return !hasPermission(userId, 'send-many-messages');
},
- }
+ },
)(verbs.get, 'conversation/search', params);
SystemLogger.debug('SearchResult: ', JSON.stringify(searchResult, null, 2));
return searchResult;
@@ -139,7 +139,7 @@ function loadSmarti() {
userId(userId) {
return !hasPermission(userId, 'send-many-messages');
},
- }
+ },
)(verbs.get, 'plugin/v1/rocket.chat.js');
if (!script.error && script) {
// add pseudo comment in order to make the script appear in the frontend as a file. This makes it de-buggable
diff --git a/app/assistify/ai/server/migrations.js b/app/assistify/ai/server/migrations.js
deleted file mode 100644
index 81ce7c129c9d..000000000000
--- a/app/assistify/ai/server/migrations.js
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
-Up to now, there's no "DB version" stored for assistify.
-Until we've got expensive of contradicting migrations, we'll just use this file to write functions running
-on startup which migrate data - ignoring the actual version
- */
diff --git a/app/authorization/client/lib/streamer.js b/app/authorization/client/lib/streamer.js
new file mode 100644
index 000000000000..1aab5af6eb45
--- /dev/null
+++ b/app/authorization/client/lib/streamer.js
@@ -0,0 +1,3 @@
+import { Meteor } from 'meteor/meteor';
+
+export const rolesStreamer = new Meteor.Streamer('roles');
diff --git a/app/authorization/client/startup.js b/app/authorization/client/startup.js
index 3656b7d00432..99c1f06e760d 100644
--- a/app/authorization/client/startup.js
+++ b/app/authorization/client/startup.js
@@ -3,9 +3,15 @@ import { Meteor } from 'meteor/meteor';
import { hasAtLeastOnePermission } from './hasPermission';
import { CachedCollectionManager } from '../../ui-cached-collection';
import { AdminBox } from '../../ui-utils/client/lib/AdminBox';
+import { APIClient } from '../../utils/client';
+import { Roles } from '../../models/client';
+import { rolesStreamer } from './lib/streamer';
Meteor.startup(() => {
- CachedCollectionManager.onLogin(() => Meteor.subscribe('roles'));
+ CachedCollectionManager.onLogin(async () => {
+ const { roles } = await APIClient.v1.get('roles.list');
+ roles.forEach((role) => Roles.insert(role));
+ });
AdminBox.addOption({
href: 'admin-permissions',
@@ -15,4 +21,12 @@ Meteor.startup(() => {
return hasAtLeastOnePermission(['access-permissions', 'access-setting-permissions']);
},
});
+ const events = {
+ changed: (role) => {
+ delete role.type;
+ Roles.upsert({ _id: role.name }, role);
+ },
+ removed: (role) => Roles.remove({ _id: role.name }),
+ };
+ rolesStreamer.on('roles', (role) => events[role.type](role));
});
diff --git a/app/authorization/client/stylesheets/permissions.css b/app/authorization/client/stylesheets/permissions.css
index 4b7532ccb87a..1561d2ebf536 100644
--- a/app/authorization/client/stylesheets/permissions.css
+++ b/app/authorization/client/stylesheets/permissions.css
@@ -120,7 +120,3 @@
}
}
}
-
-.page-container.permissions-manager {
- overflow-y: auto !important;
-}
diff --git a/app/authorization/client/views/permissions.js b/app/authorization/client/views/permissions.js
index d03ac7d52cbb..1ad319988a8e 100644
--- a/app/authorization/client/views/permissions.js
+++ b/app/authorization/client/views/permissions.js
@@ -8,13 +8,12 @@ import { Template } from 'meteor/templating';
import { Roles } from '../../../models';
import { ChatPermissions } from '../lib/ChatPermissions';
import { hasAllPermission } from '../hasPermission';
-
-import { hasAtLeastOnePermission } from '..';
-
import { t } from '../../../utils/client';
import { SideNav } from '../../../ui-utils/client/lib/SideNav';
import { CONSTANTS } from '../../lib';
+import { hasAtLeastOnePermission } from '..';
+
Template.permissions.helpers({
tabsData() {
const {
@@ -85,7 +84,7 @@ Template.permissions.helpers({
_id: 1,
},
limit,
- }
+ },
);
},
@@ -105,7 +104,7 @@ Template.permissions.helpers({
group: 1,
section: 1,
},
- }
+ },
);
},
diff --git a/app/authorization/client/views/permissionsRole.js b/app/authorization/client/views/permissionsRole.js
index 1788e47a2dd2..4e16cd666f54 100644
--- a/app/authorization/client/views/permissionsRole.js
+++ b/app/authorization/client/views/permissionsRole.js
@@ -95,7 +95,7 @@ Template.permissionsRole.helpers({
rules: [
{
collection: 'CachedChannelList',
- subscription: 'channelAndPrivateAutocomplete',
+ endpoint: 'rooms.autocomplete.channelAndPrivate',
field: 'name',
template: Template.roomSearch,
noMatchTemplate: Template.roomSearchEmpty,
@@ -118,7 +118,7 @@ Template.permissionsRole.helpers({
rules: [
{
collection: 'CachedUserList',
- subscription: 'userAutocomplete',
+ endpoint: 'users.autocomplete',
field: 'username',
template: Template.userSearch,
noMatchTemplate: Template.userSearchEmpty,
@@ -256,8 +256,6 @@ Template.permissionsRole.onCreated(async function() {
this.searchRoom = new ReactiveVar();
this.searchUsername = new ReactiveVar();
this.usersInRole = new ReactiveVar([]);
-
- this.subscription = this.subscribe('roles', FlowRouter.getParam('name'));
});
Template.permissionsRole.onRendered(function() {
diff --git a/app/authorization/server/functions/canAccessRoom.js b/app/authorization/server/functions/canAccessRoom.js
index ab4e59b457a7..abfa3e70c631 100644
--- a/app/authorization/server/functions/canAccessRoom.js
+++ b/app/authorization/server/functions/canAccessRoom.js
@@ -18,8 +18,8 @@ export const roomAccessValidators = [
return;
}
- const subscription = await Subscriptions.findOneByRoomIdAndUserId(room._id, user._id);
- if (subscription) {
+ const exists = await Subscriptions.countByRoomIdAndUserId(room._id, user._id);
+ if (exists) {
return true;
}
},
diff --git a/app/authorization/server/functions/hasRole.js b/app/authorization/server/functions/hasRole.js
index 879aeaa01241..0159026d46fe 100644
--- a/app/authorization/server/functions/hasRole.js
+++ b/app/authorization/server/functions/hasRole.js
@@ -1,6 +1,8 @@
-import { Roles } from '../../../models';
+import { Roles } from '../../../models/server/raw';
-export const hasRole = (userId, roleNames, scope) => {
+export const hasRoleAsync = async (userId, roleNames, scope) => {
roleNames = [].concat(roleNames);
return Roles.isUserInRoles(userId, roleNames, scope);
};
+
+export const hasRole = (userId, roleNames, scope) => Promise.await(hasRoleAsync(userId, roleNames, scope));
diff --git a/app/authorization/server/lib/streamer.js b/app/authorization/server/lib/streamer.js
new file mode 100644
index 000000000000..f00103832be8
--- /dev/null
+++ b/app/authorization/server/lib/streamer.js
@@ -0,0 +1,5 @@
+import { Meteor } from 'meteor/meteor';
+
+export const rolesStreamer = new Meteor.Streamer('roles');
+rolesStreamer.allowWrite('none');
+rolesStreamer.allowRead('logged');
diff --git a/app/authorization/server/methods/deleteRole.js b/app/authorization/server/methods/deleteRole.js
index 8613e1761b0a..0b42263c23f8 100644
--- a/app/authorization/server/methods/deleteRole.js
+++ b/app/authorization/server/methods/deleteRole.js
@@ -2,6 +2,7 @@ import { Meteor } from 'meteor/meteor';
import * as Models from '../../../models/server';
import { hasPermission } from '../functions/hasPermission';
+import { rolesStreamer } from '../lib/streamer';
Meteor.methods({
'authorization:deleteRole'(roleName) {
@@ -34,7 +35,13 @@ Meteor.methods({
method: 'authorization:deleteRole',
});
}
-
- return Models.Roles.remove(role.name);
+ const removed = Models.Roles.remove(role.name);
+ if (removed) {
+ rolesStreamer.emit('roles', {
+ type: 'removed',
+ name: roleName,
+ });
+ }
+ return removed;
},
});
diff --git a/app/authorization/server/methods/saveRole.js b/app/authorization/server/methods/saveRole.js
index 5f0998e7d493..64cb3437c9df 100644
--- a/app/authorization/server/methods/saveRole.js
+++ b/app/authorization/server/methods/saveRole.js
@@ -4,6 +4,7 @@ import { Roles } from '../../../models/server';
import { settings } from '../../../settings/server';
import { Notifications } from '../../../notifications/server';
import { hasPermission } from '../functions/hasPermission';
+import { rolesStreamer } from '../lib/streamer';
Meteor.methods({
'authorization:saveRole'(roleData) {
@@ -31,7 +32,10 @@ Meteor.methods({
_id: roleData.name,
});
}
-
+ rolesStreamer.emit('roles', {
+ type: 'changed',
+ ...roleData,
+ });
return update;
},
});
diff --git a/app/authorization/server/publications/permissions/emitter.js b/app/authorization/server/publications/permissions/emitter.js
index ef958ed48502..a7062439eb46 100644
--- a/app/authorization/server/publications/permissions/emitter.js
+++ b/app/authorization/server/publications/permissions/emitter.js
@@ -25,7 +25,7 @@ Permissions.on('change', ({ clientAction, id, data, diff }) => {
Notifications.notifyLoggedInThisInstance(
'permissions-changed',
clientAction,
- data
+ data,
);
if (data.level && data.level === CONSTANTS.SETTINGS_LEVEL) {
@@ -36,7 +36,7 @@ Permissions.on('change', ({ clientAction, id, data, diff }) => {
Notifications.notifyLoggedInThisInstance(
'private-settings-changed',
'updated',
- setting
+ setting,
);
}
});
diff --git a/app/authorization/server/publications/permissions/index.js b/app/authorization/server/publications/permissions/index.js
index 8e74f7b69325..09e7ccffc6c7 100644
--- a/app/authorization/server/publications/permissions/index.js
+++ b/app/authorization/server/publications/permissions/index.js
@@ -16,7 +16,7 @@ Meteor.methods({
remove: Permissions.trashFindDeletedAfter(
updatedAt,
{},
- { fields: { _id: 1, _deletedAt: 1 } }
+ { fields: { _id: 1, _deletedAt: 1 } },
).fetch(),
};
}
diff --git a/app/authorization/server/publications/roles.js b/app/authorization/server/publications/roles.js
index 57e17673eae8..c4ca8d926eb5 100644
--- a/app/authorization/server/publications/roles.js
+++ b/app/authorization/server/publications/roles.js
@@ -4,6 +4,7 @@ import { Roles } from '../../../models';
import { clearCache } from '../functions/hasPermission';
Meteor.publish('roles', function() {
+ console.warn('The publication "roles" is deprecated and will be removed after version v3.0.0');
if (!this.userId) {
return this.ready();
}
diff --git a/app/authorization/server/startup.js b/app/authorization/server/startup.js
index ee430af1de25..3314bd586900 100644
--- a/app/authorization/server/startup.js
+++ b/app/authorization/server/startup.js
@@ -85,6 +85,7 @@ Meteor.startup(function() {
{ _id: 'view-outside-room', roles: ['admin', 'owner', 'moderator', 'user'] },
{ _id: 'view-broadcast-member-list', roles: ['admin', 'owner', 'moderator'] },
{ _id: 'call-management', roles: ['admin', 'owner', 'moderator'] },
+ { _id: 'create-invite-links', roles: ['admin', 'owner', 'moderator'] },
{ _id: 'view-l-room', roles: ['livechat-agent', 'livechat-manager', 'admin'] },
{ _id: 'view-livechat-manager', roles: ['livechat-manager', 'admin'] },
{ _id: 'view-livechat-rooms', roles: ['livechat-manager', 'admin'] },
@@ -148,6 +149,7 @@ Meteor.startup(function() {
});
return previousSettingPermissions;
};
+
const createSettingPermission = function(setting, previousSettingPermissions) {
const permissionId = getSettingPermissionId(setting._id);
const permission = {
diff --git a/app/autotranslate/server/models/Settings.js b/app/autotranslate/server/models/Settings.js
deleted file mode 100644
index 3d90ad772527..000000000000
--- a/app/autotranslate/server/models/Settings.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import { Settings } from '../../../models/server/models/Settings';
-
-Object.assign(Settings, {
- renameSetting(oldId, newId) {
- const oldSetting = Settings.findById(oldId).fetch()[0];
- if (oldSetting) {
- Settings.removeById(oldSetting._id);
-
- // there has been some problem with upsert() when changing the complete doc, so decide explicitly for insert or update
- let newSetting = Settings.findById(newId).fetch()[0];
- if (newSetting) {
- Settings.updateValueById(newId, oldSetting.value);
- } else {
- newSetting = oldSetting;
- newSetting._id = newId;
- delete newSetting.$loki;
- Settings.insert(newSetting);
- }
- }
- },
-});
diff --git a/app/autotranslate/server/msTranslate.js b/app/autotranslate/server/msTranslate.js
index a299a4a927df..4e73f106b3ee 100644
--- a/app/autotranslate/server/msTranslate.js
+++ b/app/autotranslate/server/msTranslate.js
@@ -118,7 +118,7 @@ class MsAutoTranslate extends AutoTranslate {
translations = Object.assign({}, ...targetLanguages.map((language) =>
({
[language]: result.data.map((line) => line.translations.find((translation) => translation.to === language).text).join('\n'),
- })
+ }),
));
}
} catch (e) {
@@ -160,7 +160,7 @@ class MsAutoTranslate extends AutoTranslate {
translations = Object.assign({}, ...targetLanguages.map((language) =>
({
[language]: result.data.map((line) => line.translations.find((translation) => translation.to === language).text).join('\n'),
- })
+ }),
));
}
} catch (e) {
diff --git a/app/autotranslate/server/settings.js b/app/autotranslate/server/settings.js
index 86294cb8e52b..e12e580453df 100644
--- a/app/autotranslate/server/settings.js
+++ b/app/autotranslate/server/settings.js
@@ -9,6 +9,7 @@ Meteor.startup(function() {
section: 'AutoTranslate',
public: true,
});
+
settings.add('AutoTranslate_ServiceProvider', 'google-translate', {
type: 'select',
group: 'Message',
diff --git a/app/callbacks/lib/callbacks.js b/app/callbacks/lib/callbacks.js
index efc44c0ee59d..d602e0384203 100644
--- a/app/callbacks/lib/callbacks.js
+++ b/app/callbacks/lib/callbacks.js
@@ -50,7 +50,7 @@ const createCallbackTimed = (hook, callbacks) =>
callbacks
.map(wrapCallback)
.map(handleResult)
- .reduce(pipe, identity)
+ .reduce(pipe, identity),
);
const create = (hook, cbs) =>
@@ -79,7 +79,7 @@ callbacks.add = function(
hook,
callback,
priority = callbacks.priority.MEDIUM,
- id = Random.id()
+ id = Random.id(),
) {
callbacks[hook] = getHooks(hook);
if (callbacks[hook].find((cb) => cb.id === id)) {
diff --git a/app/cas/client/cas_client.js b/app/cas/client/cas_client.js
index 7046f4d024ed..6cfa3c61d6f6 100644
--- a/app/cas/client/cas_client.js
+++ b/app/cas/client/cas_client.js
@@ -45,7 +45,7 @@ Meteor.loginWithCas = function(options, callback) {
const popup = openCenteredPopup(
loginUrl,
popup_width || 800,
- popup_height || 600
+ popup_height || 600,
);
diff --git a/app/channel-settings-mail-messages/client/views/mailMessagesInstructions.js b/app/channel-settings-mail-messages/client/views/mailMessagesInstructions.js
index 71d0345a10f6..9b8660572c95 100644
--- a/app/channel-settings-mail-messages/client/views/mailMessagesInstructions.js
+++ b/app/channel-settings-mail-messages/client/views/mailMessagesInstructions.js
@@ -3,7 +3,6 @@ import { ReactiveVar } from 'meteor/reactive-var';
import { Blaze } from 'meteor/blaze';
import { Session } from 'meteor/session';
import { Template } from 'meteor/templating';
-import { AutoComplete } from 'meteor/mizzao:autocomplete';
import { Deps } from 'meteor/deps';
import toastr from 'toastr';
@@ -11,6 +10,7 @@ import { ChatRoom } from '../../../models';
import { t, isEmail, handleError, roomTypes } from '../../../utils';
import { settings } from '../../../settings';
import resetSelection from '../resetSelection';
+import { AutoComplete } from '../../../meteor-autocomplete/client';
const filterNames = (old) => {
const reg = new RegExp(`^${ settings.get('UTF8_Names_Validation') }$`);
@@ -39,7 +39,7 @@ Template.mailMessagesInstructions.helpers({
rules: [
{
collection: 'CachedChannelList',
- subscription: 'userAutocomplete',
+ endpoint: 'users.autocomplete',
field: 'username',
template: Template.userSearch,
noMatchTemplate: Template.userSearchEmpty,
@@ -253,7 +253,7 @@ Template.mailMessagesInstructions.onCreated(function() {
rules: [
{
collection: 'UserAndRoom',
- subscription: 'userAutocomplete',
+ endpoint: 'users.autocomplete',
field: 'username',
matchAll: true,
filter,
diff --git a/app/channel-settings/client/views/channelSettings.html b/app/channel-settings/client/views/channelSettings.html
index 9ff3a5886643..9d6f3b23f757 100644
--- a/app/channel-settings/client/views/channelSettings.html
+++ b/app/channel-settings/client/views/channelSettings.html
@@ -411,10 +411,10 @@
{{> icon block="rc-header__icon"
{{/if}}
+ {{#if canLeaveRoom}}
+
+ {{/if}}
- {{#if canLeaveRoom}}
-
- {{/if}}
{{#if canDeleteRoom}}
{{/if}}
diff --git a/app/channel-settings/client/views/channelSettings.js b/app/channel-settings/client/views/channelSettings.js
index 41332e2aa06b..1d56f18ff3c0 100644
--- a/app/channel-settings/client/views/channelSettings.js
+++ b/app/channel-settings/client/views/channelSettings.js
@@ -412,7 +412,7 @@ Template.channelSettingsEditing.onCreated(function() {
canView() {
return roomTypes.roomTypes[room.t].allowRoomSettingChange(
room,
- RoomSettingsEnum.SYSTEM_MESSAGES
+ RoomSettingsEnum.SYSTEM_MESSAGES,
);
},
getValue() {
@@ -425,9 +425,9 @@ Template.channelSettingsEditing.onCreated(function() {
return call('saveRoomSettings', room._id, 'systemMessages', value).then(
() => {
toastr.success(
- t('System_messages_setting_changed_successfully')
+ t('System_messages_setting_changed_successfully'),
);
- }
+ },
);
},
},
@@ -572,9 +572,9 @@ Template.channelSettingsEditing.onCreated(function() {
return call('saveRoomSettings', room._id, 'retentionOverrideGlobal', value).then(
() => {
toastr.success(
- t('Retention_setting_changed_successfully')
+ t('Retention_setting_changed_successfully'),
);
- }
+ },
);
},
},
@@ -596,9 +596,9 @@ Template.channelSettingsEditing.onCreated(function() {
return call('saveRoomSettings', room._id, 'retentionMaxAge', value).then(
() => {
toastr.success(
- t('Retention_setting_changed_successfully')
+ t('Retention_setting_changed_successfully'),
);
- }
+ },
);
},
},
@@ -620,9 +620,9 @@ Template.channelSettingsEditing.onCreated(function() {
return call('saveRoomSettings', room._id, 'retentionExcludePinned', value).then(
() => {
toastr.success(
- t('Retention_setting_changed_successfully')
+ t('Retention_setting_changed_successfully'),
);
- }
+ },
);
},
},
@@ -644,9 +644,9 @@ Template.channelSettingsEditing.onCreated(function() {
return call('saveRoomSettings', room._id, 'retentionFilesOnly', value).then(
() => {
toastr.success(
- t('Retention_setting_changed_successfully')
+ t('Retention_setting_changed_successfully'),
);
- }
+ },
);
},
},
@@ -664,7 +664,7 @@ Template.channelSettingsEditing.onCreated(function() {
save(value) {
return call('saveRoomSettings', room._id, 'encrypted', value).then(() => {
toastr.success(
- t('Encrypted_setting_changed_successfully')
+ t('Encrypted_setting_changed_successfully'),
);
});
},
diff --git a/app/chatpal-search/server/provider/provider.js b/app/chatpal-search/server/provider/provider.js
index a46d935c7250..18ee9a36f42b 100644
--- a/app/chatpal-search/server/provider/provider.js
+++ b/app/chatpal-search/server/provider/provider.js
@@ -315,7 +315,7 @@ class ChatpalProvider extends SearchProvider {
payload.start || 0,
payload.rows || this._settings.get('PageSize'),
callback,
- params
+ params,
);
}
@@ -332,7 +332,7 @@ class ChatpalProvider extends SearchProvider {
this._settings.get('Main_Language'),
this._getAcl(context),
type,
- callback
+ callback,
);
}
}
diff --git a/app/cloud/server/functions/syncWorkspace.js b/app/cloud/server/functions/syncWorkspace.js
index 7435ed4daa77..e4c7bf855424 100644
--- a/app/cloud/server/functions/syncWorkspace.js
+++ b/app/cloud/server/functions/syncWorkspace.js
@@ -72,7 +72,7 @@ export function syncWorkspace(reconnectCheck = false) {
const { data } = result;
- if (data.publicKey) {
+ if (data && data.publicKey) {
Settings.updateValueById('Cloud_Workspace_PublicKey', data.publicKey);
}
diff --git a/app/crowd/server/crowd.js b/app/crowd/server/crowd.js
index 5dc92542603d..ed64c9657884 100644
--- a/app/crowd/server/crowd.js
+++ b/app/crowd/server/crowd.js
@@ -322,7 +322,6 @@ const addCronJob = _.debounce(Meteor.bindEnvironment(function addCronJobDebounce
crowd.sync();
},
});
- SyncedCron.start();
}
}), 500);
diff --git a/app/custom-sounds/client/admin/adminSounds.html b/app/custom-sounds/client/admin/adminSounds.html
index 6fe002af89ce..b4ca2015025a 100644
--- a/app/custom-sounds/client/admin/adminSounds.html
+++ b/app/custom-sounds/client/admin/adminSounds.html
@@ -7,10 +7,10 @@